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