layout/generic/nsFloatManager.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial