1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/generic/nsBlockFrame.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,987 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +// vim:cindent:ts=2:et:sw=2: 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * rendering object for CSS display:block, inline-block, and list-item 1.12 + * boxes, also used for various anonymous boxes 1.13 + */ 1.14 + 1.15 +#ifndef nsBlockFrame_h___ 1.16 +#define nsBlockFrame_h___ 1.17 + 1.18 +#include "nsContainerFrame.h" 1.19 +#include "nsHTMLParts.h" 1.20 +#include "nsLineBox.h" 1.21 +#include "nsCSSPseudoElements.h" 1.22 +#include "nsStyleSet.h" 1.23 +#include "nsFloatManager.h" 1.24 + 1.25 +enum LineReflowStatus { 1.26 + // The line was completely reflowed and fit in available width, and we should 1.27 + // try to pull up content from the next line if possible. 1.28 + LINE_REFLOW_OK, 1.29 + // The line was completely reflowed and fit in available width, but we should 1.30 + // not try to pull up content from the next line. 1.31 + LINE_REFLOW_STOP, 1.32 + // We need to reflow the line again at its current vertical position. The 1.33 + // new reflow should not try to pull up any frames from the next line. 1.34 + LINE_REFLOW_REDO_NO_PULL, 1.35 + // We need to reflow the line again using the floats from its height 1.36 + // this reflow, since its height made it hit floats that were not 1.37 + // adjacent to its top. 1.38 + LINE_REFLOW_REDO_MORE_FLOATS, 1.39 + // We need to reflow the line again at a lower vertical postion where there 1.40 + // may be more horizontal space due to different float configuration. 1.41 + LINE_REFLOW_REDO_NEXT_BAND, 1.42 + // The line did not fit in the available vertical space. Try pushing it to 1.43 + // the next page or column if it's not the first line on the current page/column. 1.44 + LINE_REFLOW_TRUNCATED 1.45 +}; 1.46 + 1.47 +class nsBlockReflowState; 1.48 +class nsBlockInFlowLineIterator; 1.49 +class nsBulletFrame; 1.50 +class nsFirstLineFrame; 1.51 + 1.52 +/** 1.53 + * Some invariants: 1.54 + * -- The overflow out-of-flows list contains the out-of- 1.55 + * flow frames whose placeholders are in the overflow list. 1.56 + * -- A given piece of content has at most one placeholder 1.57 + * frame in a block's normal child list. 1.58 + * -- While a block is being reflowed, and from then until 1.59 + * its next-in-flow is reflowed it may have a 1.60 + * PushedFloatProperty frame property that points to 1.61 + * an nsFrameList. This list contains continuations for 1.62 + * floats whose prev-in-flow is in the block's regular float 1.63 + * list and first-in-flows of floats that did not fit, but 1.64 + * whose placeholders are in the block or one of its 1.65 + * prev-in-flows. 1.66 + * -- In all these frame lists, if there are two frames for 1.67 + * the same content appearing in the list, then the frames 1.68 + * appear with the prev-in-flow before the next-in-flow. 1.69 + * -- While reflowing a block, its overflow line list 1.70 + * will usually be empty but in some cases will have lines 1.71 + * (while we reflow the block at its shrink-wrap width). 1.72 + * In this case any new overflowing content must be 1.73 + * prepended to the overflow lines. 1.74 + */ 1.75 + 1.76 +typedef nsContainerFrame nsBlockFrameSuper; 1.77 + 1.78 +/* 1.79 + * Base class for block and inline frames. 1.80 + * The block frame has an additional child list, kAbsoluteList, which 1.81 + * contains the absolutely positioned frames. 1.82 + */ 1.83 +class nsBlockFrame : public nsBlockFrameSuper 1.84 +{ 1.85 +public: 1.86 + NS_DECL_QUERYFRAME_TARGET(nsBlockFrame) 1.87 + NS_DECL_FRAMEARENA_HELPERS 1.88 + 1.89 + typedef nsLineList::iterator line_iterator; 1.90 + typedef nsLineList::const_iterator const_line_iterator; 1.91 + typedef nsLineList::reverse_iterator reverse_line_iterator; 1.92 + typedef nsLineList::const_reverse_iterator const_reverse_line_iterator; 1.93 + 1.94 + line_iterator begin_lines() { return mLines.begin(); } 1.95 + line_iterator end_lines() { return mLines.end(); } 1.96 + const_line_iterator begin_lines() const { return mLines.begin(); } 1.97 + const_line_iterator end_lines() const { return mLines.end(); } 1.98 + reverse_line_iterator rbegin_lines() { return mLines.rbegin(); } 1.99 + reverse_line_iterator rend_lines() { return mLines.rend(); } 1.100 + const_reverse_line_iterator rbegin_lines() const { return mLines.rbegin(); } 1.101 + const_reverse_line_iterator rend_lines() const { return mLines.rend(); } 1.102 + line_iterator line(nsLineBox* aList) { return mLines.begin(aList); } 1.103 + reverse_line_iterator rline(nsLineBox* aList) { return mLines.rbegin(aList); } 1.104 + 1.105 + friend nsIFrame* NS_NewBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, nsFrameState aFlags); 1.106 + 1.107 + // nsQueryFrame 1.108 + NS_DECL_QUERYFRAME 1.109 + 1.110 + // nsIFrame 1.111 + virtual void Init(nsIContent* aContent, 1.112 + nsIFrame* aParent, 1.113 + nsIFrame* aPrevInFlow) MOZ_OVERRIDE; 1.114 + virtual nsresult SetInitialChildList(ChildListID aListID, 1.115 + nsFrameList& aChildList) MOZ_OVERRIDE; 1.116 + virtual nsresult AppendFrames(ChildListID aListID, 1.117 + nsFrameList& aFrameList) MOZ_OVERRIDE; 1.118 + virtual nsresult InsertFrames(ChildListID aListID, 1.119 + nsIFrame* aPrevFrame, 1.120 + nsFrameList& aFrameList) MOZ_OVERRIDE; 1.121 + virtual nsresult RemoveFrame(ChildListID aListID, 1.122 + nsIFrame* aOldFrame) MOZ_OVERRIDE; 1.123 + virtual const nsFrameList& GetChildList(ChildListID aListID) const MOZ_OVERRIDE; 1.124 + virtual void GetChildLists(nsTArray<ChildList>* aLists) const MOZ_OVERRIDE; 1.125 + virtual nscoord GetBaseline() const MOZ_OVERRIDE; 1.126 + virtual nscoord GetCaretBaseline() const MOZ_OVERRIDE; 1.127 + virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; 1.128 + virtual nsSplittableType GetSplittableType() const MOZ_OVERRIDE; 1.129 + virtual bool IsFloatContainingBlock() const MOZ_OVERRIDE; 1.130 + virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.131 + const nsRect& aDirtyRect, 1.132 + const nsDisplayListSet& aLists) MOZ_OVERRIDE; 1.133 + virtual nsIAtom* GetType() const MOZ_OVERRIDE; 1.134 + virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE 1.135 + { 1.136 + return nsContainerFrame::IsFrameOfType(aFlags & 1.137 + ~(nsIFrame::eCanContainOverflowContainers | 1.138 + nsIFrame::eBlockFrame)); 1.139 + } 1.140 + 1.141 + virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; 1.142 + virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; 1.143 + 1.144 +#ifdef DEBUG_FRAME_DUMP 1.145 + void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE; 1.146 + virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; 1.147 +#endif 1.148 + 1.149 +#ifdef DEBUG 1.150 + virtual nsFrameState GetDebugStateBits() const MOZ_OVERRIDE; 1.151 +#endif 1.152 + 1.153 +#ifdef ACCESSIBILITY 1.154 + virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE; 1.155 +#endif 1.156 + 1.157 + // line cursor methods to speed up searching for the line(s) 1.158 + // containing a point. The basic idea is that we set the cursor 1.159 + // property if the lines' overflowArea.VisualOverflow().ys and 1.160 + // overflowArea.VisualOverflow().yMosts are non-decreasing 1.161 + // (considering only non-empty overflowArea.VisualOverflow()s; empty 1.162 + // overflowArea.VisualOverflow()s never participate in event handling 1.163 + // or painting), and the block has sufficient number of lines. The 1.164 + // cursor property points to a "recently used" line. If we get a 1.165 + // series of requests that work on lines 1.166 + // "near" the cursor, then we can find those nearby lines quickly by 1.167 + // starting our search at the cursor. 1.168 + 1.169 + // Clear out line cursor because we're disturbing the lines (i.e., Reflow) 1.170 + void ClearLineCursor(); 1.171 + // Get the first line that might contain y-coord 'y', or nullptr if you must search 1.172 + // all lines. If nonnull is returned then we guarantee that the lines' 1.173 + // combinedArea.ys and combinedArea.yMosts are non-decreasing. 1.174 + // The actual line returned might not contain 'y', but if not, it is guaranteed 1.175 + // to be before any line which does contain 'y'. 1.176 + nsLineBox* GetFirstLineContaining(nscoord y); 1.177 + // Set the line cursor to our first line. Only call this if you 1.178 + // guarantee that the lines' combinedArea.ys and combinedArea.yMosts 1.179 + // are non-decreasing. 1.180 + void SetupLineCursor(); 1.181 + 1.182 + virtual void ChildIsDirty(nsIFrame* aChild) MOZ_OVERRIDE; 1.183 + virtual bool IsVisibleInSelection(nsISelection* aSelection) MOZ_OVERRIDE; 1.184 + 1.185 + virtual bool IsEmpty() MOZ_OVERRIDE; 1.186 + virtual bool CachedIsEmpty() MOZ_OVERRIDE; 1.187 + virtual bool IsSelfEmpty() MOZ_OVERRIDE; 1.188 + 1.189 + // Given that we have a bullet, does it actually draw something, i.e., 1.190 + // do we have either a 'list-style-type' or 'list-style-image' that is 1.191 + // not 'none'? 1.192 + bool BulletIsEmpty() const; 1.193 + 1.194 + /** 1.195 + * Return the bullet text equivalent. 1.196 + */ 1.197 + void GetBulletText(nsAString& aText) const; 1.198 + 1.199 + /** 1.200 + * Return true if there's a bullet. 1.201 + */ 1.202 + bool HasBullet() const { 1.203 + return HasOutsideBullet() || HasInsideBullet(); 1.204 + } 1.205 + 1.206 + /** 1.207 + * @return true if this frame has an inside bullet frame. 1.208 + */ 1.209 + bool HasInsideBullet() const { 1.210 + return 0 != (mState & NS_BLOCK_FRAME_HAS_INSIDE_BULLET); 1.211 + } 1.212 + 1.213 + /** 1.214 + * @return true if this frame has an outside bullet frame. 1.215 + */ 1.216 + bool HasOutsideBullet() const { 1.217 + return 0 != (mState & NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET); 1.218 + } 1.219 + 1.220 + /** 1.221 + * @return the bullet frame or nullptr if we don't have one. 1.222 + */ 1.223 + nsBulletFrame* GetBullet() const { 1.224 + nsBulletFrame* outside = GetOutsideBullet(); 1.225 + return outside ? outside : GetInsideBullet(); 1.226 + } 1.227 + 1.228 + virtual void MarkIntrinsicWidthsDirty() MOZ_OVERRIDE; 1.229 +private: 1.230 + void CheckIntrinsicCacheAgainstShrinkWrapState(); 1.231 +public: 1.232 + virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; 1.233 + virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; 1.234 + 1.235 + virtual nsRect ComputeTightBounds(gfxContext* aContext) const MOZ_OVERRIDE; 1.236 + 1.237 + virtual nsresult GetPrefWidthTightBounds(nsRenderingContext* aContext, 1.238 + nscoord* aX, 1.239 + nscoord* aXMost) MOZ_OVERRIDE; 1.240 + 1.241 + /** 1.242 + * Compute the final height of this frame. 1.243 + * 1.244 + * @param aReflowState Data structure passed from parent during reflow. 1.245 + * @param aReflowStatus A pointed to the reflow status for when we're finished 1.246 + * doing reflow. this will get set appropriately if the height causes 1.247 + * us to exceed the current available (page) height. 1.248 + * @param aContentHeight The height of content, precomputed outside of this 1.249 + * function. The final height that is used in aMetrics will be set to 1.250 + * either this or the available height, whichever is larger, in the 1.251 + * case where our available height is constrained, and we overflow that 1.252 + * available height. 1.253 + * @param aBorderPadding The margins representing the border padding for block 1.254 + * frames. Can be 0. 1.255 + * @param aMetrics Out parameter for final height. Taken as an 1.256 + * nsHTMLReflowMetrics object so that aMetrics can be passed in 1.257 + * directly during reflow. 1.258 + * @param aConsumed The height already consumed by our previous-in-flows. 1.259 + */ 1.260 + void ComputeFinalHeight(const nsHTMLReflowState& aReflowState, 1.261 + nsReflowStatus* aStatus, 1.262 + nscoord aContentHeight, 1.263 + const nsMargin& aBorderPadding, 1.264 + nsHTMLReflowMetrics& aMetrics, 1.265 + nscoord aConsumed); 1.266 + 1.267 + virtual nsresult Reflow(nsPresContext* aPresContext, 1.268 + nsHTMLReflowMetrics& aDesiredSize, 1.269 + const nsHTMLReflowState& aReflowState, 1.270 + nsReflowStatus& aStatus) MOZ_OVERRIDE; 1.271 + 1.272 + virtual nsresult AttributeChanged(int32_t aNameSpaceID, 1.273 + nsIAtom* aAttribute, 1.274 + int32_t aModType) MOZ_OVERRIDE; 1.275 + 1.276 + /** 1.277 + * Move any frames on our overflow list to the end of our principal list. 1.278 + * @return true if there were any overflow frames 1.279 + */ 1.280 + virtual bool DrainSelfOverflowList() MOZ_OVERRIDE; 1.281 + 1.282 + virtual nsresult StealFrame(nsIFrame* aChild, 1.283 + bool aForceNormal = false) MOZ_OVERRIDE; 1.284 + 1.285 + virtual void DeleteNextInFlowChild(nsIFrame* aNextInFlow, 1.286 + bool aDeletingEmptyFrames) MOZ_OVERRIDE; 1.287 + 1.288 + /** 1.289 + * This is a special method that allows a child class of nsBlockFrame to 1.290 + * return a special, customized nsStyleText object to the nsLineLayout 1.291 + * constructor. It is used when the nsBlockFrame child needs to specify its 1.292 + * custom rendering style. 1.293 + */ 1.294 + virtual const nsStyleText* StyleTextForLineLayout(); 1.295 + 1.296 + /** 1.297 + * Determines whether the collapsed margin carried out of the last 1.298 + * line includes the margin-top of a line with clearance (in which 1.299 + * case we must avoid collapsing that margin with our bottom margin) 1.300 + */ 1.301 + bool CheckForCollapsedBottomMarginFromClearanceLine(); 1.302 + 1.303 + static nsresult GetCurrentLine(nsBlockReflowState *aState, nsLineBox **aOutCurrentLine); 1.304 + 1.305 + /** 1.306 + * Determine if this block is a margin root at the top/bottom edges. 1.307 + */ 1.308 + void IsMarginRoot(bool* aTopMarginRoot, bool* aBottomMarginRoot); 1.309 + 1.310 + static bool BlockNeedsFloatManager(nsIFrame* aBlock); 1.311 + 1.312 + /** 1.313 + * Returns whether aFrame is a block frame that will wrap its contents 1.314 + * around floats intruding on it from the outside. (aFrame need not 1.315 + * be a block frame, but if it's not, the result will be false.) 1.316 + */ 1.317 + static bool BlockCanIntersectFloats(nsIFrame* aFrame); 1.318 + 1.319 + /** 1.320 + * Returns the width that needs to be cleared past floats for blocks 1.321 + * that cannot intersect floats. aState must already have 1.322 + * GetAvailableSpace called on it for the vertical position that we 1.323 + * care about (which need not be its current mY) 1.324 + */ 1.325 + struct ReplacedElementWidthToClear { 1.326 + nscoord marginLeft, borderBoxWidth, marginRight; 1.327 + nscoord MarginBoxWidth() const 1.328 + { return marginLeft + borderBoxWidth + marginRight; } 1.329 + }; 1.330 + static ReplacedElementWidthToClear 1.331 + WidthToClearPastFloats(nsBlockReflowState& aState, 1.332 + const nsRect& aFloatAvailableSpace, 1.333 + nsIFrame* aFrame); 1.334 + 1.335 + /** 1.336 + * Creates a contination for aFloat and adds it to the list of overflow floats. 1.337 + * Also updates aState.mReflowStatus to include the float's incompleteness. 1.338 + * Must only be called while this block frame is in reflow. 1.339 + * aFloatStatus must be the float's true, unmodified reflow status. 1.340 + * 1.341 + */ 1.342 + nsresult SplitFloat(nsBlockReflowState& aState, 1.343 + nsIFrame* aFloat, 1.344 + nsReflowStatus aFloatStatus); 1.345 + 1.346 + /** 1.347 + * Walks up the frame tree, starting with aCandidate, and returns the first 1.348 + * block frame that it encounters. 1.349 + */ 1.350 + static nsBlockFrame* GetNearestAncestorBlock(nsIFrame* aCandidate); 1.351 + 1.352 + struct FrameLines { 1.353 + nsLineList mLines; 1.354 + nsFrameList mFrames; 1.355 + }; 1.356 + 1.357 +protected: 1.358 + nsBlockFrame(nsStyleContext* aContext) 1.359 + : nsContainerFrame(aContext) 1.360 + , mMinWidth(NS_INTRINSIC_WIDTH_UNKNOWN) 1.361 + , mPrefWidth(NS_INTRINSIC_WIDTH_UNKNOWN) 1.362 + { 1.363 +#ifdef DEBUG 1.364 + InitDebugFlags(); 1.365 +#endif 1.366 + } 1.367 + virtual ~nsBlockFrame(); 1.368 + 1.369 +#ifdef DEBUG 1.370 + already_AddRefed<nsStyleContext> GetFirstLetterStyle(nsPresContext* aPresContext) 1.371 + { 1.372 + return aPresContext->StyleSet()-> 1.373 + ProbePseudoElementStyle(mContent->AsElement(), 1.374 + nsCSSPseudoElements::ePseudo_firstLetter, 1.375 + mStyleContext); 1.376 + } 1.377 +#endif 1.378 + 1.379 + NS_DECLARE_FRAME_PROPERTY(LineCursorProperty, nullptr) 1.380 + nsLineBox* GetLineCursor() { 1.381 + return (GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR) ? 1.382 + static_cast<nsLineBox*>(Properties().Get(LineCursorProperty())) : nullptr; 1.383 + } 1.384 + 1.385 + nsLineBox* NewLineBox(nsIFrame* aFrame, bool aIsBlock) { 1.386 + return NS_NewLineBox(PresContext()->PresShell(), aFrame, aIsBlock); 1.387 + } 1.388 + nsLineBox* NewLineBox(nsLineBox* aFromLine, nsIFrame* aFrame, int32_t aCount) { 1.389 + return NS_NewLineBox(PresContext()->PresShell(), aFromLine, aFrame, aCount); 1.390 + } 1.391 + void FreeLineBox(nsLineBox* aLine) { 1.392 + if (aLine == GetLineCursor()) { 1.393 + ClearLineCursor(); 1.394 + } 1.395 + aLine->Destroy(PresContext()->PresShell()); 1.396 + } 1.397 + /** 1.398 + * Helper method for StealFrame. 1.399 + */ 1.400 + void RemoveFrameFromLine(nsIFrame* aChild, nsLineList::iterator aLine, 1.401 + nsFrameList& aFrameList, nsLineList& aLineList); 1.402 + 1.403 + void TryAllLines(nsLineList::iterator* aIterator, 1.404 + nsLineList::iterator* aStartIterator, 1.405 + nsLineList::iterator* aEndIterator, 1.406 + bool* aInOverflowLines, 1.407 + FrameLines** aOverflowLines); 1.408 + 1.409 + void SetFlags(nsFrameState aFlags) { 1.410 + mState &= ~NS_BLOCK_FLAGS_MASK; 1.411 + mState |= aFlags; 1.412 + } 1.413 + 1.414 + /** move the frames contained by aLine by aDY 1.415 + * if aLine is a block, its child floats are added to the state manager 1.416 + */ 1.417 + void SlideLine(nsBlockReflowState& aState, 1.418 + nsLineBox* aLine, nscoord aDY); 1.419 + 1.420 + void ComputeFinalSize(const nsHTMLReflowState& aReflowState, 1.421 + nsBlockReflowState& aState, 1.422 + nsHTMLReflowMetrics& aMetrics, 1.423 + nscoord* aBottomEdgeOfChildren); 1.424 + 1.425 + void ComputeOverflowAreas(const nsRect& aBounds, 1.426 + const nsStyleDisplay* aDisplay, 1.427 + nscoord aBottomEdgeOfChildren, 1.428 + nsOverflowAreas& aOverflowAreas); 1.429 + 1.430 + /** 1.431 + * Add the frames in aFrameList to this block after aPrevSibling. 1.432 + * This block thinks in terms of lines, but the frame construction code 1.433 + * knows nothing about lines at all so we need to find the line that 1.434 + * contains aPrevSibling and add aFrameList after aPrevSibling on that line. 1.435 + * New lines are created as necessary to handle block data in aFrameList. 1.436 + * This function will clear aFrameList. 1.437 + */ 1.438 + void AddFrames(nsFrameList& aFrameList, nsIFrame* aPrevSibling); 1.439 + 1.440 + /** 1.441 + * Perform Bidi resolution on this frame 1.442 + */ 1.443 + nsresult ResolveBidi(); 1.444 + 1.445 + /** 1.446 + * Test whether the frame is a form control in a visual Bidi page. 1.447 + * This is necessary for backwards-compatibility, because most visual 1.448 + * pages use logical order for form controls so that they will 1.449 + * display correctly on native widgets in OSs with Bidi support 1.450 + * @param aPresContext the pres context 1.451 + * @return whether the frame is a BIDI form control 1.452 + */ 1.453 + bool IsVisualFormControl(nsPresContext* aPresContext); 1.454 + 1.455 +public: 1.456 + /** 1.457 + * Does all the real work for removing aDeletedFrame 1.458 + * -- finds the line containing aDeletedFrame 1.459 + * -- removes all aDeletedFrame next-in-flows (or all continuations, 1.460 + * if REMOVE_FIXED_CONTINUATIONS is given) 1.461 + * -- marks lines dirty as needed 1.462 + * -- marks textruns dirty (unless FRAMES_ARE_EMPTY is given, in which 1.463 + * case textruns do not need to be dirtied) 1.464 + * -- destroys all removed frames 1.465 + */ 1.466 + enum { 1.467 + REMOVE_FIXED_CONTINUATIONS = 0x02, 1.468 + FRAMES_ARE_EMPTY = 0x04 1.469 + }; 1.470 + nsresult DoRemoveFrame(nsIFrame* aDeletedFrame, uint32_t aFlags); 1.471 + 1.472 + void ReparentFloats(nsIFrame* aFirstFrame, nsBlockFrame* aOldParent, 1.473 + bool aReparentSiblings); 1.474 + 1.475 + virtual bool UpdateOverflow() MOZ_OVERRIDE; 1.476 + 1.477 + /** Load all of aFrame's floats into the float manager iff aFrame is not a 1.478 + * block formatting context. Handles all necessary float manager translations; 1.479 + * assumes float manager is in aFrame's parent's coord system. 1.480 + * Safe to call on non-blocks (does nothing). 1.481 + */ 1.482 + static void RecoverFloatsFor(nsIFrame* aFrame, 1.483 + nsFloatManager& aFloatManager); 1.484 + 1.485 + /** 1.486 + * Determine if we have any pushed floats from a previous continuation. 1.487 + * 1.488 + * @returns true, if any of the floats at the beginning of our mFloats list 1.489 + * have the NS_FRAME_IS_PUSHED_FLOAT bit set; false otherwise. 1.490 + */ 1.491 + bool HasPushedFloatsFromPrevContinuation() const { 1.492 + if (!mFloats.IsEmpty()) { 1.493 + // If we have pushed floats, then they should be at the beginning of our 1.494 + // float list. 1.495 + if (mFloats.FirstChild()->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT) { 1.496 + return true; 1.497 + } 1.498 + } 1.499 + 1.500 +#ifdef DEBUG 1.501 + // Double-check the above assertion that pushed floats should be at the 1.502 + // beginning of our floats list. 1.503 + for (nsFrameList::Enumerator e(mFloats); !e.AtEnd(); e.Next()) { 1.504 + nsIFrame* f = e.get(); 1.505 + NS_ASSERTION(!(f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT), 1.506 + "pushed floats must be at the beginning of the float list"); 1.507 + } 1.508 +#endif 1.509 + return false; 1.510 + } 1.511 + 1.512 +protected: 1.513 + 1.514 + /** grab overflow lines from this block's prevInFlow, and make them 1.515 + * part of this block's mLines list. 1.516 + * @return true if any lines were drained. 1.517 + */ 1.518 + bool DrainOverflowLines(); 1.519 + 1.520 + /** 1.521 + * @return false iff this block does not have a float on any child list. 1.522 + * This function is O(1). 1.523 + */ 1.524 + bool MaybeHasFloats() const { 1.525 + if (!mFloats.IsEmpty()) { 1.526 + return true; 1.527 + } 1.528 + // XXX this could be replaced with HasPushedFloats() if we enforced 1.529 + // removing the property when the frame list becomes empty. 1.530 + nsFrameList* list = GetPushedFloats(); 1.531 + if (list && !list->IsEmpty()) { 1.532 + return true; 1.533 + } 1.534 + // For the OverflowOutOfFlowsProperty I think we do enforce that, but it's 1.535 + // a mix of out-of-flow frames, so that's why the method name has "Maybe". 1.536 + return GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS; 1.537 + } 1.538 + 1.539 + /** grab pushed floats from this block's prevInFlow, and splice 1.540 + * them into this block's mFloats list. 1.541 + */ 1.542 + void DrainPushedFloats(nsBlockReflowState& aState); 1.543 + 1.544 + /** Load all our floats into the float manager (without reflowing them). 1.545 + * Assumes float manager is in our own coordinate system. 1.546 + */ 1.547 + void RecoverFloats(nsFloatManager& aFloatManager); 1.548 + 1.549 + /** Reflow pushed floats 1.550 + */ 1.551 + void ReflowPushedFloats(nsBlockReflowState& aState, 1.552 + nsOverflowAreas& aOverflowAreas, 1.553 + nsReflowStatus& aStatus); 1.554 + 1.555 + /** Find any trailing BR clear from the last line of the block (or its PIFs) 1.556 + */ 1.557 + uint8_t FindTrailingClear(); 1.558 + 1.559 + /** 1.560 + * Remove a float from our float list. 1.561 + */ 1.562 + void RemoveFloat(nsIFrame* aFloat); 1.563 + /** 1.564 + * Remove a float from the float cache for the line its placeholder is on. 1.565 + */ 1.566 + void RemoveFloatFromFloatCache(nsIFrame* aFloat); 1.567 + 1.568 + void CollectFloats(nsIFrame* aFrame, nsFrameList& aList, 1.569 + bool aCollectFromSiblings) { 1.570 + if (MaybeHasFloats()) { 1.571 + DoCollectFloats(aFrame, aList, aCollectFromSiblings); 1.572 + } 1.573 + } 1.574 + void DoCollectFloats(nsIFrame* aFrame, nsFrameList& aList, 1.575 + bool aCollectFromSiblings); 1.576 + 1.577 + // Remove a float, abs, rel positioned frame from the appropriate block's list 1.578 + static void DoRemoveOutOfFlowFrame(nsIFrame* aFrame); 1.579 + 1.580 + /** set up the conditions necessary for an resize reflow 1.581 + * the primary task is to mark the minimumly sufficient lines dirty. 1.582 + */ 1.583 + void PrepareResizeReflow(nsBlockReflowState& aState); 1.584 + 1.585 + /** reflow all lines that have been marked dirty */ 1.586 + nsresult ReflowDirtyLines(nsBlockReflowState& aState); 1.587 + 1.588 + /** Mark a given line dirty due to reflow being interrupted on or before it */ 1.589 + void MarkLineDirtyForInterrupt(nsLineBox* aLine); 1.590 + 1.591 + //---------------------------------------- 1.592 + // Methods for line reflow 1.593 + /** 1.594 + * Reflow a line. 1.595 + * @param aState the current reflow state 1.596 + * @param aLine the line to reflow. can contain a single block frame 1.597 + * or contain 1 or more inline frames. 1.598 + * @param aKeepReflowGoing [OUT] indicates whether the caller should continue to reflow more lines 1.599 + */ 1.600 + nsresult ReflowLine(nsBlockReflowState& aState, 1.601 + line_iterator aLine, 1.602 + bool* aKeepReflowGoing); 1.603 + 1.604 + // Return false if it needs another reflow because of reduced space 1.605 + // between floats that are next to it (but not next to its top), and 1.606 + // return true otherwise. 1.607 + bool PlaceLine(nsBlockReflowState& aState, 1.608 + nsLineLayout& aLineLayout, 1.609 + line_iterator aLine, 1.610 + nsFloatManager::SavedState* aFloatStateBeforeLine, 1.611 + nsRect& aFloatAvailableSpace, /* in-out */ 1.612 + nscoord& aAvailableSpaceHeight, /* in-out */ 1.613 + bool* aKeepReflowGoing); 1.614 + 1.615 + /** 1.616 + * If NS_BLOCK_LOOK_FOR_DIRTY_FRAMES is set, call MarkLineDirty 1.617 + * on any line with a child frame that is dirty. 1.618 + */ 1.619 + void LazyMarkLinesDirty(); 1.620 + 1.621 + /** 1.622 + * Mark |aLine| dirty, and, if necessary because of possible 1.623 + * pull-up, mark the previous line dirty as well. Also invalidates textruns 1.624 + * on those lines because the text in the lines might have changed due to 1.625 + * addition/removal of frames. 1.626 + * @param aLine the line to mark dirty 1.627 + * @param aLineList the line list containing that line 1.628 + */ 1.629 + void MarkLineDirty(line_iterator aLine, const nsLineList* aLineList); 1.630 + 1.631 + // XXX where to go 1.632 + bool IsLastLine(nsBlockReflowState& aState, 1.633 + line_iterator aLine); 1.634 + 1.635 + void DeleteLine(nsBlockReflowState& aState, 1.636 + nsLineList::iterator aLine, 1.637 + nsLineList::iterator aLineEnd); 1.638 + 1.639 + //---------------------------------------- 1.640 + // Methods for individual frame reflow 1.641 + 1.642 + bool ShouldApplyTopMargin(nsBlockReflowState& aState, 1.643 + nsLineBox* aLine); 1.644 + 1.645 + nsresult ReflowBlockFrame(nsBlockReflowState& aState, 1.646 + line_iterator aLine, 1.647 + bool* aKeepGoing); 1.648 + 1.649 + nsresult ReflowInlineFrames(nsBlockReflowState& aState, 1.650 + line_iterator aLine, 1.651 + bool* aKeepLineGoing); 1.652 + 1.653 + nsresult DoReflowInlineFrames(nsBlockReflowState& aState, 1.654 + nsLineLayout& aLineLayout, 1.655 + line_iterator aLine, 1.656 + nsFlowAreaRect& aFloatAvailableSpace, 1.657 + nscoord& aAvailableSpaceHeight, 1.658 + nsFloatManager::SavedState* 1.659 + aFloatStateBeforeLine, 1.660 + bool* aKeepReflowGoing, 1.661 + LineReflowStatus* aLineReflowStatus, 1.662 + bool aAllowPullUp); 1.663 + 1.664 + nsresult ReflowInlineFrame(nsBlockReflowState& aState, 1.665 + nsLineLayout& aLineLayout, 1.666 + line_iterator aLine, 1.667 + nsIFrame* aFrame, 1.668 + LineReflowStatus* aLineReflowStatus); 1.669 + 1.670 + // Compute the available width for a float. 1.671 + nsRect AdjustFloatAvailableSpace(nsBlockReflowState& aState, 1.672 + const nsRect& aFloatAvailableSpace, 1.673 + nsIFrame* aFloatFrame); 1.674 + // Computes the border-box width of the float 1.675 + nscoord ComputeFloatWidth(nsBlockReflowState& aState, 1.676 + const nsRect& aFloatAvailableSpace, 1.677 + nsIFrame* aFloat); 1.678 + // An incomplete aReflowStatus indicates the float should be split 1.679 + // but only if the available height is constrained. 1.680 + // aAdjustedAvailableSpace is the result of calling 1.681 + // nsBlockFrame::AdjustFloatAvailableSpace. 1.682 + nsresult ReflowFloat(nsBlockReflowState& aState, 1.683 + const nsRect& aAdjustedAvailableSpace, 1.684 + nsIFrame* aFloat, 1.685 + nsMargin& aFloatMargin, 1.686 + nsMargin& aFloatOffsets, 1.687 + // Whether the float's position 1.688 + // (aAdjustedAvailableSpace) has been pushed down 1.689 + // due to the presence of other floats. 1.690 + bool aFloatPushedDown, 1.691 + nsReflowStatus& aReflowStatus); 1.692 + 1.693 + //---------------------------------------- 1.694 + // Methods for pushing/pulling lines/frames 1.695 + 1.696 + /** 1.697 + * Create a next-in-flow, if necessary, for aFrame. If a new frame is 1.698 + * created, place it in aLine if aLine is not null. 1.699 + * @param aState the block reflow state 1.700 + * @param aLine where to put a new frame 1.701 + * @param aFrame the frame 1.702 + * @return true if a new frame was created, false if not 1.703 + */ 1.704 + bool CreateContinuationFor(nsBlockReflowState& aState, 1.705 + nsLineBox* aLine, 1.706 + nsIFrame* aFrame); 1.707 + 1.708 + /** 1.709 + * Push aLine (and any after it), since it cannot be placed on this 1.710 + * page/column. Set aKeepReflowGoing to false and set 1.711 + * flag aState.mReflowStatus as incomplete. 1.712 + */ 1.713 + void PushTruncatedLine(nsBlockReflowState& aState, 1.714 + line_iterator aLine, 1.715 + bool* aKeepReflowGoing); 1.716 + 1.717 + void SplitLine(nsBlockReflowState& aState, 1.718 + nsLineLayout& aLineLayout, 1.719 + line_iterator aLine, 1.720 + nsIFrame* aFrame, 1.721 + LineReflowStatus* aLineReflowStatus); 1.722 + 1.723 + /** 1.724 + * Pull a frame from the next available location (one of our lines or 1.725 + * one of our next-in-flows lines). 1.726 + * @return the pulled frame or nullptr 1.727 + */ 1.728 + nsIFrame* PullFrame(nsBlockReflowState& aState, 1.729 + line_iterator aLine); 1.730 + 1.731 + /** 1.732 + * Try to pull a frame out of a line pointed at by aFromLine. 1.733 + * 1.734 + * Note: pulling a frame from a line that is a place-holder frame 1.735 + * doesn't automatically remove the corresponding float from the 1.736 + * line's float array. This happens indirectly: either the line gets 1.737 + * emptied (and destroyed) or the line gets reflowed (because we mark 1.738 + * it dirty) and the code at the top of ReflowLine empties the 1.739 + * array. So eventually, it will be removed, just not right away. 1.740 + * 1.741 + * @return the pulled frame or nullptr 1.742 + */ 1.743 + nsIFrame* PullFrameFrom(nsLineBox* aLine, 1.744 + nsBlockFrame* aFromContainer, 1.745 + nsLineList::iterator aFromLine); 1.746 + 1.747 + /** 1.748 + * Push the line after aLineBefore to the overflow line list. 1.749 + * @param aLineBefore a line in 'mLines' (or begin_lines() when 1.750 + * pushing the first line) 1.751 + */ 1.752 + void PushLines(nsBlockReflowState& aState, 1.753 + nsLineList::iterator aLineBefore); 1.754 + 1.755 + void PropagateFloatDamage(nsBlockReflowState& aState, 1.756 + nsLineBox* aLine, 1.757 + nscoord aDeltaY); 1.758 + 1.759 + void CheckFloats(nsBlockReflowState& aState); 1.760 + 1.761 + //---------------------------------------- 1.762 + // List handling kludge 1.763 + 1.764 + // If this returns true, the block it's called on should get the 1.765 + // NS_FRAME_HAS_DIRTY_CHILDREN bit set on it by the caller; either directly 1.766 + // if it's already in reflow, or via calling FrameNeedsReflow() to schedule a 1.767 + // reflow. 1.768 + bool RenumberLists(nsPresContext* aPresContext); 1.769 + 1.770 + static bool RenumberListsInBlock(nsPresContext* aPresContext, 1.771 + nsBlockFrame* aBlockFrame, 1.772 + int32_t* aOrdinal, 1.773 + int32_t aDepth, 1.774 + int32_t aIncrement); 1.775 + 1.776 + static bool RenumberListsFor(nsPresContext* aPresContext, nsIFrame* aKid, 1.777 + int32_t* aOrdinal, int32_t aDepth, 1.778 + int32_t aIncrement); 1.779 + 1.780 + static bool FrameStartsCounterScope(nsIFrame* aFrame); 1.781 + 1.782 + void ReflowBullet(nsIFrame* aBulletFrame, 1.783 + nsBlockReflowState& aState, 1.784 + nsHTMLReflowMetrics& aMetrics, 1.785 + nscoord aLineTop); 1.786 + 1.787 + //---------------------------------------- 1.788 + 1.789 + virtual nsILineIterator* GetLineIterator() MOZ_OVERRIDE; 1.790 + 1.791 +public: 1.792 + bool HasOverflowLines() const { 1.793 + return 0 != (GetStateBits() & NS_BLOCK_HAS_OVERFLOW_LINES); 1.794 + } 1.795 + FrameLines* GetOverflowLines() const; 1.796 +protected: 1.797 + FrameLines* RemoveOverflowLines(); 1.798 + void SetOverflowLines(FrameLines* aOverflowLines); 1.799 + void DestroyOverflowLines(); 1.800 + 1.801 + /** 1.802 + * This class is useful for efficiently modifying the out of flow 1.803 + * overflow list. It gives the client direct writable access to 1.804 + * the frame list temporarily but ensures that property is only 1.805 + * written back if absolutely necessary. 1.806 + */ 1.807 + struct nsAutoOOFFrameList { 1.808 + nsFrameList mList; 1.809 + 1.810 + nsAutoOOFFrameList(nsBlockFrame* aBlock) 1.811 + : mPropValue(aBlock->GetOverflowOutOfFlows()) 1.812 + , mBlock(aBlock) { 1.813 + if (mPropValue) { 1.814 + mList = *mPropValue; 1.815 + } 1.816 + } 1.817 + ~nsAutoOOFFrameList() { 1.818 + mBlock->SetOverflowOutOfFlows(mList, mPropValue); 1.819 + } 1.820 + protected: 1.821 + nsFrameList* const mPropValue; 1.822 + nsBlockFrame* const mBlock; 1.823 + }; 1.824 + friend struct nsAutoOOFFrameList; 1.825 + 1.826 + nsFrameList* GetOverflowOutOfFlows() const; 1.827 + void SetOverflowOutOfFlows(const nsFrameList& aList, nsFrameList* aPropValue); 1.828 + 1.829 + /** 1.830 + * @return the inside bullet frame or nullptr if we don't have one. 1.831 + */ 1.832 + nsBulletFrame* GetInsideBullet() const; 1.833 + 1.834 + /** 1.835 + * @return the outside bullet frame or nullptr if we don't have one. 1.836 + */ 1.837 + nsBulletFrame* GetOutsideBullet() const; 1.838 + 1.839 + /** 1.840 + * @return the outside bullet frame list frame property. 1.841 + */ 1.842 + nsFrameList* GetOutsideBulletList() const; 1.843 + 1.844 + /** 1.845 + * @return true if this frame has pushed floats. 1.846 + */ 1.847 + bool HasPushedFloats() const { 1.848 + return 0 != (GetStateBits() & NS_BLOCK_HAS_PUSHED_FLOATS); 1.849 + } 1.850 + 1.851 + // Get the pushed floats list, which is used for *temporary* storage 1.852 + // of floats during reflow, between when we decide they don't fit in 1.853 + // this block until our next continuation takes them. 1.854 + nsFrameList* GetPushedFloats() const; 1.855 + // Get the pushed floats list, or if there is not currently one, 1.856 + // make a new empty one. 1.857 + nsFrameList* EnsurePushedFloats(); 1.858 + // Remove and return the pushed floats list. 1.859 + nsFrameList* RemovePushedFloats(); 1.860 + 1.861 +#ifdef DEBUG 1.862 + void VerifyLines(bool aFinalCheckOK); 1.863 + void VerifyOverflowSituation(); 1.864 + int32_t GetDepth() const; 1.865 +#endif 1.866 + 1.867 + nscoord mMinWidth, mPrefWidth; 1.868 + 1.869 + nsLineList mLines; 1.870 + 1.871 + // List of all floats in this block 1.872 + // XXXmats blocks rarely have floats, make it a frame property 1.873 + nsFrameList mFloats; 1.874 + 1.875 + friend class nsBlockReflowState; 1.876 + friend class nsBlockInFlowLineIterator; 1.877 + 1.878 +#ifdef DEBUG 1.879 +public: 1.880 + static bool gLamePaintMetrics; 1.881 + static bool gLameReflowMetrics; 1.882 + static bool gNoisy; 1.883 + static bool gNoisyDamageRepair; 1.884 + static bool gNoisyIntrinsic; 1.885 + static bool gNoisyReflow; 1.886 + static bool gReallyNoisyReflow; 1.887 + static bool gNoisyFloatManager; 1.888 + static bool gVerifyLines; 1.889 + static bool gDisableResizeOpt; 1.890 + 1.891 + static int32_t gNoiseIndent; 1.892 + 1.893 + static const char* kReflowCommandType[]; 1.894 + 1.895 +protected: 1.896 + static void InitDebugFlags(); 1.897 +#endif 1.898 +}; 1.899 + 1.900 +#ifdef DEBUG 1.901 +class AutoNoisyIndenter { 1.902 +public: 1.903 + AutoNoisyIndenter(bool aDoIndent) : mIndented(aDoIndent) { 1.904 + if (mIndented) { 1.905 + nsBlockFrame::gNoiseIndent++; 1.906 + } 1.907 + } 1.908 + ~AutoNoisyIndenter() { 1.909 + if (mIndented) { 1.910 + nsBlockFrame::gNoiseIndent--; 1.911 + } 1.912 + } 1.913 +private: 1.914 + bool mIndented; 1.915 +}; 1.916 +#endif 1.917 + 1.918 +/** 1.919 + * Iterates over all lines in the prev-in-flows/next-in-flows of this block. 1.920 + */ 1.921 +class nsBlockInFlowLineIterator { 1.922 +public: 1.923 + typedef nsBlockFrame::line_iterator line_iterator; 1.924 + /** 1.925 + * Set up the iterator to point to aLine which must be a normal line 1.926 + * in aFrame (not an overflow line). 1.927 + */ 1.928 + nsBlockInFlowLineIterator(nsBlockFrame* aFrame, line_iterator aLine); 1.929 + /** 1.930 + * Set up the iterator to point to the first line found starting from 1.931 + * aFrame. Sets aFoundValidLine to false if there is no such line. 1.932 + * After aFoundValidLine has returned false, don't call any methods on this 1.933 + * object again. 1.934 + */ 1.935 + nsBlockInFlowLineIterator(nsBlockFrame* aFrame, bool* aFoundValidLine); 1.936 + /** 1.937 + * Set up the iterator to point to the line that contains aFindFrame (either 1.938 + * directly or indirectly). If aFrame is out of flow, or contained in an 1.939 + * out-of-flow, finds the line containing the out-of-flow's placeholder. If 1.940 + * the frame is not found, sets aFoundValidLine to false. After 1.941 + * aFoundValidLine has returned false, don't call any methods on this 1.942 + * object again. 1.943 + */ 1.944 + nsBlockInFlowLineIterator(nsBlockFrame* aFrame, nsIFrame* aFindFrame, 1.945 + bool* aFoundValidLine); 1.946 + 1.947 + line_iterator GetLine() { return mLine; } 1.948 + bool IsLastLineInList(); 1.949 + nsBlockFrame* GetContainer() { return mFrame; } 1.950 + bool GetInOverflow() { return mLineList != &mFrame->mLines; } 1.951 + 1.952 + /** 1.953 + * Returns the current line list we're iterating, null means 1.954 + * we're iterating |mLines| of the container. 1.955 + */ 1.956 + nsLineList* GetLineList() { return mLineList; } 1.957 + 1.958 + /** 1.959 + * Returns the end-iterator of whatever line list we're in. 1.960 + */ 1.961 + line_iterator End(); 1.962 + 1.963 + /** 1.964 + * Returns false if there are no more lines. After this has returned false, 1.965 + * don't call any methods on this object again. 1.966 + */ 1.967 + bool Next(); 1.968 + /** 1.969 + * Returns false if there are no more lines. After this has returned false, 1.970 + * don't call any methods on this object again. 1.971 + */ 1.972 + bool Prev(); 1.973 + 1.974 +private: 1.975 + friend class nsBlockFrame; 1.976 + // XXX nsBlockFrame uses this internally in one place. Try to remove it. 1.977 + nsBlockInFlowLineIterator(nsBlockFrame* aFrame, line_iterator aLine, bool aInOverflow); 1.978 + 1.979 + nsBlockFrame* mFrame; 1.980 + line_iterator mLine; 1.981 + nsLineList* mLineList; // the line list mLine is in 1.982 + 1.983 + /** 1.984 + * Moves iterator to next valid line reachable from the current block. 1.985 + * Returns false if there are no valid lines. 1.986 + */ 1.987 + bool FindValidLine(); 1.988 +}; 1.989 + 1.990 +#endif /* nsBlockFrame_h___ */