зеркало из https://github.com/mozilla/gecko-dev.git
357 строки
13 KiB
C++
357 строки
13 KiB
C++
/* -*- 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 nsPresContext;
|
|
|
|
namespace mozilla {
|
|
|
|
class nsDisplayListBuilder;
|
|
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 whether the given element has a non-minimal displayport.
|
|
*/
|
|
static bool HasNonMinimalDisplayPort(nsIContent* aContent);
|
|
|
|
/**
|
|
* Check whether the given element has a non-minimal displayport that also has
|
|
* non-zero margins. A display port rect is considered non-minimal non-zero.
|
|
*/
|
|
static bool HasNonMinimalNonZeroDisplayPort(nsIContent* aContent);
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
enum class ClearMinimalDisplayPortProperty { No, Yes };
|
|
|
|
static bool SetDisplayPortMargins(
|
|
nsIContent* aContent, PresShell* aPresShell,
|
|
const DisplayPortMargins& aMargins,
|
|
ClearMinimalDisplayPortProperty aClearMinimalDisplayPortProperty,
|
|
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);
|
|
|
|
/**
|
|
* Returns root displayport base rect for |aPresShell|. In the case where
|
|
* |aPresShell| is in an out-of-process iframe, this function may return
|
|
* Nothing() if we haven't received the iframe's visible rect from the parent
|
|
* content.
|
|
* |aPresShell| should be top level content or in-process root or root in the
|
|
* browser process.
|
|
*/
|
|
static Maybe<nsRect> GetRootDisplayportBase(PresShell* aPresShell);
|
|
};
|
|
|
|
} // namespace mozilla
|
|
|
|
#endif // mozilla_DisplayPortUtils_h__
|