Thu, 22 Jan 2015 13:21:57 +0100
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 | /* |
michael@0 | 8 | * rendering object for CSS display:block, inline-block, and list-item |
michael@0 | 9 | * boxes, also used for various anonymous boxes |
michael@0 | 10 | */ |
michael@0 | 11 | |
michael@0 | 12 | #ifndef nsBlockFrame_h___ |
michael@0 | 13 | #define nsBlockFrame_h___ |
michael@0 | 14 | |
michael@0 | 15 | #include "nsContainerFrame.h" |
michael@0 | 16 | #include "nsHTMLParts.h" |
michael@0 | 17 | #include "nsLineBox.h" |
michael@0 | 18 | #include "nsCSSPseudoElements.h" |
michael@0 | 19 | #include "nsStyleSet.h" |
michael@0 | 20 | #include "nsFloatManager.h" |
michael@0 | 21 | |
michael@0 | 22 | enum LineReflowStatus { |
michael@0 | 23 | // The line was completely reflowed and fit in available width, and we should |
michael@0 | 24 | // try to pull up content from the next line if possible. |
michael@0 | 25 | LINE_REFLOW_OK, |
michael@0 | 26 | // The line was completely reflowed and fit in available width, but we should |
michael@0 | 27 | // not try to pull up content from the next line. |
michael@0 | 28 | LINE_REFLOW_STOP, |
michael@0 | 29 | // We need to reflow the line again at its current vertical position. The |
michael@0 | 30 | // new reflow should not try to pull up any frames from the next line. |
michael@0 | 31 | LINE_REFLOW_REDO_NO_PULL, |
michael@0 | 32 | // We need to reflow the line again using the floats from its height |
michael@0 | 33 | // this reflow, since its height made it hit floats that were not |
michael@0 | 34 | // adjacent to its top. |
michael@0 | 35 | LINE_REFLOW_REDO_MORE_FLOATS, |
michael@0 | 36 | // We need to reflow the line again at a lower vertical postion where there |
michael@0 | 37 | // may be more horizontal space due to different float configuration. |
michael@0 | 38 | LINE_REFLOW_REDO_NEXT_BAND, |
michael@0 | 39 | // The line did not fit in the available vertical space. Try pushing it to |
michael@0 | 40 | // the next page or column if it's not the first line on the current page/column. |
michael@0 | 41 | LINE_REFLOW_TRUNCATED |
michael@0 | 42 | }; |
michael@0 | 43 | |
michael@0 | 44 | class nsBlockReflowState; |
michael@0 | 45 | class nsBlockInFlowLineIterator; |
michael@0 | 46 | class nsBulletFrame; |
michael@0 | 47 | class nsFirstLineFrame; |
michael@0 | 48 | |
michael@0 | 49 | /** |
michael@0 | 50 | * Some invariants: |
michael@0 | 51 | * -- The overflow out-of-flows list contains the out-of- |
michael@0 | 52 | * flow frames whose placeholders are in the overflow list. |
michael@0 | 53 | * -- A given piece of content has at most one placeholder |
michael@0 | 54 | * frame in a block's normal child list. |
michael@0 | 55 | * -- While a block is being reflowed, and from then until |
michael@0 | 56 | * its next-in-flow is reflowed it may have a |
michael@0 | 57 | * PushedFloatProperty frame property that points to |
michael@0 | 58 | * an nsFrameList. This list contains continuations for |
michael@0 | 59 | * floats whose prev-in-flow is in the block's regular float |
michael@0 | 60 | * list and first-in-flows of floats that did not fit, but |
michael@0 | 61 | * whose placeholders are in the block or one of its |
michael@0 | 62 | * prev-in-flows. |
michael@0 | 63 | * -- In all these frame lists, if there are two frames for |
michael@0 | 64 | * the same content appearing in the list, then the frames |
michael@0 | 65 | * appear with the prev-in-flow before the next-in-flow. |
michael@0 | 66 | * -- While reflowing a block, its overflow line list |
michael@0 | 67 | * will usually be empty but in some cases will have lines |
michael@0 | 68 | * (while we reflow the block at its shrink-wrap width). |
michael@0 | 69 | * In this case any new overflowing content must be |
michael@0 | 70 | * prepended to the overflow lines. |
michael@0 | 71 | */ |
michael@0 | 72 | |
michael@0 | 73 | typedef nsContainerFrame nsBlockFrameSuper; |
michael@0 | 74 | |
michael@0 | 75 | /* |
michael@0 | 76 | * Base class for block and inline frames. |
michael@0 | 77 | * The block frame has an additional child list, kAbsoluteList, which |
michael@0 | 78 | * contains the absolutely positioned frames. |
michael@0 | 79 | */ |
michael@0 | 80 | class nsBlockFrame : public nsBlockFrameSuper |
michael@0 | 81 | { |
michael@0 | 82 | public: |
michael@0 | 83 | NS_DECL_QUERYFRAME_TARGET(nsBlockFrame) |
michael@0 | 84 | NS_DECL_FRAMEARENA_HELPERS |
michael@0 | 85 | |
michael@0 | 86 | typedef nsLineList::iterator line_iterator; |
michael@0 | 87 | typedef nsLineList::const_iterator const_line_iterator; |
michael@0 | 88 | typedef nsLineList::reverse_iterator reverse_line_iterator; |
michael@0 | 89 | typedef nsLineList::const_reverse_iterator const_reverse_line_iterator; |
michael@0 | 90 | |
michael@0 | 91 | line_iterator begin_lines() { return mLines.begin(); } |
michael@0 | 92 | line_iterator end_lines() { return mLines.end(); } |
michael@0 | 93 | const_line_iterator begin_lines() const { return mLines.begin(); } |
michael@0 | 94 | const_line_iterator end_lines() const { return mLines.end(); } |
michael@0 | 95 | reverse_line_iterator rbegin_lines() { return mLines.rbegin(); } |
michael@0 | 96 | reverse_line_iterator rend_lines() { return mLines.rend(); } |
michael@0 | 97 | const_reverse_line_iterator rbegin_lines() const { return mLines.rbegin(); } |
michael@0 | 98 | const_reverse_line_iterator rend_lines() const { return mLines.rend(); } |
michael@0 | 99 | line_iterator line(nsLineBox* aList) { return mLines.begin(aList); } |
michael@0 | 100 | reverse_line_iterator rline(nsLineBox* aList) { return mLines.rbegin(aList); } |
michael@0 | 101 | |
michael@0 | 102 | friend nsIFrame* NS_NewBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, nsFrameState aFlags); |
michael@0 | 103 | |
michael@0 | 104 | // nsQueryFrame |
michael@0 | 105 | NS_DECL_QUERYFRAME |
michael@0 | 106 | |
michael@0 | 107 | // nsIFrame |
michael@0 | 108 | virtual void Init(nsIContent* aContent, |
michael@0 | 109 | nsIFrame* aParent, |
michael@0 | 110 | nsIFrame* aPrevInFlow) MOZ_OVERRIDE; |
michael@0 | 111 | virtual nsresult SetInitialChildList(ChildListID aListID, |
michael@0 | 112 | nsFrameList& aChildList) MOZ_OVERRIDE; |
michael@0 | 113 | virtual nsresult AppendFrames(ChildListID aListID, |
michael@0 | 114 | nsFrameList& aFrameList) MOZ_OVERRIDE; |
michael@0 | 115 | virtual nsresult InsertFrames(ChildListID aListID, |
michael@0 | 116 | nsIFrame* aPrevFrame, |
michael@0 | 117 | nsFrameList& aFrameList) MOZ_OVERRIDE; |
michael@0 | 118 | virtual nsresult RemoveFrame(ChildListID aListID, |
michael@0 | 119 | nsIFrame* aOldFrame) MOZ_OVERRIDE; |
michael@0 | 120 | virtual const nsFrameList& GetChildList(ChildListID aListID) const MOZ_OVERRIDE; |
michael@0 | 121 | virtual void GetChildLists(nsTArray<ChildList>* aLists) const MOZ_OVERRIDE; |
michael@0 | 122 | virtual nscoord GetBaseline() const MOZ_OVERRIDE; |
michael@0 | 123 | virtual nscoord GetCaretBaseline() const MOZ_OVERRIDE; |
michael@0 | 124 | virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; |
michael@0 | 125 | virtual nsSplittableType GetSplittableType() const MOZ_OVERRIDE; |
michael@0 | 126 | virtual bool IsFloatContainingBlock() const MOZ_OVERRIDE; |
michael@0 | 127 | virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, |
michael@0 | 128 | const nsRect& aDirtyRect, |
michael@0 | 129 | const nsDisplayListSet& aLists) MOZ_OVERRIDE; |
michael@0 | 130 | virtual nsIAtom* GetType() const MOZ_OVERRIDE; |
michael@0 | 131 | virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE |
michael@0 | 132 | { |
michael@0 | 133 | return nsContainerFrame::IsFrameOfType(aFlags & |
michael@0 | 134 | ~(nsIFrame::eCanContainOverflowContainers | |
michael@0 | 135 | nsIFrame::eBlockFrame)); |
michael@0 | 136 | } |
michael@0 | 137 | |
michael@0 | 138 | virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; |
michael@0 | 139 | virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; |
michael@0 | 140 | |
michael@0 | 141 | #ifdef DEBUG_FRAME_DUMP |
michael@0 | 142 | void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE; |
michael@0 | 143 | virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; |
michael@0 | 144 | #endif |
michael@0 | 145 | |
michael@0 | 146 | #ifdef DEBUG |
michael@0 | 147 | virtual nsFrameState GetDebugStateBits() const MOZ_OVERRIDE; |
michael@0 | 148 | #endif |
michael@0 | 149 | |
michael@0 | 150 | #ifdef ACCESSIBILITY |
michael@0 | 151 | virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE; |
michael@0 | 152 | #endif |
michael@0 | 153 | |
michael@0 | 154 | // line cursor methods to speed up searching for the line(s) |
michael@0 | 155 | // containing a point. The basic idea is that we set the cursor |
michael@0 | 156 | // property if the lines' overflowArea.VisualOverflow().ys and |
michael@0 | 157 | // overflowArea.VisualOverflow().yMosts are non-decreasing |
michael@0 | 158 | // (considering only non-empty overflowArea.VisualOverflow()s; empty |
michael@0 | 159 | // overflowArea.VisualOverflow()s never participate in event handling |
michael@0 | 160 | // or painting), and the block has sufficient number of lines. The |
michael@0 | 161 | // cursor property points to a "recently used" line. If we get a |
michael@0 | 162 | // series of requests that work on lines |
michael@0 | 163 | // "near" the cursor, then we can find those nearby lines quickly by |
michael@0 | 164 | // starting our search at the cursor. |
michael@0 | 165 | |
michael@0 | 166 | // Clear out line cursor because we're disturbing the lines (i.e., Reflow) |
michael@0 | 167 | void ClearLineCursor(); |
michael@0 | 168 | // Get the first line that might contain y-coord 'y', or nullptr if you must search |
michael@0 | 169 | // all lines. If nonnull is returned then we guarantee that the lines' |
michael@0 | 170 | // combinedArea.ys and combinedArea.yMosts are non-decreasing. |
michael@0 | 171 | // The actual line returned might not contain 'y', but if not, it is guaranteed |
michael@0 | 172 | // to be before any line which does contain 'y'. |
michael@0 | 173 | nsLineBox* GetFirstLineContaining(nscoord y); |
michael@0 | 174 | // Set the line cursor to our first line. Only call this if you |
michael@0 | 175 | // guarantee that the lines' combinedArea.ys and combinedArea.yMosts |
michael@0 | 176 | // are non-decreasing. |
michael@0 | 177 | void SetupLineCursor(); |
michael@0 | 178 | |
michael@0 | 179 | virtual void ChildIsDirty(nsIFrame* aChild) MOZ_OVERRIDE; |
michael@0 | 180 | virtual bool IsVisibleInSelection(nsISelection* aSelection) MOZ_OVERRIDE; |
michael@0 | 181 | |
michael@0 | 182 | virtual bool IsEmpty() MOZ_OVERRIDE; |
michael@0 | 183 | virtual bool CachedIsEmpty() MOZ_OVERRIDE; |
michael@0 | 184 | virtual bool IsSelfEmpty() MOZ_OVERRIDE; |
michael@0 | 185 | |
michael@0 | 186 | // Given that we have a bullet, does it actually draw something, i.e., |
michael@0 | 187 | // do we have either a 'list-style-type' or 'list-style-image' that is |
michael@0 | 188 | // not 'none'? |
michael@0 | 189 | bool BulletIsEmpty() const; |
michael@0 | 190 | |
michael@0 | 191 | /** |
michael@0 | 192 | * Return the bullet text equivalent. |
michael@0 | 193 | */ |
michael@0 | 194 | void GetBulletText(nsAString& aText) const; |
michael@0 | 195 | |
michael@0 | 196 | /** |
michael@0 | 197 | * Return true if there's a bullet. |
michael@0 | 198 | */ |
michael@0 | 199 | bool HasBullet() const { |
michael@0 | 200 | return HasOutsideBullet() || HasInsideBullet(); |
michael@0 | 201 | } |
michael@0 | 202 | |
michael@0 | 203 | /** |
michael@0 | 204 | * @return true if this frame has an inside bullet frame. |
michael@0 | 205 | */ |
michael@0 | 206 | bool HasInsideBullet() const { |
michael@0 | 207 | return 0 != (mState & NS_BLOCK_FRAME_HAS_INSIDE_BULLET); |
michael@0 | 208 | } |
michael@0 | 209 | |
michael@0 | 210 | /** |
michael@0 | 211 | * @return true if this frame has an outside bullet frame. |
michael@0 | 212 | */ |
michael@0 | 213 | bool HasOutsideBullet() const { |
michael@0 | 214 | return 0 != (mState & NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET); |
michael@0 | 215 | } |
michael@0 | 216 | |
michael@0 | 217 | /** |
michael@0 | 218 | * @return the bullet frame or nullptr if we don't have one. |
michael@0 | 219 | */ |
michael@0 | 220 | nsBulletFrame* GetBullet() const { |
michael@0 | 221 | nsBulletFrame* outside = GetOutsideBullet(); |
michael@0 | 222 | return outside ? outside : GetInsideBullet(); |
michael@0 | 223 | } |
michael@0 | 224 | |
michael@0 | 225 | virtual void MarkIntrinsicWidthsDirty() MOZ_OVERRIDE; |
michael@0 | 226 | private: |
michael@0 | 227 | void CheckIntrinsicCacheAgainstShrinkWrapState(); |
michael@0 | 228 | public: |
michael@0 | 229 | virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; |
michael@0 | 230 | virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; |
michael@0 | 231 | |
michael@0 | 232 | virtual nsRect ComputeTightBounds(gfxContext* aContext) const MOZ_OVERRIDE; |
michael@0 | 233 | |
michael@0 | 234 | virtual nsresult GetPrefWidthTightBounds(nsRenderingContext* aContext, |
michael@0 | 235 | nscoord* aX, |
michael@0 | 236 | nscoord* aXMost) MOZ_OVERRIDE; |
michael@0 | 237 | |
michael@0 | 238 | /** |
michael@0 | 239 | * Compute the final height of this frame. |
michael@0 | 240 | * |
michael@0 | 241 | * @param aReflowState Data structure passed from parent during reflow. |
michael@0 | 242 | * @param aReflowStatus A pointed to the reflow status for when we're finished |
michael@0 | 243 | * doing reflow. this will get set appropriately if the height causes |
michael@0 | 244 | * us to exceed the current available (page) height. |
michael@0 | 245 | * @param aContentHeight The height of content, precomputed outside of this |
michael@0 | 246 | * function. The final height that is used in aMetrics will be set to |
michael@0 | 247 | * either this or the available height, whichever is larger, in the |
michael@0 | 248 | * case where our available height is constrained, and we overflow that |
michael@0 | 249 | * available height. |
michael@0 | 250 | * @param aBorderPadding The margins representing the border padding for block |
michael@0 | 251 | * frames. Can be 0. |
michael@0 | 252 | * @param aMetrics Out parameter for final height. Taken as an |
michael@0 | 253 | * nsHTMLReflowMetrics object so that aMetrics can be passed in |
michael@0 | 254 | * directly during reflow. |
michael@0 | 255 | * @param aConsumed The height already consumed by our previous-in-flows. |
michael@0 | 256 | */ |
michael@0 | 257 | void ComputeFinalHeight(const nsHTMLReflowState& aReflowState, |
michael@0 | 258 | nsReflowStatus* aStatus, |
michael@0 | 259 | nscoord aContentHeight, |
michael@0 | 260 | const nsMargin& aBorderPadding, |
michael@0 | 261 | nsHTMLReflowMetrics& aMetrics, |
michael@0 | 262 | nscoord aConsumed); |
michael@0 | 263 | |
michael@0 | 264 | virtual nsresult Reflow(nsPresContext* aPresContext, |
michael@0 | 265 | nsHTMLReflowMetrics& aDesiredSize, |
michael@0 | 266 | const nsHTMLReflowState& aReflowState, |
michael@0 | 267 | nsReflowStatus& aStatus) MOZ_OVERRIDE; |
michael@0 | 268 | |
michael@0 | 269 | virtual nsresult AttributeChanged(int32_t aNameSpaceID, |
michael@0 | 270 | nsIAtom* aAttribute, |
michael@0 | 271 | int32_t aModType) MOZ_OVERRIDE; |
michael@0 | 272 | |
michael@0 | 273 | /** |
michael@0 | 274 | * Move any frames on our overflow list to the end of our principal list. |
michael@0 | 275 | * @return true if there were any overflow frames |
michael@0 | 276 | */ |
michael@0 | 277 | virtual bool DrainSelfOverflowList() MOZ_OVERRIDE; |
michael@0 | 278 | |
michael@0 | 279 | virtual nsresult StealFrame(nsIFrame* aChild, |
michael@0 | 280 | bool aForceNormal = false) MOZ_OVERRIDE; |
michael@0 | 281 | |
michael@0 | 282 | virtual void DeleteNextInFlowChild(nsIFrame* aNextInFlow, |
michael@0 | 283 | bool aDeletingEmptyFrames) MOZ_OVERRIDE; |
michael@0 | 284 | |
michael@0 | 285 | /** |
michael@0 | 286 | * This is a special method that allows a child class of nsBlockFrame to |
michael@0 | 287 | * return a special, customized nsStyleText object to the nsLineLayout |
michael@0 | 288 | * constructor. It is used when the nsBlockFrame child needs to specify its |
michael@0 | 289 | * custom rendering style. |
michael@0 | 290 | */ |
michael@0 | 291 | virtual const nsStyleText* StyleTextForLineLayout(); |
michael@0 | 292 | |
michael@0 | 293 | /** |
michael@0 | 294 | * Determines whether the collapsed margin carried out of the last |
michael@0 | 295 | * line includes the margin-top of a line with clearance (in which |
michael@0 | 296 | * case we must avoid collapsing that margin with our bottom margin) |
michael@0 | 297 | */ |
michael@0 | 298 | bool CheckForCollapsedBottomMarginFromClearanceLine(); |
michael@0 | 299 | |
michael@0 | 300 | static nsresult GetCurrentLine(nsBlockReflowState *aState, nsLineBox **aOutCurrentLine); |
michael@0 | 301 | |
michael@0 | 302 | /** |
michael@0 | 303 | * Determine if this block is a margin root at the top/bottom edges. |
michael@0 | 304 | */ |
michael@0 | 305 | void IsMarginRoot(bool* aTopMarginRoot, bool* aBottomMarginRoot); |
michael@0 | 306 | |
michael@0 | 307 | static bool BlockNeedsFloatManager(nsIFrame* aBlock); |
michael@0 | 308 | |
michael@0 | 309 | /** |
michael@0 | 310 | * Returns whether aFrame is a block frame that will wrap its contents |
michael@0 | 311 | * around floats intruding on it from the outside. (aFrame need not |
michael@0 | 312 | * be a block frame, but if it's not, the result will be false.) |
michael@0 | 313 | */ |
michael@0 | 314 | static bool BlockCanIntersectFloats(nsIFrame* aFrame); |
michael@0 | 315 | |
michael@0 | 316 | /** |
michael@0 | 317 | * Returns the width that needs to be cleared past floats for blocks |
michael@0 | 318 | * that cannot intersect floats. aState must already have |
michael@0 | 319 | * GetAvailableSpace called on it for the vertical position that we |
michael@0 | 320 | * care about (which need not be its current mY) |
michael@0 | 321 | */ |
michael@0 | 322 | struct ReplacedElementWidthToClear { |
michael@0 | 323 | nscoord marginLeft, borderBoxWidth, marginRight; |
michael@0 | 324 | nscoord MarginBoxWidth() const |
michael@0 | 325 | { return marginLeft + borderBoxWidth + marginRight; } |
michael@0 | 326 | }; |
michael@0 | 327 | static ReplacedElementWidthToClear |
michael@0 | 328 | WidthToClearPastFloats(nsBlockReflowState& aState, |
michael@0 | 329 | const nsRect& aFloatAvailableSpace, |
michael@0 | 330 | nsIFrame* aFrame); |
michael@0 | 331 | |
michael@0 | 332 | /** |
michael@0 | 333 | * Creates a contination for aFloat and adds it to the list of overflow floats. |
michael@0 | 334 | * Also updates aState.mReflowStatus to include the float's incompleteness. |
michael@0 | 335 | * Must only be called while this block frame is in reflow. |
michael@0 | 336 | * aFloatStatus must be the float's true, unmodified reflow status. |
michael@0 | 337 | * |
michael@0 | 338 | */ |
michael@0 | 339 | nsresult SplitFloat(nsBlockReflowState& aState, |
michael@0 | 340 | nsIFrame* aFloat, |
michael@0 | 341 | nsReflowStatus aFloatStatus); |
michael@0 | 342 | |
michael@0 | 343 | /** |
michael@0 | 344 | * Walks up the frame tree, starting with aCandidate, and returns the first |
michael@0 | 345 | * block frame that it encounters. |
michael@0 | 346 | */ |
michael@0 | 347 | static nsBlockFrame* GetNearestAncestorBlock(nsIFrame* aCandidate); |
michael@0 | 348 | |
michael@0 | 349 | struct FrameLines { |
michael@0 | 350 | nsLineList mLines; |
michael@0 | 351 | nsFrameList mFrames; |
michael@0 | 352 | }; |
michael@0 | 353 | |
michael@0 | 354 | protected: |
michael@0 | 355 | nsBlockFrame(nsStyleContext* aContext) |
michael@0 | 356 | : nsContainerFrame(aContext) |
michael@0 | 357 | , mMinWidth(NS_INTRINSIC_WIDTH_UNKNOWN) |
michael@0 | 358 | , mPrefWidth(NS_INTRINSIC_WIDTH_UNKNOWN) |
michael@0 | 359 | { |
michael@0 | 360 | #ifdef DEBUG |
michael@0 | 361 | InitDebugFlags(); |
michael@0 | 362 | #endif |
michael@0 | 363 | } |
michael@0 | 364 | virtual ~nsBlockFrame(); |
michael@0 | 365 | |
michael@0 | 366 | #ifdef DEBUG |
michael@0 | 367 | already_AddRefed<nsStyleContext> GetFirstLetterStyle(nsPresContext* aPresContext) |
michael@0 | 368 | { |
michael@0 | 369 | return aPresContext->StyleSet()-> |
michael@0 | 370 | ProbePseudoElementStyle(mContent->AsElement(), |
michael@0 | 371 | nsCSSPseudoElements::ePseudo_firstLetter, |
michael@0 | 372 | mStyleContext); |
michael@0 | 373 | } |
michael@0 | 374 | #endif |
michael@0 | 375 | |
michael@0 | 376 | NS_DECLARE_FRAME_PROPERTY(LineCursorProperty, nullptr) |
michael@0 | 377 | nsLineBox* GetLineCursor() { |
michael@0 | 378 | return (GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR) ? |
michael@0 | 379 | static_cast<nsLineBox*>(Properties().Get(LineCursorProperty())) : nullptr; |
michael@0 | 380 | } |
michael@0 | 381 | |
michael@0 | 382 | nsLineBox* NewLineBox(nsIFrame* aFrame, bool aIsBlock) { |
michael@0 | 383 | return NS_NewLineBox(PresContext()->PresShell(), aFrame, aIsBlock); |
michael@0 | 384 | } |
michael@0 | 385 | nsLineBox* NewLineBox(nsLineBox* aFromLine, nsIFrame* aFrame, int32_t aCount) { |
michael@0 | 386 | return NS_NewLineBox(PresContext()->PresShell(), aFromLine, aFrame, aCount); |
michael@0 | 387 | } |
michael@0 | 388 | void FreeLineBox(nsLineBox* aLine) { |
michael@0 | 389 | if (aLine == GetLineCursor()) { |
michael@0 | 390 | ClearLineCursor(); |
michael@0 | 391 | } |
michael@0 | 392 | aLine->Destroy(PresContext()->PresShell()); |
michael@0 | 393 | } |
michael@0 | 394 | /** |
michael@0 | 395 | * Helper method for StealFrame. |
michael@0 | 396 | */ |
michael@0 | 397 | void RemoveFrameFromLine(nsIFrame* aChild, nsLineList::iterator aLine, |
michael@0 | 398 | nsFrameList& aFrameList, nsLineList& aLineList); |
michael@0 | 399 | |
michael@0 | 400 | void TryAllLines(nsLineList::iterator* aIterator, |
michael@0 | 401 | nsLineList::iterator* aStartIterator, |
michael@0 | 402 | nsLineList::iterator* aEndIterator, |
michael@0 | 403 | bool* aInOverflowLines, |
michael@0 | 404 | FrameLines** aOverflowLines); |
michael@0 | 405 | |
michael@0 | 406 | void SetFlags(nsFrameState aFlags) { |
michael@0 | 407 | mState &= ~NS_BLOCK_FLAGS_MASK; |
michael@0 | 408 | mState |= aFlags; |
michael@0 | 409 | } |
michael@0 | 410 | |
michael@0 | 411 | /** move the frames contained by aLine by aDY |
michael@0 | 412 | * if aLine is a block, its child floats are added to the state manager |
michael@0 | 413 | */ |
michael@0 | 414 | void SlideLine(nsBlockReflowState& aState, |
michael@0 | 415 | nsLineBox* aLine, nscoord aDY); |
michael@0 | 416 | |
michael@0 | 417 | void ComputeFinalSize(const nsHTMLReflowState& aReflowState, |
michael@0 | 418 | nsBlockReflowState& aState, |
michael@0 | 419 | nsHTMLReflowMetrics& aMetrics, |
michael@0 | 420 | nscoord* aBottomEdgeOfChildren); |
michael@0 | 421 | |
michael@0 | 422 | void ComputeOverflowAreas(const nsRect& aBounds, |
michael@0 | 423 | const nsStyleDisplay* aDisplay, |
michael@0 | 424 | nscoord aBottomEdgeOfChildren, |
michael@0 | 425 | nsOverflowAreas& aOverflowAreas); |
michael@0 | 426 | |
michael@0 | 427 | /** |
michael@0 | 428 | * Add the frames in aFrameList to this block after aPrevSibling. |
michael@0 | 429 | * This block thinks in terms of lines, but the frame construction code |
michael@0 | 430 | * knows nothing about lines at all so we need to find the line that |
michael@0 | 431 | * contains aPrevSibling and add aFrameList after aPrevSibling on that line. |
michael@0 | 432 | * New lines are created as necessary to handle block data in aFrameList. |
michael@0 | 433 | * This function will clear aFrameList. |
michael@0 | 434 | */ |
michael@0 | 435 | void AddFrames(nsFrameList& aFrameList, nsIFrame* aPrevSibling); |
michael@0 | 436 | |
michael@0 | 437 | /** |
michael@0 | 438 | * Perform Bidi resolution on this frame |
michael@0 | 439 | */ |
michael@0 | 440 | nsresult ResolveBidi(); |
michael@0 | 441 | |
michael@0 | 442 | /** |
michael@0 | 443 | * Test whether the frame is a form control in a visual Bidi page. |
michael@0 | 444 | * This is necessary for backwards-compatibility, because most visual |
michael@0 | 445 | * pages use logical order for form controls so that they will |
michael@0 | 446 | * display correctly on native widgets in OSs with Bidi support |
michael@0 | 447 | * @param aPresContext the pres context |
michael@0 | 448 | * @return whether the frame is a BIDI form control |
michael@0 | 449 | */ |
michael@0 | 450 | bool IsVisualFormControl(nsPresContext* aPresContext); |
michael@0 | 451 | |
michael@0 | 452 | public: |
michael@0 | 453 | /** |
michael@0 | 454 | * Does all the real work for removing aDeletedFrame |
michael@0 | 455 | * -- finds the line containing aDeletedFrame |
michael@0 | 456 | * -- removes all aDeletedFrame next-in-flows (or all continuations, |
michael@0 | 457 | * if REMOVE_FIXED_CONTINUATIONS is given) |
michael@0 | 458 | * -- marks lines dirty as needed |
michael@0 | 459 | * -- marks textruns dirty (unless FRAMES_ARE_EMPTY is given, in which |
michael@0 | 460 | * case textruns do not need to be dirtied) |
michael@0 | 461 | * -- destroys all removed frames |
michael@0 | 462 | */ |
michael@0 | 463 | enum { |
michael@0 | 464 | REMOVE_FIXED_CONTINUATIONS = 0x02, |
michael@0 | 465 | FRAMES_ARE_EMPTY = 0x04 |
michael@0 | 466 | }; |
michael@0 | 467 | nsresult DoRemoveFrame(nsIFrame* aDeletedFrame, uint32_t aFlags); |
michael@0 | 468 | |
michael@0 | 469 | void ReparentFloats(nsIFrame* aFirstFrame, nsBlockFrame* aOldParent, |
michael@0 | 470 | bool aReparentSiblings); |
michael@0 | 471 | |
michael@0 | 472 | virtual bool UpdateOverflow() MOZ_OVERRIDE; |
michael@0 | 473 | |
michael@0 | 474 | /** Load all of aFrame's floats into the float manager iff aFrame is not a |
michael@0 | 475 | * block formatting context. Handles all necessary float manager translations; |
michael@0 | 476 | * assumes float manager is in aFrame's parent's coord system. |
michael@0 | 477 | * Safe to call on non-blocks (does nothing). |
michael@0 | 478 | */ |
michael@0 | 479 | static void RecoverFloatsFor(nsIFrame* aFrame, |
michael@0 | 480 | nsFloatManager& aFloatManager); |
michael@0 | 481 | |
michael@0 | 482 | /** |
michael@0 | 483 | * Determine if we have any pushed floats from a previous continuation. |
michael@0 | 484 | * |
michael@0 | 485 | * @returns true, if any of the floats at the beginning of our mFloats list |
michael@0 | 486 | * have the NS_FRAME_IS_PUSHED_FLOAT bit set; false otherwise. |
michael@0 | 487 | */ |
michael@0 | 488 | bool HasPushedFloatsFromPrevContinuation() const { |
michael@0 | 489 | if (!mFloats.IsEmpty()) { |
michael@0 | 490 | // If we have pushed floats, then they should be at the beginning of our |
michael@0 | 491 | // float list. |
michael@0 | 492 | if (mFloats.FirstChild()->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT) { |
michael@0 | 493 | return true; |
michael@0 | 494 | } |
michael@0 | 495 | } |
michael@0 | 496 | |
michael@0 | 497 | #ifdef DEBUG |
michael@0 | 498 | // Double-check the above assertion that pushed floats should be at the |
michael@0 | 499 | // beginning of our floats list. |
michael@0 | 500 | for (nsFrameList::Enumerator e(mFloats); !e.AtEnd(); e.Next()) { |
michael@0 | 501 | nsIFrame* f = e.get(); |
michael@0 | 502 | NS_ASSERTION(!(f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT), |
michael@0 | 503 | "pushed floats must be at the beginning of the float list"); |
michael@0 | 504 | } |
michael@0 | 505 | #endif |
michael@0 | 506 | return false; |
michael@0 | 507 | } |
michael@0 | 508 | |
michael@0 | 509 | protected: |
michael@0 | 510 | |
michael@0 | 511 | /** grab overflow lines from this block's prevInFlow, and make them |
michael@0 | 512 | * part of this block's mLines list. |
michael@0 | 513 | * @return true if any lines were drained. |
michael@0 | 514 | */ |
michael@0 | 515 | bool DrainOverflowLines(); |
michael@0 | 516 | |
michael@0 | 517 | /** |
michael@0 | 518 | * @return false iff this block does not have a float on any child list. |
michael@0 | 519 | * This function is O(1). |
michael@0 | 520 | */ |
michael@0 | 521 | bool MaybeHasFloats() const { |
michael@0 | 522 | if (!mFloats.IsEmpty()) { |
michael@0 | 523 | return true; |
michael@0 | 524 | } |
michael@0 | 525 | // XXX this could be replaced with HasPushedFloats() if we enforced |
michael@0 | 526 | // removing the property when the frame list becomes empty. |
michael@0 | 527 | nsFrameList* list = GetPushedFloats(); |
michael@0 | 528 | if (list && !list->IsEmpty()) { |
michael@0 | 529 | return true; |
michael@0 | 530 | } |
michael@0 | 531 | // For the OverflowOutOfFlowsProperty I think we do enforce that, but it's |
michael@0 | 532 | // a mix of out-of-flow frames, so that's why the method name has "Maybe". |
michael@0 | 533 | return GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS; |
michael@0 | 534 | } |
michael@0 | 535 | |
michael@0 | 536 | /** grab pushed floats from this block's prevInFlow, and splice |
michael@0 | 537 | * them into this block's mFloats list. |
michael@0 | 538 | */ |
michael@0 | 539 | void DrainPushedFloats(nsBlockReflowState& aState); |
michael@0 | 540 | |
michael@0 | 541 | /** Load all our floats into the float manager (without reflowing them). |
michael@0 | 542 | * Assumes float manager is in our own coordinate system. |
michael@0 | 543 | */ |
michael@0 | 544 | void RecoverFloats(nsFloatManager& aFloatManager); |
michael@0 | 545 | |
michael@0 | 546 | /** Reflow pushed floats |
michael@0 | 547 | */ |
michael@0 | 548 | void ReflowPushedFloats(nsBlockReflowState& aState, |
michael@0 | 549 | nsOverflowAreas& aOverflowAreas, |
michael@0 | 550 | nsReflowStatus& aStatus); |
michael@0 | 551 | |
michael@0 | 552 | /** Find any trailing BR clear from the last line of the block (or its PIFs) |
michael@0 | 553 | */ |
michael@0 | 554 | uint8_t FindTrailingClear(); |
michael@0 | 555 | |
michael@0 | 556 | /** |
michael@0 | 557 | * Remove a float from our float list. |
michael@0 | 558 | */ |
michael@0 | 559 | void RemoveFloat(nsIFrame* aFloat); |
michael@0 | 560 | /** |
michael@0 | 561 | * Remove a float from the float cache for the line its placeholder is on. |
michael@0 | 562 | */ |
michael@0 | 563 | void RemoveFloatFromFloatCache(nsIFrame* aFloat); |
michael@0 | 564 | |
michael@0 | 565 | void CollectFloats(nsIFrame* aFrame, nsFrameList& aList, |
michael@0 | 566 | bool aCollectFromSiblings) { |
michael@0 | 567 | if (MaybeHasFloats()) { |
michael@0 | 568 | DoCollectFloats(aFrame, aList, aCollectFromSiblings); |
michael@0 | 569 | } |
michael@0 | 570 | } |
michael@0 | 571 | void DoCollectFloats(nsIFrame* aFrame, nsFrameList& aList, |
michael@0 | 572 | bool aCollectFromSiblings); |
michael@0 | 573 | |
michael@0 | 574 | // Remove a float, abs, rel positioned frame from the appropriate block's list |
michael@0 | 575 | static void DoRemoveOutOfFlowFrame(nsIFrame* aFrame); |
michael@0 | 576 | |
michael@0 | 577 | /** set up the conditions necessary for an resize reflow |
michael@0 | 578 | * the primary task is to mark the minimumly sufficient lines dirty. |
michael@0 | 579 | */ |
michael@0 | 580 | void PrepareResizeReflow(nsBlockReflowState& aState); |
michael@0 | 581 | |
michael@0 | 582 | /** reflow all lines that have been marked dirty */ |
michael@0 | 583 | nsresult ReflowDirtyLines(nsBlockReflowState& aState); |
michael@0 | 584 | |
michael@0 | 585 | /** Mark a given line dirty due to reflow being interrupted on or before it */ |
michael@0 | 586 | void MarkLineDirtyForInterrupt(nsLineBox* aLine); |
michael@0 | 587 | |
michael@0 | 588 | //---------------------------------------- |
michael@0 | 589 | // Methods for line reflow |
michael@0 | 590 | /** |
michael@0 | 591 | * Reflow a line. |
michael@0 | 592 | * @param aState the current reflow state |
michael@0 | 593 | * @param aLine the line to reflow. can contain a single block frame |
michael@0 | 594 | * or contain 1 or more inline frames. |
michael@0 | 595 | * @param aKeepReflowGoing [OUT] indicates whether the caller should continue to reflow more lines |
michael@0 | 596 | */ |
michael@0 | 597 | nsresult ReflowLine(nsBlockReflowState& aState, |
michael@0 | 598 | line_iterator aLine, |
michael@0 | 599 | bool* aKeepReflowGoing); |
michael@0 | 600 | |
michael@0 | 601 | // Return false if it needs another reflow because of reduced space |
michael@0 | 602 | // between floats that are next to it (but not next to its top), and |
michael@0 | 603 | // return true otherwise. |
michael@0 | 604 | bool PlaceLine(nsBlockReflowState& aState, |
michael@0 | 605 | nsLineLayout& aLineLayout, |
michael@0 | 606 | line_iterator aLine, |
michael@0 | 607 | nsFloatManager::SavedState* aFloatStateBeforeLine, |
michael@0 | 608 | nsRect& aFloatAvailableSpace, /* in-out */ |
michael@0 | 609 | nscoord& aAvailableSpaceHeight, /* in-out */ |
michael@0 | 610 | bool* aKeepReflowGoing); |
michael@0 | 611 | |
michael@0 | 612 | /** |
michael@0 | 613 | * If NS_BLOCK_LOOK_FOR_DIRTY_FRAMES is set, call MarkLineDirty |
michael@0 | 614 | * on any line with a child frame that is dirty. |
michael@0 | 615 | */ |
michael@0 | 616 | void LazyMarkLinesDirty(); |
michael@0 | 617 | |
michael@0 | 618 | /** |
michael@0 | 619 | * Mark |aLine| dirty, and, if necessary because of possible |
michael@0 | 620 | * pull-up, mark the previous line dirty as well. Also invalidates textruns |
michael@0 | 621 | * on those lines because the text in the lines might have changed due to |
michael@0 | 622 | * addition/removal of frames. |
michael@0 | 623 | * @param aLine the line to mark dirty |
michael@0 | 624 | * @param aLineList the line list containing that line |
michael@0 | 625 | */ |
michael@0 | 626 | void MarkLineDirty(line_iterator aLine, const nsLineList* aLineList); |
michael@0 | 627 | |
michael@0 | 628 | // XXX where to go |
michael@0 | 629 | bool IsLastLine(nsBlockReflowState& aState, |
michael@0 | 630 | line_iterator aLine); |
michael@0 | 631 | |
michael@0 | 632 | void DeleteLine(nsBlockReflowState& aState, |
michael@0 | 633 | nsLineList::iterator aLine, |
michael@0 | 634 | nsLineList::iterator aLineEnd); |
michael@0 | 635 | |
michael@0 | 636 | //---------------------------------------- |
michael@0 | 637 | // Methods for individual frame reflow |
michael@0 | 638 | |
michael@0 | 639 | bool ShouldApplyTopMargin(nsBlockReflowState& aState, |
michael@0 | 640 | nsLineBox* aLine); |
michael@0 | 641 | |
michael@0 | 642 | nsresult ReflowBlockFrame(nsBlockReflowState& aState, |
michael@0 | 643 | line_iterator aLine, |
michael@0 | 644 | bool* aKeepGoing); |
michael@0 | 645 | |
michael@0 | 646 | nsresult ReflowInlineFrames(nsBlockReflowState& aState, |
michael@0 | 647 | line_iterator aLine, |
michael@0 | 648 | bool* aKeepLineGoing); |
michael@0 | 649 | |
michael@0 | 650 | nsresult DoReflowInlineFrames(nsBlockReflowState& aState, |
michael@0 | 651 | nsLineLayout& aLineLayout, |
michael@0 | 652 | line_iterator aLine, |
michael@0 | 653 | nsFlowAreaRect& aFloatAvailableSpace, |
michael@0 | 654 | nscoord& aAvailableSpaceHeight, |
michael@0 | 655 | nsFloatManager::SavedState* |
michael@0 | 656 | aFloatStateBeforeLine, |
michael@0 | 657 | bool* aKeepReflowGoing, |
michael@0 | 658 | LineReflowStatus* aLineReflowStatus, |
michael@0 | 659 | bool aAllowPullUp); |
michael@0 | 660 | |
michael@0 | 661 | nsresult ReflowInlineFrame(nsBlockReflowState& aState, |
michael@0 | 662 | nsLineLayout& aLineLayout, |
michael@0 | 663 | line_iterator aLine, |
michael@0 | 664 | nsIFrame* aFrame, |
michael@0 | 665 | LineReflowStatus* aLineReflowStatus); |
michael@0 | 666 | |
michael@0 | 667 | // Compute the available width for a float. |
michael@0 | 668 | nsRect AdjustFloatAvailableSpace(nsBlockReflowState& aState, |
michael@0 | 669 | const nsRect& aFloatAvailableSpace, |
michael@0 | 670 | nsIFrame* aFloatFrame); |
michael@0 | 671 | // Computes the border-box width of the float |
michael@0 | 672 | nscoord ComputeFloatWidth(nsBlockReflowState& aState, |
michael@0 | 673 | const nsRect& aFloatAvailableSpace, |
michael@0 | 674 | nsIFrame* aFloat); |
michael@0 | 675 | // An incomplete aReflowStatus indicates the float should be split |
michael@0 | 676 | // but only if the available height is constrained. |
michael@0 | 677 | // aAdjustedAvailableSpace is the result of calling |
michael@0 | 678 | // nsBlockFrame::AdjustFloatAvailableSpace. |
michael@0 | 679 | nsresult ReflowFloat(nsBlockReflowState& aState, |
michael@0 | 680 | const nsRect& aAdjustedAvailableSpace, |
michael@0 | 681 | nsIFrame* aFloat, |
michael@0 | 682 | nsMargin& aFloatMargin, |
michael@0 | 683 | nsMargin& aFloatOffsets, |
michael@0 | 684 | // Whether the float's position |
michael@0 | 685 | // (aAdjustedAvailableSpace) has been pushed down |
michael@0 | 686 | // due to the presence of other floats. |
michael@0 | 687 | bool aFloatPushedDown, |
michael@0 | 688 | nsReflowStatus& aReflowStatus); |
michael@0 | 689 | |
michael@0 | 690 | //---------------------------------------- |
michael@0 | 691 | // Methods for pushing/pulling lines/frames |
michael@0 | 692 | |
michael@0 | 693 | /** |
michael@0 | 694 | * Create a next-in-flow, if necessary, for aFrame. If a new frame is |
michael@0 | 695 | * created, place it in aLine if aLine is not null. |
michael@0 | 696 | * @param aState the block reflow state |
michael@0 | 697 | * @param aLine where to put a new frame |
michael@0 | 698 | * @param aFrame the frame |
michael@0 | 699 | * @return true if a new frame was created, false if not |
michael@0 | 700 | */ |
michael@0 | 701 | bool CreateContinuationFor(nsBlockReflowState& aState, |
michael@0 | 702 | nsLineBox* aLine, |
michael@0 | 703 | nsIFrame* aFrame); |
michael@0 | 704 | |
michael@0 | 705 | /** |
michael@0 | 706 | * Push aLine (and any after it), since it cannot be placed on this |
michael@0 | 707 | * page/column. Set aKeepReflowGoing to false and set |
michael@0 | 708 | * flag aState.mReflowStatus as incomplete. |
michael@0 | 709 | */ |
michael@0 | 710 | void PushTruncatedLine(nsBlockReflowState& aState, |
michael@0 | 711 | line_iterator aLine, |
michael@0 | 712 | bool* aKeepReflowGoing); |
michael@0 | 713 | |
michael@0 | 714 | void SplitLine(nsBlockReflowState& aState, |
michael@0 | 715 | nsLineLayout& aLineLayout, |
michael@0 | 716 | line_iterator aLine, |
michael@0 | 717 | nsIFrame* aFrame, |
michael@0 | 718 | LineReflowStatus* aLineReflowStatus); |
michael@0 | 719 | |
michael@0 | 720 | /** |
michael@0 | 721 | * Pull a frame from the next available location (one of our lines or |
michael@0 | 722 | * one of our next-in-flows lines). |
michael@0 | 723 | * @return the pulled frame or nullptr |
michael@0 | 724 | */ |
michael@0 | 725 | nsIFrame* PullFrame(nsBlockReflowState& aState, |
michael@0 | 726 | line_iterator aLine); |
michael@0 | 727 | |
michael@0 | 728 | /** |
michael@0 | 729 | * Try to pull a frame out of a line pointed at by aFromLine. |
michael@0 | 730 | * |
michael@0 | 731 | * Note: pulling a frame from a line that is a place-holder frame |
michael@0 | 732 | * doesn't automatically remove the corresponding float from the |
michael@0 | 733 | * line's float array. This happens indirectly: either the line gets |
michael@0 | 734 | * emptied (and destroyed) or the line gets reflowed (because we mark |
michael@0 | 735 | * it dirty) and the code at the top of ReflowLine empties the |
michael@0 | 736 | * array. So eventually, it will be removed, just not right away. |
michael@0 | 737 | * |
michael@0 | 738 | * @return the pulled frame or nullptr |
michael@0 | 739 | */ |
michael@0 | 740 | nsIFrame* PullFrameFrom(nsLineBox* aLine, |
michael@0 | 741 | nsBlockFrame* aFromContainer, |
michael@0 | 742 | nsLineList::iterator aFromLine); |
michael@0 | 743 | |
michael@0 | 744 | /** |
michael@0 | 745 | * Push the line after aLineBefore to the overflow line list. |
michael@0 | 746 | * @param aLineBefore a line in 'mLines' (or begin_lines() when |
michael@0 | 747 | * pushing the first line) |
michael@0 | 748 | */ |
michael@0 | 749 | void PushLines(nsBlockReflowState& aState, |
michael@0 | 750 | nsLineList::iterator aLineBefore); |
michael@0 | 751 | |
michael@0 | 752 | void PropagateFloatDamage(nsBlockReflowState& aState, |
michael@0 | 753 | nsLineBox* aLine, |
michael@0 | 754 | nscoord aDeltaY); |
michael@0 | 755 | |
michael@0 | 756 | void CheckFloats(nsBlockReflowState& aState); |
michael@0 | 757 | |
michael@0 | 758 | //---------------------------------------- |
michael@0 | 759 | // List handling kludge |
michael@0 | 760 | |
michael@0 | 761 | // If this returns true, the block it's called on should get the |
michael@0 | 762 | // NS_FRAME_HAS_DIRTY_CHILDREN bit set on it by the caller; either directly |
michael@0 | 763 | // if it's already in reflow, or via calling FrameNeedsReflow() to schedule a |
michael@0 | 764 | // reflow. |
michael@0 | 765 | bool RenumberLists(nsPresContext* aPresContext); |
michael@0 | 766 | |
michael@0 | 767 | static bool RenumberListsInBlock(nsPresContext* aPresContext, |
michael@0 | 768 | nsBlockFrame* aBlockFrame, |
michael@0 | 769 | int32_t* aOrdinal, |
michael@0 | 770 | int32_t aDepth, |
michael@0 | 771 | int32_t aIncrement); |
michael@0 | 772 | |
michael@0 | 773 | static bool RenumberListsFor(nsPresContext* aPresContext, nsIFrame* aKid, |
michael@0 | 774 | int32_t* aOrdinal, int32_t aDepth, |
michael@0 | 775 | int32_t aIncrement); |
michael@0 | 776 | |
michael@0 | 777 | static bool FrameStartsCounterScope(nsIFrame* aFrame); |
michael@0 | 778 | |
michael@0 | 779 | void ReflowBullet(nsIFrame* aBulletFrame, |
michael@0 | 780 | nsBlockReflowState& aState, |
michael@0 | 781 | nsHTMLReflowMetrics& aMetrics, |
michael@0 | 782 | nscoord aLineTop); |
michael@0 | 783 | |
michael@0 | 784 | //---------------------------------------- |
michael@0 | 785 | |
michael@0 | 786 | virtual nsILineIterator* GetLineIterator() MOZ_OVERRIDE; |
michael@0 | 787 | |
michael@0 | 788 | public: |
michael@0 | 789 | bool HasOverflowLines() const { |
michael@0 | 790 | return 0 != (GetStateBits() & NS_BLOCK_HAS_OVERFLOW_LINES); |
michael@0 | 791 | } |
michael@0 | 792 | FrameLines* GetOverflowLines() const; |
michael@0 | 793 | protected: |
michael@0 | 794 | FrameLines* RemoveOverflowLines(); |
michael@0 | 795 | void SetOverflowLines(FrameLines* aOverflowLines); |
michael@0 | 796 | void DestroyOverflowLines(); |
michael@0 | 797 | |
michael@0 | 798 | /** |
michael@0 | 799 | * This class is useful for efficiently modifying the out of flow |
michael@0 | 800 | * overflow list. It gives the client direct writable access to |
michael@0 | 801 | * the frame list temporarily but ensures that property is only |
michael@0 | 802 | * written back if absolutely necessary. |
michael@0 | 803 | */ |
michael@0 | 804 | struct nsAutoOOFFrameList { |
michael@0 | 805 | nsFrameList mList; |
michael@0 | 806 | |
michael@0 | 807 | nsAutoOOFFrameList(nsBlockFrame* aBlock) |
michael@0 | 808 | : mPropValue(aBlock->GetOverflowOutOfFlows()) |
michael@0 | 809 | , mBlock(aBlock) { |
michael@0 | 810 | if (mPropValue) { |
michael@0 | 811 | mList = *mPropValue; |
michael@0 | 812 | } |
michael@0 | 813 | } |
michael@0 | 814 | ~nsAutoOOFFrameList() { |
michael@0 | 815 | mBlock->SetOverflowOutOfFlows(mList, mPropValue); |
michael@0 | 816 | } |
michael@0 | 817 | protected: |
michael@0 | 818 | nsFrameList* const mPropValue; |
michael@0 | 819 | nsBlockFrame* const mBlock; |
michael@0 | 820 | }; |
michael@0 | 821 | friend struct nsAutoOOFFrameList; |
michael@0 | 822 | |
michael@0 | 823 | nsFrameList* GetOverflowOutOfFlows() const; |
michael@0 | 824 | void SetOverflowOutOfFlows(const nsFrameList& aList, nsFrameList* aPropValue); |
michael@0 | 825 | |
michael@0 | 826 | /** |
michael@0 | 827 | * @return the inside bullet frame or nullptr if we don't have one. |
michael@0 | 828 | */ |
michael@0 | 829 | nsBulletFrame* GetInsideBullet() const; |
michael@0 | 830 | |
michael@0 | 831 | /** |
michael@0 | 832 | * @return the outside bullet frame or nullptr if we don't have one. |
michael@0 | 833 | */ |
michael@0 | 834 | nsBulletFrame* GetOutsideBullet() const; |
michael@0 | 835 | |
michael@0 | 836 | /** |
michael@0 | 837 | * @return the outside bullet frame list frame property. |
michael@0 | 838 | */ |
michael@0 | 839 | nsFrameList* GetOutsideBulletList() const; |
michael@0 | 840 | |
michael@0 | 841 | /** |
michael@0 | 842 | * @return true if this frame has pushed floats. |
michael@0 | 843 | */ |
michael@0 | 844 | bool HasPushedFloats() const { |
michael@0 | 845 | return 0 != (GetStateBits() & NS_BLOCK_HAS_PUSHED_FLOATS); |
michael@0 | 846 | } |
michael@0 | 847 | |
michael@0 | 848 | // Get the pushed floats list, which is used for *temporary* storage |
michael@0 | 849 | // of floats during reflow, between when we decide they don't fit in |
michael@0 | 850 | // this block until our next continuation takes them. |
michael@0 | 851 | nsFrameList* GetPushedFloats() const; |
michael@0 | 852 | // Get the pushed floats list, or if there is not currently one, |
michael@0 | 853 | // make a new empty one. |
michael@0 | 854 | nsFrameList* EnsurePushedFloats(); |
michael@0 | 855 | // Remove and return the pushed floats list. |
michael@0 | 856 | nsFrameList* RemovePushedFloats(); |
michael@0 | 857 | |
michael@0 | 858 | #ifdef DEBUG |
michael@0 | 859 | void VerifyLines(bool aFinalCheckOK); |
michael@0 | 860 | void VerifyOverflowSituation(); |
michael@0 | 861 | int32_t GetDepth() const; |
michael@0 | 862 | #endif |
michael@0 | 863 | |
michael@0 | 864 | nscoord mMinWidth, mPrefWidth; |
michael@0 | 865 | |
michael@0 | 866 | nsLineList mLines; |
michael@0 | 867 | |
michael@0 | 868 | // List of all floats in this block |
michael@0 | 869 | // XXXmats blocks rarely have floats, make it a frame property |
michael@0 | 870 | nsFrameList mFloats; |
michael@0 | 871 | |
michael@0 | 872 | friend class nsBlockReflowState; |
michael@0 | 873 | friend class nsBlockInFlowLineIterator; |
michael@0 | 874 | |
michael@0 | 875 | #ifdef DEBUG |
michael@0 | 876 | public: |
michael@0 | 877 | static bool gLamePaintMetrics; |
michael@0 | 878 | static bool gLameReflowMetrics; |
michael@0 | 879 | static bool gNoisy; |
michael@0 | 880 | static bool gNoisyDamageRepair; |
michael@0 | 881 | static bool gNoisyIntrinsic; |
michael@0 | 882 | static bool gNoisyReflow; |
michael@0 | 883 | static bool gReallyNoisyReflow; |
michael@0 | 884 | static bool gNoisyFloatManager; |
michael@0 | 885 | static bool gVerifyLines; |
michael@0 | 886 | static bool gDisableResizeOpt; |
michael@0 | 887 | |
michael@0 | 888 | static int32_t gNoiseIndent; |
michael@0 | 889 | |
michael@0 | 890 | static const char* kReflowCommandType[]; |
michael@0 | 891 | |
michael@0 | 892 | protected: |
michael@0 | 893 | static void InitDebugFlags(); |
michael@0 | 894 | #endif |
michael@0 | 895 | }; |
michael@0 | 896 | |
michael@0 | 897 | #ifdef DEBUG |
michael@0 | 898 | class AutoNoisyIndenter { |
michael@0 | 899 | public: |
michael@0 | 900 | AutoNoisyIndenter(bool aDoIndent) : mIndented(aDoIndent) { |
michael@0 | 901 | if (mIndented) { |
michael@0 | 902 | nsBlockFrame::gNoiseIndent++; |
michael@0 | 903 | } |
michael@0 | 904 | } |
michael@0 | 905 | ~AutoNoisyIndenter() { |
michael@0 | 906 | if (mIndented) { |
michael@0 | 907 | nsBlockFrame::gNoiseIndent--; |
michael@0 | 908 | } |
michael@0 | 909 | } |
michael@0 | 910 | private: |
michael@0 | 911 | bool mIndented; |
michael@0 | 912 | }; |
michael@0 | 913 | #endif |
michael@0 | 914 | |
michael@0 | 915 | /** |
michael@0 | 916 | * Iterates over all lines in the prev-in-flows/next-in-flows of this block. |
michael@0 | 917 | */ |
michael@0 | 918 | class nsBlockInFlowLineIterator { |
michael@0 | 919 | public: |
michael@0 | 920 | typedef nsBlockFrame::line_iterator line_iterator; |
michael@0 | 921 | /** |
michael@0 | 922 | * Set up the iterator to point to aLine which must be a normal line |
michael@0 | 923 | * in aFrame (not an overflow line). |
michael@0 | 924 | */ |
michael@0 | 925 | nsBlockInFlowLineIterator(nsBlockFrame* aFrame, line_iterator aLine); |
michael@0 | 926 | /** |
michael@0 | 927 | * Set up the iterator to point to the first line found starting from |
michael@0 | 928 | * aFrame. Sets aFoundValidLine to false if there is no such line. |
michael@0 | 929 | * After aFoundValidLine has returned false, don't call any methods on this |
michael@0 | 930 | * object again. |
michael@0 | 931 | */ |
michael@0 | 932 | nsBlockInFlowLineIterator(nsBlockFrame* aFrame, bool* aFoundValidLine); |
michael@0 | 933 | /** |
michael@0 | 934 | * Set up the iterator to point to the line that contains aFindFrame (either |
michael@0 | 935 | * directly or indirectly). If aFrame is out of flow, or contained in an |
michael@0 | 936 | * out-of-flow, finds the line containing the out-of-flow's placeholder. If |
michael@0 | 937 | * the frame is not found, sets aFoundValidLine to false. After |
michael@0 | 938 | * aFoundValidLine has returned false, don't call any methods on this |
michael@0 | 939 | * object again. |
michael@0 | 940 | */ |
michael@0 | 941 | nsBlockInFlowLineIterator(nsBlockFrame* aFrame, nsIFrame* aFindFrame, |
michael@0 | 942 | bool* aFoundValidLine); |
michael@0 | 943 | |
michael@0 | 944 | line_iterator GetLine() { return mLine; } |
michael@0 | 945 | bool IsLastLineInList(); |
michael@0 | 946 | nsBlockFrame* GetContainer() { return mFrame; } |
michael@0 | 947 | bool GetInOverflow() { return mLineList != &mFrame->mLines; } |
michael@0 | 948 | |
michael@0 | 949 | /** |
michael@0 | 950 | * Returns the current line list we're iterating, null means |
michael@0 | 951 | * we're iterating |mLines| of the container. |
michael@0 | 952 | */ |
michael@0 | 953 | nsLineList* GetLineList() { return mLineList; } |
michael@0 | 954 | |
michael@0 | 955 | /** |
michael@0 | 956 | * Returns the end-iterator of whatever line list we're in. |
michael@0 | 957 | */ |
michael@0 | 958 | line_iterator End(); |
michael@0 | 959 | |
michael@0 | 960 | /** |
michael@0 | 961 | * Returns false if there are no more lines. After this has returned false, |
michael@0 | 962 | * don't call any methods on this object again. |
michael@0 | 963 | */ |
michael@0 | 964 | bool Next(); |
michael@0 | 965 | /** |
michael@0 | 966 | * Returns false if there are no more lines. After this has returned false, |
michael@0 | 967 | * don't call any methods on this object again. |
michael@0 | 968 | */ |
michael@0 | 969 | bool Prev(); |
michael@0 | 970 | |
michael@0 | 971 | private: |
michael@0 | 972 | friend class nsBlockFrame; |
michael@0 | 973 | // XXX nsBlockFrame uses this internally in one place. Try to remove it. |
michael@0 | 974 | nsBlockInFlowLineIterator(nsBlockFrame* aFrame, line_iterator aLine, bool aInOverflow); |
michael@0 | 975 | |
michael@0 | 976 | nsBlockFrame* mFrame; |
michael@0 | 977 | line_iterator mLine; |
michael@0 | 978 | nsLineList* mLineList; // the line list mLine is in |
michael@0 | 979 | |
michael@0 | 980 | /** |
michael@0 | 981 | * Moves iterator to next valid line reachable from the current block. |
michael@0 | 982 | * Returns false if there are no valid lines. |
michael@0 | 983 | */ |
michael@0 | 984 | bool FindValidLine(); |
michael@0 | 985 | }; |
michael@0 | 986 | |
michael@0 | 987 | #endif /* nsBlockFrame_h___ */ |