layout/generic/nsFloatManager.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 // vim:cindent:ts=2:et:sw=2:
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /* class that manages rules for positioning floats */
     9 #ifndef nsFloatManager_h_
    10 #define nsFloatManager_h_
    12 #include "mozilla/Attributes.h"
    14 #include "nsIntervalSet.h"
    15 #include "nsCoord.h"
    16 #include "nsRect.h"
    17 #include "nsTArray.h"
    18 #include "nsFrameList.h" // for DEBUG_FRAME_DUMP
    20 class nsIPresShell;
    21 class nsIFrame;
    22 struct nsHTMLReflowState;
    23 class nsPresContext;
    25 /**
    26  * The available space for content not occupied by floats is divided
    27  * into a (vertical) sequence of rectangles.  However, we need to know
    28  * not only the rectangle, but also whether it was reduced (from the
    29  * content rectangle) by floats that actually intruded into the content
    30  * rectangle.
    31  */
    32 struct nsFlowAreaRect {
    33   nsRect mRect;
    34   bool mHasFloats;
    36   nsFlowAreaRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight,
    37                  bool aHasFloats)
    38     : mRect(aX, aY, aWidth, aHeight), mHasFloats(aHasFloats) {}
    39 };
    41 #define NS_FLOAT_MANAGER_CACHE_SIZE 4
    43 class nsFloatManager {
    44 public:
    45   nsFloatManager(nsIPresShell* aPresShell);
    46   ~nsFloatManager();
    48   void* operator new(size_t aSize) CPP_THROW_NEW;
    49   void operator delete(void* aPtr, size_t aSize);
    51   static void Shutdown();
    53   /**
    54    * Get float region stored on the frame. (Defaults to mRect if it's
    55    * not there.) The float region is the area impacted by this float;
    56    * the coordinates are relative to the containing block frame.
    57    */
    58   static nsRect GetRegionFor(nsIFrame* aFloatFrame);
    59   /**
    60    * Calculate the float region for this frame using aMargin and the
    61    * frame's mRect. The region includes the margins around the float,
    62    * but doesn't include the relative offsets.
    63    * Note that if the frame is or has a continuation, aMargin's top
    64    * and/or bottom must be zeroed by the caller.
    65    */
    66   static nsRect CalculateRegionFor(nsIFrame* aFloatFrame,
    67                                    const nsMargin& aMargin);
    68   /**
    69    * Store the float region on the frame. The region is stored
    70    * as a delta against the mRect, so repositioning the frame will
    71    * also reposition the float region.
    72    */
    73   static void StoreRegionFor(nsIFrame* aFloat, nsRect& aRegion);
    75   // Structure that stores the current state of a frame manager for
    76   // Save/Restore purposes.
    77   struct SavedState;
    78   friend struct SavedState;
    79   struct SavedState {
    80   private:
    81     uint32_t mFloatInfoCount;
    82     nscoord mX, mY;
    83     bool mPushedLeftFloatPastBreak;
    84     bool mPushedRightFloatPastBreak;
    85     bool mSplitLeftFloatAcrossBreak;
    86     bool mSplitRightFloatAcrossBreak;
    88     friend class nsFloatManager;
    89   };
    91   /**
    92    * Translate the current origin by the specified (dx, dy). This
    93    * creates a new local coordinate space relative to the current
    94    * coordinate space.
    95    */
    96   void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
    98   /**
    99    * Returns the current translation from local coordinate space to
   100    * world coordinate space. This represents the accumulated calls to
   101    * Translate().
   102    */
   103   void GetTranslation(nscoord& aX, nscoord& aY) const { aX = mX; aY = mY; }
   105   /**
   106    * Get information about the area available to content that flows
   107    * around floats.  Two different types of space can be requested:
   108    *   BAND_FROM_POINT: returns the band containing vertical coordinate
   109    *     |aY| (though actually with the top truncated to begin at aY),
   110    *     but up to at most |aHeight| (which may be nscoord_MAX).
   111    *     This will return the tallest rectangle whose top is |aY| and in
   112    *     which there are no changes in what floats are on the sides of
   113    *     that rectangle, but will limit the height of the rectangle to
   114    *     |aHeight|.  The left and right edges of the rectangle give the
   115    *     area available for line boxes in that space.  The width of this
   116    *     resulting rectangle will not be negative.
   117    *   WIDTH_WITHIN_HEIGHT: This returns a rectangle whose top is aY and
   118    *     whose height is exactly aHeight.  Its left and right edges give
   119    *     the left and right edges of the space that can be used for line
   120    *     boxes *throughout* that space.  (It is possible that more
   121    *     horizontal space could be used in part of the space if a float
   122    *     begins or ends in it.)  The width of the resulting rectangle
   123    *     can be negative.
   124    *
   125    * @param aY [in] vertical coordinate for top of available space
   126    *           desired
   127    * @param aHeight [in] see above
   128    * @param aContentArea [in] an nsRect representing the content area
   129    * @param aState [in] If null, use the current state, otherwise, do
   130    *                    computation based only on floats present in the given
   131    *                    saved state.
   132    * @return An nsFlowAreaRect whose:
   133    *           mRect is the resulting rectangle for line boxes.  It will not
   134    *             extend beyond aContentArea's horizontal bounds, but may be
   135    *             narrower when floats are present.
   136    *          mBandHasFloats is whether there are floats at the sides of the
   137    *            return value including those that do not reduce the line box
   138    *            width at all (because they are entirely in the margins)
   139    *
   140    * aY and aAvailSpace are positioned relative to the current translation
   141    */
   142   enum BandInfoType { BAND_FROM_POINT, WIDTH_WITHIN_HEIGHT };
   143   nsFlowAreaRect GetFlowArea(nscoord aY, BandInfoType aInfoType,
   144                              nscoord aHeight, nsRect aContentArea,
   145                              SavedState* aState) const;
   147   /**
   148    * Add a float that comes after all floats previously added.  Its top
   149    * must be even with or below the top of all previous floats.
   150    *
   151    * aMarginRect is relative to the current translation.  The caller
   152    * must ensure aMarginRect.height >= 0 and aMarginRect.width >= 0.
   153    */
   154   nsresult AddFloat(nsIFrame* aFloatFrame, const nsRect& aMarginRect);
   156   /**
   157    * Notify that we tried to place a float that could not fit at all and
   158    * had to be pushed to the next page/column?  (If so, we can't place
   159    * any more floats in this page/column because of the rule that the
   160    * top of a float cannot be above the top of an earlier float.  It
   161    * also means that any clear needs to continue to the next column.)
   162    */
   163   void SetPushedLeftFloatPastBreak()
   164     { mPushedLeftFloatPastBreak = true; }
   165   void SetPushedRightFloatPastBreak()
   166     { mPushedRightFloatPastBreak = true; }
   168   /**
   169    * Notify that we split a float, with part of it needing to be pushed
   170    * to the next page/column.  (This means that any 'clear' needs to
   171    * continue to the next page/column.)
   172    */
   173   void SetSplitLeftFloatAcrossBreak()
   174     { mSplitLeftFloatAcrossBreak = true; }
   175   void SetSplitRightFloatAcrossBreak()
   176     { mSplitRightFloatAcrossBreak = true; }
   178   /**
   179    * Remove the regions associated with this floating frame and its
   180    * next-sibling list.  Some of the frames may never have been added;
   181    * we just skip those. This is not fully general; it only works as
   182    * long as the N frames to be removed are the last N frames to have
   183    * been added; if there's a frame in the middle of them that should
   184    * not be removed, YOU LOSE.
   185    */
   186   nsresult RemoveTrailingRegions(nsIFrame* aFrameList);
   188 private:
   189   struct FloatInfo;
   190 public:
   192   bool HasAnyFloats() const { return !mFloats.IsEmpty(); }
   194   /**
   195    * Methods for dealing with the propagation of float damage during
   196    * reflow.
   197    */
   198   bool HasFloatDamage() const
   199   {
   200     return !mFloatDamage.IsEmpty();
   201   }
   203   void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
   204   {
   205     mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
   206   }
   208   bool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd) const
   209   {
   210     return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
   211   }
   213   /**
   214    * Saves the current state of the float manager into aState.
   215    */
   216   void PushState(SavedState* aState);
   218   /**
   219    * Restores the float manager to the saved state.
   220    * 
   221    * These states must be managed using stack discipline. PopState can only
   222    * be used after PushState has been used to save the state, and it can only
   223    * be used once --- although it can be omitted; saved states can be ignored.
   224    * States must be popped in the reverse order they were pushed.  A
   225    * call to PopState invalidates any saved states Pushed after the
   226    * state passed to PopState was pushed.
   227    */
   228   void PopState(SavedState* aState);
   230   /**
   231    * Get the top of the last float placed into the float manager, to
   232    * enforce the rule that a float can't be above an earlier float.
   233    * Returns the minimum nscoord value if there are no floats.
   234    *
   235    * The result is relative to the current translation.
   236    */
   237   nscoord GetLowestFloatTop() const;
   239   /**
   240    * Return the coordinate of the lowest float matching aBreakType in this
   241    * float manager. Returns aY if there are no matching floats.
   242    *
   243    * Both aY and the result are relative to the current translation.
   244    */
   245   enum {
   246     // Tell ClearFloats not to push to nscoord_MAX when floats have been
   247     // pushed to the next page/column.
   248     DONT_CLEAR_PUSHED_FLOATS = (1<<0)
   249   };
   250   nscoord ClearFloats(nscoord aY, uint8_t aBreakType, uint32_t aFlags = 0) const;
   252   /**
   253    * Checks if clear would pass into the floats' BFC's next-in-flow,
   254    * i.e. whether floats affecting this clear have continuations.
   255    */
   256   bool ClearContinues(uint8_t aBreakType) const;
   258   void AssertStateMatches(SavedState *aState) const
   259   {
   260     NS_ASSERTION(aState->mX == mX && aState->mY == mY &&
   261                  aState->mPushedLeftFloatPastBreak ==
   262                    mPushedLeftFloatPastBreak &&
   263                  aState->mPushedRightFloatPastBreak ==
   264                    mPushedRightFloatPastBreak &&
   265                  aState->mSplitLeftFloatAcrossBreak ==
   266                    mSplitLeftFloatAcrossBreak &&
   267                  aState->mSplitRightFloatAcrossBreak ==
   268                    mSplitRightFloatAcrossBreak &&
   269                  aState->mFloatInfoCount == mFloats.Length(),
   270                  "float manager state should match saved state");
   271   }
   273 #ifdef DEBUG_FRAME_DUMP
   274   /**
   275    * Dump the state of the float manager out to a file.
   276    */
   277   nsresult List(FILE* out) const;
   278 #endif
   280 private:
   282   struct FloatInfo {
   283     nsIFrame *const mFrame;
   284     nsRect mRect;
   285     // The lowest bottoms of left/right floats up to and including this one.
   286     nscoord mLeftYMost, mRightYMost;
   288     FloatInfo(nsIFrame* aFrame, const nsRect& aRect);
   289 #ifdef NS_BUILD_REFCNT_LOGGING
   290     FloatInfo(const FloatInfo& aOther);
   291     ~FloatInfo();
   292 #endif
   293   };
   295   nscoord         mX, mY;     // translation from local to global coordinate space
   296   nsTArray<FloatInfo> mFloats;
   297   nsIntervalSet   mFloatDamage;
   299   // Did we try to place a float that could not fit at all and had to be
   300   // pushed to the next page/column?  If so, we can't place any more
   301   // floats in this page/column because of the rule that the top of a
   302   // float cannot be above the top of an earlier float.  And we also
   303   // need to apply this information to 'clear', and thus need to
   304   // separate left and right floats.
   305   bool mPushedLeftFloatPastBreak;
   306   bool mPushedRightFloatPastBreak;
   308   // Did we split a float, with part of it needing to be pushed to the
   309   // next page/column.  This means that any 'clear' needs to continue to
   310   // the next page/column.
   311   bool mSplitLeftFloatAcrossBreak;
   312   bool mSplitRightFloatAcrossBreak;
   314   static int32_t sCachedFloatManagerCount;
   315   static void* sCachedFloatManagers[NS_FLOAT_MANAGER_CACHE_SIZE];
   317   nsFloatManager(const nsFloatManager&) MOZ_DELETE;
   318   void operator=(const nsFloatManager&) MOZ_DELETE;
   319 };
   321 /**
   322  * A helper class to manage maintenance of the float manager during
   323  * nsBlockFrame::Reflow. It automatically restores the old float
   324  * manager in the reflow state when the object goes out of scope.
   325  */
   326 class nsAutoFloatManager {
   327 public:
   328   nsAutoFloatManager(nsHTMLReflowState& aReflowState)
   329     : mReflowState(aReflowState),
   330       mNew(nullptr),
   331       mOld(nullptr) {}
   333   ~nsAutoFloatManager();
   335   /**
   336    * Create a new float manager for the specified frame. This will
   337    * `remember' the old float manager, and install the new float
   338    * manager in the reflow state.
   339    */
   340   nsresult
   341   CreateFloatManager(nsPresContext *aPresContext);
   343 protected:
   344   nsHTMLReflowState &mReflowState;
   345   nsFloatManager *mNew;
   346   nsFloatManager *mOld;
   347 };
   349 #endif /* !defined(nsFloatManager_h_) */

mercurial