1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /* rendering object for CSS display:inline objects */
39 :
40 : #include "nsCOMPtr.h"
41 : #include "nsInlineFrame.h"
42 : #include "nsBlockFrame.h"
43 : #include "nsPlaceholderFrame.h"
44 : #include "nsGkAtoms.h"
45 : #include "nsHTMLParts.h"
46 : #include "nsStyleContext.h"
47 : #include "nsIPresShell.h"
48 : #include "nsPresContext.h"
49 : #include "nsRenderingContext.h"
50 : #include "nsCSSAnonBoxes.h"
51 : #include "nsAutoPtr.h"
52 : #include "nsFrameManager.h"
53 : #ifdef ACCESSIBILITY
54 : #include "nsIServiceManager.h"
55 : #include "nsAccessibilityService.h"
56 : #endif
57 : #include "nsDisplayList.h"
58 :
59 : #ifdef DEBUG
60 : #undef NOISY_PUSHING
61 : #endif
62 :
63 :
64 : //////////////////////////////////////////////////////////////////////
65 :
66 : // Basic nsInlineFrame methods
67 :
68 : nsIFrame*
69 0 : NS_NewInlineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
70 : {
71 0 : return new (aPresShell) nsInlineFrame(aContext);
72 : }
73 :
74 : NS_IMETHODIMP
75 0 : nsInlineFrame::Init(nsIContent* aContent,
76 : nsIFrame* aParent,
77 : nsIFrame* aPrevInFlow)
78 : {
79 : // Let the base class do its processing
80 0 : nsresult rv = nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
81 :
82 : // Transforms do not affect regular inline elements (bug 722463)
83 0 : mState &= ~NS_FRAME_MAY_BE_TRANSFORMED;
84 :
85 0 : return rv;
86 : }
87 :
88 0 : NS_IMPL_FRAMEARENA_HELPERS(nsInlineFrame)
89 :
90 0 : NS_QUERYFRAME_HEAD(nsInlineFrame)
91 0 : NS_QUERYFRAME_ENTRY(nsInlineFrame)
92 0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
93 :
94 : #ifdef DEBUG
95 : NS_IMETHODIMP
96 0 : nsInlineFrame::GetFrameName(nsAString& aResult) const
97 : {
98 0 : return MakeFrameName(NS_LITERAL_STRING("Inline"), aResult);
99 : }
100 : #endif
101 :
102 : nsIAtom*
103 0 : nsInlineFrame::GetType() const
104 : {
105 0 : return nsGkAtoms::inlineFrame;
106 : }
107 :
108 : static inline bool
109 0 : IsMarginZero(const nsStyleCoord &aCoord)
110 : {
111 0 : return aCoord.GetUnit() == eStyleUnit_Auto ||
112 0 : nsLayoutUtils::IsMarginZero(aCoord);
113 : }
114 :
115 : /* virtual */ bool
116 0 : nsInlineFrame::IsSelfEmpty()
117 : {
118 : #if 0
119 : // I used to think inline frames worked this way, but it seems they
120 : // don't. At least not in our codebase.
121 : if (GetPresContext()->CompatibilityMode() == eCompatibility_FullStandards) {
122 : return false;
123 : }
124 : #endif
125 0 : const nsStyleMargin* margin = GetStyleMargin();
126 0 : const nsStyleBorder* border = GetStyleBorder();
127 0 : const nsStylePadding* padding = GetStylePadding();
128 : // XXX Top and bottom removed, since they shouldn't affect things, but this
129 : // doesn't really match with nsLineLayout.cpp's setting of
130 : // ZeroEffectiveSpanBox, anymore, so what should this really be?
131 : bool haveRight =
132 0 : border->GetActualBorderWidth(NS_SIDE_RIGHT) != 0 ||
133 0 : !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetRight()) ||
134 0 : !IsMarginZero(margin->mMargin.GetRight());
135 : bool haveLeft =
136 0 : border->GetActualBorderWidth(NS_SIDE_LEFT) != 0 ||
137 0 : !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetLeft()) ||
138 0 : !IsMarginZero(margin->mMargin.GetLeft());
139 0 : if (haveLeft || haveRight) {
140 0 : if (GetStateBits() & NS_FRAME_IS_SPECIAL) {
141 : bool haveStart, haveEnd;
142 0 : if (NS_STYLE_DIRECTION_LTR == GetStyleVisibility()->mDirection) {
143 0 : haveStart = haveLeft;
144 0 : haveEnd = haveRight;
145 : } else {
146 0 : haveStart = haveRight;
147 0 : haveEnd = haveLeft;
148 : }
149 : // For special frames, ignore things we know we'll skip in GetSkipSides.
150 : // XXXbz should we be doing this for non-special frames too, in a more
151 : // general way?
152 :
153 : // Get the first continuation eagerly, as a performance optimization, to
154 : // avoid having to get it twice..
155 0 : nsIFrame* firstCont = GetFirstContinuation();
156 : return
157 0 : (!haveStart || nsLayoutUtils::FrameIsNonFirstInIBSplit(firstCont)) &&
158 0 : (!haveEnd || nsLayoutUtils::FrameIsNonLastInIBSplit(firstCont));
159 : }
160 0 : return false;
161 : }
162 0 : return true;
163 : }
164 :
165 : bool
166 0 : nsInlineFrame::IsEmpty()
167 : {
168 0 : if (!IsSelfEmpty()) {
169 0 : return false;
170 : }
171 :
172 0 : for (nsIFrame *kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) {
173 0 : if (!kid->IsEmpty())
174 0 : return false;
175 : }
176 :
177 0 : return true;
178 : }
179 :
180 : bool
181 0 : nsInlineFrame::PeekOffsetCharacter(bool aForward, PRInt32* aOffset,
182 : bool aRespectClusters)
183 : {
184 : // Override the implementation in nsFrame, to skip empty inline frames
185 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
186 0 : PRInt32 startOffset = *aOffset;
187 0 : if (startOffset < 0)
188 0 : startOffset = 1;
189 0 : if (aForward == (startOffset == 0)) {
190 : // We're before the frame and moving forward, or after it and moving backwards:
191 : // skip to the other side, but keep going.
192 0 : *aOffset = 1 - startOffset;
193 : }
194 0 : return false;
195 : }
196 :
197 : NS_IMETHODIMP
198 0 : nsInlineFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
199 : const nsRect& aDirtyRect,
200 : const nsDisplayListSet& aLists)
201 : {
202 0 : nsresult rv = BuildDisplayListForInline(aBuilder, aDirtyRect, aLists);
203 0 : NS_ENSURE_SUCCESS(rv, rv);
204 :
205 : // The sole purpose of this is to trigger display of the selection
206 : // window for Named Anchors, which don't have any children and
207 : // normally don't have any size, but in Editor we use CSS to display
208 : // an image to represent this "hidden" element.
209 0 : if (!mFrames.FirstChild()) {
210 0 : rv = DisplaySelectionOverlay(aBuilder, aLists.Content());
211 : }
212 0 : return rv;
213 : }
214 :
215 : //////////////////////////////////////////////////////////////////////
216 : // Reflow methods
217 :
218 : /* virtual */ void
219 0 : nsInlineFrame::AddInlineMinWidth(nsRenderingContext *aRenderingContext,
220 : nsIFrame::InlineMinWidthData *aData)
221 : {
222 0 : DoInlineIntrinsicWidth(aRenderingContext, aData, nsLayoutUtils::MIN_WIDTH);
223 0 : }
224 :
225 : /* virtual */ void
226 0 : nsInlineFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext,
227 : nsIFrame::InlinePrefWidthData *aData)
228 : {
229 0 : DoInlineIntrinsicWidth(aRenderingContext, aData, nsLayoutUtils::PREF_WIDTH);
230 0 : }
231 :
232 : /* virtual */ nsSize
233 0 : nsInlineFrame::ComputeSize(nsRenderingContext *aRenderingContext,
234 : nsSize aCBSize, nscoord aAvailableWidth,
235 : nsSize aMargin, nsSize aBorder, nsSize aPadding,
236 : bool aShrinkWrap)
237 : {
238 : // Inlines and text don't compute size before reflow.
239 0 : return nsSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
240 : }
241 :
242 : nsRect
243 0 : nsInlineFrame::ComputeTightBounds(gfxContext* aContext) const
244 : {
245 : // be conservative
246 0 : if (GetStyleContext()->HasTextDecorationLines()) {
247 0 : return GetVisualOverflowRect();
248 : }
249 0 : return ComputeSimpleTightBounds(aContext);
250 : }
251 :
252 : void
253 0 : nsInlineFrame::ReparentFloatsForInlineChild(nsIFrame* aOurLineContainer,
254 : nsIFrame* aFrame,
255 : bool aReparentSiblings)
256 : {
257 : // XXXbz this would be better if it took a nsFrameList or a frame
258 : // list slice....
259 0 : NS_ASSERTION(aOurLineContainer->GetNextContinuation() ||
260 : aOurLineContainer->GetPrevContinuation(),
261 : "Don't call this when we have no continuation, it's a waste");
262 0 : if (!aFrame) {
263 0 : NS_ASSERTION(aReparentSiblings, "Why did we get called?");
264 0 : return;
265 : }
266 :
267 0 : nsIFrame* ancestor = aFrame;
268 : nsIFrame* ancestorBlockChild;
269 0 : do {
270 0 : ancestorBlockChild = ancestor;
271 0 : ancestor = ancestor->GetParent();
272 0 : if (!ancestor)
273 0 : return;
274 0 : } while (!ancestor->IsFloatContainingBlock());
275 :
276 0 : if (ancestor == aOurLineContainer)
277 0 : return;
278 :
279 0 : nsBlockFrame* ourBlock = nsLayoutUtils::GetAsBlock(aOurLineContainer);
280 0 : NS_ASSERTION(ourBlock, "Not a block, but broke vertically?");
281 0 : nsBlockFrame* frameBlock = nsLayoutUtils::GetAsBlock(ancestor);
282 0 : NS_ASSERTION(frameBlock, "ancestor not a block");
283 :
284 0 : const nsFrameList& blockChildren(ancestor->PrincipalChildList());
285 0 : bool isOverflow = !blockChildren.ContainsFrame(ancestorBlockChild);
286 :
287 0 : while (true) {
288 0 : ourBlock->ReparentFloats(aFrame, frameBlock, isOverflow, false);
289 :
290 0 : if (!aReparentSiblings)
291 0 : return;
292 0 : nsIFrame* next = aFrame->GetNextSibling();
293 0 : if (!next)
294 0 : return;
295 0 : if (next->GetParent() == aFrame->GetParent()) {
296 0 : aFrame = next;
297 0 : continue;
298 : }
299 : // This is paranoid and will hardly ever get hit ... but we can't actually
300 : // trust that the frames in the sibling chain all have the same parent,
301 : // because lazy reparenting may be going on. If we find a different
302 : // parent we need to redo our analysis.
303 0 : ReparentFloatsForInlineChild(aOurLineContainer, next, aReparentSiblings);
304 0 : return;
305 : }
306 : }
307 :
308 : static void
309 0 : ReparentChildListStyle(nsPresContext* aPresContext,
310 : const nsFrameList::Slice& aFrames,
311 : nsIFrame* aParentFrame)
312 : {
313 0 : nsFrameManager *frameManager = aPresContext->FrameManager();
314 :
315 0 : for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) {
316 0 : NS_ASSERTION(e.get()->GetParent() == aParentFrame, "Bogus parentage");
317 0 : frameManager->ReparentStyleContext(e.get());
318 : }
319 0 : }
320 :
321 : NS_IMETHODIMP
322 0 : nsInlineFrame::Reflow(nsPresContext* aPresContext,
323 : nsHTMLReflowMetrics& aMetrics,
324 : const nsHTMLReflowState& aReflowState,
325 : nsReflowStatus& aStatus)
326 : {
327 0 : DO_GLOBAL_REFLOW_COUNT("nsInlineFrame");
328 0 : DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
329 0 : if (nsnull == aReflowState.mLineLayout) {
330 0 : return NS_ERROR_INVALID_ARG;
331 : }
332 :
333 0 : bool lazilySetParentPointer = false;
334 :
335 0 : nsIFrame* lineContainer = aReflowState.mLineLayout->GetLineContainerFrame();
336 :
337 : // Check for an overflow list with our prev-in-flow
338 0 : nsInlineFrame* prevInFlow = (nsInlineFrame*)GetPrevInFlow();
339 0 : if (nsnull != prevInFlow) {
340 0 : nsAutoPtr<nsFrameList> prevOverflowFrames(prevInFlow->StealOverflowFrames());
341 :
342 0 : if (prevOverflowFrames) {
343 : // When pushing and pulling frames we need to check for whether any
344 : // views need to be reparented.
345 : nsContainerFrame::ReparentFrameViewList(aPresContext,
346 0 : *prevOverflowFrames,
347 0 : prevInFlow, this);
348 :
349 : // Check if we should do the lazilySetParentPointer optimization.
350 : // Only do it in simple cases where we're being reflowed for the
351 : // first time, nothing (e.g. bidi resolution) has already given
352 : // us children, and there's no next-in-flow, so all our frames
353 : // will be taken from prevOverflowFrames.
354 0 : if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) && mFrames.IsEmpty() &&
355 0 : !GetNextInFlow()) {
356 : // If our child list is empty, just put the new frames into it.
357 : // Note that we don't set the parent pointer for the new frames. Instead wait
358 : // to do this until we actually reflow the frame. If the overflow list contains
359 : // thousands of frames this is a big performance issue (see bug #5588)
360 0 : mFrames.SetFrames(*prevOverflowFrames);
361 0 : lazilySetParentPointer = true;
362 : } else {
363 : // Assign all floats to our block if necessary
364 0 : if (lineContainer && lineContainer->GetPrevContinuation()) {
365 : ReparentFloatsForInlineChild(lineContainer,
366 : prevOverflowFrames->FirstChild(),
367 0 : true);
368 : }
369 : // Insert the new frames at the beginning of the child list
370 : // and set their parent pointer
371 : const nsFrameList::Slice& newFrames =
372 0 : mFrames.InsertFrames(this, nsnull, *prevOverflowFrames);
373 : // If our prev in flow was under the first continuation of a first-line
374 : // frame then we need to reparent the style contexts to remove the
375 : // the special first-line styling. In the lazilySetParentPointer case
376 : // we reparent the style contexts when we set their parents in
377 : // nsInlineFrame::ReflowFrames and nsInlineFrame::ReflowInlineFrame.
378 0 : if (aReflowState.mLineLayout->GetInFirstLine()) {
379 0 : ReparentChildListStyle(aPresContext, newFrames, this);
380 : }
381 : }
382 : }
383 : }
384 :
385 : // It's also possible that we have an overflow list for ourselves
386 : #ifdef DEBUG
387 0 : if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
388 : // If it's our initial reflow, then we should not have an overflow list.
389 : // However, add an assertion in case we get reflowed more than once with
390 : // the initial reflow reason
391 0 : nsFrameList* overflowFrames = GetOverflowFrames();
392 0 : NS_ASSERTION(!overflowFrames || overflowFrames->IsEmpty(),
393 : "overflow list is not empty for initial reflow");
394 : }
395 : #endif
396 0 : if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
397 0 : nsAutoPtr<nsFrameList> overflowFrames(StealOverflowFrames());
398 0 : if (overflowFrames) {
399 0 : NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
400 :
401 : // Because we lazily set the parent pointer of child frames we get from
402 : // our prev-in-flow's overflow list, it's possible that we have not set
403 : // the parent pointer for these frames.
404 0 : mFrames.AppendFrames(this, *overflowFrames);
405 : }
406 : }
407 :
408 0 : if (IsFrameTreeTooDeep(aReflowState, aMetrics, aStatus)) {
409 0 : return NS_OK;
410 : }
411 :
412 : // Set our own reflow state (additional state above and beyond
413 : // aReflowState)
414 0 : InlineReflowState irs;
415 0 : irs.mPrevFrame = nsnull;
416 0 : irs.mLineContainer = lineContainer;
417 0 : irs.mLineLayout = aReflowState.mLineLayout;
418 0 : irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow();
419 0 : irs.mSetParentPointer = lazilySetParentPointer;
420 :
421 : nsresult rv;
422 0 : if (mFrames.IsEmpty()) {
423 : // Try to pull over one frame before starting so that we know
424 : // whether we have an anonymous block or not.
425 : bool complete;
426 0 : (void) PullOneFrame(aPresContext, irs, &complete);
427 : }
428 :
429 0 : rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus);
430 :
431 0 : ReflowAbsoluteFrames(aPresContext, aMetrics, aReflowState, aStatus);
432 :
433 : // Note: the line layout code will properly compute our
434 : // overflow-rect state for us.
435 :
436 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
437 0 : return rv;
438 : }
439 :
440 : /* virtual */ bool
441 0 : nsInlineFrame::CanContinueTextRun() const
442 : {
443 : // We can continue a text run through an inline frame
444 0 : return true;
445 : }
446 :
447 : /* virtual */ void
448 0 : nsInlineFrame::PullOverflowsFromPrevInFlow()
449 : {
450 0 : nsInlineFrame* prevInFlow = static_cast<nsInlineFrame*>(GetPrevInFlow());
451 0 : if (prevInFlow) {
452 0 : nsAutoPtr<nsFrameList> prevOverflowFrames(prevInFlow->StealOverflowFrames());
453 0 : if (prevOverflowFrames) {
454 : // Assume that our prev-in-flow has the same line container that we do.
455 : nsContainerFrame::ReparentFrameViewList(PresContext(),
456 0 : *prevOverflowFrames,
457 0 : prevInFlow, this);
458 0 : mFrames.InsertFrames(this, nsnull, *prevOverflowFrames);
459 : }
460 : }
461 0 : }
462 :
463 : nsresult
464 0 : nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
465 : const nsHTMLReflowState& aReflowState,
466 : InlineReflowState& irs,
467 : nsHTMLReflowMetrics& aMetrics,
468 : nsReflowStatus& aStatus)
469 : {
470 0 : nsresult rv = NS_OK;
471 0 : aStatus = NS_FRAME_COMPLETE;
472 :
473 0 : nsLineLayout* lineLayout = aReflowState.mLineLayout;
474 0 : bool inFirstLine = aReflowState.mLineLayout->GetInFirstLine();
475 0 : nsFrameManager* frameManager = aPresContext->FrameManager();
476 0 : bool ltr = (NS_STYLE_DIRECTION_LTR == aReflowState.mStyleVisibility->mDirection);
477 0 : nscoord leftEdge = 0;
478 : // Don't offset by our start borderpadding if we have a prev continuation or
479 : // if we're in a part of an {ib} split other than the first one.
480 0 : if (!GetPrevContinuation() &&
481 0 : !nsLayoutUtils::FrameIsNonFirstInIBSplit(this)) {
482 : leftEdge = ltr ? aReflowState.mComputedBorderPadding.left
483 0 : : aReflowState.mComputedBorderPadding.right;
484 : }
485 0 : nscoord availableWidth = aReflowState.availableWidth;
486 0 : NS_ASSERTION(availableWidth != NS_UNCONSTRAINEDSIZE,
487 : "should no longer use available widths");
488 : // Subtract off left and right border+padding from availableWidth
489 0 : availableWidth -= leftEdge;
490 : availableWidth -= ltr ? aReflowState.mComputedBorderPadding.right
491 0 : : aReflowState.mComputedBorderPadding.left;
492 : lineLayout->BeginSpan(this, &aReflowState, leftEdge,
493 0 : leftEdge + availableWidth, &mBaseline);
494 :
495 : // First reflow our current children
496 0 : nsIFrame* frame = mFrames.FirstChild();
497 0 : bool done = false;
498 0 : while (nsnull != frame) {
499 0 : bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
500 :
501 : // Check if we should lazily set the child frame's parent pointer
502 0 : if (irs.mSetParentPointer) {
503 : bool havePrevBlock =
504 0 : irs.mLineContainer && irs.mLineContainer->GetPrevContinuation();
505 : // If our block is the first in flow, then any floats under the pulled
506 : // frame must already belong to our block.
507 0 : if (havePrevBlock) {
508 : // This has to happen before we update frame's parent; we need to
509 : // know frame's ancestry under its old block.
510 : // The blockChildren.ContainsFrame check performed by
511 : // ReparentFloatsForInlineChild here may be slow, but we can't
512 : // easily avoid it because we don't know where 'frame' originally
513 : // came from. If we really really have to optimize this we could
514 : // cache whether frame->GetParent() is under its containing blocks
515 : // overflowList or not.
516 0 : ReparentFloatsForInlineChild(irs.mLineContainer, frame, false);
517 : }
518 0 : frame->SetParent(this);
519 0 : if (inFirstLine) {
520 0 : frameManager->ReparentStyleContext(frame);
521 : }
522 : // We also need to check if frame has a next-in-flow. If it does, then set
523 : // its parent frame pointer, too. Otherwise, if we reflow frame and it's
524 : // complete we'll fail when deleting its next-in-flow which is no longer
525 : // needed. This scenario doesn't happen often, but it can happen
526 0 : nsIFrame* nextInFlow = frame->GetNextInFlow();
527 0 : for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
528 : // Since we only do lazy setting of parent pointers for the frame's
529 : // initial reflow, this frame can't have a next-in-flow. That means
530 : // the continuing child frame must be in our child list as well. If
531 : // not, then something is wrong
532 0 : NS_ASSERTION(mFrames.ContainsFrame(nextInFlow), "unexpected flow");
533 0 : if (havePrevBlock) {
534 0 : ReparentFloatsForInlineChild(irs.mLineContainer, nextInFlow, false);
535 : }
536 0 : nextInFlow->SetParent(this);
537 0 : if (inFirstLine) {
538 0 : frameManager->ReparentStyleContext(nextInFlow);
539 : }
540 : }
541 :
542 : // Fix the parent pointer for ::first-letter child frame next-in-flows,
543 : // so nsFirstLetterFrame::Reflow can destroy them safely (bug 401042).
544 0 : nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(frame);
545 0 : if (realFrame->GetType() == nsGkAtoms::letterFrame) {
546 0 : nsIFrame* child = realFrame->GetFirstPrincipalChild();
547 0 : if (child) {
548 0 : NS_ASSERTION(child->GetType() == nsGkAtoms::textFrame,
549 : "unexpected frame type");
550 0 : nsIFrame* nextInFlow = child->GetNextInFlow();
551 0 : for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
552 0 : NS_ASSERTION(nextInFlow->GetType() == nsGkAtoms::textFrame,
553 : "unexpected frame type");
554 0 : if (mFrames.ContainsFrame(nextInFlow)) {
555 0 : nextInFlow->SetParent(this);
556 0 : if (inFirstLine) {
557 0 : frameManager->ReparentStyleContext(nextInFlow);
558 : }
559 : }
560 : else {
561 : #ifdef DEBUG
562 : // Once we find a next-in-flow that isn't ours none of the
563 : // remaining next-in-flows should be either.
564 0 : for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
565 0 : NS_ASSERTION(!mFrames.ContainsFrame(nextInFlow),
566 : "unexpected letter frame flow");
567 : }
568 : #endif
569 0 : break;
570 : }
571 : }
572 : }
573 : }
574 : }
575 0 : rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
576 0 : if (NS_FAILED(rv)) {
577 0 : done = true;
578 0 : break;
579 : }
580 0 : if (NS_INLINE_IS_BREAK(aStatus) ||
581 0 : (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) {
582 0 : done = true;
583 0 : break;
584 : }
585 0 : irs.mPrevFrame = frame;
586 0 : frame = frame->GetNextSibling();
587 : }
588 :
589 : // Attempt to pull frames from our next-in-flow until we can't
590 0 : if (!done && (nsnull != GetNextInFlow())) {
591 0 : while (!done) {
592 0 : bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
593 : bool isComplete;
594 0 : if (!frame) { // Could be non-null if we pulled a first-letter frame and
595 : // it created a continuation, since we don't push those.
596 0 : frame = PullOneFrame(aPresContext, irs, &isComplete);
597 : }
598 : #ifdef NOISY_PUSHING
599 : printf("%p pulled up %p\n", this, frame);
600 : #endif
601 0 : if (nsnull == frame) {
602 0 : if (!isComplete) {
603 0 : aStatus = NS_FRAME_NOT_COMPLETE;
604 : }
605 0 : break;
606 : }
607 0 : rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
608 0 : if (NS_FAILED(rv)) {
609 0 : done = true;
610 0 : break;
611 : }
612 0 : if (NS_INLINE_IS_BREAK(aStatus) ||
613 0 : (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) {
614 0 : done = true;
615 0 : break;
616 : }
617 0 : irs.mPrevFrame = frame;
618 0 : frame = frame->GetNextSibling();
619 : }
620 : }
621 : #ifdef DEBUG
622 0 : if (NS_FRAME_IS_COMPLETE(aStatus)) {
623 : // We can't be complete AND have overflow frames!
624 0 : NS_ASSERTION(!GetOverflowFrames(), "whoops");
625 : }
626 : #endif
627 :
628 : // If after reflowing our children they take up no area then make
629 : // sure that we don't either.
630 : //
631 : // Note: CSS demands that empty inline elements still affect the
632 : // line-height calculations. However, continuations of an inline
633 : // that are empty we force to empty so that things like collapsed
634 : // whitespace in an inline element don't affect the line-height.
635 0 : aMetrics.width = lineLayout->EndSpan(this);
636 :
637 : // Compute final width.
638 :
639 : // Make sure to not include our start border and padding if we have a prev
640 : // continuation or if we're in a part of an {ib} split other than the first
641 : // one.
642 0 : if (!GetPrevContinuation() &&
643 0 : !nsLayoutUtils::FrameIsNonFirstInIBSplit(this)) {
644 : aMetrics.width += ltr ? aReflowState.mComputedBorderPadding.left
645 0 : : aReflowState.mComputedBorderPadding.right;
646 : }
647 :
648 : /*
649 : * We want to only apply the end border and padding if we're the last
650 : * continuation and either not in an {ib} split or the last part of it. To
651 : * be the last continuation we have to be complete (so that we won't get a
652 : * next-in-flow) and have no non-fluid continuations on our continuation
653 : * chain.
654 : */
655 0 : if (NS_FRAME_IS_COMPLETE(aStatus) &&
656 0 : !GetLastInFlow()->GetNextContinuation() &&
657 0 : !nsLayoutUtils::FrameIsNonLastInIBSplit(this)) {
658 : aMetrics.width += ltr ? aReflowState.mComputedBorderPadding.right
659 0 : : aReflowState.mComputedBorderPadding.left;
660 : }
661 :
662 0 : nsRefPtr<nsFontMetrics> fm;
663 : float inflation =
664 0 : nsLayoutUtils::FontSizeInflationFor(this, nsLayoutUtils::eInReflow);
665 0 : nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), inflation);
666 0 : aReflowState.rendContext->SetFont(fm);
667 :
668 0 : if (fm) {
669 : // Compute final height of the frame.
670 : //
671 : // Do things the standard css2 way -- though it's hard to find it
672 : // in the css2 spec! It's actually found in the css1 spec section
673 : // 4.4 (you will have to read between the lines to really see
674 : // it).
675 : //
676 : // The height of our box is the sum of our font size plus the top
677 : // and bottom border and padding. The height of children do not
678 : // affect our height.
679 0 : aMetrics.ascent = fm->MaxAscent();
680 0 : aMetrics.height = fm->MaxHeight();
681 : } else {
682 0 : NS_WARNING("Cannot get font metrics - defaulting sizes to 0");
683 0 : aMetrics.ascent = aMetrics.height = 0;
684 : }
685 0 : aMetrics.ascent += aReflowState.mComputedBorderPadding.top;
686 : aMetrics.height += aReflowState.mComputedBorderPadding.top +
687 0 : aReflowState.mComputedBorderPadding.bottom;
688 :
689 : // For now our overflow area is zero. The real value will be
690 : // computed in |nsLineLayout::RelativePositionFrames|.
691 0 : aMetrics.mOverflowAreas.Clear();
692 :
693 : #ifdef NOISY_FINAL_SIZE
694 : ListTag(stdout);
695 : printf(": metrics=%d,%d ascent=%d\n",
696 : aMetrics.width, aMetrics.height, aMetrics.ascent);
697 : #endif
698 :
699 0 : return rv;
700 : }
701 :
702 : nsresult
703 0 : nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext,
704 : const nsHTMLReflowState& aReflowState,
705 : InlineReflowState& irs,
706 : nsIFrame* aFrame,
707 : nsReflowStatus& aStatus)
708 : {
709 0 : nsLineLayout* lineLayout = aReflowState.mLineLayout;
710 0 : bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
711 : bool pushedFrame;
712 : nsresult rv =
713 0 : lineLayout->ReflowFrame(aFrame, aStatus, nsnull, pushedFrame);
714 :
715 0 : if (NS_FAILED(rv)) {
716 0 : return rv;
717 : }
718 :
719 0 : if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) {
720 0 : if (aFrame != mFrames.FirstChild()) {
721 : // Change break-before status into break-after since we have
722 : // already placed at least one child frame. This preserves the
723 : // break-type so that it can be propagated upward.
724 : aStatus = NS_FRAME_NOT_COMPLETE |
725 : NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER |
726 0 : (aStatus & NS_INLINE_BREAK_TYPE_MASK);
727 0 : PushFrames(aPresContext, aFrame, irs.mPrevFrame, irs);
728 : }
729 : else {
730 : // Preserve reflow status when breaking-before our first child
731 : // and propagate it upward without modification.
732 : // Note: if we're lazily setting the frame pointer for our child
733 : // frames, then we need to set it now. Don't return and leave the
734 : // remaining child frames in our child list with the wrong parent
735 : // frame pointer...
736 0 : if (irs.mSetParentPointer) {
737 0 : if (irs.mLineContainer && irs.mLineContainer->GetPrevContinuation()) {
738 : ReparentFloatsForInlineChild(irs.mLineContainer, aFrame->GetNextSibling(),
739 0 : true);
740 : }
741 0 : for (nsIFrame* f = aFrame->GetNextSibling(); f; f = f->GetNextSibling()) {
742 0 : f->SetParent(this);
743 0 : if (lineLayout->GetInFirstLine()) {
744 0 : aPresContext->FrameManager()->ReparentStyleContext(f);
745 : }
746 : }
747 : }
748 : }
749 0 : return NS_OK;
750 : }
751 :
752 : // Create a next-in-flow if needed.
753 0 : if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
754 : nsIFrame* newFrame;
755 0 : rv = CreateNextInFlow(aPresContext, aFrame, newFrame);
756 0 : if (NS_FAILED(rv)) {
757 0 : return rv;
758 : }
759 : }
760 :
761 0 : if (NS_INLINE_IS_BREAK_AFTER(aStatus)) {
762 0 : nsIFrame* nextFrame = aFrame->GetNextSibling();
763 0 : if (nextFrame) {
764 0 : NS_FRAME_SET_INCOMPLETE(aStatus);
765 0 : PushFrames(aPresContext, nextFrame, aFrame, irs);
766 : }
767 : else {
768 : // We must return an incomplete status if there are more child
769 : // frames remaining in a next-in-flow that follows this frame.
770 0 : nsInlineFrame* nextInFlow = static_cast<nsInlineFrame*>(GetNextInFlow());
771 0 : while (nextInFlow) {
772 0 : if (nextInFlow->mFrames.NotEmpty()) {
773 0 : NS_FRAME_SET_INCOMPLETE(aStatus);
774 0 : break;
775 : }
776 0 : nextInFlow = static_cast<nsInlineFrame*>(nextInFlow->GetNextInFlow());
777 : }
778 : }
779 0 : return NS_OK;
780 : }
781 :
782 0 : if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !reflowingFirstLetter) {
783 0 : nsIFrame* nextFrame = aFrame->GetNextSibling();
784 0 : if (nextFrame) {
785 0 : PushFrames(aPresContext, nextFrame, aFrame, irs);
786 : }
787 : }
788 0 : return NS_OK;
789 : }
790 :
791 : nsIFrame*
792 0 : nsInlineFrame::PullOneFrame(nsPresContext* aPresContext,
793 : InlineReflowState& irs,
794 : bool* aIsComplete)
795 : {
796 0 : bool isComplete = true;
797 :
798 0 : nsIFrame* frame = nsnull;
799 0 : nsInlineFrame* nextInFlow = irs.mNextInFlow;
800 0 : while (nsnull != nextInFlow) {
801 0 : frame = nextInFlow->mFrames.FirstChild();
802 :
803 0 : if (!frame) {
804 : // If the principal childlist has no frames, then try moving the overflow
805 : // frames to it.
806 0 : nsAutoPtr<nsFrameList> overflowFrames(nextInFlow->StealOverflowFrames());
807 0 : if (overflowFrames) {
808 0 : nextInFlow->mFrames.SetFrames(*overflowFrames);
809 0 : frame = nextInFlow->mFrames.FirstChild();
810 : }
811 : }
812 :
813 0 : if (nsnull != frame) {
814 : // If our block has no next continuation, then any floats belonging to
815 : // the pulled frame must belong to our block already. This check ensures
816 : // we do no extra work in the common non-vertical-breaking case.
817 0 : if (irs.mLineContainer && irs.mLineContainer->GetNextContinuation()) {
818 : // The blockChildren.ContainsFrame check performed by
819 : // ReparentFloatsForInlineChild will be fast because frame's ancestor
820 : // will be the first child of its containing block.
821 0 : ReparentFloatsForInlineChild(irs.mLineContainer, frame, false);
822 : }
823 0 : nextInFlow->mFrames.RemoveFirstChild();
824 :
825 : // If we removed the last frame from the principal child list then move
826 : // any overflow frames to it.
827 0 : if (!nextInFlow->mFrames.FirstChild()) {
828 0 : nsAutoPtr<nsFrameList> overflowFrames(nextInFlow->StealOverflowFrames());
829 0 : if (overflowFrames) {
830 0 : nextInFlow->mFrames.SetFrames(*overflowFrames);
831 : }
832 : }
833 :
834 0 : mFrames.InsertFrame(this, irs.mPrevFrame, frame);
835 0 : isComplete = false;
836 0 : if (irs.mLineLayout) {
837 0 : irs.mLineLayout->SetDirtyNextLine();
838 : }
839 0 : nsContainerFrame::ReparentFrameView(aPresContext, frame, nextInFlow, this);
840 0 : break;
841 : }
842 0 : nextInFlow = (nsInlineFrame*) nextInFlow->GetNextInFlow();
843 0 : irs.mNextInFlow = nextInFlow;
844 : }
845 :
846 0 : *aIsComplete = isComplete;
847 0 : return frame;
848 : }
849 :
850 : void
851 0 : nsInlineFrame::PushFrames(nsPresContext* aPresContext,
852 : nsIFrame* aFromChild,
853 : nsIFrame* aPrevSibling,
854 : InlineReflowState& aState)
855 : {
856 0 : NS_PRECONDITION(aFromChild, "null pointer");
857 0 : NS_PRECONDITION(aPrevSibling, "pushing first child");
858 0 : NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling");
859 :
860 : #ifdef NOISY_PUSHING
861 : printf("%p pushing aFromChild %p, disconnecting from prev sib %p\n",
862 : this, aFromChild, aPrevSibling);
863 : #endif
864 :
865 : // Add the frames to our overflow list (let our next in flow drain
866 : // our overflow list when it is ready)
867 0 : SetOverflowFrames(aPresContext, mFrames.RemoveFramesAfter(aPrevSibling));
868 0 : if (aState.mLineLayout) {
869 0 : aState.mLineLayout->SetDirtyNextLine();
870 : }
871 0 : }
872 :
873 :
874 : //////////////////////////////////////////////////////////////////////
875 :
876 : PRIntn
877 0 : nsInlineFrame::GetSkipSides() const
878 : {
879 0 : PRIntn skip = 0;
880 0 : if (!IsLeftMost()) {
881 0 : nsInlineFrame* prev = (nsInlineFrame*) GetPrevContinuation();
882 0 : if ((GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) ||
883 : (prev && (prev->mRect.height || prev->mRect.width))) {
884 : // Prev continuation is not empty therefore we don't render our left
885 : // border edge.
886 0 : skip |= 1 << NS_SIDE_LEFT;
887 : }
888 : else {
889 : // If the prev continuation is empty, then go ahead and let our left
890 : // edge border render.
891 : }
892 : }
893 0 : if (!IsRightMost()) {
894 0 : nsInlineFrame* next = (nsInlineFrame*) GetNextContinuation();
895 0 : if ((GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) ||
896 : (next && (next->mRect.height || next->mRect.width))) {
897 : // Next continuation is not empty therefore we don't render our right
898 : // border edge.
899 0 : skip |= 1 << NS_SIDE_RIGHT;
900 : }
901 : else {
902 : // If the next continuation is empty, then go ahead and let our right
903 : // edge border render.
904 : }
905 : }
906 :
907 0 : if (GetStateBits() & NS_FRAME_IS_SPECIAL) {
908 : // All but the last part of an {ib} split should skip the "end" side (as
909 : // determined by this frame's direction) and all but the first part of such
910 : // a split should skip the "start" side. But figuring out which part of
911 : // the split we are involves getting our first continuation, which might be
912 : // expensive. So don't bother if we already have the relevant bits set.
913 0 : bool ltr = (NS_STYLE_DIRECTION_LTR == GetStyleVisibility()->mDirection);
914 0 : PRIntn startBit = (1 << (ltr ? NS_SIDE_LEFT : NS_SIDE_RIGHT));
915 0 : PRIntn endBit = (1 << (ltr ? NS_SIDE_RIGHT : NS_SIDE_LEFT));
916 0 : if (((startBit | endBit) & skip) != (startBit | endBit)) {
917 : // We're missing one of the skip bits, so check whether we need to set it.
918 : // Only get the first continuation once, as an optimization.
919 0 : nsIFrame* firstContinuation = GetFirstContinuation();
920 0 : if (nsLayoutUtils::FrameIsNonLastInIBSplit(firstContinuation)) {
921 0 : skip |= endBit;
922 : }
923 0 : if (nsLayoutUtils::FrameIsNonFirstInIBSplit(firstContinuation)) {
924 0 : skip |= startBit;
925 : }
926 : }
927 : }
928 :
929 0 : return skip;
930 : }
931 :
932 : nscoord
933 0 : nsInlineFrame::GetBaseline() const
934 : {
935 0 : return mBaseline;
936 : }
937 :
938 : void
939 0 : nsInlineFrame::DestroyFrom(nsIFrame* aDestructRoot)
940 : {
941 0 : DestroyAbsoluteFrames(aDestructRoot);
942 0 : nsContainerFrame::DestroyFrom(aDestructRoot);
943 0 : }
944 :
945 : #ifdef ACCESSIBILITY
946 : already_AddRefed<nsAccessible>
947 0 : nsInlineFrame::CreateAccessible()
948 : {
949 : // Broken image accessibles are created here, because layout
950 : // replaces the image or image control frame with an inline frame
951 0 : nsIAtom *tagAtom = mContent->Tag();
952 0 : if ((tagAtom == nsGkAtoms::img || tagAtom == nsGkAtoms::input ||
953 0 : tagAtom == nsGkAtoms::label) && mContent->IsHTML()) {
954 : // Only get accessibility service if we're going to use it
955 :
956 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
957 0 : if (!accService)
958 0 : return nsnull;
959 0 : if (tagAtom == nsGkAtoms::input) // Broken <input type=image ... />
960 : return accService->CreateHTMLButtonAccessible(mContent,
961 0 : PresContext()->PresShell());
962 0 : else if (tagAtom == nsGkAtoms::img) // Create accessible for broken <img>
963 : return accService->CreateHTMLImageAccessible(mContent,
964 0 : PresContext()->PresShell());
965 0 : else if (tagAtom == nsGkAtoms::label) // Creat accessible for <label>
966 : return accService->CreateHTMLLabelAccessible(mContent,
967 0 : PresContext()->PresShell());
968 : }
969 :
970 0 : return nsnull;
971 : }
972 : #endif
973 :
974 : //////////////////////////////////////////////////////////////////////
975 :
976 : // nsLineFrame implementation
977 :
978 : nsIFrame*
979 0 : NS_NewFirstLineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
980 : {
981 0 : return new (aPresShell) nsFirstLineFrame(aContext);
982 : }
983 :
984 0 : NS_IMPL_FRAMEARENA_HELPERS(nsFirstLineFrame)
985 :
986 : #ifdef DEBUG
987 : NS_IMETHODIMP
988 0 : nsFirstLineFrame::GetFrameName(nsAString& aResult) const
989 : {
990 0 : return MakeFrameName(NS_LITERAL_STRING("Line"), aResult);
991 : }
992 : #endif
993 :
994 : nsIAtom*
995 0 : nsFirstLineFrame::GetType() const
996 : {
997 0 : return nsGkAtoms::lineFrame;
998 : }
999 :
1000 : nsIFrame*
1001 0 : nsFirstLineFrame::PullOneFrame(nsPresContext* aPresContext, InlineReflowState& irs,
1002 : bool* aIsComplete)
1003 : {
1004 0 : nsIFrame* frame = nsInlineFrame::PullOneFrame(aPresContext, irs, aIsComplete);
1005 0 : if (frame && !GetPrevInFlow()) {
1006 : // We are a first-line frame. Fixup the child frames
1007 : // style-context that we just pulled.
1008 0 : NS_ASSERTION(frame->GetParent() == this, "Incorrect parent?");
1009 0 : aPresContext->FrameManager()->ReparentStyleContext(frame);
1010 : }
1011 0 : return frame;
1012 : }
1013 :
1014 : NS_IMETHODIMP
1015 0 : nsFirstLineFrame::Reflow(nsPresContext* aPresContext,
1016 : nsHTMLReflowMetrics& aMetrics,
1017 : const nsHTMLReflowState& aReflowState,
1018 : nsReflowStatus& aStatus)
1019 : {
1020 0 : if (nsnull == aReflowState.mLineLayout) {
1021 0 : return NS_ERROR_INVALID_ARG;
1022 : }
1023 :
1024 0 : nsIFrame* lineContainer = aReflowState.mLineLayout->GetLineContainerFrame();
1025 :
1026 : // Check for an overflow list with our prev-in-flow
1027 0 : nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)GetPrevInFlow();
1028 0 : if (nsnull != prevInFlow) {
1029 0 : nsAutoPtr<nsFrameList> prevOverflowFrames(prevInFlow->StealOverflowFrames());
1030 0 : if (prevOverflowFrames) {
1031 : // Assign all floats to our block if necessary
1032 0 : if (lineContainer && lineContainer->GetPrevContinuation()) {
1033 : ReparentFloatsForInlineChild(lineContainer,
1034 : prevOverflowFrames->FirstChild(),
1035 0 : true);
1036 : }
1037 : const nsFrameList::Slice& newFrames =
1038 0 : mFrames.InsertFrames(this, nsnull, *prevOverflowFrames);
1039 0 : ReparentChildListStyle(aPresContext, newFrames, this);
1040 : }
1041 : }
1042 :
1043 : // It's also possible that we have an overflow list for ourselves
1044 0 : nsAutoPtr<nsFrameList> overflowFrames(StealOverflowFrames());
1045 0 : if (overflowFrames) {
1046 0 : NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
1047 :
1048 : const nsFrameList::Slice& newFrames =
1049 0 : mFrames.AppendFrames(nsnull, *overflowFrames);
1050 0 : ReparentChildListStyle(aPresContext, newFrames, this);
1051 : }
1052 :
1053 : // Set our own reflow state (additional state above and beyond
1054 : // aReflowState)
1055 0 : InlineReflowState irs;
1056 0 : irs.mPrevFrame = nsnull;
1057 0 : irs.mLineContainer = lineContainer;
1058 0 : irs.mLineLayout = aReflowState.mLineLayout;
1059 0 : irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow();
1060 :
1061 : nsresult rv;
1062 0 : bool wasEmpty = mFrames.IsEmpty();
1063 0 : if (wasEmpty) {
1064 : // Try to pull over one frame before starting so that we know
1065 : // whether we have an anonymous block or not.
1066 : bool complete;
1067 0 : PullOneFrame(aPresContext, irs, &complete);
1068 : }
1069 :
1070 0 : if (nsnull == GetPrevInFlow()) {
1071 : // XXX This is pretty sick, but what we do here is to pull-up, in
1072 : // advance, all of the next-in-flows children. We re-resolve their
1073 : // style while we are at at it so that when we reflow they have
1074 : // the right style.
1075 : //
1076 : // All of this is so that text-runs reflow properly.
1077 0 : irs.mPrevFrame = mFrames.LastChild();
1078 0 : for (;;) {
1079 : bool complete;
1080 0 : nsIFrame* frame = PullOneFrame(aPresContext, irs, &complete);
1081 0 : if (!frame) {
1082 : break;
1083 : }
1084 0 : irs.mPrevFrame = frame;
1085 : }
1086 0 : irs.mPrevFrame = nsnull;
1087 : }
1088 : else {
1089 : // XXX do this in the Init method instead
1090 : // For continuations, we need to check and see if our style
1091 : // context is right. If its the same as the first-in-flow, then
1092 : // we need to fix it up (that way :first-line style doesn't leak
1093 : // into this continuation since we aren't the first line).
1094 0 : nsFirstLineFrame* first = (nsFirstLineFrame*) GetFirstInFlow();
1095 0 : if (mStyleContext == first->mStyleContext) {
1096 : // Fixup our style context and our children. First get the
1097 : // proper parent context.
1098 0 : nsStyleContext* parentContext = first->GetParent()->GetStyleContext();
1099 0 : if (parentContext) {
1100 : // Create a new style context that is a child of the parent
1101 : // style context thus removing the :first-line style. This way
1102 : // we behave as if an anonymous (unstyled) span was the child
1103 : // of the parent frame.
1104 0 : nsRefPtr<nsStyleContext> newSC;
1105 : newSC = aPresContext->StyleSet()->
1106 0 : ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozLineFrame, parentContext);
1107 0 : if (newSC) {
1108 : // Switch to the new style context.
1109 0 : SetStyleContext(newSC);
1110 :
1111 : // Re-resolve all children
1112 0 : ReparentChildListStyle(aPresContext, mFrames, this);
1113 : }
1114 : }
1115 : }
1116 : }
1117 :
1118 0 : NS_ASSERTION(!aReflowState.mLineLayout->GetInFirstLine(),
1119 : "Nested first-line frames? BOGUS");
1120 0 : aReflowState.mLineLayout->SetInFirstLine(true);
1121 0 : rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus);
1122 0 : aReflowState.mLineLayout->SetInFirstLine(false);
1123 :
1124 0 : ReflowAbsoluteFrames(aPresContext, aMetrics, aReflowState, aStatus);
1125 :
1126 : // Note: the line layout code will properly compute our overflow state for us
1127 :
1128 0 : return rv;
1129 : }
1130 :
1131 : /* virtual */ void
1132 0 : nsFirstLineFrame::PullOverflowsFromPrevInFlow()
1133 : {
1134 0 : nsFirstLineFrame* prevInFlow = static_cast<nsFirstLineFrame*>(GetPrevInFlow());
1135 0 : if (prevInFlow) {
1136 0 : nsAutoPtr<nsFrameList> prevOverflowFrames(prevInFlow->StealOverflowFrames());
1137 0 : if (prevOverflowFrames) {
1138 : // Assume that our prev-in-flow has the same line container that we do.
1139 : const nsFrameList::Slice& newFrames =
1140 0 : mFrames.InsertFrames(this, nsnull, *prevOverflowFrames);
1141 0 : ReparentChildListStyle(PresContext(), newFrames, this);
1142 : }
1143 : }
1144 0 : }
1145 :
|