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 "Units.h" 11 #include "nsDisplayList.h" 12 #include "nsRect.h" 13 14 #include <cstdint> 15 #include <iosfwd> 16 17 class nsIContent; 18 class nsIFrame; 19 class nsPresContext; 20 21 namespace mozilla { 22 23 class nsDisplayListBuilder; 24 class PresShell; 25 26 // For GetDisplayPort 27 enum class DisplayportRelativeTo { ScrollPort, ScrollFrame }; 28 29 // Is the displayport being applied to scrolled content or fixed content? 30 enum class ContentGeometryType { Scrolled, Fixed }; 31 32 struct DisplayPortOptions { 33 // The default options. 34 DisplayportRelativeTo mRelativeTo = DisplayportRelativeTo::ScrollPort; 35 ContentGeometryType mGeometryType = ContentGeometryType::Scrolled; 36 37 // Fluent interface for changing the defaults. WithDisplayPortOptions38 DisplayPortOptions With(DisplayportRelativeTo aRelativeTo) const { 39 DisplayPortOptions result = *this; 40 result.mRelativeTo = aRelativeTo; 41 return result; 42 } WithDisplayPortOptions43 DisplayPortOptions With(ContentGeometryType aGeometryType) const { 44 DisplayPortOptions result = *this; 45 result.mGeometryType = aGeometryType; 46 return result; 47 } 48 }; 49 50 struct DisplayPortPropertyData { DisplayPortPropertyDataDisplayPortPropertyData51 DisplayPortPropertyData(const nsRect& aRect, uint32_t aPriority, 52 bool aPainted) 53 : mRect(aRect), mPriority(aPriority), mPainted(aPainted) {} 54 nsRect mRect; 55 uint32_t mPriority; 56 bool mPainted; 57 }; 58 59 struct DisplayPortMargins { 60 // The margins relative to the visual scroll offset. 61 ScreenMargin mMargins; 62 63 // Some information captured at the time the margins are stored. 64 // This ensures that we can express the margins as being relative to 65 // the correct scroll offset when applying them. 66 67 // APZ's visual scroll offset at the time it requested the margins. 68 CSSPoint mVisualOffset; 69 70 // The scroll frame's layout scroll offset at the time the margins 71 // were saved. 72 CSSPoint mLayoutOffset; 73 74 // The scale required to convert between the CSS cordinates of 75 // mVisualOffset and mLayoutOffset, and the Screen coordinates of mMargins. 76 CSSToScreenScale2D mScale; 77 78 // Create displayport margins requested by APZ, relative to an async visual 79 // offset provided by APZ. 80 static DisplayPortMargins FromAPZ(const ScreenMargin& aMargins, 81 const CSSPoint& aVisualOffset, 82 const CSSPoint& aLayoutOffset, 83 const CSSToScreenScale2D& aScale); 84 85 // Create displayport port margins for the given scroll frame. 86 // This is for use in cases where we don't have async scroll information from 87 // APZ to use to adjust the margins. The visual and layout offset are set 88 // based on the main thread's view of them. If a scale isn't provided, one 89 // is computed based on the main thread's knowledge. 90 static DisplayPortMargins ForScrollFrame( 91 nsIScrollableFrame* aScrollFrame, const ScreenMargin& aMargins, 92 const Maybe<CSSToScreenScale2D>& aScale = Nothing()); 93 94 // Convenience version of the above that takes a content element. 95 static DisplayPortMargins ForContent(nsIContent* aContent, 96 const ScreenMargin& aMargins); 97 98 // Another convenience version that sets empty margins. EmptyDisplayPortMargins99 static DisplayPortMargins Empty(nsIContent* aContent) { 100 return ForContent(aContent, ScreenMargin()); 101 } 102 103 // Get the margins relative to the layout viewport. 104 // |aGeometryType| tells us whether the margins are being queried for the 105 // purpose of being applied to scrolled content or fixed content. 106 // |aScrollableFrame| is the scroll frame whose content the margins will be 107 // applied to (or, in the case of fixed content), the scroll frame wrt. which 108 // the content is fixed. 109 ScreenMargin GetRelativeToLayoutViewport( 110 ContentGeometryType aGeometryType, 111 nsIScrollableFrame* aScrollableFrame) const; 112 113 friend std::ostream& operator<<(std::ostream& aOs, 114 const DisplayPortMargins& aMargins); 115 116 private: 117 CSSPoint ComputeAsyncTranslation(ContentGeometryType aGeometryType, 118 nsIScrollableFrame* aScrollableFrame) const; 119 }; 120 121 struct DisplayPortMarginsPropertyData { DisplayPortMarginsPropertyDataDisplayPortMarginsPropertyData122 DisplayPortMarginsPropertyData(const DisplayPortMargins& aMargins, 123 uint32_t aPriority, bool aPainted) 124 : mMargins(aMargins), mPriority(aPriority), mPainted(aPainted) {} 125 DisplayPortMargins mMargins; 126 uint32_t mPriority; 127 bool mPainted; 128 }; 129 130 class DisplayPortUtils { 131 public: 132 /** 133 * Get display port for the given element, relative to the specified entity, 134 * defaulting to the scrollport. 135 */ 136 static bool GetDisplayPort( 137 nsIContent* aContent, nsRect* aResult, 138 const DisplayPortOptions& aOptions = DisplayPortOptions()); 139 140 /** 141 * Check whether the given element has a displayport. 142 */ 143 static bool HasDisplayPort(nsIContent* aContent); 144 145 /** 146 * Check whether the given element has a displayport that has already 147 * been sent to the compositor via a layers or WR transaction. 148 */ 149 static bool HasPaintedDisplayPort(nsIContent* aContent); 150 151 /** 152 * Mark the displayport of a given element as having been sent to 153 * the compositor via a layers or WR transaction. 154 */ 155 static void MarkDisplayPortAsPainted(nsIContent* aContent); 156 157 /** 158 * Check whether the given frame has a displayport. It returns false 159 * for scrolled frames and true for the corresponding scroll frame. 160 * Optionally pass the child, and it only returns true if the child is the 161 * scrolled frame for the displayport. 162 */ 163 static bool FrameHasDisplayPort(nsIFrame* aFrame, 164 const nsIFrame* aScrolledFrame = nullptr); 165 166 /** 167 * Check whether the given element has a non-minimal displayport. 168 */ 169 static bool HasNonMinimalDisplayPort(nsIContent* aContent); 170 171 /** 172 * Check whether the given element has a non-minimal displayport that also has 173 * non-zero margins. A display port rect is considered non-minimal non-zero. 174 */ 175 static bool HasNonMinimalNonZeroDisplayPort(nsIContent* aContent); 176 177 /** 178 * Check if the given element has a margins based displayport but is missing a 179 * displayport base rect that it needs to properly compute a displayport rect. 180 */ 181 static bool IsMissingDisplayPortBaseRect(nsIContent* aContent); 182 183 /** 184 * @return the display port for the given element which should be used for 185 * visibility testing purposes, relative to the scroll frame. 186 * 187 * This is the display port computed with a multipler of 1 which is the normal 188 * display port unless low-precision buffers are enabled. If low-precision 189 * buffers are enabled then GetDisplayPort() uses a multiplier to expand the 190 * displayport, so this will differ from GetDisplayPort. 191 */ 192 static bool GetDisplayPortForVisibilityTesting(nsIContent* aContent, 193 nsRect* aResult); 194 195 enum class RepaintMode : uint8_t { Repaint, DoNotRepaint }; 196 197 /** 198 * Invalidate for displayport change. 199 */ 200 static void InvalidateForDisplayPortChange( 201 nsIContent* aContent, bool aHadDisplayPort, const nsRect& aOldDisplayPort, 202 const nsRect& aNewDisplayPort, 203 RepaintMode aRepaintMode = RepaintMode::Repaint); 204 205 /** 206 * Set the display port margins for a content element to be used with a 207 * display port base (see SetDisplayPortBase()). 208 * See also nsIDOMWindowUtils.setDisplayPortMargins. 209 * @param aContent the content element for which to set the margins 210 * @param aPresShell the pres shell for the document containing the element 211 * @param aMargins the margins to set 212 * @param aAlignmentX, alignmentY the amount of pixels to which to align the 213 * displayport built by combining the base 214 * rect with the margins, in either direction 215 * @param aPriority a priority value to determine which margins take effect 216 * when multiple callers specify margins 217 * @param aRepaintMode whether to schedule a paint after setting the margins 218 * @return true if the new margins were applied. 219 */ 220 enum class ClearMinimalDisplayPortProperty { No, Yes }; 221 222 static bool SetDisplayPortMargins( 223 nsIContent* aContent, PresShell* aPresShell, 224 const DisplayPortMargins& aMargins, 225 ClearMinimalDisplayPortProperty aClearMinimalDisplayPortProperty, 226 uint32_t aPriority = 0, RepaintMode aRepaintMode = RepaintMode::Repaint); 227 228 /** 229 * Set the display port base rect for given element to be used with display 230 * port margins. 231 * SetDisplayPortBaseIfNotSet is like SetDisplayPortBase except it only sets 232 * the display port base to aBase if no display port base is currently set. 233 */ 234 static void SetDisplayPortBase(nsIContent* aContent, const nsRect& aBase); 235 static void SetDisplayPortBaseIfNotSet(nsIContent* aContent, 236 const nsRect& aBase); 237 238 /** 239 * Remove the displayport for the given element. 240 */ 241 static void RemoveDisplayPort(nsIContent* aContent); 242 243 /** 244 * Return true if aPresContext's viewport has a displayport. 245 */ 246 static bool ViewportHasDisplayPort(nsPresContext* aPresContext); 247 248 /** 249 * Return true if aFrame is a fixed-pos frame and is a child of a viewport 250 * which has a displayport. These frames get special treatment from the 251 * compositor. aDisplayPort, if non-null, is set to the display port rectangle 252 * (relative to the viewport). 253 */ 254 static bool IsFixedPosFrameInDisplayPort(const nsIFrame* aFrame); 255 256 static bool MaybeCreateDisplayPortInFirstScrollFrameEncountered( 257 nsIFrame* aFrame, nsDisplayListBuilder* aBuilder); 258 259 /** 260 * Calculate a default set of displayport margins for the given scrollframe 261 * and set them on the scrollframe's content element. The margins are set with 262 * the default priority, which may clobber previously set margins. The repaint 263 * mode provided is passed through to the call to SetDisplayPortMargins. 264 * The |aScrollFrame| parameter must be non-null and queryable to an nsIFrame. 265 * @return true iff the call to SetDisplayPortMargins returned true. 266 */ 267 static bool CalculateAndSetDisplayPortMargins( 268 nsIScrollableFrame* aScrollFrame, RepaintMode aRepaintMode); 269 270 /** 271 * If |aScrollFrame| WantsAsyncScroll() and we don't have a scrollable 272 * displayport yet (as tracked by |aBuilder|), calculate and set a 273 * displayport. 274 * 275 * If this is called during display list building pass DoNotRepaint in 276 * aRepaintMode. 277 * 278 * Returns true if there is a displayport on an async scrollable scrollframe 279 * after this call, either because one was just added or it already existed. 280 */ 281 static bool MaybeCreateDisplayPort(nsDisplayListBuilder* aBuilder, 282 nsIFrame* aScrollFrame, 283 RepaintMode aRepaintMode); 284 285 /** 286 * Sets a zero margin display port on all proper ancestors of aFrame that 287 * are async scrollable. 288 */ 289 static void SetZeroMarginDisplayPortOnAsyncScrollableAncestors( 290 nsIFrame* aFrame); 291 292 /** 293 * Finds the closest ancestor async scrollable frame from aFrame that has a 294 * displayport and attempts to trigger the displayport expiry on that 295 * ancestor. 296 */ 297 static void ExpireDisplayPortOnAsyncScrollableAncestor(nsIFrame* aFrame); 298 299 /** 300 * Returns root displayport base rect for |aPresShell|. In the case where 301 * |aPresShell| is in an out-of-process iframe, this function may return 302 * Nothing() if we haven't received the iframe's visible rect from the parent 303 * content. 304 * |aPresShell| should be top level content or in-process root or root in the 305 * browser process. 306 */ 307 static Maybe<nsRect> GetRootDisplayportBase(PresShell* aPresShell); 308 }; 309 310 } // namespace mozilla 311 312 #endif // mozilla_DisplayPortUtils_h__ 313