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