tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DisplayPortUtils.h (17782B)


      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 mozilla_DisplayPortUtils_h__
      8 #define mozilla_DisplayPortUtils_h__
      9 
     10 #include <cstdint>
     11 #include <iosfwd>
     12 
     13 #include "Units.h"
     14 #include "nsDisplayList.h"
     15 #include "nsRect.h"
     16 
     17 class nsIContent;
     18 class nsIFrame;
     19 class nsPresContext;
     20 
     21 namespace mozilla {
     22 
     23 class nsDisplayListBuilder;
     24 class PresShell;
     25 class ScrollContainerFrame;
     26 
     27 // For GetDisplayPort
     28 enum class DisplayportRelativeTo { ScrollPort, ScrollFrame };
     29 
     30 // Is the displayport being applied to scrolled content or fixed content?
     31 enum class ContentGeometryType { Scrolled, Fixed };
     32 
     33 struct DisplayPortOptions {
     34  // The default options.
     35  DisplayportRelativeTo mRelativeTo = DisplayportRelativeTo::ScrollPort;
     36  ContentGeometryType mGeometryType = ContentGeometryType::Scrolled;
     37 
     38  // Fluent interface for changing the defaults.
     39  DisplayPortOptions With(DisplayportRelativeTo aRelativeTo) const {
     40    DisplayPortOptions result = *this;
     41    result.mRelativeTo = aRelativeTo;
     42    return result;
     43  }
     44  DisplayPortOptions With(ContentGeometryType aGeometryType) const {
     45    DisplayPortOptions result = *this;
     46    result.mGeometryType = aGeometryType;
     47    return result;
     48  }
     49 };
     50 
     51 struct DisplayPortPropertyData {
     52  DisplayPortPropertyData(const nsRect& aRect, uint32_t aPriority,
     53                          bool aPainted)
     54      : mRect(aRect), mPriority(aPriority), mPainted(aPainted) {}
     55  nsRect mRect;
     56  uint32_t mPriority;
     57  bool mPainted;
     58 };
     59 
     60 struct DisplayPortMargins {
     61  // The margins relative to the visual scroll offset.
     62  ScreenMargin mMargins;
     63 
     64  // Some information captured at the time the margins are stored.
     65  // This ensures that we can express the margins as being relative to
     66  // the correct scroll offset when applying them.
     67 
     68  // APZ's visual scroll offset at the time it requested the margins.
     69  CSSPoint mVisualOffset;
     70 
     71  // The scroll frame's layout scroll offset at the time the margins
     72  // were saved.
     73  CSSPoint mLayoutOffset;
     74 
     75  // Create displayport margins requested by APZ, relative to an async visual
     76  // offset provided by APZ.
     77  static DisplayPortMargins FromAPZ(const ScreenMargin& aMargins,
     78                                    const CSSPoint& aVisualOffset,
     79                                    const CSSPoint& aLayoutOffset);
     80 
     81  // Create displayport port margins for the given scroll container frame.
     82  // This is for use in cases where we don't have async scroll information from
     83  // APZ to use to adjust the margins. The visual and layout offset are set
     84  // based on the main thread's view of them.
     85  static DisplayPortMargins ForScrollContainerFrame(
     86      ScrollContainerFrame* aScrollContainerFrame,
     87      const ScreenMargin& aMargins);
     88 
     89  // Convenience version of the above that takes a content element.
     90  static DisplayPortMargins ForContent(nsIContent* aContent,
     91                                       const ScreenMargin& aMargins);
     92 
     93  // Another convenience version that sets empty margins.
     94  static DisplayPortMargins Empty(nsIContent* aContent) {
     95    return ForContent(aContent, ScreenMargin());
     96  }
     97 
     98  // Get the margins relative to the layout viewport.
     99  // |aGeometryType| tells us whether the margins are being queried for the
    100  // purpose of being applied to scrolled content or fixed content.
    101  // |aScrollableFrame| is the scroll frame whose content the margins will be
    102  // applied to (or, in the case of fixed content), the scroll frame wrt. which
    103  // the content is fixed.
    104  ScreenMargin GetRelativeToLayoutViewport(
    105      ContentGeometryType aGeometryType,
    106      ScrollContainerFrame* aScrollContainerFrame,
    107      const CSSToScreenScale2D& aDisplayportScale) const;
    108 
    109  friend std::ostream& operator<<(std::ostream& aOs,
    110                                  const DisplayPortMargins& aMargins);
    111 
    112 private:
    113  CSSPoint ComputeAsyncTranslation(
    114      ContentGeometryType aGeometryType,
    115      ScrollContainerFrame* aScrollContainerFrame) const;
    116 };
    117 
    118 struct DisplayPortMarginsPropertyData {
    119  DisplayPortMarginsPropertyData(const DisplayPortMargins& aMargins,
    120                                 uint32_t aPriority, bool aPainted)
    121      : mMargins(aMargins), mPriority(aPriority), mPainted(aPainted) {}
    122  DisplayPortMargins mMargins;
    123  uint32_t mPriority;
    124  bool mPainted;
    125 };
    126 
    127 struct FrameAndASRKind {
    128  nsIFrame* mFrame;
    129  ActiveScrolledRoot::ASRKind mASRKind;
    130  bool operator==(const FrameAndASRKind&) const = default;
    131  static FrameAndASRKind default_value() {
    132    return {nullptr, ActiveScrolledRoot::ASRKind::Scroll};
    133  }
    134 };
    135 
    136 class DisplayPortUtils {
    137 public:
    138  /**
    139   * Get display port for the given element, relative to the specified entity,
    140   * defaulting to the scrollport.
    141   */
    142  static bool GetDisplayPort(
    143      nsIContent* aContent, nsRect* aResult,
    144      const DisplayPortOptions& aOptions = DisplayPortOptions());
    145 
    146  /**
    147   * Check whether the given element has a displayport.
    148   */
    149  static bool HasDisplayPort(nsIContent* aContent);
    150 
    151  /**
    152   * Check whether the given element has a displayport that has already
    153   * been sent to the compositor via a layers or WR transaction.
    154   */
    155  static bool HasPaintedDisplayPort(nsIContent* aContent);
    156 
    157  /**
    158   * Mark the displayport of a given element as having been sent to
    159   * the compositor via a layers or WR transaction.
    160   */
    161  static void MarkDisplayPortAsPainted(nsIContent* aContent);
    162 
    163  /**
    164   * Check whether the given frame has a displayport. It returns false
    165   * for scrolled frames and true for the corresponding scroll frame.
    166   * Optionally pass the child, and it only returns true if the child is the
    167   * scrolled frame for the displayport.
    168   */
    169  static bool FrameHasDisplayPort(nsIFrame* aFrame,
    170                                  const nsIFrame* aScrolledFrame = nullptr);
    171 
    172  /**
    173   * Check whether the given element has a non-minimal displayport.
    174   */
    175  static bool HasNonMinimalDisplayPort(nsIContent* aContent);
    176 
    177  /**
    178   * Check whether the given element has a non-minimal displayport that also has
    179   * non-zero margins. A display port rect is considered non-minimal non-zero.
    180   */
    181  static bool HasNonMinimalNonZeroDisplayPort(nsIContent* aContent);
    182 
    183  /**
    184   * Check if the given element has a margins based displayport but is missing a
    185   * displayport base rect that it needs to properly compute a displayport rect.
    186   */
    187  static bool IsMissingDisplayPortBaseRect(nsIContent* aContent);
    188 
    189  /**
    190   * @return the display port for the given element which should be used for
    191   * visibility testing purposes, relative to the scroll frame.
    192   *
    193   * This is the display port computed with a multipler of 1 which is the normal
    194   * display port unless low-precision buffers are enabled. If low-precision
    195   * buffers are enabled then GetDisplayPort() uses a multiplier to expand the
    196   * displayport, so this will differ from GetDisplayPort.
    197   */
    198  static bool GetDisplayPortForVisibilityTesting(nsIContent* aContent,
    199                                                 nsRect* aResult);
    200 
    201  enum class RepaintMode : uint8_t { Repaint, DoNotRepaint };
    202 
    203  /**
    204   * Invalidate for displayport change.
    205   */
    206  static void InvalidateForDisplayPortChange(
    207      nsIContent* aContent, bool aHadDisplayPort, const nsRect& aOldDisplayPort,
    208      const nsRect& aNewDisplayPort,
    209      RepaintMode aRepaintMode = RepaintMode::Repaint);
    210 
    211  /**
    212   * Set the display port margins for a content element to be used with a
    213   * display port base (see SetDisplayPortBase()).
    214   * See also nsIDOMWindowUtils.setDisplayPortMargins.
    215   * @param aContent the content element for which to set the margins
    216   * @param aPresShell the pres shell for the document containing the element
    217   * @param aMargins the margins to set
    218   * @param aAlignmentX, alignmentY the amount of pixels to which to align the
    219   *                                displayport built by combining the base
    220   *                                rect with the margins, in either direction
    221   * @param aPriority a priority value to determine which margins take effect
    222   *                  when multiple callers specify margins
    223   * @param aRepaintMode whether to schedule a paint after setting the margins
    224   * @return true if the new margins were applied.
    225   */
    226  enum class ClearMinimalDisplayPortProperty { No, Yes };
    227 
    228  static bool SetDisplayPortMargins(
    229      nsIContent* aContent, PresShell* aPresShell,
    230      const DisplayPortMargins& aMargins,
    231      ClearMinimalDisplayPortProperty aClearMinimalDisplayPortProperty,
    232      uint32_t aPriority = 0, RepaintMode aRepaintMode = RepaintMode::Repaint);
    233 
    234  /**
    235   * Set the display port base rect for given element to be used with display
    236   * port margins.
    237   * SetDisplayPortBaseIfNotSet is like SetDisplayPortBase except it only sets
    238   * the display port base to aBase if no display port base is currently set.
    239   */
    240  static void SetDisplayPortBase(nsIContent* aContent, const nsRect& aBase);
    241  static void SetDisplayPortBaseIfNotSet(nsIContent* aContent,
    242                                         const nsRect& aBase);
    243 
    244  /**
    245   * Remove the displayport for the given element.
    246   */
    247  static void RemoveDisplayPort(nsIContent* aContent);
    248 
    249  /**
    250   * Set minimal display port margins during painting.
    251   */
    252  static void SetMinimalDisplayPortDuringPainting(nsIContent* aContent,
    253                                                  PresShell* aPresShell);
    254 
    255  /**
    256   * Return true if aPresContext's viewport has a displayport.
    257   */
    258  static bool ViewportHasDisplayPort(nsPresContext* aPresContext);
    259 
    260  /**
    261   * Return true if aFrame is a fixed-pos frame and is a child of a viewport
    262   * which has a displayport. These frames get special treatment from the
    263   * compositor. aDisplayPort, if non-null, is set to the display port rectangle
    264   * (relative to the viewport).
    265   */
    266  static bool IsFixedPosFrameInDisplayPort(const nsIFrame* aFrame);
    267 
    268  static bool MaybeCreateDisplayPortInFirstScrollFrameEncountered(
    269      nsIFrame* aFrame, nsDisplayListBuilder* aBuilder);
    270 
    271  /**
    272   * Calculate a default set of displayport margins for the given scrollframe
    273   * and set them on the scrollframe's content element. The margins are set with
    274   * the default priority, which may clobber previously set margins. The repaint
    275   * mode provided is passed through to the call to SetDisplayPortMargins.
    276   * The |aScrollFrame| parameter must be non-null and queryable to an nsIFrame.
    277   * @return true iff the call to SetDisplayPortMargins returned true.
    278   */
    279  static bool CalculateAndSetDisplayPortMargins(
    280      ScrollContainerFrame* aScrollContainerFrame, RepaintMode aRepaintMode);
    281 
    282  /**
    283   * If |aScrollContainerFrame| WantsAsyncScroll() and we don't have a
    284   * scrollable displayport yet (as tracked by |aBuilder|), calculate and set a
    285   * displayport.
    286   *
    287   * If this is called during display list building pass DoNotRepaint in
    288   * aRepaintMode.
    289   *
    290   * Returns true if there is a displayport on an async scrollable scrollframe
    291   * after this call, either because one was just added or it already existed.
    292   */
    293  static bool MaybeCreateDisplayPort(
    294      nsDisplayListBuilder* aBuilder,
    295      ScrollContainerFrame* aScrollContainerFrame, RepaintMode aRepaintMode);
    296 
    297  /**
    298   * Sets a zero margin display port on all proper ancestors of aFrame that
    299   * are async scrollable.
    300   */
    301  static void SetZeroMarginDisplayPortOnAsyncScrollableAncestors(
    302      nsIFrame* aFrame);
    303 
    304  /**
    305   * Finds the closest ancestor async scrollable frame from aFrame that has a
    306   * displayport and attempts to trigger the displayport expiry on that
    307   * ancestor.
    308   */
    309  static void ExpireDisplayPortOnAsyncScrollableAncestor(nsIFrame* aFrame);
    310 
    311  /**
    312   * Returns root displayport base rect for |aPresShell|. In the case where
    313   * |aPresShell| is in an out-of-process iframe, this function may return
    314   * Nothing() if we haven't received the iframe's visible rect from the parent
    315   * content.
    316   * |aPresShell| should be top level content or in-process root or root in the
    317   * browser process.
    318   */
    319  static Maybe<nsRect> GetRootDisplayportBase(PresShell* aPresShell);
    320 
    321  static nsRect GetDisplayportBase(nsIFrame* aFrame);
    322 
    323  /**
    324   * Whether to tell the given element will use empty displayport marings.
    325   * NOTE: This function should be called only for the element having any type
    326   * of displayports.
    327   */
    328  static bool WillUseEmptyDisplayPortMargins(nsIContent* aContent);
    329 
    330  /**
    331   * Step up one frame in the async scrollable ancestor chain, to be used in
    332   * conjunction with GetAsyncScrollableAncestorFrame to walk the async
    333   * scrollable ancestor chain. Note this doesn't go from one async scrollable
    334   * frame to the next. Rather this walks all frame types, taking only one
    335   * ancestor step per call.
    336   */
    337  static nsIFrame* OneStepInAsyncScrollableAncestorChain(nsIFrame* aFrame);
    338 
    339  /**
    340   * The next two functions (GetASRAncestorFrame and OneStepInASRChain) use
    341   * FrameAndASRKind (a pair of a nsIFrame pointer an an ASRKind enum) as a
    342   * cursor iterating up the frame tree. Each frame can potential generate two
    343   * ASRs: an inner one corresponding to scrolling with the contents of the
    344   * frame if it is a scroll frame, and an outer one correspnding to scrolling
    345   * with the frame itself if it is a sticky position frame. Its meaning is
    346   * different for each of the two functions but is natural when considering
    347   * what each function does. When passed into GetASRAncestorFrame it specifies
    348   * the first frame and type for the function to check. When returned from
    349   * GetASRAncestorFrame it specifies the frame and type of the ASR (because
    350   * GetASRAncestorFrame only returns ASRs). When passed into OneStepInASRChain
    351   * it specifies the last spot that was checked, and OneStepInASRChain's job is
    352   * to move one iteration from that, so it returns the next frame and ASR kind
    353   * to be checked (which may not generate an ASR, just that it needs to be
    354   * checked because it could generate an ASR).
    355   */
    356 
    357  /**
    358   * Follows the ASR (ActiveScrolledRoot) chain of frames, so that if
    359   * f is the frame of an ASR A, then calling this function on
    360   * OneStepInASRChain(f) will return the frame of parent ASR of A. Frames that
    361   * generate an ASR are scroll frames for which IsMaybeAsynchronouslyScrolled()
    362   * returns true (aka mWillBuildScrollableLayer == true) or they are sticky
    363   * position frames for which their corresponding scroll frame will generate an
    364   * ASR. This function is different from
    365   * nsLayoutUtils::GetAsyncScrollableAncestorFrame because
    366   * GetAsyncScrollableAncestorFrame looks only for scroll frames that
    367   * WantAsyncScroll that that function walks from fixed pos to the root scroll
    368   * frame. Because that status (ie mWillBuildScrollableLayer) can change this
    369   * should only be called during a paint to the window after BuildDisplayList
    370   * has been called on aTarget so that mWillBuildScrollableLayer will have been
    371   * updated for this paint already for any frame we need to consult. Or for
    372   * some other reason you know that mWillBuildScrollableLayer is up to date for
    373   * this paint for any frame that might need to be consulted, ie you just
    374   * updated them yourself. Note that a frame returned from this function could
    375   * generate two ASRs: an inner one corresponding to an activated scroll frame,
    376   * and an outer one corresponding to sticky pos.
    377   */
    378  static FrameAndASRKind GetASRAncestorFrame(FrameAndASRKind aFrameAndASRKind,
    379                                             nsDisplayListBuilder* aBuilder);
    380 
    381  /**
    382   * Step up one frame in the ASR chain, to be used in conjunction with
    383   * GetASRAncestorFrame to walk the ASR chain. Note this doesn't go from one
    384   * ASR frame to the next. Rather this walks all frame types, taking only one
    385   * ancestor step per call. Note that a frame returned from this function could
    386   * generate two ASRs: an inner one corresponding to an activated scroll frame,
    387   * and an outer one corresponding to sticky pos. Returns null if we hit
    388   * aLimitAncestor.
    389   */
    390  static FrameAndASRKind OneStepInASRChain(FrameAndASRKind aFrameAndASRKind,
    391                                           nsDisplayListBuilder* aBuilder,
    392                                           nsIFrame* aLimitAncestor = nullptr);
    393 
    394  /**
    395   * Calls DecideScrollableLayerEnsureDisplayport on all proper ancestors of
    396   * aAnchor that are async scrollable up to but not including aLimitAncestor
    397   * (this creates a minimal display port on all async scrollable ancestors if
    398   * they don't have a display port) and makes sure that there is an ASR struct
    399   * created for all such async scrollable ancestors.
    400   * Returns the ASR of aAnchor.
    401   * This is a very specific function for anchor positioning and likely not
    402   * what you want. In that context, aAnchor is the anchor of an abspos frame f
    403   * (not passed to this function because it is not needed) and aLimitAncestor
    404   * is the parent/containing block of f.
    405   */
    406  static const ActiveScrolledRoot* ActivateDisplayportOnASRAncestors(
    407      nsIFrame* aAnchor, nsIFrame* aLimitAncestor,
    408      const ActiveScrolledRoot* aASRofLimitAncestor,
    409      nsDisplayListBuilder* aBuilder);
    410 
    411  /**
    412   * aFrame is an absolutely positioned frame that is anchor positioned and
    413   * compensates for scroll in at least one axis.
    414   */
    415  static bool ShouldAsyncScrollWithAnchor(nsIFrame* aFrame, nsIFrame* aAnchor,
    416                                          nsDisplayListBuilder* aBuilder,
    417                                          PhysicalAxes aAxes);
    418 };
    419 
    420 }  // namespace mozilla
    421 
    422 #endif  // mozilla_DisplayPortUtils_h__