1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "DisplayPortUtils.h"
9 #include "FrameMetrics.h"
11 #include "mozilla/dom/BrowserChild.h"
12 #include "mozilla/dom/Document.h"
13 #include "mozilla/gfx/gfxVars.h"
14 #include "mozilla/gfx/Point.h"
15 #include "mozilla/layers/APZCCallbackHelper.h"
16 #include "mozilla/layers/APZPublicUtils.h"
17 #include "mozilla/layers/CompositorBridgeChild.h"
18 #include "mozilla/layers/PAPZ.h"
19 #include "mozilla/layers/RepaintRequest.h"
20 #include "mozilla/PresShell.h"
21 #include "mozilla/StaticPrefs_layers.h"
22 #include "nsDeckFrame.h"
23 #include "nsIScrollableFrame.h"
24 #include "nsLayoutUtils.h"
25 #include "nsPlaceholderFrame.h"
26 #include "nsSubDocumentFrame.h"
27 #include "RetainedDisplayListBuilder.h"
36 using layers::APZCCallbackHelper
;
37 using layers::FrameMetrics
;
38 using layers::LayerManager
;
39 using layers::RepaintRequest
;
40 using layers::ScrollableLayerGuid
;
42 typedef ScrollableLayerGuid::ViewID ViewID
;
44 static LazyLogModule
sDisplayportLog("apz.displayport");
47 DisplayPortMargins
DisplayPortMargins::FromAPZ(
48 const ScreenMargin
& aMargins
, const CSSPoint
& aVisualOffset
,
49 const CSSPoint
& aLayoutOffset
, const CSSToScreenScale2D
& aScale
) {
50 return DisplayPortMargins
{aMargins
, aVisualOffset
, aLayoutOffset
, aScale
};
53 CSSToScreenScale2D
ComputeDisplayportScale(nsIScrollableFrame
* aScrollFrame
) {
54 // The calculation here is equivalent to
55 // CalculateBasicFrameMetrics(aScrollFrame).DisplayportPixelsPerCSSPixel(),
56 // but we don't calculate the entire frame metrics.
58 return CSSToScreenScale2D(1.0, 1.0);
60 nsIFrame
* frame
= do_QueryFrame(aScrollFrame
);
62 nsPresContext
* presContext
= frame
->PresContext();
63 PresShell
* presShell
= presContext
->PresShell();
64 return presContext
->CSSToDevPixelScale() *
65 LayoutDeviceToLayerScale2D(
66 presShell
->GetCumulativeResolution() *
67 nsLayoutUtils::GetTransformToAncestorScale(frame
)) *
68 LayerToScreenScale2D(1.0, 1.0);
72 DisplayPortMargins
DisplayPortMargins::ForScrollFrame(
73 nsIScrollableFrame
* aScrollFrame
, const ScreenMargin
& aMargins
,
74 const Maybe
<CSSToScreenScale2D
>& aScale
) {
75 CSSPoint visualOffset
;
76 CSSPoint layoutOffset
;
78 nsIFrame
* scrollFrame
= do_QueryFrame(aScrollFrame
);
79 PresShell
* presShell
= scrollFrame
->PresShell();
80 layoutOffset
= CSSPoint::FromAppUnits(aScrollFrame
->GetScrollPosition());
81 if (aScrollFrame
->IsRootScrollFrameOfDocument() &&
82 presShell
->IsVisualViewportOffsetSet()) {
84 CSSPoint::FromAppUnits(presShell
->GetVisualViewportOffset());
87 visualOffset
= layoutOffset
;
90 return DisplayPortMargins
{aMargins
, visualOffset
, layoutOffset
,
91 aScale
.valueOrFrom([&] {
92 return ComputeDisplayportScale(aScrollFrame
);
97 DisplayPortMargins
DisplayPortMargins::ForContent(
98 nsIContent
* aContent
, const ScreenMargin
& aMargins
) {
99 return ForScrollFrame(
100 aContent
? nsLayoutUtils::FindScrollableFrameFor(aContent
) : nullptr,
101 aMargins
, Nothing());
104 ScreenMargin
DisplayPortMargins::GetRelativeToLayoutViewport(
105 ContentGeometryType aGeometryType
,
106 nsIScrollableFrame
* aScrollableFrame
) const {
107 // APZ wants |mMargins| applied relative to the visual viewport.
108 // The main-thread painting code applies margins relative to
109 // the layout viewport. To get the main thread to paint the
110 // area APZ wants, apply a translation between the two. The
111 // magnitude of the translation depends on whether we are
112 // applying the displayport to scrolled or fixed content.
113 CSSPoint scrollDeltaCss
=
114 ComputeAsyncTranslation(aGeometryType
, aScrollableFrame
);
115 ScreenPoint scrollDelta
= scrollDeltaCss
* mScale
;
116 ScreenMargin margins
= mMargins
;
117 margins
.left
-= scrollDelta
.x
;
118 margins
.right
+= scrollDelta
.x
;
119 margins
.top
-= scrollDelta
.y
;
120 margins
.bottom
+= scrollDelta
.y
;
124 std::ostream
& operator<<(std::ostream
& aOs
,
125 const DisplayPortMargins
& aMargins
) {
126 if (aMargins
.mVisualOffset
== CSSPoint() &&
127 aMargins
.mLayoutOffset
== CSSPoint()) {
128 aOs
<< aMargins
.mMargins
;
130 aOs
<< "{" << aMargins
.mMargins
<< "," << aMargins
.mVisualOffset
<< ","
131 << aMargins
.mLayoutOffset
<< "}";
136 CSSPoint
DisplayPortMargins::ComputeAsyncTranslation(
137 ContentGeometryType aGeometryType
,
138 nsIScrollableFrame
* aScrollableFrame
) const {
139 // If we are applying the displayport to scrolled content, the
140 // translation is the entire difference between the visual and
142 if (aGeometryType
== ContentGeometryType::Scrolled
) {
143 return mVisualOffset
- mLayoutOffset
;
146 // If we are applying the displayport to fixed content, only
147 // part of the difference between the visual and layout offsets
148 // should be applied. This is because fixed content remains fixed
149 // to the layout viewport, and some of the async delta between
150 // the visual and layout offsets can drag the layout viewport
151 // with it. We want only the remaining delta, i.e. the offset of
152 // the visual viewport relative to the (async-scrolled) layout
154 if (!aScrollableFrame
) {
155 // Displayport on a non-scrolling frame for some reason.
156 // There will be no divergence between the two viewports.
159 // Fixed content is always fixed to an RSF.
160 MOZ_ASSERT(aScrollableFrame
->IsRootScrollFrameOfDocument());
161 nsIFrame
* scrollFrame
= do_QueryFrame(aScrollableFrame
);
162 if (!scrollFrame
->PresShell()->IsVisualViewportSizeSet()) {
163 // Zooming is disabled, so the layout viewport tracks the
164 // visual viewport completely.
167 // Use KeepLayoutViewportEnclosingViewportVisual() to compute
168 // an async layout viewport the way APZ would.
169 const CSSRect visualViewport
{
171 // TODO: There are probably some edge cases here around async zooming
172 // that are not currently being handled properly. For proper handling,
173 // we'd likely need to save APZ's async zoom when populating
174 // mVisualOffset, and using it to adjust the visual viewport size here.
175 // Note that any incorrectness caused by this will only occur transiently
176 // during async zooming.
177 CSSSize::FromAppUnits(scrollFrame
->PresShell()->GetVisualViewportSize())};
178 const CSSRect scrollableRect
= CSSRect::FromAppUnits(
179 nsLayoutUtils::CalculateExpandedScrollableRect(scrollFrame
));
180 CSSRect asyncLayoutViewport
{
182 CSSSize::FromAppUnits(aScrollableFrame
->GetScrollPortRect().Size())};
183 FrameMetrics::KeepLayoutViewportEnclosingVisualViewport(
184 visualViewport
, scrollableRect
, /* out */ asyncLayoutViewport
);
185 return mVisualOffset
- asyncLayoutViewport
.TopLeft();
188 // Return the maximum displayport size, based on the LayerManager's maximum
189 // supported texture size. The result is in app units.
190 static nscoord
GetMaxDisplayPortSize(nsIContent
* aContent
,
191 nsPresContext
* aFallbackPrescontext
) {
192 MOZ_ASSERT(!StaticPrefs::layers_enable_tiles_AtStartup(),
193 "Do not clamp displayports if tiling is enabled");
195 // Pick a safe maximum displayport size for sanity purposes. This is the
196 // lowest maximum texture size on tileless-platforms (Windows, D3D10).
197 // If the gfx.max-texture-size pref is set, further restrict the displayport
198 // size to fit within that, because the compositor won't upload stuff larger
200 nscoord safeMaximum
= aFallbackPrescontext
201 ? aFallbackPrescontext
->DevPixelsToAppUnits(
202 std::min(8192, gfxPlatform::MaxTextureSize()))
205 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
209 frame
= nsLayoutUtils::GetDisplayRootFrame(frame
);
211 nsIWidget
* widget
= frame
->GetNearestWidget();
215 WindowRenderer
* renderer
= widget
->GetWindowRenderer();
216 if (!renderer
|| !renderer
->AsLayerManager()) {
219 nsPresContext
* presContext
= frame
->PresContext();
221 int32_t maxSizeInDevPixels
= renderer
->AsLayerManager()->GetMaxTextureSize();
222 if (maxSizeInDevPixels
< 0 || maxSizeInDevPixels
== INT_MAX
) {
226 std::min(maxSizeInDevPixels
, gfxPlatform::MaxTextureSize());
227 return presContext
->DevPixelsToAppUnits(maxSizeInDevPixels
);
230 static nsRect
ApplyRectMultiplier(nsRect aRect
, float aMultiplier
) {
231 if (aMultiplier
== 1.0f
) {
234 float newWidth
= aRect
.width
* aMultiplier
;
235 float newHeight
= aRect
.height
* aMultiplier
;
236 float newX
= aRect
.x
- ((newWidth
- aRect
.width
) / 2.0f
);
237 float newY
= aRect
.y
- ((newHeight
- aRect
.height
) / 2.0f
);
238 // Rounding doesn't matter too much here, do a round-in
239 return nsRect(ceil(newX
), ceil(newY
), floor(newWidth
), floor(newHeight
));
242 static nsRect
GetDisplayPortFromRectData(nsIContent
* aContent
,
243 DisplayPortPropertyData
* aRectData
,
245 // In the case where the displayport is set as a rect, we assume it is
246 // already aligned and clamped as necessary. The burden to do that is
247 // on the setter of the displayport. In practice very few places set the
248 // displayport directly as a rect (mostly tests). We still do need to
249 // expand it by the multiplier though.
250 return ApplyRectMultiplier(aRectData
->mRect
, aMultiplier
);
253 static nsRect
GetDisplayPortFromMarginsData(
254 nsIContent
* aContent
, DisplayPortMarginsPropertyData
* aMarginsData
,
255 float aMultiplier
, const DisplayPortOptions
& aOptions
) {
256 // In the case where the displayport is set via margins, we apply the margins
257 // to a base rect. Then we align the expanded rect based on the alignment
258 // requested, further expand the rect by the multiplier, and finally, clamp it
259 // to the size of the scrollable rect.
262 if (nsRect
* baseData
= static_cast<nsRect
*>(
263 aContent
->GetProperty(nsGkAtoms::DisplayPortBase
))) {
266 // In theory we shouldn't get here, but we do sometimes (see bug 1212136).
267 // Fall through for graceful handling.
270 nsIFrame
* frame
= nsLayoutUtils::GetScrollFrameFromContent(aContent
);
272 // Turns out we can't really compute it. Oops. We still should return
273 // something sane. Note that since we can't clamp the rect without a
274 // frame, we don't apply the multiplier either as it can cause the result
275 // to leak outside the scrollable area.
277 "Attempting to get a displayport from a content with no primary "
283 if (aContent
->OwnerDoc()->GetRootElement() == aContent
) {
287 nsIScrollableFrame
* scrollableFrame
= frame
->GetScrollTargetFrame();
289 if (scrollableFrame
) {
290 scrollPos
= scrollableFrame
->GetScrollPosition();
293 nsPresContext
* presContext
= frame
->PresContext();
294 int32_t auPerDevPixel
= presContext
->AppUnitsPerDevPixel();
296 LayoutDeviceToScreenScale2D
res(
297 presContext
->PresShell()->GetCumulativeResolution() *
298 nsLayoutUtils::GetTransformToAncestorScale(frame
));
300 // Calculate the expanded scrollable rect, which we'll be clamping the
302 nsRect expandedScrollableRect
=
303 nsLayoutUtils::CalculateExpandedScrollableRect(frame
);
305 // GetTransformToAncestorScale() can return 0. In this case, just return the
306 // base rect (clamped to the expanded scrollable rect), as other calculations
307 // would run into divisions by zero.
308 if (res
== LayoutDeviceToScreenScale2D(0, 0)) {
309 // Make sure the displayport remains within the scrollable rect.
310 return base
.MoveInsideAndClamp(expandedScrollableRect
- scrollPos
);
313 // First convert the base rect to screen pixels
314 LayoutDeviceToScreenScale2D parentRes
= res
;
316 // the base rect for root scroll frames is specified in the parent document
317 // coordinate space, so it doesn't include the local resolution.
318 float localRes
= presContext
->PresShell()->GetResolution();
319 parentRes
.xScale
/= localRes
;
320 parentRes
.yScale
/= localRes
;
322 ScreenRect screenRect
=
323 LayoutDeviceRect::FromAppUnits(base
, auPerDevPixel
) * parentRes
;
325 // Note on the correctness of applying the alignment in Screen space:
326 // The correct space to apply the alignment in would be Layer space, but
327 // we don't necessarily know the scale to convert to Layer space at this
328 // point because Layout may not yet have chosen the resolution at which to
329 // render (it chooses that in FrameLayerBuilder, but this can be called
330 // during display list building). Therefore, we perform the alignment in
331 // Screen space, which basically assumes that Layout chose to render at
332 // screen resolution; since this is what Layout does most of the time,
333 // this is a good approximation. A proper solution would involve moving
334 // the choosing of the resolution to display-list building time.
335 ScreenSize alignment
;
337 PresShell
* presShell
= presContext
->PresShell();
338 MOZ_ASSERT(presShell
);
340 bool useWebRender
= gfxVars::UseWebRender();
342 ScreenMargin margins
= aMarginsData
->mMargins
.GetRelativeToLayoutViewport(
343 aOptions
.mGeometryType
, scrollableFrame
);
345 if (presShell
->IsDisplayportSuppressed() ||
346 aContent
->GetProperty(nsGkAtoms::MinimalDisplayPort
)) {
347 alignment
= ScreenSize(1, 1);
348 } else if (useWebRender
) {
349 // Moving the displayport is relatively expensive with WR so we use a larger
350 // alignment that causes the displayport to move less frequently. The
351 // alignment scales up with the size of the base rect so larger scrollframes
352 // use a larger alignment, but we clamp the alignment to a power of two
353 // between 128 and 1024 (inclusive).
354 // This naturally also increases the size of the displayport compared to
355 // always using a 128 alignment, so the displayport multipliers are also
356 // correspondingly smaller when WR is enabled to prevent the displayport
357 // from becoming too big.
359 layers::apz::GetDisplayportAlignmentMultiplier(screenRect
.Size());
360 alignment
= ScreenSize(128 * multiplier
.width
, 128 * multiplier
.height
);
361 } else if (StaticPrefs::layers_enable_tiles_AtStartup()) {
362 // Don't align to tiles if they are too large, because we could expand
363 // the displayport by a lot which can take more paint time. It's a tradeoff
364 // though because if we don't align to tiles we have more waste on upload.
365 IntSize tileSize
= gfxVars::TileSize();
366 alignment
= ScreenSize(std::min(256, tileSize
.width
),
367 std::min(256, tileSize
.height
));
369 // If we're not drawing with tiles then we need to be careful about not
370 // hitting the max texture size and we only need 1 draw call per layer
371 // so we can align to a smaller multiple.
372 alignment
= ScreenSize(128, 128);
375 // Avoid division by zero.
376 if (alignment
.width
== 0) {
377 alignment
.width
= 128;
379 if (alignment
.height
== 0) {
380 alignment
.height
= 128;
383 if (StaticPrefs::layers_enable_tiles_AtStartup() || useWebRender
) {
384 // Expand the rect by the margins
385 screenRect
.Inflate(margins
);
387 // Calculate the displayport to make sure we fit within the max texture size
389 nscoord maxSizeAppUnits
= GetMaxDisplayPortSize(aContent
, presContext
);
390 MOZ_ASSERT(maxSizeAppUnits
< nscoord_MAX
);
392 // The alignment code can round up to 3 tiles, we want to make sure
393 // that the displayport can grow by up to 3 tiles without going
394 // over the max texture size.
395 const int MAX_ALIGN_ROUNDING
= 3;
397 // Find the maximum size in screen pixels.
398 int32_t maxSizeDevPx
= presContext
->AppUnitsToDevPixels(maxSizeAppUnits
);
399 int32_t maxWidthScreenPx
= floor(double(maxSizeDevPx
) * res
.xScale
) -
400 MAX_ALIGN_ROUNDING
* alignment
.width
;
401 int32_t maxHeightScreenPx
= floor(double(maxSizeDevPx
) * res
.yScale
) -
402 MAX_ALIGN_ROUNDING
* alignment
.height
;
404 // For each axis, inflate the margins up to the maximum size.
405 if (screenRect
.height
< maxHeightScreenPx
) {
406 int32_t budget
= maxHeightScreenPx
- screenRect
.height
;
407 // Scale the margins down to fit into the budget if necessary, maintaining
408 // their relative ratio.
410 if (float(budget
) < margins
.TopBottom()) {
411 scale
= float(budget
) / margins
.TopBottom();
413 float top
= margins
.top
* scale
;
414 float bottom
= margins
.bottom
* scale
;
416 screenRect
.height
+= top
+ bottom
;
418 if (screenRect
.width
< maxWidthScreenPx
) {
419 int32_t budget
= maxWidthScreenPx
- screenRect
.width
;
421 if (float(budget
) < margins
.LeftRight()) {
422 scale
= float(budget
) / margins
.LeftRight();
424 float left
= margins
.left
* scale
;
425 float right
= margins
.right
* scale
;
426 screenRect
.x
-= left
;
427 screenRect
.width
+= left
+ right
;
431 ScreenPoint scrollPosScreen
=
432 LayoutDevicePoint::FromAppUnits(scrollPos
, auPerDevPixel
) * res
;
434 // Align the display port.
435 screenRect
+= scrollPosScreen
;
436 float x
= alignment
.width
* floor(screenRect
.x
/ alignment
.width
);
437 float y
= alignment
.height
* floor(screenRect
.y
/ alignment
.height
);
438 float w
= alignment
.width
* ceil(screenRect
.width
/ alignment
.width
+ 1);
439 float h
= alignment
.height
* ceil(screenRect
.height
/ alignment
.height
+ 1);
440 screenRect
= ScreenRect(x
, y
, w
, h
);
441 screenRect
-= scrollPosScreen
;
443 // Convert the aligned rect back into app units.
444 nsRect result
= LayoutDeviceRect::ToAppUnits(screenRect
/ res
, auPerDevPixel
);
446 // If we have non-zero margins, expand the displayport for the low-res buffer
447 // if that's what we're drawing. If we have zero margins, we want the
448 // displayport to reflect the scrollport.
449 if (margins
!= ScreenMargin()) {
450 result
= ApplyRectMultiplier(result
, aMultiplier
);
453 // Make sure the displayport remains within the scrollable rect.
454 result
= result
.MoveInsideAndClamp(expandedScrollableRect
- scrollPos
);
459 static bool GetDisplayPortData(
460 nsIContent
* aContent
, DisplayPortPropertyData
** aOutRectData
,
461 DisplayPortMarginsPropertyData
** aOutMarginsData
) {
462 MOZ_ASSERT(aOutRectData
&& aOutMarginsData
);
464 *aOutRectData
= static_cast<DisplayPortPropertyData
*>(
465 aContent
->GetProperty(nsGkAtoms::DisplayPort
));
466 *aOutMarginsData
= static_cast<DisplayPortMarginsPropertyData
*>(
467 aContent
->GetProperty(nsGkAtoms::DisplayPortMargins
));
469 if (!*aOutRectData
&& !*aOutMarginsData
) {
470 // This content element has no displayport data at all
474 if (*aOutRectData
&& *aOutMarginsData
) {
475 // choose margins if equal priority
476 if ((*aOutRectData
)->mPriority
> (*aOutMarginsData
)->mPriority
) {
477 *aOutMarginsData
= nullptr;
479 *aOutRectData
= nullptr;
483 NS_ASSERTION((*aOutRectData
== nullptr) != (*aOutMarginsData
== nullptr),
484 "Only one of aOutRectData or aOutMarginsData should be set!");
489 static bool GetWasDisplayPortPainted(nsIContent
* aContent
) {
490 DisplayPortPropertyData
* rectData
= nullptr;
491 DisplayPortMarginsPropertyData
* marginsData
= nullptr;
493 if (!GetDisplayPortData(aContent
, &rectData
, &marginsData
)) {
497 return rectData
? rectData
->mPainted
: marginsData
->mPainted
;
500 bool DisplayPortUtils::IsMissingDisplayPortBaseRect(nsIContent
* aContent
) {
501 DisplayPortPropertyData
* rectData
= nullptr;
502 DisplayPortMarginsPropertyData
* marginsData
= nullptr;
504 if (GetDisplayPortData(aContent
, &rectData
, &marginsData
) && marginsData
) {
505 return !aContent
->GetProperty(nsGkAtoms::DisplayPortBase
);
511 static void TranslateFromScrollPortToScrollFrame(nsIContent
* aContent
,
514 if (nsIScrollableFrame
* scrollableFrame
=
515 nsLayoutUtils::FindScrollableFrameFor(aContent
)) {
516 *aRect
+= scrollableFrame
->GetScrollPortRect().TopLeft();
520 static bool GetDisplayPortImpl(nsIContent
* aContent
, nsRect
* aResult
,
522 const DisplayPortOptions
& aOptions
) {
523 DisplayPortPropertyData
* rectData
= nullptr;
524 DisplayPortMarginsPropertyData
* marginsData
= nullptr;
526 if (!GetDisplayPortData(aContent
, &rectData
, &marginsData
)) {
530 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
531 if (frame
&& !frame
->PresShell()->AsyncPanZoomEnabled()) {
536 // We have displayport data, but the caller doesn't want the actual
537 // rect, so we don't need to actually compute it.
541 bool isDisplayportSuppressed
= false;
544 nsPresContext
* presContext
= frame
->PresContext();
545 MOZ_ASSERT(presContext
);
546 PresShell
* presShell
= presContext
->PresShell();
547 MOZ_ASSERT(presShell
);
548 isDisplayportSuppressed
= presShell
->IsDisplayportSuppressed();
553 result
= GetDisplayPortFromRectData(aContent
, rectData
, aMultiplier
);
554 } else if (isDisplayportSuppressed
||
555 nsLayoutUtils::ShouldDisableApzForElement(aContent
) ||
556 aContent
->GetProperty(nsGkAtoms::MinimalDisplayPort
)) {
557 // Make a copy of the margins data but set the margins to empty.
558 // Do not create a new DisplayPortMargins object with
559 // DisplayPortMargins::Empty(), because that will record the visual
560 // and layout scroll offsets in place right now on the DisplayPortMargins,
561 // and those are only meant to be recorded when the margins are stored.
562 DisplayPortMarginsPropertyData noMargins
= *marginsData
;
563 noMargins
.mMargins
.mMargins
= ScreenMargin();
564 result
= GetDisplayPortFromMarginsData(aContent
, &noMargins
, aMultiplier
,
567 result
= GetDisplayPortFromMarginsData(aContent
, marginsData
, aMultiplier
,
571 if (!StaticPrefs::layers_enable_tiles_AtStartup()) {
572 // Perform the desired error handling if the displayport dimensions
573 // exceeds the maximum allowed size
574 nscoord maxSize
= GetMaxDisplayPortSize(aContent
, nullptr);
575 if (result
.width
> maxSize
|| result
.height
> maxSize
) {
576 switch (aOptions
.mMaxSizeExceededBehaviour
) {
577 case MaxSizeExceededBehaviour::Assert
:
578 NS_ASSERTION(false, "Displayport must be a valid texture size");
580 case MaxSizeExceededBehaviour::Drop
:
586 if (aOptions
.mRelativeTo
== DisplayportRelativeTo::ScrollFrame
) {
587 TranslateFromScrollPortToScrollFrame(aContent
, &result
);
594 bool DisplayPortUtils::GetDisplayPort(nsIContent
* aContent
, nsRect
* aResult
,
595 const DisplayPortOptions
& aOptions
) {
596 float multiplier
= StaticPrefs::layers_low_precision_buffer()
597 ? 1.0f
/ StaticPrefs::layers_low_precision_resolution()
599 return GetDisplayPortImpl(aContent
, aResult
, multiplier
, aOptions
);
602 bool DisplayPortUtils::HasDisplayPort(nsIContent
* aContent
) {
603 return GetDisplayPort(aContent
, nullptr);
606 bool DisplayPortUtils::HasPaintedDisplayPort(nsIContent
* aContent
) {
607 DisplayPortPropertyData
* rectData
= nullptr;
608 DisplayPortMarginsPropertyData
* marginsData
= nullptr;
609 GetDisplayPortData(aContent
, &rectData
, &marginsData
);
611 return rectData
->mPainted
;
614 return marginsData
->mPainted
;
619 void DisplayPortUtils::MarkDisplayPortAsPainted(nsIContent
* aContent
) {
620 DisplayPortPropertyData
* rectData
= nullptr;
621 DisplayPortMarginsPropertyData
* marginsData
= nullptr;
622 GetDisplayPortData(aContent
, &rectData
, &marginsData
);
623 MOZ_ASSERT(rectData
|| marginsData
,
624 "MarkDisplayPortAsPainted should only be called for an element "
625 "with a displayport");
627 rectData
->mPainted
= true;
630 marginsData
->mPainted
= true;
634 bool DisplayPortUtils::HasNonMinimalDisplayPort(nsIContent
* aContent
) {
635 return HasDisplayPort(aContent
) &&
636 !aContent
->GetProperty(nsGkAtoms::MinimalDisplayPort
);
639 bool DisplayPortUtils::HasNonMinimalNonZeroDisplayPort(nsIContent
* aContent
) {
640 if (!HasDisplayPort(aContent
)) {
643 if (aContent
->GetProperty(nsGkAtoms::MinimalDisplayPort
)) {
647 DisplayPortMarginsPropertyData
* currentData
=
648 static_cast<DisplayPortMarginsPropertyData
*>(
649 aContent
->GetProperty(nsGkAtoms::DisplayPortMargins
));
652 // We have a display port, so if we don't have margin data we must have rect
653 // data. We consider such as non zero and non minimal, it's probably not too
654 // important as display port rects are only used in tests.
658 if (currentData
->mMargins
.mMargins
!= ScreenMargin()) {
666 bool DisplayPortUtils::GetDisplayPortForVisibilityTesting(nsIContent
* aContent
,
669 // Since the base rect might not have been updated very recently, it's
670 // possible to end up with an extra-large displayport at this point, if the
671 // zoom level is changed by a lot. Instead of using the default behaviour of
672 // asserting, we can just ignore the displayport if that happens, as this
673 // call site is best-effort.
674 return GetDisplayPortImpl(aContent
, aResult
, 1.0f
,
676 .With(MaxSizeExceededBehaviour::Drop
)
677 .With(DisplayportRelativeTo::ScrollFrame
));
680 void DisplayPortUtils::InvalidateForDisplayPortChange(
681 nsIContent
* aContent
, bool aHadDisplayPort
, const nsRect
& aOldDisplayPort
,
682 const nsRect
& aNewDisplayPort
, RepaintMode aRepaintMode
) {
683 if (aRepaintMode
!= RepaintMode::Repaint
) {
688 !aHadDisplayPort
|| !aOldDisplayPort
.IsEqualEdges(aNewDisplayPort
);
690 nsIFrame
* frame
= nsLayoutUtils::GetScrollFrameFromContent(aContent
);
692 frame
= do_QueryFrame(frame
->GetScrollTargetFrame());
695 if (changed
&& frame
) {
696 // It is important to call SchedulePaint on the same frame that we set the
697 // dirty rect properties on so we can find the frame later to remove the
699 frame
->SchedulePaint();
701 if (!nsLayoutUtils::AreRetainedDisplayListsEnabled() ||
702 !nsLayoutUtils::DisplayRootHasRetainedDisplayListBuilder(frame
)) {
707 nsRect
* rect
= frame
->GetProperty(
708 nsDisplayListBuilder::DisplayListBuildingDisplayPortRect(), &found
);
713 nsDisplayListBuilder::DisplayListBuildingDisplayPortRect(), rect
);
714 frame
->SetHasOverrideDirtyRegion(true);
716 nsIFrame
* rootFrame
= frame
->PresShell()->GetRootFrame();
717 MOZ_ASSERT(rootFrame
);
719 RetainedDisplayListData
* data
=
720 GetOrSetRetainedDisplayListData(rootFrame
);
721 data
->Flags(frame
) |= RetainedDisplayListData::FrameFlags::HasProps
;
723 MOZ_ASSERT(rect
, "this property should only store non-null values");
726 if (aHadDisplayPort
) {
727 // We only need to build a display list for any new areas added
728 nsRegion
newRegion(aNewDisplayPort
);
729 newRegion
.SubOut(aOldDisplayPort
);
730 rect
->UnionRect(*rect
, newRegion
.GetBounds());
732 rect
->UnionRect(*rect
, aNewDisplayPort
);
737 bool DisplayPortUtils::SetDisplayPortMargins(
738 nsIContent
* aContent
, PresShell
* aPresShell
,
739 const DisplayPortMargins
& aMargins
,
740 ClearMinimalDisplayPortProperty aClearMinimalDisplayPortProperty
,
741 uint32_t aPriority
, RepaintMode aRepaintMode
) {
742 MOZ_ASSERT(aContent
);
743 MOZ_ASSERT(aContent
->GetComposedDoc() == aPresShell
->GetDocument());
745 DisplayPortMarginsPropertyData
* currentData
=
746 static_cast<DisplayPortMarginsPropertyData
*>(
747 aContent
->GetProperty(nsGkAtoms::DisplayPortMargins
));
748 if (currentData
&& currentData
->mPriority
> aPriority
) {
752 if (currentData
&& currentData
->mMargins
.mVisualOffset
!= CSSPoint() &&
753 aMargins
.mVisualOffset
== CSSPoint()) {
754 // If we hit this, then it's possible that we're setting a displayport
755 // that is wrong because the old one had a layout/visual adjustment and
756 // the new one does not.
757 MOZ_LOG(sDisplayportLog
, LogLevel::Warning
,
758 ("Dropping visual offset %s",
759 ToString(currentData
->mMargins
.mVisualOffset
).c_str()));
762 nsIFrame
* scrollFrame
= nsLayoutUtils::GetScrollFrameFromContent(aContent
);
764 nsRect oldDisplayPort
;
765 bool hadDisplayPort
= false;
766 bool wasPainted
= GetWasDisplayPortPainted(aContent
);
768 // We only use the two return values from this function to call
769 // InvalidateForDisplayPortChange. InvalidateForDisplayPortChange does
770 // nothing if aContent does not have a frame. So getting the displayport is
771 // useless if the content has no frame, so we avoid calling this to avoid
772 // triggering a warning about not having a frame.
773 hadDisplayPort
= GetHighResolutionDisplayPort(aContent
, &oldDisplayPort
);
776 aContent
->SetProperty(
777 nsGkAtoms::DisplayPortMargins
,
778 new DisplayPortMarginsPropertyData(aMargins
, aPriority
, wasPainted
),
779 nsINode::DeleteProperty
<DisplayPortMarginsPropertyData
>);
781 if (aClearMinimalDisplayPortProperty
==
782 ClearMinimalDisplayPortProperty::Yes
) {
783 if (MOZ_LOG_TEST(sDisplayportLog
, LogLevel::Debug
) &&
784 aContent
->GetProperty(nsGkAtoms::MinimalDisplayPort
)) {
785 mozilla::layers::ScrollableLayerGuid::ViewID viewID
=
786 mozilla::layers::ScrollableLayerGuid::NULL_SCROLL_ID
;
787 nsLayoutUtils::FindIDFor(aContent
, &viewID
);
788 MOZ_LOG(sDisplayportLog
, LogLevel::Debug
,
789 ("SetDisplayPortMargins removing MinimalDisplayPort prop on "
790 "scrollId=%" PRIu64
"\n",
793 aContent
->RemoveProperty(nsGkAtoms::MinimalDisplayPort
);
796 nsIScrollableFrame
* scrollableFrame
=
797 scrollFrame
? scrollFrame
->GetScrollTargetFrame() : nullptr;
798 if (!scrollableFrame
) {
802 nsRect newDisplayPort
;
803 DebugOnly
<bool> hasDisplayPort
=
804 GetHighResolutionDisplayPort(aContent
, &newDisplayPort
);
805 MOZ_ASSERT(hasDisplayPort
);
807 if (MOZ_LOG_TEST(sDisplayportLog
, LogLevel::Debug
)) {
808 mozilla::layers::ScrollableLayerGuid::ViewID viewID
=
809 mozilla::layers::ScrollableLayerGuid::NULL_SCROLL_ID
;
810 nsLayoutUtils::FindIDFor(aContent
, &viewID
);
811 if (!hadDisplayPort
) {
812 MOZ_LOG(sDisplayportLog
, LogLevel::Debug
,
813 ("SetDisplayPortMargins %s on scrollId=%" PRIu64
", newDp=%s\n",
814 ToString(aMargins
).c_str(), viewID
,
815 ToString(newDisplayPort
).c_str()));
817 // Use verbose level logging for when an existing displayport got its
819 MOZ_LOG(sDisplayportLog
, LogLevel::Verbose
,
820 ("SetDisplayPortMargins %s on scrollId=%" PRIu64
", newDp=%s\n",
821 ToString(aMargins
).c_str(), viewID
,
822 ToString(newDisplayPort
).c_str()));
826 InvalidateForDisplayPortChange(aContent
, hadDisplayPort
, oldDisplayPort
,
827 newDisplayPort
, aRepaintMode
);
829 scrollableFrame
->TriggerDisplayPortExpiration();
831 // Display port margins changing means that the set of visible frames may
832 // have drastically changed. Check if we should schedule an update.
834 scrollableFrame
->GetDisplayPortAtLastApproximateFrameVisibilityUpdate(
837 bool needVisibilityUpdate
= !hadDisplayPort
;
838 // Check if the total size has changed by a large factor.
839 if (!needVisibilityUpdate
) {
840 if ((newDisplayPort
.width
> 2 * oldDisplayPort
.width
) ||
841 (oldDisplayPort
.width
> 2 * newDisplayPort
.width
) ||
842 (newDisplayPort
.height
> 2 * oldDisplayPort
.height
) ||
843 (oldDisplayPort
.height
> 2 * newDisplayPort
.height
)) {
844 needVisibilityUpdate
= true;
847 // Check if it's moved by a significant amount.
848 if (!needVisibilityUpdate
) {
849 if (nsRect
* baseData
= static_cast<nsRect
*>(
850 aContent
->GetProperty(nsGkAtoms::DisplayPortBase
))) {
851 nsRect base
= *baseData
;
852 if ((std::abs(newDisplayPort
.X() - oldDisplayPort
.X()) > base
.width
) ||
853 (std::abs(newDisplayPort
.XMost() - oldDisplayPort
.XMost()) >
855 (std::abs(newDisplayPort
.Y() - oldDisplayPort
.Y()) > base
.height
) ||
856 (std::abs(newDisplayPort
.YMost() - oldDisplayPort
.YMost()) >
858 needVisibilityUpdate
= true;
862 if (needVisibilityUpdate
) {
863 aPresShell
->ScheduleApproximateFrameVisibilityUpdateNow();
869 void DisplayPortUtils::SetDisplayPortBase(nsIContent
* aContent
,
870 const nsRect
& aBase
) {
871 if (MOZ_LOG_TEST(sDisplayportLog
, LogLevel::Verbose
)) {
872 ViewID viewId
= nsLayoutUtils::FindOrCreateIDFor(aContent
);
873 MOZ_LOG(sDisplayportLog
, LogLevel::Verbose
,
874 ("Setting base rect %s for scrollId=%" PRIu64
"\n",
875 ToString(aBase
).c_str(), viewId
));
877 aContent
->SetProperty(nsGkAtoms::DisplayPortBase
, new nsRect(aBase
),
878 nsINode::DeleteProperty
<nsRect
>);
881 void DisplayPortUtils::SetDisplayPortBaseIfNotSet(nsIContent
* aContent
,
882 const nsRect
& aBase
) {
883 if (!aContent
->GetProperty(nsGkAtoms::DisplayPortBase
)) {
884 SetDisplayPortBase(aContent
, aBase
);
888 bool DisplayPortUtils::GetCriticalDisplayPort(
889 nsIContent
* aContent
, nsRect
* aResult
, const DisplayPortOptions
& aOptions
) {
890 if (StaticPrefs::layers_low_precision_buffer()) {
891 return GetDisplayPortImpl(aContent
, aResult
, 1.0f
, aOptions
);
896 bool DisplayPortUtils::HasCriticalDisplayPort(nsIContent
* aContent
) {
897 return GetCriticalDisplayPort(aContent
, nullptr);
900 bool DisplayPortUtils::GetHighResolutionDisplayPort(
901 nsIContent
* aContent
, nsRect
* aResult
, const DisplayPortOptions
& aOptions
) {
902 if (StaticPrefs::layers_low_precision_buffer()) {
903 return GetCriticalDisplayPort(aContent
, aResult
, aOptions
);
905 return GetDisplayPort(aContent
, aResult
, aOptions
);
908 void DisplayPortUtils::RemoveDisplayPort(nsIContent
* aContent
) {
909 aContent
->RemoveProperty(nsGkAtoms::DisplayPort
);
910 aContent
->RemoveProperty(nsGkAtoms::DisplayPortMargins
);
913 bool DisplayPortUtils::ViewportHasDisplayPort(nsPresContext
* aPresContext
) {
914 nsIFrame
* rootScrollFrame
= aPresContext
->PresShell()->GetRootScrollFrame();
915 return rootScrollFrame
&& HasDisplayPort(rootScrollFrame
->GetContent());
918 bool DisplayPortUtils::IsFixedPosFrameInDisplayPort(const nsIFrame
* aFrame
) {
919 // Fixed-pos frames are parented by the viewport frame or the page content
920 // frame. We'll assume that printing/print preview don't have displayports for
922 nsIFrame
* parent
= aFrame
->GetParent();
923 if (!parent
|| parent
->GetParent() ||
924 aFrame
->StyleDisplay()->mPosition
!= StylePositionProperty::Fixed
) {
927 return ViewportHasDisplayPort(aFrame
->PresContext());
930 // We want to this return true for the scroll frame, but not the
931 // scrolled frame (which has the same content).
932 bool DisplayPortUtils::FrameHasDisplayPort(nsIFrame
* aFrame
,
933 const nsIFrame
* aScrolledFrame
) {
934 if (!aFrame
->GetContent() || !HasDisplayPort(aFrame
->GetContent())) {
937 nsIScrollableFrame
* sf
= do_QueryFrame(aFrame
);
939 if (aScrolledFrame
&& aScrolledFrame
!= sf
->GetScrolledFrame()) {
947 bool DisplayPortUtils::CalculateAndSetDisplayPortMargins(
948 nsIScrollableFrame
* aScrollFrame
, RepaintMode aRepaintMode
) {
949 nsIFrame
* frame
= do_QueryFrame(aScrollFrame
);
951 nsIContent
* content
= frame
->GetContent();
954 FrameMetrics metrics
=
955 nsLayoutUtils::CalculateBasicFrameMetrics(aScrollFrame
);
956 ScreenMargin displayportMargins
= layers::apz::CalculatePendingDisplayPort(
957 metrics
, ParentLayerPoint(0.0f
, 0.0f
));
958 PresShell
* presShell
= frame
->PresContext()->GetPresShell();
960 DisplayPortMargins margins
= DisplayPortMargins::ForScrollFrame(
961 aScrollFrame
, displayportMargins
,
962 Some(metrics
.DisplayportPixelsPerCSSPixel()));
964 return SetDisplayPortMargins(content
, presShell
, margins
,
965 ClearMinimalDisplayPortProperty::Yes
, 0,
969 bool DisplayPortUtils::MaybeCreateDisplayPort(nsDisplayListBuilder
* aBuilder
,
970 nsIFrame
* aScrollFrame
,
971 RepaintMode aRepaintMode
) {
972 nsIContent
* content
= aScrollFrame
->GetContent();
973 nsIScrollableFrame
* scrollableFrame
= do_QueryFrame(aScrollFrame
);
974 if (!content
|| !scrollableFrame
) {
978 bool haveDisplayPort
= HasNonMinimalNonZeroDisplayPort(content
);
980 // We perform an optimization where we ensure that at least one
981 // async-scrollable frame (i.e. one that WantsAsyncScroll()) has a
982 // displayport. If that's not the case yet, and we are async-scrollable, we
983 // will get a displayport.
984 if (aBuilder
->IsPaintingToWindow() &&
985 nsLayoutUtils::AsyncPanZoomEnabled(aScrollFrame
) &&
986 !aBuilder
->HaveScrollableDisplayPort() &&
987 scrollableFrame
->WantAsyncScroll()) {
988 // If we don't already have a displayport, calculate and set one.
989 if (!haveDisplayPort
) {
990 // We only use the viewId for logging purposes, but create it
991 // unconditionally to minimize impact of enabling logging. If we don't
992 // assign a viewId here it will get assigned later anyway so functionally
993 // there should be no difference.
994 ViewID viewId
= nsLayoutUtils::FindOrCreateIDFor(content
);
996 sDisplayportLog
, LogLevel::Debug
,
997 ("Setting DP on first-encountered scrollId=%" PRIu64
"\n", viewId
));
999 CalculateAndSetDisplayPortMargins(scrollableFrame
, aRepaintMode
);
1001 haveDisplayPort
= HasNonMinimalDisplayPort(content
);
1002 MOZ_ASSERT(haveDisplayPort
,
1003 "should have a displayport after having just set it");
1007 // Record that the we now have a scrollable display port.
1008 aBuilder
->SetHaveScrollableDisplayPort();
1013 void DisplayPortUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(
1015 nsIFrame
* frame
= aFrame
;
1017 frame
= nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(frame
);
1021 nsIScrollableFrame
* scrollAncestor
=
1022 nsLayoutUtils::GetAsyncScrollableAncestorFrame(frame
);
1023 if (!scrollAncestor
) {
1026 frame
= do_QueryFrame(scrollAncestor
);
1028 MOZ_ASSERT(scrollAncestor
->WantAsyncScroll() ||
1029 frame
->PresShell()->GetRootScrollFrame() == frame
);
1030 if (nsLayoutUtils::AsyncPanZoomEnabled(frame
) &&
1031 !HasDisplayPort(frame
->GetContent())) {
1032 SetDisplayPortMargins(frame
->GetContent(), frame
->PresShell(),
1033 DisplayPortMargins::Empty(frame
->GetContent()),
1034 ClearMinimalDisplayPortProperty::No
, 0,
1035 RepaintMode::Repaint
);
1040 bool DisplayPortUtils::MaybeCreateDisplayPortInFirstScrollFrameEncountered(
1041 nsIFrame
* aFrame
, nsDisplayListBuilder
* aBuilder
) {
1042 nsIScrollableFrame
* sf
= do_QueryFrame(aFrame
);
1044 if (MaybeCreateDisplayPort(aBuilder
, aFrame
, RepaintMode::Repaint
)) {
1048 if (aFrame
->IsPlaceholderFrame()) {
1049 nsPlaceholderFrame
* placeholder
= static_cast<nsPlaceholderFrame
*>(aFrame
);
1050 if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(
1051 placeholder
->GetOutOfFlowFrame(), aBuilder
)) {
1055 if (aFrame
->IsSubDocumentFrame()) {
1056 PresShell
* presShell
= static_cast<nsSubDocumentFrame
*>(aFrame
)
1057 ->GetSubdocumentPresShellForPainting(0);
1058 nsIFrame
* root
= presShell
? presShell
->GetRootFrame() : nullptr;
1060 if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(root
, aBuilder
)) {
1065 if (aFrame
->IsDeckFrame()) {
1066 // only descend the visible card of a decks
1067 nsIFrame
* child
= static_cast<nsDeckFrame
*>(aFrame
)->GetSelectedBox();
1069 return MaybeCreateDisplayPortInFirstScrollFrameEncountered(child
,
1074 for (nsIFrame
* child
: aFrame
->PrincipalChildList()) {
1075 if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(child
, aBuilder
)) {
1083 void DisplayPortUtils::ExpireDisplayPortOnAsyncScrollableAncestor(
1085 nsIFrame
* frame
= aFrame
;
1087 frame
= nsLayoutUtils::GetCrossDocParentFrameInProcess(frame
);
1091 nsIScrollableFrame
* scrollAncestor
=
1092 nsLayoutUtils::GetAsyncScrollableAncestorFrame(frame
);
1093 if (!scrollAncestor
) {
1096 frame
= do_QueryFrame(scrollAncestor
);
1101 MOZ_ASSERT(scrollAncestor
->WantAsyncScroll() ||
1102 frame
->PresShell()->GetRootScrollFrame() == frame
);
1103 if (HasDisplayPort(frame
->GetContent())) {
1104 scrollAncestor
->TriggerDisplayPortExpiration();
1105 // Stop after the first trigger. If it failed, there's no point in
1106 // continuing because all the rest of the frames we encounter are going
1107 // to be ancestors of |scrollAncestor| which will keep its displayport.
1108 // If the trigger succeeded, we stop because when the trigger executes
1109 // it will call this function again to trigger the next ancestor up the
1116 static PresShell
* GetPresShell(const nsIContent
* aContent
) {
1117 if (dom::Document
* doc
= aContent
->GetComposedDoc()) {
1118 return doc
->GetPresShell();
1123 static void UpdateDisplayPortMarginsForPendingMetrics(
1124 const RepaintRequest
& aMetrics
) {
1125 nsIContent
* content
= nsLayoutUtils::FindContentFor(aMetrics
.GetScrollId());
1130 RefPtr
<PresShell
> presShell
= GetPresShell(content
);
1135 if (nsLayoutUtils::AllowZoomingForDocument(presShell
->GetDocument()) &&
1136 aMetrics
.IsRootContent()) {
1137 // See APZCCallbackHelper::UpdateRootFrame for details.
1138 float presShellResolution
= presShell
->GetResolution();
1139 if (presShellResolution
!= aMetrics
.GetPresShellResolution()) {
1144 nsIScrollableFrame
* frame
=
1145 nsLayoutUtils::FindScrollableFrameFor(aMetrics
.GetScrollId());
1151 if (APZCCallbackHelper::IsScrollInProgress(frame
)) {
1152 // If these conditions are true, then the UpdateFrame
1153 // message may be ignored by the main-thread, so we
1154 // shouldn't update the displayport based on it.
1158 DisplayPortMarginsPropertyData
* currentData
=
1159 static_cast<DisplayPortMarginsPropertyData
*>(
1160 content
->GetProperty(nsGkAtoms::DisplayPortMargins
));
1165 CSSPoint frameScrollOffset
=
1166 CSSPoint::FromAppUnits(frame
->GetScrollPosition());
1168 DisplayPortUtils::SetDisplayPortMargins(
1170 DisplayPortMargins::FromAPZ(
1171 aMetrics
.GetDisplayPortMargins(), aMetrics
.GetVisualScrollOffset(),
1172 frameScrollOffset
, aMetrics
.DisplayportPixelsPerCSSPixel()),
1173 DisplayPortUtils::ClearMinimalDisplayPortProperty::No
, 0);
1177 void DisplayPortUtils::UpdateDisplayPortMarginsFromPendingMessages() {
1178 if (XRE_IsContentProcess() && layers::CompositorBridgeChild::Get() &&
1179 layers::CompositorBridgeChild::Get()->GetIPCChannel()) {
1180 layers::CompositorBridgeChild::Get()->GetIPCChannel()->PeekMessages(
1181 [](const IPC::Message
& aMsg
) -> bool {
1182 if (aMsg
.type() == layers::PAPZ::Msg_RequestContentRepaint__ID
) {
1183 PickleIterator
iter(aMsg
);
1184 RepaintRequest request
;
1185 if (!IPC::ReadParam(&aMsg
, &iter
, &request
)) {
1190 UpdateDisplayPortMarginsForPendingMetrics(request
);
1197 Maybe
<nsRect
> DisplayPortUtils::GetRootDisplayportBase(PresShell
* aPresShell
) {
1198 DebugOnly
<nsPresContext
*> pc
= aPresShell
->GetPresContext();
1199 MOZ_ASSERT(pc
, "this function should be called after PresShell::Init");
1200 MOZ_ASSERT(pc
->IsRootContentDocumentCrossProcess() ||
1201 !pc
->GetParentPresContext());
1203 dom::BrowserChild
* browserChild
= dom::BrowserChild::GetFrom(aPresShell
);
1204 if (browserChild
&& !browserChild
->IsTopLevel()) {
1205 // If this is an in-process root in on OOP iframe, use the visible rect if
1207 return browserChild
->GetVisibleRect();
1210 nsIFrame
* frame
= aPresShell
->GetRootScrollFrame();
1212 frame
= aPresShell
->GetRootFrame();
1217 baseRect
= nsRect(nsPoint(0, 0),
1218 nsLayoutUtils::CalculateCompositionSizeForFrame(frame
));
1220 baseRect
= nsRect(nsPoint(0, 0),
1221 aPresShell
->GetPresContext()->GetVisibleArea().Size());
1224 return Some(baseRect
);
1227 } // namespace mozilla