FrameMetrics.h (43888B)
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/. */ 6 7 #ifndef GFX_FRAMEMETRICS_H 8 #define GFX_FRAMEMETRICS_H 9 10 #include <stdint.h> // for uint8_t, uint32_t, uint64_t 11 #include <iosfwd> 12 13 #include "Units.h" // for CSSRect, CSSPixel, etc 14 #include "UnitTransforms.h" // for ViewAs 15 #include "mozilla/DefineEnum.h" // for MOZ_DEFINE_ENUM 16 #include "mozilla/HashFunctions.h" // for HashGeneric 17 #include "mozilla/Maybe.h" 18 #include "mozilla/dom/InteractiveWidget.h" 19 #include "mozilla/gfx/BasePoint.h" // for BasePoint 20 #include "mozilla/gfx/Rect.h" // for RoundedIn 21 #include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor 22 #include "mozilla/gfx/Logging.h" // for Log 23 #include "mozilla/layers/LayersTypes.h" // for ScrollDirection 24 #include "mozilla/layers/ScrollableLayerGuid.h" // for ScrollableLayerGuid 25 #include "mozilla/ScrollPositionUpdate.h" // for ScrollPositionUpdate 26 #include "mozilla/ScrollSnapInfo.h" 27 #include "mozilla/ScrollSnapTargetId.h" 28 #include "mozilla/StaticPtr.h" // for StaticAutoPtr 29 #include "mozilla/TimeStamp.h" // for TimeStamp 30 #include "nsTHashMap.h" // for nsTHashMap 31 #include "nsString.h" 32 #include "PLDHashTable.h" // for PLDHashNumber 33 34 struct nsStyleDisplay; 35 namespace mozilla { 36 enum class StyleOverscrollBehavior : uint8_t; 37 } // namespace mozilla 38 39 namespace IPC { 40 template <typename T> 41 struct ParamTraits; 42 } // namespace IPC 43 44 namespace mozilla { 45 namespace layers { 46 47 /** 48 * Metrics about a scroll frame that are sent to the compositor and used 49 * by APZ. 50 * 51 * This is used for two main purposes: 52 * 53 * (1) Sending information about a scroll frame to the compositor and APZ 54 * as part of a layers or WebRender transaction. 55 * (2) Storing information about a scroll frame in APZ that persists 56 * between transactions. 57 * 58 * TODO: Separate these two uses into two distinct structures. 59 * 60 * A related class, RepaintRequest, is used for sending information about a 61 * scroll frame back from the compositor to the main thread when requesting 62 * a repaint of the scroll frame's contents. 63 */ 64 struct FrameMetrics { 65 friend struct IPC::ParamTraits<mozilla::layers::FrameMetrics>; 66 friend std::ostream& operator<<(std::ostream& aStream, 67 const FrameMetrics& aMetrics); 68 69 typedef ScrollableLayerGuid::ViewID ViewID; 70 71 public: 72 // clang-format off 73 MOZ_DEFINE_ENUM_WITH_BASE_AT_CLASS_SCOPE( 74 ScrollOffsetUpdateType, uint8_t, ( 75 eNone, // The default; the scroll offset was not updated 76 eMainThread, // The scroll offset was updated by the main thread. 77 eRestore // The scroll offset was updated by the main thread, but 78 // as a restore from history or after a frame 79 // reconstruction. In this case, APZ can ignore the 80 // offset change if the user has done an APZ scroll 81 // already. 82 )); 83 // clang-format on 84 85 FrameMetrics() 86 : mScrollId(ScrollableLayerGuid::NULL_SCROLL_ID), 87 mPresShellResolution(1), 88 mCompositionBounds(0, 0, 0, 0), 89 mCompositionBoundsWidthIgnoringScrollbars(0), 90 mDisplayPort(0, 0, 0, 0), 91 mScrollableRect(0, 0, 0, 0), 92 mDevPixelsPerCSSPixel(1), 93 mScrollOffset(0, 0), 94 mBoundingCompositionSize(0, 0), 95 mPresShellId(-1), 96 mLayoutViewport(0, 0, 0, 0), 97 mVisualDestination(0, 0), 98 mVisualScrollUpdateType(eNone), 99 mInteractiveWidget( 100 dom::InteractiveWidgetUtils::DefaultInteractiveWidgetMode()), 101 mIsRootContent(false), 102 mIsScrollInfoLayer(false), 103 mHasNonZeroDisplayPortMargins(false), 104 mMinimalDisplayPort(false), 105 mIsSoftwareKeyboardVisible(false) {} 106 107 // Default copy ctor and operator= are fine 108 109 bool operator==(const FrameMetrics& aOther) const { 110 // Put mScrollId at the top since it's the most likely one to fail. 111 return mScrollId == aOther.mScrollId && 112 mPresShellResolution == aOther.mPresShellResolution && 113 mCompositionBounds.IsEqualEdges(aOther.mCompositionBounds) && 114 mCompositionBoundsWidthIgnoringScrollbars == 115 aOther.mCompositionBoundsWidthIgnoringScrollbars && 116 mDisplayPort.IsEqualEdges(aOther.mDisplayPort) && 117 mScrollableRect.IsEqualEdges(aOther.mScrollableRect) && 118 mCumulativeResolution == aOther.mCumulativeResolution && 119 mDevPixelsPerCSSPixel == aOther.mDevPixelsPerCSSPixel && 120 mScrollOffset == aOther.mScrollOffset && 121 // don't compare mZoom 122 mScrollGeneration == aOther.mScrollGeneration && 123 mBoundingCompositionSize == aOther.mBoundingCompositionSize && 124 mPresShellId == aOther.mPresShellId && 125 mLayoutViewport.IsEqualEdges(aOther.mLayoutViewport) && 126 mTransformToAncestorScale == aOther.mTransformToAncestorScale && 127 mPaintRequestTime == aOther.mPaintRequestTime && 128 mVisualDestination == aOther.mVisualDestination && 129 mVisualScrollUpdateType == aOther.mVisualScrollUpdateType && 130 mInteractiveWidget == aOther.mInteractiveWidget && 131 mIsRootContent == aOther.mIsRootContent && 132 mIsScrollInfoLayer == aOther.mIsScrollInfoLayer && 133 mHasNonZeroDisplayPortMargins == 134 aOther.mHasNonZeroDisplayPortMargins && 135 mMinimalDisplayPort == aOther.mMinimalDisplayPort && 136 mFixedLayerMargins == aOther.mFixedLayerMargins && 137 mCompositionSizeWithoutDynamicToolbar == 138 aOther.mCompositionSizeWithoutDynamicToolbar && 139 mIsSoftwareKeyboardVisible == aOther.mIsSoftwareKeyboardVisible; 140 } 141 142 bool operator!=(const FrameMetrics& aOther) const { 143 return !operator==(aOther); 144 } 145 146 bool IsScrollable() const { 147 return mScrollId != ScrollableLayerGuid::NULL_SCROLL_ID; 148 } 149 150 CSSToScreenScale2D DisplayportPixelsPerCSSPixel() const { 151 // Note: mZoom includes the async zoom. We want to include the async zoom 152 // even though the size of the pixels of our *current* displayport does not 153 // yet reflect it, because this function is used in the context of a repaint 154 // request where we'll be asking for a *new* displayport which does reflect 155 // the async zoom. Note 2: we include the transform to ancestor scale 156 // because this function (as the name implies) is used only in various 157 // displayport calculation related places, and those calculations want the 158 // transform to ancestor scale to be included becaese they want to reason 159 // about pixels which are the same size as screen pixels (so displayport 160 // sizes are e.g. limited to a multiple of the screen size). Whereas mZoom 161 // and mCumulativeResolution do not include it because of expectations of 162 // the code where they are used. 163 return mZoom * mTransformToAncestorScale; 164 } 165 166 CSSToLayerScale LayersPixelsPerCSSPixel() const { 167 return mDevPixelsPerCSSPixel * mCumulativeResolution; 168 } 169 170 // Get the amount by which this frame has been zoomed since the last repaint. 171 LayerToParentLayerScale GetAsyncZoom() const { 172 return mZoom / LayersPixelsPerCSSPixel(); 173 } 174 175 // Ensure the scrollableRect is at least as big as the compositionBounds 176 // because the scrollableRect can be smaller if the content is not large 177 // and the scrollableRect hasn't been updated yet. 178 // We move the scrollableRect up because we don't know if we can move it 179 // down. i.e. we know that scrollableRect can go back as far as zero. 180 // but we don't know how much further ahead it can go. 181 CSSRect GetExpandedScrollableRect() const { 182 CSSRect scrollableRect = mScrollableRect; 183 CSSSize compSize = CalculateCompositedSizeInCssPixels(); 184 if (scrollableRect.Width() < compSize.width) { 185 scrollableRect.SetRectX( 186 std::max(0.f, scrollableRect.X() - 187 (compSize.width - scrollableRect.Width())), 188 compSize.width); 189 } 190 191 if (scrollableRect.Height() < compSize.height) { 192 scrollableRect.SetRectY( 193 std::max(0.f, scrollableRect.Y() - 194 (compSize.height - scrollableRect.Height())), 195 compSize.height); 196 } 197 198 return scrollableRect; 199 } 200 201 CSSSize CalculateCompositedSizeInCssPixels() const { 202 return CalculateCompositedSizeInCssPixels(mCompositionBounds, mZoom); 203 } 204 205 /* 206 * Calculate the composition bounds of this frame in the CSS pixels of 207 * the content surrounding the scroll frame (OuterCSS pixels). 208 * Note that it does not make sense to ask for the composition bounds in the 209 * CSS pixels of the scrolled content (that is, regular CSS pixels), 210 * because the origin of the composition bounds is not meaningful in that 211 * coordinate space. (The size is, use CalculateCompositedSizeInCssPixels() 212 * for that.) 213 */ 214 OuterCSSRect CalculateCompositionBoundsInOuterCssPixels() const { 215 if (GetZoom() == CSSToParentLayerScale(0)) { 216 return OuterCSSRect(); // avoid division by zero 217 } 218 // The CSS pixels of the scrolled content and the CSS pixels of the 219 // surrounding content only differ if the scrolled content is rendered 220 // at a higher resolution, and the difference is the resolution. 221 return mCompositionBounds / GetZoom() * GetCSSToOuterCSSScale(); 222 } 223 224 CSSSize CalculateBoundedCompositedSizeInCssPixels() const { 225 CSSSize size = CalculateCompositedSizeInCssPixels(); 226 size.width = std::min(size.width, mBoundingCompositionSize.width); 227 size.height = std::min(size.height, mBoundingCompositionSize.height); 228 return size; 229 } 230 231 CSSRect CalculateScrollRange() const { 232 return CalculateScrollRange(mScrollableRect, mCompositionBounds, mZoom); 233 } 234 235 void ScrollBy(const CSSPoint& aPoint) { 236 SetVisualScrollOffset(GetVisualScrollOffset() + aPoint); 237 } 238 239 void ZoomBy(float aScale) { mZoom.scale *= aScale; } 240 241 /* 242 * Compares an APZ frame metrics with an incoming content frame metrics 243 * to see if APZ has a scroll offset that has not been incorporated into 244 * the content frame metrics. 245 */ 246 bool HasPendingScroll(const FrameMetrics& aContentFrameMetrics) const { 247 return GetVisualScrollOffset() != 248 aContentFrameMetrics.GetVisualScrollOffset(); 249 } 250 251 /* 252 * Returns true if the layout scroll offset or visual scroll offset changed. 253 */ 254 bool ApplyScrollUpdateFrom(const ScrollPositionUpdate& aUpdate); 255 256 /** 257 * Applies the relative scroll offset update contained in aOther to the 258 * scroll offset contained in this. The scroll delta is clamped to the 259 * scrollable region. 260 * 261 * @returns The clamped scroll offset delta that was applied 262 */ 263 enum class IsDefaultApzc { 264 No, 265 Yes, 266 }; 267 CSSPoint ApplyRelativeScrollUpdateFrom(const ScrollPositionUpdate& aUpdate, 268 IsDefaultApzc aIsDefaultApzc); 269 270 CSSPoint ApplyPureRelativeScrollUpdateFrom( 271 const ScrollPositionUpdate& aUpdate); 272 273 void UpdatePendingScrollInfo(const ScrollPositionUpdate& aInfo); 274 275 bool ScrollLayoutViewportTo(const CSSPoint& aDestination); 276 277 public: 278 void SetPresShellResolution(float aPresShellResolution) { 279 mPresShellResolution = aPresShellResolution; 280 } 281 282 float GetPresShellResolution() const { return mPresShellResolution; } 283 284 void SetCompositionBounds(const ParentLayerRect& aCompositionBounds) { 285 mCompositionBounds = aCompositionBounds; 286 } 287 288 const ParentLayerRect& GetCompositionBounds() const { 289 return mCompositionBounds; 290 } 291 292 void SetCompositionBoundsWidthIgnoringScrollbars( 293 const ParentLayerCoord aCompositionBoundsWidthIgnoringScrollbars) { 294 mCompositionBoundsWidthIgnoringScrollbars = 295 aCompositionBoundsWidthIgnoringScrollbars; 296 } 297 298 const ParentLayerCoord GetCompositionBoundsWidthIgnoringScrollbars() const { 299 return mCompositionBoundsWidthIgnoringScrollbars; 300 } 301 302 void SetDisplayPort(const CSSRect& aDisplayPort) { 303 mDisplayPort = aDisplayPort; 304 } 305 306 const CSSRect& GetDisplayPort() const { return mDisplayPort; } 307 308 void SetCumulativeResolution( 309 const LayoutDeviceToLayerScale& aCumulativeResolution) { 310 mCumulativeResolution = aCumulativeResolution; 311 } 312 313 const LayoutDeviceToLayerScale& GetCumulativeResolution() const { 314 return mCumulativeResolution; 315 } 316 317 void SetDevPixelsPerCSSPixel( 318 const CSSToLayoutDeviceScale& aDevPixelsPerCSSPixel) { 319 mDevPixelsPerCSSPixel = aDevPixelsPerCSSPixel; 320 } 321 322 const CSSToLayoutDeviceScale& GetDevPixelsPerCSSPixel() const { 323 return mDevPixelsPerCSSPixel; 324 } 325 326 CSSToOuterCSSScale GetCSSToOuterCSSScale() const { 327 // The scale difference between CSS and OuterCSS pixels is the 328 // part of the zoom that's not subject to all enclosing content, 329 // i.e. the pres shell resolution. 330 return CSSToOuterCSSScale(mPresShellResolution); 331 } 332 333 void SetIsRootContent(bool aIsRootContent) { 334 mIsRootContent = aIsRootContent; 335 } 336 337 bool IsRootContent() const { return mIsRootContent; } 338 339 // Set scroll offset, first clamping to the scroll range. 340 // Return true if it changed. 341 bool ClampAndSetVisualScrollOffset(const CSSPoint& aScrollOffset) { 342 CSSPoint offsetBefore = GetVisualScrollOffset(); 343 SetVisualScrollOffset(CalculateScrollRange().ClampPoint(aScrollOffset)); 344 return (offsetBefore != GetVisualScrollOffset()); 345 } 346 347 CSSPoint GetLayoutScrollOffset() const { return mLayoutViewport.TopLeft(); } 348 // Returns true if it changed. 349 bool SetLayoutScrollOffset(const CSSPoint& aLayoutScrollOffset) { 350 CSSPoint offsetBefore = GetLayoutScrollOffset(); 351 mLayoutViewport.MoveTo(aLayoutScrollOffset); 352 return (offsetBefore != GetLayoutScrollOffset()); 353 } 354 355 const CSSPoint& GetVisualScrollOffset() const { return mScrollOffset; } 356 void SetVisualScrollOffset(const CSSPoint& aVisualScrollOffset) { 357 mScrollOffset = aVisualScrollOffset; 358 } 359 360 void SetZoom(const CSSToParentLayerScale& aZoom) { mZoom = aZoom; } 361 362 const CSSToParentLayerScale& GetZoom() const { return mZoom; } 363 364 void SetScrollGeneration( 365 const MainThreadScrollGeneration& aScrollGeneration) { 366 mScrollGeneration = aScrollGeneration; 367 } 368 369 MainThreadScrollGeneration GetScrollGeneration() const { 370 return mScrollGeneration; 371 } 372 373 ViewID GetScrollId() const { return mScrollId; } 374 375 void SetScrollId(ViewID scrollId) { mScrollId = scrollId; } 376 377 void SetBoundingCompositionSize(const CSSSize& aBoundingCompositionSize) { 378 mBoundingCompositionSize = aBoundingCompositionSize; 379 } 380 381 const CSSSize& GetBoundingCompositionSize() const { 382 return mBoundingCompositionSize; 383 } 384 385 uint32_t GetPresShellId() const { return mPresShellId; } 386 387 void SetPresShellId(uint32_t aPresShellId) { mPresShellId = aPresShellId; } 388 389 void SetLayoutViewport(const CSSRect& aLayoutViewport) { 390 mLayoutViewport = aLayoutViewport; 391 } 392 393 const CSSRect& GetLayoutViewport() const { return mLayoutViewport; } 394 395 CSSRect GetVisualViewport() const { 396 return CSSRect(GetVisualScrollOffset(), 397 CalculateCompositedSizeInCssPixels()); 398 } 399 400 // TODO Bug 2003420: This function should eventually be able to supercede 401 // GetVisualViewport and drop the default argument for 402 // |aFixedLayerBottomMargin|. The difference from GetVisualViewport is this 403 // function handles the current dynamic toolbar state. In other words 404 // GetVisualViewport always handles the toolbar state as if the dynamic 405 // toolbar is completely hidden. 406 CSSRect GetVisualViewportForLayoutViewportContainment( 407 ScreenCoord aFixedLayerBottomMargin = 0) const; 408 409 void SetTransformToAncestorScale( 410 const ParentLayerToScreenScale2D& aTransformToAncestorScale) { 411 mTransformToAncestorScale = aTransformToAncestorScale; 412 } 413 414 const ParentLayerToScreenScale2D& GetTransformToAncestorScale() const { 415 return mTransformToAncestorScale; 416 } 417 418 const CSSRect& GetScrollableRect() const { return mScrollableRect; } 419 420 void SetScrollableRect(const CSSRect& aScrollableRect) { 421 mScrollableRect = aScrollableRect; 422 } 423 424 // If the frame is in vertical-RTL writing mode(E.g. "writing-mode: 425 // vertical-rl" in CSS), or if it's in horizontal-RTL writing-mode(E.g. 426 // "writing-mode: horizontal-tb; direction: rtl;" in CSS), then this function 427 // returns true. From the representation perspective, frames whose horizontal 428 // contents start at rightside also cause their horizontal scrollbars, if any, 429 // initially start at rightside. So we can also learn about the initial side 430 // of the horizontal scrollbar for the frame by calling this function. 431 bool IsHorizontalContentRightToLeft() const { return mScrollableRect.x < 0; } 432 433 void SetPaintRequestTime(const TimeStamp& aTime) { 434 mPaintRequestTime = aTime; 435 } 436 const TimeStamp& GetPaintRequestTime() const { return mPaintRequestTime; } 437 438 void SetIsScrollInfoLayer(bool aIsScrollInfoLayer) { 439 mIsScrollInfoLayer = aIsScrollInfoLayer; 440 } 441 bool IsScrollInfoLayer() const { return mIsScrollInfoLayer; } 442 443 void SetHasNonZeroDisplayPortMargins(bool aHasNonZeroDisplayPortMargins) { 444 mHasNonZeroDisplayPortMargins = aHasNonZeroDisplayPortMargins; 445 } 446 bool HasNonZeroDisplayPortMargins() const { 447 return mHasNonZeroDisplayPortMargins; 448 } 449 450 void SetMinimalDisplayPort(bool aMinimalDisplayPort) { 451 mMinimalDisplayPort = aMinimalDisplayPort; 452 } 453 bool IsMinimalDisplayPort() const { return mMinimalDisplayPort; } 454 455 void SetIsSoftwareKeyboardVisible(bool aValue) { 456 mIsSoftwareKeyboardVisible = aValue; 457 } 458 bool IsSoftwareKeyboardVisible() const { return mIsSoftwareKeyboardVisible; } 459 460 void SetInteractiveWidget(dom::InteractiveWidget aInteractiveWidget) { 461 mInteractiveWidget = aInteractiveWidget; 462 } 463 dom::InteractiveWidget GetInteractiveWidget() const { 464 return mInteractiveWidget; 465 } 466 467 void SetVisualDestination(const CSSPoint& aVisualDestination) { 468 mVisualDestination = aVisualDestination; 469 } 470 const CSSPoint& GetVisualDestination() const { return mVisualDestination; } 471 472 void SetVisualScrollUpdateType(ScrollOffsetUpdateType aUpdateType) { 473 mVisualScrollUpdateType = aUpdateType; 474 } 475 ScrollOffsetUpdateType GetVisualScrollUpdateType() const { 476 return mVisualScrollUpdateType; 477 } 478 479 // Determine if the visual viewport is outside of the layout viewport and 480 // adjust the x,y-offset in mLayoutViewport accordingly. This is necessary to 481 // allow APZ to async-scroll the layout viewport. 482 // 483 // This is a no-op if mIsRootContent is false. 484 void RecalculateLayoutViewportOffset(ScreenCoord aFixedLayerBottomMargin = 0); 485 486 void SetFixedLayerMargins(const ScreenMargin& aFixedLayerMargins) { 487 mFixedLayerMargins = aFixedLayerMargins; 488 } 489 const ScreenMargin& GetFixedLayerMargins() const { 490 return mFixedLayerMargins; 491 } 492 493 void SetCompositionSizeWithoutDynamicToolbar(const ParentLayerSize& aSize) { 494 MOZ_ASSERT(mIsRootContent); 495 mCompositionSizeWithoutDynamicToolbar = aSize; 496 } 497 const ParentLayerSize& GetCompositionSizeWithoutDynamicToolbar() const { 498 MOZ_ASSERT(mIsRootContent); 499 return mCompositionSizeWithoutDynamicToolbar; 500 } 501 502 // Helper function for RecalculateViewportOffset(). Exposed so that 503 // APZC can perform the operation on other copies of the layout 504 // and visual viewport rects (e.g. the "effective" ones used to implement 505 // the frame delay). 506 // Modifies |aLayoutViewport| to continue enclosing |aVisualViewport| 507 // if possible. 508 // The layout viewport needs to remain clamped to the scrollable rect, 509 // and we pass in the scrollable rect so this function can maintain that 510 // constraint. 511 static void KeepLayoutViewportEnclosingVisualViewport( 512 const CSSRect& aVisualViewport, const CSSRect& aScrollableRect, 513 CSSRect& aLayoutViewport); 514 515 // Helper functions exposed so we can perform operations on copies outside of 516 // frame metrics object. 517 static CSSRect CalculateScrollRange(const CSSRect& aScrollableRect, 518 const ParentLayerRect& aCompositionBounds, 519 const CSSToParentLayerScale& aZoom); 520 static CSSSize CalculateCompositedSizeInCssPixels( 521 const ParentLayerRect& aCompositionBounds, 522 const CSSToParentLayerScale& aZoom); 523 524 private: 525 // A ID assigned to each scrollable frame, unique within each LayersId.. 526 ViewID mScrollId; 527 528 // The pres-shell resolution that has been induced on the document containing 529 // this scroll frame as a result of zooming this scroll frame (whether via 530 // user action, or choosing an initial zoom level on page load). This can 531 // only be different from 1.0 for frames that are zoomable, which currently 532 // is just the root content document's root scroll frame 533 // (mIsRootContent = true). 534 // This is a plain float rather than a ScaleFactor because in and of itself 535 // it does not convert between any coordinate spaces for which we have names. 536 float mPresShellResolution; 537 538 // This is the area within the widget that we're compositing to. It is in the 539 // layer coordinates of the scrollable content's parent layer. 540 // 541 // The size of the composition bounds corresponds to the size of the scroll 542 // frame's scroll port (but in a coordinate system where the size does not 543 // change during zooming). 544 // 545 // The origin of the composition bounds is relative to the scroll node origin. 546 // (The "scroll node origin" is the point such that applying the APZC's 547 // apzc-to-screen transform to it takes you to the window origin, which is 548 // what Screen event coordinates are relative to. In layout terms, it's 549 // the origin of the reference frame passed to ComputeScrollMetadata().) 550 // Unlike the scroll port's origin, it does not change during scrolling of 551 // the scrollable layer to which it is associated. However, it may change due 552 // to scrolling of ancestor layers. 553 // 554 // This value is provided by Gecko at layout/paint time. 555 ParentLayerRect mCompositionBounds; 556 557 // For RCD-RSF this is the width of the composition bounds ignoring 558 // scrollbars. For everything else this will be the same as the width of the 559 // composition bounds. Only needed for the "resolution changed" check in 560 // NotifyLayersUpdated, once that switches to using IsResolutionUpdated we can 561 // remove this. 562 ParentLayerCoord mCompositionBoundsWidthIgnoringScrollbars; 563 564 // The area of a scroll frame's contents that has been painted, relative to 565 // GetLayoutScrollOffset(). 566 // 567 // Should not be larger than GetExpandedScrollableRect(). 568 // 569 // To pre-render a margin of 100 CSS pixels around the scroll port, 570 // { x = -100, y = - 100, 571 // width = scrollPort.width + 200, height = scrollPort.height + 200 } 572 // where scrollPort = CalculateCompositedSizeInCssPixels(). 573 CSSRect mDisplayPort; 574 575 // The scrollable bounds of a frame. This is determined by reflow. 576 // Ordinarily the x and y will be 0 and the width and height will be the 577 // size of the element being scrolled. However for RTL pages or elements 578 // the x value may be negative. 579 // 580 // For scrollable frames that are overflow:hidden the x and y are usually 581 // set to the value of the current scroll offset, and the width and height 582 // will match the composition bounds width and height. In effect this reduces 583 // the scrollable range to 0. 584 // 585 // This is in the same coordinate space as |mScrollOffset|, but a different 586 // coordinate space than |mDisplayPort|. Note also that this coordinate 587 // system is understood by window.scrollTo(). 588 CSSRect mScrollableRect; 589 590 // The cumulative resolution of the current frame. This is the product of the 591 // pres-shell resolutions of the document containing this scroll frame and its 592 // in-process ancestors. This information is provided by Gecko at layout/paint 593 // time. Notably, for out of process iframes cumulative resolution will be 1. 594 // The reason for this is that AsyncPanZoomController::GetTransformToThis does 595 // not contain the resolution in the process of the root content document, but 596 // in oop iframes AsyncPanZoomController::GetTransformToThis does contain the 597 // resolution. This makes coordinate math work out in APZ code because in the 598 // old layers backend GetTransformToThis was a transform of rendered pixels, 599 // and the pixels were rendered with the scale applied already. The reason 600 // that AsyncPanZoomController::GetTransformToThis contains the scale in oop 601 // iframes is because we include the resolution in the transform that includes 602 // the iframe via this call 603 // https://searchfox.org/mozilla-central/rev/2eebd6e256fa0355e08421265e57ee1307836d92/layout/generic/nsSubDocumentFrame.cpp#1404 604 // So when coordinates are passed to the process of the oop iframe they have 605 // the resolution removed by unapplying that transform which includes the 606 // resolution. 607 LayoutDeviceToLayerScale mCumulativeResolution; 608 609 // The conversion factor between CSS pixels and device pixels for this frame. 610 // This can vary based on a variety of things, such as reflowing-zoom. 611 CSSToLayoutDeviceScale mDevPixelsPerCSSPixel; 612 613 // The position of the top-left of the scroll frame's scroll port, relative 614 // to the scrollable content's origin. 615 // 616 // This is in the same coordinate space as |mScrollableRect|, but a different 617 // coordinate space than |mDisplayPort|. 618 // 619 // It is required that the rect: 620 // { x = mScrollOffset.x, y = mScrollOffset.y, 621 // width = scrollPort.width, 622 // height = scrollPort.height } 623 // (where scrollPort = CalculateCompositedSizeInCssPixels()) 624 // be within |mScrollableRect|. 625 CSSPoint mScrollOffset; 626 627 // The "user zoom". Content is painted by gecko at mCumulativeResolution * 628 // mDevPixelsPerCSSPixel, but will be drawn to the screen at mZoom. In the 629 // steady state, the two will be the same, but during an async zoom action the 630 // two may diverge. This information is initialized in Gecko but updated in 631 // the APZC. 632 CSSToParentLayerScale mZoom; 633 634 // The scroll generation counter used to acknowledge the scroll offset update. 635 MainThreadScrollGeneration mScrollGeneration; 636 637 // A bounding size for our composition bounds (no larger than the 638 // cross-process RCD-RSF's composition size), in local CSS pixels. 639 CSSSize mBoundingCompositionSize; 640 641 uint32_t mPresShellId; 642 643 // The scroll frame's layout viewport. 644 // 645 // Its origin is the scroll frame's layout scroll position, i.e. the 646 // scroll position exposed to web content via window.scrollX/Y. 647 // Its size is the dimensions we're using to constrain the allowed values 648 // of window.scrollX/Y (e.g. the maximum possible value of scrollY is) 649 // the one that makes the bottom of the layout viewport line up with the 650 // bottom of the scrollable rect). This size is also called the "scroll port 651 // size" in layout code. 652 // 653 // For scroll frames other than the root content document's root scroll frame 654 // (RCD-RSF), this should be the same as mVisualViewport. 655 // 656 // For the RCD-RSF, the layout and visual viewports can diverge. On desktop 657 // platforms, the size of the layout viewport matches the size of the 658 // document's initial containing block (ICB), which in turn is derived from 659 // the size of the content viewer. On mobile platforms, the size of the 660 // layout viewport (also called "fixed viewport", because it serves as the 661 // containing block for position:fixed content) is the "minimum scale size", 662 // as discussed in more detail at 663 // https://github.com/bokand/bokand.github.io/blob/master/web_viewports_explainer.md#minimum-scale-size. 664 CSSRect mLayoutViewport; 665 666 // The scale induced by css transforms and presshell resolution in this 667 // process and any ancestor processes that encloses this scroll frame that is 668 // _not_ included in mCumulativeResolution. This means that in the process of 669 // the root content document this only includes css transform scale (which 670 // happens in that process, but we assume there can be no css transform scale 671 // above the root content document). In other processes it includes css 672 // transform scale and any resolution scale in the current process and all 673 // ancestor processes. 674 ParentLayerToScreenScale2D mTransformToAncestorScale; 675 676 // The time at which the APZC last requested a repaint for this scroll frame. 677 TimeStamp mPaintRequestTime; 678 679 // These fields are used when the main thread wants to set a visual viewport 680 // offset that's distinct from the layout viewport offset. 681 // In this case, mVisualScrollUpdateType is set to eMainThread, and 682 // mVisualDestination is set to desired visual destination (relative 683 // to the document, like mScrollOffset). 684 CSSPoint mVisualDestination; 685 ScrollOffsetUpdateType mVisualScrollUpdateType; 686 687 // 'fixed layer margins' on the main-thread. This is only used for the 688 // root-content scroll frame. 689 ScreenMargin mFixedLayerMargins; 690 691 // Similar to mCompositionBounds.Size() but not including the dynamic toolbar 692 // height. 693 // If we are not using a dynamic toolbar, this has the same value as 694 // mCompositionBounds.Size(). 695 ParentLayerSize mCompositionSizeWithoutDynamicToolbar; 696 697 // The interactive-widget of the root-content document. 698 // This is only applicable to the root-content scroll frame, it's stored in 699 // APZTreeManager as APZTreeManager::mInteractiveWidget so that it should not 700 // be checked on AsyncPanZoomController::mScrollMetadata. 701 dom::InteractiveWidget mInteractiveWidget; 702 703 // Whether or not this is the root scroll frame for the root content document. 704 bool mIsRootContent : 1; 705 706 // True if this scroll frame is a scroll info layer. A scroll info layer is 707 // not layerized and its content cannot be truly async-scrolled, but its 708 // metrics are still sent to and updated by the compositor, with the updates 709 // being reflected on the next paint rather than the next composite. 710 bool mIsScrollInfoLayer : 1; 711 712 // Whether there are non-zero display port margins set on this element. 713 bool mHasNonZeroDisplayPortMargins : 1; 714 715 // Whether this scroll frame is using a minimal display port, which means that 716 // any set display port margins are ignored when calculating the display port 717 // and instead zero margins are used and further no tile or alignment 718 // boundaries are used that could potentially expand the size. 719 bool mMinimalDisplayPort : 1; 720 721 // Whether the software keyboard is currently visible. 722 // This is only applicable to the root-content scroll frame, it's stored in 723 // APZTreeManager as APZTreeManager::mIsSoftwareKeyboardVisible so that it 724 // should not be checked on AsyncPanZoomController::mScrollMetadata. 725 bool mIsSoftwareKeyboardVisible : 1; 726 727 // WARNING!!!! 728 // 729 // When adding a new field: 730 // 731 // - First, consider whether the field can be added to ScrollMetadata 732 // instead. If so, prefer that. 733 // 734 // - Otherwise, the following places should be updated to include them 735 // (as needed): 736 // FrameMetrics::operator == 737 // AsyncPanZoomController::NotifyLayersUpdated 738 // The ParamTraits specialization in LayersMessageUtils.h 739 // 740 // Please add new fields above this comment. 741 }; 742 743 // clang-format off 744 MOZ_DEFINE_ENUM_CLASS_WITH_BASE( 745 OverscrollBehavior, uint8_t, ( 746 Auto, 747 Contain, 748 None 749 )); 750 // clang-format on 751 752 std::ostream& operator<<(std::ostream& aStream, 753 const OverscrollBehavior& aBehavior); 754 755 struct OverscrollBehaviorInfo final { 756 OverscrollBehaviorInfo(); 757 758 // Construct from StyleOverscrollBehavior values. 759 static OverscrollBehaviorInfo FromStyleConstants( 760 StyleOverscrollBehavior aBehaviorX, StyleOverscrollBehavior aBehaviorY); 761 762 bool operator==(const OverscrollBehaviorInfo& aOther) const; 763 friend std::ostream& operator<<(std::ostream& aStream, 764 const OverscrollBehaviorInfo& aInfo); 765 766 auto MutTiedFields() { return std::tie(mBehaviorX, mBehaviorY); } 767 768 OverscrollBehavior mBehaviorX; 769 OverscrollBehavior mBehaviorY; 770 }; 771 772 struct OverflowInfo final { 773 StyleOverflow mOverflowX = StyleOverflow::Visible; 774 StyleOverflow mOverflowY = StyleOverflow::Visible; 775 776 bool operator==(const OverflowInfo& aOther) const; 777 778 auto MutTiedFields() { return std::tie(mOverflowX, mOverflowY); } 779 }; 780 781 /** 782 * Metadata about a scroll frame that's sent to the compositor during a layers 783 * or WebRender transaction, and also stored by APZ between transactions. 784 * This includes the scroll frame's FrameMetrics, as well as other metadata. 785 * We don't put the other metadata into FrameMetrics to avoid FrameMetrics 786 * becoming too bloated (as a FrameMetrics is e.g. stored in memory shared 787 * with the content process). 788 */ 789 struct ScrollMetadata { 790 friend struct IPC::ParamTraits<mozilla::layers::ScrollMetadata>; 791 friend std::ostream& operator<<(std::ostream& aStream, 792 const ScrollMetadata& aMetadata); 793 794 typedef ScrollableLayerGuid::ViewID ViewID; 795 796 public: 797 static StaticAutoPtr<const ScrollMetadata> 798 sNullMetadata; // We sometimes need an empty metadata 799 800 ScrollMetadata() 801 : mScrollParentId(ScrollableLayerGuid::NULL_SCROLL_ID), 802 mLineScrollAmount(0, 0), 803 mPageScrollAmount(0, 0), 804 mIsLayersIdRoot(false), 805 mIsAutoDirRootContentRTL(false), 806 mForceDisableApz(false), 807 mResolutionUpdated(false), 808 mIsRDMTouchSimulationActive(false), 809 mDidContentGetPainted(true), 810 mForceMousewheelAutodir(false), 811 mForceMousewheelAutodirHonourRoot(false), 812 mIsPaginatedPresentation(false) {} 813 814 bool operator==(const ScrollMetadata& aOther) const { 815 return mMetrics == aOther.mMetrics && mSnapInfo == aOther.mSnapInfo && 816 mScrollParentId == aOther.mScrollParentId && 817 // don't compare mContentDescription 818 mLineScrollAmount == aOther.mLineScrollAmount && 819 mPageScrollAmount == aOther.mPageScrollAmount && 820 mIsLayersIdRoot == aOther.mIsLayersIdRoot && 821 mIsAutoDirRootContentRTL == aOther.mIsAutoDirRootContentRTL && 822 mForceDisableApz == aOther.mForceDisableApz && 823 mResolutionUpdated == aOther.mResolutionUpdated && 824 mIsRDMTouchSimulationActive == aOther.mIsRDMTouchSimulationActive && 825 mDidContentGetPainted == aOther.mDidContentGetPainted && 826 mForceMousewheelAutodir == aOther.mForceMousewheelAutodir && 827 mForceMousewheelAutodirHonourRoot == 828 aOther.mForceMousewheelAutodirHonourRoot && 829 mIsPaginatedPresentation == aOther.mIsPaginatedPresentation && 830 mDisregardedDirection == aOther.mDisregardedDirection && 831 mOverscrollBehavior == aOther.mOverscrollBehavior && 832 mOverflow == aOther.mOverflow && 833 mScrollUpdates == aOther.mScrollUpdates; 834 } 835 836 bool operator!=(const ScrollMetadata& aOther) const { 837 return !operator==(aOther); 838 } 839 840 bool IsDefault() const { 841 ScrollMetadata def; 842 843 def.mMetrics.SetPresShellId(mMetrics.GetPresShellId()); 844 return (def == *this); 845 } 846 847 FrameMetrics& GetMetrics() { return mMetrics; } 848 const FrameMetrics& GetMetrics() const { return mMetrics; } 849 850 void SetSnapInfo(ScrollSnapInfo&& aSnapInfo) { 851 mSnapInfo = std::move(aSnapInfo); 852 } 853 const ScrollSnapInfo& GetSnapInfo() const { return mSnapInfo; } 854 855 ViewID GetScrollParentId() const { return mScrollParentId; } 856 857 void SetScrollParentId(ViewID aParentId) { mScrollParentId = aParentId; } 858 const nsCString& GetContentDescription() const { return mContentDescription; } 859 void SetContentDescription(const nsCString& aContentDescription) { 860 mContentDescription = aContentDescription; 861 } 862 const LayoutDeviceIntSize& GetLineScrollAmount() const { 863 return mLineScrollAmount; 864 } 865 void SetLineScrollAmount(const LayoutDeviceIntSize& size) { 866 mLineScrollAmount = size; 867 } 868 const LayoutDeviceIntSize& GetPageScrollAmount() const { 869 return mPageScrollAmount; 870 } 871 void SetPageScrollAmount(const LayoutDeviceIntSize& size) { 872 mPageScrollAmount = size; 873 } 874 void SetIsLayersIdRoot(bool aValue) { mIsLayersIdRoot = aValue; } 875 bool IsLayersIdRoot() const { return mIsLayersIdRoot; } 876 void SetIsAutoDirRootContentRTL(bool aValue) { 877 mIsAutoDirRootContentRTL = aValue; 878 } 879 bool IsAutoDirRootContentRTL() const { return mIsAutoDirRootContentRTL; } 880 void SetForceDisableApz(bool aForceDisable) { 881 mForceDisableApz = aForceDisable; 882 } 883 bool IsApzForceDisabled() const { return mForceDisableApz; } 884 void SetResolutionUpdated(bool aUpdated) { mResolutionUpdated = aUpdated; } 885 bool IsResolutionUpdated() const { return mResolutionUpdated; } 886 887 void SetIsRDMTouchSimulationActive(bool aValue) { 888 mIsRDMTouchSimulationActive = aValue; 889 } 890 bool GetIsRDMTouchSimulationActive() const { 891 return mIsRDMTouchSimulationActive; 892 } 893 894 void SetForceMousewheelAutodir(bool aValue) { 895 mForceMousewheelAutodir = aValue; 896 } 897 bool ForceMousewheelAutodir() const { return mForceMousewheelAutodir; } 898 899 void SetForceMousewheelAutodirHonourRoot(bool aValue) { 900 mForceMousewheelAutodirHonourRoot = aValue; 901 } 902 bool ForceMousewheelAutodirHonourRoot() const { 903 return mForceMousewheelAutodirHonourRoot; 904 } 905 906 void SetIsPaginatedPresentation(bool aValue) { 907 mIsPaginatedPresentation = aValue; 908 } 909 bool IsPaginatedPresentation() const { return mIsPaginatedPresentation; } 910 911 bool DidContentGetPainted() const { return mDidContentGetPainted; } 912 913 private: 914 // For use in IPC only 915 void SetDidContentGetPainted(bool aValue) { mDidContentGetPainted = aValue; } 916 917 public: 918 // For more details about the concept of a disregarded direction, refer to the 919 // code which defines mDisregardedDirection. 920 Maybe<ScrollDirection> GetDisregardedDirection() const { 921 return mDisregardedDirection; 922 } 923 void SetDisregardedDirection(const Maybe<ScrollDirection>& aValue) { 924 mDisregardedDirection = aValue; 925 } 926 927 void SetOverscrollBehavior( 928 const OverscrollBehaviorInfo& aOverscrollBehavior) { 929 mOverscrollBehavior = aOverscrollBehavior; 930 } 931 const OverscrollBehaviorInfo& GetOverscrollBehavior() const { 932 return mOverscrollBehavior; 933 } 934 935 void SetOverflow(const OverflowInfo& aOverflow) { mOverflow = aOverflow; } 936 const OverflowInfo& GetOverflow() const { return mOverflow; } 937 938 void SetScrollUpdates(const nsTArray<ScrollPositionUpdate>& aUpdates) { 939 mScrollUpdates = aUpdates; 940 } 941 942 const nsTArray<ScrollPositionUpdate>& GetScrollUpdates() const { 943 return mScrollUpdates; 944 } 945 946 void UpdatePendingScrollInfo(nsTArray<ScrollPositionUpdate>&& aUpdates) { 947 MOZ_ASSERT(!aUpdates.IsEmpty()); 948 mMetrics.UpdatePendingScrollInfo(aUpdates.LastElement()); 949 950 mDidContentGetPainted = false; 951 mScrollUpdates.Clear(); 952 mScrollUpdates.AppendElements(std::move(aUpdates)); 953 } 954 955 void PrependUpdates(const nsTArray<ScrollPositionUpdate>& aUpdates) { 956 MOZ_ASSERT(!aUpdates.IsEmpty()); 957 958 mScrollUpdates.InsertElementsAt(0, aUpdates); 959 } 960 961 private: 962 FrameMetrics mMetrics; 963 964 // Information used to determine where to snap to for a given scroll. 965 ScrollSnapInfo mSnapInfo; 966 967 // The ViewID of the scrollable frame to which overscroll should be handed 968 // off. 969 ViewID mScrollParentId; 970 971 // A description of the content element corresponding to this frame. 972 // This is empty unless this is a scrollable layer and the 973 // apz.printtree pref is turned on. 974 nsCString mContentDescription; 975 976 // The value of GetLineScrollAmount(), for scroll frames. 977 LayoutDeviceIntSize mLineScrollAmount; 978 979 // The value of GetPageScrollAmount(), for scroll frames. 980 LayoutDeviceIntSize mPageScrollAmount; 981 982 // Whether these framemetrics are for the root scroll frame (root element if 983 // we don't have a root scroll frame) for its layers id. 984 bool mIsLayersIdRoot : 1; 985 986 // The AutoDirRootContent is the <body> element in an HTML document, or the 987 // root scrollframe if there is no body. This member variable indicates 988 // whether this element's content in the horizontal direction starts from 989 // right to left (e.g. it's true either if "writing-mode: vertical-rl", or 990 // "writing-mode: horizontal-tb; direction: rtl" in CSS). 991 // When we do auto-dir scrolling (@see mozilla::WheelDeltaAdjustmentStrategy 992 // or refer to bug 1358017 for details), setting a pref can make the code use 993 // the writing mode of this root element instead of the target scrollframe, 994 // and so we need to know if the writing mode is RTL or not. 995 bool mIsAutoDirRootContentRTL : 1; 996 997 // Whether or not the compositor should actually do APZ-scrolling on this 998 // scrollframe. 999 bool mForceDisableApz : 1; 1000 1001 // Whether the pres shell resolution stored in mMetrics reflects a change 1002 // originated by the main thread. 1003 bool mResolutionUpdated : 1; 1004 1005 // Whether or not RDM and touch simulation are active for this document. 1006 // It's important to note that if RDM is active then this field will be 1007 // true for the content document but NOT the chrome document containing 1008 // the browser UI and RDM controls. 1009 bool mIsRDMTouchSimulationActive : 1; 1010 1011 // Whether this metadata is part of a transaction that also repainted the 1012 // content (i.e. updated the displaylist or textures). This gets set to false 1013 // for "paint-skip" transactions, where the main thread doesn't repaint but 1014 // instead requests APZ to update the compositor scroll offset instead. APZ 1015 // needs to be able to distinguish these paint-skip transactions so that it 1016 // can use the correct transforms. 1017 bool mDidContentGetPainted : 1; 1018 1019 // Whether privileged code has requested that autodir behaviour be 1020 // enabled for the scroll frame. 1021 bool mForceMousewheelAutodir : 1; 1022 bool mForceMousewheelAutodirHonourRoot : 1; 1023 1024 // Whether this content is being displayed in a paginated fashion 1025 // such as printing or print preview. In such cases, content that 1026 // would normally only generate one display item may generated one 1027 // display item per page, and the different instances may be subject 1028 // to different transforms, which constrains the assumptions APZ can make. 1029 bool mIsPaginatedPresentation : 1; 1030 1031 // The disregarded direction means the direction which is disregarded anyway, 1032 // even if the scroll frame overflows in that direction and the direction is 1033 // specified as scrollable. This could happen in some scenarios, for instance, 1034 // a single-line text control frame should disregard wheel scroll in 1035 // its block-flow direction even if it overflows in that direction. 1036 Maybe<ScrollDirection> mDisregardedDirection; 1037 1038 // The overscroll behavior for this scroll frame. 1039 OverscrollBehaviorInfo mOverscrollBehavior; 1040 1041 // The CSS overflow styles for this scroll frame. 1042 // For a root scroll frame, this stores the viewport styles 1043 // as defined in https://drafts.csswg.org/css-overflow/#overflow-propagation 1044 // (i.e. they will always be 'auto', 'hidden', or 'scrol'). 1045 OverflowInfo mOverflow; 1046 1047 // The ordered list of scroll position updates for this scroll frame since 1048 // the last transaction. 1049 CopyableTArray<ScrollPositionUpdate> mScrollUpdates; 1050 1051 // WARNING!!!! 1052 // 1053 // When adding new fields to ScrollMetadata, the following places should be 1054 // updated to include them (as needed): 1055 // 1. ScrollMetadata::operator == 1056 // 2. AsyncPanZoomController::NotifyLayersUpdated 1057 // 3. The ParamTraits specialization in LayersMessageUtils.h 1058 // 1059 // Please add new fields above this comment. 1060 }; 1061 1062 typedef nsTHashMap<ScrollableLayerGuid::ViewIDHashKey, 1063 nsTArray<ScrollPositionUpdate>> 1064 ScrollUpdatesMap; 1065 1066 } // namespace layers 1067 } // namespace mozilla 1068 1069 #endif /* GFX_FRAMEMETRICS_H */