gfx/layers/composite/ContentHost.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

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

mercurial