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/. */
5 
6 #include "ContainerLayerComposite.h"
7 #include <algorithm>                    // for min
8 #include "apz/src/AsyncPanZoomController.h"  // for AsyncPanZoomController
9 #include "FrameMetrics.h"               // for FrameMetrics
10 #include "Units.h"                      // for LayerRect, LayerPixel, etc
11 #include "CompositableHost.h"           // for CompositableHost
12 #include "gfxEnv.h"                     // for gfxEnv
13 #include "gfxPrefs.h"                   // for gfxPrefs
14 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
15 #include "mozilla/RefPtr.h"             // for RefPtr
16 #include "mozilla/UniquePtr.h"          // for UniquePtr
17 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
18 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
19 #include "mozilla/gfx/Point.h"          // for Point, IntPoint
20 #include "mozilla/gfx/Rect.h"           // for IntRect, Rect
21 #include "mozilla/layers/Compositor.h"  // for Compositor, etc
22 #include "mozilla/layers/CompositorTypes.h"  // for DiagnosticFlags::CONTAINER
23 #include "mozilla/layers/Effects.h"     // for Effect, EffectChain, etc
24 #include "mozilla/layers/TextureHost.h"  // for CompositingRenderTarget
25 #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
26 #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
27 #include "mozilla/mozalloc.h"           // for operator delete, etc
28 #include "mozilla/RefPtr.h"                   // for nsRefPtr
29 #include "nsDebug.h"                    // for NS_ASSERTION
30 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
31 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
32 #include "nsRegion.h"                   // for nsIntRegion
33 #include "nsTArray.h"                   // for AutoTArray
34 #include <stack>
35 #include "TextRenderer.h"               // for TextRenderer
36 #include <vector>
37 #include "GeckoProfiler.h"              // for GeckoProfiler
38 #ifdef MOZ_ENABLE_PROFILER_SPS
39 #include "ProfilerMarkers.h"            // for ProfilerMarkers
40 #endif
41 
42 #define CULLING_LOG(...)
43 // #define CULLING_LOG(...) printf_stderr("CULLING: " __VA_ARGS__)
44 
45 #define DUMP(...) do { if (gfxEnv::DumpDebug()) { printf_stderr(__VA_ARGS__); } } while(0)
46 #define XYWH(k)  (k).x, (k).y, (k).width, (k).height
47 #define XY(k)    (k).x, (k).y
48 #define WH(k)    (k).width, (k).height
49 
50 namespace mozilla {
51 namespace layers {
52 
53 using namespace gfx;
54 
DrawLayerInfo(const RenderTargetIntRect & aClipRect,LayerManagerComposite * aManager,Layer * aLayer)55 static void DrawLayerInfo(const RenderTargetIntRect& aClipRect,
56                           LayerManagerComposite* aManager,
57                           Layer* aLayer)
58 {
59 
60   if (aLayer->GetType() == Layer::LayerType::TYPE_CONTAINER) {
61     // XXX - should figure out a way to render this, but for now this
62     // is hard to do, since it will often get superimposed over the first
63     // child of the layer, which is bad.
64     return;
65   }
66 
67   std::stringstream ss;
68   aLayer->PrintInfo(ss, "");
69 
70   LayerIntRegion visibleRegion = aLayer->GetVisibleRegion();
71 
72   uint32_t maxWidth = std::min<uint32_t>(visibleRegion.GetBounds().width, 500);
73 
74   IntPoint topLeft = visibleRegion.ToUnknownRegion().GetBounds().TopLeft();
75   aManager->GetTextRenderer()->RenderText(ss.str().c_str(), topLeft,
76                                           aLayer->GetEffectiveTransform(), 16,
77                                           maxWidth);
78 }
79 
80 template<class ContainerT>
ContainerVisibleRect(ContainerT * aContainer)81 static gfx::IntRect ContainerVisibleRect(ContainerT* aContainer)
82 {
83   gfx::IntRect surfaceRect = aContainer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds();
84   return surfaceRect;
85 }
86 
PrintUniformityInfo(Layer * aLayer)87 static void PrintUniformityInfo(Layer* aLayer)
88 {
89 #ifdef MOZ_ENABLE_PROFILER_SPS
90   if (!profiler_is_active()) {
91     return;
92   }
93 
94   // Don't want to print a log for smaller layers
95   if (aLayer->GetLocalVisibleRegion().GetBounds().width < 300 ||
96       aLayer->GetLocalVisibleRegion().GetBounds().height < 300) {
97     return;
98   }
99 
100   Matrix4x4 transform = aLayer->AsLayerComposite()->GetShadowBaseTransform();
101   if (!transform.Is2D()) {
102     return;
103   }
104 
105   Point translation = transform.As2D().GetTranslation();
106   LayerTranslationPayload* payload = new LayerTranslationPayload(aLayer, translation);
107   PROFILER_MARKER_PAYLOAD("LayerTranslation", payload);
108 #endif
109 }
110 
111 /* all of the per-layer prepared data we need to maintain */
112 struct PreparedLayer
113 {
PreparedLayermozilla::layers::PreparedLayer114   PreparedLayer(Layer *aLayer, RenderTargetIntRect aClipRect) :
115     mLayer(aLayer), mClipRect(aClipRect) {}
116   RefPtr<Layer> mLayer;
117   RenderTargetIntRect mClipRect;
118 };
119 
120 /* all of the prepared data that we need in RenderLayer() */
121 struct PreparedData
122 {
123   RefPtr<CompositingRenderTarget> mTmpTarget;
124   AutoTArray<PreparedLayer, 12> mLayers;
125   bool mNeedsSurfaceCopy;
126 };
127 
128 // ContainerPrepare is shared between RefLayer and ContainerLayer
129 template<class ContainerT> void
ContainerPrepare(ContainerT * aContainer,LayerManagerComposite * aManager,const RenderTargetIntRect & aClipRect)130 ContainerPrepare(ContainerT* aContainer,
131                  LayerManagerComposite* aManager,
132                  const RenderTargetIntRect& aClipRect)
133 {
134   aContainer->mPrepared = MakeUnique<PreparedData>();
135   aContainer->mPrepared->mNeedsSurfaceCopy = false;
136 
137   /**
138    * Determine which layers to draw.
139    */
140   AutoTArray<Layer*, 12> children;
141   aContainer->SortChildrenBy3DZOrder(children);
142 
143   for (uint32_t i = 0; i < children.Length(); i++) {
144     LayerComposite* layerToRender = static_cast<LayerComposite*>(children.ElementAt(i)->ImplData());
145 
146     RenderTargetIntRect clipRect = layerToRender->GetLayer()->
147         CalculateScissorRect(aClipRect);
148 
149     if (layerToRender->GetLayer()->IsBackfaceHidden()) {
150       continue;
151     }
152 
153     // We don't want to skip container layers because otherwise their mPrepared
154     // may be null which is not allowed.
155     if (!layerToRender->GetLayer()->AsContainerLayer()) {
156       if (!layerToRender->GetLayer()->IsVisible() &&
157           !layerToRender->NeedToDrawCheckerboarding(nullptr)) {
158         CULLING_LOG("Sublayer %p has no effective visible region\n", layerToRender->GetLayer());
159         continue;
160       }
161 
162       if (clipRect.IsEmpty()) {
163         CULLING_LOG("Sublayer %p has an empty world clip rect\n", layerToRender->GetLayer());
164         continue;
165       }
166     }
167 
168     CULLING_LOG("Preparing sublayer %p\n", layerToRender->GetLayer());
169 
170     layerToRender->Prepare(clipRect);
171     aContainer->mPrepared->mLayers.AppendElement(PreparedLayer(layerToRender->GetLayer(),
172                                                                clipRect));
173   }
174 
175   CULLING_LOG("Preparing container layer %p\n", aContainer->GetLayer());
176 
177   /**
178    * Setup our temporary surface for rendering the contents of this container.
179    */
180 
181   gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
182   if (surfaceRect.IsEmpty()) {
183     return;
184   }
185 
186   bool surfaceCopyNeeded;
187   // DefaultComputeSupportsComponentAlphaChildren can mutate aContainer so call it unconditionally
188   aContainer->DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded);
189   if (aContainer->UseIntermediateSurface()) {
190     if (!surfaceCopyNeeded) {
191       RefPtr<CompositingRenderTarget> surface = nullptr;
192 
193       RefPtr<CompositingRenderTarget>& lastSurf = aContainer->mLastIntermediateSurface;
194       if (lastSurf && !aContainer->mChildrenChanged && lastSurf->GetRect().IsEqualEdges(surfaceRect)) {
195         surface = lastSurf;
196       }
197 
198       if (!surface) {
199         // If we don't need a copy we can render to the intermediate now to avoid
200         // unecessary render target switching. This brings a big perf boost on mobile gpus.
201         surface = CreateOrRecycleTarget(aContainer, aManager);
202 
203         MOZ_PERFORMANCE_WARNING("gfx", "[%p] Container layer requires intermediate surface rendering\n", aContainer);
204         RenderIntermediate(aContainer, aManager, aClipRect.ToUnknownRect(), surface);
205         aContainer->SetChildrenChanged(false);
206       }
207 
208       aContainer->mPrepared->mTmpTarget = surface;
209     } else {
210       MOZ_PERFORMANCE_WARNING("gfx", "[%p] Container layer requires intermediate surface copy\n", aContainer);
211       aContainer->mPrepared->mNeedsSurfaceCopy = true;
212       aContainer->mLastIntermediateSurface = nullptr;
213     }
214   } else {
215     aContainer->mLastIntermediateSurface = nullptr;
216   }
217 }
218 
219 template<class ContainerT> void
RenderMinimap(ContainerT * aContainer,LayerManagerComposite * aManager,const RenderTargetIntRect & aClipRect,Layer * aLayer)220 RenderMinimap(ContainerT* aContainer, LayerManagerComposite* aManager,
221                    const RenderTargetIntRect& aClipRect, Layer* aLayer)
222 {
223   Compositor* compositor = aManager->GetCompositor();
224 
225   if (aLayer->GetScrollMetadataCount() < 1) {
226     return;
227   }
228 
229   AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(0);
230   if (!controller) {
231     return;
232   }
233 
234   ParentLayerPoint scrollOffset = controller->GetCurrentAsyncScrollOffset(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
235 
236   // Options
237   const int verticalPadding = 10;
238   const int horizontalPadding = 5;
239   gfx::Color backgroundColor(0.3f, 0.3f, 0.3f, 0.3f);
240   gfx::Color tileActiveColor(1, 1, 1, 0.4f);
241   gfx::Color tileBorderColor(0, 0, 0, 0.1f);
242   gfx::Color pageBorderColor(0, 0, 0);
243   gfx::Color criticalDisplayPortColor(1.f, 1.f, 0);
244   gfx::Color displayPortColor(0, 1.f, 0);
245   gfx::Color viewPortColor(0, 0, 1.f, 0.3f);
246   gfx::Color visibilityColor(1.f, 0, 0);
247 
248   // Rects
249   const FrameMetrics& fm = aLayer->GetFrameMetrics(0);
250   ParentLayerRect compositionBounds = fm.GetCompositionBounds();
251   LayerRect scrollRect = fm.GetScrollableRect() * fm.LayersPixelsPerCSSPixel();
252   LayerRect viewRect = ParentLayerRect(scrollOffset, compositionBounds.Size()) / LayerToParentLayerScale(1);
253   LayerRect dp = (fm.GetDisplayPort() + fm.GetScrollOffset()) * fm.LayersPixelsPerCSSPixel();
254   Maybe<LayerRect> cdp;
255   if (!fm.GetCriticalDisplayPort().IsEmpty()) {
256     cdp = Some((fm.GetCriticalDisplayPort() + fm.GetScrollOffset()) * fm.LayersPixelsPerCSSPixel());
257   }
258 
259   // Don't render trivial minimap. They can show up from textboxes and other tiny frames.
260   if (viewRect.width < 64 && viewRect.height < 64) {
261     return;
262   }
263 
264   // Compute a scale with an appropriate aspect ratio
265   // We allocate up to 100px of width and the height of this layer.
266   float scaleFactor;
267   float scaleFactorX;
268   float scaleFactorY;
269   Rect dest = Rect(aClipRect.ToUnknownRect());
270   if (aLayer->GetLocalClipRect()) {
271     dest = Rect(aLayer->GetLocalClipRect().value().ToUnknownRect());
272   } else {
273     dest = aContainer->GetEffectiveTransform().Inverse().TransformBounds(dest);
274   }
275   dest = dest.Intersect(compositionBounds.ToUnknownRect());
276   scaleFactorX = std::min(100.f, dest.width - (2 * horizontalPadding)) / scrollRect.width;
277   scaleFactorY = (dest.height - (2 * verticalPadding)) / scrollRect.height;
278   scaleFactor = std::min(scaleFactorX, scaleFactorY);
279   if (scaleFactor <= 0) {
280     return;
281   }
282 
283   Matrix4x4 transform = Matrix4x4::Scaling(scaleFactor, scaleFactor, 1);
284   transform.PostTranslate(horizontalPadding + dest.x, verticalPadding + dest.y, 0);
285 
286   Rect transformedScrollRect = transform.TransformBounds(scrollRect.ToUnknownRect());
287 
288   IntRect clipRect = RoundedOut(aContainer->GetEffectiveTransform().TransformBounds(transformedScrollRect));
289 
290   // Render the scrollable area.
291   compositor->FillRect(transformedScrollRect, backgroundColor, clipRect, aContainer->GetEffectiveTransform());
292   compositor->SlowDrawRect(transformedScrollRect, pageBorderColor, clipRect, aContainer->GetEffectiveTransform());
293 
294   // If enabled, render information about visibility.
295   if (gfxPrefs::APZMinimapVisibilityEnabled()) {
296     // Retrieve the APZC scrollable layer guid, which we'll use to get the
297     // appropriate visibility information from the layer manager.
298     AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(0);
299     MOZ_ASSERT(controller);
300 
301     ScrollableLayerGuid guid = controller->GetGuid();
302 
303     // Get the approximately visible region.
304     static CSSIntRegion emptyRegion;
305     CSSIntRegion* visibleRegion = aManager->GetApproximatelyVisibleRegion(guid);
306     if (!visibleRegion) {
307       visibleRegion = &emptyRegion;
308     }
309 
310     // Iterate through and draw the rects in the region.
311     for (CSSIntRegion::RectIterator iterator = visibleRegion->RectIter();
312          !iterator.Done();
313          iterator.Next())
314     {
315       CSSIntRect rect = iterator.Get();
316       LayerRect scaledRect = rect * fm.LayersPixelsPerCSSPixel();
317       Rect r = transform.TransformBounds(scaledRect.ToUnknownRect());
318       compositor->FillRect(r, visibilityColor, clipRect, aContainer->GetEffectiveTransform());
319     }
320   }
321 
322   // Render the displayport.
323   Rect r = transform.TransformBounds(dp.ToUnknownRect());
324   compositor->FillRect(r, tileActiveColor, clipRect, aContainer->GetEffectiveTransform());
325   compositor->SlowDrawRect(r, displayPortColor, clipRect, aContainer->GetEffectiveTransform());
326 
327   // Render the critical displayport if there is one
328   if (cdp) {
329     r = transform.TransformBounds(cdp->ToUnknownRect());
330     compositor->SlowDrawRect(r, criticalDisplayPortColor, clipRect, aContainer->GetEffectiveTransform());
331   }
332 
333   // Render the viewport.
334   r = transform.TransformBounds(viewRect.ToUnknownRect());
335   compositor->SlowDrawRect(r, viewPortColor, clipRect, aContainer->GetEffectiveTransform(), 2);
336 }
337 
338 
339 template<class ContainerT> void
RenderLayers(ContainerT * aContainer,LayerManagerComposite * aManager,const RenderTargetIntRect & aClipRect)340 RenderLayers(ContainerT* aContainer,
341 	     LayerManagerComposite* aManager,
342 	     const RenderTargetIntRect& aClipRect)
343 {
344   Compositor* compositor = aManager->GetCompositor();
345 
346   for (size_t i = 0u; i < aContainer->mPrepared->mLayers.Length(); i++) {
347     PreparedLayer& preparedData = aContainer->mPrepared->mLayers[i];
348     LayerComposite* layerToRender = static_cast<LayerComposite*>(preparedData.mLayer->ImplData());
349     const RenderTargetIntRect& clipRect = preparedData.mClipRect;
350     Layer* layer = layerToRender->GetLayer();
351 
352     if (layerToRender->HasStaleCompositor()) {
353       continue;
354     }
355 
356     if (gfxPrefs::LayersDrawFPS()) {
357       for (const auto& metadata : layer->GetAllScrollMetadata()) {
358         if (metadata.IsApzForceDisabled()) {
359           aManager->DisabledApzWarning();
360           break;
361         }
362       }
363     }
364 
365     Color color;
366     if (layerToRender->NeedToDrawCheckerboarding(&color)) {
367       if (gfxPrefs::APZHighlightCheckerboardedAreas()) {
368         color = Color(255 / 255.f, 188 / 255.f, 217 / 255.f, 1.f); // "Cotton Candy"
369       }
370       // Ideally we would want to intersect the checkerboard region from the APZ with the layer bounds
371       // and only fill in that area. However the layer bounds takes into account the base translation
372       // for the painted layer whereas the checkerboard region does not. One does not simply
373       // intersect areas in different coordinate spaces. So we do this a little more permissively
374       // and only fill in the background when we know there is checkerboard, which in theory
375       // should only occur transiently.
376       gfx::IntRect layerBounds = layer->GetLayerBounds();
377       EffectChain effectChain(layer);
378       effectChain.mPrimaryEffect = new EffectSolidColor(color);
379       aManager->GetCompositor()->DrawQuad(gfx::Rect(layerBounds.x, layerBounds.y, layerBounds.width, layerBounds.height),
380                                           clipRect.ToUnknownRect(),
381                                           effectChain, layer->GetEffectiveOpacity(),
382                                           layer->GetEffectiveTransform());
383     }
384 
385     if (layerToRender->HasLayerBeenComposited()) {
386       // Composer2D will compose this layer so skip GPU composition
387       // this time. The flag will be reset for the next composition phase
388       // at the beginning of LayerManagerComposite::Rener().
389       gfx::IntRect clearRect = layerToRender->GetClearRect();
390       if (!clearRect.IsEmpty()) {
391         // Clear layer's visible rect on FrameBuffer with transparent pixels
392         gfx::Rect fbRect(clearRect.x, clearRect.y, clearRect.width, clearRect.height);
393         compositor->ClearRect(fbRect);
394         layerToRender->SetClearRect(gfx::IntRect(0, 0, 0, 0));
395       }
396     } else {
397       layerToRender->RenderLayer(clipRect.ToUnknownRect());
398     }
399 
400     if (gfxPrefs::UniformityInfo()) {
401       PrintUniformityInfo(layer);
402     }
403 
404     if (gfxPrefs::DrawLayerInfo()) {
405       DrawLayerInfo(clipRect, aManager, layer);
406     }
407 
408     // Draw a border around scrollable layers.
409     // A layer can be scrolled by multiple scroll frames. Draw a border
410     // for each.
411     // Within the list of scroll frames for a layer, the layer border for a
412     // scroll frame lower down is affected by the async transforms on scroll
413     // frames higher up, so loop from the top down, and accumulate an async
414     // transform as we go along.
415     Matrix4x4 asyncTransform;
416     for (uint32_t i = layer->GetScrollMetadataCount(); i > 0; --i) {
417       if (layer->GetFrameMetrics(i - 1).IsScrollable()) {
418         // Since the composition bounds are in the parent layer's coordinates,
419         // use the parent's effective transform rather than the layer's own.
420         ParentLayerRect compositionBounds = layer->GetFrameMetrics(i - 1).GetCompositionBounds();
421         aManager->GetCompositor()->DrawDiagnostics(DiagnosticFlags::CONTAINER,
422                                                    compositionBounds.ToUnknownRect(),
423                                                    aClipRect.ToUnknownRect(),
424                                                    asyncTransform * aContainer->GetEffectiveTransform());
425         if (AsyncPanZoomController* apzc = layer->GetAsyncPanZoomController(i - 1)) {
426           asyncTransform =
427               apzc->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::RESPECT_FORCE_DISABLE).ToUnknownMatrix()
428             * asyncTransform;
429         }
430       }
431     }
432 
433     if (gfxPrefs::APZMinimap()) {
434       RenderMinimap(aContainer, aManager, aClipRect, layer);
435     }
436 
437     // invariant: our GL context should be current here, I don't think we can
438     // assert it though
439   }
440 }
441 
442 template<class ContainerT> RefPtr<CompositingRenderTarget>
CreateOrRecycleTarget(ContainerT * aContainer,LayerManagerComposite * aManager)443 CreateOrRecycleTarget(ContainerT* aContainer,
444                       LayerManagerComposite* aManager)
445 {
446   Compositor* compositor = aManager->GetCompositor();
447   SurfaceInitMode mode = INIT_MODE_CLEAR;
448   gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
449   if (aContainer->GetLocalVisibleRegion().GetNumRects() == 1 &&
450       (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE))
451   {
452     mode = INIT_MODE_NONE;
453   }
454 
455   RefPtr<CompositingRenderTarget>& lastSurf = aContainer->mLastIntermediateSurface;
456   if (lastSurf && lastSurf->GetRect().IsEqualEdges(surfaceRect)) {
457     if (mode == INIT_MODE_CLEAR) {
458       lastSurf->ClearOnBind();
459     }
460 
461     return lastSurf;
462   } else {
463     lastSurf = compositor->CreateRenderTarget(surfaceRect, mode);
464 
465     return lastSurf;
466   }
467 }
468 
469 template<class ContainerT> RefPtr<CompositingRenderTarget>
CreateTemporaryTargetAndCopyFromBackground(ContainerT * aContainer,LayerManagerComposite * aManager)470 CreateTemporaryTargetAndCopyFromBackground(ContainerT* aContainer,
471                                            LayerManagerComposite* aManager)
472 {
473   Compositor* compositor = aManager->GetCompositor();
474   gfx::IntRect visibleRect = aContainer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds();
475   RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
476   gfx::IntRect surfaceRect = gfx::IntRect(visibleRect.x, visibleRect.y,
477                                           visibleRect.width, visibleRect.height);
478 
479   gfx::IntPoint sourcePoint = gfx::IntPoint(visibleRect.x, visibleRect.y);
480 
481   gfx::Matrix4x4 transform = aContainer->GetEffectiveTransform();
482   DebugOnly<gfx::Matrix> transform2d;
483   MOZ_ASSERT(transform.Is2D(&transform2d) && !gfx::ThebesMatrix(transform2d).HasNonIntegerTranslation());
484   sourcePoint += gfx::IntPoint::Truncate(transform._41, transform._42);
485 
486   sourcePoint -= compositor->GetCurrentRenderTarget()->GetOrigin();
487 
488   return compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget, sourcePoint);
489 }
490 
491 template<class ContainerT> void
RenderIntermediate(ContainerT * aContainer,LayerManagerComposite * aManager,const gfx::IntRect & aClipRect,RefPtr<CompositingRenderTarget> surface)492 RenderIntermediate(ContainerT* aContainer,
493                    LayerManagerComposite* aManager,
494                    const gfx::IntRect& aClipRect,
495                    RefPtr<CompositingRenderTarget> surface)
496 {
497   Compositor* compositor = aManager->GetCompositor();
498   RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
499 
500   if (!surface) {
501     return;
502   }
503 
504   compositor->SetRenderTarget(surface);
505   // pre-render all of the layers into our temporary
506   RenderLayers(aContainer, aManager, RenderTargetIntRect::FromUnknownRect(aClipRect));
507   // Unbind the current surface and rebind the previous one.
508   compositor->SetRenderTarget(previousTarget);
509 }
510 
511 template<class ContainerT> void
ContainerRender(ContainerT * aContainer,LayerManagerComposite * aManager,const gfx::IntRect & aClipRect)512 ContainerRender(ContainerT* aContainer,
513                  LayerManagerComposite* aManager,
514                  const gfx::IntRect& aClipRect)
515 {
516   MOZ_ASSERT(aContainer->mPrepared);
517 
518   if (aContainer->UseIntermediateSurface()) {
519     RefPtr<CompositingRenderTarget> surface;
520 
521     if (aContainer->mPrepared->mNeedsSurfaceCopy) {
522       // we needed to copy the background so we waited until now to render the intermediate
523       surface = CreateTemporaryTargetAndCopyFromBackground(aContainer, aManager);
524       RenderIntermediate(aContainer, aManager,
525                          aClipRect, surface);
526     } else {
527       surface = aContainer->mPrepared->mTmpTarget;
528     }
529 
530     if (!surface) {
531       aContainer->mPrepared = nullptr;
532       return;
533     }
534 
535     gfx::Rect visibleRect(aContainer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds());
536     RefPtr<Compositor> compositor = aManager->GetCompositor();
537 #ifdef MOZ_DUMP_PAINTING
538     if (gfxEnv::DumpCompositorTextures()) {
539       RefPtr<gfx::DataSourceSurface> surf = surface->Dump(compositor);
540       if (surf) {
541         WriteSnapshotToDumpFile(aContainer, surf);
542       }
543     }
544 #endif
545 
546     RefPtr<ContainerT> container = aContainer;
547     RenderWithAllMasks(aContainer, compositor, aClipRect,
548                        [&, surface, compositor, container](EffectChain& effectChain, const IntRect& clipRect) {
549       effectChain.mPrimaryEffect = new EffectRenderTarget(surface);
550       compositor->DrawQuad(visibleRect, clipRect, effectChain,
551                            container->GetEffectiveOpacity(),
552                            container->GetEffectiveTransform());
553     });
554   } else {
555     RenderLayers(aContainer, aManager, RenderTargetIntRect::FromUnknownRect(aClipRect));
556   }
557   aContainer->mPrepared = nullptr;
558 
559   // If it is a scrollable container layer with no child layers, and one of the APZCs
560   // attached to it has a nonempty async transform, then that transform is not applied
561   // to any visible content. Display a warning box (conditioned on the FPS display being
562   // enabled).
563   if (gfxPrefs::LayersDrawFPS() && aContainer->IsScrollInfoLayer()) {
564     // Since aContainer doesn't have any children we can just iterate from the top metrics
565     // on it down to the bottom using GetFirstChild and not worry about walking onto another
566     // underlying layer.
567     for (LayerMetricsWrapper i(aContainer); i; i = i.GetFirstChild()) {
568       if (AsyncPanZoomController* apzc = i.GetApzc()) {
569         if (!apzc->GetAsyncTransformAppliedToContent()
570             && !AsyncTransformComponentMatrix(apzc->GetCurrentAsyncTransform(AsyncPanZoomController::NORMAL)).IsIdentity()) {
571           aManager->UnusedApzTransformWarning();
572           break;
573         }
574       }
575     }
576   }
577 }
578 
ContainerLayerComposite(LayerManagerComposite * aManager)579 ContainerLayerComposite::ContainerLayerComposite(LayerManagerComposite *aManager)
580   : ContainerLayer(aManager, nullptr)
581   , LayerComposite(aManager)
582 {
583   MOZ_COUNT_CTOR(ContainerLayerComposite);
584   mImplData = static_cast<LayerComposite*>(this);
585 }
586 
~ContainerLayerComposite()587 ContainerLayerComposite::~ContainerLayerComposite()
588 {
589   MOZ_COUNT_DTOR(ContainerLayerComposite);
590 
591   // We don't Destroy() on destruction here because this destructor
592   // can be called after remote content has crashed, and it may not be
593   // safe to free the IPC resources of our children.  Those resources
594   // are automatically cleaned up by IPDL-generated code.
595   //
596   // In the common case of normal shutdown, either
597   // LayerManagerComposite::Destroy(), a parent
598   // *ContainerLayerComposite::Destroy(), or Disconnect() will trigger
599   // cleanup of our resources.
600   while (mFirstChild) {
601     RemoveChild(mFirstChild);
602   }
603 }
604 
605 void
Destroy()606 ContainerLayerComposite::Destroy()
607 {
608   if (!mDestroyed) {
609     while (mFirstChild) {
610       static_cast<LayerComposite*>(GetFirstChild()->ImplData())->Destroy();
611       RemoveChild(mFirstChild);
612     }
613     mDestroyed = true;
614   }
615 }
616 
617 LayerComposite*
GetFirstChildComposite()618 ContainerLayerComposite::GetFirstChildComposite()
619 {
620   if (!mFirstChild) {
621     return nullptr;
622    }
623   return static_cast<LayerComposite*>(mFirstChild->ImplData());
624 }
625 
626 void
RenderLayer(const gfx::IntRect & aClipRect)627 ContainerLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
628 {
629   ContainerRender(this, mCompositeManager, aClipRect);
630 }
631 
632 void
Prepare(const RenderTargetIntRect & aClipRect)633 ContainerLayerComposite::Prepare(const RenderTargetIntRect& aClipRect)
634 {
635   ContainerPrepare(this, mCompositeManager, aClipRect);
636 }
637 
638 void
CleanupResources()639 ContainerLayerComposite::CleanupResources()
640 {
641   mLastIntermediateSurface = nullptr;
642   mPrepared = nullptr;
643 
644   for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
645     LayerComposite* layerToCleanup = static_cast<LayerComposite*>(l->ImplData());
646     layerToCleanup->CleanupResources();
647   }
648 }
649 
RefLayerComposite(LayerManagerComposite * aManager)650 RefLayerComposite::RefLayerComposite(LayerManagerComposite* aManager)
651   : RefLayer(aManager, nullptr)
652   , LayerComposite(aManager)
653 {
654   mImplData = static_cast<LayerComposite*>(this);
655 }
656 
~RefLayerComposite()657 RefLayerComposite::~RefLayerComposite()
658 {
659   Destroy();
660 }
661 
662 void
Destroy()663 RefLayerComposite::Destroy()
664 {
665   MOZ_ASSERT(!mFirstChild);
666   mDestroyed = true;
667 }
668 
669 LayerComposite*
GetFirstChildComposite()670 RefLayerComposite::GetFirstChildComposite()
671 {
672   if (!mFirstChild) {
673     return nullptr;
674    }
675   return static_cast<LayerComposite*>(mFirstChild->ImplData());
676 }
677 
678 void
RenderLayer(const gfx::IntRect & aClipRect)679 RefLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
680 {
681   ContainerRender(this, mCompositeManager, aClipRect);
682 }
683 
684 void
Prepare(const RenderTargetIntRect & aClipRect)685 RefLayerComposite::Prepare(const RenderTargetIntRect& aClipRect)
686 {
687   ContainerPrepare(this, mCompositeManager, aClipRect);
688 }
689 
690 void
CleanupResources()691 RefLayerComposite::CleanupResources()
692 {
693   mLastIntermediateSurface = nullptr;
694   mPrepared = nullptr;
695 }
696 
697 } // namespace layers
698 } // namespace mozilla
699