gfx/layers/composite/ContainerLayerComposite.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: 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 "ContainerLayerComposite.h"
     7 #include <algorithm>                    // for min
     8 #include "FrameMetrics.h"               // for FrameMetrics
     9 #include "Units.h"                      // for LayerRect, LayerPixel, etc
    10 #include "gfx2DGlue.h"                  // for ToMatrix4x4
    11 #include "gfx3DMatrix.h"                // for gfx3DMatrix
    12 #include "gfxPrefs.h"                   // for gfxPrefs
    13 #include "gfxUtils.h"                   // for gfxUtils, etc
    14 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
    15 #include "mozilla/RefPtr.h"             // for RefPtr
    16 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
    17 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
    18 #include "mozilla/gfx/Point.h"          // for Point, IntPoint
    19 #include "mozilla/gfx/Rect.h"           // for IntRect, Rect
    20 #include "mozilla/layers/Compositor.h"  // for Compositor, etc
    21 #include "mozilla/layers/CompositorTypes.h"  // for DIAGNOSTIC_CONTAINER
    22 #include "mozilla/layers/Effects.h"     // for Effect, EffectChain, etc
    23 #include "mozilla/layers/TextureHost.h"  // for CompositingRenderTarget
    24 #include "mozilla/mozalloc.h"           // for operator delete, etc
    25 #include "nsAutoPtr.h"                  // for nsRefPtr
    26 #include "nsDebug.h"                    // for NS_ASSERTION
    27 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
    28 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
    29 #include "nsPoint.h"                    // for nsIntPoint
    30 #include "nsRect.h"                     // for nsIntRect
    31 #include "nsRegion.h"                   // for nsIntRegion
    32 #include "nsTArray.h"                   // for nsAutoTArray
    33 #include "TextRenderer.h"               // for TextRenderer
    34 #include <vector>
    36 namespace mozilla {
    37 namespace layers {
    39 /**
    40  * Returns a rectangle of content painted opaquely by aLayer. Very consertative;
    41  * bails by returning an empty rect in any tricky situations.
    42  */
    43 static nsIntRect
    44 GetOpaqueRect(Layer* aLayer)
    45 {
    46   nsIntRect result;
    47   gfx::Matrix matrix;
    48   bool is2D = aLayer->GetBaseTransform().Is2D(&matrix);
    50   // Just bail if there's anything difficult to handle.
    51   if (!is2D || aLayer->GetMaskLayer() ||
    52     aLayer->GetEffectiveOpacity() != 1.0f ||
    53     matrix.HasNonIntegerTranslation()) {
    54     return result;
    55   }
    57   if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) {
    58     result = aLayer->GetEffectiveVisibleRegion().GetLargestRectangle();
    59   } else {
    60     // Drill down into RefLayers because that's what we particularly care about;
    61     // layer construction for aLayer will not have known about the opaqueness
    62     // of any RefLayer subtrees.
    63     RefLayer* refLayer = aLayer->AsRefLayer();
    64     if (refLayer && refLayer->GetFirstChild()) {
    65       result = GetOpaqueRect(refLayer->GetFirstChild());
    66     }
    67   }
    69   // Translate our opaque region to cover the child
    70   gfx::Point point = matrix.GetTranslation();
    71   result.MoveBy(static_cast<int>(point.x), static_cast<int>(point.y));
    73   const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
    74   if (clipRect) {
    75     result.IntersectRect(result, *clipRect);
    76   }
    78   return result;
    79 }
    81 struct LayerVelocityUserData : public LayerUserData {
    82 public:
    83   LayerVelocityUserData() {
    84     MOZ_COUNT_CTOR(LayerVelocityUserData);
    85   }
    86   ~LayerVelocityUserData() {
    87     MOZ_COUNT_DTOR(LayerVelocityUserData);
    88   }
    90   struct VelocityData {
    91     VelocityData(TimeStamp frameTime, int scrollX, int scrollY)
    92       : mFrameTime(frameTime)
    93       , mPoint(scrollX, scrollY)
    94     {}
    96     TimeStamp mFrameTime;
    97     gfx::Point mPoint;
    98   };
    99   std::vector<VelocityData> mData;
   100 };
   102 static gfx::Point GetScrollData(Layer* aLayer) {
   103   gfx::Matrix matrix;
   104   if (aLayer->GetLocalTransform().Is2D(&matrix)) {
   105     return matrix.GetTranslation();
   106   }
   108   gfx::Point origin;
   109   return origin;
   110 }
   112 static void DrawLayerInfo(const nsIntRect& aClipRect,
   113                           LayerManagerComposite* aManager,
   114                           Layer* aLayer)
   115 {
   117   if (aLayer->GetType() == Layer::LayerType::TYPE_CONTAINER) {
   118     // XXX - should figure out a way to render this, but for now this
   119     // is hard to do, since it will often get superimposed over the first
   120     // child of the layer, which is bad.
   121     return;
   122   }
   124   nsAutoCString layerInfo;
   125   aLayer->PrintInfo(layerInfo, "");
   127   nsIntRegion visibleRegion = aLayer->GetVisibleRegion();
   129   uint32_t maxWidth = std::min<uint32_t>(visibleRegion.GetBounds().width, 500);
   131   nsIntPoint topLeft = visibleRegion.GetBounds().TopLeft();
   132   aManager->GetTextRenderer()->RenderText(layerInfo.get(), gfx::IntPoint(topLeft.x, topLeft.y),
   133                                           aLayer->GetEffectiveTransform(), 16,
   134                                           maxWidth);
   136 }
   138 static LayerVelocityUserData* GetVelocityData(Layer* aLayer) {
   139   static char sLayerVelocityUserDataKey;
   140   void* key = reinterpret_cast<void*>(&sLayerVelocityUserDataKey);
   141   if (!aLayer->HasUserData(key)) {
   142     LayerVelocityUserData* newData = new LayerVelocityUserData();
   143     aLayer->SetUserData(key, newData);
   144   }
   146   return static_cast<LayerVelocityUserData*>(aLayer->GetUserData(key));
   147 }
   149 static void DrawVelGraph(const nsIntRect& aClipRect,
   150                          LayerManagerComposite* aManager,
   151                          Layer* aLayer) {
   152   Compositor* compositor = aManager->GetCompositor();
   153   gfx::Rect clipRect(aClipRect.x, aClipRect.y,
   154                      aClipRect.width, aClipRect.height);
   156   TimeStamp now = TimeStamp::Now();
   157   LayerVelocityUserData* velocityData = GetVelocityData(aLayer);
   159   if (velocityData->mData.size() >= 1 &&
   160     now > velocityData->mData[velocityData->mData.size() - 1].mFrameTime +
   161       TimeDuration::FromMilliseconds(200)) {
   162     // clear stale data
   163     velocityData->mData.clear();
   164   }
   166   const gfx::Point layerTransform = GetScrollData(aLayer);
   167   velocityData->mData.push_back(
   168     LayerVelocityUserData::VelocityData(now,
   169       static_cast<int>(layerTransform.x), static_cast<int>(layerTransform.y)));
   171   // TODO: dump to file
   172   // XXX: Uncomment these lines to enable ScrollGraph logging. This is
   173   //      useful for HVGA phones or to output the data to accurate
   174   //      graphing software.
   175   // printf_stderr("ScrollGraph (%p): %f, %f\n",
   176   // aLayer, layerTransform.x, layerTransform.y);
   178   // Keep a circular buffer of 100.
   179   size_t circularBufferSize = 100;
   180   if (velocityData->mData.size() > circularBufferSize) {
   181     velocityData->mData.erase(velocityData->mData.begin());
   182   }
   184   if (velocityData->mData.size() == 1) {
   185     return;
   186   }
   188   // Clear and disable the graph when it's flat
   189   for (size_t i = 1; i < velocityData->mData.size(); i++) {
   190     if (velocityData->mData[i - 1].mPoint != velocityData->mData[i].mPoint) {
   191       break;
   192     }
   193     if (i == velocityData->mData.size() - 1) {
   194       velocityData->mData.clear();
   195       return;
   196     }
   197   }
   199   if (aLayer->GetEffectiveVisibleRegion().GetBounds().width < 300 ||
   200       aLayer->GetEffectiveVisibleRegion().GetBounds().height < 300) {
   201     // Don't want a graph for smaller layers
   202     return;
   203   }
   205   aManager->SetDebugOverlayWantsNextFrame(true);
   207   const gfx::Matrix4x4& transform = aLayer->GetEffectiveTransform();
   208   nsIntRect bounds = aLayer->GetEffectiveVisibleRegion().GetBounds();
   209   gfx::Rect graphBounds = gfx::Rect(bounds.x, bounds.y,
   210                                     bounds.width, bounds.height);
   211   gfx::Rect graphRect = gfx::Rect(bounds.x, bounds.y, 200, 100);
   213   float opacity = 1.0;
   214   EffectChain effects;
   215   effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(0.2f,0,0,1));
   216   compositor->DrawQuad(graphRect,
   217                        clipRect,
   218                        effects,
   219                        opacity,
   220                        transform);
   222   std::vector<gfx::Point> graph;
   223   int yScaleFactor = 3;
   224   for (int32_t i = (int32_t)velocityData->mData.size() - 2; i >= 0; i--) {
   225     const gfx::Point& p1 = velocityData->mData[i+1].mPoint;
   226     const gfx::Point& p2 = velocityData->mData[i].mPoint;
   227     int vel = sqrt((p1.x - p2.x) * (p1.x - p2.x) +
   228                    (p1.y - p2.y) * (p1.y - p2.y));
   229     graph.push_back(
   230       gfx::Point(bounds.x + graphRect.width / circularBufferSize * i,
   231                  graphBounds.y + graphRect.height - vel/yScaleFactor));
   232   }
   234   compositor->DrawLines(graph, clipRect, gfx::Color(0,1,0,1),
   235                         opacity, transform);
   236 }
   238 // ContainerRender is shared between RefLayer and ContainerLayer
   239 template<class ContainerT> void
   240 ContainerRender(ContainerT* aContainer,
   241                 LayerManagerComposite* aManager,
   242                 const nsIntRect& aClipRect)
   243 {
   244   /**
   245    * Setup our temporary surface for rendering the contents of this container.
   246    */
   247   RefPtr<CompositingRenderTarget> surface;
   249   Compositor* compositor = aManager->GetCompositor();
   251   RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
   253   nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();
   255   aContainer->mSupportsComponentAlphaChildren = false;
   257   float opacity = aContainer->GetEffectiveOpacity();
   259   bool needsSurface = aContainer->UseIntermediateSurface();
   260   if (needsSurface) {
   261     SurfaceInitMode mode = INIT_MODE_CLEAR;
   262     bool surfaceCopyNeeded = false;
   263     gfx::IntRect surfaceRect = gfx::IntRect(visibleRect.x, visibleRect.y,
   264                                             visibleRect.width, visibleRect.height);
   265     gfx::IntPoint sourcePoint = gfx::IntPoint(visibleRect.x, visibleRect.y);
   266     // we're about to create a framebuffer backed by textures to use as an intermediate
   267     // surface. What to do if its size (as given by framebufferRect) would exceed the
   268     // maximum texture size supported by the GL? The present code chooses the compromise
   269     // of just clamping the framebuffer's size to the max supported size.
   270     // This gives us a lower resolution rendering of the intermediate surface (children layers).
   271     // See bug 827170 for a discussion.
   272     int32_t maxTextureSize = compositor->GetMaxTextureSize();
   273     surfaceRect.width = std::min(maxTextureSize, surfaceRect.width);
   274     surfaceRect.height = std::min(maxTextureSize, surfaceRect.height);
   275     if (aContainer->GetEffectiveVisibleRegion().GetNumRects() == 1 &&
   276         (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE))
   277     {
   278       // don't need a background, we're going to paint all opaque stuff
   279       aContainer->mSupportsComponentAlphaChildren = true;
   280       mode = INIT_MODE_NONE;
   281     } else {
   282       const gfx::Matrix4x4& transform3D = aContainer->GetEffectiveTransform();
   283       gfx::Matrix transform;
   284       // If we have an opaque ancestor layer, then we can be sure that
   285       // all the pixels we draw into are either opaque already or will be
   286       // covered by something opaque. Otherwise copying up the background is
   287       // not safe.
   288       if (ContainerLayer::HasOpaqueAncestorLayer(aContainer) &&
   289           transform3D.Is2D(&transform) && !ThebesMatrix(transform).HasNonIntegerTranslation()) {
   290         surfaceCopyNeeded = gfxPrefs::ComponentAlphaEnabled();
   291         sourcePoint.x += transform._31;
   292         sourcePoint.y += transform._32;
   293         aContainer->mSupportsComponentAlphaChildren
   294           = gfxPrefs::ComponentAlphaEnabled();
   295       }
   296     }
   298     sourcePoint -= compositor->GetCurrentRenderTarget()->GetOrigin();
   299     if (surfaceCopyNeeded) {
   300       surface = compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget, sourcePoint);
   301     } else {
   302       surface = compositor->CreateRenderTarget(surfaceRect, mode);
   303     }
   305     if (!surface) {
   306       return;
   307     }
   309     compositor->SetRenderTarget(surface);
   310   } else {
   311     surface = previousTarget;
   312     aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) ||
   313       (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren());
   314   }
   316   nsAutoTArray<Layer*, 12> children;
   317   aContainer->SortChildrenBy3DZOrder(children);
   319   /**
   320    * Render this container's contents.
   321    */
   322   for (uint32_t i = 0; i < children.Length(); i++) {
   323     LayerComposite* layerToRender = static_cast<LayerComposite*>(children.ElementAt(i)->ImplData());
   325     if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty() &&
   326         !layerToRender->GetLayer()->AsContainerLayer()) {
   327       continue;
   328     }
   330     nsIntRect clipRect = layerToRender->GetLayer()->
   331         CalculateScissorRect(aClipRect, &aManager->GetWorldTransform());
   332     if (clipRect.IsEmpty()) {
   333       continue;
   334     }
   336     nsIntRegion savedVisibleRegion;
   337     bool restoreVisibleRegion = false;
   338     if (i + 1 < children.Length() &&
   339         layerToRender->GetLayer()->GetEffectiveTransform().IsIdentity()) {
   340       LayerComposite* nextLayer = static_cast<LayerComposite*>(children.ElementAt(i + 1)->ImplData());
   341       nsIntRect nextLayerOpaqueRect;
   342       if (nextLayer && nextLayer->GetLayer()) {
   343         nextLayerOpaqueRect = GetOpaqueRect(nextLayer->GetLayer());
   344       }
   345       if (!nextLayerOpaqueRect.IsEmpty()) {
   346         savedVisibleRegion = layerToRender->GetShadowVisibleRegion();
   347         nsIntRegion visibleRegion;
   348         visibleRegion.Sub(savedVisibleRegion, nextLayerOpaqueRect);
   349         if (visibleRegion.IsEmpty()) {
   350           continue;
   351         }
   352         layerToRender->SetShadowVisibleRegion(visibleRegion);
   353         restoreVisibleRegion = true;
   354       }
   355     }
   357     if (layerToRender->HasLayerBeenComposited()) {
   358       // Composer2D will compose this layer so skip GPU composition
   359       // this time & reset composition flag for next composition phase
   360       layerToRender->SetLayerComposited(false);
   361       nsIntRect clearRect = layerToRender->GetClearRect();
   362       if (!clearRect.IsEmpty()) {
   363         // Clear layer's visible rect on FrameBuffer with transparent pixels
   364         gfx::Rect fbRect(clearRect.x, clearRect.y, clearRect.width, clearRect.height);
   365         compositor->ClearRect(fbRect);
   366         layerToRender->SetClearRect(nsIntRect(0, 0, 0, 0));
   367       }
   368     } else {
   369       layerToRender->RenderLayer(clipRect);
   370     }
   372     if (restoreVisibleRegion) {
   373       // Restore the region in case it's not covered by opaque content next time
   374       layerToRender->SetShadowVisibleRegion(savedVisibleRegion);
   375     }
   377     if (gfxPrefs::LayersScrollGraph()) {
   378       DrawVelGraph(clipRect, aManager, layerToRender->GetLayer());
   379     }
   381     if (gfxPrefs::DrawLayerInfo()) {
   382       DrawLayerInfo(clipRect, aManager, layerToRender->GetLayer());
   383     }
   384     // invariant: our GL context should be current here, I don't think we can
   385     // assert it though
   386   }
   388   if (needsSurface) {
   389     // Unbind the current surface and rebind the previous one.
   390 #ifdef MOZ_DUMP_PAINTING
   391     if (gfxUtils::sDumpPainting) {
   392       RefPtr<gfx::DataSourceSurface> surf = surface->Dump(aManager->GetCompositor());
   393       WriteSnapshotToDumpFile(aContainer, surf);
   394     }
   395 #endif
   397     compositor->SetRenderTarget(previousTarget);
   398     EffectChain effectChain(aContainer);
   399     LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(aContainer->GetMaskLayer(),
   400                                                             effectChain,
   401                                                             !aContainer->GetTransform().CanDraw2D());
   403     effectChain.mPrimaryEffect = new EffectRenderTarget(surface);
   405     gfx::Rect rect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height);
   406     gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
   407     aManager->GetCompositor()->DrawQuad(rect, clipRect, effectChain, opacity,
   408                                         aContainer->GetEffectiveTransform());
   409   }
   411   if (aContainer->GetFrameMetrics().IsScrollable()) {
   412     const FrameMetrics& frame = aContainer->GetFrameMetrics();
   413     LayerRect layerBounds = ParentLayerRect(frame.mCompositionBounds) * ParentLayerToLayerScale(1.0);
   414     gfx::Rect rect(layerBounds.x, layerBounds.y, layerBounds.width, layerBounds.height);
   415     gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
   416     aManager->GetCompositor()->DrawDiagnostics(DIAGNOSTIC_CONTAINER,
   417                                                rect, clipRect,
   418                                                aContainer->GetEffectiveTransform());
   419   }
   420 }
   422 ContainerLayerComposite::ContainerLayerComposite(LayerManagerComposite *aManager)
   423   : ContainerLayer(aManager, nullptr)
   424   , LayerComposite(aManager)
   425 {
   426   MOZ_COUNT_CTOR(ContainerLayerComposite);
   427   mImplData = static_cast<LayerComposite*>(this);
   428 }
   430 ContainerLayerComposite::~ContainerLayerComposite()
   431 {
   432   MOZ_COUNT_DTOR(ContainerLayerComposite);
   434   // We don't Destroy() on destruction here because this destructor
   435   // can be called after remote content has crashed, and it may not be
   436   // safe to free the IPC resources of our children.  Those resources
   437   // are automatically cleaned up by IPDL-generated code.
   438   //
   439   // In the common case of normal shutdown, either
   440   // LayerManagerComposite::Destroy(), a parent
   441   // *ContainerLayerComposite::Destroy(), or Disconnect() will trigger
   442   // cleanup of our resources.
   443   while (mFirstChild) {
   444     RemoveChild(mFirstChild);
   445   }
   446 }
   448 void
   449 ContainerLayerComposite::Destroy()
   450 {
   451   if (!mDestroyed) {
   452     while (mFirstChild) {
   453       static_cast<LayerComposite*>(GetFirstChild()->ImplData())->Destroy();
   454       RemoveChild(mFirstChild);
   455     }
   456     mDestroyed = true;
   457   }
   458 }
   460 LayerComposite*
   461 ContainerLayerComposite::GetFirstChildComposite()
   462 {
   463   if (!mFirstChild) {
   464     return nullptr;
   465    }
   466   return static_cast<LayerComposite*>(mFirstChild->ImplData());
   467 }
   469 void
   470 ContainerLayerComposite::RenderLayer(const nsIntRect& aClipRect)
   471 {
   472   ContainerRender(this, mCompositeManager, aClipRect);
   473 }
   475 void
   476 ContainerLayerComposite::CleanupResources()
   477 {
   478   for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
   479     LayerComposite* layerToCleanup = static_cast<LayerComposite*>(l->ImplData());
   480     layerToCleanup->CleanupResources();
   481   }
   482 }
   484 RefLayerComposite::RefLayerComposite(LayerManagerComposite* aManager)
   485   : RefLayer(aManager, nullptr)
   486   , LayerComposite(aManager)
   487 {
   488   mImplData = static_cast<LayerComposite*>(this);
   489 }
   491 RefLayerComposite::~RefLayerComposite()
   492 {
   493   Destroy();
   494 }
   496 void
   497 RefLayerComposite::Destroy()
   498 {
   499   MOZ_ASSERT(!mFirstChild);
   500   mDestroyed = true;
   501 }
   503 LayerComposite*
   504 RefLayerComposite::GetFirstChildComposite()
   505 {
   506   if (!mFirstChild) {
   507     return nullptr;
   508    }
   509   return static_cast<LayerComposite*>(mFirstChild->ImplData());
   510 }
   512 void
   513 RefLayerComposite::RenderLayer(const nsIntRect& aClipRect)
   514 {
   515   ContainerRender(this, mCompositeManager, aClipRect);
   516 }
   518 void
   519 RefLayerComposite::CleanupResources()
   520 {
   521 }
   523 } /* layers */
   524 } /* mozilla */

mercurial