gfx/layers/client/ContentClient.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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/ContentClient.h"
     7 #include "BasicLayers.h"                // for BasicLayerManager
     8 #include "gfxColor.h"                   // for gfxRGBA
     9 #include "gfxContext.h"                 // for gfxContext, etc
    10 #include "gfxPlatform.h"                // for gfxPlatform
    11 #include "gfxPrefs.h"                   // for gfxPrefs
    12 #include "gfxPoint.h"                   // for gfxIntSize, gfxPoint
    13 #include "gfxTeeSurface.h"              // for gfxTeeSurface
    14 #include "gfxUtils.h"                   // for gfxUtils
    15 #include "ipc/ShadowLayers.h"           // for ShadowLayerForwarder
    16 #include "mozilla/ArrayUtils.h"         // for ArrayLength
    17 #include "mozilla/gfx/2D.h"             // for DrawTarget, Factory
    18 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
    19 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
    20 #include "mozilla/gfx/Rect.h"           // for Rect
    21 #include "mozilla/gfx/Types.h"
    22 #include "mozilla/layers/LayerManagerComposite.h"
    23 #include "mozilla/layers/LayersMessages.h"  // for ThebesBufferData
    24 #include "mozilla/layers/LayersTypes.h"
    25 #include "nsAutoPtr.h"                  // for nsRefPtr
    26 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
    27 #include "nsISupportsImpl.h"            // for gfxContext::Release, etc
    28 #include "nsIWidget.h"                  // for nsIWidget
    29 #include "prenv.h"                      // for PR_GetEnv
    30 #ifdef XP_WIN
    31 #include "gfxWindowsPlatform.h"
    32 #endif
    33 #include "gfx2DGlue.h"
    35 namespace mozilla {
    37 using namespace gfx;
    39 namespace layers {
    41 static TextureFlags TextureFlagsForRotatedContentBufferFlags(uint32_t aBufferFlags)
    42 {
    43   TextureFlags result = 0;
    45   if (aBufferFlags & RotatedContentBuffer::BUFFER_COMPONENT_ALPHA) {
    46     result |= TEXTURE_COMPONENT_ALPHA;
    47   }
    49   if (aBufferFlags & RotatedContentBuffer::ALLOW_REPEAT) {
    50     result |= TEXTURE_ALLOW_REPEAT;
    51   }
    53   return result;
    54 }
    57 /* static */ TemporaryRef<ContentClient>
    58 ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
    59 {
    60   LayersBackend backend = aForwarder->GetCompositorBackendType();
    61   if (backend != LayersBackend::LAYERS_OPENGL &&
    62       backend != LayersBackend::LAYERS_D3D9 &&
    63       backend != LayersBackend::LAYERS_D3D11 &&
    64       backend != LayersBackend::LAYERS_BASIC) {
    65     return nullptr;
    66   }
    68   bool useDoubleBuffering = false;
    70 #ifdef XP_WIN
    71   if (backend == LayersBackend::LAYERS_D3D11) {
    72     useDoubleBuffering = !!gfxWindowsPlatform::GetPlatform()->GetD2DDevice();
    73   } else
    74 #endif
    75   {
    76     useDoubleBuffering = (LayerManagerComposite::SupportsDirectTexturing() &&
    77                          backend != LayersBackend::LAYERS_D3D9) ||
    78                          backend == LayersBackend::LAYERS_BASIC;
    79   }
    81   if (useDoubleBuffering || PR_GetEnv("MOZ_FORCE_DOUBLE_BUFFERING")) {
    82     return new ContentClientDoubleBuffered(aForwarder);
    83   }
    84 #ifdef XP_MACOSX
    85   if (backend == LayersBackend::LAYERS_OPENGL) {
    86     return new ContentClientIncremental(aForwarder);
    87   }
    88 #endif
    89   return new ContentClientSingleBuffered(aForwarder);
    90 }
    92 void
    93 ContentClient::EndPaint()
    94 {
    95   // It is very important that this is called after any overridden EndPaint behaviour,
    96   // because destroying textures is a three stage process:
    97   // 1. We are done with the buffer and move it to ContentClient::mOldTextures,
    98   // that happens in DestroyBuffers which is may be called indirectly from
    99   // PaintThebes.
   100   // 2. The content client calls RemoveTextureClient on the texture clients in
   101   // mOldTextures and forgets them. They then become invalid. The compositable
   102   // client keeps a record of IDs. This happens in EndPaint.
   103   // 3. An IPC message is sent to destroy the corresponding texture host. That
   104   // happens from OnTransaction.
   105   // It is important that these steps happen in order.
   106   OnTransaction();
   107 }
   109 // We pass a null pointer for the ContentClient Forwarder argument, which means
   110 // this client will not have a ContentHost on the other side.
   111 ContentClientBasic::ContentClientBasic()
   112   : ContentClient(nullptr)
   113   , RotatedContentBuffer(ContainsVisibleBounds)
   114 {}
   116 void
   117 ContentClientBasic::CreateBuffer(ContentType aType,
   118                                  const nsIntRect& aRect,
   119                                  uint32_t aFlags,
   120                                  RefPtr<gfx::DrawTarget>* aBlackDT,
   121                                  RefPtr<gfx::DrawTarget>* aWhiteDT)
   122 {
   123   MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA));
   124   gfxImageFormat format =
   125     gfxPlatform::GetPlatform()->OptimalFormatForContent(aType);
   127   *aBlackDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
   128     IntSize(aRect.width, aRect.height),
   129     ImageFormatToSurfaceFormat(format));
   130 }
   132 void
   133 ContentClientRemoteBuffer::DestroyBuffers()
   134 {
   135   if (!mTextureClient) {
   136     return;
   137   }
   139   mOldTextures.AppendElement(mTextureClient);
   140   mTextureClient = nullptr;
   141   if (mTextureClientOnWhite) {
   142     mOldTextures.AppendElement(mTextureClientOnWhite);
   143     mTextureClientOnWhite = nullptr;
   144   }
   146   DestroyFrontBuffer();
   147 }
   149 void
   150 ContentClientRemoteBuffer::BeginPaint()
   151 {
   152   // XXX: So we might not have a TextureClient yet.. because it will
   153   // only be created by CreateBuffer.. which will deliver a locked surface!.
   154   if (mTextureClient) {
   155     SetBufferProvider(mTextureClient);
   156   }
   157   if (mTextureClientOnWhite) {
   158     SetBufferProviderOnWhite(mTextureClientOnWhite);
   159   }
   160 }
   162 void
   163 ContentClientRemoteBuffer::EndPaint()
   164 {
   165   // XXX: We might still not have a texture client if PaintThebes
   166   // decided we didn't need one yet because the region to draw was empty.
   167   SetBufferProvider(nullptr);
   168   SetBufferProviderOnWhite(nullptr);
   169   for (unsigned i = 0; i< mOldTextures.Length(); ++i) {
   170     if (mOldTextures[i]->IsLocked()) {
   171       mOldTextures[i]->Unlock();
   172     }
   173   }
   174   mOldTextures.Clear();
   176   if (mTextureClient && mTextureClient->IsLocked()) {
   177     mTextureClient->Unlock();
   178   }
   179   if (mTextureClientOnWhite && mTextureClientOnWhite->IsLocked()) {
   180     mTextureClientOnWhite->Unlock();
   181   }
   182   ContentClientRemote::EndPaint();
   183 }
   185 bool
   186 ContentClientRemoteBuffer::CreateAndAllocateTextureClient(RefPtr<TextureClient>& aClient,
   187                                                           TextureFlags aFlags)
   188 {
   189   // gfx::BackendType::NONE means fallback to the content backend
   190   aClient = CreateTextureClientForDrawing(mSurfaceFormat,
   191                                           mTextureInfo.mTextureFlags | aFlags,
   192                                           gfx::BackendType::NONE,
   193                                           mSize);
   194   if (!aClient) {
   195     return false;
   196   }
   198   if (!aClient->AllocateForSurface(mSize, ALLOC_CLEAR_BUFFER)) {
   199     aClient = CreateTextureClientForDrawing(mSurfaceFormat,
   200                 mTextureInfo.mTextureFlags | TEXTURE_ALLOC_FALLBACK | aFlags,
   201                 gfx::BackendType::NONE,
   202                 mSize);
   203     if (!aClient) {
   204       return false;
   205     }
   206     if (!aClient->AllocateForSurface(mSize, ALLOC_CLEAR_BUFFER)) {
   207       NS_WARNING("Could not allocate texture client");
   208       aClient = nullptr;
   209       return false;
   210     }
   211   }
   213   NS_WARN_IF_FALSE(aClient->IsValid(), "Created an invalid texture client");
   214   return true;
   215 }
   217 void
   218 ContentClientRemoteBuffer::BuildTextureClients(SurfaceFormat aFormat,
   219                                                const nsIntRect& aRect,
   220                                                uint32_t aFlags)
   221 {
   222   // If we hit this assertion, then it might be due to an empty transaction
   223   // followed by a real transaction. Our buffers should be created (but not
   224   // painted in the empty transaction) and then painted (but not created) in the
   225   // real transaction. That is kind of fragile, and this assert will catch
   226   // circumstances where we screw that up, e.g., by unnecessarily recreating our
   227   // buffers.
   228   NS_ABORT_IF_FALSE(!mIsNewBuffer,
   229                     "Bad! Did we create a buffer twice without painting?");
   231   mIsNewBuffer = true;
   233   DestroyBuffers();
   235   mSurfaceFormat = aFormat;
   236   mSize = gfx::IntSize(aRect.width, aRect.height);
   237   mTextureInfo.mTextureFlags = TextureFlagsForRotatedContentBufferFlags(aFlags);
   239   if (!CreateAndAllocateTextureClient(mTextureClient, TEXTURE_ON_BLACK) ||
   240       !AddTextureClient(mTextureClient)) {
   241     AbortTextureClientCreation();
   242     return;
   243   }
   245   if (aFlags & BUFFER_COMPONENT_ALPHA) {
   246     if (!CreateAndAllocateTextureClient(mTextureClientOnWhite, TEXTURE_ON_WHITE) ||
   247         !AddTextureClient(mTextureClientOnWhite)) {
   248       AbortTextureClientCreation();
   249       return;
   250     }
   251     mTextureInfo.mTextureFlags |= TEXTURE_COMPONENT_ALPHA;
   252   }
   254   CreateFrontBuffer(aRect);
   255 }
   257 void
   258 ContentClientRemoteBuffer::CreateBuffer(ContentType aType,
   259                                         const nsIntRect& aRect,
   260                                         uint32_t aFlags,
   261                                         RefPtr<gfx::DrawTarget>* aBlackDT,
   262                                         RefPtr<gfx::DrawTarget>* aWhiteDT)
   263 {
   264   BuildTextureClients(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aType), aRect, aFlags);
   265   if (!mTextureClient) {
   266     return;
   267   }
   269   // We just created the textures and we are about to get their draw targets
   270   // so we have to lock them here.
   271   DebugOnly<bool> locked = mTextureClient->Lock(OPEN_READ_WRITE);
   272   MOZ_ASSERT(locked, "Could not lock the TextureClient");
   274   *aBlackDT = mTextureClient->GetAsDrawTarget();
   275   if (aFlags & BUFFER_COMPONENT_ALPHA) {
   276     locked = mTextureClientOnWhite->Lock(OPEN_READ_WRITE);
   277     MOZ_ASSERT(locked, "Could not lock the second TextureClient for component alpha");
   279     *aWhiteDT = mTextureClientOnWhite->GetAsDrawTarget();
   280   }
   281 }
   283 nsIntRegion
   284 ContentClientRemoteBuffer::GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
   285                                             const nsIntRegion& aVisibleRegion,
   286                                             bool aDidSelfCopy)
   287 {
   288   nsIntRegion updatedRegion;
   289   if (mIsNewBuffer || aDidSelfCopy) {
   290     // A buffer reallocation clears both buffers. The front buffer has all the
   291     // content by now, but the back buffer is still clear. Here, in effect, we
   292     // are saying to copy all of the pixels of the front buffer to the back.
   293     // Also when we self-copied in the buffer, the buffer space
   294     // changes and some changed buffer content isn't reflected in the
   295     // draw or invalidate region (on purpose!).  When this happens, we
   296     // need to read back the entire buffer too.
   297     updatedRegion = aVisibleRegion;
   298     mIsNewBuffer = false;
   299   } else {
   300     updatedRegion = aRegionToDraw;
   301   }
   303   NS_ASSERTION(BufferRect().Contains(aRegionToDraw.GetBounds()),
   304                "Update outside of buffer rect!");
   305   NS_ABORT_IF_FALSE(mTextureClient, "should have a back buffer by now");
   307   return updatedRegion;
   308 }
   310 void
   311 ContentClientRemoteBuffer::Updated(const nsIntRegion& aRegionToDraw,
   312                                    const nsIntRegion& aVisibleRegion,
   313                                    bool aDidSelfCopy)
   314 {
   315   nsIntRegion updatedRegion = GetUpdatedRegion(aRegionToDraw,
   316                                                aVisibleRegion,
   317                                                aDidSelfCopy);
   319   MOZ_ASSERT(mTextureClient);
   320   if (mTextureClientOnWhite) {
   321     mForwarder->UseComponentAlphaTextures(this, mTextureClient,
   322                                           mTextureClientOnWhite);
   323   } else {
   324     mForwarder->UseTexture(this, mTextureClient);
   325   }
   326   mForwarder->UpdateTextureRegion(this,
   327                                   ThebesBufferData(BufferRect(),
   328                                                    BufferRotation()),
   329                                   updatedRegion);
   330 }
   332 void
   333 ContentClientRemoteBuffer::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion)
   334 {
   335   MOZ_ASSERT(mTextureClient);
   336   mFrontAndBackBufferDiffer = true;
   337 }
   339 void
   340 ContentClientDoubleBuffered::CreateFrontBuffer(const nsIntRect& aBufferRect)
   341 {
   342   if (!CreateAndAllocateTextureClient(mFrontClient, TEXTURE_ON_BLACK) ||
   343       !AddTextureClient(mFrontClient)) {
   344     AbortTextureClientCreation();
   345     return;
   346   }
   347   if (mTextureInfo.mTextureFlags & TEXTURE_COMPONENT_ALPHA) {
   348     if (!CreateAndAllocateTextureClient(mFrontClientOnWhite, TEXTURE_ON_WHITE) ||
   349         !AddTextureClient(mFrontClientOnWhite)) {
   350       AbortTextureClientCreation();
   351       return;
   352     }
   353   }
   355   mFrontBufferRect = aBufferRect;
   356   mFrontBufferRotation = nsIntPoint();
   357 }
   359 void
   360 ContentClientDoubleBuffered::DestroyFrontBuffer()
   361 {
   362   MOZ_ASSERT(mFrontClient);
   364   mOldTextures.AppendElement(mFrontClient);
   365   mFrontClient = nullptr;
   366   if (mFrontClientOnWhite) {
   367     mOldTextures.AppendElement(mFrontClientOnWhite);
   368     mFrontClientOnWhite = nullptr;
   369   }
   370 }
   372 void
   373 ContentClientDoubleBuffered::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion)
   374 {
   375   mFrontUpdatedRegion = aFrontUpdatedRegion;
   377   RefPtr<TextureClient> oldBack = mTextureClient;
   378   mTextureClient = mFrontClient;
   379   mFrontClient = oldBack;
   381   oldBack = mTextureClientOnWhite;
   382   mTextureClientOnWhite = mFrontClientOnWhite;
   383   mFrontClientOnWhite = oldBack;
   385   nsIntRect oldBufferRect = mBufferRect;
   386   mBufferRect = mFrontBufferRect;
   387   mFrontBufferRect = oldBufferRect;
   389   nsIntPoint oldBufferRotation = mBufferRotation;
   390   mBufferRotation = mFrontBufferRotation;
   391   mFrontBufferRotation = oldBufferRotation;
   393   MOZ_ASSERT(mFrontClient);
   395   ContentClientRemoteBuffer::SwapBuffers(aFrontUpdatedRegion);
   396 }
   398 void
   399 ContentClientDoubleBuffered::BeginPaint()
   400 {
   401   ContentClientRemoteBuffer::BeginPaint();
   403   mIsNewBuffer = false;
   405   if (!mFrontAndBackBufferDiffer) {
   406     return;
   407   }
   409   if (mDidSelfCopy) {
   410     // We can't easily draw our front buffer into us, since we're going to be
   411     // copying stuff around anyway it's easiest if we just move our situation
   412     // to non-rotated while we're at it. If this situation occurs we'll have
   413     // hit a self-copy path in PaintThebes before as well anyway.
   414     mBufferRect.MoveTo(mFrontBufferRect.TopLeft());
   415     mBufferRotation = nsIntPoint();
   416     return;
   417   }
   418   mBufferRect = mFrontBufferRect;
   419   mBufferRotation = mFrontBufferRotation;
   420 }
   422 // Sync front/back buffers content
   423 // After executing, the new back buffer has the same (interesting) pixels as
   424 // the new front buffer, and mValidRegion et al. are correct wrt the new
   425 // back buffer (i.e. as they were for the old back buffer)
   426 void
   427 ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
   428 {
   429   if (mTextureClient) {
   430     DebugOnly<bool> locked = mTextureClient->Lock(OPEN_READ_WRITE);
   431     MOZ_ASSERT(locked);
   432   }
   433   if (mTextureClientOnWhite) {
   434     DebugOnly<bool> locked = mTextureClientOnWhite->Lock(OPEN_READ_WRITE);
   435     MOZ_ASSERT(locked);
   436   }
   438   if (!mFrontAndBackBufferDiffer) {
   439     MOZ_ASSERT(!mDidSelfCopy, "If we have to copy the world, then our buffers are different, right?");
   440     return;
   441   }
   442   MOZ_ASSERT(mFrontClient);
   444   MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>",
   445                   this,
   446                   mFrontUpdatedRegion.GetBounds().x,
   447                   mFrontUpdatedRegion.GetBounds().y,
   448                   mFrontUpdatedRegion.GetBounds().width,
   449                   mFrontUpdatedRegion.GetBounds().height));
   451   mFrontAndBackBufferDiffer = false;
   453   nsIntRegion updateRegion = mFrontUpdatedRegion;
   454   if (mDidSelfCopy) {
   455     mDidSelfCopy = false;
   456     updateRegion = mBufferRect;
   457   }
   459   // No point in sync'ing what we are going to draw over anyway. And if there is
   460   // nothing to sync at all, there is nothing to do and we can go home early.
   461   updateRegion.Sub(updateRegion, aRegionToDraw);
   462   if (updateRegion.IsEmpty()) {
   463     return;
   464   }
   466   // We need to ensure that we lock these two buffers in the same
   467   // order as the compositor to prevent deadlocks.
   468   if (!mFrontClient->Lock(OPEN_READ_ONLY)) {
   469     return;
   470   }
   471   if (mFrontClientOnWhite &&
   472       !mFrontClientOnWhite->Lock(OPEN_READ_ONLY)) {
   473     mFrontClient->Unlock();
   474     return;
   475   }
   476   {
   477     // Restrict the DrawTargets and frontBuffer to a scope to make
   478     // sure there is no more external references to the DrawTargets
   479     // when we Unlock the TextureClients.
   480     RefPtr<DrawTarget> dt = mFrontClient->GetAsDrawTarget();
   481     RefPtr<DrawTarget> dtOnWhite = mFrontClientOnWhite
   482       ? mFrontClientOnWhite->GetAsDrawTarget()
   483       : nullptr;
   484     RotatedBuffer frontBuffer(dt,
   485                               dtOnWhite,
   486                               mFrontBufferRect,
   487                               mFrontBufferRotation);
   488     UpdateDestinationFrom(frontBuffer, updateRegion);
   489   }
   491   mFrontClient->Unlock();
   492   if (mFrontClientOnWhite) {
   493     mFrontClientOnWhite->Unlock();
   494   }
   495 }
   497 void
   498 ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
   499                                                    const nsIntRegion& aUpdateRegion)
   500 {
   501   DrawIterator iter;
   502   while (DrawTarget* destDT =
   503     BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK, &iter)) {
   504     bool isClippingCheap = IsClippingCheap(destDT, iter.mDrawRegion);
   505     if (isClippingCheap) {
   506       gfxUtils::ClipToRegion(destDT, iter.mDrawRegion);
   507     }
   509     aSource.DrawBufferWithRotation(destDT, BUFFER_BLACK, 1.0, CompositionOp::OP_SOURCE);
   510     if (isClippingCheap) {
   511       destDT->PopClip();
   512     }
   513     // Flush the destination before the sources become inaccessible (Unlock).
   514     destDT->Flush();
   515     ReturnDrawTargetToBuffer(destDT);
   516   }
   518   if (aSource.HaveBufferOnWhite()) {
   519     MOZ_ASSERT(HaveBufferOnWhite());
   520     DrawIterator whiteIter;
   521     while (DrawTarget* destDT =
   522       BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE, &whiteIter)) {
   523       bool isClippingCheap = IsClippingCheap(destDT, whiteIter.mDrawRegion);
   524       if (isClippingCheap) {
   525         gfxUtils::ClipToRegion(destDT, whiteIter.mDrawRegion);
   526       }
   528       aSource.DrawBufferWithRotation(destDT, BUFFER_WHITE, 1.0, CompositionOp::OP_SOURCE);
   529       if (isClippingCheap) {
   530         destDT->PopClip();
   531       }
   532       // Flush the destination before the sources become inaccessible (Unlock).
   533       destDT->Flush();
   534       ReturnDrawTargetToBuffer(destDT);
   535     }
   536   }
   537 }
   539 void
   540 ContentClientSingleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
   541 {
   542   if (mTextureClient) {
   543     DebugOnly<bool> locked = mTextureClient->Lock(OPEN_READ_WRITE);
   544     MOZ_ASSERT(locked);
   545   }
   546   if (mTextureClientOnWhite) {
   547     DebugOnly<bool> locked = mTextureClientOnWhite->Lock(OPEN_READ_WRITE);
   548     MOZ_ASSERT(locked);
   549   }
   550 }
   552 static void
   553 WrapRotationAxis(int32_t* aRotationPoint, int32_t aSize)
   554 {
   555   if (*aRotationPoint < 0) {
   556     *aRotationPoint += aSize;
   557   } else if (*aRotationPoint >= aSize) {
   558     *aRotationPoint -= aSize;
   559   }
   560 }
   562 static void
   563 FillSurface(DrawTarget* aDT, const nsIntRegion& aRegion,
   564             const nsIntPoint& aOffset, const gfxRGBA& aColor)
   565 {
   566   nsIntRegionRectIterator iter(aRegion);
   567   const nsIntRect* r;
   568   while ((r = iter.Next()) != nullptr) {
   569     aDT->FillRect(Rect(r->x - aOffset.x, r->y - aOffset.y,
   570                        r->width, r->height),
   571                   ColorPattern(ToColor(aColor)));
   572   }
   573 }
   575 RotatedContentBuffer::PaintState
   576 ContentClientIncremental::BeginPaintBuffer(ThebesLayer* aLayer,
   577                                            uint32_t aFlags)
   578 {
   579   mTextureInfo.mDeprecatedTextureHostFlags = 0;
   580   PaintState result;
   581   // We need to disable rotation if we're going to be resampled when
   582   // drawing, because we might sample across the rotation boundary.
   583   bool canHaveRotation =  !(aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE);
   585   nsIntRegion validRegion = aLayer->GetValidRegion();
   587   bool canUseOpaqueSurface = aLayer->CanUseOpaqueSurface();
   588   ContentType contentType =
   589     canUseOpaqueSurface ? gfxContentType::COLOR :
   590                           gfxContentType::COLOR_ALPHA;
   592   SurfaceMode mode;
   593   nsIntRegion neededRegion;
   594   bool canReuseBuffer;
   595   nsIntRect destBufferRect;
   597   while (true) {
   598     mode = aLayer->GetSurfaceMode();
   599     neededRegion = aLayer->GetVisibleRegion();
   600     // If we're going to resample, we need a buffer that's in clamp mode.
   601     canReuseBuffer = neededRegion.GetBounds().Size() <= mBufferRect.Size() &&
   602       mHasBuffer &&
   603       (!(aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE) ||
   604        !(mTextureInfo.mTextureFlags & TEXTURE_ALLOW_REPEAT));
   606     if (canReuseBuffer) {
   607       if (mBufferRect.Contains(neededRegion.GetBounds())) {
   608         // We don't need to adjust mBufferRect.
   609         destBufferRect = mBufferRect;
   610       } else {
   611         // The buffer's big enough but doesn't contain everything that's
   612         // going to be visible. We'll move it.
   613         destBufferRect = nsIntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size());
   614       }
   615     } else {
   616       destBufferRect = neededRegion.GetBounds();
   617     }
   619     if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
   620       if (!gfxPrefs::ComponentAlphaEnabled() ||
   621           !aLayer->GetParent() ||
   622           !aLayer->GetParent()->SupportsComponentAlphaChildren()) {
   623         mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
   624       } else {
   625         contentType = gfxContentType::COLOR;
   626       }
   627     }
   629     if ((aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE) &&
   630         (!neededRegion.GetBounds().IsEqualInterior(destBufferRect) ||
   631          neededRegion.GetNumRects() > 1)) {
   632       // The area we add to neededRegion might not be painted opaquely
   633       if (mode == SurfaceMode::SURFACE_OPAQUE) {
   634         contentType = gfxContentType::COLOR_ALPHA;
   635         mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
   636       }
   637       // For component alpha layers, we leave contentType as gfxContentType::COLOR.
   639       // We need to validate the entire buffer, to make sure that only valid
   640       // pixels are sampled
   641       neededRegion = destBufferRect;
   642     }
   644     if (mHasBuffer &&
   645         (mContentType != contentType ||
   646          (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != mHasBufferOnWhite)) {
   647       // We're effectively clearing the valid region, so we need to draw
   648       // the entire needed region now.
   649       result.mRegionToInvalidate = aLayer->GetValidRegion();
   650       validRegion.SetEmpty();
   651       mHasBuffer = false;
   652       mHasBufferOnWhite = false;
   653       mBufferRect.SetRect(0, 0, 0, 0);
   654       mBufferRotation.MoveTo(0, 0);
   655       // Restart decision process with the cleared buffer. We can only go
   656       // around the loop one more iteration, since mTexImage is null now.
   657       continue;
   658     }
   660     break;
   661   }
   663   result.mRegionToDraw.Sub(neededRegion, validRegion);
   664   if (result.mRegionToDraw.IsEmpty())
   665     return result;
   667   if (destBufferRect.width > mForwarder->GetMaxTextureSize() ||
   668       destBufferRect.height > mForwarder->GetMaxTextureSize()) {
   669     return result;
   670   }
   672   // BlitTextureImage depends on the FBO texture target being
   673   // TEXTURE_2D.  This isn't the case on some older X1600-era Radeons.
   674   if (!mForwarder->SupportsTextureBlitting() ||
   675       !mForwarder->SupportsPartialUploads()) {
   676     result.mRegionToDraw = neededRegion;
   677     validRegion.SetEmpty();
   678     mHasBuffer = false;
   679     mHasBufferOnWhite = false;
   680     mBufferRect.SetRect(0, 0, 0, 0);
   681     mBufferRotation.MoveTo(0, 0);
   682     canReuseBuffer = false;
   683   }
   685   nsIntRect drawBounds = result.mRegionToDraw.GetBounds();
   686   bool createdBuffer = false;
   688   uint32_t bufferFlags = canHaveRotation ? TEXTURE_ALLOW_REPEAT : 0;
   689   if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
   690     bufferFlags |= TEXTURE_COMPONENT_ALPHA;
   691   }
   692   if (canReuseBuffer) {
   693     nsIntRect keepArea;
   694     if (keepArea.IntersectRect(destBufferRect, mBufferRect)) {
   695       // Set mBufferRotation so that the pixels currently in mBuffer
   696       // will still be rendered in the right place when mBufferRect
   697       // changes to destBufferRect.
   698       nsIntPoint newRotation = mBufferRotation +
   699         (destBufferRect.TopLeft() - mBufferRect.TopLeft());
   700       WrapRotationAxis(&newRotation.x, mBufferRect.width);
   701       WrapRotationAxis(&newRotation.y, mBufferRect.height);
   702       NS_ASSERTION(nsIntRect(nsIntPoint(0,0), mBufferRect.Size()).Contains(newRotation),
   703                    "newRotation out of bounds");
   704       int32_t xBoundary = destBufferRect.XMost() - newRotation.x;
   705       int32_t yBoundary = destBufferRect.YMost() - newRotation.y;
   706       if ((drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) ||
   707           (drawBounds.y < yBoundary && yBoundary < drawBounds.YMost()) ||
   708           (newRotation != nsIntPoint(0,0) && !canHaveRotation)) {
   709         // The stuff we need to redraw will wrap around an edge of the
   710         // buffer, so we will need to do a self-copy
   711         // If mBufferRotation == nsIntPoint(0,0) we could do a real
   712         // self-copy but we're not going to do that in GL yet.
   713         // We can't do a real self-copy because the buffer is rotated.
   714         // So allocate a new buffer for the destination.
   715         destBufferRect = neededRegion.GetBounds();
   716         createdBuffer = true;
   717       } else {
   718         mBufferRect = destBufferRect;
   719         mBufferRotation = newRotation;
   720       }
   721     } else {
   722       // No pixels are going to be kept. The whole visible region
   723       // will be redrawn, so we don't need to copy anything, so we don't
   724       // set destBuffer.
   725       mBufferRect = destBufferRect;
   726       mBufferRotation = nsIntPoint(0,0);
   727     }
   728   } else {
   729     // The buffer's not big enough, so allocate a new one
   730     createdBuffer = true;
   731   }
   732   NS_ASSERTION(!(aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE) ||
   733                destBufferRect == neededRegion.GetBounds(),
   734                "If we're resampling, we need to validate the entire buffer");
   736   if (!createdBuffer && !mHasBuffer) {
   737     return result;
   738   }
   740   if (createdBuffer) {
   741     if (mHasBuffer &&
   742         (mode != SurfaceMode::SURFACE_COMPONENT_ALPHA || mHasBufferOnWhite)) {
   743       mTextureInfo.mDeprecatedTextureHostFlags = TEXTURE_HOST_COPY_PREVIOUS;
   744     }
   746     mHasBuffer = true;
   747     if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
   748       mHasBufferOnWhite = true;
   749     }
   750     mBufferRect = destBufferRect;
   751     mBufferRotation = nsIntPoint(0,0);
   752     NotifyBufferCreated(contentType, bufferFlags);
   753   }
   755   NS_ASSERTION(canHaveRotation || mBufferRotation == nsIntPoint(0,0),
   756                "Rotation disabled, but we have nonzero rotation?");
   758   nsIntRegion invalidate;
   759   invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
   760   result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
   762   // If we do partial updates, we have to clip drawing to the regionToDraw.
   763   // If we don't clip, background images will be fillrect'd to the region correctly,
   764   // while text or lines will paint outside of the regionToDraw. This becomes apparent
   765   // with concave regions. Right now the scrollbars invalidate a narrow strip of the bar
   766   // although they never cover it. This leads to two draw rects, the narow strip and the actually
   767   // newly exposed area. It would be wise to fix this glitch in any way to have simpler
   768   // clip and draw regions.
   769   result.mClip = DrawRegionClip::DRAW;
   770   result.mMode = mode;
   772   return result;
   773 }
   775 DrawTarget*
   776 ContentClientIncremental::BorrowDrawTargetForPainting(const PaintState& aPaintState,
   777                                                       RotatedContentBuffer::DrawIterator* aIter)
   778 {
   779   if (aPaintState.mMode == SurfaceMode::SURFACE_NONE) {
   780     return nullptr;
   781   }
   783   if (aIter) {
   784     if (aIter->mCount++ > 0) {
   785       return nullptr;
   786     }
   787     aIter->mDrawRegion = aPaintState.mRegionToDraw;
   788   }
   790   DrawTarget* result = nullptr;
   792   nsIntRect drawBounds = aPaintState.mRegionToDraw.GetBounds();
   793   MOZ_ASSERT(!mLoanedDrawTarget);
   795   // BeginUpdate is allowed to modify the given region,
   796   // if it wants more to be repainted than we request.
   797   if (aPaintState.mMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
   798     nsIntRegion drawRegionCopy = aPaintState.mRegionToDraw;
   799     RefPtr<DrawTarget> onBlack = GetUpdateSurface(BUFFER_BLACK, drawRegionCopy);
   800     RefPtr<DrawTarget> onWhite = GetUpdateSurface(BUFFER_WHITE, aPaintState.mRegionToDraw);
   801     if (onBlack && onWhite) {
   802       NS_ASSERTION(aPaintState.mRegionToDraw == drawRegionCopy,
   803                    "BeginUpdate should always modify the draw region in the same way!");
   804       FillSurface(onBlack, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(0.0, 0.0, 0.0, 1.0));
   805       FillSurface(onWhite, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(1.0, 1.0, 1.0, 1.0));
   806       mLoanedDrawTarget = Factory::CreateDualDrawTarget(onBlack, onWhite);
   807     } else {
   808       mLoanedDrawTarget = nullptr;
   809     }
   810   } else {
   811     mLoanedDrawTarget = GetUpdateSurface(BUFFER_BLACK, aPaintState.mRegionToDraw);
   812   }
   813   if (!mLoanedDrawTarget) {
   814     NS_WARNING("unable to get context for update");
   815     return nullptr;
   816   }
   818   result = mLoanedDrawTarget;
   819   mLoanedTransform = mLoanedDrawTarget->GetTransform();
   820   mLoanedTransform.Translate(-drawBounds.x, -drawBounds.y);
   821   result->SetTransform(mLoanedTransform);
   822   mLoanedTransform.Translate(drawBounds.x, drawBounds.y);
   824   if (mContentType == gfxContentType::COLOR_ALPHA) {
   825     gfxUtils::ClipToRegion(result, aPaintState.mRegionToDraw);
   826     nsIntRect bounds = aPaintState.mRegionToDraw.GetBounds();
   827     result->ClearRect(Rect(bounds.x, bounds.y, bounds.width, bounds.height));
   828   }
   830   return result;
   831 }
   833 void
   834 ContentClientIncremental::Updated(const nsIntRegion& aRegionToDraw,
   835                                   const nsIntRegion& aVisibleRegion,
   836                                   bool aDidSelfCopy)
   837 {
   838   if (IsSurfaceDescriptorValid(mUpdateDescriptor)) {
   839     mForwarder->UpdateTextureIncremental(this,
   840                                          TextureFront,
   841                                          mUpdateDescriptor,
   842                                          aRegionToDraw,
   843                                          mBufferRect,
   844                                          mBufferRotation);
   845     mUpdateDescriptor = SurfaceDescriptor();
   846   }
   847   if (IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite)) {
   848     mForwarder->UpdateTextureIncremental(this,
   849                                          TextureOnWhiteFront,
   850                                          mUpdateDescriptorOnWhite,
   851                                          aRegionToDraw,
   852                                          mBufferRect,
   853                                          mBufferRotation);
   854     mUpdateDescriptorOnWhite = SurfaceDescriptor();
   855   }
   857 }
   859 TemporaryRef<DrawTarget>
   860 ContentClientIncremental::GetUpdateSurface(BufferType aType,
   861                                            const nsIntRegion& aUpdateRegion)
   862 {
   863   nsIntRect rgnSize = aUpdateRegion.GetBounds();
   864   if (!mBufferRect.Contains(rgnSize)) {
   865     NS_ERROR("update outside of image");
   866     return nullptr;
   867   }
   868   SurfaceDescriptor desc;
   869   if (!mForwarder->AllocSurfaceDescriptor(rgnSize.Size().ToIntSize(),
   870                                           mContentType,
   871                                           &desc)) {
   872     NS_WARNING("creating SurfaceDescriptor failed!");
   873     Clear();
   874     return nullptr;
   875   }
   877   if (aType == BUFFER_BLACK) {
   878     MOZ_ASSERT(!IsSurfaceDescriptorValid(mUpdateDescriptor));
   879     mUpdateDescriptor = desc;
   880   } else {
   881     MOZ_ASSERT(!IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite));
   882     MOZ_ASSERT(aType == BUFFER_WHITE);
   883     mUpdateDescriptorOnWhite = desc;
   884   }
   886   return GetDrawTargetForDescriptor(desc, gfx::BackendType::COREGRAPHICS);
   887 }
   889 }
   890 }

mercurial