ScrollContainerFrame.h (61869B)
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 /* rendering object to wrap rendering objects that should be scrollable */ 8 9 #ifndef mozilla_ScrollContainerFrame_h_ 10 #define mozilla_ScrollContainerFrame_h_ 11 12 #include "FrameMetrics.h" 13 #include "ScrollVelocityQueue.h" 14 #include "mozilla/Attributes.h" 15 #include "mozilla/ScrollOrigin.h" 16 #include "mozilla/ScrollTypes.h" 17 #include "mozilla/dom/WindowBinding.h" // for mozilla::dom::ScrollBehavior 18 #include "mozilla/layout/ScrollAnchorContainer.h" 19 #include "nsContainerFrame.h" 20 #include "nsExpirationTracker.h" 21 #include "nsIAnonymousContentCreator.h" 22 #include "nsIReflowCallback.h" 23 #include "nsIScrollbarMediator.h" 24 #include "nsIStatefulFrame.h" 25 #include "nsQueryFrame.h" 26 #include "nsThreadUtils.h" 27 28 class nsPresContext; 29 class nsIContent; 30 class nsAtom; 31 class AutoContainsBlendModeCapturer; 32 33 namespace mozilla { 34 struct nsDisplayListCollection; 35 class PresShell; 36 class PresState; 37 enum class PhysicalAxis : uint8_t; 38 enum class StyleScrollbarWidth : uint8_t; 39 class ScrollContainerFrame; 40 class ScrollPositionUpdate; 41 class StickyScrollContainer; 42 struct ScrollReflowInput; 43 struct ScrollStyles; 44 struct StyleScrollSnapAlign; 45 namespace layers { 46 class Layer; 47 class WebRenderLayerManager; 48 } // namespace layers 49 namespace layout { 50 class ScrollbarActivity; 51 } // namespace layout 52 53 } // namespace mozilla 54 55 mozilla::ScrollContainerFrame* NS_NewScrollContainerFrame( 56 mozilla::PresShell* aPresShell, mozilla::ComputedStyle* aStyle, 57 bool aIsRoot); 58 59 namespace mozilla { 60 61 /** 62 * The scroll frame creates and manages the scrolling view 63 * 64 * It only supports having a single child frame that typically is an area 65 * frame, but doesn't have to be. The child frame must have a view, though 66 * 67 * Scroll frames don't support incremental changes, i.e. you can't replace 68 * or remove the scrolled frame 69 */ 70 class ScrollContainerFrame : public nsContainerFrame, 71 public nsIScrollbarMediator, 72 public nsIAnonymousContentCreator, 73 public nsIReflowCallback, 74 public nsIStatefulFrame { 75 public: 76 using CSSPoint = mozilla::CSSPoint; 77 using Element = dom::Element; 78 using ScrollAnchorContainer = layout::ScrollAnchorContainer; 79 using SnapTargetSet = nsTHashSet<RefPtr<nsIContent>>; 80 81 friend ScrollContainerFrame* ::NS_NewScrollContainerFrame( 82 mozilla::PresShell* aPresShell, ComputedStyle* aStyle, bool aIsRoot); 83 friend class layout::ScrollAnchorContainer; 84 85 NS_DECL_QUERYFRAME 86 NS_DECL_FRAMEARENA_HELPERS(ScrollContainerFrame) 87 88 void BuildDisplayList(nsDisplayListBuilder* aBuilder, 89 const nsDisplayListSet& aLists) override; 90 91 // Return the sum of inline-size of the scrollbar gutters (if any) at the 92 // inline-start and inline-end edges of the scroll frame (for a potential 93 // scrollbar that scrolls in the block axis). 94 nscoord IntrinsicScrollbarGutterSizeAtInlineEdges() const; 95 96 // Return the size of space created by scrollbar-gutter or actual scrollbars, 97 // assuming that the content is *not* overflowing the container. In other 98 // words, this space is created by stable scrollbar-gutter or by scrollbars 99 // due to "overflow: scroll". 100 nsMargin IntrinsicScrollbarGutterSize() const; 101 102 // Compute stable scrollbar-gutter from scrollbar-width and scrollbar-gutter 103 // properties. 104 // 105 // Note: this method doesn't consider overflow property and the space created 106 // by the actual scrollbars. That is, if scrollbar-gutter is 'auto', this 107 // method just returns empty result. 108 nsMargin ComputeStableScrollbarGutter( 109 const StyleScrollbarWidth& aStyleScrollbarWidth, 110 const StyleScrollbarGutter& aStyleScrollbarGutter) const; 111 112 bool GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea, 113 nsIFrame::Sides aSkipSides, 114 nsRectCornerRadii&) const final; 115 116 nscoord IntrinsicISize(const IntrinsicSizeInput& aInput, 117 IntrinsicISizeType aType) override; 118 119 void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, 120 const ReflowInput& aReflowInput, 121 nsReflowStatus& aStatus) override; 122 void DidReflow(nsPresContext* aPresContext, 123 const ReflowInput* aReflowInput) override; 124 125 bool ComputeCustomOverflow(OverflowAreas& aOverflowAreas) final; 126 127 BaselineSharingGroup GetDefaultBaselineSharingGroup() const override; 128 nscoord SynthesizeFallbackBaseline( 129 WritingMode aWM, BaselineSharingGroup aBaselineGroup) const override; 130 Maybe<nscoord> GetNaturalBaselineBOffset( 131 WritingMode aWM, BaselineSharingGroup aBaselineGroup, 132 BaselineExportContext aExportContext) const override; 133 134 StickyScrollContainer* GetStickyContainer() const { 135 return mStickyContainer.get(); 136 } 137 StickyScrollContainer& EnsureStickyContainer(); 138 139 // Recomputes the scrollable overflow area we store in the helper to take 140 // children that are affected by perpsective set on the outer frame and scroll 141 // at different rates. 142 void AdjustForPerspective(nsRect& aScrollableOverflow); 143 144 // Called to set the child frames. We typically have three: the scroll area, 145 // the vertical scrollbar, and the horizontal scrollbar. 146 void SetInitialChildList(ChildListID aListID, 147 nsFrameList&& aChildList) override; 148 void AppendFrames(ChildListID aListID, nsFrameList&& aFrameList) final; 149 void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame, 150 const nsLineList::iterator* aPrevFrameLine, 151 nsFrameList&& aFrameList) final; 152 void RemoveFrame(DestroyContext&, ChildListID, nsIFrame*) final; 153 154 void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) final; 155 156 void Destroy(DestroyContext&) override; 157 158 ScrollContainerFrame* GetScrollTargetFrame() const final { 159 return const_cast<ScrollContainerFrame*>(this); 160 } 161 162 nsContainerFrame* GetContentInsertionFrame() override { 163 return GetScrolledFrame()->GetContentInsertionFrame(); 164 } 165 166 nsPoint GetPositionOfChildIgnoringScrolling(const nsIFrame* aChild) final { 167 nsPoint pt = aChild->GetPosition(); 168 if (aChild == GetScrolledFrame()) { 169 pt += GetScrollPosition(); 170 } 171 return pt; 172 } 173 174 // nsIAnonymousContentCreator 175 nsresult CreateAnonymousContent(nsTArray<ContentInfo>&) final; 176 void AppendAnonymousContentTo(nsTArray<nsIContent*>&, uint32_t aFilter) final; 177 178 /** 179 * Get the frame for the content that we are scrolling within 180 * this scrollable frame. 181 */ 182 nsIFrame* GetScrolledFrame() const { return mScrolledFrame; } 183 184 /** 185 * Get the overflow styles (StyleOverflow::Scroll, StyleOverflow::Hidden, or 186 * StyleOverflow::Auto) governing the horizontal and vertical scrollbars for 187 * this frame. 188 * 189 * This is special because they can be propagated from the <body> element, 190 * unlike other styles. 191 */ 192 ScrollStyles GetScrollStyles() const; 193 194 /** 195 * Returns whether we already have anonymous content nodes for all our needed 196 * scrollbar parts (or a superset thereof). 197 */ 198 bool HasAllNeededScrollbars() const { 199 return GetCurrentAnonymousContent().contains(GetNeededAnonymousContent()); 200 } 201 202 struct PerAxisScrollDirections { 203 bool mToRight = false; 204 bool mToBottom = false; 205 }; 206 207 static PerAxisScrollDirections ComputePerAxisScrollDirections( 208 const nsIFrame* aScrolledFrame); 209 210 /** 211 * Get the overscroll-behavior styles. 212 */ 213 layers::OverscrollBehaviorInfo GetOverscrollBehaviorInfo() const; 214 215 /** 216 * Return the scrollbars which are visible. It's OK to call this during reflow 217 * of the scrolled contents, in which case it will reflect the current 218 * assumptions about scrollbar visibility. 219 */ 220 layers::ScrollDirections GetScrollbarVisibility() const { 221 layers::ScrollDirections result; 222 if (mHasHorizontalScrollbar) { 223 result += layers::ScrollDirection::eHorizontal; 224 } 225 if (mHasVerticalScrollbar) { 226 result += layers::ScrollDirection::eVertical; 227 } 228 return result; 229 } 230 231 /** 232 * Returns the directions in which scrolling is allowed (if the scroll range 233 * is at least one device pixel in that direction). 234 */ 235 layers::ScrollDirections GetAvailableScrollingDirections() const; 236 237 /** 238 * Returns the directions in which scrolling is allowed when taking into 239 * account the visual viewport size and overflow hidden. (An (apz) zoomed in 240 * overflow hidden scrollframe is actually user scrollable.) 241 */ 242 layers::ScrollDirections GetAvailableScrollingDirectionsForUserInputEvents() 243 const; 244 245 /** 246 * Return the actual sizes of all possible scrollbars. Returns 0 for scrollbar 247 * positions that don't have a scrollbar or where the scrollbar is not 248 * visible. Do not call this while this frame's descendants are being 249 * reflowed, it won't be accurate. 250 * INCLUDE_VISUAL_VIEWPORT_SCROLLBARS means we include the size of layout 251 * scrollbars that are only visible to scroll the visual viewport inside the 252 * layout viewport (ie the layout viewport cannot be scrolled) even though 253 * there is no layout space set aside for these scrollbars. 254 */ 255 enum class ScrollbarSizesOptions { NONE, INCLUDE_VISUAL_VIEWPORT_SCROLLBARS }; 256 nsMargin GetActualScrollbarSizes( 257 ScrollbarSizesOptions aOptions = ScrollbarSizesOptions::NONE) const; 258 259 /** 260 * Return the sizes of all scrollbars assuming that any scrollbars that could 261 * be visible due to overflowing content, are. This can be called during 262 * reflow of the scrolled contents. 263 */ 264 nsMargin GetDesiredScrollbarSizes() const; 265 266 /** 267 * Get the layout size of this frame. 268 * Note that this is a value which is not expanded by the minimum scale size. 269 * For scroll frames other than the root content document's scroll frame, this 270 * value will be the same as GetScrollPortRect().Size(). 271 * 272 * This value is used for Element.clientWidth and clientHeight. 273 */ 274 nsSize GetLayoutSize() const { 275 if (mIsUsingMinimumScaleSize) { 276 return mICBSize; 277 } 278 return mScrollPort.Size(); 279 } 280 281 /** 282 * Get the size used for window.innerWidth or innerHeight. 283 * This works only for the root scroll container. 284 */ 285 nsSize GetSizeForWindowInnerSize() const; 286 287 /** 288 * GetScrolledRect is designed to encapsulate deciding which 289 * directions of overflow should be reachable by scrolling and which 290 * should not. Callers should NOT depend on it having any particular 291 * behavior. 292 * 293 * This should only be called when the scrolled frame has been 294 * reflowed with the scroll port size given in mScrollPort. 295 * 296 * Currently it allows scrolling down and to the right for 297 * ScrollContainerFrames with LTR directionality, and allows scrolling down 298 * and to the left for ScrollContainerFrames with RTL directionality. 299 */ 300 nsRect GetScrolledRect() const; 301 302 /** 303 * Get the area of the scrollport relative to the origin of this frame's 304 * border-box. 305 * This is the area of this frame minus border and scrollbars. 306 */ 307 nsRect GetScrollPortRect() const { return mScrollPort; } 308 nsRect GetScrollPortRectAccountingForDynamicToolbar() const { 309 auto rect = mScrollPort; 310 if (mIsRoot) { 311 rect.height += PresContext()->GetBimodalDynamicToolbarHeightInAppUnits(); 312 } 313 return rect; 314 } 315 nsRect GetScrollPortRectAccountingForMaxDynamicToolbar() const; 316 317 nsSize GetScrolledFrameSizeAccountingForDynamicToolbar() const { 318 auto size = mScrolledFrame->GetContentRectRelativeToSelf().Size(); 319 if (mIsRoot) { 320 size.height += PresContext()->GetBimodalDynamicToolbarHeightInAppUnits(); 321 } 322 return size; 323 } 324 325 /** 326 * Get the offset of the scrollport origin relative to the scrolled 327 * frame origin. Typically the position will be non-negative. 328 * This will always be a multiple of device pixels. 329 */ 330 nsPoint GetScrollPosition() const { 331 return mScrollPort.TopLeft() - mScrolledFrame->GetPosition(); 332 } 333 334 /** 335 * For LTR frames, the logical scroll position is the offset of the top left 336 * corner of the frame from the top left corner of the scroll port (same as 337 * GetScrollPosition). 338 * For RTL frames, it is the offset of the top right corner of the frame from 339 * the top right corner of the scroll port. 340 */ 341 nsPoint GetLogicalScrollPosition() const { 342 nsPoint pt; 343 pt.x = IsPhysicalLTR() 344 ? mScrollPort.x - mScrolledFrame->GetPosition().x 345 : mScrollPort.XMost() - mScrolledFrame->GetRect().XMost(); 346 pt.y = mScrollPort.y - mScrolledFrame->GetPosition().y; 347 return pt; 348 } 349 350 /** 351 * Get the area that must contain the scroll position. Typically 352 * (but not always, e.g. for RTL content) x and y will be 0, and 353 * width or height will be nonzero if the content can be scrolled in 354 * that direction. Since scroll positions must be a multiple of 355 * device pixels, the range extrema will also be a multiple of 356 * device pixels. 357 */ 358 nsRect GetScrollRange() const { return GetLayoutScrollRange(); } 359 360 /** 361 * Get the size of the view port to use when clamping the scroll 362 * position. 363 */ 364 nsSize GetVisualViewportSize() const; 365 366 /** 367 * Returns the offset of the visual viewport relative to 368 * the origin of the scrolled content. Note that only the RCD-RSF 369 * has a distinct visual viewport; for other scroll frames, the 370 * visual viewport always coincides with the layout viewport, and 371 * consequently the offset this function returns is equal to 372 * GetScrollPosition(). 373 */ 374 nsPoint GetVisualViewportOffset() const; 375 376 /** 377 * Set the visual viewport offset associated with a root scroll frame. This is 378 * only valid when called on a root scroll frame and will assert otherwise. 379 * aRepaint indicates if we need to ask for a main thread paint if this 380 * changes scrollbar positions or not. For example, if the compositor has 381 * already put the scrollbars at this position then they don't need to move so 382 * we can skip the repaint. Returns true if the offset changed and the scroll 383 * frame is still alive after this call. 384 */ 385 bool SetVisualViewportOffset(const nsPoint& aOffset, bool aRepaint); 386 /** 387 * Get the area that must contain the visual viewport offset. 388 */ 389 nsRect GetVisualScrollRange() const; 390 391 /** 392 * Like GetVisualScrollRange but also takes into account overflow: hidden. 393 */ 394 nsRect GetScrollRangeForUserInputEvents() const; 395 396 /** 397 * Return how much we would try to scroll by in each direction if 398 * asked to scroll by one "line" vertically and horizontally. 399 */ 400 nsSize GetLineScrollAmount() const; 401 /** 402 * Return how much we would try to scroll by in each direction if 403 * asked to scroll by one "page" vertically and horizontally. 404 */ 405 nsSize GetPageScrollAmount() const; 406 407 /** 408 * Return scroll-padding value of this frame. 409 */ 410 nsMargin GetScrollPadding() const; 411 412 /** 413 * @note This method might destroy the frame, pres shell and other objects. 414 * Clamps aScrollPosition to GetScrollRange and sets the scroll position 415 * to that value. 416 * @param aRange If non-null, specifies area which contains aScrollPosition 417 * and can be used for choosing a performance-optimized scroll position. 418 * Any point within this area can be chosen. 419 * The choosen point will be as close as possible to aScrollPosition. 420 */ 421 void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode, 422 const nsRect* aRange = nullptr, 423 ScrollSnapFlags aSnapFlags = ScrollSnapFlags::Disabled, 424 ScrollTriggeredByScript aTriggeredByScript = 425 ScrollTriggeredByScript::No) { 426 return ScrollToInternal(aScrollPosition, aMode, ScrollOrigin::Other, aRange, 427 aSnapFlags, aTriggeredByScript); 428 } 429 430 /** 431 * @note This method might destroy the frame, pres shell and other objects. 432 * Scrolls to a particular position in integer CSS pixels. 433 * Keeps the exact current horizontal or vertical position if the current 434 * position, rounded to CSS pixels, matches aScrollPosition. If 435 * aScrollPosition.x/y is different from the current CSS pixel position, 436 * makes sure we only move in the direction given by the difference. 437 * 438 * When aMode is SMOOTH, INSTANT, or NORMAL, GetRoundedScrollPositionCSSPixels 439 * (the scroll position after rounding to CSS pixels) will be exactly 440 * aScrollPosition at the end of the scroll animation. 441 * 442 * When aMode is SMOOTH_MSD, intermediate animation frames may be outside the 443 * range and / or moving in any direction; GetRoundedScrollPositionCSSPixels 444 * will be exactly aScrollPosition at the end of the scroll animation unless 445 * the SMOOTH_MSD animation is interrupted. 446 */ 447 void ScrollToCSSPixels(const CSSPoint& aScrollPosition, 448 ScrollMode aMode = ScrollMode::Instant); 449 450 /** 451 * @note This method might destroy the frame, pres shell and other objects. 452 * Scrolls to a particular position in float CSS pixels. 453 * This does not guarantee that GetRoundedScrollPositionCSSPixels equals 454 * aScrollPosition afterward. It tries to scroll as close to 455 * aScrollPosition as possible while scrolling by an integer 456 * number of layer pixels (so the operation is fast and looks clean). 457 */ 458 void ScrollToCSSPixelsForApz(const CSSPoint& aScrollPosition, 459 ScrollSnapTargetIds&& aLastSnapTargetIds); 460 461 /** 462 * Returns the scroll position in integer CSS pixels, rounded to the nearest 463 * pixel. 464 */ 465 CSSIntPoint GetRoundedScrollPositionCSSPixels(); 466 467 /** 468 * Returns the scroll position in CSS pixels. 469 */ 470 CSSPoint GetScrollPositionCSSPixels() const { 471 return CSSPoint::FromAppUnits(GetScrollPosition()); 472 } 473 474 /** 475 * Some platforms (OSX) may generate additional scrolling events even 476 * after the user has stopped scrolling, simulating a momentum scrolling 477 * effect resulting from fling gestures. 478 * SYNTHESIZED_MOMENTUM_EVENT indicates that the scrolling is being requested 479 * by such a synthesized event and may be ignored if another scroll has 480 * been started since the last actual user input. 481 */ 482 enum ScrollMomentum { NOT_MOMENTUM, SYNTHESIZED_MOMENTUM_EVENT }; 483 484 /** 485 * @note This method might destroy the frame, pres shell and other objects. 486 * Modifies the current scroll position by aDelta units given by aUnit, 487 * clamping it to GetScrollRange. If WHOLE is specified as the unit, 488 * content is scrolled all the way in the direction(s) given by aDelta. 489 * @param aOverflow if non-null, returns the amount that scrolling 490 * was clamped by in each direction (how far we moved the scroll position 491 * to bring it back into the legal range). This is never negative. The 492 * values are in device pixels. 493 */ 494 void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode, 495 nsIntPoint* aOverflow = nullptr, 496 ScrollOrigin aOrigin = ScrollOrigin::NotSpecified, 497 ScrollMomentum aMomentum = NOT_MOMENTUM, 498 ScrollSnapFlags aSnapFlags = ScrollSnapFlags::Disabled); 499 500 void ScrollByCSSPixels(const CSSPoint& aDelta, 501 ScrollMode aMode = ScrollMode::Instant) { 502 return ScrollByCSSPixelsInternal(aDelta, aMode); 503 } 504 505 /** 506 * Perform scroll snapping, possibly resulting in a smooth scroll to 507 * maintain the scroll snap position constraints. Velocity sampled from 508 * main thread scrolling is used to determine best matching snap point 509 * when called after a fling gesture on a trackpad or mouse wheel. 510 */ 511 void ScrollSnap() { return ScrollSnap(ScrollMode::SmoothMsd); } 512 513 /** 514 * @note This method might destroy the frame, pres shell and other objects. 515 * This tells the scroll frame to try scrolling to the scroll 516 * position that was restored from the history. This must be called 517 * at least once after state has been restored. It is called by the 518 * scrolled frame itself during reflow, but sometimes state can be 519 * restored after reflows are done... 520 * XXX should we take an aMode parameter here? Currently it's instant. 521 */ 522 void ScrollToRestoredPosition(); 523 524 bool NeedRestorePosition() const { 525 return mRestorePos.y != -1 && mLastPos.x != -1 && mLastPos.y != -1; 526 } 527 528 /** 529 * @note This method might destroy the frame, pres shell and other objects. 530 * Internal method used by scrollbars to notify their scrolling 531 * container of changes. 532 */ 533 void ScrollbarCurPosChanged(bool aDoScroll = true); 534 535 /** 536 * Allows the docshell to request that the scroll frame post an event 537 * after being restored from history. 538 */ 539 NS_IMETHOD PostScrolledAreaEventForCurrentArea() final { 540 PostScrolledAreaEvent(); 541 return NS_OK; 542 } 543 544 /** 545 * Returns true if this scrollframe is being "actively scrolled". 546 * This basically means that we should allocate resources in the 547 * expectation that scrolling is going to happen. 548 */ 549 bool IsScrollingActive() const; 550 551 /** 552 * Returns true if this scroll frame might be scrolled 553 * asynchronously by the compositor. 554 */ 555 bool IsMaybeAsynchronouslyScrolled() const { 556 // If this is true, then we'll build an ASR, and that's what we want 557 // to know I think. 558 return mWillBuildScrollableLayer; 559 } 560 561 /** 562 * Was the current presentation state for this frame restored from history? 563 */ 564 bool DidHistoryRestore() const { return mDidHistoryRestore; } 565 566 /** 567 * Clear the flag so that DidHistoryRestore() returns false until the next 568 * RestoreState call. 569 * @see nsIStatefulFrame::RestoreState 570 */ 571 void ClearDidHistoryRestore() { mDidHistoryRestore = false; } 572 573 /** 574 * Mark the frame as having been scrolled at least once, so that it remains 575 * active and we can also start storing its scroll position when saving state. 576 */ 577 void MarkEverScrolled(); 578 579 /** 580 * Determine if the passed in rect is nearly visible according to the frame 581 * visibility heuristics for how close it is to the visible scrollport. 582 */ 583 bool IsRectNearlyVisible(const nsRect& aRect) const; 584 585 /** 586 * Expand the given rect taking into account which directions we can scroll 587 * and how far we want to expand for frame visibility purposes. 588 */ 589 nsRect ExpandRectToNearlyVisible(const nsRect& aRect) const; 590 591 /** 592 * Returns the origin that triggered the last instant scroll. Will equal 593 * ScrollOrigin::Apz when the compositor's replica frame metrics includes the 594 * latest instant scroll. 595 */ 596 ScrollOrigin LastScrollOrigin() const { return mLastScrollOrigin; } 597 598 /** 599 * Gets the async scroll animation state of this scroll frame. 600 * 601 * There are five possible kinds that can overlap. 602 * MainThread means async scroll animated by the main thread. 603 * APZ scroll animations that are requested from the main thread go through 604 * three states: 1) pending, when the main thread has recorded that it wants 605 * apz to do a scroll animation, 2) requested, when the main thread has sent 606 * the request to the compositor (but it hasn't necessarily arrived yet), and 607 * 3) in progress, after apz has responded to the main thread that it got the 608 * request. 609 * TriggeredByScript means that the async scroll animation was triggered by 610 * script, e.g. Element.scrollTo(). 611 */ 612 enum class AnimationState { 613 MainThread, // mAsyncScroll || mAsyncSmoothMSDScroll 614 APZPending, // mScrollUpdates.LastElement() is Smooth or SmoothMsd 615 APZRequested, // mApzAnimationRequested 616 APZInProgress, // mCurrentAPZScrollAnimationType != 617 // APZScrollAniationType::No 618 TriggeredByScript // The animation was triggered with 619 // ScrollTriggeredByScript::Yes 620 }; 621 EnumSet<AnimationState> ScrollAnimationState() const; 622 623 /** 624 * Returns the current generation counter for the scrollframe. This counter 625 * increments every time the scroll position is set. 626 */ 627 MainThreadScrollGeneration CurrentScrollGeneration() const { 628 return mScrollGeneration; 629 } 630 631 /** 632 * The APZ scroll generation associated with the last APZ scroll offset for 633 * which we processed a repaint request. 634 */ 635 APZScrollGeneration ScrollGenerationOnApz() const { 636 return mScrollGenerationOnApz; 637 } 638 639 /** 640 * LastScrollDestination returns the destination of the most recently 641 * requested smooth scroll animation. 642 */ 643 nsPoint LastScrollDestination() { return mDestination; } 644 645 /** 646 * Returns the list of scroll position updates since the last call to 647 * NotifyApzTransaction(). 648 */ 649 nsTArray<ScrollPositionUpdate> GetScrollUpdates() const; 650 651 /** 652 * Returns true if the scroll frame has any scroll position updates since 653 * the last call to NotifyApzTransaction(). 654 */ 655 bool HasScrollUpdates() const { return !mScrollUpdates.IsEmpty(); } 656 657 /** 658 * Clears the "origin of last scroll" property stored in this frame, if 659 * the generation counter passed in matches the current scroll generation 660 * counter, and clears the "origin of last smooth scroll" property if the 661 * generation counter matches. It also resets whether there's an ongoing apz 662 * animation. 663 */ 664 enum class InScrollingGesture : bool { No, Yes }; 665 void ResetScrollInfoIfNeeded(const MainThreadScrollGeneration& aGeneration, 666 const APZScrollGeneration& aGenerationOnApz, 667 APZScrollAnimationType aAPZScrollAnimationType, 668 InScrollingGesture aInScrollingGesture); 669 670 /** 671 * Determine whether it is desirable to be able to asynchronously scroll this 672 * scroll frame. 673 */ 674 bool WantAsyncScroll() const; 675 676 /** 677 * Returns the ScrollMetadata contributed by this frame, if there is one. 678 */ 679 Maybe<layers::ScrollMetadata> ComputeScrollMetadata( 680 layers::WebRenderLayerManager* aLayerManager, const nsIFrame* aItemFrame, 681 const nsPoint& aOffsetToReferenceFrame) const; 682 683 /** 684 * Mark the scrollbar frames for reflow. 685 */ 686 void MarkScrollbarsDirtyForReflow() const; 687 688 /** 689 * Invalidate the scrollbar after the marks have been changed. 690 */ 691 void InvalidateScrollbars() const; 692 693 /** 694 * @note This method might destroy the frame, pres shell and other objects. 695 * Update scrollbar to reflect current scroll position 696 */ 697 void UpdateScrollbarPosition(); 698 699 void SetTransformingByAPZ(bool aTransforming); 700 bool IsTransformingByAPZ() const { return mTransformingByAPZ; } 701 702 /** 703 * Notify this scroll frame that it can be scrolled by APZ. In particular, 704 * this is called *after* the APZ code has created an APZC for this scroll 705 * frame and verified that it is not a scrollinfo layer. Therefore, setting an 706 * async transform on it is actually user visible. 707 */ 708 void SetScrollableByAPZ(bool aScrollable); 709 710 /** 711 * Notify this scroll frame that it can be zoomed by APZ. 712 */ 713 void SetZoomableByAPZ(bool aZoomable); 714 715 /** 716 * Mark this scroll frame as having out-of-flow content inside a CSS filter. 717 * Such content will move incorrectly during async-scrolling; to mitigate 718 * this, paint skipping is disabled for such scroll frames. 719 */ 720 void SetHasOutOfFlowContentInsideFilter(); 721 722 /** 723 * Determine if we should build a scrollable layer for this scroll frame and 724 * return the result. It will also record this result on the scroll frame. 725 * Pass the visible rect in aVisibleRect. On return it will be set to the 726 * displayport if there is one. 727 * Pass the dirty rect in aDirtyRect. On return it will be set to the 728 * dirty rect inside the displayport (ie the dirty rect that should be used). 729 * This function will set the display port base rect if aSetBase is true. 730 * aSetBase is only allowed to be false if there has been a call with it 731 * set to true before on the same paint. 732 */ 733 bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder, 734 nsRect* aVisibleRect, nsRect* aDirtyRect, 735 bool aSetBase) { 736 return DecideScrollableLayer(aBuilder, aVisibleRect, aDirtyRect, aSetBase, 737 nullptr); 738 } 739 740 /** 741 * Like DecideScrollableLayer but skips computing dirty/visible rects and 742 * setting the base rect. In addition, this always ensures a display port is 743 * set if this scroll frame could async scroll. DecideScrollableLayer only 744 * sets a display port in that situation if ShouldActivateAllScrollFrames 745 * returns true. However you should only call this function is 746 * ShouldActivateAllScrollFrames returns true anyways. 747 * */ 748 bool DecideScrollableLayerEnsureDisplayport(nsDisplayListBuilder* aBuilder); 749 750 /** 751 * Notify the scrollframe that the current scroll offset and origin have been 752 * sent over in a layers transaction. 753 * 754 * This sets a flag on the scrollframe that indicates subsequent changes 755 * to the scroll position by "weaker" origins are permitted to overwrite the 756 * the scroll origin. Scroll origins that 757 * nsLayoutUtils::CanScrollOriginClobberApz returns false for are considered 758 * "weaker" than scroll origins for which that function returns true. 759 * 760 * This function must be called for a scrollframe after all calls to 761 * ComputeScrollMetadata in a layers transaction have been completed. 762 * 763 */ 764 void NotifyApzTransaction(); 765 766 /** 767 * Notification that this scroll frame is getting its frame visibility 768 * updated. aIgnoreDisplayPort indicates that the display port was ignored 769 * (because there was no suitable base rect) 770 */ 771 void NotifyApproximateFrameVisibilityUpdate(bool aIgnoreDisplayPort); 772 773 /** 774 * Returns true if this scroll frame had a display port at the last frame 775 * visibility update and fills in aDisplayPort with that displayport. Returns 776 * false otherwise, and doesn't touch aDisplayPort. 777 */ 778 bool GetDisplayPortAtLastApproximateFrameVisibilityUpdate( 779 nsRect* aDisplayPort); 780 781 /** 782 * This is called when a descendant scrollframe's has its displayport expired. 783 * This function will check to see if this scrollframe may safely expire its 784 * own displayport and schedule a timer to do that if it is safe. 785 */ 786 void TriggerDisplayPortExpiration(); 787 788 /** 789 * Returns information required to determine where to snap to after a scroll. 790 */ 791 ScrollSnapInfo GetScrollSnapInfo(); 792 793 void TryResnap(); 794 795 /** 796 * Post a pending re-snap request if the given |aFrame| is one of the snap 797 * points on the last scroll operation. 798 */ 799 void PostPendingResnapIfNeeded(const nsIFrame* aFrame); 800 void PostPendingResnap(); 801 802 /** 803 * Returns a pair of the scroll-snap-align property value both on X and Y axes 804 * for the given |aFrame| considering the scroll-snap-type of this scroll 805 * container. For example, if the scroll-snap-type is `none`, the pair of 806 * scroll-snap-align is also `none none`. 807 */ 808 using PhysicalScrollSnapAlign = 809 std::pair<StyleScrollSnapAlignKeyword, StyleScrollSnapAlignKeyword>; 810 PhysicalScrollSnapAlign GetScrollSnapAlignFor(const nsIFrame* aFrame) const; 811 812 /** 813 * Given the drag event aEvent, determine whether the mouse is near the edge 814 * of the scrollable area, and scroll the view in the direction of that edge 815 * if so. If scrolling occurred, true is returned. When false is returned, the 816 * caller should look for an ancestor to scroll. 817 */ 818 bool DragScroll(WidgetEvent* aEvent); 819 820 void AsyncScrollbarDragInitiated(uint64_t aDragBlockId, 821 layers::ScrollDirection aDirection); 822 void AsyncScrollbarDragRejected(); 823 824 /** 825 * Returns whether this scroll frame is the root scroll frame of the document 826 * that it is in. Note that some documents don't have root scroll frames at 827 * all (ie XUL documents) even though they may contain other scroll frames. 828 */ 829 bool IsRootScrollFrameOfDocument() const { return mIsRoot; } 830 831 /** 832 * Returns the paint sequence number if this scroll frame was the first 833 * scrollable frame for the paint. 834 */ 835 Maybe<uint32_t> IsFirstScrollableFrameSequenceNumber() const { 836 return mIsFirstScrollableFrameSequenceNumber; 837 } 838 839 /** 840 * Set the paint sequence number for the paint in which this was the first 841 * scrollable frame that was encountered. 842 */ 843 void SetIsFirstScrollableFrameSequenceNumber(Maybe<uint32_t> aValue) { 844 mIsFirstScrollableFrameSequenceNumber = aValue; 845 } 846 847 /** 848 * Returns the scroll anchor associated with this scrollable frame. This is 849 * never null. 850 */ 851 const ScrollAnchorContainer* Anchor() const { return &mAnchor; } 852 ScrollAnchorContainer* Anchor() { return &mAnchor; } 853 854 bool SmoothScrollVisual( 855 const nsPoint& aVisualViewportOffset, 856 layers::FrameMetrics::ScrollOffsetUpdateType aUpdateType, 857 ScrollMode aMode); 858 859 /** 860 * Returns true if this scroll frame should perform smooth scroll with the 861 * given |aBehavior|. 862 */ 863 bool IsSmoothScroll( 864 dom::ScrollBehavior aBehavior = dom::ScrollBehavior::Auto) const; 865 866 /** 867 * Returns the ScrollMode that this scroll frame should use for a 868 * programmatic scroll governed by CSSOM-View `scroll-behavior`. 869 * This includes most programmatic scrolls but not scroll snapping. 870 */ 871 ScrollMode ScrollModeForScrollBehavior( 872 dom::ScrollBehavior aBehavior = dom::ScrollBehavior::Auto) const; 873 874 static nscoord GetNonOverlayScrollbarSize(const nsPresContext*, 875 StyleScrollbarWidth); 876 877 void ScrollByCSSPixelsInternal( 878 const CSSPoint& aDelta, ScrollMode aMode = ScrollMode::Instant, 879 // This ScrollByCSSPixels is mainly used for Element.scrollBy and 880 // Window.scrollBy. An exception is the transmogrification of 881 // ScrollToCSSPixels. 882 ScrollSnapFlags aSnapFlags = ScrollSnapFlags::IntendedDirection | 883 ScrollSnapFlags::IntendedEndPosition); 884 885 // nsIReflowCallback 886 bool ReflowFinished() override; 887 void ReflowCallbackCanceled() final; 888 889 // nsIStatefulFrame 890 UniquePtr<PresState> SaveState() final; 891 NS_IMETHOD RestoreState(PresState* aState) final; 892 893 // nsIScrollbarMediator 894 void ScrollByPage( 895 nsScrollbarFrame* aScrollbar, int32_t aDirection, 896 ScrollSnapFlags aSnapFlags = ScrollSnapFlags::Disabled) final; 897 void ScrollByWhole( 898 nsScrollbarFrame* aScrollbar, int32_t aDirection, 899 ScrollSnapFlags aSnapFlags = ScrollSnapFlags::Disabled) final; 900 void ScrollByLine(nsScrollbarFrame* aScrollbar, int32_t aDirection, 901 ScrollSnapFlags = ScrollSnapFlags::Disabled) final; 902 void ScrollByUnit(nsScrollbarFrame* aScrollbar, ScrollMode aMode, 903 int32_t aDirection, ScrollUnit aUnit, 904 ScrollSnapFlags = ScrollSnapFlags::Disabled) final; 905 void RepeatButtonScroll(nsScrollbarFrame* aScrollbar) final; 906 void ThumbMoved(nsScrollbarFrame* aScrollbar, nscoord aOldPos, 907 nscoord aNewPos) final; 908 void ScrollbarReleased(nsScrollbarFrame* aScrollbar) final; 909 void VisibilityChanged(bool aVisible) final {} 910 nsScrollbarFrame* GetScrollbarBox(bool aVertical) final { 911 return aVertical ? mVScrollbarBox : mHScrollbarBox; 912 } 913 void ScrollbarActivityStarted() const final; 914 void ScrollbarActivityStopped() const final; 915 bool IsScrollbarOnRight() const final; 916 bool ShouldSuppressScrollbarRepaints() const final { 917 return mSuppressScrollbarRepaints; 918 } 919 920 // Return the scrolled frame. 921 void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) final { 922 aResult.AppendElement(OwnedAnonBox(GetScrolledFrame())); 923 } 924 925 #ifdef DEBUG_FRAME_DUMP 926 nsresult GetFrameName(nsAString& aResult) const override; 927 #endif 928 929 #ifdef ACCESSIBILITY 930 a11y::AccType AccessibleType() override; 931 #endif 932 933 static void AsyncScrollCallback(ScrollContainerFrame* aInstance, 934 TimeStamp aTime); 935 static void AsyncSmoothMSDScrollCallback(ScrollContainerFrame* aInstance, 936 TimeDuration aDeltaTime); 937 /** 938 * @note This method might destroy the frame, pres shell and other objects. 939 * aRange is the range of allowable scroll positions around the desired 940 * aScrollPosition. Null means only aScrollPosition is allowed. 941 * This is a closed-ended range --- aRange.XMost()/aRange.YMost() are allowed. 942 */ 943 void ScrollToInternal( 944 nsPoint aScrollPosition, ScrollMode aMode, 945 ScrollOrigin aOrigin = ScrollOrigin::NotSpecified, 946 const nsRect* aRange = nullptr, 947 ScrollSnapFlags aSnapFlags = ScrollSnapFlags::Disabled, 948 ScrollTriggeredByScript aTriggeredByScript = ScrollTriggeredByScript::No); 949 /** 950 * @note This method might destroy the frame, pres shell and other objects. 951 */ 952 void ScrollToImpl( 953 nsPoint aPt, const nsRect& aRange, 954 ScrollOrigin aOrigin = ScrollOrigin::NotSpecified, 955 ScrollTriggeredByScript aTriggeredByScript = ScrollTriggeredByScript::No); 956 void ScrollVisual(); 957 958 enum class LoadingState { Loading, Stopped, Loaded }; 959 960 LoadingState GetPageLoadingState(); 961 962 /** 963 * GetSnapPointForDestination determines which point to snap to after 964 * scrolling. aStartPos gives the position before scrolling and aDestination 965 * gives the position after scrolling, with no snapping. Behaviour is 966 * dependent on the value of aUnit. 967 * Returns true if a suitable snap point could be found and aDestination has 968 * been updated to a valid snapping position. 969 */ 970 Maybe<SnapDestination> GetSnapPointForDestination( 971 ScrollUnit aUnit, ScrollSnapFlags aFlags, const nsPoint& aStartPos, 972 const nsPoint& aDestination); 973 974 Maybe<SnapDestination> GetSnapPointForResnap(); 975 bool NeedsResnap(); 976 977 void SetLastSnapTargetIds(UniquePtr<ScrollSnapTargetIds> aId); 978 979 static void SetScrollbarVisibility(nsIFrame* aScrollbar, bool aVisible); 980 981 /** 982 * GetUnsnappedScrolledRectInternal is designed to encapsulate deciding which 983 * directions of overflow should be reachable by scrolling and which 984 * should not. Callers should NOT depend on it having any particular 985 * behavior. 986 * 987 * Currently it allows scrolling down and to the right for 988 * ScrollContainerFrames with LTR directionality, and allows scrolling down 989 * and to the left for ScrollContainerFrames with RTL directionality. 990 */ 991 nsRect GetUnsnappedScrolledRectInternal(const nsRect& aScrolledOverflowArea, 992 const nsSize& aScrollPortSize) const; 993 994 bool IsPhysicalLTR() const { return GetWritingMode().IsPhysicalLTR(); } 995 bool IsBidiLTR() const { return GetWritingMode().IsBidiLTR(); } 996 997 bool IsAlwaysActive() const; 998 void MarkRecentlyScrolled(); 999 void MarkNotRecentlyScrolled(); 1000 nsExpirationState* GetExpirationState() { return &mActivityExpirationState; } 1001 1002 bool UsesOverlayScrollbars() const; 1003 bool IsLastSnappedTarget(const nsIFrame* aFrame) const; 1004 1005 // If aBuilder is non-null, returns the value cached on aBuilder. Pass null 1006 // for aBuilder to get the correct value to cache on a new builder or new 1007 // frame of painting, or if you need the correct value outside of paint time. 1008 static bool ShouldActivateAllScrollFrames(nsDisplayListBuilder* aBuilder, 1009 nsIFrame* aFrame); 1010 nsRect RestrictToRootDisplayPort(const nsRect& aDisplayportBase); 1011 bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder, 1012 nsRect* aVisibleRect, nsRect* aDirtyRect, 1013 bool aSetBase, bool* aDirtyRectHasBeenOverriden); 1014 bool AllowDisplayPortExpiration(); 1015 void ResetDisplayPortExpiryTimer(); 1016 1017 void ScheduleSyntheticMouseMove(); 1018 static void ScrollActivityCallback(nsITimer* aTimer, void* anInstance); 1019 1020 void HandleScrollbarStyleSwitching(); 1021 1022 bool IsApzAnimationInProgress() const { 1023 return mCurrentAPZScrollAnimationType != APZScrollAnimationType::No; 1024 } 1025 nsPoint LastScrollDestination() const { return mDestination; } 1026 1027 bool IsLastScrollUpdateAnimating() const; 1028 bool IsLastScrollUpdateTriggeredByScriptAnimating() const; 1029 1030 // Update minimum-scale size. The minimum-scale size will be set/used only 1031 // if there is overflow-x:hidden region. 1032 void UpdateMinimumScaleSize(const nsRect& aScrollableOverflow, 1033 const nsSize& aICBSize); 1034 1035 // Return the scroll frame's "true outer size". 1036 // This is GetSize(), except when we've been sized to reflect a virtual 1037 // (layout) viewport in which case this returns the outer size used to size 1038 // the physical (visual) viewport. 1039 nsSize TrueOuterSize(nsDisplayListBuilder* aBuilder) const; 1040 1041 already_AddRefed<Element> MakeScrollbar(dom::NodeInfo* aNodeInfo, 1042 bool aVertical, 1043 AnonymousContentKey& aKey); 1044 1045 void AppendScrollUpdate(const ScrollPositionUpdate& aUpdate); 1046 1047 bool HasBeenScrolled() const { return mHasBeenScrolled; } 1048 1049 protected: 1050 ScrollContainerFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, 1051 bool aIsRoot) 1052 : ScrollContainerFrame(aStyle, aPresContext, kClassID, aIsRoot) {} 1053 ScrollContainerFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, 1054 nsIFrame::ClassID aID, bool aIsRoot); 1055 ~ScrollContainerFrame(); 1056 bool GuessHScrollbarNeeded(const ScrollReflowInput& aState); 1057 bool GuessVScrollbarNeeded(const ScrollReflowInput& aState); 1058 1059 // Return whether we're in an "initial" reflow. Some reflows with 1060 // NS_FRAME_FIRST_REFLOW set are NOT "initial" as far as we're concerned. 1061 bool InInitialReflow() const; 1062 1063 bool TryLayout(ScrollReflowInput& aState, ReflowOutput* aKidMetrics, 1064 bool aAssumeHScroll, bool aAssumeVScroll, bool aForce); 1065 1066 // Return true if ReflowScrolledFrame is going to do something different based 1067 // on the presence of a horizontal scrollbar in a horizontal writing mode or a 1068 // vertical scrollbar in a vertical writing mode. 1069 bool ScrolledContentDependsOnBSize(const ScrollReflowInput& aState) const; 1070 1071 void ReflowScrolledFrame(ScrollReflowInput& aState, bool aAssumeHScroll, 1072 bool aAssumeVScroll, ReflowOutput* aMetrics); 1073 void ReflowContents(ScrollReflowInput& aState, 1074 const ReflowOutput& aDesiredSize); 1075 void PlaceScrollArea(ScrollReflowInput& aState, 1076 const nsPoint& aScrollPosition); 1077 1078 void UpdateSticky(); 1079 void UpdatePrevScrolledRect(); 1080 1081 // adjust the scrollbar rectangle aRect to account for any visible resizer. 1082 // aHasResizer specifies if there is a content resizer, however this method 1083 // will also check if a widget resizer is present as well. 1084 void AdjustScrollbarRectForResizer(nsIFrame* aFrame, 1085 nsPresContext* aPresContext, nsRect& aRect, 1086 bool aHasResizer, 1087 layers::ScrollDirection aDirection); 1088 void LayoutScrollbars(ScrollReflowInput& aState, 1089 const nsRect& aInsideBorderArea, 1090 const nsRect& aOldScrollPort); 1091 1092 void LayoutScrollbarPartAtRect(const ScrollReflowInput&, 1093 ReflowInput& aKidReflowInput, const nsRect&); 1094 1095 /** 1096 * Override this to return false if computed bsize/min-bsize/max-bsize 1097 * should NOT be propagated to child content. 1098 * nsListControlFrame uses this. 1099 */ 1100 virtual bool ShouldPropagateComputedBSizeToScrolledContent() const { 1101 return true; 1102 } 1103 1104 PhysicalAxes GetOverflowAxes() const; 1105 1106 MOZ_CAN_RUN_SCRIPT nsresult FireScrollPortEvent(); 1107 void PostScrollEndEvent(); 1108 MOZ_CAN_RUN_SCRIPT void FireScrollEndEvent(); 1109 void PostOverflowEvent(); 1110 1111 // Add display items for the top-layer (which includes things like 1112 // the fullscreen element, its backdrop, and text selection carets) 1113 // to |aLists|. 1114 // This is a no-op for scroll frames other than the viewport's 1115 // root scroll frame. 1116 // This should be called with an nsDisplayListSet that will be 1117 // wrapped in the async zoom container, if we're building one. 1118 // It should not be called with an ASR setter on the stack, as the 1119 // top-layer items handle setting up their own ASRs. 1120 void MaybeCreateTopLayerAndWrapRootItems( 1121 nsDisplayListBuilder*, nsDisplayListCollection&, bool aCreateAsyncZoom, 1122 bool aCapturedByViewTransition, 1123 AutoContainsBlendModeCapturer* aAsyncZoomBlendCapture, 1124 const nsRect& aAsyncZoomClipRect, const nsRectCornerRadii* aRadii); 1125 1126 void AppendScrollPartsTo(nsDisplayListBuilder* aBuilder, 1127 const nsDisplayListSet& aLists, bool aCreateLayer, 1128 bool aPositioned); 1129 1130 void PostScrollEvent(); 1131 MOZ_CAN_RUN_SCRIPT void FireScrollEvent(); 1132 void PostScrolledAreaEvent(); 1133 MOZ_CAN_RUN_SCRIPT void FireScrolledAreaEvent(); 1134 1135 void FinishReflowForScrollbar(nsScrollbarFrame*, nscoord aMinXY, 1136 nscoord aMaxXY, nscoord aCurPosXY, 1137 nscoord aPageIncrement); 1138 void ActivityOccurred(); 1139 1140 nsRect GetLayoutScrollRange() const; 1141 // Get the scroll range assuming the viewport has size (aWidth, aHeight). 1142 nsRect GetScrollRange(nscoord aWidth, nscoord aHeight) const; 1143 1144 const nsRect& ScrollPort() const { return mScrollPort; } 1145 void SetScrollPort(const nsRect& aNewScrollPort) { 1146 if (!mScrollPort.IsEqualEdges(aNewScrollPort)) { 1147 mMayScheduleScrollAnimations = true; 1148 } 1149 mScrollPort = aNewScrollPort; 1150 } 1151 1152 /** 1153 * Return the 'optimal viewing region' as a rect suitable for use by 1154 * scroll anchoring. This rect is in the same coordinate space as 1155 * 'GetScrollPortRect', and accounts for 'scroll-padding' as defined by: 1156 * 1157 * https://drafts.csswg.org/css-scroll-snap-1/#optimal-viewing-region 1158 */ 1159 nsRect GetVisualOptimalViewingRect() const; 1160 1161 /** 1162 * For LTR frames, this is the same as GetVisualViewportOffset(). 1163 * For RTL frames, we take the offset from the top right corner of the frame 1164 * to the top right corner of the visual viewport. 1165 */ 1166 nsPoint GetLogicalVisualViewportOffset() const { 1167 nsPoint pt = GetVisualViewportOffset(); 1168 if (!IsPhysicalLTR()) { 1169 pt.x += GetVisualViewportSize().width - mScrolledFrame->GetRect().width; 1170 } 1171 return pt; 1172 } 1173 void ScrollSnap(ScrollMode aMode); 1174 void ScrollSnap(const nsPoint& aDestination, 1175 ScrollMode aMode = ScrollMode::SmoothMsd); 1176 1177 bool HasPendingScrollRestoration() const { 1178 return mRestorePos != nsPoint(-1, -1); 1179 } 1180 1181 bool IsProcessingScrollEvent() const { return mProcessingScrollEvent; } 1182 1183 class AutoScrollbarRepaintSuppression; 1184 friend class AutoScrollbarRepaintSuppression; 1185 class AutoScrollbarRepaintSuppression { 1186 public: 1187 AutoScrollbarRepaintSuppression(ScrollContainerFrame* aFrame, 1188 AutoWeakFrame& aWeakOuter, bool aSuppress) 1189 : mFrame(aFrame), 1190 mWeakOuter(aWeakOuter), 1191 mOldSuppressValue(aFrame->mSuppressScrollbarRepaints) { 1192 mFrame->mSuppressScrollbarRepaints = aSuppress; 1193 } 1194 1195 ~AutoScrollbarRepaintSuppression() { 1196 if (mWeakOuter.IsAlive()) { 1197 mFrame->mSuppressScrollbarRepaints = mOldSuppressValue; 1198 } 1199 } 1200 1201 private: 1202 ScrollContainerFrame* mFrame; 1203 AutoWeakFrame& mWeakOuter; 1204 bool mOldSuppressValue; 1205 }; 1206 1207 struct ScrollOperationParams { 1208 ScrollOperationParams(const ScrollOperationParams&) = delete; 1209 ScrollOperationParams(ScrollMode aMode, ScrollOrigin aOrigin) 1210 : mMode(aMode), mOrigin(aOrigin) {} 1211 ScrollOperationParams(ScrollMode aMode, ScrollOrigin aOrigin, 1212 ScrollSnapTargetIds&& aSnapTargetIds) 1213 : ScrollOperationParams(aMode, aOrigin) { 1214 mTargetIds = std::move(aSnapTargetIds); 1215 } 1216 ScrollOperationParams(ScrollMode aMode, ScrollOrigin aOrigin, 1217 ScrollSnapFlags aSnapFlags, 1218 ScrollTriggeredByScript aTriggeredByScript) 1219 : ScrollOperationParams(aMode, aOrigin) { 1220 mSnapFlags = aSnapFlags; 1221 mTriggeredByScript = aTriggeredByScript; 1222 } 1223 1224 ScrollMode mMode; 1225 ScrollOrigin mOrigin; 1226 ScrollSnapFlags mSnapFlags = ScrollSnapFlags::Disabled; 1227 ScrollTriggeredByScript mTriggeredByScript = ScrollTriggeredByScript::No; 1228 ScrollSnapTargetIds mTargetIds; 1229 1230 bool IsInstant() const { return mMode == ScrollMode::Instant; } 1231 bool IsSmoothMsd() const { return mMode == ScrollMode::SmoothMsd; } 1232 bool IsSmooth() const { return mMode == ScrollMode::Smooth; } 1233 bool IsScrollSnapDisabled() const { 1234 return mSnapFlags == ScrollSnapFlags::Disabled; 1235 } 1236 }; 1237 1238 /** 1239 * @note This method might destroy the frame, pres shell and other objects. 1240 * 1241 * A caller can ask this ScrollToWithOrigin() function to perform snapping by 1242 * passing in aParams.mSnapFlags != ScrollSnapFlags::Disabled. Alternatively, 1243 * a caller may want to do its own snapping, in which case it should pass 1244 * ScrollSnapFlags::Disabled and populate aParams.mTargetIds based on the 1245 * result of the snapping. 1246 */ 1247 void ScrollToWithOrigin(nsPoint aScrollPosition, const nsRect* aRange, 1248 ScrollOperationParams&& aParams); 1249 1250 void CompleteAsyncScroll(const nsPoint& aStartPosition, const nsRect& aRange, 1251 UniquePtr<ScrollSnapTargetIds> aSnapTargetIds, 1252 ScrollOrigin aOrigin = ScrollOrigin::NotSpecified); 1253 1254 bool HasPerspective() const { return ChildrenHavePerspective(); } 1255 bool HasBgAttachmentLocal() const; 1256 StyleDirection GetScrolledFrameDir() const; 1257 static StyleDirection GetScrolledFrameDir(const nsIFrame*); 1258 1259 // Ask APZ to smooth scroll to |aDestination|. 1260 // This method does not clamp the destination; callers should clamp it to 1261 // either the layout or the visual scroll range (APZ will happily smooth 1262 // scroll to either). 1263 void ApzSmoothScrollTo(const nsPoint& aDestination, ScrollMode, ScrollOrigin, 1264 ScrollTriggeredByScript, 1265 UniquePtr<ScrollSnapTargetIds> aSnapTargetIds, 1266 ViewportType aViewportToScroll); 1267 1268 // Check whether APZ can scroll in the provided directions, keeping in mind 1269 // that APZ currently cannot scroll along axes which are overflow:hidden. 1270 bool CanApzScrollInTheseDirections(layers::ScrollDirections aDirections); 1271 1272 // Removes any RefreshDriver observers we might have registered. 1273 void RemoveObservers(); 1274 1275 private: 1276 class AsyncScroll; 1277 class AsyncSmoothMSDScroll; 1278 class AutoMinimumScaleSizeChangeDetector; 1279 1280 enum class AnonymousContentType { 1281 VerticalScrollbar, 1282 HorizontalScrollbar, 1283 Resizer, 1284 }; 1285 EnumSet<AnonymousContentType> GetNeededAnonymousContent() const; 1286 EnumSet<AnonymousContentType> GetCurrentAnonymousContent() const; 1287 1288 // If a child frame was added or removed on the scrollframe, 1289 // reload our child frame list. 1290 // We need this if a scrollbar frame is recreated. 1291 void ReloadChildFrames(); 1292 1293 // NOTE: Use GetScrollStyles() if you want `overflow` property info. 1294 nsIFrame* GetFrameForStyle() const; 1295 1296 // Compute all scroll snap related information and store eash snap target 1297 // element in |mSnapTargets|. 1298 ScrollSnapInfo ComputeScrollSnapInfo(); 1299 1300 bool NeedsScrollSnap() const; 1301 1302 // Returns the snapport size of this scroll container. 1303 // https://drafts.csswg.org/css-scroll-snap/#scroll-snapport 1304 nsSize GetSnapportSize() const; 1305 1306 // Schedule the scroll-driven animations. 1307 void ScheduleScrollAnimations(); 1308 void TryScheduleScrollAnimations() { 1309 if (!mMayScheduleScrollAnimations) { 1310 return; 1311 } 1312 ScheduleScrollAnimations(); 1313 mMayScheduleScrollAnimations = false; 1314 } 1315 1316 static void RemoveDisplayPortCallback(nsITimer* aTimer, void* aClosure); 1317 1318 // owning references to the nsIAnonymousContentCreator-built content 1319 nsCOMPtr<Element> mHScrollbarContent; 1320 nsCOMPtr<Element> mVScrollbarContent; 1321 nsCOMPtr<Element> mScrollCornerContent; 1322 nsCOMPtr<Element> mResizerContent; 1323 1324 class ScrollEvent; 1325 class ScrollEndEvent; 1326 class AsyncScrollPortEvent; 1327 class ScrolledAreaEvent; 1328 1329 RefPtr<ScrollEvent> mScrollEvent; 1330 RefPtr<ScrollEndEvent> mScrollEndEvent; 1331 nsRevocableEventPtr<AsyncScrollPortEvent> mAsyncScrollPortEvent; 1332 nsRevocableEventPtr<ScrolledAreaEvent> mScrolledAreaEvent; 1333 nsScrollbarFrame* mHScrollbarBox; 1334 nsScrollbarFrame* mVScrollbarBox; 1335 nsIFrame* mScrolledFrame; 1336 nsIFrame* mScrollCornerBox; 1337 nsIFrame* mResizerBox; 1338 const nsIFrame* mReferenceFrameDuringPainting; 1339 RefPtr<AsyncScroll> mAsyncScroll; 1340 RefPtr<AsyncSmoothMSDScroll> mAsyncSmoothMSDScroll; 1341 RefPtr<layout::ScrollbarActivity> mScrollbarActivity; 1342 ScrollOrigin mLastScrollOrigin; 1343 Maybe<nsPoint> mApzSmoothScrollDestination; 1344 MainThreadScrollGeneration mScrollGeneration; 1345 APZScrollGeneration mScrollGenerationOnApz; 1346 1347 nsTArray<ScrollPositionUpdate> mScrollUpdates; 1348 1349 // The minimum-scale size, this is specific to mobile environments where the 1350 // initial-scale can be less than 1.0. 1351 // See 1352 // https://github.com/bokand/bokand.github.io/blob/master/web_viewports_explainer.md#minimum-scale 1353 // for details. 1354 nsSize mMinimumScaleSize; 1355 1356 // Stores the ICB size for the root document if this frame is using the 1357 // minimum scale size for |mScrollPort|. 1358 nsSize mICBSize; 1359 1360 // Where we're currently scrolling to, if we're scrolling asynchronously. 1361 // If we're not in the middle of an asynchronous scroll then this is 1362 // just the current scroll position. ScrollBy will choose its 1363 // destination based on this value. 1364 nsPoint mDestination; 1365 1366 // A goal position to try to scroll to as content loads. As long as mLastPos 1367 // matches the current logical scroll position, we try to scroll to 1368 // mRestorePos after every reflow --- because after each time content is 1369 // loaded/added to the scrollable element, there will be a reflow. 1370 // Note that for frames where layout and visual viewport aren't one and the 1371 // same thing, this scroll position will be the logical scroll position of 1372 // the *visual* viewport, as its position will be more relevant to the user. 1373 nsPoint mRestorePos; 1374 // The last logical position we scrolled to while trying to restore 1375 // mRestorePos, or 0,0 when this is a new frame. Set to -1,-1 once we've 1376 // scrolled for any reason other than trying to restore mRestorePos. 1377 // Just as with mRestorePos, this position will be the logical position of 1378 // the *visual* viewport where available. 1379 nsPoint mLastPos; 1380 1381 // The latest scroll position we've sent or received from APZ. This 1382 // represents the main thread's best knowledge of the APZ scroll position, 1383 // and is used to calculate relative scroll offset updates. 1384 nsPoint mApzScrollPos; 1385 1386 nsExpirationState mActivityExpirationState; 1387 1388 nsCOMPtr<nsITimer> mScrollActivityTimer; 1389 1390 // The scroll position where we last updated frame visibility. 1391 nsPoint mLastUpdateFramesPos; 1392 nsRect mDisplayPortAtLastFrameUpdate; 1393 1394 nsRect mPrevScrolledRect; 1395 1396 layers::ScrollableLayerGuid::ViewID mScrollParentID; 1397 1398 // Timer to remove the displayport some time after scrolling has stopped 1399 nsCOMPtr<nsITimer> mDisplayPortExpiryTimer; 1400 1401 ScrollAnchorContainer mAnchor; 1402 1403 // We keep holding a strong reference for each snap target element until the 1404 // next snapping happens so that it avoids using the same nsIContent* pointer 1405 // for newly created contents in this scroll container. Otherwise we will try 1406 // to match different nsIContent(s) generated at the same address during 1407 // re-snapping. 1408 SnapTargetSet mSnapTargets; 1409 1410 // Representing there's an APZ animation is in progress and what caused the 1411 // animation. Note that this is only set when repainted via APZ, which means 1412 // that there may be a request for an APZ animation in flight for example, 1413 // while this is still `No`. In order to answer "is an APZ animation in the 1414 // process of starting or in progress" you need to check mScrollUpdates, 1415 // mApzAnimationRequested, and this type. 1416 APZScrollAnimationType mCurrentAPZScrollAnimationType; 1417 1418 // The paint sequence number if the scroll frame is the first scrollable frame 1419 // encountered. 1420 Maybe<uint32_t> mIsFirstScrollableFrameSequenceNumber; 1421 1422 // Representing whether the APZC corresponding to this frame is now in the 1423 // middle of handling a gesture (e.g. a pan gesture). 1424 InScrollingGesture mInScrollingGesture : 1; 1425 1426 bool mAllowScrollOriginDowngrade : 1; 1427 bool mHadDisplayPortAtLastFrameUpdate : 1; 1428 1429 // True if the most recent reflow of the scroll container frame has 1430 // the vertical scrollbar shown. 1431 bool mHasVerticalScrollbar : 1; 1432 // True if the most recent reflow of the scroll container frame has the 1433 // horizontal scrollbar shown. 1434 bool mHasHorizontalScrollbar : 1; 1435 1436 // If mHas(Vertical|Horizontal)Scrollbar is true then 1437 // mOnlyNeed(V|H)ScrollbarToScrollVVInsideLV indicates if the only reason we 1438 // need that scrollbar is to scroll the visual viewport inside the layout 1439 // viewport. These scrollbars are special in that even if they are layout 1440 // scrollbars they do not take up any layout space. 1441 bool mOnlyNeedVScrollbarToScrollVVInsideLV : 1; 1442 bool mOnlyNeedHScrollbarToScrollVVInsideLV : 1; 1443 bool mFrameIsUpdatingScrollbar : 1; 1444 bool mDidHistoryRestore : 1; 1445 // Is this the scrollframe for the document's viewport? 1446 bool mIsRoot : 1; 1447 // If true, we skipped a scrollbar layout due to mSuppressScrollbarUpdate 1448 // being set at some point. That means we should lay out scrollbars even if 1449 // it might not strictly be needed next time mSuppressScrollbarUpdate is 1450 // false. 1451 bool mSkippedScrollbarLayout : 1; 1452 1453 bool mHadNonInitialReflow : 1; 1454 // Initially true; first call to ReflowFinished() sets it to false. 1455 bool mFirstReflow : 1; 1456 // State used only by PostScrollEvents so we know 1457 // which overflow states have changed. 1458 bool mHorizontalOverflow : 1; 1459 bool mVerticalOverflow : 1; 1460 bool mPostedReflowCallback : 1; 1461 bool mMayHaveDirtyFixedChildren : 1; 1462 // If true, need to actually update our scrollbar attributes in the 1463 // reflow callback. 1464 bool mUpdateScrollbarAttributes : 1; 1465 // If true, we should be prepared to scroll using this scrollframe 1466 // by placing descendant content into its own layer(s) 1467 bool mHasBeenScrolledRecently : 1; 1468 1469 // If true, the scroll frame should always be active because we always build 1470 // a scrollable layer. Used for asynchronous scrolling. 1471 bool mWillBuildScrollableLayer : 1; 1472 1473 // If true, the scroll frame is an ancestor of other "active" scrolling 1474 // frames, where "active" means has a non-minimal display port if 1475 // ShouldActivateAllScrollFrames is true, or has a display port if 1476 // ShouldActivateAllScrollFrames is false. And this means that we shouldn't 1477 // expire the display port (if ShouldActivateAllScrollFrames is true then 1478 // expiring a display port means making it minimal, otherwise it means 1479 // removing the display port). If those descendant scrollframes have their 1480 // display ports removed or made minimal, then we expire our display port. 1481 bool mIsParentToActiveScrollFrames : 1; 1482 1483 // True if this frame has been scrolled at least once 1484 bool mHasBeenScrolled : 1; 1485 1486 // True if the events synthesized by OSX to produce momentum scrolling should 1487 // be ignored. Reset when the next real, non-synthesized scroll event occurs. 1488 bool mIgnoreMomentumScroll : 1; 1489 1490 // True if the APZ is in the process of async-transforming this scrollframe, 1491 // (as best as we can tell on the main thread, anyway). 1492 bool mTransformingByAPZ : 1; 1493 1494 // True if APZ can scroll this frame asynchronously (i.e. it has an APZC 1495 // set up for this frame and it's not a scrollinfo layer). 1496 bool mScrollableByAPZ : 1; 1497 1498 // True if the APZ is allowed to zoom this scrollframe. 1499 bool mZoomableByAPZ : 1; 1500 1501 // True if the scroll frame contains out-of-flow content and is inside 1502 // a CSS filter. 1503 bool mHasOutOfFlowContentInsideFilter : 1; 1504 1505 // True if we don't want the scrollbar to repaint itself right now. 1506 bool mSuppressScrollbarRepaints : 1; 1507 1508 // True if we are using the minimum scale size instead of ICB for scroll port. 1509 bool mIsUsingMinimumScaleSize : 1; 1510 1511 // True if the minimum scale size has been changed since the last reflow. 1512 bool mMinimumScaleSizeChanged : 1; 1513 1514 // True if we're processing an scroll event. 1515 bool mProcessingScrollEvent : 1; 1516 1517 // This is true from the time a scroll animation is requested of APZ to the 1518 // time that APZ responds with an up-to-date repaint request. More precisely, 1519 // this is flipped to true if a repaint request is dispatched to APZ where 1520 // the most recent scroll request is a smooth scroll, and it is cleared when 1521 // mApzAnimationInProgress is updated. 1522 bool mApzAnimationRequested : 1; 1523 1524 // Similar to above mApzAnimationRequested but the request came from script, 1525 // e.g., scrollBy(). 1526 bool mApzAnimationTriggeredByScriptRequested : 1; 1527 1528 // Whether we need to reclamp the visual viewport offset in ReflowFinished. 1529 bool mReclampVVOffsetInReflowFinished : 1; 1530 1531 // Whether we need to schedule the scroll-driven animations. 1532 bool mMayScheduleScrollAnimations : 1; 1533 1534 #ifdef MOZ_WIDGET_ANDROID 1535 // True if this scrollable frame was vertically overflowed on the last reflow. 1536 bool mHasVerticalOverflowForDynamicToolbar : 1; 1537 #endif 1538 1539 layout::ScrollVelocityQueue mVelocityQueue; 1540 1541 // NOTE: On mobile this value might be factoring into overflow:hidden region 1542 // in the case of the top level document. 1543 nsRect mScrollPort; 1544 UniquePtr<ScrollSnapTargetIds> mLastSnapTargetIds; 1545 // Lazily created on demand, see StickyScrollContainer::GetOrCreateForFrame. 1546 UniquePtr<StickyScrollContainer> mStickyContainer; 1547 }; 1548 1549 } // namespace mozilla 1550 1551 #endif /* mozilla_ScrollContainerFrame_h_ */