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