1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/generic/nsInlineFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1130 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* rendering object for CSS display:inline objects */ 1.10 + 1.11 +#include "nsInlineFrame.h" 1.12 +#include "nsLineLayout.h" 1.13 +#include "nsBlockFrame.h" 1.14 +#include "nsPlaceholderFrame.h" 1.15 +#include "nsGkAtoms.h" 1.16 +#include "nsStyleContext.h" 1.17 +#include "nsPresContext.h" 1.18 +#include "nsRenderingContext.h" 1.19 +#include "nsCSSAnonBoxes.h" 1.20 +#include "nsAutoPtr.h" 1.21 +#include "RestyleManager.h" 1.22 +#include "nsDisplayList.h" 1.23 +#include "mozilla/Likely.h" 1.24 + 1.25 +#ifdef DEBUG 1.26 +#undef NOISY_PUSHING 1.27 +#endif 1.28 + 1.29 +using namespace mozilla; 1.30 +using namespace mozilla::layout; 1.31 + 1.32 + 1.33 +////////////////////////////////////////////////////////////////////// 1.34 + 1.35 +// Basic nsInlineFrame methods 1.36 + 1.37 +nsIFrame* 1.38 +NS_NewInlineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.39 +{ 1.40 + return new (aPresShell) nsInlineFrame(aContext); 1.41 +} 1.42 + 1.43 +NS_IMPL_FRAMEARENA_HELPERS(nsInlineFrame) 1.44 + 1.45 +NS_QUERYFRAME_HEAD(nsInlineFrame) 1.46 + NS_QUERYFRAME_ENTRY(nsInlineFrame) 1.47 +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) 1.48 + 1.49 +#ifdef DEBUG_FRAME_DUMP 1.50 +nsresult 1.51 +nsInlineFrame::GetFrameName(nsAString& aResult) const 1.52 +{ 1.53 + return MakeFrameName(NS_LITERAL_STRING("Inline"), aResult); 1.54 +} 1.55 +#endif 1.56 + 1.57 +nsIAtom* 1.58 +nsInlineFrame::GetType() const 1.59 +{ 1.60 + return nsGkAtoms::inlineFrame; 1.61 +} 1.62 + 1.63 +void 1.64 +nsInlineFrame::InvalidateFrame(uint32_t aDisplayItemKey) 1.65 +{ 1.66 + if (IsSVGText()) { 1.67 + nsIFrame* svgTextFrame = 1.68 + nsLayoutUtils::GetClosestFrameOfType(GetParent(), 1.69 + nsGkAtoms::svgTextFrame); 1.70 + svgTextFrame->InvalidateFrame(); 1.71 + return; 1.72 + } 1.73 + nsInlineFrameBase::InvalidateFrame(aDisplayItemKey); 1.74 +} 1.75 + 1.76 +void 1.77 +nsInlineFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey) 1.78 +{ 1.79 + if (IsSVGText()) { 1.80 + nsIFrame* svgTextFrame = 1.81 + nsLayoutUtils::GetClosestFrameOfType(GetParent(), 1.82 + nsGkAtoms::svgTextFrame); 1.83 + svgTextFrame->InvalidateFrame(); 1.84 + return; 1.85 + } 1.86 + nsInlineFrameBase::InvalidateFrameWithRect(aRect, aDisplayItemKey); 1.87 +} 1.88 + 1.89 +static inline bool 1.90 +IsMarginZero(const nsStyleCoord &aCoord) 1.91 +{ 1.92 + return aCoord.GetUnit() == eStyleUnit_Auto || 1.93 + nsLayoutUtils::IsMarginZero(aCoord); 1.94 +} 1.95 + 1.96 +/* virtual */ bool 1.97 +nsInlineFrame::IsSelfEmpty() 1.98 +{ 1.99 +#if 0 1.100 + // I used to think inline frames worked this way, but it seems they 1.101 + // don't. At least not in our codebase. 1.102 + if (GetPresContext()->CompatibilityMode() == eCompatibility_FullStandards) { 1.103 + return false; 1.104 + } 1.105 +#endif 1.106 + const nsStyleMargin* margin = StyleMargin(); 1.107 + const nsStyleBorder* border = StyleBorder(); 1.108 + const nsStylePadding* padding = StylePadding(); 1.109 + // XXX Top and bottom removed, since they shouldn't affect things, but this 1.110 + // doesn't really match with nsLineLayout.cpp's setting of 1.111 + // ZeroEffectiveSpanBox, anymore, so what should this really be? 1.112 + bool haveRight = 1.113 + border->GetComputedBorderWidth(NS_SIDE_RIGHT) != 0 || 1.114 + !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetRight()) || 1.115 + !IsMarginZero(margin->mMargin.GetRight()); 1.116 + bool haveLeft = 1.117 + border->GetComputedBorderWidth(NS_SIDE_LEFT) != 0 || 1.118 + !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetLeft()) || 1.119 + !IsMarginZero(margin->mMargin.GetLeft()); 1.120 + if (haveLeft || haveRight) { 1.121 + if (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) { 1.122 + bool haveStart, haveEnd; 1.123 + if (NS_STYLE_DIRECTION_LTR == StyleVisibility()->mDirection) { 1.124 + haveStart = haveLeft; 1.125 + haveEnd = haveRight; 1.126 + } else { 1.127 + haveStart = haveRight; 1.128 + haveEnd = haveLeft; 1.129 + } 1.130 + // For ib-split frames, ignore things we know we'll skip in GetSkipSides. 1.131 + // XXXbz should we be doing this for non-ib-split frames too, in a more 1.132 + // general way? 1.133 + 1.134 + // Get the first continuation eagerly, as a performance optimization, to 1.135 + // avoid having to get it twice.. 1.136 + nsIFrame* firstCont = FirstContinuation(); 1.137 + return 1.138 + (!haveStart || firstCont->FrameIsNonFirstInIBSplit()) && 1.139 + (!haveEnd || firstCont->FrameIsNonLastInIBSplit()); 1.140 + } 1.141 + return false; 1.142 + } 1.143 + return true; 1.144 +} 1.145 + 1.146 +bool 1.147 +nsInlineFrame::IsEmpty() 1.148 +{ 1.149 + if (!IsSelfEmpty()) { 1.150 + return false; 1.151 + } 1.152 + 1.153 + for (nsIFrame *kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) { 1.154 + if (!kid->IsEmpty()) 1.155 + return false; 1.156 + } 1.157 + 1.158 + return true; 1.159 +} 1.160 + 1.161 +nsIFrame::FrameSearchResult 1.162 +nsInlineFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset, 1.163 + bool aRespectClusters) 1.164 +{ 1.165 + // Override the implementation in nsFrame, to skip empty inline frames 1.166 + NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range"); 1.167 + int32_t startOffset = *aOffset; 1.168 + if (startOffset < 0) 1.169 + startOffset = 1; 1.170 + if (aForward == (startOffset == 0)) { 1.171 + // We're before the frame and moving forward, or after it and moving backwards: 1.172 + // skip to the other side, but keep going. 1.173 + *aOffset = 1 - startOffset; 1.174 + } 1.175 + return CONTINUE; 1.176 +} 1.177 + 1.178 +void 1.179 +nsInlineFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.180 + const nsRect& aDirtyRect, 1.181 + const nsDisplayListSet& aLists) 1.182 +{ 1.183 + BuildDisplayListForInline(aBuilder, aDirtyRect, aLists); 1.184 + 1.185 + // The sole purpose of this is to trigger display of the selection 1.186 + // window for Named Anchors, which don't have any children and 1.187 + // normally don't have any size, but in Editor we use CSS to display 1.188 + // an image to represent this "hidden" element. 1.189 + if (!mFrames.FirstChild()) { 1.190 + DisplaySelectionOverlay(aBuilder, aLists.Content()); 1.191 + } 1.192 +} 1.193 + 1.194 +////////////////////////////////////////////////////////////////////// 1.195 +// Reflow methods 1.196 + 1.197 +/* virtual */ void 1.198 +nsInlineFrame::AddInlineMinWidth(nsRenderingContext *aRenderingContext, 1.199 + nsIFrame::InlineMinWidthData *aData) 1.200 +{ 1.201 + DoInlineIntrinsicWidth(aRenderingContext, aData, nsLayoutUtils::MIN_WIDTH); 1.202 +} 1.203 + 1.204 +/* virtual */ void 1.205 +nsInlineFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext, 1.206 + nsIFrame::InlinePrefWidthData *aData) 1.207 +{ 1.208 + DoInlineIntrinsicWidth(aRenderingContext, aData, nsLayoutUtils::PREF_WIDTH); 1.209 +} 1.210 + 1.211 +/* virtual */ nsSize 1.212 +nsInlineFrame::ComputeSize(nsRenderingContext *aRenderingContext, 1.213 + nsSize aCBSize, nscoord aAvailableWidth, 1.214 + nsSize aMargin, nsSize aBorder, nsSize aPadding, 1.215 + uint32_t aFlags) 1.216 +{ 1.217 + // Inlines and text don't compute size before reflow. 1.218 + return nsSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); 1.219 +} 1.220 + 1.221 +nsRect 1.222 +nsInlineFrame::ComputeTightBounds(gfxContext* aContext) const 1.223 +{ 1.224 + // be conservative 1.225 + if (StyleContext()->HasTextDecorationLines()) { 1.226 + return GetVisualOverflowRect(); 1.227 + } 1.228 + return ComputeSimpleTightBounds(aContext); 1.229 +} 1.230 + 1.231 +void 1.232 +nsInlineFrame::ReparentFloatsForInlineChild(nsIFrame* aOurLineContainer, 1.233 + nsIFrame* aFrame, 1.234 + bool aReparentSiblings) 1.235 +{ 1.236 + // XXXbz this would be better if it took a nsFrameList or a frame 1.237 + // list slice.... 1.238 + NS_ASSERTION(aOurLineContainer->GetNextContinuation() || 1.239 + aOurLineContainer->GetPrevContinuation(), 1.240 + "Don't call this when we have no continuation, it's a waste"); 1.241 + if (!aFrame) { 1.242 + NS_ASSERTION(aReparentSiblings, "Why did we get called?"); 1.243 + return; 1.244 + } 1.245 + 1.246 + nsIFrame* ancestor = aFrame; 1.247 + do { 1.248 + ancestor = ancestor->GetParent(); 1.249 + if (!ancestor) 1.250 + return; 1.251 + } while (!ancestor->IsFloatContainingBlock()); 1.252 + 1.253 + if (ancestor == aOurLineContainer) 1.254 + return; 1.255 + 1.256 + nsBlockFrame* ourBlock = nsLayoutUtils::GetAsBlock(aOurLineContainer); 1.257 + NS_ASSERTION(ourBlock, "Not a block, but broke vertically?"); 1.258 + nsBlockFrame* frameBlock = nsLayoutUtils::GetAsBlock(ancestor); 1.259 + NS_ASSERTION(frameBlock, "ancestor not a block"); 1.260 + 1.261 + while (true) { 1.262 + ourBlock->ReparentFloats(aFrame, frameBlock, false); 1.263 + 1.264 + if (!aReparentSiblings) 1.265 + return; 1.266 + nsIFrame* next = aFrame->GetNextSibling(); 1.267 + if (!next) 1.268 + return; 1.269 + if (next->GetParent() == aFrame->GetParent()) { 1.270 + aFrame = next; 1.271 + continue; 1.272 + } 1.273 + // This is paranoid and will hardly ever get hit ... but we can't actually 1.274 + // trust that the frames in the sibling chain all have the same parent, 1.275 + // because lazy reparenting may be going on. If we find a different 1.276 + // parent we need to redo our analysis. 1.277 + ReparentFloatsForInlineChild(aOurLineContainer, next, aReparentSiblings); 1.278 + return; 1.279 + } 1.280 +} 1.281 + 1.282 +static void 1.283 +ReparentChildListStyle(nsPresContext* aPresContext, 1.284 + const nsFrameList::Slice& aFrames, 1.285 + nsIFrame* aParentFrame) 1.286 +{ 1.287 + RestyleManager* restyleManager = aPresContext->RestyleManager(); 1.288 + 1.289 + for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) { 1.290 + NS_ASSERTION(e.get()->GetParent() == aParentFrame, "Bogus parentage"); 1.291 + restyleManager->ReparentStyleContext(e.get()); 1.292 + nsLayoutUtils::MarkDescendantsDirty(e.get()); 1.293 + } 1.294 +} 1.295 + 1.296 +nsresult 1.297 +nsInlineFrame::Reflow(nsPresContext* aPresContext, 1.298 + nsHTMLReflowMetrics& aMetrics, 1.299 + const nsHTMLReflowState& aReflowState, 1.300 + nsReflowStatus& aStatus) 1.301 +{ 1.302 + DO_GLOBAL_REFLOW_COUNT("nsInlineFrame"); 1.303 + DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); 1.304 + if (nullptr == aReflowState.mLineLayout) { 1.305 + return NS_ERROR_INVALID_ARG; 1.306 + } 1.307 + if (IsFrameTreeTooDeep(aReflowState, aMetrics, aStatus)) { 1.308 + return NS_OK; 1.309 + } 1.310 + 1.311 + bool lazilySetParentPointer = false; 1.312 + 1.313 + nsIFrame* lineContainer = aReflowState.mLineLayout->LineContainerFrame(); 1.314 + 1.315 + // Check for an overflow list with our prev-in-flow 1.316 + nsInlineFrame* prevInFlow = (nsInlineFrame*)GetPrevInFlow(); 1.317 + if (prevInFlow) { 1.318 + AutoFrameListPtr prevOverflowFrames(aPresContext, 1.319 + prevInFlow->StealOverflowFrames()); 1.320 + if (prevOverflowFrames) { 1.321 + // When pushing and pulling frames we need to check for whether any 1.322 + // views need to be reparented. 1.323 + nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames, prevInFlow, 1.324 + this); 1.325 + 1.326 + // Check if we should do the lazilySetParentPointer optimization. 1.327 + // Only do it in simple cases where we're being reflowed for the 1.328 + // first time, nothing (e.g. bidi resolution) has already given 1.329 + // us children, and there's no next-in-flow, so all our frames 1.330 + // will be taken from prevOverflowFrames. 1.331 + if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) && mFrames.IsEmpty() && 1.332 + !GetNextInFlow()) { 1.333 + // If our child list is empty, just put the new frames into it. 1.334 + // Note that we don't set the parent pointer for the new frames. Instead wait 1.335 + // to do this until we actually reflow the frame. If the overflow list contains 1.336 + // thousands of frames this is a big performance issue (see bug #5588) 1.337 + mFrames.SetFrames(*prevOverflowFrames); 1.338 + lazilySetParentPointer = true; 1.339 + } else { 1.340 + // Assign all floats to our block if necessary 1.341 + if (lineContainer && lineContainer->GetPrevContinuation()) { 1.342 + ReparentFloatsForInlineChild(lineContainer, 1.343 + prevOverflowFrames->FirstChild(), 1.344 + true); 1.345 + } 1.346 + // Insert the new frames at the beginning of the child list 1.347 + // and set their parent pointer 1.348 + const nsFrameList::Slice& newFrames = 1.349 + mFrames.InsertFrames(this, nullptr, *prevOverflowFrames); 1.350 + // If our prev in flow was under the first continuation of a first-line 1.351 + // frame then we need to reparent the style contexts to remove the 1.352 + // the special first-line styling. In the lazilySetParentPointer case 1.353 + // we reparent the style contexts when we set their parents in 1.354 + // nsInlineFrame::ReflowFrames and nsInlineFrame::ReflowInlineFrame. 1.355 + if (aReflowState.mLineLayout->GetInFirstLine()) { 1.356 + ReparentChildListStyle(aPresContext, newFrames, this); 1.357 + } 1.358 + } 1.359 + } 1.360 + } 1.361 + 1.362 + // It's also possible that we have an overflow list for ourselves 1.363 +#ifdef DEBUG 1.364 + if (GetStateBits() & NS_FRAME_FIRST_REFLOW) { 1.365 + // If it's our initial reflow, then we should not have an overflow list. 1.366 + // However, add an assertion in case we get reflowed more than once with 1.367 + // the initial reflow reason 1.368 + nsFrameList* overflowFrames = GetOverflowFrames(); 1.369 + NS_ASSERTION(!overflowFrames || overflowFrames->IsEmpty(), 1.370 + "overflow list is not empty for initial reflow"); 1.371 + } 1.372 +#endif 1.373 + if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { 1.374 + DrainFlags flags = 1.375 + lazilySetParentPointer ? eDontReparentFrames : DrainFlags(0); 1.376 + if (aReflowState.mLineLayout->GetInFirstLine()) { 1.377 + flags = DrainFlags(flags | eInFirstLine); 1.378 + } 1.379 + DrainSelfOverflowListInternal(flags, lineContainer); 1.380 + } 1.381 + 1.382 + // Set our own reflow state (additional state above and beyond 1.383 + // aReflowState) 1.384 + InlineReflowState irs; 1.385 + irs.mPrevFrame = nullptr; 1.386 + irs.mLineContainer = lineContainer; 1.387 + irs.mLineLayout = aReflowState.mLineLayout; 1.388 + irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow(); 1.389 + irs.mSetParentPointer = lazilySetParentPointer; 1.390 + 1.391 + nsresult rv; 1.392 + if (mFrames.IsEmpty()) { 1.393 + // Try to pull over one frame before starting so that we know 1.394 + // whether we have an anonymous block or not. 1.395 + bool complete; 1.396 + (void) PullOneFrame(aPresContext, irs, &complete); 1.397 + } 1.398 + 1.399 + rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus); 1.400 + 1.401 + ReflowAbsoluteFrames(aPresContext, aMetrics, aReflowState, aStatus); 1.402 + 1.403 + // Note: the line layout code will properly compute our 1.404 + // overflow-rect state for us. 1.405 + 1.406 + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); 1.407 + return rv; 1.408 +} 1.409 + 1.410 +bool 1.411 +nsInlineFrame::DrainSelfOverflowListInternal(DrainFlags aFlags, 1.412 + nsIFrame* aLineContainer) 1.413 +{ 1.414 + AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames()); 1.415 + if (overflowFrames) { 1.416 + NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); 1.417 + // The frames on our own overflowlist may have been pushed by a 1.418 + // previous lazilySetParentPointer Reflow so we need to ensure the 1.419 + // correct parent pointer. This is sometimes skipped by Reflow. 1.420 + if (!(aFlags & eDontReparentFrames)) { 1.421 + nsIFrame* firstChild = overflowFrames->FirstChild(); 1.422 + if (aLineContainer && aLineContainer->GetPrevContinuation()) { 1.423 + ReparentFloatsForInlineChild(aLineContainer, firstChild, true); 1.424 + } 1.425 + const bool inFirstLine = (aFlags & eInFirstLine); 1.426 + RestyleManager* restyleManager = PresContext()->RestyleManager(); 1.427 + for (nsIFrame* f = firstChild; f; f = f->GetNextSibling()) { 1.428 + f->SetParent(this); 1.429 + if (inFirstLine) { 1.430 + restyleManager->ReparentStyleContext(f); 1.431 + nsLayoutUtils::MarkDescendantsDirty(f); 1.432 + } 1.433 + } 1.434 + } 1.435 + bool result = !overflowFrames->IsEmpty(); 1.436 + mFrames.AppendFrames(nullptr, *overflowFrames); 1.437 + return result; 1.438 + } 1.439 + return false; 1.440 +} 1.441 + 1.442 +/* virtual */ bool 1.443 +nsInlineFrame::DrainSelfOverflowList() 1.444 +{ 1.445 + nsIFrame* lineContainer = nsLayoutUtils::FindNearestBlockAncestor(this); 1.446 + // Add the eInFirstLine flag if we have a ::first-line ancestor frame. 1.447 + // No need to look further than the nearest line container though. 1.448 + DrainFlags flags = DrainFlags(0); 1.449 + for (nsIFrame* p = GetParent(); p != lineContainer; p = p->GetParent()) { 1.450 + if (p->GetType() == nsGkAtoms::lineFrame) { 1.451 + flags = DrainFlags(flags | eInFirstLine); 1.452 + break; 1.453 + } 1.454 + } 1.455 + return DrainSelfOverflowListInternal(flags, lineContainer); 1.456 +} 1.457 + 1.458 +/* virtual */ bool 1.459 +nsInlineFrame::CanContinueTextRun() const 1.460 +{ 1.461 + // We can continue a text run through an inline frame 1.462 + return true; 1.463 +} 1.464 + 1.465 +/* virtual */ void 1.466 +nsInlineFrame::PullOverflowsFromPrevInFlow() 1.467 +{ 1.468 + nsInlineFrame* prevInFlow = static_cast<nsInlineFrame*>(GetPrevInFlow()); 1.469 + if (prevInFlow) { 1.470 + nsPresContext* presContext = PresContext(); 1.471 + AutoFrameListPtr prevOverflowFrames(presContext, 1.472 + prevInFlow->StealOverflowFrames()); 1.473 + if (prevOverflowFrames) { 1.474 + // Assume that our prev-in-flow has the same line container that we do. 1.475 + nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames, prevInFlow, 1.476 + this); 1.477 + mFrames.InsertFrames(this, nullptr, *prevOverflowFrames); 1.478 + } 1.479 + } 1.480 +} 1.481 + 1.482 +nsresult 1.483 +nsInlineFrame::ReflowFrames(nsPresContext* aPresContext, 1.484 + const nsHTMLReflowState& aReflowState, 1.485 + InlineReflowState& irs, 1.486 + nsHTMLReflowMetrics& aMetrics, 1.487 + nsReflowStatus& aStatus) 1.488 +{ 1.489 + nsresult rv = NS_OK; 1.490 + aStatus = NS_FRAME_COMPLETE; 1.491 + 1.492 + nsLineLayout* lineLayout = aReflowState.mLineLayout; 1.493 + bool inFirstLine = aReflowState.mLineLayout->GetInFirstLine(); 1.494 + RestyleManager* restyleManager = aPresContext->RestyleManager(); 1.495 + WritingMode wm = aReflowState.GetWritingMode(); 1.496 + nscoord startEdge = 0; 1.497 + // Don't offset by our start borderpadding if we have a prev continuation or 1.498 + // if we're in a part of an {ib} split other than the first one. 1.499 + if (!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) { 1.500 + startEdge = aReflowState.ComputedLogicalBorderPadding().IStart(wm); 1.501 + } 1.502 + nscoord availableISize = aReflowState.AvailableISize(); 1.503 + NS_ASSERTION(availableISize != NS_UNCONSTRAINEDSIZE, 1.504 + "should no longer use available widths"); 1.505 + // Subtract off inline axis border+padding from availableISize 1.506 + availableISize -= startEdge; 1.507 + availableISize -= aReflowState.ComputedLogicalBorderPadding().IEnd(wm); 1.508 + lineLayout->BeginSpan(this, &aReflowState, startEdge, 1.509 + startEdge + availableISize, &mBaseline); 1.510 + 1.511 + // First reflow our principal children. 1.512 + nsIFrame* frame = mFrames.FirstChild(); 1.513 + bool done = false; 1.514 + while (frame) { 1.515 + // Check if we should lazily set the child frame's parent pointer. 1.516 + if (irs.mSetParentPointer) { 1.517 + bool havePrevBlock = 1.518 + irs.mLineContainer && irs.mLineContainer->GetPrevContinuation(); 1.519 + nsIFrame* child = frame; 1.520 + do { 1.521 + // If our block is the first in flow, then any floats under the pulled 1.522 + // frame must already belong to our block. 1.523 + if (havePrevBlock) { 1.524 + // This has to happen before we update frame's parent; we need to 1.525 + // know frame's ancestry under its old block. 1.526 + // The blockChildren.ContainsFrame check performed by 1.527 + // ReparentFloatsForInlineChild here may be slow, but we can't 1.528 + // easily avoid it because we don't know where 'frame' originally 1.529 + // came from. If we really really have to optimize this we could 1.530 + // cache whether frame->GetParent() is under its containing blocks 1.531 + // overflowList or not. 1.532 + ReparentFloatsForInlineChild(irs.mLineContainer, child, false); 1.533 + } 1.534 + child->SetParent(this); 1.535 + if (inFirstLine) { 1.536 + restyleManager->ReparentStyleContext(child); 1.537 + nsLayoutUtils::MarkDescendantsDirty(child); 1.538 + } 1.539 + // We also need to do the same for |frame|'s next-in-flows that are in 1.540 + // the sibling list. Otherwise, if we reflow |frame| and it's complete 1.541 + // we'll crash when trying to delete its next-in-flow. 1.542 + // This scenario doesn't happen often, but it can happen. 1.543 + nsIFrame* nextSibling = child->GetNextSibling(); 1.544 + child = child->GetNextInFlow(); 1.545 + if (MOZ_UNLIKELY(child)) { 1.546 + while (child != nextSibling && nextSibling) { 1.547 + nextSibling = nextSibling->GetNextSibling(); 1.548 + } 1.549 + if (!nextSibling) { 1.550 + child = nullptr; 1.551 + } 1.552 + } 1.553 + MOZ_ASSERT(!child || mFrames.ContainsFrame(child)); 1.554 + } while (child); 1.555 + 1.556 + // Fix the parent pointer for ::first-letter child frame next-in-flows, 1.557 + // so nsFirstLetterFrame::Reflow can destroy them safely (bug 401042). 1.558 + nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(frame); 1.559 + if (realFrame->GetType() == nsGkAtoms::letterFrame) { 1.560 + nsIFrame* child = realFrame->GetFirstPrincipalChild(); 1.561 + if (child) { 1.562 + NS_ASSERTION(child->GetType() == nsGkAtoms::textFrame, 1.563 + "unexpected frame type"); 1.564 + nsIFrame* nextInFlow = child->GetNextInFlow(); 1.565 + for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) { 1.566 + NS_ASSERTION(nextInFlow->GetType() == nsGkAtoms::textFrame, 1.567 + "unexpected frame type"); 1.568 + if (mFrames.ContainsFrame(nextInFlow)) { 1.569 + nextInFlow->SetParent(this); 1.570 + if (inFirstLine) { 1.571 + restyleManager->ReparentStyleContext(nextInFlow); 1.572 + nsLayoutUtils::MarkDescendantsDirty(nextInFlow); 1.573 + } 1.574 + } 1.575 + else { 1.576 +#ifdef DEBUG 1.577 + // Once we find a next-in-flow that isn't ours none of the 1.578 + // remaining next-in-flows should be either. 1.579 + for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) { 1.580 + NS_ASSERTION(!mFrames.ContainsFrame(nextInFlow), 1.581 + "unexpected letter frame flow"); 1.582 + } 1.583 +#endif 1.584 + break; 1.585 + } 1.586 + } 1.587 + } 1.588 + } 1.589 + } 1.590 + MOZ_ASSERT(frame->GetParent() == this); 1.591 + 1.592 + if (!done) { 1.593 + bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); 1.594 + rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus); 1.595 + done = NS_FAILED(rv) || 1.596 + NS_INLINE_IS_BREAK(aStatus) || 1.597 + (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus)); 1.598 + if (done) { 1.599 + if (!irs.mSetParentPointer) { 1.600 + break; 1.601 + } 1.602 + // Keep reparenting the remaining siblings, but don't reflow them. 1.603 + nsFrameList* pushedFrames = GetOverflowFrames(); 1.604 + if (pushedFrames && pushedFrames->FirstChild() == frame) { 1.605 + // Don't bother if |frame| was pushed to our overflow list. 1.606 + break; 1.607 + } 1.608 + } else { 1.609 + irs.mPrevFrame = frame; 1.610 + } 1.611 + } 1.612 + frame = frame->GetNextSibling(); 1.613 + } 1.614 + 1.615 + // Attempt to pull frames from our next-in-flow until we can't 1.616 + if (!done && GetNextInFlow()) { 1.617 + while (true) { 1.618 + bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); 1.619 + bool isComplete; 1.620 + if (!frame) { // Could be non-null if we pulled a first-letter frame and 1.621 + // it created a continuation, since we don't push those. 1.622 + frame = PullOneFrame(aPresContext, irs, &isComplete); 1.623 + } 1.624 +#ifdef NOISY_PUSHING 1.625 + printf("%p pulled up %p\n", this, frame); 1.626 +#endif 1.627 + if (nullptr == frame) { 1.628 + if (!isComplete) { 1.629 + aStatus = NS_FRAME_NOT_COMPLETE; 1.630 + } 1.631 + break; 1.632 + } 1.633 + rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus); 1.634 + if (NS_FAILED(rv) || 1.635 + NS_INLINE_IS_BREAK(aStatus) || 1.636 + (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) { 1.637 + break; 1.638 + } 1.639 + irs.mPrevFrame = frame; 1.640 + frame = frame->GetNextSibling(); 1.641 + } 1.642 + } 1.643 + 1.644 + NS_ASSERTION(!NS_FRAME_IS_COMPLETE(aStatus) || !GetOverflowFrames(), 1.645 + "We can't be complete AND have overflow frames!"); 1.646 + 1.647 + // If after reflowing our children they take up no area then make 1.648 + // sure that we don't either. 1.649 + // 1.650 + // Note: CSS demands that empty inline elements still affect the 1.651 + // line-height calculations. However, continuations of an inline 1.652 + // that are empty we force to empty so that things like collapsed 1.653 + // whitespace in an inline element don't affect the line-height. 1.654 + aMetrics.ISize() = lineLayout->EndSpan(this); 1.655 + 1.656 + // Compute final width. 1.657 + 1.658 + // Make sure to not include our start border and padding if we have a prev 1.659 + // continuation or if we're in a part of an {ib} split other than the first 1.660 + // one. 1.661 + if (!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) { 1.662 + aMetrics.ISize() += aReflowState.ComputedLogicalBorderPadding().IStart(wm); 1.663 + } 1.664 + 1.665 + /* 1.666 + * We want to only apply the end border and padding if we're the last 1.667 + * continuation and either not in an {ib} split or the last part of it. To 1.668 + * be the last continuation we have to be complete (so that we won't get a 1.669 + * next-in-flow) and have no non-fluid continuations on our continuation 1.670 + * chain. 1.671 + */ 1.672 + if (NS_FRAME_IS_COMPLETE(aStatus) && 1.673 + !LastInFlow()->GetNextContinuation() && 1.674 + !FrameIsNonLastInIBSplit()) { 1.675 + aMetrics.Width() += aReflowState.ComputedLogicalBorderPadding().IEnd(wm); 1.676 + } 1.677 + 1.678 + nsRefPtr<nsFontMetrics> fm; 1.679 + float inflation = nsLayoutUtils::FontSizeInflationFor(this); 1.680 + nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), inflation); 1.681 + aReflowState.rendContext->SetFont(fm); 1.682 + 1.683 + if (fm) { 1.684 + // Compute final height of the frame. 1.685 + // 1.686 + // Do things the standard css2 way -- though it's hard to find it 1.687 + // in the css2 spec! It's actually found in the css1 spec section 1.688 + // 4.4 (you will have to read between the lines to really see 1.689 + // it). 1.690 + // 1.691 + // The height of our box is the sum of our font size plus the top 1.692 + // and bottom border and padding. The height of children do not 1.693 + // affect our height. 1.694 + aMetrics.SetTopAscent(fm->MaxAscent()); 1.695 + aMetrics.Height() = fm->MaxHeight(); 1.696 + } else { 1.697 + NS_WARNING("Cannot get font metrics - defaulting sizes to 0"); 1.698 + aMetrics.SetTopAscent(aMetrics.Height() = 0); 1.699 + } 1.700 + aMetrics.SetTopAscent(aMetrics.TopAscent() + aReflowState.ComputedPhysicalBorderPadding().top); 1.701 + aMetrics.Height() += aReflowState.ComputedPhysicalBorderPadding().top + 1.702 + aReflowState.ComputedPhysicalBorderPadding().bottom; 1.703 + 1.704 + // For now our overflow area is zero. The real value will be 1.705 + // computed in |nsLineLayout::RelativePositionFrames|. 1.706 + aMetrics.mOverflowAreas.Clear(); 1.707 + 1.708 +#ifdef NOISY_FINAL_SIZE 1.709 + ListTag(stdout); 1.710 + printf(": metrics=%d,%d ascent=%d\n", 1.711 + aMetrics.Width(), aMetrics.Height(), aMetrics.TopAscent()); 1.712 +#endif 1.713 + 1.714 + return rv; 1.715 +} 1.716 + 1.717 +nsresult 1.718 +nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext, 1.719 + const nsHTMLReflowState& aReflowState, 1.720 + InlineReflowState& irs, 1.721 + nsIFrame* aFrame, 1.722 + nsReflowStatus& aStatus) 1.723 +{ 1.724 + nsLineLayout* lineLayout = aReflowState.mLineLayout; 1.725 + bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); 1.726 + bool pushedFrame; 1.727 + nsresult rv = 1.728 + lineLayout->ReflowFrame(aFrame, aStatus, nullptr, pushedFrame); 1.729 + 1.730 + if (NS_FAILED(rv)) { 1.731 + return rv; 1.732 + } 1.733 + 1.734 + if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) { 1.735 + if (aFrame != mFrames.FirstChild()) { 1.736 + // Change break-before status into break-after since we have 1.737 + // already placed at least one child frame. This preserves the 1.738 + // break-type so that it can be propagated upward. 1.739 + aStatus = NS_FRAME_NOT_COMPLETE | 1.740 + NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER | 1.741 + (aStatus & NS_INLINE_BREAK_TYPE_MASK); 1.742 + PushFrames(aPresContext, aFrame, irs.mPrevFrame, irs); 1.743 + } 1.744 + else { 1.745 + // Preserve reflow status when breaking-before our first child 1.746 + // and propagate it upward without modification. 1.747 + } 1.748 + return NS_OK; 1.749 + } 1.750 + 1.751 + // Create a next-in-flow if needed. 1.752 + if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) { 1.753 + nsIFrame* newFrame; 1.754 + rv = CreateNextInFlow(aFrame, newFrame); 1.755 + if (NS_FAILED(rv)) { 1.756 + return rv; 1.757 + } 1.758 + } 1.759 + 1.760 + if (NS_INLINE_IS_BREAK_AFTER(aStatus)) { 1.761 + nsIFrame* nextFrame = aFrame->GetNextSibling(); 1.762 + if (nextFrame) { 1.763 + NS_FRAME_SET_INCOMPLETE(aStatus); 1.764 + PushFrames(aPresContext, nextFrame, aFrame, irs); 1.765 + } 1.766 + else { 1.767 + // We must return an incomplete status if there are more child 1.768 + // frames remaining in a next-in-flow that follows this frame. 1.769 + nsInlineFrame* nextInFlow = static_cast<nsInlineFrame*>(GetNextInFlow()); 1.770 + while (nextInFlow) { 1.771 + if (nextInFlow->mFrames.NotEmpty()) { 1.772 + NS_FRAME_SET_INCOMPLETE(aStatus); 1.773 + break; 1.774 + } 1.775 + nextInFlow = static_cast<nsInlineFrame*>(nextInFlow->GetNextInFlow()); 1.776 + } 1.777 + } 1.778 + return NS_OK; 1.779 + } 1.780 + 1.781 + if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !reflowingFirstLetter) { 1.782 + nsIFrame* nextFrame = aFrame->GetNextSibling(); 1.783 + if (nextFrame) { 1.784 + PushFrames(aPresContext, nextFrame, aFrame, irs); 1.785 + } 1.786 + } 1.787 + return NS_OK; 1.788 +} 1.789 + 1.790 +nsIFrame* 1.791 +nsInlineFrame::PullOneFrame(nsPresContext* aPresContext, 1.792 + InlineReflowState& irs, 1.793 + bool* aIsComplete) 1.794 +{ 1.795 + bool isComplete = true; 1.796 + 1.797 + nsIFrame* frame = nullptr; 1.798 + nsInlineFrame* nextInFlow = irs.mNextInFlow; 1.799 + while (nextInFlow) { 1.800 + frame = nextInFlow->mFrames.FirstChild(); 1.801 + if (!frame) { 1.802 + // The nextInFlow's principal list has no frames, try its overflow list. 1.803 + nsFrameList* overflowFrames = nextInFlow->GetOverflowFrames(); 1.804 + if (overflowFrames) { 1.805 + frame = overflowFrames->RemoveFirstChild(); 1.806 + if (overflowFrames->IsEmpty()) { 1.807 + // We're stealing the only frame - delete the overflow list. 1.808 + nextInFlow->DestroyOverflowList(); 1.809 + } else { 1.810 + // We leave the remaining frames on the overflow list (rather than 1.811 + // putting them on nextInFlow's principal list) so we don't have to 1.812 + // set up the parent for them. 1.813 + } 1.814 + // ReparentFloatsForInlineChild needs it to be on a child list - 1.815 + // we remove it again below. 1.816 + nextInFlow->mFrames.SetFrames(frame); 1.817 + } 1.818 + } 1.819 + 1.820 + if (frame) { 1.821 + // If our block has no next continuation, then any floats belonging to 1.822 + // the pulled frame must belong to our block already. This check ensures 1.823 + // we do no extra work in the common non-vertical-breaking case. 1.824 + if (irs.mLineContainer && irs.mLineContainer->GetNextContinuation()) { 1.825 + // The blockChildren.ContainsFrame check performed by 1.826 + // ReparentFloatsForInlineChild will be fast because frame's ancestor 1.827 + // will be the first child of its containing block. 1.828 + ReparentFloatsForInlineChild(irs.mLineContainer, frame, false); 1.829 + } 1.830 + nextInFlow->mFrames.RemoveFirstChild(); 1.831 + // nsFirstLineFrame::PullOneFrame calls ReparentStyleContext. 1.832 + 1.833 + mFrames.InsertFrame(this, irs.mPrevFrame, frame); 1.834 + isComplete = false; 1.835 + if (irs.mLineLayout) { 1.836 + irs.mLineLayout->SetDirtyNextLine(); 1.837 + } 1.838 + nsContainerFrame::ReparentFrameView(frame, nextInFlow, this); 1.839 + break; 1.840 + } 1.841 + nextInFlow = static_cast<nsInlineFrame*>(nextInFlow->GetNextInFlow()); 1.842 + irs.mNextInFlow = nextInFlow; 1.843 + } 1.844 + 1.845 + *aIsComplete = isComplete; 1.846 + return frame; 1.847 +} 1.848 + 1.849 +void 1.850 +nsInlineFrame::PushFrames(nsPresContext* aPresContext, 1.851 + nsIFrame* aFromChild, 1.852 + nsIFrame* aPrevSibling, 1.853 + InlineReflowState& aState) 1.854 +{ 1.855 + NS_PRECONDITION(aFromChild, "null pointer"); 1.856 + NS_PRECONDITION(aPrevSibling, "pushing first child"); 1.857 + NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling"); 1.858 + 1.859 +#ifdef NOISY_PUSHING 1.860 + printf("%p pushing aFromChild %p, disconnecting from prev sib %p\n", 1.861 + this, aFromChild, aPrevSibling); 1.862 +#endif 1.863 + 1.864 + // Add the frames to our overflow list (let our next in flow drain 1.865 + // our overflow list when it is ready) 1.866 + SetOverflowFrames(mFrames.RemoveFramesAfter(aPrevSibling)); 1.867 + if (aState.mLineLayout) { 1.868 + aState.mLineLayout->SetDirtyNextLine(); 1.869 + } 1.870 +} 1.871 + 1.872 + 1.873 +////////////////////////////////////////////////////////////////////// 1.874 + 1.875 +int 1.876 +nsInlineFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const 1.877 +{ 1.878 + int skip = 0; 1.879 + if (!IsFirst()) { 1.880 + nsInlineFrame* prev = (nsInlineFrame*) GetPrevContinuation(); 1.881 + if ((GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) || 1.882 + (prev && (prev->mRect.height || prev->mRect.width))) { 1.883 + // Prev continuation is not empty therefore we don't render our start 1.884 + // border edge. 1.885 + skip |= LOGICAL_SIDE_I_START; 1.886 + } 1.887 + else { 1.888 + // If the prev continuation is empty, then go ahead and let our start 1.889 + // edge border render. 1.890 + } 1.891 + } 1.892 + if (!IsLast()) { 1.893 + nsInlineFrame* next = (nsInlineFrame*) GetNextContinuation(); 1.894 + if ((GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) || 1.895 + (next && (next->mRect.height || next->mRect.width))) { 1.896 + // Next continuation is not empty therefore we don't render our end 1.897 + // border edge. 1.898 + skip |= LOGICAL_SIDE_I_END; 1.899 + } 1.900 + else { 1.901 + // If the next continuation is empty, then go ahead and let our end 1.902 + // edge border render. 1.903 + } 1.904 + } 1.905 + 1.906 + if (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) { 1.907 + // All but the last part of an {ib} split should skip the "end" side (as 1.908 + // determined by this frame's direction) and all but the first part of such 1.909 + // a split should skip the "start" side. But figuring out which part of 1.910 + // the split we are involves getting our first continuation, which might be 1.911 + // expensive. So don't bother if we already have the relevant bits set. 1.912 + if (skip != LOGICAL_SIDES_I_BOTH) { 1.913 + // We're missing one of the skip bits, so check whether we need to set it. 1.914 + // Only get the first continuation once, as an optimization. 1.915 + nsIFrame* firstContinuation = FirstContinuation(); 1.916 + if (firstContinuation->FrameIsNonLastInIBSplit()) { 1.917 + skip |= LOGICAL_SIDE_I_END; 1.918 + } 1.919 + if (firstContinuation->FrameIsNonFirstInIBSplit()) { 1.920 + skip |= LOGICAL_SIDE_I_START; 1.921 + } 1.922 + } 1.923 + } 1.924 + 1.925 + return skip; 1.926 +} 1.927 + 1.928 +nscoord 1.929 +nsInlineFrame::GetBaseline() const 1.930 +{ 1.931 + return mBaseline; 1.932 +} 1.933 + 1.934 +#ifdef ACCESSIBILITY 1.935 +a11y::AccType 1.936 +nsInlineFrame::AccessibleType() 1.937 +{ 1.938 + // Broken image accessibles are created here, because layout 1.939 + // replaces the image or image control frame with an inline frame 1.940 + nsIAtom *tagAtom = mContent->Tag(); 1.941 + if (tagAtom == nsGkAtoms::input) // Broken <input type=image ... /> 1.942 + return a11y::eHTMLButtonType; 1.943 + if (tagAtom == nsGkAtoms::img) // Create accessible for broken <img> 1.944 + return a11y::eHyperTextType; 1.945 + 1.946 + return a11y::eNoType; 1.947 +} 1.948 +#endif 1.949 + 1.950 +////////////////////////////////////////////////////////////////////// 1.951 + 1.952 +// nsLineFrame implementation 1.953 + 1.954 +nsIFrame* 1.955 +NS_NewFirstLineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.956 +{ 1.957 + return new (aPresShell) nsFirstLineFrame(aContext); 1.958 +} 1.959 + 1.960 +NS_IMPL_FRAMEARENA_HELPERS(nsFirstLineFrame) 1.961 + 1.962 +void 1.963 +nsFirstLineFrame::Init(nsIContent* aContent, nsIFrame* aParent, 1.964 + nsIFrame* aPrevInFlow) 1.965 +{ 1.966 + nsInlineFrame::Init(aContent, aParent, aPrevInFlow); 1.967 + if (!aPrevInFlow) { 1.968 + MOZ_ASSERT(StyleContext()->GetPseudo() == nsCSSPseudoElements::firstLine); 1.969 + return; 1.970 + } 1.971 + 1.972 + // This frame is a continuation - fixup the style context if aPrevInFlow 1.973 + // is the first-in-flow (the only one with a ::first-line pseudo). 1.974 + if (aPrevInFlow->StyleContext()->GetPseudo() == nsCSSPseudoElements::firstLine) { 1.975 + MOZ_ASSERT(FirstInFlow() == aPrevInFlow); 1.976 + // Create a new style context that is a child of the parent 1.977 + // style context thus removing the ::first-line style. This way 1.978 + // we behave as if an anonymous (unstyled) span was the child 1.979 + // of the parent frame. 1.980 + nsStyleContext* parentContext = aParent->StyleContext(); 1.981 + nsRefPtr<nsStyleContext> newSC = PresContext()->StyleSet()-> 1.982 + ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozLineFrame, parentContext); 1.983 + SetStyleContext(newSC); 1.984 + } else { 1.985 + MOZ_ASSERT(FirstInFlow() != aPrevInFlow); 1.986 + MOZ_ASSERT(aPrevInFlow->StyleContext()->GetPseudo() == 1.987 + nsCSSAnonBoxes::mozLineFrame); 1.988 + } 1.989 +} 1.990 + 1.991 +#ifdef DEBUG_FRAME_DUMP 1.992 +nsresult 1.993 +nsFirstLineFrame::GetFrameName(nsAString& aResult) const 1.994 +{ 1.995 + return MakeFrameName(NS_LITERAL_STRING("Line"), aResult); 1.996 +} 1.997 +#endif 1.998 + 1.999 +nsIAtom* 1.1000 +nsFirstLineFrame::GetType() const 1.1001 +{ 1.1002 + return nsGkAtoms::lineFrame; 1.1003 +} 1.1004 + 1.1005 +nsIFrame* 1.1006 +nsFirstLineFrame::PullOneFrame(nsPresContext* aPresContext, InlineReflowState& irs, 1.1007 + bool* aIsComplete) 1.1008 +{ 1.1009 + nsIFrame* frame = nsInlineFrame::PullOneFrame(aPresContext, irs, aIsComplete); 1.1010 + if (frame && !GetPrevInFlow()) { 1.1011 + // We are a first-line frame. Fixup the child frames 1.1012 + // style-context that we just pulled. 1.1013 + NS_ASSERTION(frame->GetParent() == this, "Incorrect parent?"); 1.1014 + aPresContext->RestyleManager()->ReparentStyleContext(frame); 1.1015 + nsLayoutUtils::MarkDescendantsDirty(frame); 1.1016 + } 1.1017 + return frame; 1.1018 +} 1.1019 + 1.1020 +nsresult 1.1021 +nsFirstLineFrame::Reflow(nsPresContext* aPresContext, 1.1022 + nsHTMLReflowMetrics& aMetrics, 1.1023 + const nsHTMLReflowState& aReflowState, 1.1024 + nsReflowStatus& aStatus) 1.1025 +{ 1.1026 + if (nullptr == aReflowState.mLineLayout) { 1.1027 + return NS_ERROR_INVALID_ARG; 1.1028 + } 1.1029 + 1.1030 + nsIFrame* lineContainer = aReflowState.mLineLayout->LineContainerFrame(); 1.1031 + 1.1032 + // Check for an overflow list with our prev-in-flow 1.1033 + nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)GetPrevInFlow(); 1.1034 + if (prevInFlow) { 1.1035 + AutoFrameListPtr prevOverflowFrames(aPresContext, 1.1036 + prevInFlow->StealOverflowFrames()); 1.1037 + if (prevOverflowFrames) { 1.1038 + // Assign all floats to our block if necessary 1.1039 + if (lineContainer && lineContainer->GetPrevContinuation()) { 1.1040 + ReparentFloatsForInlineChild(lineContainer, 1.1041 + prevOverflowFrames->FirstChild(), 1.1042 + true); 1.1043 + } 1.1044 + const nsFrameList::Slice& newFrames = 1.1045 + mFrames.InsertFrames(this, nullptr, *prevOverflowFrames); 1.1046 + ReparentChildListStyle(aPresContext, newFrames, this); 1.1047 + } 1.1048 + } 1.1049 + 1.1050 + // It's also possible that we have an overflow list for ourselves. 1.1051 + DrainSelfOverflowList(); 1.1052 + 1.1053 + // Set our own reflow state (additional state above and beyond 1.1054 + // aReflowState) 1.1055 + InlineReflowState irs; 1.1056 + irs.mPrevFrame = nullptr; 1.1057 + irs.mLineContainer = lineContainer; 1.1058 + irs.mLineLayout = aReflowState.mLineLayout; 1.1059 + irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow(); 1.1060 + 1.1061 + nsresult rv; 1.1062 + bool wasEmpty = mFrames.IsEmpty(); 1.1063 + if (wasEmpty) { 1.1064 + // Try to pull over one frame before starting so that we know 1.1065 + // whether we have an anonymous block or not. 1.1066 + bool complete; 1.1067 + PullOneFrame(aPresContext, irs, &complete); 1.1068 + } 1.1069 + 1.1070 + if (nullptr == GetPrevInFlow()) { 1.1071 + // XXX This is pretty sick, but what we do here is to pull-up, in 1.1072 + // advance, all of the next-in-flows children. We re-resolve their 1.1073 + // style while we are at at it so that when we reflow they have 1.1074 + // the right style. 1.1075 + // 1.1076 + // All of this is so that text-runs reflow properly. 1.1077 + irs.mPrevFrame = mFrames.LastChild(); 1.1078 + for (;;) { 1.1079 + bool complete; 1.1080 + nsIFrame* frame = PullOneFrame(aPresContext, irs, &complete); 1.1081 + if (!frame) { 1.1082 + break; 1.1083 + } 1.1084 + irs.mPrevFrame = frame; 1.1085 + } 1.1086 + irs.mPrevFrame = nullptr; 1.1087 + } 1.1088 + 1.1089 + NS_ASSERTION(!aReflowState.mLineLayout->GetInFirstLine(), 1.1090 + "Nested first-line frames? BOGUS"); 1.1091 + aReflowState.mLineLayout->SetInFirstLine(true); 1.1092 + rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus); 1.1093 + aReflowState.mLineLayout->SetInFirstLine(false); 1.1094 + 1.1095 + ReflowAbsoluteFrames(aPresContext, aMetrics, aReflowState, aStatus); 1.1096 + 1.1097 + // Note: the line layout code will properly compute our overflow state for us 1.1098 + 1.1099 + return rv; 1.1100 +} 1.1101 + 1.1102 +/* virtual */ void 1.1103 +nsFirstLineFrame::PullOverflowsFromPrevInFlow() 1.1104 +{ 1.1105 + nsFirstLineFrame* prevInFlow = static_cast<nsFirstLineFrame*>(GetPrevInFlow()); 1.1106 + if (prevInFlow) { 1.1107 + nsPresContext* presContext = PresContext(); 1.1108 + AutoFrameListPtr prevOverflowFrames(presContext, 1.1109 + prevInFlow->StealOverflowFrames()); 1.1110 + if (prevOverflowFrames) { 1.1111 + // Assume that our prev-in-flow has the same line container that we do. 1.1112 + const nsFrameList::Slice& newFrames = 1.1113 + mFrames.InsertFrames(this, nullptr, *prevOverflowFrames); 1.1114 + ReparentChildListStyle(presContext, newFrames, this); 1.1115 + } 1.1116 + } 1.1117 +} 1.1118 + 1.1119 +/* virtual */ bool 1.1120 +nsFirstLineFrame::DrainSelfOverflowList() 1.1121 +{ 1.1122 + AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames()); 1.1123 + if (overflowFrames) { 1.1124 + NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); 1.1125 + 1.1126 + bool result = !overflowFrames->IsEmpty(); 1.1127 + const nsFrameList::Slice& newFrames = 1.1128 + mFrames.AppendFrames(nullptr, *overflowFrames); 1.1129 + ReparentChildListStyle(PresContext(), newFrames, this); 1.1130 + return result; 1.1131 + } 1.1132 + return false; 1.1133 +}