Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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/. */
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
20 namespace mozilla {
21 namespace gfx {
22 class Matrix4x4;
23 }
24 using namespace gfx;
26 namespace layers {
28 ContentHostBase::ContentHostBase(const TextureInfo& aTextureInfo)
29 : ContentHost(aTextureInfo)
30 , mPaintWillResample(false)
31 , mInitialised(false)
32 {}
34 ContentHostBase::~ContentHostBase()
35 {
36 }
38 struct AutoLockContentHost
39 {
40 AutoLockContentHost(ContentHostBase* aHost)
41 : mHost(aHost)
42 {
43 mSucceeded = mHost->Lock();
44 }
46 ~AutoLockContentHost()
47 {
48 if (mSucceeded) {
49 mHost->Unlock();
50 }
51 }
53 bool Failed() { return !mSucceeded; }
55 ContentHostBase* mHost;
56 bool mSucceeded;
57 };
59 void
60 ContentHostBase::Composite(EffectChain& aEffectChain,
61 float aOpacity,
62 const gfx::Matrix4x4& aTransform,
63 const Filter& aFilter,
64 const Rect& aClipRect,
65 const nsIntRegion* aVisibleRegion,
66 TiledLayerProperties* aLayerProperties)
67 {
68 NS_ASSERTION(aVisibleRegion, "Requires a visible region");
70 AutoLockContentHost lock(this);
71 if (lock.Failed()) {
72 return;
73 }
75 RefPtr<NewTextureSource> source = GetTextureSource();
76 RefPtr<NewTextureSource> sourceOnWhite = GetTextureSourceOnWhite();
78 if (!source) {
79 return;
80 }
81 RefPtr<TexturedEffect> effect =
82 CreateTexturedEffect(source, sourceOnWhite, aFilter);
84 if (!effect) {
85 return;
86 }
88 aEffectChain.mPrimaryEffect = effect;
90 nsIntRegion tmpRegion;
91 const nsIntRegion* renderRegion;
92 if (PaintWillResample()) {
93 // If we're resampling, then the texture image will contain exactly the
94 // entire visible region's bounds, and we should draw it all in one quad
95 // to avoid unexpected aliasing.
96 tmpRegion = aVisibleRegion->GetBounds();
97 renderRegion = &tmpRegion;
98 } else {
99 renderRegion = aVisibleRegion;
100 }
102 nsIntRegion region(*renderRegion);
103 nsIntPoint origin = GetOriginOffset();
104 // translate into TexImage space, buffer origin might not be at texture (0,0)
105 region.MoveBy(-origin);
107 // Figure out the intersecting draw region
108 gfx::IntSize texSize = source->GetSize();
109 nsIntRect textureRect = nsIntRect(0, 0, texSize.width, texSize.height);
110 textureRect.MoveBy(region.GetBounds().TopLeft());
111 nsIntRegion subregion;
112 subregion.And(region, textureRect);
113 if (subregion.IsEmpty()) {
114 // Region is empty, nothing to draw
115 return;
116 }
118 nsIntRegion screenRects;
119 nsIntRegion regionRects;
121 // Collect texture/screen coordinates for drawing
122 nsIntRegionRectIterator iter(subregion);
123 while (const nsIntRect* iterRect = iter.Next()) {
124 nsIntRect regionRect = *iterRect;
125 nsIntRect screenRect = regionRect;
126 screenRect.MoveBy(origin);
128 screenRects.Or(screenRects, screenRect);
129 regionRects.Or(regionRects, regionRect);
130 }
132 TileIterator* tileIter = source->AsTileIterator();
133 TileIterator* iterOnWhite = nullptr;
134 if (tileIter) {
135 tileIter->BeginTileIteration();
136 }
138 if (sourceOnWhite) {
139 iterOnWhite = sourceOnWhite->AsTileIterator();
140 MOZ_ASSERT(!tileIter || tileIter->GetTileCount() == iterOnWhite->GetTileCount(),
141 "Tile count mismatch on component alpha texture");
142 if (iterOnWhite) {
143 iterOnWhite->BeginTileIteration();
144 }
145 }
147 bool usingTiles = (tileIter && tileIter->GetTileCount() > 1);
148 do {
149 if (iterOnWhite) {
150 MOZ_ASSERT(iterOnWhite->GetTileRect() == tileIter->GetTileRect(),
151 "component alpha textures should be the same size.");
152 }
154 nsIntRect texRect = tileIter ? tileIter->GetTileRect()
155 : nsIntRect(0, 0,
156 texSize.width,
157 texSize.height);
159 // Draw texture. If we're using tiles, we do repeating manually, as texture
160 // repeat would cause each individual tile to repeat instead of the
161 // compound texture as a whole. This involves drawing at most 4 sections,
162 // 2 for each axis that has texture repeat.
163 for (int y = 0; y < (usingTiles ? 2 : 1); y++) {
164 for (int x = 0; x < (usingTiles ? 2 : 1); x++) {
165 nsIntRect currentTileRect(texRect);
166 currentTileRect.MoveBy(x * texSize.width, y * texSize.height);
168 nsIntRegionRectIterator screenIter(screenRects);
169 nsIntRegionRectIterator regionIter(regionRects);
171 const nsIntRect* screenRect;
172 const nsIntRect* regionRect;
173 while ((screenRect = screenIter.Next()) &&
174 (regionRect = regionIter.Next())) {
175 nsIntRect tileScreenRect(*screenRect);
176 nsIntRect tileRegionRect(*regionRect);
178 // When we're using tiles, find the intersection between the tile
179 // rect and this region rect. Tiling is then handled by the
180 // outer for-loops and modifying the tile rect.
181 if (usingTiles) {
182 tileScreenRect.MoveBy(-origin);
183 tileScreenRect = tileScreenRect.Intersect(currentTileRect);
184 tileScreenRect.MoveBy(origin);
186 if (tileScreenRect.IsEmpty())
187 continue;
189 tileRegionRect = regionRect->Intersect(currentTileRect);
190 tileRegionRect.MoveBy(-currentTileRect.TopLeft());
191 }
192 gfx::Rect rect(tileScreenRect.x, tileScreenRect.y,
193 tileScreenRect.width, tileScreenRect.height);
195 effect->mTextureCoords = Rect(Float(tileRegionRect.x) / texRect.width,
196 Float(tileRegionRect.y) / texRect.height,
197 Float(tileRegionRect.width) / texRect.width,
198 Float(tileRegionRect.height) / texRect.height);
199 GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, aOpacity, aTransform);
200 if (usingTiles) {
201 DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT | DIAGNOSTIC_BIGIMAGE;
202 diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0;
203 GetCompositor()->DrawDiagnostics(diagnostics, rect, aClipRect,
204 aTransform, mFlashCounter);
205 }
206 }
207 }
208 }
210 if (iterOnWhite) {
211 iterOnWhite->NextTile();
212 }
213 } while (usingTiles && tileIter->NextTile());
215 if (tileIter) {
216 tileIter->EndTileIteration();
217 }
218 if (iterOnWhite) {
219 iterOnWhite->EndTileIteration();
220 }
222 DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT;
223 diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0;
224 GetCompositor()->DrawDiagnostics(diagnostics, *aVisibleRegion, aClipRect,
225 aTransform, mFlashCounter);
226 }
229 void
230 ContentHostTexture::UseTextureHost(TextureHost* aTexture)
231 {
232 ContentHostBase::UseTextureHost(aTexture);
233 mTextureHost = aTexture;
234 mTextureHostOnWhite = nullptr;
235 }
237 void
238 ContentHostTexture::UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
239 TextureHost* aTextureOnWhite)
240 {
241 ContentHostBase::UseComponentAlphaTextures(aTextureOnBlack, aTextureOnWhite);
242 mTextureHost = aTextureOnBlack;
243 mTextureHostOnWhite = aTextureOnWhite;
244 }
246 void
247 ContentHostTexture::SetCompositor(Compositor* aCompositor)
248 {
249 ContentHostBase::SetCompositor(aCompositor);
250 if (mTextureHost) {
251 mTextureHost->SetCompositor(aCompositor);
252 }
253 if (mTextureHostOnWhite) {
254 mTextureHostOnWhite->SetCompositor(aCompositor);
255 }
256 }
258 #ifdef MOZ_DUMP_PAINTING
259 void
260 ContentHostTexture::Dump(FILE* aFile,
261 const char* aPrefix,
262 bool aDumpHtml)
263 {
264 if (!aDumpHtml) {
265 return;
266 }
267 if (!aFile) {
268 aFile = stderr;
269 }
270 fprintf(aFile, "<ul>");
271 if (mTextureHost) {
272 fprintf(aFile, "%s", aPrefix);
273 fprintf(aFile, "<li> <a href=");
274 DumpTextureHost(aFile, mTextureHost);
275 fprintf(aFile, "> Front buffer </a></li> ");
276 }
277 if (mTextureHostOnWhite) {
278 fprintf(aFile, "%s", aPrefix);
279 fprintf(aFile, "<li> <a href=");
280 DumpTextureHost(aFile, mTextureHostOnWhite);
281 fprintf(aFile, "> Front buffer on white </a> </li> ");
282 }
283 fprintf(aFile, "</ul>");
284 }
285 #endif
287 static inline void
288 AddWrappedRegion(const nsIntRegion& aInput, nsIntRegion& aOutput,
289 const nsIntSize& aSize, const nsIntPoint& aShift)
290 {
291 nsIntRegion tempRegion;
292 tempRegion.And(nsIntRect(aShift, aSize), aInput);
293 tempRegion.MoveBy(-aShift);
294 aOutput.Or(aOutput, tempRegion);
295 }
297 bool
298 ContentHostSingleBuffered::UpdateThebes(const ThebesBufferData& aData,
299 const nsIntRegion& aUpdated,
300 const nsIntRegion& aOldValidRegionBack,
301 nsIntRegion* aUpdatedRegionBack)
302 {
303 aUpdatedRegionBack->SetEmpty();
305 if (!mTextureHost) {
306 mInitialised = false;
307 return true; // FIXME should we return false? Returning true for now
308 } // to preserve existing behavior of NOT causing IPC errors.
310 // updated is in screen coordinates. Convert it to buffer coordinates.
311 nsIntRegion destRegion(aUpdated);
312 destRegion.MoveBy(-aData.rect().TopLeft());
314 if (!aData.rect().Contains(aUpdated.GetBounds()) ||
315 aData.rotation().x > aData.rect().width ||
316 aData.rotation().y > aData.rect().height) {
317 NS_ERROR("Invalid update data");
318 return false;
319 }
321 // destRegion is now in logical coordinates relative to the buffer, but we
322 // need to account for rotation. We do that by moving the region to the
323 // rotation offset and then wrapping any pixels that extend off the
324 // bottom/right edges.
326 // Shift to the rotation point
327 destRegion.MoveBy(aData.rotation());
329 nsIntSize bufferSize = aData.rect().Size();
331 // Select only the pixels that are still within the buffer.
332 nsIntRegion finalRegion;
333 finalRegion.And(nsIntRect(nsIntPoint(), bufferSize), destRegion);
335 // For each of the overlap areas (right, bottom-right, bottom), select those
336 // pixels and wrap them around to the opposite edge of the buffer rect.
337 AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().width, 0));
338 AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().width, aData.rect().height));
339 AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(0, aData.rect().height));
341 MOZ_ASSERT(nsIntRect(0, 0, aData.rect().width, aData.rect().height).Contains(finalRegion.GetBounds()));
343 mTextureHost->Updated(&finalRegion);
344 if (mTextureHostOnWhite) {
345 mTextureHostOnWhite->Updated(&finalRegion);
346 }
347 mInitialised = true;
349 mBufferRect = aData.rect();
350 mBufferRotation = aData.rotation();
352 return true;
353 }
355 bool
356 ContentHostDoubleBuffered::UpdateThebes(const ThebesBufferData& aData,
357 const nsIntRegion& aUpdated,
358 const nsIntRegion& aOldValidRegionBack,
359 nsIntRegion* aUpdatedRegionBack)
360 {
361 if (!mTextureHost) {
362 mInitialised = false;
364 *aUpdatedRegionBack = aUpdated;
365 return true;
366 }
368 // We don't need to calculate an update region because we assume that if we
369 // are using double buffering then we have render-to-texture and thus no
370 // upload to do.
371 mTextureHost->Updated();
372 if (mTextureHostOnWhite) {
373 mTextureHostOnWhite->Updated();
374 }
375 mInitialised = true;
377 mBufferRect = aData.rect();
378 mBufferRotation = aData.rotation();
380 *aUpdatedRegionBack = aUpdated;
382 // Save the current valid region of our front buffer, because if
383 // we're double buffering, it's going to be the valid region for the
384 // next back buffer sent back to the renderer.
385 //
386 // NB: we rely here on the fact that mValidRegion is initialized to
387 // empty, and that the first time Swap() is called we don't have a
388 // valid front buffer that we're going to return to content.
389 mValidRegionForNextBackBuffer = aOldValidRegionBack;
391 return true;
392 }
394 ContentHostIncremental::ContentHostIncremental(const TextureInfo& aTextureInfo)
395 : ContentHostBase(aTextureInfo)
396 , mDeAllocator(nullptr)
397 , mLocked(false)
398 {
399 }
401 ContentHostIncremental::~ContentHostIncremental()
402 {
403 }
405 bool
406 ContentHostIncremental::CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
407 const TextureInfo& aTextureInfo,
408 const nsIntRect& aBufferRect)
409 {
410 mUpdateList.AppendElement(new TextureCreationRequest(aTextureInfo,
411 aBufferRect));
412 mDeAllocator = aAllocator;
413 FlushUpdateQueue();
414 return true;
415 }
417 void
418 ContentHostIncremental::UpdateIncremental(TextureIdentifier aTextureId,
419 SurfaceDescriptor& aSurface,
420 const nsIntRegion& aUpdated,
421 const nsIntRect& aBufferRect,
422 const nsIntPoint& aBufferRotation)
423 {
424 mUpdateList.AppendElement(new TextureUpdateRequest(mDeAllocator,
425 aTextureId,
426 aSurface,
427 aUpdated,
428 aBufferRect,
429 aBufferRotation));
430 FlushUpdateQueue();
431 }
433 void
434 ContentHostIncremental::FlushUpdateQueue()
435 {
436 // If we're not compositing for some reason (the window being minimized
437 // is one example), then we never process these updates and it can consume
438 // huge amounts of memory. Instead we forcibly process the updates (during the
439 // transaction) if the list gets too long.
440 static const uint32_t kMaxUpdateCount = 6;
441 if (mUpdateList.Length() >= kMaxUpdateCount) {
442 ProcessTextureUpdates();
443 }
444 }
446 void
447 ContentHostIncremental::ProcessTextureUpdates()
448 {
449 for (uint32_t i = 0; i < mUpdateList.Length(); i++) {
450 mUpdateList[i]->Execute(this);
451 }
452 mUpdateList.Clear();
453 }
455 NewTextureSource*
456 ContentHostIncremental::GetTextureSource()
457 {
458 MOZ_ASSERT(mLocked);
459 return mSource;
460 }
462 NewTextureSource*
463 ContentHostIncremental::GetTextureSourceOnWhite()
464 {
465 MOZ_ASSERT(mLocked);
466 return mSourceOnWhite;
467 }
469 void
470 ContentHostIncremental::TextureCreationRequest::Execute(ContentHostIncremental* aHost)
471 {
472 Compositor* compositor = aHost->GetCompositor();
473 MOZ_ASSERT(compositor);
475 RefPtr<DataTextureSource> temp =
476 compositor->CreateDataTextureSource(mTextureInfo.mTextureFlags);
477 MOZ_ASSERT(temp->AsSourceOGL() &&
478 temp->AsSourceOGL()->AsTextureImageTextureSource());
479 RefPtr<TextureImageTextureSourceOGL> newSource =
480 temp->AsSourceOGL()->AsTextureImageTextureSource();
482 RefPtr<TextureImageTextureSourceOGL> newSourceOnWhite;
483 if (mTextureInfo.mTextureFlags & TEXTURE_COMPONENT_ALPHA) {
484 temp =
485 compositor->CreateDataTextureSource(mTextureInfo.mTextureFlags);
486 MOZ_ASSERT(temp->AsSourceOGL() &&
487 temp->AsSourceOGL()->AsTextureImageTextureSource());
488 newSourceOnWhite = temp->AsSourceOGL()->AsTextureImageTextureSource();
489 }
491 if (mTextureInfo.mDeprecatedTextureHostFlags & TEXTURE_HOST_COPY_PREVIOUS) {
492 MOZ_ASSERT(aHost->mSource);
493 MOZ_ASSERT(aHost->mSource->IsValid());
494 nsIntRect bufferRect = aHost->mBufferRect;
495 nsIntPoint bufferRotation = aHost->mBufferRotation;
496 nsIntRect overlap;
498 // The buffer looks like:
499 // ______
500 // |1 |2 | Where the center point is offset by mBufferRotation from the top-left corner.
501 // |___|__|
502 // |3 |4 |
503 // |___|__|
504 //
505 // This is drawn to the screen as:
506 // ______
507 // |4 |3 | Where the center point is { width - mBufferRotation.x, height - mBufferRotation.y } from
508 // |___|__| from the top left corner - rotationPoint.
509 // |2 |1 |
510 // |___|__|
511 //
513 // The basic idea below is to take all quadrant rectangles from the src and transform them into rectangles
514 // in the destination. Unfortunately, it seems it is overly complex and could perhaps be simplified.
516 nsIntRect srcBufferSpaceBottomRight(bufferRotation.x, bufferRotation.y, bufferRect.width - bufferRotation.x, bufferRect.height - bufferRotation.y);
517 nsIntRect srcBufferSpaceTopRight(bufferRotation.x, 0, bufferRect.width - bufferRotation.x, bufferRotation.y);
518 nsIntRect srcBufferSpaceTopLeft(0, 0, bufferRotation.x, bufferRotation.y);
519 nsIntRect srcBufferSpaceBottomLeft(0, bufferRotation.y, bufferRotation.x, bufferRect.height - bufferRotation.y);
521 overlap.IntersectRect(bufferRect, mBufferRect);
523 nsIntRect srcRect(overlap), dstRect(overlap);
524 srcRect.MoveBy(- bufferRect.TopLeft() + bufferRotation);
526 nsIntRect srcRectDrawTopRight(srcRect);
527 nsIntRect srcRectDrawTopLeft(srcRect);
528 nsIntRect srcRectDrawBottomLeft(srcRect);
529 // transform into the different quadrants
530 srcRectDrawTopRight .MoveBy(-nsIntPoint(0, bufferRect.height));
531 srcRectDrawTopLeft .MoveBy(-nsIntPoint(bufferRect.width, bufferRect.height));
532 srcRectDrawBottomLeft.MoveBy(-nsIntPoint(bufferRect.width, 0));
534 // Intersect with the quadrant
535 srcRect = srcRect .Intersect(srcBufferSpaceBottomRight);
536 srcRectDrawTopRight = srcRectDrawTopRight .Intersect(srcBufferSpaceTopRight);
537 srcRectDrawTopLeft = srcRectDrawTopLeft .Intersect(srcBufferSpaceTopLeft);
538 srcRectDrawBottomLeft = srcRectDrawBottomLeft.Intersect(srcBufferSpaceBottomLeft);
540 dstRect = srcRect;
541 nsIntRect dstRectDrawTopRight(srcRectDrawTopRight);
542 nsIntRect dstRectDrawTopLeft(srcRectDrawTopLeft);
543 nsIntRect dstRectDrawBottomLeft(srcRectDrawBottomLeft);
545 // transform back to src buffer space
546 dstRect .MoveBy(-bufferRotation);
547 dstRectDrawTopRight .MoveBy(-bufferRotation + nsIntPoint(0, bufferRect.height));
548 dstRectDrawTopLeft .MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, bufferRect.height));
549 dstRectDrawBottomLeft.MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, 0));
551 // transform back to draw coordinates
552 dstRect .MoveBy(bufferRect.TopLeft());
553 dstRectDrawTopRight .MoveBy(bufferRect.TopLeft());
554 dstRectDrawTopLeft .MoveBy(bufferRect.TopLeft());
555 dstRectDrawBottomLeft.MoveBy(bufferRect.TopLeft());
557 // transform to destBuffer space
558 dstRect .MoveBy(-mBufferRect.TopLeft());
559 dstRectDrawTopRight .MoveBy(-mBufferRect.TopLeft());
560 dstRectDrawTopLeft .MoveBy(-mBufferRect.TopLeft());
561 dstRectDrawBottomLeft.MoveBy(-mBufferRect.TopLeft());
563 newSource->EnsureBuffer(mBufferRect.Size(),
564 ContentForFormat(aHost->mSource->GetFormat()));
566 aHost->mSource->CopyTo(srcRect, newSource, dstRect);
567 if (bufferRotation != nsIntPoint(0, 0)) {
568 // Draw the remaining quadrants. We call BlitTextureImage 3 extra
569 // times instead of doing a single draw call because supporting that
570 // with a tiled source is quite tricky.
572 if (!srcRectDrawTopRight.IsEmpty())
573 aHost->mSource->CopyTo(srcRectDrawTopRight,
574 newSource, dstRectDrawTopRight);
575 if (!srcRectDrawTopLeft.IsEmpty())
576 aHost->mSource->CopyTo(srcRectDrawTopLeft,
577 newSource, dstRectDrawTopLeft);
578 if (!srcRectDrawBottomLeft.IsEmpty())
579 aHost->mSource->CopyTo(srcRectDrawBottomLeft,
580 newSource, dstRectDrawBottomLeft);
581 }
583 if (newSourceOnWhite) {
584 newSourceOnWhite->EnsureBuffer(mBufferRect.Size(),
585 ContentForFormat(aHost->mSourceOnWhite->GetFormat()));
586 aHost->mSourceOnWhite->CopyTo(srcRect, newSourceOnWhite, dstRect);
587 if (bufferRotation != nsIntPoint(0, 0)) {
588 // draw the remaining quadrants
589 if (!srcRectDrawTopRight.IsEmpty())
590 aHost->mSourceOnWhite->CopyTo(srcRectDrawTopRight,
591 newSourceOnWhite, dstRectDrawTopRight);
592 if (!srcRectDrawTopLeft.IsEmpty())
593 aHost->mSourceOnWhite->CopyTo(srcRectDrawTopLeft,
594 newSourceOnWhite, dstRectDrawTopLeft);
595 if (!srcRectDrawBottomLeft.IsEmpty())
596 aHost->mSourceOnWhite->CopyTo(srcRectDrawBottomLeft,
597 newSourceOnWhite, dstRectDrawBottomLeft);
598 }
599 }
600 }
602 aHost->mSource = newSource;
603 aHost->mSourceOnWhite = newSourceOnWhite;
605 aHost->mBufferRect = mBufferRect;
606 aHost->mBufferRotation = nsIntPoint();
607 }
609 nsIntRect
610 ContentHostIncremental::TextureUpdateRequest::GetQuadrantRectangle(XSide aXSide,
611 YSide aYSide) const
612 {
613 // quadrantTranslation is the amount we translate the top-left
614 // of the quadrant by to get coordinates relative to the layer
615 nsIntPoint quadrantTranslation = -mBufferRotation;
616 quadrantTranslation.x += aXSide == LEFT ? mBufferRect.width : 0;
617 quadrantTranslation.y += aYSide == TOP ? mBufferRect.height : 0;
618 return mBufferRect + quadrantTranslation;
619 }
621 void
622 ContentHostIncremental::TextureUpdateRequest::Execute(ContentHostIncremental* aHost)
623 {
624 nsIntRect drawBounds = mUpdated.GetBounds();
626 aHost->mBufferRect = mBufferRect;
627 aHost->mBufferRotation = mBufferRotation;
629 // Figure out which quadrant to draw in
630 int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x;
631 int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y;
632 XSide sideX = drawBounds.XMost() <= xBoundary ? RIGHT : LEFT;
633 YSide sideY = drawBounds.YMost() <= yBoundary ? BOTTOM : TOP;
634 nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
635 NS_ASSERTION(quadrantRect.Contains(drawBounds), "Messed up quadrants");
637 mUpdated.MoveBy(-nsIntPoint(quadrantRect.x, quadrantRect.y));
639 IntPoint offset = ToIntPoint(-mUpdated.GetBounds().TopLeft());
641 RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(mDescriptor);
643 if (mTextureId == TextureFront) {
644 aHost->mSource->Update(surf, &mUpdated, &offset);
645 } else {
646 aHost->mSourceOnWhite->Update(surf, &mUpdated, &offset);
647 }
648 }
650 void
651 ContentHostTexture::PrintInfo(nsACString& aTo, const char* aPrefix)
652 {
653 aTo += aPrefix;
654 aTo += nsPrintfCString("ContentHost (0x%p)", this);
656 AppendToString(aTo, mBufferRect, " [buffer-rect=", "]");
657 AppendToString(aTo, mBufferRotation, " [buffer-rotation=", "]");
658 if (PaintWillResample()) {
659 aTo += " [paint-will-resample]";
660 }
662 nsAutoCString pfx(aPrefix);
663 pfx += " ";
665 if (mTextureHost) {
666 aTo += "\n";
667 mTextureHost->PrintInfo(aTo, pfx.get());
668 }
669 }
672 LayerRenderState
673 ContentHostTexture::GetRenderState()
674 {
675 if (!mTextureHost) {
676 return LayerRenderState();
677 }
679 LayerRenderState result = mTextureHost->GetRenderState();
681 if (mBufferRotation != nsIntPoint()) {
682 result.mFlags |= LAYER_RENDER_STATE_BUFFER_ROTATION;
683 }
684 result.SetOffset(GetOriginOffset());
685 return result;
686 }
688 #ifdef MOZ_DUMP_PAINTING
689 TemporaryRef<gfx::DataSourceSurface>
690 ContentHostTexture::GetAsSurface()
691 {
692 if (!mTextureHost) {
693 return nullptr;
694 }
696 return mTextureHost->GetAsSurface();
697 }
699 #endif
702 } // namespace
703 } // namespace