1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
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
15
* The Original Code is Mozilla Communicator client code.
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.
24
* Alternatively, the contents of this file may be used under the terms of
25
* either the GNU General Public License Version 2 or later (the "GPL"), or
26
* 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 NPL, 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 NPL, the GPL or the LGPL.
36
* ***** END LICENSE BLOCK ***** */
38
#include "nsInlineFrame.h"
39
#include "nsBlockFrame.h"
40
#include "nsHTMLAtoms.h"
41
#include "nsHTMLParts.h"
42
#include "nsStyleContext.h"
43
#include "nsIPresShell.h"
44
#include "nsIPresContext.h"
45
#include "nsIRenderingContext.h"
46
#include "nsIFontMetrics.h"
47
#include "nsAbsoluteContainingBlock.h"
48
#include "nsLayoutAtoms.h"
49
#include "nsCSSAnonBoxes.h"
50
#include "nsReflowPath.h"
51
#include "nsAutoPtr.h"
52
#include "nsFrameManager.h"
54
#include "nsIServiceManager.h"
55
#include "nsIAccessibilityService.h"
63
NS_DEFINE_IID(kInlineFrameCID, NS_INLINE_FRAME_CID);
66
//////////////////////////////////////////////////////////////////////
68
// Basic nsInlineFrame methods
71
NS_NewInlineFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
73
NS_PRECONDITION(aNewFrame, "null OUT ptr");
74
if (nsnull == aNewFrame) {
75
return NS_ERROR_NULL_POINTER;
77
nsInlineFrame* it = new (aPresShell) nsInlineFrame;
79
return NS_ERROR_OUT_OF_MEMORY;
85
nsInlineFrame::nsInlineFrame()
90
nsInlineFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
92
if (nsnull == aInstancePtr) {
93
return NS_ERROR_NULL_POINTER;
95
if (aIID.Equals(kInlineFrameCID)) {
96
nsInlineFrame* tmp = this;
97
*aInstancePtr = (void*) tmp;
100
return nsInlineFrameSuper::QueryInterface(aIID, aInstancePtr);
105
nsInlineFrame::GetFrameName(nsAString& aResult) const
107
return MakeFrameName(NS_LITERAL_STRING("Inline"), aResult);
112
nsInlineFrame::GetType() const
114
return nsLayoutAtoms::inlineFrame;
118
IsBorderZero(nsStyleUnit aUnit, nsStyleCoord &aCoord)
120
return ((aUnit == eStyleUnit_Coord && aCoord.GetCoordValue() == 0));
124
IsPaddingZero(nsStyleUnit aUnit, nsStyleCoord &aCoord)
126
return (aUnit == eStyleUnit_Null ||
127
(aUnit == eStyleUnit_Coord && aCoord.GetCoordValue() == 0) ||
128
(aUnit == eStyleUnit_Percent && aCoord.GetPercentValue() == 0.0));
132
IsMarginZero(nsStyleUnit aUnit, nsStyleCoord &aCoord)
134
return (aUnit == eStyleUnit_Null ||
135
aUnit == eStyleUnit_Auto ||
136
(aUnit == eStyleUnit_Coord && aCoord.GetCoordValue() == 0) ||
137
(aUnit == eStyleUnit_Percent && aCoord.GetPercentValue() == 0.0));
141
nsInlineFrame::IsEmpty()
144
// I used to think inline frames worked this way, but it seems they
145
// don't. At least not in our codebase.
146
if (GetPresContext()->CompatibilityMode() == eCompatibility_FullStandards) {
150
const nsStyleMargin* margin = GetStyleMargin();
151
const nsStyleBorder* border = GetStyleBorder();
152
const nsStylePadding* padding = GetStylePadding();
154
// XXX Top and bottom removed, since they shouldn't affect things, but this
155
// doesn't really match with nsLineLayout.cpp's setting of
156
// ZeroEffectiveSpanBox, anymore, so what should this really be?
157
if ((border->IsBorderSideVisible(NS_SIDE_RIGHT) &&
158
!IsBorderZero(border->mBorder.GetRightUnit(),
159
border->mBorder.GetRight(coord))) ||
160
(border->IsBorderSideVisible(NS_SIDE_LEFT) &&
161
!IsBorderZero(border->mBorder.GetLeftUnit(),
162
border->mBorder.GetLeft(coord))) ||
163
!IsPaddingZero(padding->mPadding.GetRightUnit(),
164
padding->mPadding.GetRight(coord)) ||
165
!IsPaddingZero(padding->mPadding.GetLeftUnit(),
166
padding->mPadding.GetLeft(coord)) ||
167
!IsMarginZero(margin->mMargin.GetRightUnit(),
168
margin->mMargin.GetRight(coord)) ||
169
!IsMarginZero(margin->mMargin.GetLeftUnit(),
170
margin->mMargin.GetLeft(coord))) {
174
for (nsIFrame *kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) {
182
nsInlineFrame::AppendFrames(nsIPresContext* aPresContext,
183
nsIPresShell& aPresShell,
185
nsIFrame* aFrameList)
187
if (nsnull != aListName) {
188
return NS_ERROR_INVALID_ARG;
191
mFrames.AppendFrames(this, aFrameList);
193
// Ask the parent frame to reflow me.
194
ReflowDirtyChild(&aPresShell, nsnull);
200
nsInlineFrame::InsertFrames(nsIPresContext* aPresContext,
201
nsIPresShell& aPresShell,
203
nsIFrame* aPrevFrame,
204
nsIFrame* aFrameList)
206
if (nsnull != aListName) {
208
if (aListName != nsLayoutAtoms::nextBidi)
210
return NS_ERROR_INVALID_ARG;
213
// Insert frames after aPrevFrame
214
mFrames.InsertFrames(this, aPrevFrame, aFrameList);
217
if (nsnull == aListName)
219
// Ask the parent frame to reflow me.
220
ReflowDirtyChild(&aPresShell, nsnull);
226
nsInlineFrame::RemoveFrame(nsIPresContext* aPresContext,
227
nsIPresShell& aPresShell,
231
if (nsnull != aListName) {
233
if (nsLayoutAtoms::nextBidi != aListName)
235
return NS_ERROR_INVALID_ARG;
239
// Loop and destroy the frame and all of its continuations.
240
// If the frame we are removing is a brFrame, we need a reflow so
241
// the line the brFrame was on can attempt to pull up any frames
242
// that can fit from lines below it.
243
PRBool generateReflowCommand =
244
aOldFrame->GetType() == nsLayoutAtoms::brFrame;
246
nsInlineFrame* parent = NS_STATIC_CAST(nsInlineFrame*, aOldFrame->GetParent());
249
if (nsLayoutAtoms::nextBidi != aListName) {
251
// If the frame being removed has zero size then don't bother
252
// generating a reflow command, otherwise make sure we do.
253
nsRect bbox = aOldFrame->GetRect();
254
if (bbox.width || bbox.height) {
255
generateReflowCommand = PR_TRUE;
261
// When the parent is an inline frame we have a simple task - just
262
// remove the frame from its parents list and generate a reflow
264
nsIFrame* oldFrameNextInFlow;
265
aOldFrame->GetNextInFlow(&oldFrameNextInFlow);
266
parent->mFrames.DestroyFrame(aPresContext, aOldFrame);
267
aOldFrame = oldFrameNextInFlow;
269
parent = NS_STATIC_CAST(nsInlineFrame*, aOldFrame->GetParent());
273
if (generateReflowCommand) {
274
// Ask the parent frame to reflow me.
275
ReflowDirtyChild(&aPresShell, nsnull);
283
nsInlineFrame::ReplaceFrame(nsIPresContext* aPresContext,
284
nsIPresShell& aPresShell,
290
NS_ERROR("Don't have any special lists on inline frames!");
291
return NS_ERROR_INVALID_ARG;
293
if (!aOldFrame || !aNewFrame) {
294
NS_ERROR("Missing aOldFrame or aNewFrame");
295
return NS_ERROR_INVALID_ARG;
299
mFrames.ReplaceFrame(aPresContext, this, aOldFrame, aNewFrame, PR_TRUE);
301
// Ask the parent frame to reflow me.
302
ReflowDirtyChild(&aPresShell, nsnull);
304
return retval ? NS_OK : NS_ERROR_FAILURE;
309
nsInlineFrame::Paint(nsIPresContext* aPresContext,
310
nsIRenderingContext& aRenderingContext,
311
const nsRect& aDirtyRect,
312
nsFramePaintLayer aWhichLayer,
315
if (NS_FRAME_IS_UNFLOWABLE & mState) {
319
// Paint inline element backgrounds in the foreground layer (bug 36710).
320
if (aWhichLayer == NS_FRAME_PAINT_LAYER_FOREGROUND) {
321
PaintSelf(aPresContext, aRenderingContext, aDirtyRect);
324
// The sole purpose of this is to trigger display of the selection
325
// window for Named Anchors, which don't have any children and
326
// normally don't have any size, but in Editor we use CSS to display
327
// an image to represent this "hidden" element.
328
if (!mFrames.FirstChild()) {
329
nsFrame::Paint(aPresContext, aRenderingContext, aDirtyRect,
330
aWhichLayer, aFlags);
333
PaintDecorationsAndChildren(aPresContext, aRenderingContext,
334
aDirtyRect, aWhichLayer, PR_FALSE,
339
//////////////////////////////////////////////////////////////////////
343
nsInlineFrame::Reflow(nsIPresContext* aPresContext,
344
nsHTMLReflowMetrics& aMetrics,
345
const nsHTMLReflowState& aReflowState,
346
nsReflowStatus& aStatus)
348
DO_GLOBAL_REFLOW_COUNT("nsInlineFrame", aReflowState.reason);
349
DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
350
if (nsnull == aReflowState.mLineLayout) {
351
return NS_ERROR_INVALID_ARG;
354
PRBool lazilySetParentPointer = PR_FALSE;
356
// Check for an overflow list with our prev-in-flow
357
nsInlineFrame* prevInFlow = (nsInlineFrame*)mPrevInFlow;
358
if (nsnull != prevInFlow) {
359
nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext, PR_TRUE);
361
if (prevOverflowFrames) {
362
// When pushing and pulling frames we need to check for whether any
363
// views need to be reparented.
364
nsHTMLContainerFrame::ReparentFrameViewList(aPresContext, prevOverflowFrames,
367
if (aReflowState.reason == eReflowReason_Initial) {
368
// If it's the initial reflow, then our child list must be empty, so
369
// just set the child list rather than calling InsertFrame(). This avoids
370
// having to get the last child frame in the list.
371
// Note that we don't set the parent pointer for the new frames. Instead wait
372
// to do this until we actually reflow the frame. If the overflow list contains
373
// thousands of frames this is a big performance issue (see bug #5588)
374
NS_ASSERTION(mFrames.IsEmpty(), "child list is not empty for initial reflow");
375
mFrames.SetFrames(prevOverflowFrames);
376
lazilySetParentPointer = PR_TRUE;
379
// Insert the new frames at the beginning of the child list
380
// and set their parent pointer
381
mFrames.InsertFrames(this, nsnull, prevOverflowFrames);
386
// It's also possible that we have an overflow list for ourselves
388
if (aReflowState.reason == eReflowReason_Initial) {
389
// If it's our initial reflow, then we should not have an overflow list.
390
// However, add an assertion in case we get reflowed more than once with
391
// the initial reflow reason
392
nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_FALSE);
393
NS_ASSERTION(!overflowFrames, "overflow list is not empty for initial reflow");
396
if (aReflowState.reason != eReflowReason_Initial) {
397
nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE);
398
if (overflowFrames) {
399
NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
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. Check the first frame to see, and
404
// if we haven't set the parent pointer then set it now
405
mFrames.AppendFrames(overflowFrames->GetParent() == this ? nsnull : this, overflowFrames);
409
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
412
extern char* nsPresShell_ReflowStackPointerTop;
414
char* newsp = (char*) ▮
415
printf("XXX: frame tree is too deep; approx stack size = %d\n",
416
nsPresShell_ReflowStackPointerTop - newsp);
419
aStatus = NS_FRAME_COMPLETE;
423
// Set our own reflow state (additional state above and beyond
425
InlineReflowState irs;
426
irs.mPrevFrame = nsnull;
427
irs.mNextInFlow = (nsInlineFrame*) mNextInFlow;
428
irs.mSetParentPointer = lazilySetParentPointer;
431
if (mFrames.IsEmpty()) {
432
// Try to pull over one frame before starting so that we know
433
// whether we have an anonymous block or not.
435
(void) PullOneFrame(aPresContext, irs, &complete);
438
rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus);
440
// Note: the line layout code will properly compute our
441
// NS_FRAME_OUTSIDE_CHILDREN state for us.
443
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
448
nsInlineFrame::CanContinueTextRun(PRBool& aContinueTextRun) const
450
// We can continue a text run through an inline frame
451
aContinueTextRun = PR_TRUE;
456
nsInlineFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild)
458
// The inline container frame does not handle the reflow
459
// request. It passes it up to its parent container.
461
// If you don't already have dirty children,
462
if (!(mState & NS_FRAME_HAS_DIRTY_CHILDREN)) {
464
// Record that you are dirty and have dirty children
465
mState |= NS_FRAME_IS_DIRTY;
466
mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
468
// Pass the reflow request up to the parent
469
mParent->ReflowDirtyChild(aPresShell, this);
472
NS_ERROR("No parent to pass the reflow request up to.");
480
nsInlineFrame::ReflowFrames(nsIPresContext* aPresContext,
481
const nsHTMLReflowState& aReflowState,
482
InlineReflowState& irs,
483
nsHTMLReflowMetrics& aMetrics,
484
nsReflowStatus& aStatus)
487
aStatus = NS_FRAME_COMPLETE;
489
nsLineLayout* lineLayout = aReflowState.mLineLayout;
490
nscoord leftEdge = 0;
491
if (nsnull == mPrevInFlow) {
492
leftEdge = aReflowState.mComputedBorderPadding.left;
494
nscoord availableWidth = aReflowState.availableWidth;
495
if (NS_UNCONSTRAINEDSIZE != availableWidth) {
496
// Subtract off left and right border+padding from availableWidth
497
availableWidth -= leftEdge;
498
availableWidth -= aReflowState.mComputedBorderPadding.right;
499
availableWidth = PR_MAX(0, availableWidth);
501
lineLayout->BeginSpan(this, &aReflowState, leftEdge, leftEdge + availableWidth);
503
// First reflow our current children
504
nsIFrame* frame = mFrames.FirstChild();
505
PRBool done = PR_FALSE;
506
while (nsnull != frame) {
507
PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
509
// Check if we should lazily set the child frame's parent pointer
510
if (irs.mSetParentPointer) {
511
frame->SetParent(this);
513
// We also need to check if frame has a next-in-flow. It it does, then set
514
// its parent frame pointer, too. Otherwise, if we reflow frame and it's
515
// complete we'll fail when deleting its next-in-flow which is no longer
516
// needed. This scenario doesn't happen often, but it can happen
517
nsIFrame* nextInFlow;
518
frame->GetNextInFlow(&nextInFlow);
520
// Since we only do lazy setting of parent pointers for the frame's
521
// initial reflow, this frame can't have a next-in-flow. That means
522
// the continuing child frame must be in our child list as well. If
523
// not, then something is wrong
524
NS_ASSERTION(mFrames.ContainsFrame(nextInFlow), "unexpected flow");
525
nextInFlow->SetParent(this);
526
nextInFlow->GetNextInFlow(&nextInFlow);
529
rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
534
if (NS_INLINE_IS_BREAK(aStatus) ||
535
(!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) {
539
irs.mPrevFrame = frame;
540
frame = frame->GetNextSibling();
543
// Attempt to pull frames from our next-in-flow until we can't
544
if (!done && (nsnull != mNextInFlow)) {
546
PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
548
frame = PullOneFrame(aPresContext, irs, &isComplete);
550
printf("%p pulled up %p\n", this, frame);
552
if (nsnull == frame) {
554
aStatus = NS_FRAME_NOT_COMPLETE;
558
rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
563
if (NS_INLINE_IS_BREAK(aStatus) ||
564
(!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) {
568
irs.mPrevFrame = frame;
572
if (NS_FRAME_IS_COMPLETE(aStatus)) {
573
// We can't be complete AND have overflow frames!
574
nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_FALSE);
575
NS_ASSERTION(!overflowFrames, "whoops");
579
// If after reflowing our children they take up no area then make
580
// sure that we don't either.
582
// Note: CSS demands that empty inline elements still affect the
583
// line-height calculations. However, continuations of an inline
584
// that are empty we force to empty so that things like collapsed
585
// whitespace in an inline element don't affect the line-height.
587
lineLayout->EndSpan(this, size,
588
aMetrics.mComputeMEW ? &aMetrics.mMaxElementWidth : nsnull);
589
if ((0 == size.height) && (0 == size.width) &&
590
((nsnull != mPrevInFlow) || (nsnull != mNextInFlow))) {
591
// This is a continuation of a previous inline. Therefore make
592
// sure we don't affect the line-height.
596
aMetrics.descent = 0;
597
if (aMetrics.mComputeMEW) {
598
aMetrics.mMaxElementWidth = 0;
602
// Compute final width
603
aMetrics.width = size.width;
604
if (nsnull == mPrevInFlow) {
605
aMetrics.width += aReflowState.mComputedBorderPadding.left;
607
if (NS_FRAME_IS_COMPLETE(aStatus)) {
608
aMetrics.width += aReflowState.mComputedBorderPadding.right;
611
SetFontFromStyle(aReflowState.rendContext, mStyleContext);
612
nsCOMPtr<nsIFontMetrics> fm;
613
aReflowState.rendContext->GetFontMetrics(*getter_AddRefs(fm));
616
// Compute final height of the frame.
618
// Do things the standard css2 way -- though it's hard to find it
619
// in the css2 spec! It's actually found in the css1 spec section
620
// 4.4 (you will have to read between the lines to really see
623
// The height of our box is the sum of our font size plus the top
624
// and bottom border and padding. The height of children do not
625
// affect our height.
626
fm->GetMaxAscent(aMetrics.ascent);
627
fm->GetMaxDescent(aMetrics.descent);
628
fm->GetHeight(aMetrics.height);
630
NS_WARNING("Cannot get font metrics - defaulting sizes to 0");
631
aMetrics.ascent = aMetrics.descent = aMetrics.height = 0;
633
aMetrics.ascent += aReflowState.mComputedBorderPadding.top;
634
aMetrics.descent += aReflowState.mComputedBorderPadding.bottom;
635
aMetrics.height += aReflowState.mComputedBorderPadding.top +
636
aReflowState.mComputedBorderPadding.bottom;
638
// Note: we normally use the actual font height for computing the
639
// line-height raw value from the style context. On systems where
640
// they disagree the actual font height is more appropriate. This
641
// little hack lets us override that behavior to allow for more
642
// precise layout in the face of imprecise fonts.
643
if (nsHTMLReflowState::UseComputedHeight()) {
644
const nsStyleFont* font = GetStyleFont();
645
aMetrics.height = font->mFont.size +
646
aReflowState.mComputedBorderPadding.top +
647
aReflowState.mComputedBorderPadding.bottom;
651
// For now our overflow area is zero. The real value will be
652
// computed during vertical alignment of the line we are on.
653
aMetrics.mOverflowArea.x = 0;
654
aMetrics.mOverflowArea.y = 0;
655
aMetrics.mOverflowArea.width = aMetrics.width;
656
aMetrics.mOverflowArea.height = aMetrics.height;
658
#ifdef NOISY_FINAL_SIZE
660
printf(": metrics=%d,%d ascent=%d descent=%d\n",
661
aMetrics.width, aMetrics.height, aMetrics.ascent, aMetrics.descent);
662
if (aMetrics.mComputeMEW) {
663
printf(" maxElementWidth %d\n", aMetrics.mMaxElementWidth);
671
void SetContainsPercentAwareChild(nsIFrame *aFrame)
673
aFrame->AddStateBits(NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD);
677
void MarkPercentAwareFrame(nsIPresContext *aPresContext,
678
nsInlineFrame *aInline,
681
if (aFrame->GetStateBits() & NS_FRAME_REPLACED_ELEMENT)
682
{ // aFrame is a replaced element, check it's style
683
if (nsLineLayout::IsPercentageAwareReplacedElement(aPresContext, aFrame)) {
684
SetContainsPercentAwareChild(aInline);
689
if (aFrame->GetFirstChild(nsnull))
690
{ // aFrame is an inline container frame, check my frame state
691
if (aFrame->GetStateBits() & NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD) {
692
SetContainsPercentAwareChild(aInline); // if a child container is effected, so am I
695
// else frame is a leaf that we don't care about
700
nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext,
701
const nsHTMLReflowState& aReflowState,
702
InlineReflowState& irs,
704
nsReflowStatus& aStatus)
706
nsLineLayout* lineLayout = aReflowState.mLineLayout;
707
PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
709
nsresult rv = lineLayout->ReflowFrame(aFrame, aStatus, nsnull, pushedFrame);
710
/* This next block is for bug 28811
711
Test the child frame for %-awareness,
712
and mark this frame with a bit if it is %-aware.
713
Don't bother if this frame is already marked
715
if (!(mState & NS_INLINE_FRAME_CONTAINS_PERCENT_AWARE_CHILD)) {
716
MarkPercentAwareFrame(aPresContext, this, aFrame);
722
if (NS_INLINE_IS_BREAK(aStatus)) {
723
if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) {
724
if (aFrame != mFrames.FirstChild()) {
725
// Change break-before status into break-after since we have
726
// already placed at least one child frame. This preserves the
727
// break-type so that it can be propagated upward.
728
aStatus = NS_FRAME_NOT_COMPLETE |
729
NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER |
730
(aStatus & NS_INLINE_BREAK_TYPE_MASK);
731
PushFrames(aPresContext, aFrame, irs.mPrevFrame);
734
// Preserve reflow status when breaking-before our first child
735
// and propagate it upward without modification.
736
// Note: if we're lazily setting the frame pointer for our child
737
// frames, then we need to set it now. Don't return and leave the
738
// remaining child frames in our child list with the wrong parent
740
if (irs.mSetParentPointer) {
741
for (nsIFrame* f = aFrame->GetNextSibling(); f; f = f->GetNextSibling()) {
749
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
751
rv = CreateNextInFlow(aPresContext, this, aFrame, newFrame);
756
nsIFrame* nextFrame = aFrame->GetNextSibling();
758
aStatus |= NS_FRAME_NOT_COMPLETE;
759
PushFrames(aPresContext, nextFrame, aFrame);
761
else if (nsnull != mNextInFlow) {
762
// We must return an incomplete status if there are more child
763
// frames remaining in a next-in-flow that follows this frame.
764
nsInlineFrame* nextInFlow = (nsInlineFrame*) mNextInFlow;
765
while (nsnull != nextInFlow) {
766
if (nextInFlow->mFrames.NotEmpty()) {
767
aStatus |= NS_FRAME_NOT_COMPLETE;
770
nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow;
775
else if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
776
if (nsLayoutAtoms::placeholderFrame == aFrame->GetType()) {
777
nsBlockReflowState* blockRS = lineLayout->mBlockRS;
778
blockRS->mBlock->SplitPlaceholder(*aPresContext, *aFrame);
782
rv = CreateNextInFlow(aPresContext, this, aFrame, newFrame);
786
if (!reflowingFirstLetter) {
787
nsIFrame* nextFrame = aFrame->GetNextSibling();
789
PushFrames(aPresContext, nextFrame, aFrame);
798
nsInlineFrame::PullOneFrame(nsIPresContext* aPresContext,
799
InlineReflowState& irs,
802
PRBool isComplete = PR_TRUE;
804
nsIFrame* frame = nsnull;
805
nsInlineFrame* nextInFlow = irs.mNextInFlow;
806
while (nsnull != nextInFlow) {
807
frame = mFrames.PullFrame(this, irs.mPrevFrame, nextInFlow->mFrames);
808
if (nsnull != frame) {
809
isComplete = PR_FALSE;
810
nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, nextInFlow, this);
813
nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow;
814
irs.mNextInFlow = nextInFlow;
817
*aIsComplete = isComplete;
822
nsInlineFrame::PushFrames(nsIPresContext* aPresContext,
823
nsIFrame* aFromChild,
824
nsIFrame* aPrevSibling)
826
NS_PRECONDITION(nsnull != aFromChild, "null pointer");
827
NS_PRECONDITION(nsnull != aPrevSibling, "pushing first child");
828
NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling");
831
printf("%p pushing aFromChild %p, disconnecting from prev sib %p\n",
832
this, aFromChild, aPrevSibling);
834
// Disconnect aFromChild from its previous sibling
835
aPrevSibling->SetNextSibling(nsnull);
837
// Add the frames to our overflow list (let our next in flow drain
838
// our overflow list when it is ready)
839
SetOverflowFrames(aPresContext, aFromChild);
843
//////////////////////////////////////////////////////////////////////
846
nsInlineFrame::GetSkipSides() const
849
if (nsnull != mPrevInFlow) {
850
nsInlineFrame* prev = (nsInlineFrame*) mPrevInFlow;
851
if (prev->mRect.height || prev->mRect.width) {
852
// Prev-in-flow is not empty therefore we don't render our left
854
skip |= 1 << NS_SIDE_LEFT;
857
// If the prev-in-flow is empty, then go ahead and let our left
858
// edge border render.
861
if (nsnull != mNextInFlow) {
862
nsInlineFrame* next = (nsInlineFrame*) mNextInFlow;
863
if (next->mRect.height || next->mRect.width) {
864
// Next-in-flow is not empty therefore we don't render our right
866
skip |= 1 << NS_SIDE_RIGHT;
869
// If the next-in-flow is empty, then go ahead and let our right
870
// edge border render.
877
NS_IMETHODIMP nsInlineFrame::GetAccessible(nsIAccessible** aAccessible)
879
// Broken image accessibles are created here, because layout
880
// replaces the image or image control frame with an inline frame
881
*aAccessible = nsnull;
882
nsIAtom *tagAtom = mContent->Tag();
883
if ((tagAtom == nsHTMLAtoms::img || tagAtom == nsHTMLAtoms::input ||
884
tagAtom == nsHTMLAtoms::label || tagAtom == nsHTMLAtoms::hr) &&
885
mContent->IsContentOfType(nsIContent::eHTML)) {
886
// Only get accessibility service if we're going to use it
887
nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
889
return NS_ERROR_FAILURE;
890
if (tagAtom == nsHTMLAtoms::input) // Broken <input type=image ... />
891
return accService->CreateHTML4ButtonAccessible(NS_STATIC_CAST(nsIFrame*, this), aAccessible);
892
else if (tagAtom == nsHTMLAtoms::img) // Create accessible for broken <img>
893
return accService->CreateHTMLImageAccessible(NS_STATIC_CAST(nsIFrame*, this), aAccessible);
894
else if (tagAtom == nsHTMLAtoms::label) // Creat accessible for <label>
895
return accService->CreateHTMLLabelAccessible(NS_STATIC_CAST(nsIFrame*, this), aAccessible);
896
// Create accessible for <hr>
897
return accService->CreateHTMLHRAccessible(NS_STATIC_CAST(nsIFrame*, this), aAccessible);
900
return NS_ERROR_FAILURE;
904
//////////////////////////////////////////////////////////////////////
906
// nsLineFrame implementation
909
ReParentChildListStyle(nsIPresContext* aPresContext,
910
nsStyleContext* aParentStyleContext,
911
nsFrameList& aFrameList)
913
nsFrameManager *frameManager = aPresContext->FrameManager();
915
for (nsIFrame* kid = aFrameList.FirstChild(); kid;
916
kid = kid->GetNextSibling()) {
917
frameManager->ReParentStyleContext(kid, aParentStyleContext);
922
NS_NewFirstLineFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
924
NS_PRECONDITION(nsnull != aNewFrame, "null ptr");
925
if (nsnull == aNewFrame) {
926
return NS_ERROR_NULL_POINTER;
928
nsInlineFrame* it = new (aPresShell) nsFirstLineFrame;
930
return NS_ERROR_OUT_OF_MEMORY;
936
nsFirstLineFrame::nsFirstLineFrame()
942
nsFirstLineFrame::GetFrameName(nsAString& aResult) const
944
return MakeFrameName(NS_LITERAL_STRING("Line"), aResult);
949
nsFirstLineFrame::GetType() const
951
return nsLayoutAtoms::lineFrame;
955
nsFirstLineFrame::StealFramesFrom(nsIFrame* aFrame)
957
nsIFrame* prevFrame = mFrames.GetPrevSiblingFor(aFrame);
959
prevFrame->SetNextSibling(nsnull);
962
mFrames.SetFrames(nsnull);
967
nsFirstLineFrame::PullOneFrame(nsIPresContext* aPresContext, InlineReflowState& irs, PRBool* aIsComplete)
969
nsIFrame* frame = nsInlineFrame::PullOneFrame(aPresContext, irs, aIsComplete);
970
if (frame && !mPrevInFlow) {
971
// We are a first-line frame. Fixup the child frames
972
// style-context that we just pulled.
973
aPresContext->FrameManager()->ReParentStyleContext(frame, mStyleContext);
979
nsFirstLineFrame::Reflow(nsIPresContext* aPresContext,
980
nsHTMLReflowMetrics& aMetrics,
981
const nsHTMLReflowState& aReflowState,
982
nsReflowStatus& aStatus)
984
if (nsnull == aReflowState.mLineLayout) {
985
return NS_ERROR_INVALID_ARG;
988
// Check for an overflow list with our prev-in-flow
989
nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)mPrevInFlow;
990
if (nsnull != prevInFlow) {
991
nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext, PR_TRUE);
992
if (prevOverflowFrames) {
993
nsFrameList frames(prevOverflowFrames);
995
mFrames.InsertFrames(this, nsnull, prevOverflowFrames);
996
ReParentChildListStyle(aPresContext, mStyleContext, frames);
1000
// It's also possible that we have an overflow list for ourselves
1001
nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE);
1002
if (overflowFrames) {
1003
NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
1004
nsFrameList frames(overflowFrames);
1006
mFrames.AppendFrames(nsnull, overflowFrames);
1007
ReParentChildListStyle(aPresContext, mStyleContext, frames);
1010
// Set our own reflow state (additional state above and beyond
1012
InlineReflowState irs;
1013
irs.mPrevFrame = nsnull;
1014
irs.mNextInFlow = (nsInlineFrame*) mNextInFlow;
1017
PRBool wasEmpty = mFrames.IsEmpty();
1019
// Try to pull over one frame before starting so that we know
1020
// whether we have an anonymous block or not.
1022
PullOneFrame(aPresContext, irs, &complete);
1025
if (nsnull == mPrevInFlow) {
1026
// XXX This is pretty sick, but what we do here is to pull-up, in
1027
// advance, all of the next-in-flows children. We re-resolve their
1028
// style while we are at at it so that when we reflow they have
1031
// All of this is so that text-runs reflow properly.
1032
irs.mPrevFrame = mFrames.LastChild();
1035
nsIFrame* frame = PullOneFrame(aPresContext, irs, &complete);
1039
irs.mPrevFrame = frame;
1041
irs.mPrevFrame = nsnull;
1044
// XXX do this in the Init method instead
1045
// For continuations, we need to check and see if our style
1046
// context is right. If its the same as the first-in-flow, then
1047
// we need to fix it up (that way :first-line style doesn't leak
1048
// into this continuation since we aren't the first line).
1049
nsFirstLineFrame* first = (nsFirstLineFrame*) GetFirstInFlow();
1050
if (mStyleContext == first->mStyleContext) {
1051
// Fixup our style context and our children. First get the
1052
// proper parent context.
1053
nsStyleContext* parentContext = first->GetParent()->GetStyleContext();
1054
if (parentContext) {
1055
// Create a new style context that is a child of the parent
1056
// style context thus removing the :first-line style. This way
1057
// we behave as if an anonymous (unstyled) span was the child
1058
// of the parent frame.
1059
nsRefPtr<nsStyleContext> newSC;
1060
newSC = aPresContext->StyleSet()->
1061
ResolvePseudoStyleFor(nsnull,
1062
nsCSSAnonBoxes::mozLineFrame, parentContext);
1064
// Switch to the new style context.
1065
SetStyleContext(aPresContext, newSC);
1067
// Re-resolve all children
1068
ReParentChildListStyle(aPresContext, mStyleContext, mFrames);
1074
rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus);
1076
// Note: the line layout code will properly compute our
1077
// NS_FRAME_OUTSIDE_CHILDREN state for us.
1082
//////////////////////////////////////////////////////////////////////
1085
NS_NewPositionedInlineFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
1087
NS_PRECONDITION(aNewFrame, "null OUT ptr");
1088
if (nsnull == aNewFrame) {
1089
return NS_ERROR_NULL_POINTER;
1091
nsPositionedInlineFrame* it = new (aPresShell) nsPositionedInlineFrame();
1093
return NS_ERROR_OUT_OF_MEMORY;
1100
nsPositionedInlineFrame::Destroy(nsIPresContext* aPresContext)
1102
mAbsoluteContainer.DestroyFrames(this, aPresContext);
1103
return nsInlineFrame::Destroy(aPresContext);
1107
nsPositionedInlineFrame::SetInitialChildList(nsIPresContext* aPresContext,
1109
nsIFrame* aChildList)
1113
if (mAbsoluteContainer.GetChildListName() == aListName) {
1114
rv = mAbsoluteContainer.SetInitialChildList(this, aPresContext, aListName, aChildList);
1116
rv = nsInlineFrame::SetInitialChildList(aPresContext, aListName, aChildList);
1123
nsPositionedInlineFrame::AppendFrames(nsIPresContext* aPresContext,
1124
nsIPresShell& aPresShell,
1126
nsIFrame* aFrameList)
1130
if (mAbsoluteContainer.GetChildListName() == aListName) {
1131
rv = mAbsoluteContainer.AppendFrames(this, aPresContext, aPresShell, aListName,
1134
rv = nsInlineFrame::AppendFrames(aPresContext, aPresShell, aListName,
1142
nsPositionedInlineFrame::InsertFrames(nsIPresContext* aPresContext,
1143
nsIPresShell& aPresShell,
1145
nsIFrame* aPrevFrame,
1146
nsIFrame* aFrameList)
1150
if (mAbsoluteContainer.GetChildListName() == aListName) {
1151
rv = mAbsoluteContainer.InsertFrames(this, aPresContext, aPresShell, aListName,
1152
aPrevFrame, aFrameList);
1154
rv = nsInlineFrame::InsertFrames(aPresContext, aPresShell, aListName, aPrevFrame,
1162
nsPositionedInlineFrame::RemoveFrame(nsIPresContext* aPresContext,
1163
nsIPresShell& aPresShell,
1165
nsIFrame* aOldFrame)
1169
if (mAbsoluteContainer.GetChildListName() == aListName) {
1170
rv = mAbsoluteContainer.RemoveFrame(this, aPresContext, aPresShell, aListName, aOldFrame);
1172
rv = nsInlineFrame::RemoveFrame(aPresContext, aPresShell, aListName, aOldFrame);
1179
nsPositionedInlineFrame::ReplaceFrame(nsIPresContext* aPresContext,
1180
nsIPresShell& aPresShell,
1182
nsIFrame* aOldFrame,
1183
nsIFrame* aNewFrame)
1185
if (mAbsoluteContainer.GetChildListName() == aListName) {
1186
return mAbsoluteContainer.ReplaceFrame(this, aPresContext, aPresShell,
1187
aListName, aOldFrame, aNewFrame);
1189
return nsInlineFrame::ReplaceFrame(aPresContext, aPresShell, aListName,
1190
aOldFrame, aNewFrame);
1195
nsPositionedInlineFrame::GetAdditionalChildListName(PRInt32 aIndex) const
1198
return mAbsoluteContainer.GetChildListName();
1204
nsPositionedInlineFrame::GetFirstChild(nsIAtom* aListName) const
1206
if (mAbsoluteContainer.GetChildListName() == aListName) {
1207
nsIFrame* result = nsnull;
1208
mAbsoluteContainer.FirstChild(this, aListName, &result);
1212
return nsInlineFrame::GetFirstChild(aListName);
1216
nsPositionedInlineFrame::GetType() const
1218
return nsLayoutAtoms::positionedInlineFrame;
1222
nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext,
1223
nsHTMLReflowMetrics& aDesiredSize,
1224
const nsHTMLReflowState& aReflowState,
1225
nsReflowStatus& aStatus)
1227
nsresult rv = NS_OK;
1229
nsRect oldRect(mRect);
1231
// See if it's an incremental reflow command
1232
if (mAbsoluteContainer.HasAbsoluteFrames() &&
1233
eReflowReason_Incremental == aReflowState.reason) {
1234
// Give the absolute positioning code a chance to handle it
1236
nscoord containingBlockWidth = -1;
1237
nscoord containingBlockHeight = -1;
1239
mAbsoluteContainer.IncrementalReflow(this, aPresContext, aReflowState,
1240
containingBlockWidth, containingBlockHeight,
1243
// If the incremental reflow command was handled by the absolute positioning
1244
// code, then we're all done
1246
// Just return our current size as our desired size
1247
// XXX I don't know how to compute that without a reflow, so for the
1248
// time being pretend a resize reflow occured
1249
nsHTMLReflowState reflowState(aReflowState);
1250
reflowState.reason = eReflowReason_Resize;
1251
reflowState.path = nsnull;
1252
rv = nsInlineFrame::Reflow(aPresContext, aDesiredSize, reflowState, aStatus);
1254
// Factor the absolutely positioned child bounds into the overflow area
1256
mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds);
1257
aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, childBounds);
1259
// Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly
1260
if ((aDesiredSize.mOverflowArea.x < 0) ||
1261
(aDesiredSize.mOverflowArea.y < 0) ||
1262
(aDesiredSize.mOverflowArea.XMost() > aDesiredSize.width) ||
1263
(aDesiredSize.mOverflowArea.YMost() > aDesiredSize.height)) {
1264
mState |= NS_FRAME_OUTSIDE_CHILDREN;
1266
mState &= ~NS_FRAME_OUTSIDE_CHILDREN;
1272
// Let the inline frame do its reflow first
1273
rv = nsInlineFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
1275
// Let the absolutely positioned container reflow any absolutely positioned
1276
// child frames that need to be reflowed
1277
// We want to do this under either of two conditions:
1278
// 1. If we didn't do the incremental reflow above.
1279
// 2. If our size changed.
1280
// Even though it's the padding edge that's the containing block, we
1281
// can use our rect (the border edge) since if the border style
1282
// changed, the reflow would have been targeted at us so we'd satisfy
1284
if (NS_SUCCEEDED(rv) &&
1285
mAbsoluteContainer.HasAbsoluteFrames() &&
1286
(eReflowReason_Incremental != aReflowState.reason ||
1287
aReflowState.path->mReflowCommand ||
1288
mRect != oldRect)) {
1289
nscoord containingBlockWidth = -1;
1290
nscoord containingBlockHeight = -1;
1293
rv = mAbsoluteContainer.Reflow(this, aPresContext, aReflowState,
1294
containingBlockWidth, containingBlockHeight,
1297
// Factor the absolutely positioned child bounds into the overflow area
1298
aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, childBounds);
1300
// Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly
1301
if ((aDesiredSize.mOverflowArea.x < 0) ||
1302
(aDesiredSize.mOverflowArea.y < 0) ||
1303
(aDesiredSize.mOverflowArea.XMost() > aDesiredSize.width) ||
1304
(aDesiredSize.mOverflowArea.YMost() > aDesiredSize.height)) {
1305
mState |= NS_FRAME_OUTSIDE_CHILDREN;
1307
mState &= ~NS_FRAME_OUTSIDE_CHILDREN;