Coverage Report

Created: 2018-09-25 14:53

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