/* -*- 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 // for uint32_t, uint64_t #include "Units.h" // for CSSRect, CSSPixel, etc #include "mozilla/gfx/BasePoint.h" // for BasePoint #include "mozilla/gfx/Rect.h" // for RoundedIn #include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor namespace mozilla { namespace layers { /** * 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 { 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 ROOT_SCROLL_ID; // This is the root scroll frame. static const ViewID START_SCROLL_ID; // This is the ID that scrolling subframes // will begin at. FrameMetrics() : mCompositionBounds(0, 0, 0, 0) , mDisplayPort(0, 0, 0, 0) , mCriticalDisplayPort(0, 0, 0, 0) , mViewport(0, 0, 0, 0) , mScrollOffset(0, 0) , mScrollId(NULL_SCROLL_ID) , mScrollableRect(0, 0, 0, 0) , mResolution(1) , mZoom(1) , mDevPixelsPerCSSPixel(1) , mMayHaveTouchListeners(false) , mPresShellId(-1) {} // Default copy ctor and operator= are fine bool operator==(const FrameMetrics& aOther) const { return mCompositionBounds.IsEqualEdges(aOther.mCompositionBounds) && mDisplayPort.IsEqualEdges(aOther.mDisplayPort) && mCriticalDisplayPort.IsEqualEdges(aOther.mCriticalDisplayPort) && mViewport.IsEqualEdges(aOther.mViewport) && mScrollOffset == aOther.mScrollOffset && mScrollId == aOther.mScrollId && mScrollableRect.IsEqualEdges(aOther.mScrollableRect) && mResolution == aOther.mResolution && mDevPixelsPerCSSPixel == aOther.mDevPixelsPerCSSPixel && mMayHaveTouchListeners == aOther.mMayHaveTouchListeners && mPresShellId == aOther.mPresShellId; } bool operator!=(const FrameMetrics& aOther) const { return !operator==(aOther); } bool IsDefault() const { FrameMetrics def; def.mPresShellId = mPresShellId; return (def == *this); } bool IsRootScrollable() const { return mScrollId == ROOT_SCROLL_ID; } bool IsScrollable() const { return mScrollId != NULL_SCROLL_ID; } CSSToLayerScale LayersPixelsPerCSSPixel() const { return mResolution * mDevPixelsPerCSSPixel; } LayerPoint GetScrollOffsetInLayerPixels() const { return mScrollOffset * LayersPixelsPerCSSPixel(); } /** * Return the scale factor needed to fit the viewport * into its composition bounds. */ CSSToScreenScale CalculateIntrinsicScale() const { return CSSToScreenScale(float(mCompositionBounds.width) / float(mViewport.width)); } /** * Return the resolution that content should be rendered at given * the configuration in this metrics object: viewport dimensions, * zoom factor, etc. (The mResolution member of this metrics is * ignored.) */ CSSToScreenScale CalculateResolution() const { return CalculateIntrinsicScale() * mZoom; } CSSRect CalculateCompositedRectInCssPixels() const { return CSSRect(gfx::RoundedIn(mCompositionBounds / CalculateResolution())); } // --------------------------------------------------------------------------- // The following metrics are all in widget space/device pixels. // // This is the area within the widget that we're compositing to, which means // that it is the visible region of this frame. It is not relative to // anything. // So { 0, 0, [compositeArea.width], [compositeArea.height] }. // // 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 displayport is the same as the // viewport, there is no need for this and we can just use the viewport // instead. // // This is only valid on the root layer. Nested iframes do not need this // metric as they do not have a displayport set. See bug 775452. ScreenIntRect mCompositionBounds; // --------------------------------------------------------------------------- // The following metrics are all in CSS pixels. They are not in any uniform // space, so each is explained separately. // // The area of a frame's contents that has been painted, relative to the // viewport. It is in the same coordinate space as |mViewport|. For example, // if it is at 0,0, then it's at the same place at the viewport, which is at // the top-left in the layer, and at the same place as the scroll offset of // the document. // // 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 } // // This is only valid on the root layer. Nested iframes do not have a // displayport set on them. See bug 775452. 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 CSS viewport, which is the dimensions we're using to constrain the // 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 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; // A unique ID assigned to each scrollable frame (unless this is // ROOT_SCROLL_ID, in which case it is not unique). ViewID mScrollId; // 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 following metrics are dimensionless. // // The resolution, along both axes, that the current frame has been painted // at. // // Every time this frame is composited and the compositor samples its // transform, this metric is used to create a transform which is // post-multiplied into the parent's transform. Since this only happens when // we walk the layer tree, the resulting transform isn't stored here. Thus the // resolution of parent layers is opaque to this metric. LayoutDeviceToLayerScale mResolution; // The resolution-independent "user zoom". For example, if a page // configures the viewport to a zoom value of 2x, then this member // will always be 2.0 no matter what the viewport or composition // bounds. // // In the steady state (no animations), the following is usually true // // intrinsicScale = (mCompositionBounds / mViewport) // mResolution = mZoom * intrinsicScale / mDevPixelsPerCSSPixel // // When this is not true, we're probably asynchronously sampling a // zoom animation for content. ScreenToScreenScale mZoom; // 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; // Whether or not this frame may have touch listeners. bool mMayHaveTouchListeners; uint32_t mPresShellId; }; } } #endif /* GFX_FRAMEMETRICS_H */