1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "ClientTiledPaintedLayer.h"
8 #include "FrameMetrics.h"          // for FrameMetrics
9 #include "Units.h"                 // for ScreenIntRect, CSSPoint, etc
10 #include "UnitTransforms.h"        // for TransformTo
11 #include "ClientLayerManager.h"    // for ClientLayerManager, etc
12 #include "gfxPlatform.h"           // for gfxPlatform
13 #include "gfxPrefs.h"              // for gfxPrefs
14 #include "gfxRect.h"               // for gfxRect
15 #include "mozilla/Assertions.h"    // for MOZ_ASSERT, etc
16 #include "mozilla/gfx/BaseSize.h"  // for BaseSize
17 #include "mozilla/gfx/gfxVars.h"
18 #include "mozilla/gfx/Rect.h"  // for Rect, RectTyped
19 #include "mozilla/layers/CompositorBridgeChild.h"
20 #include "mozilla/layers/LayerMetricsWrapper.h"  // for LayerMetricsWrapper
21 #include "mozilla/layers/LayersMessages.h"
22 #include "mozilla/layers/PaintThread.h"
23 #include "mozilla/mozalloc.h"  // for operator delete, etc
24 #include "nsISupportsImpl.h"   // for MOZ_COUNT_CTOR, etc
25 #include "LayersLogging.h"
26 #include "mozilla/layers/SingleTiledContentClient.h"
27 
28 namespace mozilla {
29 namespace layers {
30 
31 using gfx::IntRect;
32 using gfx::IntSize;
33 using gfx::Rect;
34 
ClientTiledPaintedLayer(ClientLayerManager * const aManager,ClientLayerManager::PaintedLayerCreationHint aCreationHint)35 ClientTiledPaintedLayer::ClientTiledPaintedLayer(
36     ClientLayerManager* const aManager,
37     ClientLayerManager::PaintedLayerCreationHint aCreationHint)
38     : PaintedLayer(aManager, static_cast<ClientLayer*>(this), aCreationHint),
39       mContentClient(),
40       mHaveSingleTiledContentClient(false) {
41   MOZ_COUNT_CTOR(ClientTiledPaintedLayer);
42   mPaintData.mLastScrollOffset = ParentLayerPoint(0, 0);
43   mPaintData.mFirstPaint = true;
44 }
45 
~ClientTiledPaintedLayer()46 ClientTiledPaintedLayer::~ClientTiledPaintedLayer() {
47   MOZ_COUNT_DTOR(ClientTiledPaintedLayer);
48 }
49 
ClearCachedResources()50 void ClientTiledPaintedLayer::ClearCachedResources() {
51   if (mContentClient) {
52     mContentClient->ClearCachedResources();
53   }
54   ClearValidRegion();
55   mContentClient = nullptr;
56 }
57 
FillSpecificAttributes(SpecificLayerAttributes & aAttrs)58 void ClientTiledPaintedLayer::FillSpecificAttributes(
59     SpecificLayerAttributes& aAttrs) {
60   aAttrs = PaintedLayerAttributes(GetValidRegion());
61 }
62 
ApplyParentLayerToLayerTransform(const ParentLayerToLayerMatrix4x4 & aTransform,const ParentLayerRect & aParentLayerRect,const LayerRect & aClip)63 static Maybe<LayerRect> ApplyParentLayerToLayerTransform(
64     const ParentLayerToLayerMatrix4x4& aTransform,
65     const ParentLayerRect& aParentLayerRect, const LayerRect& aClip) {
66   return UntransformBy(aTransform, aParentLayerRect, aClip);
67 }
68 
GetTransformToAncestorsParentLayer(Layer * aStart,const LayerMetricsWrapper & aAncestor)69 static LayerToParentLayerMatrix4x4 GetTransformToAncestorsParentLayer(
70     Layer* aStart, const LayerMetricsWrapper& aAncestor) {
71   gfx::Matrix4x4 transform;
72   const LayerMetricsWrapper& ancestorParent = aAncestor.GetParent();
73   for (LayerMetricsWrapper iter(aStart, LayerMetricsWrapper::StartAt::BOTTOM);
74        ancestorParent ? iter != ancestorParent : iter.IsValid();
75        iter = iter.GetParent()) {
76     transform = transform * iter.GetTransform();
77 
78     if (gfxPrefs::LayoutUseContainersForRootFrames()) {
79       // When scrolling containers, layout adds a post-scale into the transform
80       // of the displayport-ancestor (which we pick up in GetTransform() above)
81       // to cancel out the pres shell resolution (for historical reasons). The
82       // compositor in turn cancels out this post-scale (i.e., scales by the
83       // pres shell resolution), and to get correct calculations, we need to do
84       // so here, too.
85       //
86       // With containerless scrolling, the offending post-scale is on the
87       // parent layer of the displayport-ancestor, which we don't reach in this
88       // loop, so we don't need to worry about it.
89       float presShellResolution = iter.GetPresShellResolution();
90       transform.PostScale(presShellResolution, presShellResolution, 1.0f);
91     }
92   }
93   return ViewAs<LayerToParentLayerMatrix4x4>(transform);
94 }
95 
GetAncestorLayers(LayerMetricsWrapper * aOutScrollAncestor,LayerMetricsWrapper * aOutDisplayPortAncestor,bool * aOutHasTransformAnimation)96 void ClientTiledPaintedLayer::GetAncestorLayers(
97     LayerMetricsWrapper* aOutScrollAncestor,
98     LayerMetricsWrapper* aOutDisplayPortAncestor,
99     bool* aOutHasTransformAnimation) {
100   LayerMetricsWrapper scrollAncestor;
101   LayerMetricsWrapper displayPortAncestor;
102   bool hasTransformAnimation = false;
103   for (LayerMetricsWrapper ancestor(this, LayerMetricsWrapper::StartAt::BOTTOM);
104        ancestor; ancestor = ancestor.GetParent()) {
105     hasTransformAnimation |= ancestor.HasTransformAnimation();
106     const FrameMetrics& metrics = ancestor.Metrics();
107     if (!scrollAncestor &&
108         metrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID) {
109       scrollAncestor = ancestor;
110     }
111     if (!metrics.GetDisplayPort().IsEmpty()) {
112       displayPortAncestor = ancestor;
113       // Any layer that has a displayport must be scrollable, so we can break
114       // here.
115       break;
116     }
117   }
118   if (aOutScrollAncestor) {
119     *aOutScrollAncestor = scrollAncestor;
120   }
121   if (aOutDisplayPortAncestor) {
122     *aOutDisplayPortAncestor = displayPortAncestor;
123   }
124   if (aOutHasTransformAnimation) {
125     *aOutHasTransformAnimation = hasTransformAnimation;
126   }
127 }
128 
BeginPaint()129 void ClientTiledPaintedLayer::BeginPaint() {
130   mPaintData.ResetPaintData();
131 
132   if (!GetBaseTransform().Is2D()) {
133     // Give up if there is a complex CSS transform on the layer. We might
134     // eventually support these but for now it's too complicated to handle
135     // given that it's a pretty rare scenario.
136     return;
137   }
138 
139   // Get the metrics of the nearest scrollable layer and the nearest layer
140   // with a displayport.
141   LayerMetricsWrapper scrollAncestor;
142   LayerMetricsWrapper displayPortAncestor;
143   bool hasTransformAnimation;
144   GetAncestorLayers(&scrollAncestor, &displayPortAncestor,
145                     &hasTransformAnimation);
146 
147   if (!displayPortAncestor || !scrollAncestor) {
148   // No displayport or scroll ancestor, so we can't do progressive rendering.
149 #if defined(MOZ_WIDGET_ANDROID)
150     // Android are guaranteed to have a displayport set, so this
151     // should never happen.
152     NS_WARNING("Tiled PaintedLayer with no scrollable container ancestor");
153 #endif
154     return;
155   }
156 
157   TILING_LOG(
158       "TILING %p: Found scrollAncestor %p, displayPortAncestor %p, transform "
159       "%d\n",
160       this, scrollAncestor.GetLayer(), displayPortAncestor.GetLayer(),
161       hasTransformAnimation);
162 
163   const FrameMetrics& scrollMetrics = scrollAncestor.Metrics();
164   const FrameMetrics& displayportMetrics = displayPortAncestor.Metrics();
165 
166   // Calculate the transform required to convert ParentLayer space of our
167   // display port ancestor to the Layer space of this layer.
168   ParentLayerToLayerMatrix4x4 transformDisplayPortToLayer =
169       GetTransformToAncestorsParentLayer(this, displayPortAncestor).Inverse();
170 
171   LayerRect layerBounds(GetVisibleRegion().GetBounds());
172 
173   // Compute the critical display port that applies to this layer in the
174   // LayoutDevice space of this layer, but only if there is no OMT animation
175   // on this layer. If there is an OMT animation then we need to draw the whole
176   // visible region of this layer as determined by layout, because we don't know
177   // what parts of it might move into view in the compositor.
178   mPaintData.mHasTransformAnimation = hasTransformAnimation;
179   if (!mPaintData.mHasTransformAnimation &&
180       mContentClient->GetLowPrecisionTiledBuffer()) {
181     ParentLayerRect criticalDisplayPort =
182         (displayportMetrics.GetCriticalDisplayPort() *
183          displayportMetrics.GetZoom()) +
184         displayportMetrics.GetCompositionBounds().TopLeft();
185     Maybe<LayerRect> criticalDisplayPortTransformed =
186         ApplyParentLayerToLayerTransform(transformDisplayPortToLayer,
187                                          criticalDisplayPort, layerBounds);
188     if (criticalDisplayPortTransformed) {
189       mPaintData.mCriticalDisplayPort =
190           Some(RoundedToInt(*criticalDisplayPortTransformed));
191     } else {
192       mPaintData.mCriticalDisplayPort = Some(LayerIntRect(0, 0, 0, 0));
193     }
194   }
195   TILING_LOG("TILING %p: Critical displayport %s\n", this,
196              mPaintData.mCriticalDisplayPort
197                  ? Stringify(*mPaintData.mCriticalDisplayPort).c_str()
198                  : "not set");
199 
200   // Store the resolution from the displayport ancestor layer. Because this is
201   // Gecko-side, before any async transforms have occurred, we can use the zoom
202   // for this.
203   mPaintData.mResolution = displayportMetrics.GetZoom();
204   TILING_LOG("TILING %p: Resolution %s\n", this,
205              Stringify(mPaintData.mResolution).c_str());
206 
207   // Store the applicable composition bounds in this layer's Layer units.
208   mPaintData.mTransformToCompBounds =
209       GetTransformToAncestorsParentLayer(this, scrollAncestor);
210   ParentLayerToLayerMatrix4x4 transformToBounds =
211       mPaintData.mTransformToCompBounds.Inverse();
212   Maybe<LayerRect> compositionBoundsTransformed =
213       ApplyParentLayerToLayerTransform(
214           transformToBounds, scrollMetrics.GetCompositionBounds(), layerBounds);
215   if (compositionBoundsTransformed) {
216     mPaintData.mCompositionBounds = *compositionBoundsTransformed;
217   } else {
218     mPaintData.mCompositionBounds.SetEmpty();
219   }
220   TILING_LOG("TILING %p: Composition bounds %s\n", this,
221              Stringify(mPaintData.mCompositionBounds).c_str());
222 
223   // Calculate the scroll offset since the last transaction
224   mPaintData.mScrollOffset =
225       displayportMetrics.GetScrollOffset() * displayportMetrics.GetZoom();
226   TILING_LOG("TILING %p: Scroll offset %s\n", this,
227              Stringify(mPaintData.mScrollOffset).c_str());
228 }
229 
IsScrollingOnCompositor(const FrameMetrics & aParentMetrics)230 bool ClientTiledPaintedLayer::IsScrollingOnCompositor(
231     const FrameMetrics& aParentMetrics) {
232   CompositorBridgeChild* compositor = nullptr;
233   if (Manager() && Manager()->AsClientLayerManager()) {
234     compositor = Manager()->AsClientLayerManager()->GetCompositorBridgeChild();
235   }
236 
237   if (!compositor) {
238     return false;
239   }
240 
241   FrameMetrics compositorMetrics;
242   if (!compositor->LookupCompositorFrameMetrics(aParentMetrics.GetScrollId(),
243                                                 compositorMetrics)) {
244     return false;
245   }
246 
247   // 1 is a tad high for a fuzzy equals epsilon however if our scroll delta
248   // is so small then we have nothing to gain from using paint heuristics.
249   float COORDINATE_EPSILON = 1.f;
250 
251   return !FuzzyEqualsAdditive(compositorMetrics.GetScrollOffset().x,
252                               aParentMetrics.GetScrollOffset().x,
253                               COORDINATE_EPSILON) ||
254          !FuzzyEqualsAdditive(compositorMetrics.GetScrollOffset().y,
255                               aParentMetrics.GetScrollOffset().y,
256                               COORDINATE_EPSILON);
257 }
258 
UseProgressiveDraw()259 bool ClientTiledPaintedLayer::UseProgressiveDraw() {
260   if (!gfxPrefs::ProgressivePaint()) {
261     // pref is disabled, so never do progressive
262     return false;
263   }
264 
265   if (!mContentClient->GetTiledBuffer()->SupportsProgressiveUpdate()) {
266     return false;
267   }
268 
269   if (ClientManager()->HasShadowTarget()) {
270     // This condition is true when we are in a reftest scenario. We don't want
271     // to draw progressively here because it can cause intermittent reftest
272     // failures because the harness won't wait for all the tiles to be drawn.
273     return false;
274   }
275 
276   if (GetIsFixedPosition() || GetParent()->GetIsFixedPosition()) {
277     // This layer is fixed-position and so even if it does have a scrolling
278     // ancestor it will likely be entirely on-screen all the time, so we
279     // should draw it all at once
280     return false;
281   }
282 
283   if (mPaintData.mHasTransformAnimation) {
284     // The compositor is going to animate this somehow, so we want it all
285     // on the screen at once.
286     return false;
287   }
288 
289   if (ClientManager()->AsyncPanZoomEnabled()) {
290     LayerMetricsWrapper scrollAncestor;
291     GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
292     MOZ_ASSERT(
293         scrollAncestor);  // because mPaintData.mCriticalDisplayPort is set
294     if (!scrollAncestor) {
295       return false;
296     }
297     const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
298     if (!IsScrollingOnCompositor(parentMetrics)) {
299       return false;
300     }
301   }
302 
303   return true;
304 }
305 
RenderHighPrecision(const nsIntRegion & aInvalidRegion,const nsIntRegion & aVisibleRegion,LayerManager::DrawPaintedLayerCallback aCallback,void * aCallbackData)306 bool ClientTiledPaintedLayer::RenderHighPrecision(
307     const nsIntRegion& aInvalidRegion, const nsIntRegion& aVisibleRegion,
308     LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData) {
309   // If we have started drawing low-precision already, then we
310   // shouldn't do anything there.
311   if (mPaintData.mLowPrecisionPaintCount != 0) {
312     return false;
313   }
314 
315   // Only draw progressively when there is something to paint and the
316   // resolution is unchanged
317   if (!aInvalidRegion.IsEmpty() && UseProgressiveDraw() &&
318       mContentClient->GetTiledBuffer()->GetFrameResolution() ==
319           mPaintData.mResolution) {
320     // Store the old valid region, then clear it before painting.
321     // We clip the old valid region to the visible region, as it only gets
322     // used to decide stale content (currently valid and previously visible)
323     nsIntRegion oldValidRegion =
324         mContentClient->GetTiledBuffer()->GetValidRegion();
325     oldValidRegion.And(oldValidRegion, aVisibleRegion);
326     if (mPaintData.mCriticalDisplayPort) {
327       oldValidRegion.And(oldValidRegion,
328                          mPaintData.mCriticalDisplayPort->ToUnknownRect());
329     }
330 
331     TILING_LOG("TILING %p: Progressive update with old valid region %s\n", this,
332                Stringify(oldValidRegion).c_str());
333 
334     nsIntRegion drawnRegion;
335     bool updatedBuffer = mContentClient->GetTiledBuffer()->ProgressiveUpdate(
336         GetValidRegion(), aInvalidRegion, oldValidRegion, drawnRegion,
337         &mPaintData, aCallback, aCallbackData);
338     AddToValidRegion(drawnRegion);
339     return updatedBuffer;
340   }
341 
342   // Otherwise do a non-progressive paint. We must do this even when
343   // the region to paint is empty as the valid region may have shrunk.
344 
345   nsIntRegion validRegion = aVisibleRegion;
346   if (mPaintData.mCriticalDisplayPort) {
347     validRegion.AndWith(mPaintData.mCriticalDisplayPort->ToUnknownRect());
348   }
349   SetValidRegion(validRegion);
350 
351   TILING_LOG("TILING %p: Non-progressive paint invalid region %s\n", this,
352              Stringify(aInvalidRegion).c_str());
353   TILING_LOG("TILING %p: Non-progressive paint new valid region %s\n", this,
354              Stringify(GetValidRegion()).c_str());
355 
356   TilePaintFlags flags =
357       PaintThread::Get() ? TilePaintFlags::Async : TilePaintFlags::None;
358 
359   mContentClient->GetTiledBuffer()->SetFrameResolution(mPaintData.mResolution);
360   mContentClient->GetTiledBuffer()->PaintThebes(
361       GetValidRegion(), aInvalidRegion, aInvalidRegion, aCallback,
362       aCallbackData, flags);
363   mPaintData.mPaintFinished = true;
364   return true;
365 }
366 
RenderLowPrecision(const nsIntRegion & aInvalidRegion,const nsIntRegion & aVisibleRegion,LayerManager::DrawPaintedLayerCallback aCallback,void * aCallbackData)367 bool ClientTiledPaintedLayer::RenderLowPrecision(
368     const nsIntRegion& aInvalidRegion, const nsIntRegion& aVisibleRegion,
369     LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData) {
370   nsIntRegion invalidRegion = aInvalidRegion;
371 
372   // Render the low precision buffer, if the visible region is larger than the
373   // critical display port.
374   if (!mPaintData.mCriticalDisplayPort ||
375       !nsIntRegion(mPaintData.mCriticalDisplayPort->ToUnknownRect())
376            .Contains(aVisibleRegion)) {
377     nsIntRegion oldValidRegion =
378         mContentClient->GetLowPrecisionTiledBuffer()->GetValidRegion();
379     oldValidRegion.And(oldValidRegion, aVisibleRegion);
380 
381     bool updatedBuffer = false;
382 
383     // If the frame resolution or format have changed, invalidate the buffer
384     if (mContentClient->GetLowPrecisionTiledBuffer()->GetFrameResolution() !=
385             mPaintData.mResolution ||
386         mContentClient->GetLowPrecisionTiledBuffer()->HasFormatChanged()) {
387       if (!mLowPrecisionValidRegion.IsEmpty()) {
388         updatedBuffer = true;
389       }
390       oldValidRegion.SetEmpty();
391       mLowPrecisionValidRegion.SetEmpty();
392       mContentClient->GetLowPrecisionTiledBuffer()->ResetPaintedAndValidState();
393       mContentClient->GetLowPrecisionTiledBuffer()->SetFrameResolution(
394           mPaintData.mResolution);
395       invalidRegion = aVisibleRegion;
396     }
397 
398     // Invalidate previously valid content that is no longer visible
399     if (mPaintData.mLowPrecisionPaintCount == 1) {
400       mLowPrecisionValidRegion.And(mLowPrecisionValidRegion, aVisibleRegion);
401     }
402     mPaintData.mLowPrecisionPaintCount++;
403 
404     // Remove the valid high-precision region from the invalid low-precision
405     // region. We don't want to spend time drawing things twice.
406     invalidRegion.SubOut(GetValidRegion());
407 
408     TILING_LOG(
409         "TILING %p: Progressive paint: low-precision invalid region is %s\n",
410         this, Stringify(invalidRegion).c_str());
411     TILING_LOG(
412         "TILING %p: Progressive paint: low-precision old valid region is %s\n",
413         this, Stringify(oldValidRegion).c_str());
414 
415     if (!invalidRegion.IsEmpty()) {
416       nsIntRegion drawnRegion;
417       updatedBuffer =
418           mContentClient->GetLowPrecisionTiledBuffer()->ProgressiveUpdate(
419               mLowPrecisionValidRegion, invalidRegion, oldValidRegion,
420               drawnRegion, &mPaintData, aCallback, aCallbackData);
421       mLowPrecisionValidRegion.OrWith(drawnRegion);
422     }
423 
424     TILING_LOG(
425         "TILING %p: Progressive paint: low-precision new valid region is %s\n",
426         this, Stringify(mLowPrecisionValidRegion).c_str());
427     return updatedBuffer;
428   }
429   if (!mLowPrecisionValidRegion.IsEmpty()) {
430     TILING_LOG("TILING %p: Clearing low-precision buffer\n", this);
431     // Clear the low precision tiled buffer.
432     mLowPrecisionValidRegion.SetEmpty();
433     mContentClient->GetLowPrecisionTiledBuffer()->ResetPaintedAndValidState();
434     // Return true here so we send a Painted callback after clearing the valid
435     // region of the low precision buffer. This allows the shadow buffer's valid
436     // region to be updated and the associated resources to be freed.
437     return true;
438   }
439   return false;
440 }
441 
EndPaint()442 void ClientTiledPaintedLayer::EndPaint() {
443   mPaintData.mLastScrollOffset = mPaintData.mScrollOffset;
444   mPaintData.mPaintFinished = true;
445   mPaintData.mFirstPaint = false;
446   TILING_LOG("TILING %p: Paint finished\n", this);
447 }
448 
RenderLayer()449 void ClientTiledPaintedLayer::RenderLayer() {
450   LayerManager::DrawPaintedLayerCallback callback =
451       ClientManager()->GetPaintedLayerCallback();
452   void* data = ClientManager()->GetPaintedLayerCallbackData();
453 
454   IntSize layerSize = mVisibleRegion.ToUnknownRegion().GetBounds().Size();
455   IntSize tileSize = gfx::gfxVars::TileSize();
456   bool isHalfTileWidthOrHeight = layerSize.width <= tileSize.width / 2 ||
457                                  layerSize.height <= tileSize.height / 2;
458 
459   // Use single tile when layer is not scrollable, is smaller than one
460   // tile, or when more than half of the tiles' pixels in either
461   // dimension would be wasted.
462   bool wantSingleTiledContentClient =
463       (mCreationHint == LayerManager::NONE || layerSize <= tileSize ||
464        isHalfTileWidthOrHeight) &&
465       SingleTiledContentClient::ClientSupportsLayerSize(layerSize,
466                                                         ClientManager()) &&
467       gfxPrefs::LayersSingleTileEnabled();
468 
469   if (mContentClient && mHaveSingleTiledContentClient &&
470       !wantSingleTiledContentClient) {
471     mContentClient = nullptr;
472     ClearValidRegion();
473   }
474 
475   if (!mContentClient) {
476     if (wantSingleTiledContentClient) {
477       mContentClient = new SingleTiledContentClient(*this, ClientManager());
478       mHaveSingleTiledContentClient = true;
479     } else {
480       mContentClient = new MultiTiledContentClient(*this, ClientManager());
481       mHaveSingleTiledContentClient = false;
482     }
483 
484     mContentClient->Connect();
485     ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
486     MOZ_ASSERT(mContentClient->GetForwarder());
487   }
488 
489   if (mContentClient->GetTiledBuffer()->HasFormatChanged()) {
490     ClearValidRegion();
491     mContentClient->GetTiledBuffer()->ResetPaintedAndValidState();
492   }
493 
494   TILING_LOG("TILING %p: Initial visible region %s\n", this,
495              Stringify(mVisibleRegion).c_str());
496   TILING_LOG("TILING %p: Initial valid region %s\n", this,
497              Stringify(GetValidRegion()).c_str());
498   TILING_LOG("TILING %p: Initial low-precision valid region %s\n", this,
499              Stringify(mLowPrecisionValidRegion).c_str());
500 
501   nsIntRegion neededRegion = mVisibleRegion.ToUnknownRegion();
502 #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
503   // This is handled by PadDrawTargetOutFromRegion in TiledContentClient for
504   // mobile
505   if (MayResample()) {
506     // If we're resampling then bilinear filtering can read up to 1 pixel
507     // outside of our texture coords. Make the visible region a single rect,
508     // and pad it out by 1 pixel (restricted to tile boundaries) so that
509     // we always have valid content or transparent pixels to sample from.
510     IntRect bounds = neededRegion.GetBounds();
511     IntRect wholeTiles = bounds;
512     wholeTiles.InflateToMultiple(gfx::gfxVars::TileSize());
513     IntRect padded = bounds;
514     padded.Inflate(1);
515     padded.IntersectRect(padded, wholeTiles);
516     neededRegion = padded;
517   }
518 #endif
519 
520   nsIntRegion invalidRegion;
521   invalidRegion.Sub(neededRegion, GetValidRegion());
522   if (invalidRegion.IsEmpty()) {
523     EndPaint();
524     return;
525   }
526 
527   if (!callback) {
528     ClientManager()->SetTransactionIncomplete();
529     return;
530   }
531 
532   if (!ClientManager()->IsRepeatTransaction()) {
533     // Only paint the mask layers on the first transaction.
534     RenderMaskLayers(this);
535 
536     // For more complex cases we need to calculate a bunch of metrics before we
537     // can do the paint.
538     BeginPaint();
539     if (mPaintData.mPaintFinished) {
540       return;
541     }
542 
543     // Make sure that tiles that fall outside of the visible region or outside
544     // of the critical displayport are discarded on the first update. Also make
545     // sure that we only draw stuff inside the critical displayport on the first
546     // update.
547     nsIntRegion validRegion;
548     validRegion.And(GetValidRegion(), neededRegion);
549     if (mPaintData.mCriticalDisplayPort) {
550       validRegion.AndWith(mPaintData.mCriticalDisplayPort->ToUnknownRect());
551       invalidRegion.And(invalidRegion,
552                         mPaintData.mCriticalDisplayPort->ToUnknownRect());
553     }
554     SetValidRegion(validRegion);
555 
556     TILING_LOG("TILING %p: First-transaction valid region %s\n", this,
557                Stringify(validRegion).c_str());
558     TILING_LOG("TILING %p: First-transaction invalid region %s\n", this,
559                Stringify(invalidRegion).c_str());
560   } else {
561     if (mPaintData.mCriticalDisplayPort) {
562       invalidRegion.And(invalidRegion,
563                         mPaintData.mCriticalDisplayPort->ToUnknownRect());
564     }
565     TILING_LOG("TILING %p: Repeat-transaction invalid region %s\n", this,
566                Stringify(invalidRegion).c_str());
567   }
568 
569   nsIntRegion lowPrecisionInvalidRegion;
570   if (mContentClient->GetLowPrecisionTiledBuffer()) {
571     // Calculate the invalid region for the low precision buffer. Make sure
572     // to remove the valid high-precision area so we don't double-paint it.
573     lowPrecisionInvalidRegion.Sub(neededRegion, mLowPrecisionValidRegion);
574     lowPrecisionInvalidRegion.Sub(lowPrecisionInvalidRegion, GetValidRegion());
575   }
576   TILING_LOG("TILING %p: Low-precision invalid region %s\n", this,
577              Stringify(lowPrecisionInvalidRegion).c_str());
578 
579   bool updatedHighPrecision =
580       RenderHighPrecision(invalidRegion, neededRegion, callback, data);
581   if (updatedHighPrecision) {
582     ClientManager()->Hold(this);
583     mContentClient->UpdatedBuffer(TiledContentClient::TILED_BUFFER);
584 
585     if (!mPaintData.mPaintFinished) {
586       // There is still more high-res stuff to paint, so we're not
587       // done yet. A subsequent transaction will take care of this.
588       ClientManager()->SetRepeatTransaction();
589       return;
590     }
591   }
592 
593   // If there is nothing to draw in low-precision, then we're done.
594   if (lowPrecisionInvalidRegion.IsEmpty()) {
595     EndPaint();
596     return;
597   }
598 
599   if (updatedHighPrecision) {
600     // If there are low precision updates, but we just did some high-precision
601     // updates, then mark the paint as unfinished and request a repeat
602     // transaction. This is so that we don't perform low-precision updates in
603     // the same transaction as high-precision updates.
604     TILING_LOG(
605         "TILING %p: Scheduling repeat transaction for low-precision painting\n",
606         this);
607     ClientManager()->SetRepeatTransaction();
608     mPaintData.mLowPrecisionPaintCount = 1;
609     mPaintData.mPaintFinished = false;
610     return;
611   }
612 
613   bool updatedLowPrecision = RenderLowPrecision(lowPrecisionInvalidRegion,
614                                                 neededRegion, callback, data);
615   if (updatedLowPrecision) {
616     ClientManager()->Hold(this);
617     mContentClient->UpdatedBuffer(
618         TiledContentClient::LOW_PRECISION_TILED_BUFFER);
619 
620     if (!mPaintData.mPaintFinished) {
621       // There is still more low-res stuff to paint, so we're not
622       // done yet. A subsequent transaction will take care of this.
623       ClientManager()->SetRepeatTransaction();
624       return;
625     }
626   }
627 
628   // If we get here, we've done all the high- and low-precision
629   // paints we wanted to do, so we can finish the paint and chill.
630   EndPaint();
631 }
632 
IsOptimizedFor(LayerManager::PaintedLayerCreationHint aHint)633 bool ClientTiledPaintedLayer::IsOptimizedFor(
634     LayerManager::PaintedLayerCreationHint aHint) {
635   // The only creation hint is whether the layer is scrollable or not, and this
636   // is only respected on OSX, where it's used to determine whether to
637   // use a tiled content client or not.
638   // There are pretty nasty performance consequences for not using tiles on
639   // large, scrollable layers, so we want the layer to be recreated in this
640   // situation.
641   return aHint == GetCreationHint();
642 }
643 
PrintInfo(std::stringstream & aStream,const char * aPrefix)644 void ClientTiledPaintedLayer::PrintInfo(std::stringstream& aStream,
645                                         const char* aPrefix) {
646   PaintedLayer::PrintInfo(aStream, aPrefix);
647   if (mContentClient) {
648     aStream << "\n";
649     nsAutoCString pfx(aPrefix);
650     pfx += "  ";
651     mContentClient->PrintInfo(aStream, pfx.get());
652   }
653 }
654 
655 }  // namespace layers
656 }  // namespace mozilla
657