diff options
Diffstat (limited to '')
-rw-r--r-- | layout/base/DisplayPortUtils.h | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/layout/base/DisplayPortUtils.h b/layout/base/DisplayPortUtils.h new file mode 100644 index 0000000000..0be42918e4 --- /dev/null +++ b/layout/base/DisplayPortUtils.h @@ -0,0 +1,332 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_DisplayPortUtils_h__ +#define mozilla_DisplayPortUtils_h__ + +#include "Units.h" +#include "nsDisplayList.h" +#include "nsRect.h" + +#include <cstdint> +#include <iosfwd> + +class nsIContent; +class nsIFrame; +class nsDisplayListBuilder; +class nsPresContext; + +namespace mozilla { + +class PresShell; + +// For GetDisplayPort +enum class DisplayportRelativeTo { ScrollPort, ScrollFrame }; + +enum class MaxSizeExceededBehaviour { + // Ask GetDisplayPort to assert if the calculated displayport exceeds + // the maximum allowed size. + Assert, + // Ask GetDisplayPort to pretend like there's no displayport at all, if + // the calculated displayport exceeds the maximum allowed size. + Drop, +}; + +// Is the displayport being applied to scrolled content or fixed content? +enum class ContentGeometryType { Scrolled, Fixed }; + +struct DisplayPortOptions { + // The default options. + DisplayportRelativeTo mRelativeTo = DisplayportRelativeTo::ScrollPort; + MaxSizeExceededBehaviour mMaxSizeExceededBehaviour = + MaxSizeExceededBehaviour::Assert; + ContentGeometryType mGeometryType = ContentGeometryType::Scrolled; + + // Fluent interface for changing the defaults. + DisplayPortOptions With(DisplayportRelativeTo aRelativeTo) const { + DisplayPortOptions result = *this; + result.mRelativeTo = aRelativeTo; + return result; + } + DisplayPortOptions With( + MaxSizeExceededBehaviour aMaxSizeExceededBehaviour) const { + DisplayPortOptions result = *this; + result.mMaxSizeExceededBehaviour = aMaxSizeExceededBehaviour; + return result; + } + DisplayPortOptions With(ContentGeometryType aGeometryType) const { + DisplayPortOptions result = *this; + result.mGeometryType = aGeometryType; + return result; + } +}; + +struct DisplayPortPropertyData { + DisplayPortPropertyData(const nsRect& aRect, uint32_t aPriority, + bool aPainted) + : mRect(aRect), mPriority(aPriority), mPainted(aPainted) {} + nsRect mRect; + uint32_t mPriority; + bool mPainted; +}; + +struct DisplayPortMargins { + // The margins relative to the visual scroll offset. + ScreenMargin mMargins; + + // Some information captured at the time the margins are stored. + // This ensures that we can express the margins as being relative to + // the correct scroll offset when applying them. + + // APZ's visual scroll offset at the time it requested the margins. + CSSPoint mVisualOffset; + + // The scroll frame's layout scroll offset at the time the margins + // were saved. + CSSPoint mLayoutOffset; + + // The scale required to convert between the CSS cordinates of + // mVisualOffset and mLayoutOffset, and the Screen coordinates of mMargins. + CSSToScreenScale2D mScale; + + // Create displayport margins requested by APZ, relative to an async visual + // offset provided by APZ. + static DisplayPortMargins FromAPZ(const ScreenMargin& aMargins, + const CSSPoint& aVisualOffset, + const CSSPoint& aLayoutOffset, + const CSSToScreenScale2D& aScale); + + // Create displayport port margins for the given scroll frame. + // This is for use in cases where we don't have async scroll information from + // APZ to use to adjust the margins. The visual and layout offset are set + // based on the main thread's view of them. If a scale isn't provided, one + // is computed based on the main thread's knowledge. + static DisplayPortMargins ForScrollFrame( + nsIScrollableFrame* aScrollFrame, const ScreenMargin& aMargins, + const Maybe<CSSToScreenScale2D>& aScale = Nothing()); + + // Convenience version of the above that takes a content element. + static DisplayPortMargins ForContent(nsIContent* aContent, + const ScreenMargin& aMargins); + + // Another convenience version that sets empty margins. + static DisplayPortMargins Empty(nsIContent* aContent) { + return ForContent(aContent, ScreenMargin()); + } + + // Get the margins relative to the layout viewport. + // |aGeometryType| tells us whether the margins are being queried for the + // purpose of being applied to scrolled content or fixed content. + // |aScrollableFrame| is the scroll frame whose content the margins will be + // applied to (or, in the case of fixed content), the scroll frame wrt. which + // the content is fixed. + ScreenMargin GetRelativeToLayoutViewport( + ContentGeometryType aGeometryType, + nsIScrollableFrame* aScrollableFrame) const; + + friend std::ostream& operator<<(std::ostream& aOs, + const DisplayPortMargins& aMargins); + + private: + CSSPoint ComputeAsyncTranslation(ContentGeometryType aGeometryType, + nsIScrollableFrame* aScrollableFrame) const; +}; + +struct DisplayPortMarginsPropertyData { + DisplayPortMarginsPropertyData(const DisplayPortMargins& aMargins, + uint32_t aPriority, bool aPainted) + : mMargins(aMargins), mPriority(aPriority), mPainted(aPainted) {} + DisplayPortMargins mMargins; + uint32_t mPriority; + bool mPainted; +}; + +class DisplayPortUtils { + public: + /** + * Get display port for the given element, relative to the specified entity, + * defaulting to the scrollport. + */ + static bool GetDisplayPort( + nsIContent* aContent, nsRect* aResult, + const DisplayPortOptions& aOptions = DisplayPortOptions()); + + /** + * Check whether the given element has a displayport. + */ + static bool HasDisplayPort(nsIContent* aContent); + + /** + * Check whether the given element has a displayport that has already + * been sent to the compositor via a layers or WR transaction. + */ + static bool HasPaintedDisplayPort(nsIContent* aContent); + + /** + * Mark the displayport of a given element as having been sent to + * the compositor via a layers or WR transaction. + */ + static void MarkDisplayPortAsPainted(nsIContent* aContent); + + /** + * Check whether the given frame has a displayport. It returns false + * for scrolled frames and true for the corresponding scroll frame. + * Optionally pass the child, and it only returns true if the child is the + * scrolled frame for the displayport. + */ + static bool FrameHasDisplayPort(nsIFrame* aFrame, + const nsIFrame* aScrolledFrame = nullptr); + + /** + * Check if the given element has a margins based displayport but is missing a + * displayport base rect that it needs to properly compute a displayport rect. + */ + static bool IsMissingDisplayPortBaseRect(nsIContent* aContent); + + /** + * Go through the IPC Channel and update displayport margins for content + * elements based on UpdateFrame messages. The messages are left in the + * queue and will be fully processed when dequeued. The aim is to paint + * the most up-to-date displayport without waiting for these message to + * go through the message queue. + */ + static void UpdateDisplayPortMarginsFromPendingMessages(); + + /** + * @return the display port for the given element which should be used for + * visibility testing purposes, relative to the scroll frame. + * + * If low-precision buffers are enabled, this is the critical display port; + * otherwise, it's the same display port returned by GetDisplayPort(). + */ + static bool GetDisplayPortForVisibilityTesting(nsIContent* aContent, + nsRect* aResult); + + enum class RepaintMode : uint8_t { Repaint, DoNotRepaint }; + + /** + * Invalidate for displayport change. + */ + static void InvalidateForDisplayPortChange( + nsIContent* aContent, bool aHadDisplayPort, const nsRect& aOldDisplayPort, + const nsRect& aNewDisplayPort, + RepaintMode aRepaintMode = RepaintMode::Repaint); + + /** + * Set the display port margins for a content element to be used with a + * display port base (see SetDisplayPortBase()). + * See also nsIDOMWindowUtils.setDisplayPortMargins. + * @param aContent the content element for which to set the margins + * @param aPresShell the pres shell for the document containing the element + * @param aMargins the margins to set + * @param aAlignmentX, alignmentY the amount of pixels to which to align the + * displayport built by combining the base + * rect with the margins, in either direction + * @param aPriority a priority value to determine which margins take effect + * when multiple callers specify margins + * @param aRepaintMode whether to schedule a paint after setting the margins + * @return true if the new margins were applied. + */ + static bool SetDisplayPortMargins( + nsIContent* aContent, PresShell* aPresShell, + const DisplayPortMargins& aMargins, uint32_t aPriority = 0, + RepaintMode aRepaintMode = RepaintMode::Repaint); + + /** + * Set the display port base rect for given element to be used with display + * port margins. + * SetDisplayPortBaseIfNotSet is like SetDisplayPortBase except it only sets + * the display port base to aBase if no display port base is currently set. + */ + static void SetDisplayPortBase(nsIContent* aContent, const nsRect& aBase); + static void SetDisplayPortBaseIfNotSet(nsIContent* aContent, + const nsRect& aBase); + + /** + * Get the critical display port for the given element. + */ + static bool GetCriticalDisplayPort( + nsIContent* aContent, nsRect* aResult, + const DisplayPortOptions& aOptions = DisplayPortOptions()); + + /** + * Check whether the given element has a critical display port. + */ + static bool HasCriticalDisplayPort(nsIContent* aContent); + + /** + * If low-precision painting is turned on, delegates to + * GetCriticalDisplayPort. Otherwise, delegates to GetDisplayPort. + */ + static bool GetHighResolutionDisplayPort( + nsIContent* aContent, nsRect* aResult, + const DisplayPortOptions& aOptions = DisplayPortOptions()); + + /** + * Remove the displayport for the given element. + */ + static void RemoveDisplayPort(nsIContent* aContent); + + /** + * Return true if aPresContext's viewport has a displayport. + */ + static bool ViewportHasDisplayPort(nsPresContext* aPresContext); + + /** + * Return true if aFrame is a fixed-pos frame and is a child of a viewport + * which has a displayport. These frames get special treatment from the + * compositor. aDisplayPort, if non-null, is set to the display port rectangle + * (relative to the viewport). + */ + static bool IsFixedPosFrameInDisplayPort(const nsIFrame* aFrame); + + static bool MaybeCreateDisplayPortInFirstScrollFrameEncountered( + nsIFrame* aFrame, nsDisplayListBuilder* aBuilder); + + /** + * Calculate a default set of displayport margins for the given scrollframe + * and set them on the scrollframe's content element. The margins are set with + * the default priority, which may clobber previously set margins. The repaint + * mode provided is passed through to the call to SetDisplayPortMargins. + * The |aScrollFrame| parameter must be non-null and queryable to an nsIFrame. + * @return true iff the call to SetDisplayPortMargins returned true. + */ + static bool CalculateAndSetDisplayPortMargins( + nsIScrollableFrame* aScrollFrame, RepaintMode aRepaintMode); + + /** + * If |aScrollFrame| WantsAsyncScroll() and we don't have a scrollable + * displayport yet (as tracked by |aBuilder|), calculate and set a + * displayport. + * + * If this is called during display list building pass DoNotRepaint in + * aRepaintMode. + * + * Returns true if there is a displayport on an async scrollable scrollframe + * after this call, either because one was just added or it already existed. + */ + static bool MaybeCreateDisplayPort(nsDisplayListBuilder* aBuilder, + nsIFrame* aScrollFrame, + RepaintMode aRepaintMode); + + /** + * Sets a zero margin display port on all proper ancestors of aFrame that + * are async scrollable. + */ + static void SetZeroMarginDisplayPortOnAsyncScrollableAncestors( + nsIFrame* aFrame); + + /** + * Finds the closest ancestor async scrollable frame from aFrame that has a + * displayport and attempts to trigger the displayport expiry on that + * ancestor. + */ + static void ExpireDisplayPortOnAsyncScrollableAncestor(nsIFrame* aFrame); +}; + +} // namespace mozilla + +#endif // mozilla_DisplayPortUtils_h__ |