/src/mozilla-central/gfx/layers/composite/ContentHost.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "mozilla/layers/ContentHost.h" |
8 | | #include "LayersLogging.h" // for AppendToString |
9 | | #include "gfx2DGlue.h" // for ContentForFormat |
10 | | #include "mozilla/gfx/Point.h" // for IntSize |
11 | | #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc |
12 | | #include "mozilla/gfx/BaseRect.h" // for BaseRect |
13 | | #include "mozilla/layers/Compositor.h" // for Compositor |
14 | | #include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc |
15 | | #include "mozilla/layers/LayersMessages.h" // for ThebesBufferData |
16 | | #include "nsAString.h" |
17 | | #include "nsPrintfCString.h" // for nsPrintfCString |
18 | | #include "nsString.h" // for nsAutoCString |
19 | | #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL |
20 | | |
21 | | namespace mozilla { |
22 | | using namespace gfx; |
23 | | |
24 | | namespace layers { |
25 | | |
26 | | ContentHostBase::ContentHostBase(const TextureInfo& aTextureInfo) |
27 | | : ContentHost(aTextureInfo) |
28 | | , mInitialised(false) |
29 | 0 | {} |
30 | | |
31 | | ContentHostBase::~ContentHostBase() |
32 | 0 | { |
33 | 0 | } |
34 | | |
35 | | void |
36 | | ContentHostTexture::Composite(Compositor* aCompositor, |
37 | | LayerComposite* aLayer, |
38 | | EffectChain& aEffectChain, |
39 | | float aOpacity, |
40 | | const gfx::Matrix4x4& aTransform, |
41 | | const SamplingFilter aSamplingFilter, |
42 | | const IntRect& aClipRect, |
43 | | const nsIntRegion* aVisibleRegion, |
44 | | const Maybe<gfx::Polygon>& aGeometry) |
45 | 0 | { |
46 | 0 | NS_ASSERTION(aVisibleRegion, "Requires a visible region"); |
47 | 0 |
|
48 | 0 | AutoLockCompositableHost lock(this); |
49 | 0 | if (lock.Failed()) { |
50 | 0 | return; |
51 | 0 | } |
52 | 0 | |
53 | 0 | if (!mTextureHost->BindTextureSource(mTextureSource)) { |
54 | 0 | return; |
55 | 0 | } |
56 | 0 | MOZ_ASSERT(mTextureSource.get()); |
57 | 0 |
|
58 | 0 | if (!mTextureHostOnWhite) { |
59 | 0 | mTextureSourceOnWhite = nullptr; |
60 | 0 | } |
61 | 0 | if (mTextureHostOnWhite && !mTextureHostOnWhite->BindTextureSource(mTextureSourceOnWhite)) { |
62 | 0 | return; |
63 | 0 | } |
64 | 0 | |
65 | 0 | RefPtr<TexturedEffect> effect = CreateTexturedEffect(mTextureSource.get(), |
66 | 0 | mTextureSourceOnWhite.get(), |
67 | 0 | aSamplingFilter, true); |
68 | 0 | if (!effect) { |
69 | 0 | return; |
70 | 0 | } |
71 | 0 | |
72 | 0 | aEffectChain.mPrimaryEffect = effect; |
73 | 0 |
|
74 | 0 | nsIntRegion tmpRegion; |
75 | 0 | const nsIntRegion* renderRegion; |
76 | 0 | #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE |
77 | 0 | if (PaintWillResample()) { |
78 | 0 | // If we're resampling, then the texture image will contain exactly the |
79 | 0 | // entire visible region's bounds, and we should draw it all in one quad |
80 | 0 | // to avoid unexpected aliasing. |
81 | 0 | tmpRegion = aVisibleRegion->GetBounds(); |
82 | 0 | renderRegion = &tmpRegion; |
83 | 0 | } else { |
84 | 0 | renderRegion = aVisibleRegion; |
85 | 0 | } |
86 | | #else |
87 | | renderRegion = aVisibleRegion; |
88 | | #endif |
89 | |
|
90 | 0 | nsIntRegion region(*renderRegion); |
91 | 0 | nsIntPoint origin = GetOriginOffset(); |
92 | 0 | // translate into TexImage space, buffer origin might not be at texture (0,0) |
93 | 0 | region.MoveBy(-origin); |
94 | 0 |
|
95 | 0 | // Figure out the intersecting draw region |
96 | 0 | gfx::IntSize texSize = mTextureSource->GetSize(); |
97 | 0 | IntRect textureRect = IntRect(0, 0, texSize.width, texSize.height); |
98 | 0 | textureRect.MoveBy(region.GetBounds().TopLeft()); |
99 | 0 | nsIntRegion subregion; |
100 | 0 | subregion.And(region, textureRect); |
101 | 0 | if (subregion.IsEmpty()) { |
102 | 0 | // Region is empty, nothing to draw |
103 | 0 | return; |
104 | 0 | } |
105 | 0 | |
106 | 0 | nsIntRegion screenRects; |
107 | 0 | nsIntRegion regionRects; |
108 | 0 |
|
109 | 0 | // Collect texture/screen coordinates for drawing |
110 | 0 | for (auto iter = subregion.RectIter(); !iter.Done(); iter.Next()) { |
111 | 0 | IntRect regionRect = iter.Get(); |
112 | 0 | IntRect screenRect = iter.Get(); |
113 | 0 | screenRect.MoveBy(origin); |
114 | 0 |
|
115 | 0 | screenRects.Or(screenRects, screenRect); |
116 | 0 | regionRects.Or(regionRects, regionRect); |
117 | 0 | } |
118 | 0 |
|
119 | 0 | BigImageIterator* bigImgIter = mTextureSource->AsBigImageIterator(); |
120 | 0 | BigImageIterator* iterOnWhite = nullptr; |
121 | 0 | if (bigImgIter) { |
122 | 0 | bigImgIter->BeginBigImageIteration(); |
123 | 0 | } |
124 | 0 |
|
125 | 0 | if (mTextureSourceOnWhite) { |
126 | 0 | iterOnWhite = mTextureSourceOnWhite->AsBigImageIterator(); |
127 | 0 | MOZ_ASSERT(!bigImgIter || bigImgIter->GetTileCount() == iterOnWhite->GetTileCount(), |
128 | 0 | "Tile count mismatch on component alpha texture"); |
129 | 0 | if (iterOnWhite) { |
130 | 0 | iterOnWhite->BeginBigImageIteration(); |
131 | 0 | } |
132 | 0 | } |
133 | 0 |
|
134 | 0 | bool usingTiles = (bigImgIter && bigImgIter->GetTileCount() > 1); |
135 | 0 | do { |
136 | 0 | if (iterOnWhite && bigImgIter) { |
137 | 0 | MOZ_ASSERT(iterOnWhite->GetTileRect() == bigImgIter->GetTileRect(), |
138 | 0 | "component alpha textures should be the same size."); |
139 | 0 | } |
140 | 0 |
|
141 | 0 | IntRect texRect = bigImgIter ? bigImgIter->GetTileRect() |
142 | 0 | : IntRect(0, 0, |
143 | 0 | texSize.width, |
144 | 0 | texSize.height); |
145 | 0 |
|
146 | 0 | // Draw texture. If we're using tiles, we do repeating manually, as texture |
147 | 0 | // repeat would cause each individual tile to repeat instead of the |
148 | 0 | // compound texture as a whole. This involves drawing at most 4 sections, |
149 | 0 | // 2 for each axis that has texture repeat. |
150 | 0 | for (int y = 0; y < (usingTiles ? 2 : 1); y++) { |
151 | 0 | for (int x = 0; x < (usingTiles ? 2 : 1); x++) { |
152 | 0 | IntRect currentTileRect(texRect); |
153 | 0 | currentTileRect.MoveBy(x * texSize.width, y * texSize.height); |
154 | 0 |
|
155 | 0 | for (auto screenIter = screenRects.RectIter(), |
156 | 0 | regionIter = regionRects.RectIter(); |
157 | 0 | !screenIter.Done() && !regionIter.Done(); |
158 | 0 | screenIter.Next(), regionIter.Next()) { |
159 | 0 | const IntRect& screenRect = screenIter.Get(); |
160 | 0 | const IntRect& regionRect = regionIter.Get(); |
161 | 0 | IntRect tileScreenRect(screenRect); |
162 | 0 | IntRect tileRegionRect(regionRect); |
163 | 0 |
|
164 | 0 | // When we're using tiles, find the intersection between the tile |
165 | 0 | // rect and this region rect. Tiling is then handled by the |
166 | 0 | // outer for-loops and modifying the tile rect. |
167 | 0 | if (usingTiles) { |
168 | 0 | tileScreenRect.MoveBy(-origin); |
169 | 0 | tileScreenRect = tileScreenRect.Intersect(currentTileRect); |
170 | 0 | tileScreenRect.MoveBy(origin); |
171 | 0 |
|
172 | 0 | if (tileScreenRect.IsEmpty()) |
173 | 0 | continue; |
174 | 0 | |
175 | 0 | tileRegionRect = regionRect.Intersect(currentTileRect); |
176 | 0 | tileRegionRect.MoveBy(-currentTileRect.TopLeft()); |
177 | 0 | } |
178 | 0 | gfx::Rect rect(tileScreenRect.X(), tileScreenRect.Y(), |
179 | 0 | tileScreenRect.Width(), tileScreenRect.Height()); |
180 | 0 |
|
181 | 0 | effect->mTextureCoords = Rect(Float(tileRegionRect.X()) / texRect.Width(), |
182 | 0 | Float(tileRegionRect.Y()) / texRect.Height(), |
183 | 0 | Float(tileRegionRect.Width()) / texRect.Width(), |
184 | 0 | Float(tileRegionRect.Height()) / texRect.Height()); |
185 | 0 |
|
186 | 0 | aCompositor->DrawGeometry(rect, aClipRect, aEffectChain, |
187 | 0 | aOpacity, aTransform, aGeometry); |
188 | 0 |
|
189 | 0 | if (usingTiles) { |
190 | 0 | DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT | DiagnosticFlags::BIGIMAGE; |
191 | 0 | if (iterOnWhite) { |
192 | 0 | diagnostics |= DiagnosticFlags::COMPONENT_ALPHA; |
193 | 0 | } |
194 | 0 | aCompositor->DrawDiagnostics(diagnostics, rect, aClipRect, |
195 | 0 | aTransform, mFlashCounter); |
196 | 0 | } |
197 | 0 | } |
198 | 0 | } |
199 | 0 | } |
200 | 0 |
|
201 | 0 | if (iterOnWhite) { |
202 | 0 | iterOnWhite->NextTile(); |
203 | 0 | } |
204 | 0 | } while (usingTiles && bigImgIter->NextTile()); |
205 | 0 |
|
206 | 0 | if (bigImgIter) { |
207 | 0 | bigImgIter->EndBigImageIteration(); |
208 | 0 | } |
209 | 0 | if (iterOnWhite) { |
210 | 0 | iterOnWhite->EndBigImageIteration(); |
211 | 0 | } |
212 | 0 |
|
213 | 0 | DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT; |
214 | 0 | if (iterOnWhite) { |
215 | 0 | diagnostics |= DiagnosticFlags::COMPONENT_ALPHA; |
216 | 0 | } |
217 | 0 | aCompositor->DrawDiagnostics(diagnostics, nsIntRegion(mBufferRect), aClipRect, |
218 | 0 | aTransform, mFlashCounter); |
219 | 0 | } |
220 | | |
221 | | RefPtr<TextureSource> |
222 | | ContentHostTexture::AcquireTextureSource() |
223 | 0 | { |
224 | 0 | if (!mTextureHost || !mTextureHost->AcquireTextureSource(mTextureSource)) { |
225 | 0 | return nullptr; |
226 | 0 | } |
227 | 0 | return mTextureSource.get(); |
228 | 0 | } |
229 | | |
230 | | RefPtr<TextureSource> |
231 | | ContentHostTexture::AcquireTextureSourceOnWhite() |
232 | 0 | { |
233 | 0 | if (!mTextureHostOnWhite || |
234 | 0 | !mTextureHostOnWhite->AcquireTextureSource(mTextureSourceOnWhite)) |
235 | 0 | { |
236 | 0 | return nullptr; |
237 | 0 | } |
238 | 0 | return mTextureSourceOnWhite.get(); |
239 | 0 | } |
240 | | |
241 | | void |
242 | | ContentHostTexture::UseTextureHost(const nsTArray<TimedTexture>& aTextures) |
243 | 0 | { |
244 | 0 | ContentHostBase::UseTextureHost(aTextures); |
245 | 0 | MOZ_ASSERT(aTextures.Length() == 1); |
246 | 0 | const TimedTexture& t = aTextures[0]; |
247 | 0 | MOZ_ASSERT(t.mPictureRect.IsEqualInterior( |
248 | 0 | nsIntRect(nsIntPoint(0, 0), nsIntSize(t.mTexture->GetSize()))), |
249 | 0 | "Only default picture rect supported"); |
250 | 0 |
|
251 | 0 | if (t.mTexture != mTextureHost) { |
252 | 0 | mReceivedNewHost = true; |
253 | 0 | } |
254 | 0 |
|
255 | 0 | mTextureHost = t.mTexture; |
256 | 0 | mTextureHostOnWhite = nullptr; |
257 | 0 | mTextureSourceOnWhite = nullptr; |
258 | 0 | if (mTextureHost) { |
259 | 0 | mTextureHost->PrepareTextureSource(mTextureSource); |
260 | 0 | } |
261 | 0 | } |
262 | | |
263 | | void |
264 | | ContentHostTexture::UseComponentAlphaTextures(TextureHost* aTextureOnBlack, |
265 | | TextureHost* aTextureOnWhite) |
266 | 0 | { |
267 | 0 | ContentHostBase::UseComponentAlphaTextures(aTextureOnBlack, aTextureOnWhite); |
268 | 0 | mTextureHost = aTextureOnBlack; |
269 | 0 | mTextureHostOnWhite = aTextureOnWhite; |
270 | 0 | if (mTextureHost) { |
271 | 0 | mTextureHost->PrepareTextureSource(mTextureSource); |
272 | 0 | } |
273 | 0 | if (mTextureHostOnWhite) { |
274 | 0 | mTextureHostOnWhite->PrepareTextureSource(mTextureSourceOnWhite); |
275 | 0 | } |
276 | 0 | } |
277 | | |
278 | | void |
279 | | ContentHostTexture::SetTextureSourceProvider(TextureSourceProvider* aProvider) |
280 | 0 | { |
281 | 0 | ContentHostBase::SetTextureSourceProvider(aProvider); |
282 | 0 | if (mTextureHost) { |
283 | 0 | mTextureHost->SetTextureSourceProvider(aProvider); |
284 | 0 | } |
285 | 0 | if (mTextureHostOnWhite) { |
286 | 0 | mTextureHostOnWhite->SetTextureSourceProvider(aProvider); |
287 | 0 | } |
288 | 0 | } |
289 | | |
290 | | void |
291 | | ContentHostTexture::Dump(std::stringstream& aStream, |
292 | | const char* aPrefix, |
293 | | bool aDumpHtml) |
294 | 0 | { |
295 | | #ifdef MOZ_DUMP_PAINTING |
296 | | if (aDumpHtml) { |
297 | | aStream << "<ul>"; |
298 | | } |
299 | | if (mTextureHost) { |
300 | | aStream << aPrefix; |
301 | | if (aDumpHtml) { |
302 | | aStream << "<li> <a href="; |
303 | | } else { |
304 | | aStream << "Front buffer: "; |
305 | | } |
306 | | DumpTextureHost(aStream, mTextureHost); |
307 | | if (aDumpHtml) { |
308 | | aStream << "> Front buffer </a></li> "; |
309 | | } else { |
310 | | aStream << "\n"; |
311 | | } |
312 | | } |
313 | | if (mTextureHostOnWhite) { |
314 | | aStream << aPrefix; |
315 | | if (aDumpHtml) { |
316 | | aStream << "<li> <a href="; |
317 | | } else { |
318 | | aStream << "Front buffer on white: "; |
319 | | } |
320 | | DumpTextureHost(aStream, mTextureHostOnWhite); |
321 | | if (aDumpHtml) { |
322 | | aStream << "> Front buffer on white </a> </li> "; |
323 | | } else { |
324 | | aStream << "\n"; |
325 | | } |
326 | | } |
327 | | if (aDumpHtml) { |
328 | | aStream << "</ul>"; |
329 | | } |
330 | | #endif |
331 | | } |
332 | | |
333 | | static inline void |
334 | | AddWrappedRegion(const nsIntRegion& aInput, nsIntRegion& aOutput, |
335 | | const IntSize& aSize, const nsIntPoint& aShift) |
336 | 0 | { |
337 | 0 | nsIntRegion tempRegion; |
338 | 0 | tempRegion.And(IntRect(aShift, aSize), aInput); |
339 | 0 | tempRegion.MoveBy(-aShift); |
340 | 0 | aOutput.Or(aOutput, tempRegion); |
341 | 0 | } |
342 | | |
343 | | bool |
344 | | ContentHostSingleBuffered::UpdateThebes(const ThebesBufferData& aData, |
345 | | const nsIntRegion& aUpdated, |
346 | | const nsIntRegion& aOldValidRegionBack) |
347 | 0 | { |
348 | 0 | if (!mTextureHost) { |
349 | 0 | mInitialised = false; |
350 | 0 | return true; // FIXME should we return false? Returning true for now |
351 | 0 | } // to preserve existing behavior of NOT causing IPC errors. |
352 | 0 | |
353 | 0 | // updated is in screen coordinates. Convert it to buffer coordinates. |
354 | 0 | nsIntRegion destRegion(aUpdated); |
355 | 0 |
|
356 | 0 | if (mReceivedNewHost) { |
357 | 0 | destRegion.Or(destRegion, aOldValidRegionBack); |
358 | 0 | mReceivedNewHost = false; |
359 | 0 | } |
360 | 0 | destRegion.MoveBy(-aData.rect().TopLeft()); |
361 | 0 |
|
362 | 0 | if (!aData.rect().Contains(aUpdated.GetBounds()) || |
363 | 0 | aData.rotation().x > aData.rect().Width() || |
364 | 0 | aData.rotation().y > aData.rect().Height()) { |
365 | 0 | NS_ERROR("Invalid update data"); |
366 | 0 | return false; |
367 | 0 | } |
368 | 0 |
|
369 | 0 | // destRegion is now in logical coordinates relative to the buffer, but we |
370 | 0 | // need to account for rotation. We do that by moving the region to the |
371 | 0 | // rotation offset and then wrapping any pixels that extend off the |
372 | 0 | // bottom/right edges. |
373 | 0 |
|
374 | 0 | // Shift to the rotation point |
375 | 0 | destRegion.MoveBy(aData.rotation()); |
376 | 0 |
|
377 | 0 | IntSize bufferSize = aData.rect().Size(); |
378 | 0 |
|
379 | 0 | // Select only the pixels that are still within the buffer. |
380 | 0 | nsIntRegion finalRegion; |
381 | 0 | finalRegion.And(IntRect(IntPoint(), bufferSize), destRegion); |
382 | 0 |
|
383 | 0 | // For each of the overlap areas (right, bottom-right, bottom), select those |
384 | 0 | // pixels and wrap them around to the opposite edge of the buffer rect. |
385 | 0 | AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().Width(), 0)); |
386 | 0 | AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().Width(), aData.rect().Height())); |
387 | 0 | AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(0, aData.rect().Height())); |
388 | 0 |
|
389 | 0 | MOZ_ASSERT(IntRect(0, 0, aData.rect().Width(), aData.rect().Height()).Contains(finalRegion.GetBounds())); |
390 | 0 |
|
391 | 0 | mTextureHost->Updated(&finalRegion); |
392 | 0 | if (mTextureHostOnWhite) { |
393 | 0 | mTextureHostOnWhite->Updated(&finalRegion); |
394 | 0 | } |
395 | 0 | mInitialised = true; |
396 | 0 |
|
397 | 0 | mBufferRect = aData.rect(); |
398 | 0 | mBufferRotation = aData.rotation(); |
399 | 0 |
|
400 | 0 | return true; |
401 | 0 | } |
402 | | |
403 | | bool |
404 | | ContentHostDoubleBuffered::UpdateThebes(const ThebesBufferData& aData, |
405 | | const nsIntRegion& aUpdated, |
406 | | const nsIntRegion& aOldValidRegionBack) |
407 | 0 | { |
408 | 0 | if (!mTextureHost) { |
409 | 0 | mInitialised = false; |
410 | 0 | return true; |
411 | 0 | } |
412 | 0 | |
413 | 0 | // We don't need to calculate an update region because we assume that if we |
414 | 0 | // are using double buffering then we have render-to-texture and thus no |
415 | 0 | // upload to do. |
416 | 0 | mTextureHost->Updated(); |
417 | 0 | if (mTextureHostOnWhite) { |
418 | 0 | mTextureHostOnWhite->Updated(); |
419 | 0 | } |
420 | 0 | mInitialised = true; |
421 | 0 |
|
422 | 0 | mBufferRect = aData.rect(); |
423 | 0 | mBufferRotation = aData.rotation(); |
424 | 0 |
|
425 | 0 | // Save the current valid region of our front buffer, because if |
426 | 0 | // we're double buffering, it's going to be the valid region for the |
427 | 0 | // next back buffer sent back to the renderer. |
428 | 0 | // |
429 | 0 | // NB: we rely here on the fact that mValidRegion is initialized to |
430 | 0 | // empty, and that the first time Swap() is called we don't have a |
431 | 0 | // valid front buffer that we're going to return to content. |
432 | 0 | mValidRegionForNextBackBuffer = aOldValidRegionBack; |
433 | 0 |
|
434 | 0 | return true; |
435 | 0 | } |
436 | | |
437 | | void |
438 | | ContentHostTexture::PrintInfo(std::stringstream& aStream, const char* aPrefix) |
439 | 0 | { |
440 | 0 | aStream << aPrefix; |
441 | 0 | aStream << nsPrintfCString("ContentHost (0x%p)", this).get(); |
442 | 0 |
|
443 | 0 | AppendToString(aStream, mBufferRect, " [buffer-rect=", "]"); |
444 | 0 | AppendToString(aStream, mBufferRotation, " [buffer-rotation=", "]"); |
445 | 0 | if (PaintWillResample()) { |
446 | 0 | aStream << " [paint-will-resample]"; |
447 | 0 | } |
448 | 0 |
|
449 | 0 | if (mTextureHost) { |
450 | 0 | nsAutoCString pfx(aPrefix); |
451 | 0 | pfx += " "; |
452 | 0 |
|
453 | 0 | aStream << "\n"; |
454 | 0 | mTextureHost->PrintInfo(aStream, pfx.get()); |
455 | 0 | } |
456 | 0 | } |
457 | | |
458 | | |
459 | | already_AddRefed<TexturedEffect> |
460 | | ContentHostTexture::GenEffect(const gfx::SamplingFilter aSamplingFilter) |
461 | 0 | { |
462 | 0 | if (!mTextureHost) { |
463 | 0 | return nullptr; |
464 | 0 | } |
465 | 0 | if (!mTextureHost->BindTextureSource(mTextureSource)) { |
466 | 0 | return nullptr; |
467 | 0 | } |
468 | 0 | if (!mTextureHostOnWhite) { |
469 | 0 | mTextureSourceOnWhite = nullptr; |
470 | 0 | } |
471 | 0 | if (mTextureHostOnWhite && !mTextureHostOnWhite->BindTextureSource(mTextureSourceOnWhite)) { |
472 | 0 | return nullptr; |
473 | 0 | } |
474 | 0 | return CreateTexturedEffect(mTextureSource.get(), |
475 | 0 | mTextureSourceOnWhite.get(), |
476 | 0 | aSamplingFilter, true); |
477 | 0 | } |
478 | | |
479 | | already_AddRefed<gfx::DataSourceSurface> |
480 | | ContentHostTexture::GetAsSurface() |
481 | 0 | { |
482 | 0 | if (!mTextureHost) { |
483 | 0 | return nullptr; |
484 | 0 | } |
485 | 0 | |
486 | 0 | return mTextureHost->GetAsSurface(); |
487 | 0 | } |
488 | | |
489 | | |
490 | | } // namespace layers |
491 | | } // namespace mozilla |