gfx/layers/basic/BasicLayerManager.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; 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 <stdint.h>                     // for uint32_t
     7 #include <stdlib.h>                     // for rand, RAND_MAX
     8 #include <sys/types.h>                  // for int32_t
     9 #include "BasicContainerLayer.h"        // for BasicContainerLayer
    10 #include "BasicLayersImpl.h"            // for ToData, BasicReadbackLayer, etc
    11 #include "GeckoProfiler.h"              // for PROFILER_LABEL
    12 #include "ImageContainer.h"             // for ImageFactory
    13 #include "Layers.h"                     // for Layer, ContainerLayer, etc
    14 #include "ReadbackLayer.h"              // for ReadbackLayer
    15 #include "ReadbackProcessor.h"          // for ReadbackProcessor
    16 #include "RenderTrace.h"                // for RenderTraceLayers, etc
    17 #include "basic/BasicImplData.h"        // for BasicImplData
    18 #include "basic/BasicLayers.h"          // for BasicLayerManager, etc
    19 #include "gfx3DMatrix.h"                // for gfx3DMatrix
    20 #include "gfxASurface.h"                // for gfxASurface, etc
    21 #include "gfxCachedTempSurface.h"       // for gfxCachedTempSurface
    22 #include "gfxColor.h"                   // for gfxRGBA
    23 #include "gfxContext.h"                 // for gfxContext, etc
    24 #include "gfxImageSurface.h"            // for gfxImageSurface
    25 #include "gfxMatrix.h"                  // for gfxMatrix
    26 #include "gfxPlatform.h"                // for gfxPlatform
    27 #include "gfxPrefs.h"                   // for gfxPrefs
    28 #include "gfxPoint.h"                   // for gfxIntSize, gfxPoint
    29 #include "gfxRect.h"                    // for gfxRect
    30 #include "gfxUtils.h"                   // for gfxUtils
    31 #include "gfx2DGlue.h"                  // for thebes --> moz2d transition
    32 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
    33 #include "mozilla/WidgetUtils.h"        // for ScreenRotation
    34 #include "mozilla/gfx/2D.h"             // for DrawTarget
    35 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
    36 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
    37 #include "mozilla/gfx/Matrix.h"         // for Matrix
    38 #include "mozilla/gfx/Rect.h"           // for IntRect, Rect
    39 #include "mozilla/layers/LayersTypes.h"  // for BufferMode::BUFFER_NONE, etc
    40 #include "mozilla/mozalloc.h"           // for operator new
    41 #include "nsAutoPtr.h"                  // for nsRefPtr
    42 #include "nsCOMPtr.h"                   // for already_AddRefed
    43 #include "nsDebug.h"                    // for NS_ASSERTION, etc
    44 #include "nsISupportsImpl.h"            // for gfxContext::Release, etc
    45 #include "nsPoint.h"                    // for nsIntPoint
    46 #include "nsRect.h"                     // for nsIntRect
    47 #include "nsRegion.h"                   // for nsIntRegion, etc
    48 #include "nsTArray.h"                   // for nsAutoTArray
    49 #define PIXMAN_DONT_DEFINE_STDINT
    50 #include "pixman.h"                     // for pixman_f_transform, etc
    52 class nsIWidget;
    54 using namespace mozilla::dom;
    55 using namespace mozilla::gfx;
    57 namespace mozilla {
    58 namespace layers {
    60 /**
    61  * Clips to the smallest device-pixel-aligned rectangle containing aRect
    62  * in user space.
    63  * Returns true if the clip is "perfect", i.e. we actually clipped exactly to
    64  * aRect.
    65  */
    66 static bool
    67 ClipToContain(gfxContext* aContext, const nsIntRect& aRect)
    68 {
    69   gfxRect userRect(aRect.x, aRect.y, aRect.width, aRect.height);
    70   gfxRect deviceRect = aContext->UserToDevice(userRect);
    71   deviceRect.RoundOut();
    73   gfxMatrix currentMatrix = aContext->CurrentMatrix();
    74   aContext->IdentityMatrix();
    75   aContext->NewPath();
    76   aContext->Rectangle(deviceRect);
    77   aContext->Clip();
    78   aContext->SetMatrix(currentMatrix);
    80   return aContext->DeviceToUser(deviceRect).IsEqualInterior(userRect);
    81 }
    83 already_AddRefed<gfxContext>
    84 BasicLayerManager::PushGroupForLayer(gfxContext* aContext, Layer* aLayer,
    85                                      const nsIntRegion& aRegion,
    86                                      bool* aNeedsClipToVisibleRegion)
    87 {
    88   // If we need to call PushGroup, we should clip to the smallest possible
    89   // area first to minimize the size of the temporary surface.
    90   bool didCompleteClip = ClipToContain(aContext, aRegion.GetBounds());
    92   nsRefPtr<gfxContext> result;
    93   if (aLayer->CanUseOpaqueSurface() &&
    94       ((didCompleteClip && aRegion.GetNumRects() == 1) ||
    95        !aContext->CurrentMatrix().HasNonIntegerTranslation())) {
    96     // If the layer is opaque in its visible region we can push a gfxContentType::COLOR
    97     // group. We need to make sure that only pixels inside the layer's visible
    98     // region are copied back to the destination. Remember if we've already
    99     // clipped precisely to the visible region.
   100     *aNeedsClipToVisibleRegion = !didCompleteClip || aRegion.GetNumRects() > 1;
   101     MOZ_ASSERT(!aContext->IsCairo());
   102     result = PushGroupWithCachedSurface(aContext, gfxContentType::COLOR);
   103   } else {
   104     *aNeedsClipToVisibleRegion = false;
   105     result = aContext;
   106     if (aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) {
   107       aContext->PushGroupAndCopyBackground(gfxContentType::COLOR_ALPHA);
   108     } else {
   109       aContext->PushGroup(gfxContentType::COLOR_ALPHA);
   110     }
   111   }
   112   return result.forget();
   113 }
   115 static nsIntRect
   116 ToOutsideIntRect(const gfxRect &aRect)
   117 {
   118   gfxRect r = aRect;
   119   r.RoundOut();
   120   return nsIntRect(r.X(), r.Y(), r.Width(), r.Height());
   121 }
   123 static nsIntRect
   124 ToInsideIntRect(const gfxRect& aRect)
   125 {
   126   gfxRect r = aRect;
   127   r.RoundIn();
   128   return nsIntRect(r.X(), r.Y(), r.Width(), r.Height());
   129 }
   131 // A context helper for BasicLayerManager::PaintLayer() that holds all the
   132 // painting context together in a data structure so it can be easily passed
   133 // around. It also uses ensures that the Transform and Opaque rect are restored
   134 // to their former state on destruction.
   136 class PaintLayerContext {
   137 public:
   138   PaintLayerContext(gfxContext* aTarget, Layer* aLayer,
   139                     LayerManager::DrawThebesLayerCallback aCallback,
   140                     void* aCallbackData, ReadbackProcessor* aReadback)
   141    : mTarget(aTarget)
   142    , mTargetMatrixSR(aTarget)
   143    , mLayer(aLayer)
   144    , mCallback(aCallback)
   145    , mCallbackData(aCallbackData)
   146    , mReadback(aReadback)
   147    , mPushedOpaqueRect(false)
   148   {}
   150   ~PaintLayerContext()
   151   {
   152     // Matrix is restored by mTargetMatrixSR
   153     if (mPushedOpaqueRect)
   154     {
   155       ClearOpaqueRect();
   156     }
   157   }
   159   // Gets the effective transform and returns true if it is a 2D
   160   // transform.
   161   bool Setup2DTransform()
   162   {
   163     // Will return an identity matrix for 3d transforms.
   164     return mLayer->GetEffectiveTransform().CanDraw2D(&mTransform);
   165   }
   167   // Applies the effective transform if it's 2D. If it's a 3D transform then
   168   // it applies an identity.
   169   void Apply2DTransform()
   170   {
   171     mTarget->SetMatrix(ThebesMatrix(mTransform));
   172   }
   174   // Set the opaque rect to match the bounds of the visible region.
   175   void AnnotateOpaqueRect()
   176   {
   177     const nsIntRegion& visibleRegion = mLayer->GetEffectiveVisibleRegion();
   178     const nsIntRect& bounds = visibleRegion.GetBounds();
   180     if (mTarget->IsCairo()) {
   181       nsRefPtr<gfxASurface> currentSurface = mTarget->CurrentSurface();
   182       const gfxRect& targetOpaqueRect = currentSurface->GetOpaqueRect();
   184       // Try to annotate currentSurface with a region of pixels that have been
   185       // (or will be) painted opaque, if no such region is currently set.
   186       if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
   187           (mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
   188           !mTransform.HasNonAxisAlignedTransform()) {
   189         currentSurface->SetOpaqueRect(
   190             mTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)));
   191         mPushedOpaqueRect = true;
   192       }
   193     } else {
   194       DrawTarget *dt = mTarget->GetDrawTarget();
   195       const IntRect& targetOpaqueRect = dt->GetOpaqueRect();
   197       // Try to annotate currentSurface with a region of pixels that have been
   198       // (or will be) painted opaque, if no such region is currently set.
   199       if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
   200           (mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
   201           !mTransform.HasNonAxisAlignedTransform()) {
   203         gfx::Rect opaqueRect = dt->GetTransform().TransformBounds(
   204           gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height));
   205         opaqueRect.RoundIn();
   206         IntRect intOpaqueRect;
   207         if (opaqueRect.ToIntRect(&intOpaqueRect)) {
   208           mTarget->GetDrawTarget()->SetOpaqueRect(intOpaqueRect);
   209           mPushedOpaqueRect = true;
   210         }
   211       }
   212     }
   213   }
   215   // Clear the Opaque rect. Although this doesn't really restore it to it's
   216   // previous state it will happen on the exit path of the PaintLayer() so when
   217   // painting is complete the opaque rect qill be clear.
   218   void ClearOpaqueRect() {
   219     if (mTarget->IsCairo()) {
   220       nsRefPtr<gfxASurface> currentSurface = mTarget->CurrentSurface();
   221       currentSurface->SetOpaqueRect(gfxRect());
   222     } else {
   223       mTarget->GetDrawTarget()->SetOpaqueRect(IntRect());
   224     }
   225   }
   227   gfxContext* mTarget;
   228   gfxContextMatrixAutoSaveRestore mTargetMatrixSR;
   229   Layer* mLayer;
   230   LayerManager::DrawThebesLayerCallback mCallback;
   231   void* mCallbackData;
   232   ReadbackProcessor* mReadback;
   233   Matrix mTransform;
   234   bool mPushedOpaqueRect;
   235 };
   237 BasicLayerManager::BasicLayerManager(nsIWidget* aWidget) :
   238   mPhase(PHASE_NONE),
   239   mWidget(aWidget)
   240   , mDoubleBuffering(BufferMode::BUFFER_NONE), mUsingDefaultTarget(false)
   241   , mCachedSurfaceInUse(false)
   242   , mTransactionIncomplete(false)
   243   , mCompositorMightResample(false)
   244 {
   245   MOZ_COUNT_CTOR(BasicLayerManager);
   246   NS_ASSERTION(aWidget, "Must provide a widget");
   247 }
   249 BasicLayerManager::BasicLayerManager() :
   250   mPhase(PHASE_NONE),
   251   mWidget(nullptr)
   252   , mDoubleBuffering(BufferMode::BUFFER_NONE), mUsingDefaultTarget(false)
   253   , mCachedSurfaceInUse(false)
   254   , mTransactionIncomplete(false)
   255 {
   256   MOZ_COUNT_CTOR(BasicLayerManager);
   257 }
   259 BasicLayerManager::~BasicLayerManager()
   260 {
   261   NS_ASSERTION(!InTransaction(), "Died during transaction?");
   263   ClearCachedResources();
   265   mRoot = nullptr;
   267   MOZ_COUNT_DTOR(BasicLayerManager);
   268 }
   270 void
   271 BasicLayerManager::SetDefaultTarget(gfxContext* aContext)
   272 {
   273   NS_ASSERTION(!InTransaction(),
   274                "Must set default target outside transaction");
   275   mDefaultTarget = aContext;
   276 }
   278 void
   279 BasicLayerManager::SetDefaultTargetConfiguration(BufferMode aDoubleBuffering, ScreenRotation aRotation)
   280 {
   281   mDoubleBuffering = aDoubleBuffering;
   282 }
   284 void
   285 BasicLayerManager::BeginTransaction()
   286 {
   287   mInTransaction = true;
   288   mUsingDefaultTarget = true;
   289   BeginTransactionWithTarget(mDefaultTarget);
   290 }
   292 already_AddRefed<gfxContext>
   293 BasicLayerManager::PushGroupWithCachedSurface(gfxContext *aTarget,
   294                                               gfxContentType aContent)
   295 {
   296   nsRefPtr<gfxContext> ctx;
   297   // We can't cache Azure DrawTargets at this point.
   298   if (!mCachedSurfaceInUse && aTarget->IsCairo()) {
   299     gfxContextMatrixAutoSaveRestore saveMatrix(aTarget);
   300     aTarget->IdentityMatrix();
   302     nsRefPtr<gfxASurface> currentSurf = aTarget->CurrentSurface();
   303     gfxRect clip = aTarget->GetClipExtents();
   304     clip.RoundOut();
   306     ctx = mCachedSurface.Get(aContent, clip, currentSurf);
   308     if (ctx) {
   309       mCachedSurfaceInUse = true;
   310       /* Align our buffer for the original surface */
   311       ctx->SetMatrix(saveMatrix.Matrix());
   312       return ctx.forget();
   313     }
   314   }
   316   ctx = aTarget;
   317   ctx->PushGroup(aContent);
   318   return ctx.forget();
   319 }
   321 void
   322 BasicLayerManager::PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed)
   323 {
   324   if (!aTarget)
   325     return;
   326   if (aTarget->IsCairo()) {
   327     nsRefPtr<gfxASurface> current = aPushed->CurrentSurface();
   328     if (mCachedSurface.IsSurface(current)) {
   329       gfxContextMatrixAutoSaveRestore saveMatrix(aTarget);
   330       aTarget->IdentityMatrix();
   331       aTarget->SetSource(current);
   332       mCachedSurfaceInUse = false;
   333       return;
   334     }
   335   }
   336   aTarget->PopGroupToSource();
   337 }
   339 void
   340 BasicLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
   341 {
   342   mInTransaction = true;
   344 #ifdef MOZ_LAYERS_HAVE_LOG
   345   MOZ_LAYERS_LOG(("[----- BeginTransaction"));
   346   Log();
   347 #endif
   349   NS_ASSERTION(!InTransaction(), "Nested transactions not allowed");
   350   mPhase = PHASE_CONSTRUCTION;
   351   mTarget = aTarget;
   352 }
   354 static void
   355 TransformIntRect(nsIntRect& aRect, const Matrix& aMatrix,
   356                  nsIntRect (*aRoundMethod)(const gfxRect&))
   357 {
   358   Rect gr = Rect(aRect.x, aRect.y, aRect.width, aRect.height);
   359   gr = aMatrix.TransformBounds(gr);
   360   aRect = (*aRoundMethod)(ThebesRect(gr));
   361 }
   363 /**
   364  * This function assumes that GetEffectiveTransform transforms
   365  * all layers to the same coordinate system (the "root coordinate system").
   366  * It can't be used as is by accelerated layers because of intermediate surfaces.
   367  * This must set the hidden flag to true or false on *all* layers in the subtree.
   368  * It also sets the operator for all layers to "OVER", and call
   369  * SetDrawAtomically(false).
   370  * It clears mClipToVisibleRegion on all layers.
   371  * @param aClipRect the cliprect, in the root coordinate system. We assume
   372  * that any layer drawing is clipped to this rect. It is therefore not
   373  * allowed to add to the opaque region outside that rect.
   374  * @param aDirtyRect the dirty rect that will be painted, in the root
   375  * coordinate system. Layers outside this rect should be hidden.
   376  * @param aOpaqueRegion the opaque region covering aLayer, in the
   377  * root coordinate system.
   378  */
   379 enum {
   380     ALLOW_OPAQUE = 0x01,
   381 };
   382 static void
   383 MarkLayersHidden(Layer* aLayer, const nsIntRect& aClipRect,
   384                  const nsIntRect& aDirtyRect,
   385                  nsIntRegion& aOpaqueRegion,
   386                  uint32_t aFlags)
   387 {
   388   nsIntRect newClipRect(aClipRect);
   389   uint32_t newFlags = aFlags;
   391   // Allow aLayer or aLayer's descendants to cover underlying layers
   392   // only if it's opaque.
   393   if (aLayer->GetOpacity() != 1.0f) {
   394     newFlags &= ~ALLOW_OPAQUE;
   395   }
   397   {
   398     const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
   399     if (clipRect) {
   400       nsIntRect cr = *clipRect;
   401       // clipRect is in the container's coordinate system. Get it into the
   402       // global coordinate system.
   403       if (aLayer->GetParent()) {
   404         Matrix tr;
   405         if (aLayer->GetParent()->GetEffectiveTransform().CanDraw2D(&tr)) {
   406           // Clip rect is applied after aLayer's transform, i.e., in the coordinate
   407           // system of aLayer's parent.
   408           TransformIntRect(cr, tr, ToInsideIntRect);
   409         } else {
   410           cr.SetRect(0, 0, 0, 0);
   411         }
   412       }
   413       newClipRect.IntersectRect(newClipRect, cr);
   414     }
   415   }
   417   BasicImplData* data = ToData(aLayer);
   418   data->SetOperator(CompositionOp::OP_OVER);
   419   data->SetClipToVisibleRegion(false);
   420   data->SetDrawAtomically(false);
   422   if (!aLayer->AsContainerLayer()) {
   423     Matrix transform;
   424     if (!aLayer->GetEffectiveTransform().CanDraw2D(&transform)) {
   425       data->SetHidden(false);
   426       return;
   427     }
   429     nsIntRegion region = aLayer->GetEffectiveVisibleRegion();
   430     nsIntRect r = region.GetBounds();
   431     TransformIntRect(r, transform, ToOutsideIntRect);
   432     r.IntersectRect(r, aDirtyRect);
   433     data->SetHidden(aOpaqueRegion.Contains(r));
   435     // Allow aLayer to cover underlying layers only if aLayer's
   436     // content is opaque
   437     if ((aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
   438         (newFlags & ALLOW_OPAQUE)) {
   439       nsIntRegionRectIterator it(region);
   440       while (const nsIntRect* sr = it.Next()) {
   441         r = *sr;
   442         TransformIntRect(r, transform, ToInsideIntRect);
   444         r.IntersectRect(r, newClipRect);
   445         aOpaqueRegion.Or(aOpaqueRegion, r);
   446       }
   447     }
   448   } else {
   449     Layer* child = aLayer->GetLastChild();
   450     bool allHidden = true;
   451     for (; child; child = child->GetPrevSibling()) {
   452       MarkLayersHidden(child, newClipRect, aDirtyRect, aOpaqueRegion, newFlags);
   453       if (!ToData(child)->IsHidden()) {
   454         allHidden = false;
   455       }
   456     }
   457     data->SetHidden(allHidden);
   458   }
   459 }
   461 /**
   462  * This function assumes that GetEffectiveTransform transforms
   463  * all layers to the same coordinate system (the "root coordinate system").
   464  * MarkLayersHidden must be called before calling this.
   465  * @param aVisibleRect the rectangle of aLayer that is visible (i.e. not
   466  * clipped and in the dirty rect), in the root coordinate system.
   467  */
   468 static void
   469 ApplyDoubleBuffering(Layer* aLayer, const nsIntRect& aVisibleRect)
   470 {
   471   BasicImplData* data = ToData(aLayer);
   472   if (data->IsHidden())
   473     return;
   475   nsIntRect newVisibleRect(aVisibleRect);
   477   {
   478     const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
   479     if (clipRect) {
   480       nsIntRect cr = *clipRect;
   481       // clipRect is in the container's coordinate system. Get it into the
   482       // global coordinate system.
   483       if (aLayer->GetParent()) {
   484         Matrix tr;
   485         if (aLayer->GetParent()->GetEffectiveTransform().CanDraw2D(&tr)) {
   486           NS_ASSERTION(!ThebesMatrix(tr).HasNonIntegerTranslation(),
   487                        "Parent can only have an integer translation");
   488           cr += nsIntPoint(int32_t(tr._31), int32_t(tr._32));
   489         } else {
   490           NS_ERROR("Parent can only have an integer translation");
   491         }
   492       }
   493       newVisibleRect.IntersectRect(newVisibleRect, cr);
   494     }
   495   }
   497   BasicContainerLayer* container =
   498     static_cast<BasicContainerLayer*>(aLayer->AsContainerLayer());
   499   // Layers that act as their own backbuffers should be drawn to the destination
   500   // using OPERATOR_SOURCE to ensure that alpha values in a transparent window
   501   // are cleared. This can also be faster than OPERATOR_OVER.
   502   if (!container) {
   503     data->SetOperator(CompositionOp::OP_SOURCE);
   504     data->SetDrawAtomically(true);
   505   } else {
   506     if (container->UseIntermediateSurface() ||
   507         !container->ChildrenPartitionVisibleRegion(newVisibleRect)) {
   508       // We need to double-buffer this container.
   509       data->SetOperator(CompositionOp::OP_SOURCE);
   510       container->ForceIntermediateSurface();
   511     } else {
   512       // Tell the children to clip to their visible regions so our assumption
   513       // that they don't paint outside their visible regions is valid!
   514       for (Layer* child = aLayer->GetFirstChild(); child;
   515            child = child->GetNextSibling()) {
   516         ToData(child)->SetClipToVisibleRegion(true);
   517         ApplyDoubleBuffering(child, newVisibleRect);
   518       }
   519     }
   520   }
   521 }
   523 void
   524 BasicLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
   525                                   void* aCallbackData,
   526                                   EndTransactionFlags aFlags)
   527 {
   528   mInTransaction = false;
   530   EndTransactionInternal(aCallback, aCallbackData, aFlags);
   531 }
   533 void
   534 BasicLayerManager::AbortTransaction()
   535 {
   536   NS_ASSERTION(InConstruction(), "Should be in construction phase");
   537   mPhase = PHASE_NONE;
   538   mUsingDefaultTarget = false;
   539   mInTransaction = false;
   540 }
   542 static uint16_t sFrameCount = 0;
   543 void
   544 BasicLayerManager::RenderDebugOverlay()
   545 {
   546   if (!gfxPrefs::DrawFrameCounter()) {
   547     return;
   548   }
   550   profiler_set_frame_number(sFrameCount);
   552   uint16_t frameNumber = sFrameCount;
   553   const uint16_t bitWidth = 3;
   554   for (size_t i = 0; i < 16; i++) {
   556     gfxRGBA bitColor;
   557     if ((frameNumber >> i) & 0x1) {
   558       bitColor = gfxRGBA(0, 0, 0, 1.0);
   559     } else {
   560       bitColor = gfxRGBA(1.0, 1.0, 1.0, 1.0);
   561     }
   562     mTarget->NewPath();
   563     mTarget->SetColor(bitColor);
   564     mTarget->Rectangle(gfxRect(bitWidth*i, 0, bitWidth, bitWidth));
   565     mTarget->Fill();
   566   }
   567   // We intentionally overflow at 2^16.
   568   sFrameCount++;
   569 }
   571 bool
   572 BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
   573                                           void* aCallbackData,
   574                                           EndTransactionFlags aFlags)
   575 {
   576   PROFILER_LABEL("BasicLayerManager", "EndTransactionInternal");
   577 #ifdef MOZ_LAYERS_HAVE_LOG
   578   MOZ_LAYERS_LOG(("  ----- (beginning paint)"));
   579   Log();
   580 #endif
   582   NS_ASSERTION(InConstruction(), "Should be in construction phase");
   583   mPhase = PHASE_DRAWING;
   585   RenderTraceLayers(mRoot, "FF00");
   587   mTransactionIncomplete = false;
   589   if (mRoot) {
   590     // Need to do this before we call ApplyDoubleBuffering,
   591     // which depends on correct effective transforms
   592     mSnapEffectiveTransforms =
   593       mTarget ? !(mTarget->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING) : true;
   594     mRoot->ComputeEffectiveTransforms(mTarget ? Matrix4x4::From2D(ToMatrix(mTarget->CurrentMatrix())) : Matrix4x4());
   596     ToData(mRoot)->Validate(aCallback, aCallbackData);
   597     if (mRoot->GetMaskLayer()) {
   598       ToData(mRoot->GetMaskLayer())->Validate(aCallback, aCallbackData);
   599     }
   601     if (aFlags & END_NO_COMPOSITE) {
   602       // Apply pending tree updates before recomputing effective
   603       // properties.
   604       mRoot->ApplyPendingUpdatesToSubtree();
   605     }
   606   }
   608   if (mTarget && mRoot &&
   609       !(aFlags & END_NO_IMMEDIATE_REDRAW) &&
   610       !(aFlags & END_NO_COMPOSITE)) {
   611     nsIntRect clipRect;
   613     {
   614       gfxContextMatrixAutoSaveRestore save(mTarget);
   615       mTarget->SetMatrix(gfxMatrix());
   616       clipRect = ToOutsideIntRect(mTarget->GetClipExtents());
   617     }
   619     if (IsRetained()) {
   620       nsIntRegion region;
   621       MarkLayersHidden(mRoot, clipRect, clipRect, region, ALLOW_OPAQUE);
   622       if (mUsingDefaultTarget && mDoubleBuffering != BufferMode::BUFFER_NONE) {
   623         ApplyDoubleBuffering(mRoot, clipRect);
   624       }
   625     }
   627     PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
   628     if (!mRegionToClear.IsEmpty()) {
   629       AutoSetOperator op(mTarget, gfxContext::OPERATOR_CLEAR);
   630       nsIntRegionRectIterator iter(mRegionToClear);
   631       const nsIntRect *r;
   632       while ((r = iter.Next())) {
   633         mTarget->NewPath();
   634         mTarget->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
   635         mTarget->Fill();
   636       }
   637     }
   638     if (mWidget) {
   639       FlashWidgetUpdateArea(mTarget);
   640     }
   641     RenderDebugOverlay();
   642     RecordFrame();
   643     PostPresent();
   645     if (!mTransactionIncomplete) {
   646       // Clear out target if we have a complete transaction.
   647       mTarget = nullptr;
   648     }
   649   }
   651 #ifdef MOZ_LAYERS_HAVE_LOG
   652   Log();
   653   MOZ_LAYERS_LOG(("]----- EndTransaction"));
   654 #endif
   656   // Go back to the construction phase if the transaction isn't complete.
   657   // Layout will update the layer tree and call EndTransaction().
   658   mPhase = mTransactionIncomplete ? PHASE_CONSTRUCTION : PHASE_NONE;
   660   if (!mTransactionIncomplete) {
   661     // This is still valid if the transaction was incomplete.
   662     mUsingDefaultTarget = false;
   663   }
   665   NS_ASSERTION(!aCallback || !mTransactionIncomplete,
   666                "If callback is not null, transaction must be complete");
   668   // XXX - We should probably assert here that for an incomplete transaction
   669   // out target is the default target.
   671   return !mTransactionIncomplete;
   672 }
   674 void
   675 BasicLayerManager::FlashWidgetUpdateArea(gfxContext *aContext)
   676 {
   677   if (gfxPrefs::WidgetUpdateFlashing()) {
   678     float r = float(rand()) / RAND_MAX;
   679     float g = float(rand()) / RAND_MAX;
   680     float b = float(rand()) / RAND_MAX;
   681     aContext->SetColor(gfxRGBA(r, g, b, 0.2));
   682     aContext->Paint();
   683   }
   684 }
   686 bool
   687 BasicLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
   688 {
   689   mInTransaction = false;
   691   if (!mRoot) {
   692     return false;
   693   }
   695   return EndTransactionInternal(nullptr, nullptr, aFlags);
   696 }
   698 void
   699 BasicLayerManager::SetRoot(Layer* aLayer)
   700 {
   701   NS_ASSERTION(aLayer, "Root can't be null");
   702   NS_ASSERTION(aLayer->Manager() == this, "Wrong manager");
   703   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   704   mRoot = aLayer;
   705 }
   707 static pixman_transform
   708 BasicLayerManager_Matrix3DToPixman(const gfx3DMatrix& aMatrix)
   709 {
   710   pixman_f_transform transform;
   712   transform.m[0][0] = aMatrix._11;
   713   transform.m[0][1] = aMatrix._21;
   714   transform.m[0][2] = aMatrix._41;
   715   transform.m[1][0] = aMatrix._12;
   716   transform.m[1][1] = aMatrix._22;
   717   transform.m[1][2] = aMatrix._42;
   718   transform.m[2][0] = aMatrix._14;
   719   transform.m[2][1] = aMatrix._24;
   720   transform.m[2][2] = aMatrix._44;
   722   pixman_transform result;
   723   pixman_transform_from_pixman_f_transform(&result, &transform);
   725   return result;
   726 }
   728 static void
   729 PixmanTransform(const gfxImageSurface* aDest,
   730                 RefPtr<DataSourceSurface> aSrc,
   731                 const gfx3DMatrix& aTransform,
   732                 gfxPoint aDestOffset)
   733 {
   734   IntSize destSize = ToIntSize(aDest->GetSize());
   735   pixman_image_t* dest = pixman_image_create_bits(aDest->Format() == gfxImageFormat::ARGB32 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
   736                                                   destSize.width,
   737                                                   destSize.height,
   738                                                   (uint32_t*)aDest->Data(),
   739                                                   aDest->Stride());
   741   IntSize srcSize = aSrc->GetSize();
   742   pixman_image_t* src = pixman_image_create_bits(aSrc->GetFormat() == SurfaceFormat::B8G8R8A8 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
   743                                                  srcSize.width,
   744                                                  srcSize.height,
   745                                                  (uint32_t*)aSrc->GetData(),
   746                                                  aSrc->Stride());
   748   NS_ABORT_IF_FALSE(src && dest, "Failed to create pixman images?");
   750   pixman_transform pixTransform = BasicLayerManager_Matrix3DToPixman(aTransform);
   751   pixman_transform pixTransformInverted;
   753   // If the transform is singular then nothing would be drawn anyway, return here
   754   if (!pixman_transform_invert(&pixTransformInverted, &pixTransform)) {
   755     return;
   756   }
   757   pixman_image_set_transform(src, &pixTransformInverted);
   759   pixman_image_composite32(PIXMAN_OP_SRC,
   760                            src,
   761                            nullptr,
   762                            dest,
   763                            aDestOffset.x,
   764                            aDestOffset.y,
   765                            0,
   766                            0,
   767                            0,
   768                            0,
   769                            destSize.width,
   770                            destSize.height);
   772   pixman_image_unref(dest);
   773   pixman_image_unref(src);
   774 }
   776 /**
   777  * Transform a surface using a gfx3DMatrix and blit to the destination if
   778  * it is efficient to do so.
   779  *
   780  * @param aSource       Source surface.
   781  * @param aDest         Desintation context.
   782  * @param aBounds       Area represented by aSource.
   783  * @param aTransform    Transformation matrix.
   784  * @param aDestRect     Output: rectangle in which to draw returned surface on aDest
   785  *                      (same size as aDest). Only filled in if this returns
   786  *                      a surface.
   787  * @return              Transformed surface
   788  */
   789 static already_AddRefed<gfxASurface>
   790 Transform3D(RefPtr<SourceSurface> aSource,
   791             gfxContext* aDest,
   792             const gfxRect& aBounds,
   793             const gfx3DMatrix& aTransform,
   794             gfxRect& aDestRect)
   795 {
   796   // Find the transformed rectangle of our layer.
   797   gfxRect offsetRect = aTransform.TransformBounds(aBounds);
   799   // Intersect the transformed layer with the destination rectangle.
   800   // This is in device space since we have an identity transform set on aTarget.
   801   aDestRect = aDest->GetClipExtents();
   802   aDestRect.IntersectRect(aDestRect, offsetRect);
   803   aDestRect.RoundOut();
   805   // Create a surface the size of the transformed object.
   806   nsRefPtr<gfxASurface> dest = aDest->CurrentSurface();
   807   nsRefPtr<gfxImageSurface> destImage = new gfxImageSurface(gfxIntSize(aDestRect.width,
   808                                                                        aDestRect.height),
   809                                                             gfxImageFormat::ARGB32);
   810   gfxPoint offset = aDestRect.TopLeft();
   812   // Include a translation to the correct origin.
   813   gfx3DMatrix translation = gfx3DMatrix::Translation(aBounds.x, aBounds.y, 0);
   815   // Transform the content and offset it such that the content begins at the origin.
   816   PixmanTransform(destImage, aSource->GetDataSurface(), translation * aTransform, offset);
   818   // If we haven't actually drawn to aDest then return our temporary image so
   819   // that the caller can do this.
   820   return destImage.forget();
   821 }
   823 void
   824 BasicLayerManager::PaintSelfOrChildren(PaintLayerContext& aPaintContext,
   825                                        gfxContext* aGroupTarget)
   826 {
   827   BasicImplData* data = ToData(aPaintContext.mLayer);
   829   /* Only paint ourself, or our children - This optimization relies on this! */
   830   Layer* child = aPaintContext.mLayer->GetFirstChild();
   831   if (!child) {
   832     if (aPaintContext.mLayer->AsThebesLayer()) {
   833       data->PaintThebes(aGroupTarget, aPaintContext.mLayer->GetMaskLayer(),
   834           aPaintContext.mCallback, aPaintContext.mCallbackData,
   835           aPaintContext.mReadback);
   836     } else {
   837       data->Paint(aGroupTarget->GetDrawTarget(),
   838                   aGroupTarget->GetDeviceOffset(),
   839                   aPaintContext.mLayer->GetMaskLayer());
   840     }
   841   } else {
   842     ReadbackProcessor readback;
   843     ContainerLayer* container =
   844         static_cast<ContainerLayer*>(aPaintContext.mLayer);
   845     if (IsRetained()) {
   846       readback.BuildUpdates(container);
   847     }
   848     nsAutoTArray<Layer*, 12> children;
   849     container->SortChildrenBy3DZOrder(children);
   850     for (uint32_t i = 0; i < children.Length(); i++) {
   851       PaintLayer(aGroupTarget, children.ElementAt(i), aPaintContext.mCallback,
   852           aPaintContext.mCallbackData, &readback);
   853       if (mTransactionIncomplete)
   854         break;
   855     }
   856   }
   857 }
   859 void
   860 BasicLayerManager::FlushGroup(PaintLayerContext& aPaintContext, bool aNeedsClipToVisibleRegion)
   861 {
   862   // If we're doing our own double-buffering, we need to avoid drawing
   863   // the results of an incomplete transaction to the destination surface ---
   864   // that could cause flicker. Double-buffering is implemented using a
   865   // temporary surface for one or more container layers, so we need to stop
   866   // those temporary surfaces from being composited to aTarget.
   867   // ApplyDoubleBuffering guarantees that this container layer can't
   868   // intersect any other leaf layers, so if the transaction is not yet marked
   869   // incomplete, the contents of this container layer are the final contents
   870   // for the window.
   871   if (!mTransactionIncomplete) {
   872     if (aNeedsClipToVisibleRegion) {
   873       gfxUtils::ClipToRegion(aPaintContext.mTarget,
   874                              aPaintContext.mLayer->GetEffectiveVisibleRegion());
   875     }
   877     CompositionOp op = GetEffectiveOperator(aPaintContext.mLayer);
   878     AutoSetOperator setOperator(aPaintContext.mTarget, ThebesOp(op));
   880     PaintWithMask(aPaintContext.mTarget, aPaintContext.mLayer->GetEffectiveOpacity(),
   881                   aPaintContext.mLayer->GetMaskLayer());
   882   }
   883 }
   885 void
   886 BasicLayerManager::PaintLayer(gfxContext* aTarget,
   887                               Layer* aLayer,
   888                               DrawThebesLayerCallback aCallback,
   889                               void* aCallbackData,
   890                               ReadbackProcessor* aReadback)
   891 {
   892   PROFILER_LABEL("BasicLayerManager", "PaintLayer");
   893   PaintLayerContext paintLayerContext(aTarget, aLayer, aCallback, aCallbackData, aReadback);
   895   // Don't attempt to paint layers with a singular transform, cairo will
   896   // just throw an error.
   897   if (aLayer->GetEffectiveTransform().IsSingular()) {
   898     return;
   899   }
   901   RenderTraceScope trace("BasicLayerManager::PaintLayer", "707070");
   903   const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
   904   BasicContainerLayer* container =
   905     static_cast<BasicContainerLayer*>(aLayer->AsContainerLayer());
   906   bool needsGroup = container &&
   907                     container->UseIntermediateSurface();
   908   BasicImplData* data = ToData(aLayer);
   909   bool needsClipToVisibleRegion =
   910     data->GetClipToVisibleRegion() && !aLayer->AsThebesLayer();
   911   NS_ASSERTION(needsGroup || !container ||
   912                container->GetOperator() == CompositionOp::OP_OVER,
   913                "non-OVER operator should have forced UseIntermediateSurface");
   914   NS_ASSERTION(!container || !aLayer->GetMaskLayer() ||
   915                container->UseIntermediateSurface(),
   916                "ContainerLayer with mask layer should force UseIntermediateSurface");
   918   gfxContextAutoSaveRestore contextSR;
   919   gfxMatrix transform;
   920   // Will return an identity matrix for 3d transforms, and is handled separately below.
   921   bool is2D = paintLayerContext.Setup2DTransform();
   922   NS_ABORT_IF_FALSE(is2D || needsGroup || !aLayer->GetFirstChild(), "Must PushGroup for 3d transforms!");
   924   bool needsSaveRestore =
   925     needsGroup || clipRect || needsClipToVisibleRegion || !is2D;
   926   if (needsSaveRestore) {
   927     contextSR.SetContext(aTarget);
   929     if (clipRect) {
   930       aTarget->NewPath();
   931       aTarget->SnappedRectangle(gfxRect(clipRect->x, clipRect->y, clipRect->width, clipRect->height));
   932       aTarget->Clip();
   933     }
   934   }
   936   paintLayerContext.Apply2DTransform();
   938   const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
   939   // If needsGroup is true, we'll clip to the visible region after we've popped the group
   940   if (needsClipToVisibleRegion && !needsGroup) {
   941     gfxUtils::ClipToRegion(aTarget, visibleRegion);
   942     // Don't need to clip to visible region again
   943     needsClipToVisibleRegion = false;
   944   }
   946   if (is2D) {
   947     paintLayerContext.AnnotateOpaqueRect();
   948   }
   950   bool clipIsEmpty = !aTarget || aTarget->GetClipExtents().IsEmpty();
   951   if (clipIsEmpty) {
   952     PaintSelfOrChildren(paintLayerContext, aTarget);
   953     return;
   954   }
   956   if (is2D) {
   957     if (needsGroup) {
   958       nsRefPtr<gfxContext> groupTarget = PushGroupForLayer(aTarget, aLayer, aLayer->GetEffectiveVisibleRegion(),
   959                                       &needsClipToVisibleRegion);
   960       PaintSelfOrChildren(paintLayerContext, groupTarget);
   961       PopGroupToSourceWithCachedSurface(aTarget, groupTarget);
   962       FlushGroup(paintLayerContext, needsClipToVisibleRegion);
   963     } else {
   964       PaintSelfOrChildren(paintLayerContext, aTarget);
   965     }
   966   } else {
   967     const nsIntRect& bounds = visibleRegion.GetBounds();
   968     RefPtr<DrawTarget> untransformedDT =
   969       gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(bounds.width, bounds.height),
   970                                                                    SurfaceFormat::B8G8R8A8);
   971     if (!untransformedDT) {
   972       return;
   973     }
   975     nsRefPtr<gfxContext> groupTarget = new gfxContext(untransformedDT,
   976                                                       Point(bounds.x, bounds.y));
   978     PaintSelfOrChildren(paintLayerContext, groupTarget);
   980     // Temporary fast fix for bug 725886
   981     // Revert these changes when 725886 is ready
   982     NS_ABORT_IF_FALSE(untransformedDT,
   983                       "We should always allocate an untransformed surface with 3d transforms!");
   984     gfxRect destRect;
   985 #ifdef DEBUG
   986     if (aLayer->GetDebugColorIndex() != 0) {
   987       gfxRGBA  color((aLayer->GetDebugColorIndex() & 1) ? 1.0 : 0.0,
   988                      (aLayer->GetDebugColorIndex() & 2) ? 1.0 : 0.0,
   989                      (aLayer->GetDebugColorIndex() & 4) ? 1.0 : 0.0,
   990                      1.0);
   992       nsRefPtr<gfxContext> temp = new gfxContext(untransformedDT, Point(bounds.x, bounds.y));
   993       temp->SetColor(color);
   994       temp->Paint();
   995     }
   996 #endif
   997     gfx3DMatrix effectiveTransform;
   998     gfx::To3DMatrix(aLayer->GetEffectiveTransform(), effectiveTransform);
   999     nsRefPtr<gfxASurface> result =
  1000       Transform3D(untransformedDT->Snapshot(), aTarget, bounds,
  1001                   effectiveTransform, destRect);
  1003     if (result) {
  1004       aTarget->SetSource(result, destRect.TopLeft());
  1005       // Azure doesn't support EXTEND_NONE, so to avoid extending the edges
  1006       // of the source surface out to the current clip region, clip to
  1007       // the rectangle of the result surface now.
  1008       aTarget->NewPath();
  1009       aTarget->SnappedRectangle(destRect);
  1010       aTarget->Clip();
  1011       FlushGroup(paintLayerContext, needsClipToVisibleRegion);
  1016 void
  1017 BasicLayerManager::ClearCachedResources(Layer* aSubtree)
  1019   MOZ_ASSERT(!aSubtree || aSubtree->Manager() == this);
  1020   if (aSubtree) {
  1021     ClearLayer(aSubtree);
  1022   } else if (mRoot) {
  1023     ClearLayer(mRoot);
  1025   mCachedSurface.Expire();
  1027 void
  1028 BasicLayerManager::ClearLayer(Layer* aLayer)
  1030   ToData(aLayer)->ClearCachedResources();
  1031   for (Layer* child = aLayer->GetFirstChild(); child;
  1032        child = child->GetNextSibling()) {
  1033     ClearLayer(child);
  1037 already_AddRefed<ReadbackLayer>
  1038 BasicLayerManager::CreateReadbackLayer()
  1040   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
  1041   nsRefPtr<ReadbackLayer> layer = new BasicReadbackLayer(this);
  1042   return layer.forget();

mercurial