gfx/layers/FrameMetrics.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef GFX_FRAMEMETRICS_H
     7 #define GFX_FRAMEMETRICS_H
     9 #include <stdint.h>                     // for uint32_t, uint64_t
    10 #include <string>                       // for std::string
    11 #include "Units.h"                      // for CSSRect, CSSPixel, etc
    12 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
    13 #include "mozilla/gfx/Rect.h"           // for RoundedIn
    14 #include "mozilla/gfx/ScaleFactor.h"    // for ScaleFactor
    15 #include "mozilla/gfx/Logging.h"        // for Log
    17 namespace IPC {
    18 template <typename T> struct ParamTraits;
    19 } // namespace IPC
    21 namespace mozilla {
    23 // The layer coordinates of the parent layer.
    24 // This can be arrived at in two ways:
    25 //   - Start with the CSS coordinates of the parent layer (note: NOT the
    26 //     CSS coordinates of the current layer, that will give you the wrong
    27 //     answer), multiply by the device scale and the resolutions of all
    28 //     layers from the root down to and including the parent.
    29 //   - Start with global screen coordinates and unapply all CSS and async
    30 //     transforms from the root down to and including the parent.
    31 // It's helpful to look at https://wiki.mozilla.org/Platform/GFX/APZ#Coordinate_systems
    32 // to get a picture of how the various coordinate systems relate to each other.
    33 struct ParentLayerPixel {};
    35 typedef gfx::PointTyped<ParentLayerPixel> ParentLayerPoint;
    36 typedef gfx::RectTyped<ParentLayerPixel> ParentLayerRect;
    37 typedef gfx::SizeTyped<ParentLayerPixel> ParentLayerSize;
    39 typedef gfx::IntMarginTyped<ParentLayerPixel> ParentLayerIntMargin;
    40 typedef gfx::IntPointTyped<ParentLayerPixel> ParentLayerIntPoint;
    41 typedef gfx::IntRectTyped<ParentLayerPixel> ParentLayerIntRect;
    42 typedef gfx::IntSizeTyped<ParentLayerPixel> ParentLayerIntSize;
    44 typedef gfx::ScaleFactor<CSSPixel, ParentLayerPixel> CSSToParentLayerScale;
    45 typedef gfx::ScaleFactor<LayoutDevicePixel, ParentLayerPixel> LayoutDeviceToParentLayerScale;
    46 typedef gfx::ScaleFactor<ScreenPixel, ParentLayerPixel> ScreenToParentLayerScale;
    48 typedef gfx::ScaleFactor<ParentLayerPixel, LayerPixel> ParentLayerToLayerScale;
    49 typedef gfx::ScaleFactor<ParentLayerPixel, ScreenPixel> ParentLayerToScreenScale;
    52 namespace layers {
    54 /**
    55  * The viewport and displayport metrics for the painted frame at the
    56  * time of a layer-tree transaction.  These metrics are especially
    57  * useful for shadow layers, because the metrics values are updated
    58  * atomically with new pixels.
    59  */
    60 struct FrameMetrics {
    61   friend struct IPC::ParamTraits<mozilla::layers::FrameMetrics>;
    62 public:
    63   // We use IDs to identify frames across processes.
    64   typedef uint64_t ViewID;
    65   static const ViewID NULL_SCROLL_ID;   // This container layer does not scroll.
    66   static const ViewID START_SCROLL_ID = 2;  // This is the ID that scrolling subframes
    67                                         // will begin at.
    69   FrameMetrics()
    70     : mCompositionBounds(0, 0, 0, 0)
    71     , mDisplayPort(0, 0, 0, 0)
    72     , mCriticalDisplayPort(0, 0, 0, 0)
    73     , mViewport(0, 0, 0, 0)
    74     , mScrollableRect(0, 0, 0, 0)
    75     , mResolution(1)
    76     , mCumulativeResolution(1)
    77     , mTransformScale(1)
    78     , mDevPixelsPerCSSPixel(1)
    79     , mPresShellId(-1)
    80     , mMayHaveTouchListeners(false)
    81     , mIsRoot(false)
    82     , mHasScrollgrab(false)
    83     , mScrollId(NULL_SCROLL_ID)
    84     , mScrollOffset(0, 0)
    85     , mZoom(1)
    86     , mUpdateScrollOffset(false)
    87     , mScrollGeneration(0)
    88     , mRootCompositionSize(0, 0)
    89     , mDisplayPortMargins(0, 0, 0, 0)
    90     , mUseDisplayPortMargins(false)
    91   {}
    93   // Default copy ctor and operator= are fine
    95   bool operator==(const FrameMetrics& aOther) const
    96   {
    97     // mContentDescription is not compared on purpose as it's only used
    98     // for debugging.
    99     return mCompositionBounds.IsEqualEdges(aOther.mCompositionBounds) &&
   100            mRootCompositionSize == aOther.mRootCompositionSize &&
   101            mDisplayPort.IsEqualEdges(aOther.mDisplayPort) &&
   102            mDisplayPortMargins == aOther.mDisplayPortMargins &&
   103            mUseDisplayPortMargins == aOther.mUseDisplayPortMargins &&
   104            mCriticalDisplayPort.IsEqualEdges(aOther.mCriticalDisplayPort) &&
   105            mViewport.IsEqualEdges(aOther.mViewport) &&
   106            mScrollableRect.IsEqualEdges(aOther.mScrollableRect) &&
   107            mResolution == aOther.mResolution &&
   108            mCumulativeResolution == aOther.mCumulativeResolution &&
   109            mDevPixelsPerCSSPixel == aOther.mDevPixelsPerCSSPixel &&
   110            mMayHaveTouchListeners == aOther.mMayHaveTouchListeners &&
   111            mPresShellId == aOther.mPresShellId &&
   112            mIsRoot == aOther.mIsRoot &&
   113            mScrollId == aOther.mScrollId &&
   114            mScrollOffset == aOther.mScrollOffset &&
   115            mHasScrollgrab == aOther.mHasScrollgrab &&
   116            mUpdateScrollOffset == aOther.mUpdateScrollOffset;
   117   }
   118   bool operator!=(const FrameMetrics& aOther) const
   119   {
   120     return !operator==(aOther);
   121   }
   123   bool IsDefault() const
   124   {
   125     FrameMetrics def;
   127     def.mPresShellId = mPresShellId;
   128     return (def == *this);
   129   }
   131   bool IsRootScrollable() const
   132   {
   133     return mIsRoot;
   134   }
   136   bool IsScrollable() const
   137   {
   138     return mScrollId != NULL_SCROLL_ID;
   139   }
   141   CSSToLayerScale LayersPixelsPerCSSPixel() const
   142   {
   143     return mCumulativeResolution * mDevPixelsPerCSSPixel;
   144   }
   146   LayerPoint GetScrollOffsetInLayerPixels() const
   147   {
   148     return GetScrollOffset() * LayersPixelsPerCSSPixel();
   149   }
   151   LayoutDeviceToParentLayerScale GetParentResolution() const
   152   {
   153     return mCumulativeResolution / mResolution;
   154   }
   156   // Ensure the scrollableRect is at least as big as the compositionBounds
   157   // because the scrollableRect can be smaller if the content is not large
   158   // and the scrollableRect hasn't been updated yet.
   159   // We move the scrollableRect up because we don't know if we can move it
   160   // down. i.e. we know that scrollableRect can go back as far as zero.
   161   // but we don't know how much further ahead it can go.
   162   CSSRect GetExpandedScrollableRect() const
   163   {
   164     CSSRect scrollableRect = mScrollableRect;
   165     CSSSize compSize = CalculateCompositedSizeInCssPixels();
   166     if (scrollableRect.width < compSize.width) {
   167       scrollableRect.x = std::max(0.f,
   168                                   scrollableRect.x - (compSize.width - scrollableRect.width));
   169       scrollableRect.width = compSize.width;
   170     }
   172     if (scrollableRect.height < compSize.height) {
   173       scrollableRect.y = std::max(0.f,
   174                                   scrollableRect.y - (compSize.height - scrollableRect.height));
   175       scrollableRect.height = compSize.height;
   176     }
   178     return scrollableRect;
   179   }
   181   // Return the scale factor needed to fit the viewport
   182   // into its composition bounds.
   183   CSSToScreenScale CalculateIntrinsicScale() const
   184   {
   185     return CSSToScreenScale(float(mCompositionBounds.width) / float(mViewport.width));
   186   }
   188   // Return the scale factor for converting from CSS pixels (for this layer)
   189   // to layer pixels of our parent layer. Much as mZoom is used to interface
   190   // between inputs we get in screen pixels and quantities in CSS pixels,
   191   // this is used to interface between mCompositionBounds and quantities
   192   // in CSS pixels.
   193   CSSToParentLayerScale GetZoomToParent() const
   194   {
   195     return mZoom * mTransformScale;
   196   }
   198   CSSSize CalculateCompositedSizeInCssPixels() const
   199   {
   200     return mCompositionBounds.Size() / GetZoomToParent();
   201   }
   203   CSSRect CalculateCompositedRectInCssPixels() const
   204   {
   205     return mCompositionBounds / GetZoomToParent();
   206   }
   208   void ScrollBy(const CSSPoint& aPoint)
   209   {
   210     mScrollOffset += aPoint;
   211   }
   213   void ZoomBy(float aFactor)
   214   {
   215     mZoom.scale *= aFactor;
   216   }
   218   void CopyScrollInfoFrom(const FrameMetrics& aOther)
   219   {
   220     mScrollOffset = aOther.mScrollOffset;
   221     mScrollGeneration = aOther.mScrollGeneration;
   222   }
   224   // ---------------------------------------------------------------------------
   225   // The following metrics are all in widget space/device pixels.
   226   //
   228   // This is the area within the widget that we're compositing to. It is relative
   229   // to the layer tree origin.
   230   //
   231   // This is useful because, on mobile, the viewport and composition dimensions
   232   // are not always the same. In this case, we calculate the displayport using
   233   // an area bigger than the region we're compositing to. If we used the
   234   // viewport dimensions to calculate the displayport, we'd run into situations
   235   // where we're prerendering the wrong regions and the content may be clipped,
   236   // or too much of it prerendered. If the composition dimensions are the same as the
   237   // viewport dimensions, there is no need for this and we can just use the viewport
   238   // instead.
   239   //
   240   // This value is valid for nested scrollable layers as well, and is still
   241   // relative to the layer tree origin. This value is provided by Gecko at
   242   // layout/paint time.
   243   ParentLayerIntRect mCompositionBounds;
   245   // ---------------------------------------------------------------------------
   246   // The following metrics are all in CSS pixels. They are not in any uniform
   247   // space, so each is explained separately.
   248   //
   250   // The area of a frame's contents that has been painted, relative to the
   251   // viewport. It is in the same coordinate space as |mViewport|. For example,
   252   // if it is at 0,0, then it's at the same place at the viewport, which is at
   253   // the top-left in the layer, and at the same place as the scroll offset of
   254   // the document.
   255   //
   256   // Note that this is structured in such a way that it doesn't depend on the
   257   // method layout uses to scroll content.
   258   //
   259   // May be larger or smaller than |mScrollableRect|.
   260   //
   261   // To pre-render a margin of 100 CSS pixels around the window,
   262   // { x = -100, y = - 100,
   263   //   width = window.innerWidth + 200, height = window.innerHeight + 200 }
   264   CSSRect mDisplayPort;
   266   // If non-empty, the area of a frame's contents that is considered critical
   267   // to paint. Area outside of this area (i.e. area inside mDisplayPort, but
   268   // outside of mCriticalDisplayPort) is considered low-priority, and may be
   269   // painted with lower precision, or not painted at all.
   270   //
   271   // The same restrictions for mDisplayPort apply here.
   272   CSSRect mCriticalDisplayPort;
   274   // The CSS viewport, which is the dimensions we're using to constrain the
   275   // <html> element of this frame, relative to the top-left of the layer. Note
   276   // that its offset is structured in such a way that it doesn't depend on the
   277   // method layout uses to scroll content.
   278   //
   279   // This is mainly useful on the root layer, however nested iframes can have
   280   // their own viewport, which will just be the size of the window of the
   281   // iframe. For layers that don't correspond to a document, this metric is
   282   // meaningless and invalid.
   283   CSSRect mViewport;
   285   // The scrollable bounds of a frame. This is determined by reflow.
   286   // Ordinarily the x and y will be 0 and the width and height will be the
   287   // size of the element being scrolled. However for RTL pages or elements
   288   // the x value may be negative.
   289   //
   290   // This is relative to the document. It is in the same coordinate space as
   291   // |mScrollOffset|, but a different coordinate space than |mViewport| and
   292   // |mDisplayPort|. Note also that this coordinate system is understood by
   293   // window.scrollTo().
   294   //
   295   // This is valid on any layer unless it has no content.
   296   CSSRect mScrollableRect;
   298   // ---------------------------------------------------------------------------
   299   // The following metrics are dimensionless.
   300   //
   302   // The incremental resolution that the current frame has been painted at
   303   // relative to the parent frame's resolution. This information is provided
   304   // by Gecko at layout/paint time.
   305   ParentLayerToLayerScale mResolution;
   307   // The cumulative resolution that the current frame has been painted at.
   308   // This is the product of our mResolution and the mResolutions of our parent frames.
   309   // This information is provided by Gecko at layout/paint time.
   310   LayoutDeviceToLayerScale mCumulativeResolution;
   312   // The conversion factor between local screen pixels (the coordinate
   313   // system in which APZCs receive input events) and our parent layer's
   314   // layer pixels (the coordinate system of mCompositionBounds).
   315   // This consists of the scale of the local CSS transform and the
   316   // nontransient async transform.
   317   // TODO: APZ does not currently work well if there is a CSS transform
   318   //       on the layer being scrolled that's not just a scale that's
   319   //       the same in both directions. When we fix this, mTransformScale
   320   //       will probably need to turn into a matrix.
   321   ScreenToParentLayerScale mTransformScale;
   323   // The conversion factor between CSS pixels and device pixels for this frame.
   324   // This can vary based on a variety of things, such as reflowing-zoom. The
   325   // conversion factor for device pixels to layers pixels is just the
   326   // resolution.
   327   CSSToLayoutDeviceScale mDevPixelsPerCSSPixel;
   329   uint32_t mPresShellId;
   331   // Whether or not this frame may have touch listeners.
   332   bool mMayHaveTouchListeners;
   334   // Whether or not this is the root scroll frame for the root content document.
   335   bool mIsRoot;
   337   // Whether or not this frame is for an element marked 'scrollgrab'.
   338   bool mHasScrollgrab;
   340 public:
   341   void SetScrollOffset(const CSSPoint& aScrollOffset)
   342   {
   343     mScrollOffset = aScrollOffset;
   344   }
   346   const CSSPoint& GetScrollOffset() const
   347   {
   348     return mScrollOffset;
   349   }
   351   void SetZoom(const CSSToScreenScale& aZoom)
   352   {
   353     mZoom = aZoom;
   354   }
   356   CSSToScreenScale GetZoom() const
   357   {
   358     return mZoom;
   359   }
   361   void SetScrollOffsetUpdated(uint32_t aScrollGeneration)
   362   {
   363     mUpdateScrollOffset = true;
   364     mScrollGeneration = aScrollGeneration;
   365   }
   367   bool GetScrollOffsetUpdated() const
   368   {
   369     return mUpdateScrollOffset;
   370   }
   372   uint32_t GetScrollGeneration() const
   373   {
   374     return mScrollGeneration;
   375   }
   377   const std::string& GetContentDescription() const
   378   {
   379     return mContentDescription;
   380   }
   382   void SetContentDescription(const std::string& aContentDescription)
   383   {
   384     mContentDescription = aContentDescription;
   385   }
   387   ViewID GetScrollId() const
   388   {
   389     return mScrollId;
   390   }
   392   void SetScrollId(ViewID scrollId) 
   393   {
   394     mScrollId = scrollId;
   395   }
   397   void SetRootCompositionSize(const CSSSize& aRootCompositionSize)
   398   {
   399     mRootCompositionSize = aRootCompositionSize;
   400   }
   402   const CSSSize& GetRootCompositionSize() const
   403   {
   404     return mRootCompositionSize;
   405   }
   407   void SetDisplayPortMargins(const LayerMargin& aDisplayPortMargins)
   408   {
   409     mDisplayPortMargins = aDisplayPortMargins;
   410   }
   412   const LayerMargin& GetDisplayPortMargins() const
   413   {
   414     return mDisplayPortMargins;
   415   }
   417   void SetUseDisplayPortMargins()
   418   {
   419     mUseDisplayPortMargins = true;
   420   }
   422   bool GetUseDisplayPortMargins() const
   423   {
   424     return mUseDisplayPortMargins;
   425   }
   427 private:
   428   // New fields from now on should be made private and old fields should
   429   // be refactored to be private.
   431   // A unique ID assigned to each scrollable frame.
   432   ViewID mScrollId;
   434   // The position of the top-left of the CSS viewport, relative to the document
   435   // (or the document relative to the viewport, if that helps understand it).
   436   //
   437   // Thus it is relative to the document. It is in the same coordinate space as
   438   // |mScrollableRect|, but a different coordinate space than |mViewport| and
   439   // |mDisplayPort|.
   440   //
   441   // It is required that the rect:
   442   // { x = mScrollOffset.x, y = mScrollOffset.y,
   443   //   width = mCompositionBounds.x / mResolution.scale,
   444   //   height = mCompositionBounds.y / mResolution.scale }
   445   // Be within |mScrollableRect|.
   446   //
   447   // This is valid for any layer, but is always relative to this frame and
   448   // not any parents, regardless of parent transforms.
   449   CSSPoint mScrollOffset;
   451   // The "user zoom". Content is painted by gecko at mResolution * mDevPixelsPerCSSPixel,
   452   // but will be drawn to the screen at mZoom. In the steady state, the
   453   // two will be the same, but during an async zoom action the two may
   454   // diverge. This information is initialized in Gecko but updated in the APZC.
   455   CSSToScreenScale mZoom;
   457   // Whether mScrollOffset was updated by something other than the APZ code, and
   458   // if the APZC receiving this metrics should update its local copy.
   459   bool mUpdateScrollOffset;
   460   // The scroll generation counter used to acknowledge the scroll offset update.
   461   uint32_t mScrollGeneration;
   463   // A description of the content element corresponding to this frame.
   464   // This is empty unless the apz.printtree pref is turned on.
   465   std::string mContentDescription;
   467   // The size of the root scrollable's composition bounds, but in local CSS pixels.
   468   CSSSize mRootCompositionSize;
   470   // A display port expressed as layer margins that apply to the rect of what
   471   // is drawn of the scrollable element.
   472   LayerMargin mDisplayPortMargins;
   474   // If this is true then we use the display port margins on this metrics,
   475   // otherwise use the display port rect.
   476   bool mUseDisplayPortMargins;
   477 };
   479 /**
   480  * This class allows us to uniquely identify a scrollable layer. The
   481  * mLayersId identifies the layer tree (corresponding to a child process
   482  * and/or tab) that the scrollable layer belongs to. The mPresShellId
   483  * is a temporal identifier (corresponding to the document loaded that
   484  * contains the scrollable layer, which may change over time). The
   485  * mScrollId corresponds to the actual frame that is scrollable.
   486  */
   487 struct ScrollableLayerGuid {
   488   uint64_t mLayersId;
   489   uint32_t mPresShellId;
   490   FrameMetrics::ViewID mScrollId;
   492   ScrollableLayerGuid()
   493     : mLayersId(0)
   494     , mPresShellId(0)
   495     , mScrollId(0)
   496   {
   497     MOZ_COUNT_CTOR(ScrollableLayerGuid);
   498   }
   500   ScrollableLayerGuid(uint64_t aLayersId, uint32_t aPresShellId,
   501                       FrameMetrics::ViewID aScrollId)
   502     : mLayersId(aLayersId)
   503     , mPresShellId(aPresShellId)
   504     , mScrollId(aScrollId)
   505   {
   506     MOZ_COUNT_CTOR(ScrollableLayerGuid);
   507   }
   509   ScrollableLayerGuid(uint64_t aLayersId, const FrameMetrics& aMetrics)
   510     : mLayersId(aLayersId)
   511     , mPresShellId(aMetrics.mPresShellId)
   512     , mScrollId(aMetrics.GetScrollId())
   513   {
   514     MOZ_COUNT_CTOR(ScrollableLayerGuid);
   515   }
   517   ~ScrollableLayerGuid()
   518   {
   519     MOZ_COUNT_DTOR(ScrollableLayerGuid);
   520   }
   522   bool operator==(const ScrollableLayerGuid& other) const
   523   {
   524     return mLayersId == other.mLayersId
   525         && mPresShellId == other.mPresShellId
   526         && mScrollId == other.mScrollId;
   527   }
   529   bool operator!=(const ScrollableLayerGuid& other) const
   530   {
   531     return !(*this == other);
   532   }
   533 };
   535 template <int LogLevel>
   536 gfx::Log<LogLevel>& operator<<(gfx::Log<LogLevel>& log, const ScrollableLayerGuid& aGuid) {
   537   return log << '(' << aGuid.mLayersId << ',' << aGuid.mPresShellId << ',' << aGuid.mScrollId << ')';
   538 }
   540 struct ZoomConstraints {
   541   bool mAllowZoom;
   542   bool mAllowDoubleTapZoom;
   543   CSSToScreenScale mMinZoom;
   544   CSSToScreenScale mMaxZoom;
   546   ZoomConstraints()
   547     : mAllowZoom(true)
   548     , mAllowDoubleTapZoom(true)
   549   {
   550     MOZ_COUNT_CTOR(ZoomConstraints);
   551   }
   553   ZoomConstraints(bool aAllowZoom,
   554                   bool aAllowDoubleTapZoom,
   555                   const CSSToScreenScale& aMinZoom,
   556                   const CSSToScreenScale& aMaxZoom)
   557     : mAllowZoom(aAllowZoom)
   558     , mAllowDoubleTapZoom(aAllowDoubleTapZoom)
   559     , mMinZoom(aMinZoom)
   560     , mMaxZoom(aMaxZoom)
   561   {
   562     MOZ_COUNT_CTOR(ZoomConstraints);
   563   }
   565   ~ZoomConstraints()
   566   {
   567     MOZ_COUNT_DTOR(ZoomConstraints);
   568   }
   570   bool operator==(const ZoomConstraints& other) const
   571   {
   572     return mAllowZoom == other.mAllowZoom
   573         && mAllowDoubleTapZoom == other.mAllowDoubleTapZoom
   574         && mMinZoom == other.mMinZoom
   575         && mMaxZoom == other.mMaxZoom;
   576   }
   578   bool operator!=(const ZoomConstraints& other) const
   579   {
   580     return !(*this == other);
   581   }
   582 };
   584 }
   585 }
   587 #endif /* GFX_FRAMEMETRICS_H */

mercurial