diff options
Diffstat (limited to 'gfx/layers/FrameMetrics.h')
-rw-r--r-- | gfx/layers/FrameMetrics.h | 1112 |
1 files changed, 1112 insertions, 0 deletions
diff --git a/gfx/layers/FrameMetrics.h b/gfx/layers/FrameMetrics.h new file mode 100644 index 000000000..0261dbad7 --- /dev/null +++ b/gfx/layers/FrameMetrics.h @@ -0,0 +1,1112 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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 GFX_FRAMEMETRICS_H +#define GFX_FRAMEMETRICS_H + +#include <stdint.h> // for uint32_t, uint64_t +#include "Units.h" // for CSSRect, CSSPixel, etc +#include "mozilla/HashFunctions.h" // for HashGeneric +#include "mozilla/Maybe.h" +#include "mozilla/gfx/BasePoint.h" // for BasePoint +#include "mozilla/gfx/Rect.h" // for RoundedIn +#include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor +#include "mozilla/gfx/Logging.h" // for Log +#include "mozilla/StaticPtr.h" // for StaticAutoPtr +#include "mozilla/TimeStamp.h" // for TimeStamp +#include "nsString.h" +#include "nsStyleCoord.h" // for nsStyleCoord + +namespace IPC { +template <typename T> struct ParamTraits; +} // namespace IPC + +namespace mozilla { +namespace layers { + +/** + * Helper struct to hold a couple of fields that can be updated as part of + * an empty transaction. + */ +struct ScrollUpdateInfo { + uint32_t mScrollGeneration; + CSSPoint mScrollOffset; +}; + +/** + * The viewport and displayport metrics for the painted frame at the + * time of a layer-tree transaction. These metrics are especially + * useful for shadow layers, because the metrics values are updated + * atomically with new pixels. + */ +struct FrameMetrics { + friend struct IPC::ParamTraits<mozilla::layers::FrameMetrics>; +public: + // We use IDs to identify frames across processes. + typedef uint64_t ViewID; + static const ViewID NULL_SCROLL_ID; // This container layer does not scroll. + static const ViewID START_SCROLL_ID = 2; // This is the ID that scrolling subframes + // will begin at. + + enum ScrollOffsetUpdateType : uint8_t { + eNone, // The default; the scroll offset was not updated + eMainThread, // The scroll offset was updated by the main thread. + ePending, // The scroll offset was updated on the main thread, but not + // painted, so the layer texture data is still at the old + // offset. + eUserAction, // In an APZ repaint request, this means the APZ generated + // the scroll position based on user action (the alternative + // is eNone which means it's just request a repaint because + // it got a scroll update from the main thread). + eRestore, // The scroll offset was updated by the main thread, but as + // a restore from history or after a frame reconstruction. + // In this case, APZ can ignore the offset change if the + // user has done an APZ scroll already. + + eSentinel // For IPC use only + }; + + FrameMetrics() + : mScrollId(NULL_SCROLL_ID) + , mPresShellResolution(1) + , mCompositionBounds(0, 0, 0, 0) + , mDisplayPort(0, 0, 0, 0) + , mCriticalDisplayPort(0, 0, 0, 0) + , mScrollableRect(0, 0, 0, 0) + , mCumulativeResolution() + , mDevPixelsPerCSSPixel(1) + , mScrollOffset(0, 0) + , mZoom() + , mScrollGeneration(0) + , mSmoothScrollOffset(0, 0) + , mRootCompositionSize(0, 0) + , mDisplayPortMargins(0, 0, 0, 0) + , mPresShellId(-1) + , mViewport(0, 0, 0, 0) + , mExtraResolution() + , mPaintRequestTime() + , mScrollUpdateType(eNone) + , mIsRootContent(false) + , mDoSmoothScroll(false) + , mUseDisplayPortMargins(false) + , mIsScrollInfoLayer(false) + { + } + + // Default copy ctor and operator= are fine + + bool operator==(const FrameMetrics& aOther) const + { + // Put mScrollId at the top since it's the most likely one to fail. + return mScrollId == aOther.mScrollId && + mPresShellResolution == aOther.mPresShellResolution && + mCompositionBounds.IsEqualEdges(aOther.mCompositionBounds) && + mDisplayPort.IsEqualEdges(aOther.mDisplayPort) && + mCriticalDisplayPort.IsEqualEdges(aOther.mCriticalDisplayPort) && + mScrollableRect.IsEqualEdges(aOther.mScrollableRect) && + mCumulativeResolution == aOther.mCumulativeResolution && + mDevPixelsPerCSSPixel == aOther.mDevPixelsPerCSSPixel && + mScrollOffset == aOther.mScrollOffset && + // don't compare mZoom + mScrollGeneration == aOther.mScrollGeneration && + mSmoothScrollOffset == aOther.mSmoothScrollOffset && + mRootCompositionSize == aOther.mRootCompositionSize && + mDisplayPortMargins == aOther.mDisplayPortMargins && + mPresShellId == aOther.mPresShellId && + mViewport.IsEqualEdges(aOther.mViewport) && + mExtraResolution == aOther.mExtraResolution && + mPaintRequestTime == aOther.mPaintRequestTime && + mScrollUpdateType == aOther.mScrollUpdateType && + mIsRootContent == aOther.mIsRootContent && + mDoSmoothScroll == aOther.mDoSmoothScroll && + mUseDisplayPortMargins == aOther.mUseDisplayPortMargins && + mIsScrollInfoLayer == aOther.mIsScrollInfoLayer; + } + + bool operator!=(const FrameMetrics& aOther) const + { + return !operator==(aOther); + } + + bool IsScrollable() const + { + return mScrollId != NULL_SCROLL_ID; + } + + CSSToScreenScale2D DisplayportPixelsPerCSSPixel() const + { + // Note: use 'mZoom * ParentLayerToLayerScale(1.0f)' as the CSS-to-Layer scale + // instead of LayersPixelsPerCSSPixel(), because displayport calculations + // are done in the context of a repaint request, where we ask Layout to + // repaint at a new resolution that includes any async zoom. Until this + // repaint request is processed, LayersPixelsPerCSSPixel() does not yet + // include the async zoom, but it will when the displayport is interpreted + // for the repaint. + return mZoom * ParentLayerToLayerScale(1.0f) / mExtraResolution; + } + + CSSToLayerScale2D LayersPixelsPerCSSPixel() const + { + return mDevPixelsPerCSSPixel * mCumulativeResolution; + } + + // Get the amount by which this frame has been zoomed since the last repaint. + LayerToParentLayerScale GetAsyncZoom() const + { + // The async portion of the zoom should be the same along the x and y + // axes. + return (mZoom / LayersPixelsPerCSSPixel()).ToScaleFactor(); + } + + // Ensure the scrollableRect is at least as big as the compositionBounds + // because the scrollableRect can be smaller if the content is not large + // and the scrollableRect hasn't been updated yet. + // We move the scrollableRect up because we don't know if we can move it + // down. i.e. we know that scrollableRect can go back as far as zero. + // but we don't know how much further ahead it can go. + CSSRect GetExpandedScrollableRect() const + { + CSSRect scrollableRect = mScrollableRect; + CSSSize compSize = CalculateCompositedSizeInCssPixels(); + if (scrollableRect.width < compSize.width) { + scrollableRect.x = std::max(0.f, + scrollableRect.x - (compSize.width - scrollableRect.width)); + scrollableRect.width = compSize.width; + } + + if (scrollableRect.height < compSize.height) { + scrollableRect.y = std::max(0.f, + scrollableRect.y - (compSize.height - scrollableRect.height)); + scrollableRect.height = compSize.height; + } + + return scrollableRect; + } + + CSSSize CalculateCompositedSizeInCssPixels() const + { + if (GetZoom() == CSSToParentLayerScale2D(0, 0)) { + return CSSSize(); // avoid division by zero + } + return mCompositionBounds.Size() / GetZoom(); + } + + CSSRect CalculateCompositedRectInCssPixels() const + { + if (GetZoom() == CSSToParentLayerScale2D(0, 0)) { + return CSSRect(); // avoid division by zero + } + return mCompositionBounds / GetZoom(); + } + + CSSSize CalculateBoundedCompositedSizeInCssPixels() const + { + CSSSize size = CalculateCompositedSizeInCssPixels(); + size.width = std::min(size.width, mRootCompositionSize.width); + size.height = std::min(size.height, mRootCompositionSize.height); + return size; + } + + CSSRect CalculateScrollRange() const + { + CSSSize scrollPortSize = CalculateCompositedSizeInCssPixels(); + CSSRect scrollRange = mScrollableRect; + scrollRange.width = std::max(scrollRange.width - scrollPortSize.width, 0.0f); + scrollRange.height = std::max(scrollRange.height - scrollPortSize.height, 0.0f); + return scrollRange; + } + + void ScrollBy(const CSSPoint& aPoint) + { + mScrollOffset += aPoint; + } + + void ZoomBy(float aScale) + { + ZoomBy(gfxSize(aScale, aScale)); + } + + void ZoomBy(const gfxSize& aScale) + { + mZoom.xScale *= aScale.width; + mZoom.yScale *= aScale.height; + } + + void CopyScrollInfoFrom(const FrameMetrics& aOther) + { + mScrollOffset = aOther.mScrollOffset; + mScrollGeneration = aOther.mScrollGeneration; + } + + void CopySmoothScrollInfoFrom(const FrameMetrics& aOther) + { + mSmoothScrollOffset = aOther.mSmoothScrollOffset; + mScrollGeneration = aOther.mScrollGeneration; + mDoSmoothScroll = aOther.mDoSmoothScroll; + } + + void UpdatePendingScrollInfo(const ScrollUpdateInfo& aInfo) + { + mScrollOffset = aInfo.mScrollOffset; + mScrollGeneration = aInfo.mScrollGeneration; + mScrollUpdateType = ePending; + } + + void SetRepaintDrivenByUserAction(bool aUserAction) + { + mScrollUpdateType = aUserAction ? eUserAction : eNone; + } + +public: + void SetPresShellResolution(float aPresShellResolution) + { + mPresShellResolution = aPresShellResolution; + } + + float GetPresShellResolution() const + { + return mPresShellResolution; + } + + void SetCompositionBounds(const ParentLayerRect& aCompositionBounds) + { + mCompositionBounds = aCompositionBounds; + } + + const ParentLayerRect& GetCompositionBounds() const + { + return mCompositionBounds; + } + + void SetDisplayPort(const CSSRect& aDisplayPort) + { + mDisplayPort = aDisplayPort; + } + + const CSSRect& GetDisplayPort() const + { + return mDisplayPort; + } + + void SetCriticalDisplayPort(const CSSRect& aCriticalDisplayPort) + { + mCriticalDisplayPort = aCriticalDisplayPort; + } + + const CSSRect& GetCriticalDisplayPort() const + { + return mCriticalDisplayPort; + } + + void SetCumulativeResolution(const LayoutDeviceToLayerScale2D& aCumulativeResolution) + { + mCumulativeResolution = aCumulativeResolution; + } + + const LayoutDeviceToLayerScale2D& GetCumulativeResolution() const + { + return mCumulativeResolution; + } + + void SetDevPixelsPerCSSPixel(const CSSToLayoutDeviceScale& aDevPixelsPerCSSPixel) + { + mDevPixelsPerCSSPixel = aDevPixelsPerCSSPixel; + } + + const CSSToLayoutDeviceScale& GetDevPixelsPerCSSPixel() const + { + return mDevPixelsPerCSSPixel; + } + + void SetIsRootContent(bool aIsRootContent) + { + mIsRootContent = aIsRootContent; + } + + bool IsRootContent() const + { + return mIsRootContent; + } + + void SetScrollOffset(const CSSPoint& aScrollOffset) + { + mScrollOffset = aScrollOffset; + } + + const CSSPoint& GetScrollOffset() const + { + return mScrollOffset; + } + + void SetSmoothScrollOffset(const CSSPoint& aSmoothScrollDestination) + { + mSmoothScrollOffset = aSmoothScrollDestination; + } + + const CSSPoint& GetSmoothScrollOffset() const + { + return mSmoothScrollOffset; + } + + void SetZoom(const CSSToParentLayerScale2D& aZoom) + { + mZoom = aZoom; + } + + const CSSToParentLayerScale2D& GetZoom() const + { + return mZoom; + } + + void SetScrollOffsetUpdated(uint32_t aScrollGeneration) + { + mScrollUpdateType = eMainThread; + mScrollGeneration = aScrollGeneration; + } + + void SetScrollOffsetRestored(uint32_t aScrollGeneration) + { + mScrollUpdateType = eRestore; + mScrollGeneration = aScrollGeneration; + } + + void SetSmoothScrollOffsetUpdated(int32_t aScrollGeneration) + { + mDoSmoothScroll = true; + mScrollGeneration = aScrollGeneration; + } + + ScrollOffsetUpdateType GetScrollUpdateType() const + { + return mScrollUpdateType; + } + + bool GetScrollOffsetUpdated() const + { + return mScrollUpdateType != eNone; + } + + bool GetDoSmoothScroll() const + { + return mDoSmoothScroll; + } + + uint32_t GetScrollGeneration() const + { + return mScrollGeneration; + } + + ViewID GetScrollId() const + { + return mScrollId; + } + + void SetScrollId(ViewID scrollId) + { + mScrollId = scrollId; + } + + void SetRootCompositionSize(const CSSSize& aRootCompositionSize) + { + mRootCompositionSize = aRootCompositionSize; + } + + const CSSSize& GetRootCompositionSize() const + { + return mRootCompositionSize; + } + + void SetDisplayPortMargins(const ScreenMargin& aDisplayPortMargins) + { + mDisplayPortMargins = aDisplayPortMargins; + } + + const ScreenMargin& GetDisplayPortMargins() const + { + return mDisplayPortMargins; + } + + void SetUseDisplayPortMargins(bool aValue) + { + mUseDisplayPortMargins = aValue; + } + + bool GetUseDisplayPortMargins() const + { + return mUseDisplayPortMargins; + } + + uint32_t GetPresShellId() const + { + return mPresShellId; + } + + void SetPresShellId(uint32_t aPresShellId) + { + mPresShellId = aPresShellId; + } + + void SetViewport(const CSSRect& aViewport) + { + mViewport = aViewport; + } + + const CSSRect& GetViewport() const + { + return mViewport; + } + + void SetExtraResolution(const ScreenToLayerScale2D& aExtraResolution) + { + mExtraResolution = aExtraResolution; + } + + const ScreenToLayerScale2D& GetExtraResolution() const + { + return mExtraResolution; + } + + const CSSRect& GetScrollableRect() const + { + return mScrollableRect; + } + + void SetScrollableRect(const CSSRect& aScrollableRect) + { + mScrollableRect = aScrollableRect; + } + + void SetPaintRequestTime(const TimeStamp& aTime) { + mPaintRequestTime = aTime; + } + const TimeStamp& GetPaintRequestTime() const { + return mPaintRequestTime; + } + + void SetIsScrollInfoLayer(bool aIsScrollInfoLayer) { + mIsScrollInfoLayer = aIsScrollInfoLayer; + } + bool IsScrollInfoLayer() const { + return mIsScrollInfoLayer; + } + +private: + // A unique ID assigned to each scrollable frame. + ViewID mScrollId; + + // The pres-shell resolution that has been induced on the document containing + // this scroll frame as a result of zooming this scroll frame (whether via + // user action, or choosing an initial zoom level on page load). This can + // only be different from 1.0 for frames that are zoomable, which currently + // is just the root content document's root scroll frame (mIsRoot = true). + // This is a plain float rather than a ScaleFactor because in and of itself + // it does not convert between any coordinate spaces for which we have names. + float mPresShellResolution; + + // This is the area within the widget that we're compositing to. It is in the + // same coordinate space as the reference frame for the scrolled frame. + // + // This is useful because, on mobile, the viewport and composition dimensions + // are not always the same. In this case, we calculate the displayport using + // an area bigger than the region we're compositing to. If we used the + // viewport dimensions to calculate the displayport, we'd run into situations + // where we're prerendering the wrong regions and the content may be clipped, + // or too much of it prerendered. If the composition dimensions are the same + // as the viewport dimensions, there is no need for this and we can just use + // the viewport instead. + // + // This value is valid for nested scrollable layers as well, and is still + // relative to the layer tree origin. This value is provided by Gecko at + // layout/paint time. + ParentLayerRect mCompositionBounds; + + // The area of a frame's contents that has been painted, relative to + // mCompositionBounds. + // + // Note that this is structured in such a way that it doesn't depend on the + // method layout uses to scroll content. + // + // May be larger or smaller than |mScrollableRect|. + // + // To pre-render a margin of 100 CSS pixels around the window, + // { x = -100, y = - 100, + // width = window.innerWidth + 200, height = window.innerHeight + 200 } + CSSRect mDisplayPort; + + // If non-empty, the area of a frame's contents that is considered critical + // to paint. Area outside of this area (i.e. area inside mDisplayPort, but + // outside of mCriticalDisplayPort) is considered low-priority, and may be + // painted with lower precision, or not painted at all. + // + // The same restrictions for mDisplayPort apply here. + CSSRect mCriticalDisplayPort; + + // The scrollable bounds of a frame. This is determined by reflow. + // Ordinarily the x and y will be 0 and the width and height will be the + // size of the element being scrolled. However for RTL pages or elements + // the x value may be negative. + // + // This is relative to the document. It is in the same coordinate space as + // |mScrollOffset|, but a different coordinate space than |mViewport| and + // |mDisplayPort|. Note also that this coordinate system is understood by + // window.scrollTo(). + // + // This is valid on any layer unless it has no content. + CSSRect mScrollableRect; + + // The cumulative resolution that the current frame has been painted at. + // This is the product of the pres-shell resolutions of the document + // containing this scroll frame and its ancestors, and any css-driven + // resolution. This information is provided by Gecko at layout/paint time. + // Note that this is allowed to have different x- and y-scales, but only + // for subframes (mIsRoot = false). (The same applies to other scales that + // "inherit" the 2D-ness of this one, such as mZoom.) + LayoutDeviceToLayerScale2D mCumulativeResolution; + + // New fields from now on should be made private and old fields should + // be refactored to be private. + + // The conversion factor between CSS pixels and device pixels for this frame. + // This can vary based on a variety of things, such as reflowing-zoom. The + // conversion factor for device pixels to layers pixels is just the + // resolution. + CSSToLayoutDeviceScale mDevPixelsPerCSSPixel; + + // The position of the top-left of the CSS viewport, relative to the document + // (or the document relative to the viewport, if that helps understand it). + // + // Thus it is relative to the document. It is in the same coordinate space as + // |mScrollableRect|, but a different coordinate space than |mViewport| and + // |mDisplayPort|. + // + // It is required that the rect: + // { x = mScrollOffset.x, y = mScrollOffset.y, + // width = mCompositionBounds.x / mResolution.scale, + // height = mCompositionBounds.y / mResolution.scale } + // Be within |mScrollableRect|. + // + // This is valid for any layer, but is always relative to this frame and + // not any parents, regardless of parent transforms. + CSSPoint mScrollOffset; + + // The "user zoom". Content is painted by gecko at mResolution * mDevPixelsPerCSSPixel, + // but will be drawn to the screen at mZoom. In the steady state, the + // two will be the same, but during an async zoom action the two may + // diverge. This information is initialized in Gecko but updated in the APZC. + CSSToParentLayerScale2D mZoom; + + // The scroll generation counter used to acknowledge the scroll offset update. + uint32_t mScrollGeneration; + + // If mDoSmoothScroll is true, the scroll offset will be animated smoothly + // to this value. + CSSPoint mSmoothScrollOffset; + + // The size of the root scrollable's composition bounds, but in local CSS pixels. + CSSSize mRootCompositionSize; + + // A display port expressed as layer margins that apply to the rect of what + // is drawn of the scrollable element. + ScreenMargin mDisplayPortMargins; + + uint32_t mPresShellId; + + // The CSS viewport, which is the dimensions we're using to constrain the + // <html> element of this frame, relative to the top-left of the layer. Note + // that its offset is structured in such a way that it doesn't depend on the + // method layout uses to scroll content. + // + // This is mainly useful on the root layer, however nested iframes can have + // their own viewport, which will just be the size of the window of the + // iframe. For layers that don't correspond to a document, this metric is + // meaningless and invalid. + CSSRect mViewport; + + // The extra resolution at which content in this scroll frame is drawn beyond + // that necessary to draw one Layer pixel per Screen pixel. + ScreenToLayerScale2D mExtraResolution; + + // The time at which the APZC last requested a repaint for this scrollframe. + TimeStamp mPaintRequestTime; + + // Whether mScrollOffset was updated by something other than the APZ code, and + // if the APZC receiving this metrics should update its local copy. + ScrollOffsetUpdateType mScrollUpdateType; + + // Whether or not this is the root scroll frame for the root content document. + bool mIsRootContent:1; + + // When mDoSmoothScroll, the scroll offset should be animated to + // smoothly transition to mScrollOffset rather than be updated instantly. + bool mDoSmoothScroll:1; + + // If this is true then we use the display port margins on this metrics, + // otherwise use the display port rect. + bool mUseDisplayPortMargins:1; + + // Whether or not this frame has a "scroll info layer" to capture events. + bool mIsScrollInfoLayer:1; + + // WARNING!!!! + // + // When adding a new field: + // + // - First, consider whether the field can be added to ScrollMetadata + // instead. If so, prefer that. + // + // - Otherwise, the following places should be updated to include them + // (as needed): + // FrameMetrics::operator == + // AsyncPanZoomController::NotifyLayersUpdated + // The ParamTraits specialization in GfxMessageUtils.h + // + // Please add new fields above this comment. + + // Private helpers for IPC purposes + void SetDoSmoothScroll(bool aValue) { + mDoSmoothScroll = aValue; + } +}; + +struct ScrollSnapInfo { + ScrollSnapInfo() + : mScrollSnapTypeX(NS_STYLE_SCROLL_SNAP_TYPE_NONE) + , mScrollSnapTypeY(NS_STYLE_SCROLL_SNAP_TYPE_NONE) + {} + + bool operator==(const ScrollSnapInfo& aOther) const + { + return mScrollSnapTypeX == aOther.mScrollSnapTypeX && + mScrollSnapTypeY == aOther.mScrollSnapTypeY && + mScrollSnapIntervalX == aOther.mScrollSnapIntervalX && + mScrollSnapIntervalY == aOther.mScrollSnapIntervalY && + mScrollSnapDestination == aOther.mScrollSnapDestination && + mScrollSnapCoordinates == aOther.mScrollSnapCoordinates; + } + + // The scroll frame's scroll-snap-type. + // One of NS_STYLE_SCROLL_SNAP_{NONE, MANDATORY, PROXIMITY}. + uint8_t mScrollSnapTypeX; + uint8_t mScrollSnapTypeY; + + // The intervals derived from the scroll frame's scroll-snap-points. + Maybe<nscoord> mScrollSnapIntervalX; + Maybe<nscoord> mScrollSnapIntervalY; + + // The scroll frame's scroll-snap-destination, in cooked form (to avoid + // shipping the raw nsStyleCoord::CalcValue over IPC). + nsPoint mScrollSnapDestination; + + // The scroll-snap-coordinates of any descendant frames of the scroll frame, + // relative to the origin of the scrolled frame. + nsTArray<nsPoint> mScrollSnapCoordinates; +}; + +/** + * A clip that applies to a layer, that may be scrolled by some of the + * scroll frames associated with the layer. + */ +struct LayerClip { + friend struct IPC::ParamTraits<mozilla::layers::LayerClip>; + +public: + LayerClip() + : mClipRect() + , mMaskLayerIndex() + {} + + explicit LayerClip(const ParentLayerIntRect& aClipRect) + : mClipRect(aClipRect) + , mMaskLayerIndex() + {} + + bool operator==(const LayerClip& aOther) const + { + return mClipRect == aOther.mClipRect && + mMaskLayerIndex == aOther.mMaskLayerIndex; + } + + void SetClipRect(const ParentLayerIntRect& aClipRect) { + mClipRect = aClipRect; + } + const ParentLayerIntRect& GetClipRect() const { + return mClipRect; + } + + void SetMaskLayerIndex(const Maybe<size_t>& aIndex) { + mMaskLayerIndex = aIndex; + } + const Maybe<size_t>& GetMaskLayerIndex() const { + return mMaskLayerIndex; + } + +private: + ParentLayerIntRect mClipRect; + + // Optionally, specifies a mask layer that's part of the clip. + // This is an index into the MetricsMaskLayers array on the Layer. + Maybe<size_t> mMaskLayerIndex; +}; + +typedef Maybe<LayerClip> MaybeLayerClip; // for passing over IPDL + +/** + * Metadata about a scroll frame that's stored in the layer tree for use by + * the compositor (including APZ). This includes the scroll frame's FrameMetrics, + * as well as other metadata. We don't put the other metadata into FrameMetrics + * to avoid FrameMetrics becoming too bloated (as a FrameMetrics is e.g. sent + * over IPC for every repaint request for every active scroll frame). + */ +struct ScrollMetadata { + friend struct IPC::ParamTraits<mozilla::layers::ScrollMetadata>; + + typedef FrameMetrics::ViewID ViewID; +public: + static StaticAutoPtr<const ScrollMetadata> sNullMetadata; // We sometimes need an empty metadata + + ScrollMetadata() + : mMetrics() + , mSnapInfo() + , mScrollParentId(FrameMetrics::NULL_SCROLL_ID) + , mBackgroundColor() + , mContentDescription() + , mLineScrollAmount(0, 0) + , mPageScrollAmount(0, 0) + , mScrollClip() + , mHasScrollgrab(false) + , mAllowVerticalScrollWithWheel(false) + , mIsLayersIdRoot(false) + , mUsesContainerScrolling(false) + , mForceDisableApz(false) + {} + + bool operator==(const ScrollMetadata& aOther) const + { + return mMetrics == aOther.mMetrics && + mSnapInfo == aOther.mSnapInfo && + mScrollParentId == aOther.mScrollParentId && + mBackgroundColor == aOther.mBackgroundColor && + // don't compare mContentDescription + mLineScrollAmount == aOther.mLineScrollAmount && + mPageScrollAmount == aOther.mPageScrollAmount && + mScrollClip == aOther.mScrollClip && + mHasScrollgrab == aOther.mHasScrollgrab && + mAllowVerticalScrollWithWheel == aOther.mAllowVerticalScrollWithWheel && + mIsLayersIdRoot == aOther.mIsLayersIdRoot && + mUsesContainerScrolling == aOther.mUsesContainerScrolling && + mForceDisableApz == aOther.mForceDisableApz; + } + + bool operator!=(const ScrollMetadata& aOther) const + { + return !operator==(aOther); + } + + bool IsDefault() const + { + ScrollMetadata def; + + def.mMetrics.SetPresShellId(mMetrics.GetPresShellId()); + return (def == *this); + } + + FrameMetrics& GetMetrics() { return mMetrics; } + const FrameMetrics& GetMetrics() const { return mMetrics; } + + void SetSnapInfo(ScrollSnapInfo&& aSnapInfo) { + mSnapInfo = Move(aSnapInfo); + } + const ScrollSnapInfo& GetSnapInfo() const { return mSnapInfo; } + + ViewID GetScrollParentId() const { + return mScrollParentId; + } + + void SetScrollParentId(ViewID aParentId) { + mScrollParentId = aParentId; + } + const gfx::Color& GetBackgroundColor() const { + return mBackgroundColor; + } + void SetBackgroundColor(const gfx::Color& aBackgroundColor) { + mBackgroundColor = aBackgroundColor; + } + const nsCString& GetContentDescription() const { + return mContentDescription; + } + void SetContentDescription(const nsCString& aContentDescription) { + mContentDescription = aContentDescription; + } + const LayoutDeviceIntSize& GetLineScrollAmount() const { + return mLineScrollAmount; + } + void SetLineScrollAmount(const LayoutDeviceIntSize& size) { + mLineScrollAmount = size; + } + const LayoutDeviceIntSize& GetPageScrollAmount() const { + return mPageScrollAmount; + } + void SetPageScrollAmount(const LayoutDeviceIntSize& size) { + mPageScrollAmount = size; + } + + void SetScrollClip(const Maybe<LayerClip>& aScrollClip) { + mScrollClip = aScrollClip; + } + const Maybe<LayerClip>& GetScrollClip() const { + return mScrollClip; + } + bool HasScrollClip() const { + return mScrollClip.isSome(); + } + const LayerClip& ScrollClip() const { + return mScrollClip.ref(); + } + LayerClip& ScrollClip() { + return mScrollClip.ref(); + } + + bool HasMaskLayer() const { + return HasScrollClip() && ScrollClip().GetMaskLayerIndex(); + } + Maybe<ParentLayerIntRect> GetClipRect() const { + return mScrollClip.isSome() ? Some(mScrollClip->GetClipRect()) : Nothing(); + } + + void SetHasScrollgrab(bool aHasScrollgrab) { + mHasScrollgrab = aHasScrollgrab; + } + bool GetHasScrollgrab() const { + return mHasScrollgrab; + } + bool AllowVerticalScrollWithWheel() const { + return mAllowVerticalScrollWithWheel; + } + void SetAllowVerticalScrollWithWheel(bool aValue) { + mAllowVerticalScrollWithWheel = aValue; + } + void SetIsLayersIdRoot(bool aValue) { + mIsLayersIdRoot = aValue; + } + bool IsLayersIdRoot() const { + return mIsLayersIdRoot; + } + // Implemented out of line because the implementation needs gfxPrefs.h + // and we don't want to include that from FrameMetrics.h. + void SetUsesContainerScrolling(bool aValue); + bool UsesContainerScrolling() const { + return mUsesContainerScrolling; + } + void SetForceDisableApz(bool aForceDisable) { + mForceDisableApz = aForceDisable; + } + bool IsApzForceDisabled() const { + return mForceDisableApz; + } + +private: + FrameMetrics mMetrics; + + // Information used to determine where to snap to for a given scroll. + ScrollSnapInfo mSnapInfo; + + // The ViewID of the scrollable frame to which overscroll should be handed off. + ViewID mScrollParentId; + + // The background color to use when overscrolling. + gfx::Color mBackgroundColor; + + // A description of the content element corresponding to this frame. + // This is empty unless this is a scrollable layer and the + // apz.printtree pref is turned on. + nsCString mContentDescription; + + // The value of GetLineScrollAmount(), for scroll frames. + LayoutDeviceIntSize mLineScrollAmount; + + // The value of GetPageScrollAmount(), for scroll frames. + LayoutDeviceIntSize mPageScrollAmount; + + // A clip to apply when compositing the layer bearing this ScrollMetadata, + // after applying any transform arising from scrolling this scroll frame. + // Note that, unlike most other fields of ScrollMetadata, this is allowed + // to differ between different layers scrolled by the same scroll frame. + // TODO: Group the fields of ScrollMetadata into sub-structures to separate + // fields with this property better. + Maybe<LayerClip> mScrollClip; + + // Whether or not this frame is for an element marked 'scrollgrab'. + bool mHasScrollgrab:1; + + // Whether or not the frame can be vertically scrolled with a mouse wheel. + bool mAllowVerticalScrollWithWheel:1; + + // Whether these framemetrics are for the root scroll frame (root element if + // we don't have a root scroll frame) for its layers id. + bool mIsLayersIdRoot:1; + + // True if scrolling using containers, false otherwise. This can be removed + // when containerful scrolling is eliminated. + bool mUsesContainerScrolling:1; + + // Whether or not the compositor should actually do APZ-scrolling on this + // scrollframe. + bool mForceDisableApz:1; + + // WARNING!!!! + // + // When adding new fields to ScrollMetadata, the following places should be + // updated to include them (as needed): + // ScrollMetadata::operator == + // AsyncPanZoomController::NotifyLayersUpdated + // The ParamTraits specialization in GfxMessageUtils.h + // + // Please add new fields above this comment. +}; + +/** + * This class allows us to uniquely identify a scrollable layer. The + * mLayersId identifies the layer tree (corresponding to a child process + * and/or tab) that the scrollable layer belongs to. The mPresShellId + * is a temporal identifier (corresponding to the document loaded that + * contains the scrollable layer, which may change over time). The + * mScrollId corresponds to the actual frame that is scrollable. + */ +struct ScrollableLayerGuid { + uint64_t mLayersId; + uint32_t mPresShellId; + FrameMetrics::ViewID mScrollId; + + ScrollableLayerGuid() + : mLayersId(0) + , mPresShellId(0) + , mScrollId(0) + { + } + + ScrollableLayerGuid(uint64_t aLayersId, uint32_t aPresShellId, + FrameMetrics::ViewID aScrollId) + : mLayersId(aLayersId) + , mPresShellId(aPresShellId) + , mScrollId(aScrollId) + { + } + + ScrollableLayerGuid(uint64_t aLayersId, const FrameMetrics& aMetrics) + : mLayersId(aLayersId) + , mPresShellId(aMetrics.GetPresShellId()) + , mScrollId(aMetrics.GetScrollId()) + { + } + + ScrollableLayerGuid(const ScrollableLayerGuid& other) + : mLayersId(other.mLayersId) + , mPresShellId(other.mPresShellId) + , mScrollId(other.mScrollId) + { + } + + ~ScrollableLayerGuid() + { + } + + bool operator==(const ScrollableLayerGuid& other) const + { + return mLayersId == other.mLayersId + && mPresShellId == other.mPresShellId + && mScrollId == other.mScrollId; + } + + bool operator!=(const ScrollableLayerGuid& other) const + { + return !(*this == other); + } + + bool operator<(const ScrollableLayerGuid& other) const + { + if (mLayersId < other.mLayersId) { + return true; + } + if (mLayersId == other.mLayersId) { + if (mPresShellId < other.mPresShellId) { + return true; + } + if (mPresShellId == other.mPresShellId) { + return mScrollId < other.mScrollId; + } + } + return false; + } + + uint32_t Hash() const + { + return HashGeneric(mLayersId, mPresShellId, mScrollId); + } +}; + +template <int LogLevel> +gfx::Log<LogLevel>& operator<<(gfx::Log<LogLevel>& log, const ScrollableLayerGuid& aGuid) { + return log << '(' << aGuid.mLayersId << ',' << aGuid.mPresShellId << ',' << aGuid.mScrollId << ')'; +} + +struct ZoomConstraints { + bool mAllowZoom; + bool mAllowDoubleTapZoom; + CSSToParentLayerScale mMinZoom; + CSSToParentLayerScale mMaxZoom; + + ZoomConstraints() + : mAllowZoom(true) + , mAllowDoubleTapZoom(true) + { + MOZ_COUNT_CTOR(ZoomConstraints); + } + + ZoomConstraints(bool aAllowZoom, + bool aAllowDoubleTapZoom, + const CSSToParentLayerScale& aMinZoom, + const CSSToParentLayerScale& aMaxZoom) + : mAllowZoom(aAllowZoom) + , mAllowDoubleTapZoom(aAllowDoubleTapZoom) + , mMinZoom(aMinZoom) + , mMaxZoom(aMaxZoom) + { + MOZ_COUNT_CTOR(ZoomConstraints); + } + + ZoomConstraints(const ZoomConstraints& other) + : mAllowZoom(other.mAllowZoom) + , mAllowDoubleTapZoom(other.mAllowDoubleTapZoom) + , mMinZoom(other.mMinZoom) + , mMaxZoom(other.mMaxZoom) + { + MOZ_COUNT_CTOR(ZoomConstraints); + } + + ~ZoomConstraints() + { + MOZ_COUNT_DTOR(ZoomConstraints); + } + + bool operator==(const ZoomConstraints& other) const + { + return mAllowZoom == other.mAllowZoom + && mAllowDoubleTapZoom == other.mAllowDoubleTapZoom + && mMinZoom == other.mMinZoom + && mMaxZoom == other.mMaxZoom; + } + + bool operator!=(const ZoomConstraints& other) const + { + return !(*this == other); + } +}; + +typedef Maybe<ZoomConstraints> MaybeZoomConstraints; + +} // namespace layers +} // namespace mozilla + +#endif /* GFX_FRAMEMETRICS_H */ |