Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | #include "ClientTiledThebesLayer.h" |
michael@0 | 6 | #include "FrameMetrics.h" // for FrameMetrics |
michael@0 | 7 | #include "Units.h" // for ScreenIntRect, CSSPoint, etc |
michael@0 | 8 | #include "UnitTransforms.h" // for TransformTo |
michael@0 | 9 | #include "ClientLayerManager.h" // for ClientLayerManager, etc |
michael@0 | 10 | #include "gfx3DMatrix.h" // for gfx3DMatrix |
michael@0 | 11 | #include "gfxPlatform.h" // for gfxPlatform |
michael@0 | 12 | #include "gfxPrefs.h" // for gfxPrefs |
michael@0 | 13 | #include "gfxRect.h" // for gfxRect |
michael@0 | 14 | #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc |
michael@0 | 15 | #include "mozilla/gfx/BaseSize.h" // for BaseSize |
michael@0 | 16 | #include "mozilla/gfx/Rect.h" // for Rect, RectTyped |
michael@0 | 17 | #include "mozilla/layers/LayersMessages.h" |
michael@0 | 18 | #include "mozilla/mozalloc.h" // for operator delete, etc |
michael@0 | 19 | #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc |
michael@0 | 20 | #include "nsRect.h" // for nsIntRect |
michael@0 | 21 | |
michael@0 | 22 | namespace mozilla { |
michael@0 | 23 | namespace layers { |
michael@0 | 24 | |
michael@0 | 25 | |
michael@0 | 26 | ClientTiledThebesLayer::ClientTiledThebesLayer(ClientLayerManager* const aManager) |
michael@0 | 27 | : ThebesLayer(aManager, |
michael@0 | 28 | static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST())) |
michael@0 | 29 | , mContentClient() |
michael@0 | 30 | { |
michael@0 | 31 | MOZ_COUNT_CTOR(ClientTiledThebesLayer); |
michael@0 | 32 | mPaintData.mLastScrollOffset = ParentLayerPoint(0, 0); |
michael@0 | 33 | mPaintData.mFirstPaint = true; |
michael@0 | 34 | } |
michael@0 | 35 | |
michael@0 | 36 | ClientTiledThebesLayer::~ClientTiledThebesLayer() |
michael@0 | 37 | { |
michael@0 | 38 | MOZ_COUNT_DTOR(ClientTiledThebesLayer); |
michael@0 | 39 | } |
michael@0 | 40 | |
michael@0 | 41 | void |
michael@0 | 42 | ClientTiledThebesLayer::ClearCachedResources() |
michael@0 | 43 | { |
michael@0 | 44 | if (mContentClient) { |
michael@0 | 45 | mContentClient->ClearCachedResources(); |
michael@0 | 46 | } |
michael@0 | 47 | } |
michael@0 | 48 | |
michael@0 | 49 | void |
michael@0 | 50 | ClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs) |
michael@0 | 51 | { |
michael@0 | 52 | aAttrs = ThebesLayerAttributes(GetValidRegion()); |
michael@0 | 53 | } |
michael@0 | 54 | |
michael@0 | 55 | static LayoutDeviceRect |
michael@0 | 56 | ApplyParentLayerToLayoutTransform(const gfx3DMatrix& aTransform, const ParentLayerRect& aParentLayerRect) |
michael@0 | 57 | { |
michael@0 | 58 | return TransformTo<LayoutDevicePixel>(aTransform, aParentLayerRect); |
michael@0 | 59 | } |
michael@0 | 60 | |
michael@0 | 61 | void |
michael@0 | 62 | ClientTiledThebesLayer::BeginPaint() |
michael@0 | 63 | { |
michael@0 | 64 | if (ClientManager()->IsRepeatTransaction()) { |
michael@0 | 65 | return; |
michael@0 | 66 | } |
michael@0 | 67 | |
michael@0 | 68 | mPaintData.mLowPrecisionPaintCount = 0; |
michael@0 | 69 | mPaintData.mPaintFinished = false; |
michael@0 | 70 | mPaintData.mCompositionBounds.SetEmpty(); |
michael@0 | 71 | mPaintData.mCriticalDisplayPort.SetEmpty(); |
michael@0 | 72 | |
michael@0 | 73 | if (!GetBaseTransform().Is2DIntegerTranslation()) { |
michael@0 | 74 | // Give up if the layer is transformed. The code below assumes that there |
michael@0 | 75 | // is no transform set, and not making that assumption would cause huge |
michael@0 | 76 | // complication to handle a quite rare case. |
michael@0 | 77 | // |
michael@0 | 78 | // FIXME The intention is to bail out of this function when there's a CSS |
michael@0 | 79 | // transform set on the layer, but unfortunately there's no way to |
michael@0 | 80 | // distinguish transforms due to scrolling from transforms due to |
michael@0 | 81 | // CSS transforms. |
michael@0 | 82 | // |
michael@0 | 83 | // Because of this, there may be unintended behaviour when setting |
michael@0 | 84 | // 2d CSS translations on the children of scrollable displayport |
michael@0 | 85 | // layers. |
michael@0 | 86 | return; |
michael@0 | 87 | } |
michael@0 | 88 | |
michael@0 | 89 | #ifdef MOZ_WIDGET_ANDROID |
michael@0 | 90 | // Subframes on Fennec are not async scrollable because they have no displayport. |
michael@0 | 91 | // However, the code in RenderLayer() picks up a displayport from the nearest |
michael@0 | 92 | // scrollable ancestor container layer anyway, which is incorrect for Fennec. This |
michael@0 | 93 | // behaviour results in the subframe getting clipped improperly and perma-blank areas |
michael@0 | 94 | // while scrolling the subframe. To work around this, we detect if this layer is |
michael@0 | 95 | // the primary scrollable layer and disable the tiling behaviour if it is not. |
michael@0 | 96 | bool isPrimaryScrollableThebesLayer = false; |
michael@0 | 97 | if (Layer* scrollable = ClientManager()->GetPrimaryScrollableLayer()) { |
michael@0 | 98 | if (GetParent() == scrollable) { |
michael@0 | 99 | for (Layer* child = scrollable->GetFirstChild(); child; child = child->GetNextSibling()) { |
michael@0 | 100 | if (child->GetType() == Layer::TYPE_THEBES) { |
michael@0 | 101 | if (child == this) { |
michael@0 | 102 | // |this| is the first thebes layer child of the GetPrimaryScrollableLayer() |
michael@0 | 103 | isPrimaryScrollableThebesLayer = true; |
michael@0 | 104 | } |
michael@0 | 105 | break; |
michael@0 | 106 | } |
michael@0 | 107 | } |
michael@0 | 108 | } |
michael@0 | 109 | } |
michael@0 | 110 | if (!isPrimaryScrollableThebesLayer) { |
michael@0 | 111 | return; |
michael@0 | 112 | } |
michael@0 | 113 | #endif |
michael@0 | 114 | |
michael@0 | 115 | // Get the metrics of the nearest scrollable layer and the nearest layer |
michael@0 | 116 | // with a displayport. |
michael@0 | 117 | ContainerLayer* displayPortParent = nullptr; |
michael@0 | 118 | ContainerLayer* scrollParent = nullptr; |
michael@0 | 119 | for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) { |
michael@0 | 120 | const FrameMetrics& metrics = parent->GetFrameMetrics(); |
michael@0 | 121 | if (!scrollParent && metrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID) { |
michael@0 | 122 | scrollParent = parent; |
michael@0 | 123 | } |
michael@0 | 124 | if (!metrics.mDisplayPort.IsEmpty()) { |
michael@0 | 125 | displayPortParent = parent; |
michael@0 | 126 | // Any layer that has a displayport must be scrollable, so we can break |
michael@0 | 127 | // here. |
michael@0 | 128 | break; |
michael@0 | 129 | } |
michael@0 | 130 | } |
michael@0 | 131 | |
michael@0 | 132 | if (!displayPortParent || !scrollParent) { |
michael@0 | 133 | // No displayport or scroll parent, so we can't do progressive rendering. |
michael@0 | 134 | // Just set the composition bounds to empty and return. |
michael@0 | 135 | #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_B2G) |
michael@0 | 136 | // Both Android and b2g are guaranteed to have a displayport set, so this |
michael@0 | 137 | // should never happen. |
michael@0 | 138 | NS_WARNING("Tiled Thebes layer with no scrollable container parent"); |
michael@0 | 139 | #endif |
michael@0 | 140 | return; |
michael@0 | 141 | } |
michael@0 | 142 | |
michael@0 | 143 | // Note, not handling transformed layers lets us assume that LayoutDevice |
michael@0 | 144 | // space of the scroll parent layer is the same as LayoutDevice space of |
michael@0 | 145 | // this layer. |
michael@0 | 146 | const FrameMetrics& scrollMetrics = scrollParent->GetFrameMetrics(); |
michael@0 | 147 | const FrameMetrics& displayportMetrics = displayPortParent->GetFrameMetrics(); |
michael@0 | 148 | |
michael@0 | 149 | // Calculate the transform required to convert ParentLayer space of our |
michael@0 | 150 | // display port parent to LayoutDevice space of this layer. |
michael@0 | 151 | gfx::Matrix4x4 transform = scrollParent->GetTransform(); |
michael@0 | 152 | ContainerLayer* displayPortParentParent = displayPortParent->GetParent() ? |
michael@0 | 153 | displayPortParent->GetParent()->GetParent() : nullptr; |
michael@0 | 154 | for (ContainerLayer* parent = scrollParent->GetParent(); |
michael@0 | 155 | parent != displayPortParentParent; |
michael@0 | 156 | parent = parent->GetParent()) { |
michael@0 | 157 | transform = transform * parent->GetTransform(); |
michael@0 | 158 | } |
michael@0 | 159 | gfx3DMatrix layoutDeviceToScrollParentLayer; |
michael@0 | 160 | gfx::To3DMatrix(transform, layoutDeviceToScrollParentLayer); |
michael@0 | 161 | layoutDeviceToScrollParentLayer.ScalePost(scrollMetrics.mCumulativeResolution.scale, |
michael@0 | 162 | scrollMetrics.mCumulativeResolution.scale, |
michael@0 | 163 | 1.f); |
michael@0 | 164 | |
michael@0 | 165 | mPaintData.mTransformParentLayerToLayoutDevice = layoutDeviceToScrollParentLayer.Inverse(); |
michael@0 | 166 | |
michael@0 | 167 | // Compute the critical display port of the display port layer in |
michael@0 | 168 | // LayoutDevice space of this layer. |
michael@0 | 169 | ParentLayerRect criticalDisplayPort = |
michael@0 | 170 | (displayportMetrics.mCriticalDisplayPort + displayportMetrics.GetScrollOffset()) * |
michael@0 | 171 | displayportMetrics.GetZoomToParent(); |
michael@0 | 172 | mPaintData.mCriticalDisplayPort = LayoutDeviceIntRect::ToUntyped(RoundedOut( |
michael@0 | 173 | ApplyParentLayerToLayoutTransform(mPaintData.mTransformParentLayerToLayoutDevice, |
michael@0 | 174 | criticalDisplayPort))); |
michael@0 | 175 | |
michael@0 | 176 | // Compute the viewport of the display port layer in LayoutDevice space of |
michael@0 | 177 | // this layer. |
michael@0 | 178 | ParentLayerRect viewport = |
michael@0 | 179 | (displayportMetrics.mViewport + displayportMetrics.GetScrollOffset()) * |
michael@0 | 180 | displayportMetrics.GetZoomToParent(); |
michael@0 | 181 | mPaintData.mViewport = ApplyParentLayerToLayoutTransform( |
michael@0 | 182 | mPaintData.mTransformParentLayerToLayoutDevice, viewport); |
michael@0 | 183 | |
michael@0 | 184 | // Store the scroll parent resolution. Because this is Gecko-side, before any |
michael@0 | 185 | // async transforms have occurred, we can use the zoom for this. |
michael@0 | 186 | mPaintData.mResolution = displayportMetrics.GetZoomToParent(); |
michael@0 | 187 | |
michael@0 | 188 | // Store the parent composition bounds in LayoutDevice units. |
michael@0 | 189 | // This is actually in LayoutDevice units of the scrollParent's parent layer, |
michael@0 | 190 | // but because there is no transform, we can assume that these are the same. |
michael@0 | 191 | mPaintData.mCompositionBounds = |
michael@0 | 192 | scrollMetrics.mCompositionBounds / scrollMetrics.GetParentResolution(); |
michael@0 | 193 | |
michael@0 | 194 | // Calculate the scroll offset since the last transaction |
michael@0 | 195 | mPaintData.mScrollOffset = displayportMetrics.GetScrollOffset() * displayportMetrics.GetZoomToParent(); |
michael@0 | 196 | } |
michael@0 | 197 | |
michael@0 | 198 | void |
michael@0 | 199 | ClientTiledThebesLayer::EndPaint(bool aFinish) |
michael@0 | 200 | { |
michael@0 | 201 | if (!aFinish && !mPaintData.mPaintFinished) { |
michael@0 | 202 | return; |
michael@0 | 203 | } |
michael@0 | 204 | |
michael@0 | 205 | mPaintData.mLastScrollOffset = mPaintData.mScrollOffset; |
michael@0 | 206 | mPaintData.mPaintFinished = true; |
michael@0 | 207 | mPaintData.mFirstPaint = false; |
michael@0 | 208 | } |
michael@0 | 209 | |
michael@0 | 210 | void |
michael@0 | 211 | ClientTiledThebesLayer::RenderLayer() |
michael@0 | 212 | { |
michael@0 | 213 | LayerManager::DrawThebesLayerCallback callback = |
michael@0 | 214 | ClientManager()->GetThebesLayerCallback(); |
michael@0 | 215 | void *data = ClientManager()->GetThebesLayerCallbackData(); |
michael@0 | 216 | if (!callback) { |
michael@0 | 217 | ClientManager()->SetTransactionIncomplete(); |
michael@0 | 218 | return; |
michael@0 | 219 | } |
michael@0 | 220 | |
michael@0 | 221 | if (!mContentClient) { |
michael@0 | 222 | mContentClient = new TiledContentClient(this, ClientManager()); |
michael@0 | 223 | |
michael@0 | 224 | mContentClient->Connect(); |
michael@0 | 225 | ClientManager()->AsShadowForwarder()->Attach(mContentClient, this); |
michael@0 | 226 | MOZ_ASSERT(mContentClient->GetForwarder()); |
michael@0 | 227 | } |
michael@0 | 228 | |
michael@0 | 229 | if (mContentClient->mTiledBuffer.HasFormatChanged()) { |
michael@0 | 230 | mValidRegion = nsIntRegion(); |
michael@0 | 231 | } |
michael@0 | 232 | |
michael@0 | 233 | nsIntRegion invalidRegion = mVisibleRegion; |
michael@0 | 234 | invalidRegion.Sub(invalidRegion, mValidRegion); |
michael@0 | 235 | if (invalidRegion.IsEmpty()) { |
michael@0 | 236 | EndPaint(true); |
michael@0 | 237 | return; |
michael@0 | 238 | } |
michael@0 | 239 | |
michael@0 | 240 | // Only paint the mask layer on the first transaction. |
michael@0 | 241 | if (GetMaskLayer() && !ClientManager()->IsRepeatTransaction()) { |
michael@0 | 242 | ToClientLayer(GetMaskLayer())->RenderLayer(); |
michael@0 | 243 | } |
michael@0 | 244 | |
michael@0 | 245 | bool isFixed = GetIsFixedPosition() || GetParent()->GetIsFixedPosition(); |
michael@0 | 246 | |
michael@0 | 247 | // Fast path for no progressive updates, no low-precision updates and no |
michael@0 | 248 | // critical display-port set, or no display-port set, or this is a fixed |
michael@0 | 249 | // position layer/contained in a fixed position layer |
michael@0 | 250 | const FrameMetrics& parentMetrics = GetParent()->GetFrameMetrics(); |
michael@0 | 251 | if ((!gfxPrefs::UseProgressiveTilePainting() && |
michael@0 | 252 | !gfxPrefs::UseLowPrecisionBuffer() && |
michael@0 | 253 | parentMetrics.mCriticalDisplayPort.IsEmpty()) || |
michael@0 | 254 | parentMetrics.mDisplayPort.IsEmpty() || |
michael@0 | 255 | isFixed) { |
michael@0 | 256 | mValidRegion = mVisibleRegion; |
michael@0 | 257 | |
michael@0 | 258 | NS_ASSERTION(!ClientManager()->IsRepeatTransaction(), "Didn't paint our mask layer"); |
michael@0 | 259 | |
michael@0 | 260 | mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, |
michael@0 | 261 | callback, data); |
michael@0 | 262 | |
michael@0 | 263 | ClientManager()->Hold(this); |
michael@0 | 264 | mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER); |
michael@0 | 265 | |
michael@0 | 266 | return; |
michael@0 | 267 | } |
michael@0 | 268 | |
michael@0 | 269 | // Calculate everything we need to perform the paint. |
michael@0 | 270 | BeginPaint(); |
michael@0 | 271 | if (mPaintData.mPaintFinished) { |
michael@0 | 272 | return; |
michael@0 | 273 | } |
michael@0 | 274 | |
michael@0 | 275 | // Make sure that tiles that fall outside of the visible region are |
michael@0 | 276 | // discarded on the first update. |
michael@0 | 277 | if (!ClientManager()->IsRepeatTransaction()) { |
michael@0 | 278 | mValidRegion.And(mValidRegion, mVisibleRegion); |
michael@0 | 279 | if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { |
michael@0 | 280 | // Make sure that tiles that fall outside of the critical displayport are |
michael@0 | 281 | // discarded on the first update. |
michael@0 | 282 | mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort); |
michael@0 | 283 | } |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | nsIntRegion lowPrecisionInvalidRegion; |
michael@0 | 287 | if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { |
michael@0 | 288 | if (gfxPrefs::UseLowPrecisionBuffer()) { |
michael@0 | 289 | // Calculate the invalid region for the low precision buffer |
michael@0 | 290 | lowPrecisionInvalidRegion.Sub(mVisibleRegion, mLowPrecisionValidRegion); |
michael@0 | 291 | |
michael@0 | 292 | // Remove the valid region from the low precision valid region (we don't |
michael@0 | 293 | // validate this part of the low precision buffer). |
michael@0 | 294 | lowPrecisionInvalidRegion.Sub(lowPrecisionInvalidRegion, mValidRegion); |
michael@0 | 295 | } |
michael@0 | 296 | |
michael@0 | 297 | // Clip the invalid region to the critical display-port |
michael@0 | 298 | invalidRegion.And(invalidRegion, mPaintData.mCriticalDisplayPort); |
michael@0 | 299 | if (invalidRegion.IsEmpty() && lowPrecisionInvalidRegion.IsEmpty()) { |
michael@0 | 300 | EndPaint(true); |
michael@0 | 301 | return; |
michael@0 | 302 | } |
michael@0 | 303 | } |
michael@0 | 304 | |
michael@0 | 305 | if (!invalidRegion.IsEmpty() && mPaintData.mLowPrecisionPaintCount == 0) { |
michael@0 | 306 | bool updatedBuffer = false; |
michael@0 | 307 | // Only draw progressively when the resolution is unchanged. |
michael@0 | 308 | if (gfxPrefs::UseProgressiveTilePainting() && |
michael@0 | 309 | !ClientManager()->HasShadowTarget() && |
michael@0 | 310 | mContentClient->mTiledBuffer.GetFrameResolution() == mPaintData.mResolution) { |
michael@0 | 311 | // Store the old valid region, then clear it before painting. |
michael@0 | 312 | // We clip the old valid region to the visible region, as it only gets |
michael@0 | 313 | // used to decide stale content (currently valid and previously visible) |
michael@0 | 314 | nsIntRegion oldValidRegion = mContentClient->mTiledBuffer.GetValidRegion(); |
michael@0 | 315 | oldValidRegion.And(oldValidRegion, mVisibleRegion); |
michael@0 | 316 | if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { |
michael@0 | 317 | oldValidRegion.And(oldValidRegion, mPaintData.mCriticalDisplayPort); |
michael@0 | 318 | } |
michael@0 | 319 | |
michael@0 | 320 | updatedBuffer = |
michael@0 | 321 | mContentClient->mTiledBuffer.ProgressiveUpdate(mValidRegion, invalidRegion, |
michael@0 | 322 | oldValidRegion, &mPaintData, |
michael@0 | 323 | callback, data); |
michael@0 | 324 | } else { |
michael@0 | 325 | updatedBuffer = true; |
michael@0 | 326 | mValidRegion = mVisibleRegion; |
michael@0 | 327 | if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { |
michael@0 | 328 | mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort); |
michael@0 | 329 | } |
michael@0 | 330 | mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution); |
michael@0 | 331 | mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, |
michael@0 | 332 | callback, data); |
michael@0 | 333 | } |
michael@0 | 334 | |
michael@0 | 335 | if (updatedBuffer) { |
michael@0 | 336 | ClientManager()->Hold(this); |
michael@0 | 337 | mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER); |
michael@0 | 338 | |
michael@0 | 339 | // If there are low precision updates, mark the paint as unfinished and |
michael@0 | 340 | // request a repeat transaction. |
michael@0 | 341 | if (!lowPrecisionInvalidRegion.IsEmpty() && mPaintData.mPaintFinished) { |
michael@0 | 342 | ClientManager()->SetRepeatTransaction(); |
michael@0 | 343 | mPaintData.mLowPrecisionPaintCount = 1; |
michael@0 | 344 | mPaintData.mPaintFinished = false; |
michael@0 | 345 | } |
michael@0 | 346 | |
michael@0 | 347 | // Return so that low precision updates aren't performed in the same |
michael@0 | 348 | // transaction as high-precision updates. |
michael@0 | 349 | EndPaint(false); |
michael@0 | 350 | return; |
michael@0 | 351 | } |
michael@0 | 352 | } |
michael@0 | 353 | |
michael@0 | 354 | // Render the low precision buffer, if there's area to invalidate and the |
michael@0 | 355 | // visible region is larger than the critical display port. |
michael@0 | 356 | bool updatedLowPrecision = false; |
michael@0 | 357 | if (!lowPrecisionInvalidRegion.IsEmpty() && |
michael@0 | 358 | !nsIntRegion(mPaintData.mCriticalDisplayPort).Contains(mVisibleRegion)) { |
michael@0 | 359 | nsIntRegion oldValidRegion = |
michael@0 | 360 | mContentClient->mLowPrecisionTiledBuffer.GetValidRegion(); |
michael@0 | 361 | oldValidRegion.And(oldValidRegion, mVisibleRegion); |
michael@0 | 362 | |
michael@0 | 363 | // If the frame resolution or format have changed, invalidate the buffer |
michael@0 | 364 | if (mContentClient->mLowPrecisionTiledBuffer.GetFrameResolution() != mPaintData.mResolution || |
michael@0 | 365 | mContentClient->mLowPrecisionTiledBuffer.HasFormatChanged()) { |
michael@0 | 366 | if (!mLowPrecisionValidRegion.IsEmpty()) { |
michael@0 | 367 | updatedLowPrecision = true; |
michael@0 | 368 | } |
michael@0 | 369 | oldValidRegion.SetEmpty(); |
michael@0 | 370 | mLowPrecisionValidRegion.SetEmpty(); |
michael@0 | 371 | mContentClient->mLowPrecisionTiledBuffer.SetFrameResolution(mPaintData.mResolution); |
michael@0 | 372 | lowPrecisionInvalidRegion = mVisibleRegion; |
michael@0 | 373 | } |
michael@0 | 374 | |
michael@0 | 375 | // Invalidate previously valid content that is no longer visible |
michael@0 | 376 | if (mPaintData.mLowPrecisionPaintCount == 1) { |
michael@0 | 377 | mLowPrecisionValidRegion.And(mLowPrecisionValidRegion, mVisibleRegion); |
michael@0 | 378 | } |
michael@0 | 379 | mPaintData.mLowPrecisionPaintCount++; |
michael@0 | 380 | |
michael@0 | 381 | // Remove the valid high-precision region from the invalid low-precision |
michael@0 | 382 | // region. We don't want to spend time drawing things twice. |
michael@0 | 383 | lowPrecisionInvalidRegion.Sub(lowPrecisionInvalidRegion, mValidRegion); |
michael@0 | 384 | |
michael@0 | 385 | if (!lowPrecisionInvalidRegion.IsEmpty()) { |
michael@0 | 386 | updatedLowPrecision = mContentClient->mLowPrecisionTiledBuffer |
michael@0 | 387 | .ProgressiveUpdate(mLowPrecisionValidRegion, |
michael@0 | 388 | lowPrecisionInvalidRegion, |
michael@0 | 389 | oldValidRegion, &mPaintData, |
michael@0 | 390 | callback, data); |
michael@0 | 391 | } |
michael@0 | 392 | } else if (!mLowPrecisionValidRegion.IsEmpty()) { |
michael@0 | 393 | // Clear the low precision tiled buffer |
michael@0 | 394 | updatedLowPrecision = true; |
michael@0 | 395 | mLowPrecisionValidRegion.SetEmpty(); |
michael@0 | 396 | mContentClient->mLowPrecisionTiledBuffer.PaintThebes(mLowPrecisionValidRegion, |
michael@0 | 397 | mLowPrecisionValidRegion, |
michael@0 | 398 | callback, data); |
michael@0 | 399 | } |
michael@0 | 400 | |
michael@0 | 401 | // We send a Painted callback if we clear the valid region of the low |
michael@0 | 402 | // precision buffer, so that the shadow buffer's valid region can be updated |
michael@0 | 403 | // and the associated resources can be freed. |
michael@0 | 404 | if (updatedLowPrecision) { |
michael@0 | 405 | ClientManager()->Hold(this); |
michael@0 | 406 | mContentClient->UseTiledLayerBuffer(TiledContentClient::LOW_PRECISION_TILED_BUFFER); |
michael@0 | 407 | } |
michael@0 | 408 | |
michael@0 | 409 | EndPaint(false); |
michael@0 | 410 | } |
michael@0 | 411 | |
michael@0 | 412 | } // mozilla |
michael@0 | 413 | } // layers |