LCOV - code coverage report
Current view: top level - gfx/layers/client - TiledContentClient.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 642 0.2 %
Date: 2017-07-14 16:53:18 Functions: 0 53 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "mozilla/layers/TiledContentClient.h"
       7             : #include <math.h>                       // for ceil, ceilf, floor
       8             : #include <algorithm>
       9             : #include "ClientTiledPaintedLayer.h"     // for ClientTiledPaintedLayer
      10             : #include "GeckoProfiler.h"              // for AUTO_PROFILER_LABEL
      11             : #include "ClientLayerManager.h"         // for ClientLayerManager
      12             : #include "gfxContext.h"                 // for gfxContext, etc
      13             : #include "gfxPlatform.h"                // for gfxPlatform
      14             : #include "gfxPrefs.h"                   // for gfxPrefs
      15             : #include "gfxRect.h"                    // for gfxRect
      16             : #include "mozilla/MathAlgorithms.h"     // for Abs
      17             : #include "mozilla/gfx/Point.h"          // for IntSize
      18             : #include "mozilla/gfx/Rect.h"           // for Rect
      19             : #include "mozilla/gfx/Tools.h"          // for BytesPerPixel
      20             : #include "mozilla/layers/CompositableForwarder.h"
      21             : #include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
      22             : #include "mozilla/layers/LayerMetricsWrapper.h"
      23             : #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder
      24             : #include "TextureClientPool.h"
      25             : #include "nsDebug.h"                    // for NS_ASSERTION
      26             : #include "nsISupportsImpl.h"            // for gfxContext::AddRef, etc
      27             : #include "nsExpirationTracker.h"        // for nsExpirationTracker
      28             : #include "nsMathUtils.h"               // for NS_lroundf
      29             : #include "LayersLogging.h"
      30             : #include "UnitTransforms.h"             // for TransformTo
      31             : #include "mozilla/UniquePtr.h"
      32             : 
      33             : // This is the minimum area that we deem reasonable to copy from the front buffer to the
      34             : // back buffer on tile updates. If the valid region is smaller than this, we just
      35             : // redraw it and save on the copy (and requisite surface-locking involved).
      36             : #define MINIMUM_TILE_COPY_AREA (1.f/16.f)
      37             : 
      38             : #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
      39             : #include "cairo.h"
      40             : #include <sstream>
      41             : using mozilla::layers::Layer;
      42             : static void DrawDebugOverlay(mozilla::gfx::DrawTarget* dt, int x, int y, int width, int height)
      43             : {
      44             :   gfxContext c(dt);
      45             : 
      46             :   // Draw border
      47             :   c.NewPath();
      48             :   c.SetDeviceColor(Color(0.f, 0.f, 0.f));
      49             :   c.Rectangle(gfxRect(0, 0, width, height));
      50             :   c.Stroke();
      51             : 
      52             :   // Build tile description
      53             :   std::stringstream ss;
      54             :   ss << x << ", " << y;
      55             : 
      56             :   // Draw text using cairo toy text API
      57             :   // XXX: this drawing will silently fail if |dt| doesn't have a Cairo backend
      58             :   cairo_t* cr = gfxFont::RefCairo(dt);
      59             :   cairo_set_font_size(cr, 25);
      60             :   cairo_text_extents_t extents;
      61             :   cairo_text_extents(cr, ss.str().c_str(), &extents);
      62             : 
      63             :   int textWidth = extents.width + 6;
      64             : 
      65             :   c.NewPath();
      66             :   c.SetDeviceColor(Color(0.f, 0.f, 0.f));
      67             :   c.Rectangle(gfxRect(gfxPoint(2,2),gfxSize(textWidth, 30)));
      68             :   c.Fill();
      69             : 
      70             :   c.NewPath();
      71             :   c.SetDeviceColor(Color(1.0, 0.0, 0.0));
      72             :   c.Rectangle(gfxRect(gfxPoint(2,2),gfxSize(textWidth, 30)));
      73             :   c.Stroke();
      74             : 
      75             :   c.NewPath();
      76             :   cairo_move_to(cr, 4, 28);
      77             :   cairo_show_text(cr, ss.str().c_str());
      78             : 
      79             : }
      80             : 
      81             : #endif
      82             : 
      83             : namespace mozilla {
      84             : 
      85             : using namespace gfx;
      86             : 
      87             : namespace layers {
      88             : 
      89             : 
      90           0 : MultiTiledContentClient::MultiTiledContentClient(ClientTiledPaintedLayer& aPaintedLayer,
      91           0 :                                                  ClientLayerManager* aManager)
      92             :   : TiledContentClient(aManager, "Multi")
      93             :   , mTiledBuffer(aPaintedLayer, *this, aManager, &mSharedFrameMetricsHelper)
      94           0 :   , mLowPrecisionTiledBuffer(aPaintedLayer, *this, aManager, &mSharedFrameMetricsHelper)
      95             : {
      96           0 :   MOZ_COUNT_CTOR(MultiTiledContentClient);
      97           0 :   mLowPrecisionTiledBuffer.SetResolution(gfxPrefs::LowPrecisionResolution());
      98           0 :   mHasLowPrecision = gfxPrefs::UseLowPrecisionBuffer();
      99           0 : }
     100             : 
     101             : void
     102           0 : MultiTiledContentClient::ClearCachedResources()
     103             : {
     104           0 :   CompositableClient::ClearCachedResources();
     105           0 :   mTiledBuffer.DiscardBuffers();
     106           0 :   mLowPrecisionTiledBuffer.DiscardBuffers();
     107           0 : }
     108             : 
     109             : void
     110           0 : MultiTiledContentClient::UpdatedBuffer(TiledBufferType aType)
     111             : {
     112             :   ClientMultiTiledLayerBuffer* buffer = aType == LOW_PRECISION_TILED_BUFFER
     113           0 :     ? &mLowPrecisionTiledBuffer
     114           0 :     : &mTiledBuffer;
     115             : 
     116           0 :   MOZ_ASSERT(aType != LOW_PRECISION_TILED_BUFFER || mHasLowPrecision);
     117             : 
     118           0 :   mForwarder->UseTiledLayerBuffer(this, buffer->GetSurfaceDescriptorTiles());
     119           0 :   buffer->ClearPaintedRegion();
     120           0 : }
     121             : 
     122           0 : SharedFrameMetricsHelper::SharedFrameMetricsHelper()
     123             :   : mLastProgressiveUpdateWasLowPrecision(false)
     124           0 :   , mProgressiveUpdateWasInDanger(false)
     125             : {
     126           0 :   MOZ_COUNT_CTOR(SharedFrameMetricsHelper);
     127           0 : }
     128             : 
     129           0 : SharedFrameMetricsHelper::~SharedFrameMetricsHelper()
     130             : {
     131           0 :   MOZ_COUNT_DTOR(SharedFrameMetricsHelper);
     132           0 : }
     133             : 
     134             : static inline bool
     135           0 : FuzzyEquals(float a, float b) {
     136           0 :   return (fabsf(a - b) < 1e-6);
     137             : }
     138             : 
     139             : static AsyncTransform
     140           0 : ComputeViewTransform(const FrameMetrics& aContentMetrics, const FrameMetrics& aCompositorMetrics)
     141             : {
     142             :   // This is basically the same code as AsyncPanZoomController::GetCurrentAsyncTransform
     143             :   // but with aContentMetrics used in place of mLastContentPaintMetrics, because they
     144             :   // should be equivalent, modulo race conditions while transactions are inflight.
     145             : 
     146           0 :   ParentLayerPoint translation = (aCompositorMetrics.GetScrollOffset() - aContentMetrics.GetScrollOffset())
     147           0 :                                * aCompositorMetrics.GetZoom();
     148           0 :   return AsyncTransform(aCompositorMetrics.GetAsyncZoom(), -translation);
     149             : }
     150             : 
     151             : bool
     152           0 : SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
     153             :     const LayerMetricsWrapper& aLayer,
     154             :     bool aHasPendingNewThebesContent,
     155             :     bool aLowPrecision,
     156             :     AsyncTransform& aViewTransform)
     157             : {
     158           0 :   MOZ_ASSERT(aLayer);
     159             : 
     160           0 :   CompositorBridgeChild* compositor = nullptr;
     161           0 :   if (aLayer.Manager() &&
     162           0 :       aLayer.Manager()->AsClientLayerManager()) {
     163           0 :     compositor = aLayer.Manager()->AsClientLayerManager()->GetCompositorBridgeChild();
     164             :   }
     165             : 
     166           0 :   if (!compositor) {
     167           0 :     return false;
     168             :   }
     169             : 
     170           0 :   const FrameMetrics& contentMetrics = aLayer.Metrics();
     171           0 :   FrameMetrics compositorMetrics;
     172             : 
     173           0 :   if (!compositor->LookupCompositorFrameMetrics(contentMetrics.GetScrollId(),
     174             :                                                 compositorMetrics)) {
     175           0 :     return false;
     176             :   }
     177             : 
     178           0 :   aViewTransform = ComputeViewTransform(contentMetrics, compositorMetrics);
     179             : 
     180             :   // Reset the checkerboard risk flag when switching to low precision
     181             :   // rendering.
     182           0 :   if (aLowPrecision && !mLastProgressiveUpdateWasLowPrecision) {
     183             :     // Skip low precision rendering until we're at risk of checkerboarding.
     184           0 :     if (!mProgressiveUpdateWasInDanger) {
     185             :       TILING_LOG("TILING: Aborting low-precision rendering because not at risk of checkerboarding\n");
     186           0 :       return true;
     187             :     }
     188           0 :     mProgressiveUpdateWasInDanger = false;
     189             :   }
     190           0 :   mLastProgressiveUpdateWasLowPrecision = aLowPrecision;
     191             : 
     192             :   // Always abort updates if the resolution has changed. There's no use
     193             :   // in drawing at the incorrect resolution.
     194           0 :   if (!FuzzyEquals(compositorMetrics.GetZoom().xScale, contentMetrics.GetZoom().xScale) ||
     195           0 :       !FuzzyEquals(compositorMetrics.GetZoom().yScale, contentMetrics.GetZoom().yScale)) {
     196             :     TILING_LOG("TILING: Aborting because resolution changed from %s to %s\n",
     197             :         ToString(contentMetrics.GetZoom()).c_str(), ToString(compositorMetrics.GetZoom()).c_str());
     198           0 :     return true;
     199             :   }
     200             : 
     201             :   // Never abort drawing if we can't be sure we've sent a more recent
     202             :   // display-port. If we abort updating when we shouldn't, we can end up
     203             :   // with blank regions on the screen and we open up the risk of entering
     204             :   // an endless updating cycle.
     205           0 :   if (fabsf(contentMetrics.GetScrollOffset().x - compositorMetrics.GetScrollOffset().x) <= 2 &&
     206           0 :       fabsf(contentMetrics.GetScrollOffset().y - compositorMetrics.GetScrollOffset().y) <= 2 &&
     207           0 :       fabsf(contentMetrics.GetDisplayPort().x - compositorMetrics.GetDisplayPort().x) <= 2 &&
     208           0 :       fabsf(contentMetrics.GetDisplayPort().y - compositorMetrics.GetDisplayPort().y) <= 2 &&
     209           0 :       fabsf(contentMetrics.GetDisplayPort().width - compositorMetrics.GetDisplayPort().width) <= 2 &&
     210           0 :       fabsf(contentMetrics.GetDisplayPort().height - compositorMetrics.GetDisplayPort().height) <= 2) {
     211           0 :     return false;
     212             :   }
     213             : 
     214             :   // When not a low precision pass and the page is in danger of checker boarding
     215             :   // abort update.
     216           0 :   if (!aLowPrecision && !mProgressiveUpdateWasInDanger) {
     217           0 :     bool scrollUpdatePending = contentMetrics.GetScrollOffsetUpdated() &&
     218           0 :         contentMetrics.GetScrollGeneration() != compositorMetrics.GetScrollGeneration();
     219             :     // If scrollUpdatePending is true, then that means the content-side
     220             :     // metrics has a new scroll offset that is going to be forced into the
     221             :     // compositor but it hasn't gotten there yet.
     222             :     // Even though right now comparing the metrics might indicate we're
     223             :     // about to checkerboard (and that's true), the checkerboarding will
     224             :     // disappear as soon as the new scroll offset update is processed
     225             :     // on the compositor side. To avoid leaving things in a low-precision
     226             :     // paint, we need to detect and handle this case (bug 1026756).
     227           0 :     if (!scrollUpdatePending && AboutToCheckerboard(contentMetrics, compositorMetrics)) {
     228           0 :       mProgressiveUpdateWasInDanger = true;
     229           0 :       return true;
     230             :     }
     231             :   }
     232             : 
     233             :   // Abort drawing stale low-precision content if there's a more recent
     234             :   // display-port in the pipeline.
     235           0 :   if (aLowPrecision && !aHasPendingNewThebesContent) {
     236             :     TILING_LOG("TILING: Aborting low-precision because of new pending content\n");
     237           0 :     return true;
     238             :   }
     239             : 
     240           0 :   return false;
     241             : }
     242             : 
     243             : bool
     244           0 : SharedFrameMetricsHelper::AboutToCheckerboard(const FrameMetrics& aContentMetrics,
     245             :                                               const FrameMetrics& aCompositorMetrics)
     246             : {
     247             :   // The size of the painted area is originally computed in layer pixels in layout, but then
     248             :   // converted to app units and then back to CSS pixels before being put in the FrameMetrics.
     249             :   // This process can introduce some rounding error, so we inflate the rect by one app unit
     250             :   // to account for that.
     251           0 :   CSSRect painted = (aContentMetrics.GetCriticalDisplayPort().IsEmpty()
     252           0 :                       ? aContentMetrics.GetDisplayPort()
     253             :                       : aContentMetrics.GetCriticalDisplayPort())
     254           0 :                     + aContentMetrics.GetScrollOffset();
     255           0 :   painted.Inflate(CSSMargin::FromAppUnits(nsMargin(1, 1, 1, 1)));
     256             : 
     257             :   // Inflate the rect by the danger zone. See the description of the danger zone prefs
     258             :   // in AsyncPanZoomController.cpp for an explanation of this.
     259           0 :   CSSRect showing = CSSRect(aCompositorMetrics.GetScrollOffset(),
     260           0 :                             aCompositorMetrics.CalculateBoundedCompositedSizeInCssPixels());
     261           0 :   showing.Inflate(LayerSize(gfxPrefs::APZDangerZoneX(), gfxPrefs::APZDangerZoneY())
     262           0 :                   / aCompositorMetrics.LayersPixelsPerCSSPixel());
     263             : 
     264             :   // Clamp both rects to the scrollable rect, because having either of those
     265             :   // exceed the scrollable rect doesn't make sense, and could lead to false
     266             :   // positives.
     267           0 :   painted = painted.Intersect(aContentMetrics.GetScrollableRect());
     268           0 :   showing = showing.Intersect(aContentMetrics.GetScrollableRect());
     269             : 
     270           0 :   if (!painted.Contains(showing)) {
     271             :     TILING_LOG("TILING: About to checkerboard; content %s\n", Stringify(aContentMetrics).c_str());
     272             :     TILING_LOG("TILING: About to checkerboard; painted %s\n", Stringify(painted).c_str());
     273             :     TILING_LOG("TILING: About to checkerboard; compositor %s\n", Stringify(aCompositorMetrics).c_str());
     274             :     TILING_LOG("TILING: About to checkerboard; showing %s\n", Stringify(showing).c_str());
     275           0 :     return true;
     276             :   }
     277           0 :   return false;
     278             : }
     279             : 
     280           0 : ClientMultiTiledLayerBuffer::ClientMultiTiledLayerBuffer(ClientTiledPaintedLayer& aPaintedLayer,
     281             :                                                          CompositableClient& aCompositableClient,
     282             :                                                          ClientLayerManager* aManager,
     283           0 :                                                          SharedFrameMetricsHelper* aHelper)
     284             :   : ClientTiledLayerBuffer(aPaintedLayer, aCompositableClient)
     285             :   , mManager(aManager)
     286             :   , mCallback(nullptr)
     287             :   , mCallbackData(nullptr)
     288           0 :   , mSharedFrameMetricsHelper(aHelper)
     289             : {
     290           0 : }
     291             : 
     292             : bool
     293           0 : ClientTiledLayerBuffer::HasFormatChanged() const
     294             : {
     295             :   SurfaceMode mode;
     296           0 :   gfxContentType content = GetContentType(&mode);
     297           0 :   return content != mLastPaintContentType ||
     298           0 :          mode != mLastPaintSurfaceMode;
     299             : }
     300             : 
     301             : 
     302             : gfxContentType
     303           0 : ClientTiledLayerBuffer::GetContentType(SurfaceMode* aMode) const
     304             : {
     305             :   gfxContentType content =
     306           0 :     mPaintedLayer.CanUseOpaqueSurface() ? gfxContentType::COLOR :
     307           0 :                                           gfxContentType::COLOR_ALPHA;
     308           0 :   SurfaceMode mode = mPaintedLayer.GetSurfaceMode();
     309             : 
     310           0 :   if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
     311             : #if defined(MOZ_GFX_OPTIMIZE_MOBILE)
     312             :     mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
     313             : #else
     314           0 :     if (!mPaintedLayer.GetParent() ||
     315           0 :         !mPaintedLayer.GetParent()->SupportsComponentAlphaChildren()) {
     316           0 :       mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
     317             :     } else {
     318           0 :       content = gfxContentType::COLOR;
     319             :     }
     320             : #endif
     321           0 :   } else if (mode == SurfaceMode::SURFACE_OPAQUE) {
     322             : #if defined(MOZ_GFX_OPTIMIZE_MOBILE)
     323             :     if (IsLowPrecision()) {
     324             :       // If we're in low-res mode, drawing can sample from outside the visible
     325             :       // region. Make sure that we only sample transparency if that happens.
     326             :       mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
     327             :       content = gfxContentType::COLOR_ALPHA;
     328             :     }
     329             : #else
     330           0 :     if (mPaintedLayer.MayResample()) {
     331           0 :       mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
     332           0 :       content = gfxContentType::COLOR_ALPHA;
     333             :     }
     334             : #endif
     335             :   }
     336             : 
     337           0 :   if (aMode) {
     338           0 :     *aMode = mode;
     339             :   }
     340           0 :   return content;
     341             : }
     342             : 
     343           0 : class TileExpiry final : public nsExpirationTracker<TileClient, 3>
     344             : {
     345             :   public:
     346           0 :     TileExpiry() : nsExpirationTracker<TileClient, 3>(1000, "TileExpiry") {}
     347             : 
     348           0 :     static void AddTile(TileClient* aTile)
     349             :     {
     350           0 :       if (!sTileExpiry) {
     351           0 :         sTileExpiry = MakeUnique<TileExpiry>();
     352             :       }
     353             : 
     354           0 :       sTileExpiry->AddObject(aTile);
     355           0 :     }
     356             : 
     357           0 :     static void RemoveTile(TileClient* aTile)
     358             :     {
     359           0 :       MOZ_ASSERT(sTileExpiry);
     360           0 :       sTileExpiry->RemoveObject(aTile);
     361           0 :     }
     362             : 
     363           0 :     static void Shutdown() {
     364           0 :       sTileExpiry = nullptr;
     365           0 :     }
     366             :   private:
     367           0 :     virtual void NotifyExpired(TileClient* aTile) override
     368             :     {
     369           0 :       aTile->DiscardBackBuffer();
     370           0 :     }
     371             : 
     372             :     static UniquePtr<TileExpiry> sTileExpiry;
     373             : };
     374           3 : UniquePtr<TileExpiry> TileExpiry::sTileExpiry;
     375             : 
     376           0 : void ShutdownTileCache()
     377             : {
     378           0 :   TileExpiry::Shutdown();
     379           0 : }
     380             : 
     381             : void
     382           0 : TileClient::PrivateProtector::Set(TileClient * const aContainer, RefPtr<TextureClient> aNewValue)
     383             : {
     384           0 :   if (mBuffer) {
     385           0 :     TileExpiry::RemoveTile(aContainer);
     386             :   }
     387           0 :   mBuffer = aNewValue;
     388           0 :   if (mBuffer) {
     389           0 :     TileExpiry::AddTile(aContainer);
     390             :   }
     391           0 : }
     392             : 
     393             : void
     394           0 : TileClient::PrivateProtector::Set(TileClient * const aContainer, TextureClient* aNewValue)
     395             : {
     396           0 :   Set(aContainer, RefPtr<TextureClient>(aNewValue));
     397           0 : }
     398             : 
     399             : // Placeholder
     400           0 : TileClient::TileClient()
     401           0 :   : mWasPlaceholder(false)
     402             : {
     403           0 : }
     404             : 
     405           0 : TileClient::~TileClient()
     406             : {
     407           0 :   if (mExpirationState.IsTracked()) {
     408           0 :     MOZ_ASSERT(mBackBuffer);
     409           0 :     TileExpiry::RemoveTile(this);
     410             :   }
     411           0 : }
     412             : 
     413           0 : TileClient::TileClient(const TileClient& o)
     414             : {
     415           0 :   mBackBuffer.Set(this, o.mBackBuffer);
     416           0 :   mBackBufferOnWhite = o.mBackBufferOnWhite;
     417           0 :   mFrontBuffer = o.mFrontBuffer;
     418           0 :   mFrontBufferOnWhite = o.mFrontBufferOnWhite;
     419           0 :   mWasPlaceholder = o.mWasPlaceholder;
     420           0 :   mUpdateRect = o.mUpdateRect;
     421             : #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
     422             :   mLastUpdate = o.mLastUpdate;
     423             : #endif
     424           0 :   mAllocator = o.mAllocator;
     425           0 :   mInvalidFront = o.mInvalidFront;
     426           0 :   mInvalidBack = o.mInvalidBack;
     427           0 : }
     428             : 
     429             : TileClient&
     430           0 : TileClient::operator=(const TileClient& o)
     431             : {
     432           0 :   if (this == &o) return *this;
     433           0 :   mBackBuffer.Set(this, o.mBackBuffer);
     434           0 :   mBackBufferOnWhite = o.mBackBufferOnWhite;
     435           0 :   mFrontBuffer = o.mFrontBuffer;
     436           0 :   mFrontBufferOnWhite = o.mFrontBufferOnWhite;
     437           0 :   mWasPlaceholder = o.mWasPlaceholder;
     438           0 :   mUpdateRect = o.mUpdateRect;
     439             : #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
     440             :   mLastUpdate = o.mLastUpdate;
     441             : #endif
     442           0 :   mAllocator = o.mAllocator;
     443           0 :   mInvalidFront = o.mInvalidFront;
     444           0 :   mInvalidBack = o.mInvalidBack;
     445           0 :   return *this;
     446             : }
     447             : 
     448             : void
     449           0 : TileClient::Dump(std::stringstream& aStream)
     450             : {
     451           0 :   aStream << "TileClient(bb=" << (TextureClient*)mBackBuffer << " fb=" << mFrontBuffer.get();
     452           0 :   if (mBackBufferOnWhite) {
     453           0 :     aStream << " bbow=" << mBackBufferOnWhite.get();
     454             :   }
     455           0 :   if (mFrontBufferOnWhite) {
     456           0 :     aStream << " fbow=" << mFrontBufferOnWhite.get();
     457             :   }
     458           0 :   aStream << ")";
     459           0 : }
     460             : 
     461             : void
     462           0 : TileClient::Flip()
     463             : {
     464           0 :   RefPtr<TextureClient> frontBuffer = mFrontBuffer;
     465           0 :   RefPtr<TextureClient> frontBufferOnWhite = mFrontBufferOnWhite;
     466           0 :   mFrontBuffer = mBackBuffer;
     467           0 :   mFrontBufferOnWhite = mBackBufferOnWhite;
     468           0 :   mBackBuffer.Set(this, frontBuffer);
     469           0 :   mBackBufferOnWhite = frontBufferOnWhite;
     470           0 :   nsIntRegion invalidFront = mInvalidFront;
     471           0 :   mInvalidFront = mInvalidBack;
     472           0 :   mInvalidBack = invalidFront;
     473           0 : }
     474             : 
     475             : static bool
     476           0 : CopyFrontToBack(TextureClient* aFront,
     477             :                 TextureClient* aBack,
     478             :                 const gfx::IntRect& aRectToCopy)
     479             : {
     480           0 :   TextureClientAutoLock frontLock(aFront, OpenMode::OPEN_READ);
     481           0 :   if (!frontLock.Succeeded()) {
     482           0 :     gfxCriticalError() << "[Tiling:Client] Failed to lock the tile's front buffer";
     483           0 :     return false;
     484             :   }
     485             : 
     486           0 :   if (!aBack->Lock(OpenMode::OPEN_READ_WRITE)) {
     487           0 :     gfxCriticalError() << "[Tiling:Client] Failed to lock the tile's back buffer";
     488           0 :     return false;
     489             :   }
     490             : 
     491           0 :   gfx::IntPoint rectToCopyTopLeft = aRectToCopy.TopLeft();
     492           0 :   aFront->CopyToTextureClient(aBack, &aRectToCopy, &rectToCopyTopLeft);
     493           0 :   return true;
     494             : }
     495             : 
     496             : void
     497           0 : TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
     498             :                                         nsIntRegion& aAddPaintedRegion)
     499             : {
     500           0 :   if (mBackBuffer && mFrontBuffer) {
     501           0 :     gfx::IntSize tileSize = mFrontBuffer->GetSize();
     502           0 :     const IntRect tileRect = IntRect(0, 0, tileSize.width, tileSize.height);
     503             : 
     504           0 :     if (aDirtyRegion.Contains(tileRect)) {
     505             :       // The dirty region means that we no longer need the front buffer, so
     506             :       // discard it.
     507           0 :       DiscardFrontBuffer();
     508             :     } else {
     509             :       // Region that needs copying.
     510           0 :       nsIntRegion regionToCopy = mInvalidBack;
     511             : 
     512           0 :       regionToCopy.Sub(regionToCopy, aDirtyRegion);
     513             : 
     514           0 :       aAddPaintedRegion = regionToCopy;
     515             : 
     516           0 :       if (regionToCopy.IsEmpty()) {
     517             :         // Just redraw it all.
     518           0 :         return;
     519             :       }
     520             : 
     521             :       // Copy the bounding rect of regionToCopy. As tiles are quite small, it
     522             :       // is unlikely that we'd save much by copying each individual rect of the
     523             :       // region, but we can reevaluate this if it becomes an issue.
     524           0 :       const IntRect rectToCopy = regionToCopy.GetBounds();
     525           0 :       gfx::IntRect gfxRectToCopy(rectToCopy.x, rectToCopy.y, rectToCopy.width, rectToCopy.height);
     526           0 :       CopyFrontToBack(mFrontBuffer, mBackBuffer, gfxRectToCopy);
     527             : 
     528           0 :       if (mBackBufferOnWhite) {
     529           0 :         MOZ_ASSERT(mFrontBufferOnWhite);
     530           0 :         CopyFrontToBack(mFrontBufferOnWhite, mBackBufferOnWhite, gfxRectToCopy);
     531             :       }
     532             : 
     533           0 :       mInvalidBack.SetEmpty();
     534             :     }
     535             :   }
     536             : }
     537             : 
     538             : void
     539           0 : TileClient::DiscardFrontBuffer()
     540             : {
     541           0 :   if (mFrontBuffer) {
     542           0 :     MOZ_ASSERT(mFrontBuffer->GetReadLock());
     543             : 
     544           0 :     MOZ_ASSERT(mAllocator);
     545           0 :     if (mAllocator) {
     546           0 :       mAllocator->ReturnTextureClientDeferred(mFrontBuffer);
     547           0 :       if (mFrontBufferOnWhite) {
     548           0 :         mAllocator->ReturnTextureClientDeferred(mFrontBufferOnWhite);
     549             :       }
     550             :     }
     551             : 
     552           0 :     if (mFrontBuffer->IsLocked()) {
     553           0 :       mFrontBuffer->Unlock();
     554             :     }
     555           0 :     if (mFrontBufferOnWhite && mFrontBufferOnWhite->IsLocked()) {
     556           0 :       mFrontBufferOnWhite->Unlock();
     557             :     }
     558           0 :     mFrontBuffer = nullptr;
     559           0 :     mFrontBufferOnWhite = nullptr;
     560             :   }
     561           0 : }
     562             : 
     563             : static void
     564           0 : DiscardTexture(TextureClient* aTexture, TextureClientAllocator* aAllocator)
     565             : {
     566           0 :   MOZ_ASSERT(aAllocator);
     567           0 :   if (aTexture && aAllocator) {
     568           0 :     MOZ_ASSERT(aTexture->GetReadLock());
     569           0 :     if (!aTexture->HasSynchronization() && aTexture->IsReadLocked()) {
     570             :       // Our current back-buffer is still locked by the compositor. This can occur
     571             :       // when the client is producing faster than the compositor can consume. In
     572             :       // this case we just want to drop it and not return it to the pool.
     573           0 :      aAllocator->ReportClientLost();
     574             :     } else {
     575           0 :       aAllocator->ReturnTextureClientDeferred(aTexture);
     576             :     }
     577           0 :     if (aTexture->IsLocked()) {
     578           0 :       aTexture->Unlock();
     579             :     }
     580             :   }
     581           0 : }
     582             : 
     583             : void
     584           0 : TileClient::DiscardBackBuffer()
     585             : {
     586           0 :   if (mBackBuffer) {
     587           0 :     DiscardTexture(mBackBuffer, mAllocator);
     588           0 :     mBackBuffer.Set(this, nullptr);
     589           0 :     DiscardTexture(mBackBufferOnWhite, mAllocator);
     590           0 :     mBackBufferOnWhite = nullptr;
     591             :   }
     592           0 : }
     593             : 
     594             : static already_AddRefed<TextureClient>
     595           0 : CreateBackBufferTexture(TextureClient* aCurrentTexture,
     596             :                         CompositableClient& aCompositable,
     597             :                         TextureClientAllocator* aAllocator)
     598             : {
     599           0 :   if (aCurrentTexture) {
     600             :     // Our current back-buffer is still locked by the compositor. This can occur
     601             :     // when the client is producing faster than the compositor can consume. In
     602             :     // this case we just want to drop it and not return it to the pool.
     603           0 :     aAllocator->ReportClientLost();
     604             :   }
     605             : 
     606           0 :   RefPtr<TextureClient> texture = aAllocator->GetTextureClient();
     607             : 
     608           0 :   if (!texture) {
     609           0 :     gfxCriticalError() << "[Tiling:Client] Failed to allocate a TextureClient";
     610           0 :     return nullptr;
     611             :   }
     612             : 
     613           0 :   texture->EnableReadLock();
     614             : 
     615           0 :   if (!aCompositable.AddTextureClient(texture)) {
     616           0 :     gfxCriticalError() << "[Tiling:Client] Failed to connect a TextureClient";
     617           0 :     return nullptr;
     618             :   }
     619             : 
     620           0 :   return texture.forget();
     621             : }
     622             : 
     623             : TextureClient*
     624           0 : TileClient::GetBackBuffer(CompositableClient& aCompositable,
     625             :                           const nsIntRegion& aDirtyRegion,
     626             :                           gfxContentType aContent,
     627             :                           SurfaceMode aMode,
     628             :                           nsIntRegion& aAddPaintedRegion,
     629             :                           RefPtr<TextureClient>* aBackBufferOnWhite)
     630             : {
     631           0 :   if (!mAllocator) {
     632           0 :     gfxCriticalError() << "[TileClient] Missing TextureClientAllocator.";
     633           0 :     return nullptr;
     634             :   }
     635           0 :   if (aMode != SurfaceMode::SURFACE_COMPONENT_ALPHA) {
     636             :     // It can happen that a component-alpha layer stops being on component alpha
     637             :     // on the next frame, just drop the buffers on white if that happens.
     638           0 :     if (mBackBufferOnWhite) {
     639           0 :       mAllocator->ReportClientLost();
     640           0 :       mBackBufferOnWhite = nullptr;
     641             :     }
     642           0 :     if (mFrontBufferOnWhite) {
     643           0 :       mAllocator->ReportClientLost();
     644           0 :       mFrontBufferOnWhite = nullptr;
     645             :     }
     646             :   }
     647             : 
     648             :   // Try to re-use the front-buffer if possible
     649           0 :   if (mFrontBuffer &&
     650           0 :       mFrontBuffer->HasIntermediateBuffer() &&
     651           0 :       !mFrontBuffer->IsReadLocked() &&
     652           0 :       (aMode != SurfaceMode::SURFACE_COMPONENT_ALPHA || (
     653           0 :         mFrontBufferOnWhite && !mFrontBufferOnWhite->IsReadLocked()))) {
     654             :     // If we had a backbuffer we no longer care about it since we'll
     655             :     // re-use the front buffer.
     656           0 :     DiscardBackBuffer();
     657           0 :     Flip();
     658             :   } else {
     659           0 :     if (!mBackBuffer || mBackBuffer->IsReadLocked()) {
     660           0 :       mBackBuffer.Set(this,
     661           0 :         CreateBackBufferTexture(mBackBuffer, aCompositable, mAllocator)
     662           0 :       );
     663           0 :       if (!mBackBuffer) {
     664           0 :         DiscardBackBuffer();
     665           0 :         DiscardFrontBuffer();
     666           0 :         return nullptr;
     667             :       }
     668           0 :       mInvalidBack = IntRect(IntPoint(), mBackBuffer->GetSize());
     669             :     }
     670             : 
     671           0 :     if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA
     672           0 :         && (!mBackBufferOnWhite || mBackBufferOnWhite->IsReadLocked())) {
     673           0 :       mBackBufferOnWhite = CreateBackBufferTexture(
     674             :         mBackBufferOnWhite, aCompositable, mAllocator
     675           0 :       );
     676           0 :       if (!mBackBufferOnWhite) {
     677           0 :         DiscardBackBuffer();
     678           0 :         DiscardFrontBuffer();
     679           0 :         return nullptr;
     680             :       }
     681           0 :       mInvalidBack = IntRect(IntPoint(), mBackBufferOnWhite->GetSize());
     682             :     }
     683             : 
     684           0 :     ValidateBackBufferFromFront(aDirtyRegion, aAddPaintedRegion);
     685             :   }
     686             : 
     687           0 :   if (!mBackBuffer->IsLocked()) {
     688           0 :     if (!mBackBuffer->Lock(OpenMode::OPEN_READ_WRITE)) {
     689           0 :       gfxCriticalError() << "[Tiling:Client] Failed to lock a tile (B)";
     690           0 :       DiscardBackBuffer();
     691           0 :       DiscardFrontBuffer();
     692           0 :       return nullptr;
     693             :     }
     694             :   }
     695             : 
     696           0 :   if (mBackBufferOnWhite && !mBackBufferOnWhite->IsLocked()) {
     697           0 :     if (!mBackBufferOnWhite->Lock(OpenMode::OPEN_READ_WRITE)) {
     698           0 :       gfxCriticalError() << "[Tiling:Client] Failed to lock a tile (W)";
     699           0 :       DiscardBackBuffer();
     700           0 :       DiscardFrontBuffer();
     701           0 :       return nullptr;
     702             :     }
     703             :   }
     704             : 
     705           0 :   *aBackBufferOnWhite = mBackBufferOnWhite;
     706           0 :   return mBackBuffer;
     707             : }
     708             : 
     709             : TileDescriptor
     710           0 : TileClient::GetTileDescriptor()
     711             : {
     712           0 :   if (IsPlaceholderTile()) {
     713           0 :     mWasPlaceholder = true;
     714           0 :     return PlaceholderTileDescriptor();
     715             :   }
     716           0 :   bool wasPlaceholder = mWasPlaceholder;
     717           0 :   mWasPlaceholder = false;
     718             : 
     719           0 :   ReadLockDescriptor lock;
     720           0 :   mFrontBuffer->SerializeReadLock(lock);
     721             : 
     722           0 :   ReadLockDescriptor lockOnWhite = null_t();
     723           0 :   if (mFrontBufferOnWhite) {
     724           0 :     mFrontBufferOnWhite->SerializeReadLock(lockOnWhite);
     725             :   }
     726             : 
     727           0 :   return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(),
     728           0 :                                 mFrontBufferOnWhite ? MaybeTexture(mFrontBufferOnWhite->GetIPDLActor()) : MaybeTexture(null_t()),
     729             :                                 mUpdateRect,
     730             :                                 lock, lockOnWhite,
     731           0 :                                 wasPlaceholder);
     732             : }
     733             : 
     734             : void
     735           0 : ClientMultiTiledLayerBuffer::DiscardBuffers()
     736             : {
     737           0 :   for (TileClient& tile : mRetainedTiles) {
     738           0 :     tile.DiscardBuffers();
     739             :   }
     740           0 : }
     741             : 
     742             : SurfaceDescriptorTiles
     743           0 : ClientMultiTiledLayerBuffer::GetSurfaceDescriptorTiles()
     744             : {
     745           0 :   InfallibleTArray<TileDescriptor> tiles;
     746             : 
     747           0 :   for (TileClient& tile : mRetainedTiles) {
     748           0 :     TileDescriptor tileDesc = tile.GetTileDescriptor();
     749           0 :     tiles.AppendElement(tileDesc);
     750             :     // Reset the update rect
     751           0 :     tile.mUpdateRect = IntRect();
     752             :   }
     753             :   return SurfaceDescriptorTiles(mValidRegion,
     754             :                                 tiles,
     755             :                                 mTileOrigin, mTileSize,
     756             :                                 mTiles.mFirst.x, mTiles.mFirst.y,
     757             :                                 mTiles.mSize.width, mTiles.mSize.height,
     758             :                                 mResolution, mFrameResolution.xScale,
     759             :                                 mFrameResolution.yScale,
     760           0 :                                 mWasLastPaintProgressive);
     761             : }
     762             : 
     763             : void
     764           0 : ClientMultiTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
     765             :                                          const nsIntRegion& aPaintRegion,
     766             :                                          const nsIntRegion& aDirtyRegion,
     767             :                                          LayerManager::DrawPaintedLayerCallback aCallback,
     768             :                                          void* aCallbackData,
     769             :                                          bool aIsProgressive)
     770             : {
     771             :   TILING_LOG("TILING %p: PaintThebes painting region %s\n", &mPaintedLayer, Stringify(aPaintRegion).c_str());
     772             :   TILING_LOG("TILING %p: PaintThebes new valid region %s\n", &mPaintedLayer, Stringify(aNewValidRegion).c_str());
     773             : 
     774           0 :   mCallback = aCallback;
     775           0 :   mCallbackData = aCallbackData;
     776           0 :   mWasLastPaintProgressive = aIsProgressive;
     777             : 
     778             : #ifdef GFX_TILEDLAYER_PREF_WARNINGS
     779             :   long start = PR_IntervalNow();
     780             : #endif
     781             : 
     782             : #ifdef GFX_TILEDLAYER_PREF_WARNINGS
     783             :   if (PR_IntervalNow() - start > 30) {
     784             :     const IntRect bounds = aPaintRegion.GetBounds();
     785             :     printf_stderr("Time to draw %i: %i, %i, %i, %i\n", PR_IntervalNow() - start, bounds.x, bounds.y, bounds.width, bounds.height);
     786             :     if (aPaintRegion.IsComplex()) {
     787             :       printf_stderr("Complex region\n");
     788             :       for (auto iter = aPaintRegion.RectIter(); !iter.Done(); iter.Next()) {
     789             :         const IntRect& rect = iter.Get();
     790             :         printf_stderr(" rect %i, %i, %i, %i\n",
     791             :                       rect.x, rect.y, rect.width, rect.height);
     792             :       }
     793             :     }
     794             :   }
     795             :   start = PR_IntervalNow();
     796             : #endif
     797             : 
     798           0 :   AUTO_PROFILER_LABEL("ClientMultiTiledLayerBuffer::PaintThebes", GRAPHICS);
     799             : 
     800           0 :   mNewValidRegion = aNewValidRegion;
     801           0 :   Update(aNewValidRegion, aPaintRegion, aDirtyRegion);
     802             : 
     803             : #ifdef GFX_TILEDLAYER_PREF_WARNINGS
     804             :   if (PR_IntervalNow() - start > 10) {
     805             :     const IntRect bounds = aPaintRegion.GetBounds();
     806             :     printf_stderr("Time to tile %i: %i, %i, %i, %i\n", PR_IntervalNow() - start, bounds.x, bounds.y, bounds.width, bounds.height);
     807             :   }
     808             : #endif
     809             : 
     810           0 :   mLastPaintContentType = GetContentType(&mLastPaintSurfaceMode);
     811           0 :   mCallback = nullptr;
     812           0 :   mCallbackData = nullptr;
     813           0 : }
     814             : 
     815           0 : void PadDrawTargetOutFromRegion(RefPtr<DrawTarget> drawTarget, nsIntRegion &region)
     816             : {
     817           0 :   struct LockedBits {
     818             :     uint8_t *data;
     819             :     IntSize size;
     820             :     int32_t stride;
     821             :     SurfaceFormat format;
     822           0 :     static int clamp(int x, int min, int max)
     823             :     {
     824           0 :       if (x < min)
     825           0 :         x = min;
     826           0 :       if (x > max)
     827           0 :         x = max;
     828           0 :       return x;
     829             :     }
     830             : 
     831           0 :     static void ensure_memcpy(uint8_t *dst, uint8_t *src, size_t n, uint8_t *bitmap, int stride, int height)
     832             :     {
     833           0 :         if (src + n > bitmap + stride*height) {
     834           0 :             MOZ_CRASH("GFX: long src memcpy");
     835             :         }
     836           0 :         if (src < bitmap) {
     837           0 :             MOZ_CRASH("GFX: short src memcpy");
     838             :         }
     839           0 :         if (dst + n > bitmap + stride*height) {
     840           0 :             MOZ_CRASH("GFX: long dst mempcy");
     841             :         }
     842           0 :         if (dst < bitmap) {
     843           0 :             MOZ_CRASH("GFX: short dst mempcy");
     844             :         }
     845           0 :     }
     846             : 
     847           0 :     static void visitor(void *closure, VisitSide side, int x1, int y1, int x2, int y2) {
     848           0 :       LockedBits *lb = static_cast<LockedBits*>(closure);
     849           0 :       uint8_t *bitmap = lb->data;
     850           0 :       const int bpp = gfx::BytesPerPixel(lb->format);
     851           0 :       const int stride = lb->stride;
     852           0 :       const int width = lb->size.width;
     853           0 :       const int height = lb->size.height;
     854             : 
     855           0 :       if (side == VisitSide::TOP) {
     856           0 :         if (y1 > 0) {
     857           0 :           x1 = clamp(x1, 0, width - 1);
     858           0 :           x2 = clamp(x2, 0, width - 1);
     859           0 :           ensure_memcpy(&bitmap[x1*bpp + (y1-1) * stride], &bitmap[x1*bpp + y1 * stride], (x2 - x1) * bpp, bitmap, stride, height);
     860           0 :           memcpy(&bitmap[x1*bpp + (y1-1) * stride], &bitmap[x1*bpp + y1 * stride], (x2 - x1) * bpp);
     861             :         }
     862           0 :       } else if (side == VisitSide::BOTTOM) {
     863           0 :         if (y1 < height) {
     864           0 :           x1 = clamp(x1, 0, width - 1);
     865           0 :           x2 = clamp(x2, 0, width - 1);
     866           0 :           ensure_memcpy(&bitmap[x1*bpp + y1 * stride], &bitmap[x1*bpp + (y1-1) * stride], (x2 - x1) * bpp, bitmap, stride, height);
     867           0 :           memcpy(&bitmap[x1*bpp + y1 * stride], &bitmap[x1*bpp + (y1-1) * stride], (x2 - x1) * bpp);
     868             :         }
     869           0 :       } else if (side == VisitSide::LEFT) {
     870           0 :         if (x1 > 0) {
     871           0 :           while (y1 != y2) {
     872           0 :             memcpy(&bitmap[(x1-1)*bpp + y1 * stride], &bitmap[x1*bpp + y1*stride], bpp);
     873           0 :             y1++;
     874             :           }
     875             :         }
     876           0 :       } else if (side == VisitSide::RIGHT) {
     877           0 :         if (x1 < width) {
     878           0 :           while (y1 != y2) {
     879           0 :             memcpy(&bitmap[x1*bpp + y1 * stride], &bitmap[(x1-1)*bpp + y1*stride], bpp);
     880           0 :             y1++;
     881             :           }
     882             :         }
     883             :       }
     884             : 
     885           0 :     }
     886           0 :   } lb;
     887             : 
     888           0 :   if (drawTarget->LockBits(&lb.data, &lb.size, &lb.stride, &lb.format)) {
     889             :     // we can only pad software targets so if we can't lock the bits don't pad
     890           0 :     region.VisitEdges(lb.visitor, &lb);
     891           0 :     drawTarget->ReleaseBits(lb.data);
     892             :   }
     893           0 : }
     894             : 
     895             : void
     896           0 : ClientTiledLayerBuffer::UnlockTile(TileClient& aTile)
     897             : {
     898             :   // We locked the back buffer, and flipped so we now need to unlock the front
     899           0 :   if (aTile.mFrontBuffer && aTile.mFrontBuffer->IsLocked()) {
     900           0 :     aTile.mFrontBuffer->Unlock();
     901           0 :     aTile.mFrontBuffer->SyncWithObject(mCompositableClient.GetForwarder()->GetSyncObject());
     902             :   }
     903           0 :   if (aTile.mFrontBufferOnWhite && aTile.mFrontBufferOnWhite->IsLocked()) {
     904           0 :     aTile.mFrontBufferOnWhite->Unlock();
     905           0 :     aTile.mFrontBufferOnWhite->SyncWithObject(mCompositableClient.GetForwarder()->GetSyncObject());
     906             :   }
     907           0 :   if (aTile.mBackBuffer && aTile.mBackBuffer->IsLocked()) {
     908           0 :     aTile.mBackBuffer->Unlock();
     909             :   }
     910           0 :   if (aTile.mBackBufferOnWhite && aTile.mBackBufferOnWhite->IsLocked()) {
     911           0 :     aTile.mBackBufferOnWhite->Unlock();
     912             :   }
     913           0 : }
     914             : 
     915           0 : void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
     916             :                                          const nsIntRegion& aPaintRegion,
     917             :                                          const nsIntRegion& aDirtyRegion)
     918             : {
     919           0 :   const IntSize scaledTileSize = GetScaledTileSize();
     920           0 :   const gfx::IntRect newBounds = newValidRegion.GetBounds();
     921             : 
     922           0 :   const TilesPlacement oldTiles = mTiles;
     923           0 :   const TilesPlacement newTiles(floor_div(newBounds.x, scaledTileSize.width),
     924           0 :                           floor_div(newBounds.y, scaledTileSize.height),
     925           0 :                           floor_div(GetTileStart(newBounds.x, scaledTileSize.width)
     926           0 :                                     + newBounds.width, scaledTileSize.width) + 1,
     927           0 :                           floor_div(GetTileStart(newBounds.y, scaledTileSize.height)
     928           0 :                                     + newBounds.height, scaledTileSize.height) + 1);
     929             : 
     930           0 :   const size_t oldTileCount = mRetainedTiles.Length();
     931           0 :   const size_t newTileCount = newTiles.mSize.width * newTiles.mSize.height;
     932             : 
     933           0 :   nsTArray<TileClient> oldRetainedTiles;
     934           0 :   mRetainedTiles.SwapElements(oldRetainedTiles);
     935           0 :   mRetainedTiles.SetLength(newTileCount);
     936             : 
     937           0 :   for (size_t oldIndex = 0; oldIndex < oldTileCount; oldIndex++) {
     938           0 :     const TileIntPoint tilePosition = oldTiles.TilePosition(oldIndex);
     939           0 :     const size_t newIndex = newTiles.TileIndex(tilePosition);
     940             :     // First, get the already existing tiles to the right place in the new array.
     941             :     // Leave placeholders (default constructor) where there was no tile.
     942           0 :     if (newTiles.HasTile(tilePosition)) {
     943           0 :       mRetainedTiles[newIndex] = oldRetainedTiles[oldIndex];
     944             :     } else {
     945             :       // release tiles that we are not going to reuse before allocating new ones
     946             :       // to avoid allocating unnecessarily.
     947           0 :       oldRetainedTiles[oldIndex].DiscardBuffers();
     948             :     }
     949             :   }
     950             : 
     951           0 :   oldRetainedTiles.Clear();
     952             : 
     953           0 :   if (!aPaintRegion.IsEmpty()) {
     954           0 :     for (size_t i = 0; i < newTileCount; ++i) {
     955           0 :       const TileIntPoint tilePosition = newTiles.TilePosition(i);
     956             : 
     957           0 :       IntPoint tileOffset = GetTileOffset(tilePosition);
     958           0 :       nsIntRegion tileDrawRegion = IntRect(tileOffset, scaledTileSize);
     959           0 :       tileDrawRegion.AndWith(aPaintRegion);
     960             : 
     961           0 :       if (tileDrawRegion.IsEmpty()) {
     962           0 :         continue;
     963             :       }
     964             : 
     965           0 :       TileClient& tile = mRetainedTiles[i];
     966           0 :       if (!ValidateTile(tile, GetTileOffset(tilePosition), tileDrawRegion)) {
     967           0 :         gfxCriticalError() << "ValidateTile failed";
     968             :       }
     969             :     }
     970             : 
     971           0 :     if (mMoz2DTiles.size() > 0) {
     972             :       gfx::TileSet tileset;
     973           0 :       for (size_t i = 0; i < mMoz2DTiles.size(); ++i) {
     974           0 :         mMoz2DTiles[i].mTileOrigin -= mTilingOrigin;
     975             :       }
     976           0 :       tileset.mTiles = &mMoz2DTiles[0];
     977           0 :       tileset.mTileCount = mMoz2DTiles.size();
     978           0 :       RefPtr<DrawTarget> drawTarget = gfx::Factory::CreateTiledDrawTarget(tileset);
     979           0 :       if (!drawTarget || !drawTarget->IsValid()) {
     980           0 :         gfxDevCrash(LogReason::InvalidContext) << "Invalid tiled draw target";
     981           0 :         return;
     982             :       }
     983           0 :       drawTarget->SetTransform(Matrix());
     984             : 
     985           0 :       RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(drawTarget);
     986           0 :       MOZ_ASSERT(ctx); // already checked the draw target above
     987           0 :       ctx->SetMatrix(
     988           0 :         ctx->CurrentMatrix().PreScale(mResolution, mResolution).PreTranslate(ThebesPoint(-mTilingOrigin)));
     989             : 
     990           0 :       mCallback(&mPaintedLayer, ctx, aPaintRegion, aDirtyRegion,
     991           0 :                 DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
     992           0 :       mMoz2DTiles.clear();
     993             :       // Reset:
     994           0 :       mTilingOrigin = IntPoint(std::numeric_limits<int32_t>::max(),
     995           0 :                                std::numeric_limits<int32_t>::max());
     996             :     }
     997             : 
     998           0 :     bool edgePaddingEnabled = gfxPrefs::TileEdgePaddingEnabled();
     999             : 
    1000           0 :     for (uint32_t i = 0; i < mRetainedTiles.Length(); ++i) {
    1001           0 :       TileClient& tile = mRetainedTiles[i];
    1002             : 
    1003             :       // Only worry about padding when not doing low-res because it simplifies
    1004             :       // the math and the artifacts won't be noticable
    1005             :       // Edge padding prevents sampling artifacts when compositing.
    1006           0 :       if (edgePaddingEnabled && mResolution == 1 &&
    1007           0 :           tile.mFrontBuffer && tile.mFrontBuffer->IsLocked()) {
    1008             : 
    1009           0 :         const TileIntPoint tilePosition = newTiles.TilePosition(i);
    1010           0 :         IntPoint tileOffset = GetTileOffset(tilePosition);
    1011             :         // Strictly speakig we want the unscaled rect here, but it doesn't matter
    1012             :         // because we only run this code when the resolution is equal to 1.
    1013             :         IntRect tileRect = IntRect(tileOffset.x, tileOffset.y,
    1014           0 :                                    GetTileSize().width, GetTileSize().height);
    1015             : 
    1016           0 :         nsIntRegion tileDrawRegion = IntRect(tileOffset, scaledTileSize);
    1017           0 :         tileDrawRegion.AndWith(aPaintRegion);
    1018             : 
    1019           0 :         nsIntRegion tileValidRegion = mValidRegion;
    1020           0 :         tileValidRegion.OrWith(tileDrawRegion);
    1021             : 
    1022             :         // We only need to pad out if the tile has area that's not valid
    1023           0 :         if (!tileValidRegion.Contains(tileRect)) {
    1024           0 :           tileValidRegion = tileValidRegion.Intersect(tileRect);
    1025             :           // translate the region into tile space and pad
    1026           0 :           tileValidRegion.MoveBy(-IntPoint(tileOffset.x, tileOffset.y));
    1027           0 :           RefPtr<DrawTarget> drawTarget = tile.mFrontBuffer->BorrowDrawTarget();
    1028           0 :           PadDrawTargetOutFromRegion(drawTarget, tileValidRegion);
    1029             :         }
    1030             :       }
    1031           0 :       UnlockTile(tile);
    1032             :     }
    1033             :   }
    1034             : 
    1035           0 :   mTiles = newTiles;
    1036           0 :   mValidRegion = newValidRegion;
    1037           0 :   mPaintedRegion.OrWith(aPaintRegion);
    1038             : }
    1039             : 
    1040             : bool
    1041           0 : ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
    1042             :                                           const nsIntPoint& aTileOrigin,
    1043             :                                           const nsIntRegion& aDirtyRegion)
    1044             : {
    1045           0 :   AUTO_PROFILER_LABEL("ClientMultiTiledLayerBuffer::ValidateTile", GRAPHICS);
    1046             : 
    1047             : #ifdef GFX_TILEDLAYER_PREF_WARNINGS
    1048             :   if (aDirtyRegion.IsComplex()) {
    1049             :     printf_stderr("Complex region\n");
    1050             :   }
    1051             : #endif
    1052             : 
    1053             :   SurfaceMode mode;
    1054           0 :   gfxContentType content = GetContentType(&mode);
    1055             : 
    1056           0 :   if (!aTile.mAllocator) {
    1057           0 :     aTile.SetTextureAllocator(mManager->GetCompositorBridgeChild()->GetTexturePool(
    1058           0 :       mManager->AsShadowForwarder(),
    1059           0 :       gfxPlatform::GetPlatform()->Optimal2DFormatForContent(content),
    1060           0 :       TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD));
    1061           0 :     MOZ_ASSERT(aTile.mAllocator);
    1062             :   }
    1063             : 
    1064           0 :   nsIntRegion offsetScaledDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin);
    1065           0 :   offsetScaledDirtyRegion.ScaleRoundOut(mResolution, mResolution);
    1066             : 
    1067           0 :   nsIntRegion extraPainted;
    1068           0 :   RefPtr<TextureClient> backBufferOnWhite;
    1069             :   RefPtr<TextureClient> backBuffer =
    1070             :     aTile.GetBackBuffer(mCompositableClient,
    1071             :                         offsetScaledDirtyRegion,
    1072             :                         content, mode,
    1073             :                         extraPainted,
    1074           0 :                         &backBufferOnWhite);
    1075             : 
    1076           0 :   aTile.mUpdateRect = offsetScaledDirtyRegion.GetBounds().Union(extraPainted.GetBounds());
    1077             : 
    1078           0 :   extraPainted.MoveBy(aTileOrigin);
    1079           0 :   extraPainted.And(extraPainted, mNewValidRegion);
    1080           0 :   mPaintedRegion.Or(mPaintedRegion, extraPainted);
    1081             : 
    1082           0 :   if (!backBuffer) {
    1083           0 :     return false;
    1084             :   }
    1085             : 
    1086           0 :   gfx::Tile moz2DTile;
    1087           0 :   RefPtr<DrawTarget> dt = backBuffer->BorrowDrawTarget();
    1088           0 :   RefPtr<DrawTarget> dtOnWhite;
    1089           0 :   if (backBufferOnWhite) {
    1090           0 :     dtOnWhite = backBufferOnWhite->BorrowDrawTarget();
    1091           0 :     moz2DTile.mDrawTarget = Factory::CreateDualDrawTarget(dt, dtOnWhite);
    1092             :   } else {
    1093           0 :     moz2DTile.mDrawTarget = dt;
    1094             :   }
    1095           0 :   moz2DTile.mTileOrigin = gfx::IntPoint(aTileOrigin.x, aTileOrigin.y);
    1096           0 :   if (!dt || (backBufferOnWhite && !dtOnWhite)) {
    1097           0 :     aTile.DiscardBuffers();
    1098           0 :     return false;
    1099             :   }
    1100             : 
    1101           0 :   mMoz2DTiles.push_back(moz2DTile);
    1102           0 :   mTilingOrigin.x = std::min(mTilingOrigin.x, moz2DTile.mTileOrigin.x);
    1103           0 :   mTilingOrigin.y = std::min(mTilingOrigin.y, moz2DTile.mTileOrigin.y);
    1104             : 
    1105           0 :   for (auto iter = aDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
    1106           0 :     const IntRect& dirtyRect = iter.Get();
    1107           0 :     gfx::Rect drawRect(dirtyRect.x - aTileOrigin.x,
    1108           0 :                        dirtyRect.y - aTileOrigin.y,
    1109           0 :                        dirtyRect.width,
    1110           0 :                        dirtyRect.height);
    1111           0 :     drawRect.Scale(mResolution);
    1112             : 
    1113             :     // Mark the newly updated area as invalid in the front buffer
    1114           0 :     aTile.mInvalidFront.Or(aTile.mInvalidFront, IntRect::RoundOut(drawRect));
    1115             : 
    1116           0 :     if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
    1117           0 :       dt->FillRect(drawRect, ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
    1118           0 :       dtOnWhite->FillRect(drawRect, ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
    1119           0 :     } else if (content == gfxContentType::COLOR_ALPHA) {
    1120           0 :       dt->ClearRect(drawRect);
    1121             :     }
    1122             :   }
    1123             : 
    1124             :   // The new buffer is now validated, remove the dirty region from it.
    1125           0 :   aTile.mInvalidBack.SubOut(offsetScaledDirtyRegion);
    1126             : 
    1127           0 :   aTile.Flip();
    1128             : 
    1129           0 :   return true;
    1130             : }
    1131             : 
    1132             : /**
    1133             :  * This function takes the transform stored in aTransformToCompBounds
    1134             :  * (which was generated in GetTransformToAncestorsParentLayer), and
    1135             :  * modifies it with the ViewTransform from the compositor side so that
    1136             :  * it reflects what the compositor is actually rendering. This operation
    1137             :  * basically adds in the layer's async transform.
    1138             :  * This function then returns the scroll ancestor's composition bounds,
    1139             :  * transformed into the painted layer's LayerPixel coordinates, accounting
    1140             :  * for the compositor state.
    1141             :  */
    1142             : static Maybe<LayerRect>
    1143           0 : GetCompositorSideCompositionBounds(const LayerMetricsWrapper& aScrollAncestor,
    1144             :                                    const LayerToParentLayerMatrix4x4& aTransformToCompBounds,
    1145             :                                    const AsyncTransform& aAPZTransform,
    1146             :                                    const LayerRect& aClip)
    1147             : {
    1148             :   LayerToParentLayerMatrix4x4 transform = aTransformToCompBounds *
    1149           0 :       AsyncTransformComponentMatrix(aAPZTransform);
    1150             : 
    1151           0 :   return UntransformBy(transform.Inverse(),
    1152           0 :     aScrollAncestor.Metrics().GetCompositionBounds(), aClip);
    1153             : }
    1154             : 
    1155             : bool
    1156           0 : ClientMultiTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvalidRegion,
    1157             :                                                             const nsIntRegion& aOldValidRegion,
    1158             :                                                             nsIntRegion& aRegionToPaint,
    1159             :                                                             BasicTiledLayerPaintData* aPaintData,
    1160             :                                                             bool aIsRepeated)
    1161             : {
    1162           0 :   aRegionToPaint = aInvalidRegion;
    1163             : 
    1164             :   // If the composition bounds rect is empty, we can't make any sensible
    1165             :   // decision about how to update coherently. In this case, just update
    1166             :   // everything in one transaction.
    1167           0 :   if (aPaintData->mCompositionBounds.IsEmpty()) {
    1168           0 :     aPaintData->mPaintFinished = true;
    1169           0 :     return false;
    1170             :   }
    1171             : 
    1172             :   // If this is a low precision buffer, we force progressive updates. The
    1173             :   // assumption is that the contents is less important, so visual coherency
    1174             :   // is lower priority than speed.
    1175           0 :   bool drawingLowPrecision = IsLowPrecision();
    1176             : 
    1177             :   // Find out if we have any non-stale content to update.
    1178           0 :   nsIntRegion staleRegion;
    1179           0 :   staleRegion.And(aInvalidRegion, aOldValidRegion);
    1180             : 
    1181             :   TILING_LOG("TILING %p: Progressive update stale region %s\n", &mPaintedLayer, Stringify(staleRegion).c_str());
    1182             : 
    1183           0 :   LayerMetricsWrapper scrollAncestor;
    1184           0 :   mPaintedLayer.GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
    1185             : 
    1186             :   // Find out the current view transform to determine which tiles to draw
    1187             :   // first, and see if we should just abort this paint. Aborting is usually
    1188             :   // caused by there being an incoming, more relevant paint.
    1189           0 :   AsyncTransform viewTransform;
    1190           0 :   MOZ_ASSERT(mSharedFrameMetricsHelper);
    1191             : 
    1192             :   bool abortPaint =
    1193           0 :     mSharedFrameMetricsHelper->UpdateFromCompositorFrameMetrics(
    1194             :       scrollAncestor,
    1195           0 :       !staleRegion.Contains(aInvalidRegion),
    1196             :       drawingLowPrecision,
    1197           0 :       viewTransform);
    1198             : 
    1199             :   TILING_LOG("TILING %p: Progressive update view transform %s zoom %f abort %d\n",
    1200             :       &mPaintedLayer, ToString(viewTransform.mTranslation).c_str(), viewTransform.mScale.scale, abortPaint);
    1201             : 
    1202           0 :   if (abortPaint) {
    1203             :     // We ignore if front-end wants to abort if this is the first,
    1204             :     // non-low-precision paint, as in that situation, we're about to override
    1205             :     // front-end's page/viewport metrics.
    1206           0 :     if (!aPaintData->mFirstPaint || drawingLowPrecision) {
    1207           0 :       AUTO_PROFILER_LABEL(
    1208             :         "ClientMultiTiledLayerBuffer::ComputeProgressiveUpdateRegion",
    1209             :         GRAPHICS);
    1210             : 
    1211           0 :       aRegionToPaint.SetEmpty();
    1212           0 :       return aIsRepeated;
    1213             :     }
    1214             :   }
    1215             : 
    1216             :   Maybe<LayerRect> transformedCompositionBounds =
    1217             :     GetCompositorSideCompositionBounds(scrollAncestor,
    1218             :                                        aPaintData->mTransformToCompBounds,
    1219             :                                        viewTransform,
    1220           0 :                                        LayerRect(mPaintedLayer.GetVisibleRegion().GetBounds()));
    1221             : 
    1222           0 :   if (!transformedCompositionBounds) {
    1223           0 :     aPaintData->mPaintFinished = true;
    1224           0 :     return false;
    1225             :   }
    1226             : 
    1227             :   TILING_LOG("TILING %p: Progressive update transformed compositor bounds %s\n", &mPaintedLayer, Stringify(*transformedCompositionBounds).c_str());
    1228             : 
    1229             :   // Compute a "coherent update rect" that we should paint all at once in a
    1230             :   // single transaction. This is to avoid rendering glitches on animated
    1231             :   // page content, and when layers change size/shape.
    1232             :   // On Fennec uploads are more expensive because we're not using gralloc, so
    1233             :   // we use a coherent update rect that is intersected with the screen at the
    1234             :   // time of issuing the draw command. This will paint faster but also potentially
    1235             :   // make the progressive paint more visible to the user while scrolling.
    1236           0 :   IntRect coherentUpdateRect(RoundedOut(
    1237             : #ifdef MOZ_WIDGET_ANDROID
    1238             :     transformedCompositionBounds->Intersect(aPaintData->mCompositionBounds)
    1239             : #else
    1240           0 :     *transformedCompositionBounds
    1241             : #endif
    1242           0 :   ).ToUnknownRect());
    1243             : 
    1244             :   TILING_LOG("TILING %p: Progressive update final coherency rect %s\n", &mPaintedLayer, Stringify(coherentUpdateRect).c_str());
    1245             : 
    1246           0 :   aRegionToPaint.And(aInvalidRegion, coherentUpdateRect);
    1247           0 :   aRegionToPaint.Or(aRegionToPaint, staleRegion);
    1248           0 :   bool drawingStale = !aRegionToPaint.IsEmpty();
    1249           0 :   if (!drawingStale) {
    1250           0 :     aRegionToPaint = aInvalidRegion;
    1251             :   }
    1252             : 
    1253             :   // Prioritise tiles that are currently visible on the screen.
    1254           0 :   bool paintingVisible = false;
    1255           0 :   if (aRegionToPaint.Intersects(coherentUpdateRect)) {
    1256           0 :     aRegionToPaint.And(aRegionToPaint, coherentUpdateRect);
    1257           0 :     paintingVisible = true;
    1258             :   }
    1259             : 
    1260             :   TILING_LOG("TILING %p: Progressive update final paint region %s\n", &mPaintedLayer, Stringify(aRegionToPaint).c_str());
    1261             : 
    1262             :   // Paint area that's visible and overlaps previously valid content to avoid
    1263             :   // visible glitches in animated elements, such as gifs.
    1264           0 :   bool paintInSingleTransaction = paintingVisible && (drawingStale || aPaintData->mFirstPaint);
    1265             : 
    1266             :   TILING_LOG("TILING %p: paintingVisible %d drawingStale %d firstPaint %d singleTransaction %d\n",
    1267             :     &mPaintedLayer, paintingVisible, drawingStale, aPaintData->mFirstPaint, paintInSingleTransaction);
    1268             : 
    1269             :   // The following code decides what order to draw tiles in, based on the
    1270             :   // current scroll direction of the primary scrollable layer.
    1271           0 :   NS_ASSERTION(!aRegionToPaint.IsEmpty(), "Unexpectedly empty paint region!");
    1272           0 :   IntRect paintBounds = aRegionToPaint.GetBounds();
    1273             : 
    1274             :   int startX, incX, startY, incY;
    1275           0 :   gfx::IntSize scaledTileSize = GetScaledTileSize();
    1276           0 :   if (aPaintData->mScrollOffset.x >= aPaintData->mLastScrollOffset.x) {
    1277           0 :     startX = RoundDownToTileEdge(paintBounds.x, scaledTileSize.width);
    1278           0 :     incX = scaledTileSize.width;
    1279             :   } else {
    1280           0 :     startX = RoundDownToTileEdge(paintBounds.XMost() - 1, scaledTileSize.width);
    1281           0 :     incX = -scaledTileSize.width;
    1282             :   }
    1283             : 
    1284           0 :   if (aPaintData->mScrollOffset.y >= aPaintData->mLastScrollOffset.y) {
    1285           0 :     startY = RoundDownToTileEdge(paintBounds.y, scaledTileSize.height);
    1286           0 :     incY = scaledTileSize.height;
    1287             :   } else {
    1288           0 :     startY = RoundDownToTileEdge(paintBounds.YMost() - 1, scaledTileSize.height);
    1289           0 :     incY = -scaledTileSize.height;
    1290             :   }
    1291             : 
    1292             :   // Find a tile to draw.
    1293           0 :   IntRect tileBounds(startX, startY, scaledTileSize.width, scaledTileSize.height);
    1294           0 :   int32_t scrollDiffX = aPaintData->mScrollOffset.x - aPaintData->mLastScrollOffset.x;
    1295           0 :   int32_t scrollDiffY = aPaintData->mScrollOffset.y - aPaintData->mLastScrollOffset.y;
    1296             :   // This loop will always terminate, as there is at least one tile area
    1297             :   // along the first/last row/column intersecting with regionToPaint, or its
    1298             :   // bounds would have been smaller.
    1299             :   while (true) {
    1300           0 :     aRegionToPaint.And(aInvalidRegion, tileBounds);
    1301           0 :     if (!aRegionToPaint.IsEmpty()) {
    1302           0 :       if (mResolution != 1) {
    1303             :         // Paint the entire tile for low-res. This is aimed to fixing low-res resampling
    1304             :         // and to avoid doing costly region accurate painting for a small area.
    1305           0 :         aRegionToPaint = tileBounds;
    1306             :       }
    1307           0 :       break;
    1308             :     }
    1309           0 :     if (Abs(scrollDiffY) >= Abs(scrollDiffX)) {
    1310           0 :       tileBounds.x += incX;
    1311             :     } else {
    1312           0 :       tileBounds.y += incY;
    1313             :     }
    1314             :   }
    1315             : 
    1316           0 :   if (!aRegionToPaint.Contains(aInvalidRegion)) {
    1317             :     // The region needed to paint is larger then our progressive chunk size
    1318             :     // therefore update what we want to paint and ask for a new paint transaction.
    1319             : 
    1320             :     // If we need to draw more than one tile to maintain coherency, make
    1321             :     // sure it happens in the same transaction by requesting this work be
    1322             :     // repeated immediately.
    1323             :     // If this is unnecessary, the remaining work will be done tile-by-tile in
    1324             :     // subsequent transactions. The caller code is responsible for scheduling
    1325             :     // the subsequent transactions as long as we don't set the mPaintFinished
    1326             :     // flag to true.
    1327           0 :     return (!drawingLowPrecision && paintInSingleTransaction);
    1328             :   }
    1329             : 
    1330             :   // We're not repeating painting and we've not requested a repeat transaction,
    1331             :   // so the paint is finished. If there's still a separate low precision
    1332             :   // paint to do, it will get marked as unfinished later.
    1333           0 :   aPaintData->mPaintFinished = true;
    1334           0 :   return false;
    1335             : }
    1336             : 
    1337             : bool
    1338           0 : ClientMultiTiledLayerBuffer::ProgressiveUpdate(const nsIntRegion& aValidRegion,
    1339             :                                                const nsIntRegion& aInvalidRegion,
    1340             :                                                const nsIntRegion& aOldValidRegion,
    1341             :                                                nsIntRegion& aOutDrawnRegion,
    1342             :                                                BasicTiledLayerPaintData* aPaintData,
    1343             :                                                LayerManager::DrawPaintedLayerCallback aCallback,
    1344             :                                                void* aCallbackData)
    1345             : {
    1346             :   TILING_LOG("TILING %p: Progressive update valid region %s\n", &mPaintedLayer, Stringify(aValidRegion).c_str());
    1347             :   TILING_LOG("TILING %p: Progressive update invalid region %s\n", &mPaintedLayer, Stringify(aInvalidRegion).c_str());
    1348             :   TILING_LOG("TILING %p: Progressive update old valid region %s\n", &mPaintedLayer, Stringify(aOldValidRegion).c_str());
    1349             : 
    1350           0 :   bool repeat = false;
    1351           0 :   bool isBufferChanged = false;
    1352           0 :   nsIntRegion remainingInvalidRegion = aInvalidRegion;
    1353           0 :   nsIntRegion updatedValidRegion = aValidRegion;
    1354           0 :   do {
    1355             :     // Compute the region that should be updated. Repeat as many times as
    1356             :     // is required.
    1357           0 :     nsIntRegion regionToPaint;
    1358           0 :     repeat = ComputeProgressiveUpdateRegion(remainingInvalidRegion,
    1359             :                                             aOldValidRegion,
    1360             :                                             regionToPaint,
    1361             :                                             aPaintData,
    1362           0 :                                             repeat);
    1363             : 
    1364             :     TILING_LOG("TILING %p: Progressive update computed paint region %s repeat %d\n", &mPaintedLayer, Stringify(regionToPaint).c_str(), repeat);
    1365             : 
    1366             :     // There's no further work to be done.
    1367           0 :     if (regionToPaint.IsEmpty()) {
    1368           0 :       break;
    1369             :     }
    1370             : 
    1371           0 :     isBufferChanged = true;
    1372             : 
    1373             :     // Keep track of what we're about to refresh.
    1374           0 :     aOutDrawnRegion.OrWith(regionToPaint);
    1375           0 :     updatedValidRegion.OrWith(regionToPaint);
    1376             : 
    1377             :     // aValidRegion may have been altered by InvalidateRegion, but we still
    1378             :     // want to display stale content until it gets progressively updated.
    1379             :     // Create a region that includes stale content.
    1380           0 :     nsIntRegion validOrStale;
    1381           0 :     validOrStale.Or(updatedValidRegion, aOldValidRegion);
    1382             : 
    1383             :     // Paint the computed region and subtract it from the invalid region.
    1384             :     PaintThebes(validOrStale, regionToPaint, remainingInvalidRegion,
    1385           0 :                 aCallback, aCallbackData, true);
    1386           0 :     remainingInvalidRegion.SubOut(regionToPaint);
    1387             :   } while (repeat);
    1388             : 
    1389             :   TILING_LOG("TILING %p: Progressive update final valid region %s buffer changed %d\n", &mPaintedLayer, Stringify(updatedValidRegion).c_str(), isBufferChanged);
    1390             :   TILING_LOG("TILING %p: Progressive update final invalid region %s\n", &mPaintedLayer, Stringify(remainingInvalidRegion).c_str());
    1391             : 
    1392             :   // Return false if nothing has been drawn, or give what has been drawn
    1393             :   // to the shadow layer to upload.
    1394           0 :   return isBufferChanged;
    1395             : }
    1396             : 
    1397             : void
    1398           0 : TiledContentClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
    1399             : {
    1400           0 :   aStream << aPrefix;
    1401           0 :   aStream << nsPrintfCString("%sTiledContentClient (0x%p)", mName, this).get();
    1402             : 
    1403           0 :   if (profiler_feature_active(ProfilerFeature::DisplayListDump)) {
    1404           0 :     nsAutoCString pfx(aPrefix);
    1405           0 :     pfx += "  ";
    1406             : 
    1407           0 :     Dump(aStream, pfx.get(), false);
    1408             :   }
    1409           0 : }
    1410             : 
    1411             : void
    1412           0 : TiledContentClient::Dump(std::stringstream& aStream,
    1413             :                          const char* aPrefix,
    1414             :                          bool aDumpHtml,
    1415             :                          TextureDumpMode aCompress)
    1416             : {
    1417           0 :   GetTiledBuffer()->Dump(aStream, aPrefix, aDumpHtml, aCompress);
    1418           0 : }
    1419             : 
    1420             : void
    1421           0 : BasicTiledLayerPaintData::ResetPaintData()
    1422             : {
    1423           0 :   mLowPrecisionPaintCount = 0;
    1424           0 :   mPaintFinished = false;
    1425           0 :   mHasTransformAnimation = false;
    1426           0 :   mCompositionBounds.SetEmpty();
    1427           0 :   mCriticalDisplayPort = Nothing();
    1428           0 : }
    1429             : 
    1430             : } // namespace layers
    1431             : } // namespace mozilla

Generated by: LCOV version 1.13