gfx/layers/client/ClientTiledThebesLayer.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial