1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim:cindent:ts=2:et:sw=2:
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * Dan Rosen <dr@netscape.com>
25 * Mats Palmgren <matspal@gmail.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 * construction of a frame tree that is nearly isomorphic to the content
43 * tree and updating of that tree in response to dynamic changes
46 #include "nsCSSFrameConstructor.h"
50 #include "nsHashtable.h"
51 #include "nsIHTMLDocument.h"
52 #include "nsIStyleRule.h"
54 #include "nsGkAtoms.h"
55 #include "nsPresContext.h"
56 #include "nsILinkHandler.h"
57 #include "nsIDocument.h"
58 #include "nsTableFrame.h"
59 #include "nsTableColGroupFrame.h"
60 #include "nsTableColFrame.h"
61 #include "nsIDOMHTMLDocument.h"
62 #include "nsIDOMHTMLTableColElement.h"
63 #include "nsIDOMHTMLTableCaptionElem.h"
64 #include "nsHTMLParts.h"
65 #include "nsIPresShell.h"
66 #include "nsUnicharUtils.h"
67 #include "nsStyleSet.h"
68 #include "nsIViewManager.h"
69 #include "nsIEventStateManager.h"
70 #include "nsStyleConsts.h"
71 #include "nsTableOuterFrame.h"
72 #include "nsIDOMXULElement.h"
73 #include "nsHTMLContainerFrame.h"
74 #include "nsINameSpaceManager.h"
75 #include "nsIDOMHTMLSelectElement.h"
76 #include "nsIDOMHTMLLegendElement.h"
77 #include "nsIComboboxControlFrame.h"
78 #include "nsIListControlFrame.h"
79 #include "nsISelectControlFrame.h"
80 #include "nsIDOMCharacterData.h"
81 #include "nsIDOMHTMLImageElement.h"
82 #include "nsPlaceholderFrame.h"
83 #include "nsTableRowGroupFrame.h"
84 #include "nsStyleChangeList.h"
85 #include "nsIFormControl.h"
86 #include "nsCSSAnonBoxes.h"
87 #include "nsIDeviceContext.h"
88 #include "nsTextFragment.h"
89 #include "nsIAnonymousContentCreator.h"
90 #include "nsFrameManager.h"
91 #include "nsLegendFrame.h"
92 #include "nsIContentIterator.h"
93 #include "nsBoxLayoutState.h"
94 #include "nsBindingManager.h"
95 #include "nsXBLBinding.h"
97 #include "nsContentCID.h"
98 #include "nsContentUtils.h"
99 #include "nsIScriptError.h"
100 #include "nsIDocShell.h"
101 #include "nsIDocShellTreeItem.h"
102 #include "nsObjectFrame.h"
103 #include "nsRuleNode.h"
104 #include "nsIDOMMutationEvent.h"
105 #include "nsChildIterator.h"
106 #include "nsCSSRendering.h"
107 #include "nsISelectElement.h"
108 #include "nsLayoutErrors.h"
109 #include "nsLayoutUtils.h"
110 #include "nsAutoPtr.h"
111 #include "nsBoxFrame.h"
112 #include "nsIBoxLayout.h"
113 #include "nsImageFrame.h"
114 #include "nsIObjectLoadingContent.h"
115 #include "nsContentErrors.h"
116 #include "nsIPrincipal.h"
117 #include "nsIDOMWindowInternal.h"
118 #include "nsStyleUtil.h"
120 #include "nsTArray.h"
121 #include "nsGenericDOMDataNode.h"
122 #include "mozilla/dom/Element.h"
123 #include "FrameLayerBuilder.h"
126 #include "nsIRootBox.h"
127 #include "nsIDOMXULCommandDispatcher.h"
128 #include "nsIDOMXULDocument.h"
129 #include "nsIXULDocument.h"
132 #include "nsIAccessibilityService.h"
135 #include "nsInlineFrame.h"
136 #include "nsBlockFrame.h"
138 #include "nsIScrollableFrame.h"
140 #include "nsIXBLService.h"
142 #undef NOISY_FIRST_LETTER
145 #include "nsMathMLParts.h"
148 #include "nsSVGFeatures.h"
149 #include "nsSVGEffects.h"
150 #include "nsSVGUtils.h"
151 #include "nsSVGOuterSVGFrame.h"
154 #include "nsRefreshDriver.h"
156 using namespace mozilla
;
157 using namespace mozilla::dom
;
160 NS_NewHTMLCanvasFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
162 #if defined(MOZ_MEDIA)
164 NS_NewHTMLVideoFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
168 #include "nsSVGTextContainerFrame.h"
173 NS_NewSVGOuterSVGFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
175 NS_NewSVGInnerSVGFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
177 NS_NewSVGPathGeometryFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
179 NS_NewSVGGFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
181 NS_NewSVGGenericContainerFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
183 NS_NewSVGForeignObjectFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
185 NS_NewSVGAFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
187 NS_NewSVGGlyphFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
189 NS_NewSVGSwitchFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
191 NS_NewSVGTextFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
193 NS_NewSVGTSpanFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
195 NS_NewSVGContainerFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
197 NS_NewSVGUseFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
199 NS_NewSVGLinearGradientFrame(nsIPresShell
*aPresShell
, nsStyleContext
* aContext
);
201 NS_NewSVGRadialGradientFrame(nsIPresShell
*aPresShell
, nsStyleContext
* aContext
);
203 NS_NewSVGStopFrame(nsIPresShell
*aPresShell
, nsStyleContext
* aContext
);
205 NS_NewSVGMarkerFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
207 NS_NewSVGImageFrame(nsIPresShell
*aPresShell
, nsStyleContext
* aContext
);
209 NS_NewSVGClipPathFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
211 NS_NewSVGTextPathFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
213 NS_NewSVGFilterFrame(nsIPresShell
*aPresShell
, nsStyleContext
* aContext
);
215 NS_NewSVGPatternFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
217 NS_NewSVGMaskFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
219 NS_NewSVGLeafFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
222 #include "nsIDocument.h"
223 #include "nsIDOMElement.h"
224 #include "nsIDOMNodeList.h"
225 #include "nsIDOMDocument.h"
226 #include "nsIDOMDocumentXBL.h"
227 #include "nsIScrollable.h"
228 #include "nsINodeInfo.h"
230 #include "nsWidgetsCID.h"
231 #include "nsNodeInfoManager.h"
232 #include "nsContentCreatorFunctions.h"
233 #include "nsIServiceManager.h"
235 // Global object maintenance
236 nsIXBLService
* nsCSSFrameConstructor::gXBLService
= nsnull
;
239 // Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or
240 // more of the following flags (comma separated) for handy debug
242 static PRBool gNoisyContentUpdates
= PR_FALSE
;
243 static PRBool gReallyNoisyContentUpdates
= PR_FALSE
;
244 static PRBool gNoisyInlineConstruction
= PR_FALSE
;
246 struct FrameCtorDebugFlags
{
251 static FrameCtorDebugFlags gFlags
[] = {
252 { "content-updates", &gNoisyContentUpdates
},
253 { "really-noisy-content-updates", &gReallyNoisyContentUpdates
},
254 { "noisy-inline", &gNoisyInlineConstruction
}
257 #define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
262 #include "nsMenuFrame.h"
263 #include "nsMenuPopupFrame.h"
264 #include "nsPopupSetFrame.h"
265 #include "nsTreeColFrame.h"
266 #include "nsIBoxObject.h"
267 #include "nsPIListBoxObject.h"
268 #include "nsListBoxBodyFrame.h"
269 #include "nsListItemFrame.h"
270 #include "nsXULLabelFrame.h"
272 //------------------------------------------------------------------
275 NS_NewAutoRepeatBoxFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
278 NS_NewRootBoxFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
281 NS_NewDocElementBoxFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
284 NS_NewThumbFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
287 NS_NewDeckFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
290 NS_NewLeafBoxFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
293 NS_NewStackFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
296 NS_NewProgressMeterFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
299 NS_NewImageBoxFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
302 NS_NewTextBoxFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
305 NS_NewGroupBoxFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
308 NS_NewButtonBoxFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
311 NS_NewSplitterFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
314 NS_NewMenuPopupFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
317 NS_NewPopupSetFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
320 NS_NewMenuFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
, PRUint32 aFlags
);
323 NS_NewMenuBarFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
326 NS_NewTreeBodyFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
330 NS_NewGridLayout2 ( nsIPresShell
* aPresShell
, nsIBoxLayout
** aNewLayout
);
332 NS_NewGridRowLeafFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
334 NS_NewGridRowGroupFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
339 NS_NewTitleBarFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
342 NS_NewResizerFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
348 NS_NewHTMLScrollFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
, PRBool aIsRoot
);
351 NS_NewXULScrollFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
, PRBool aIsRoot
);
354 NS_NewSliderFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
357 NS_NewScrollbarFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
360 NS_NewScrollbarButtonFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
363 #ifdef NOISY_FINDFRAME
364 static PRInt32 FFWC_totalCount
=0;
365 static PRInt32 FFWC_doLoop
=0;
366 static PRInt32 FFWC_doSibling
=0;
367 static PRInt32 FFWC_recursions
=0;
368 static PRInt32 FFWC_nextInFlows
=0;
371 static inline nsIFrame
*
372 GetFieldSetBlockFrame(nsIFrame
* aFieldsetFrame
)
374 // Depends on the fieldset child frame order - see ConstructFieldSetFrame() below.
375 nsIFrame
* firstChild
= aFieldsetFrame
->GetFirstChild(nsnull
);
376 return firstChild
&& firstChild
->GetNextSibling() ? firstChild
->GetNextSibling() : firstChild
;
379 #define FCDATA_DECL(_flags, _func) \
380 { _flags, { (FrameCreationFunc)_func } }
382 //----------------------------------------------------------------------
385 IsInlineOutside(nsIFrame
* aFrame
)
387 return aFrame
->GetStyleDisplay()->IsInlineOutside();
391 * True if aFrame is an actual inline frame in the sense of non-replaced
392 * display:inline CSS boxes. In other words, it can be affected by {ib}
393 * splitting and can contain first-letter frames. Basically, this is either an
394 * inline frame (positioned or otherwise) or an line frame (this last because
395 * it can contain first-letter and because inserting blocks in the middle of it
396 * needs to terminate it).
399 IsInlineFrame(const nsIFrame
* aFrame
)
401 return aFrame
->IsFrameOfType(nsIFrame::eLineParticipant
);
405 * If any children require a block parent, return the first such child.
406 * Otherwise return null.
409 AnyKidsNeedBlockParent(nsIFrame
*aFrameList
)
411 for (nsIFrame
*k
= aFrameList
; k
; k
= k
->GetNextSibling()) {
412 // Line participants, such as text and inline frames, can't be
413 // directly inside a XUL box; they must be wrapped in an
414 // intermediate block.
415 if (k
->IsFrameOfType(nsIFrame::eLineParticipant
)) {
416 return k
->GetContent();
422 // Reparent a frame into a wrapper frame that is a child of its old parent.
424 ReparentFrame(nsFrameManager
* aFrameManager
,
425 nsIFrame
* aNewParentFrame
,
428 aFrame
->SetParent(aNewParentFrame
);
429 aFrameManager
->ReparentStyleContext(aFrame
);
433 ReparentFrames(nsFrameManager
* aFrameManager
,
434 nsIFrame
* aNewParentFrame
,
435 const nsFrameList
& aFrameList
)
437 for (nsFrameList::Enumerator
e(aFrameList
); !e
.AtEnd(); e
.Next()) {
438 ReparentFrame(aFrameManager
, aNewParentFrame
, e
.get());
442 //----------------------------------------------------------------------
444 // When inline frames get weird and have block frames in them, we
445 // annotate them to help us respond to incremental content changes
449 IsFrameSpecial(nsIFrame
* aFrame
)
451 return (aFrame
->GetStateBits() & NS_FRAME_IS_SPECIAL
) != 0;
454 static nsIFrame
* GetSpecialSibling(nsIFrame
* aFrame
)
456 NS_PRECONDITION(IsFrameSpecial(aFrame
), "Shouldn't call this");
458 // We only store the "special sibling" annotation with the first
459 // frame in the continuation chain. Walk back to find that frame now.
460 return static_cast<nsIFrame
*>
461 (aFrame
->GetFirstContinuation()->
462 Properties().Get(nsIFrame::IBSplitSpecialSibling()));
465 static nsIFrame
* GetSpecialPrevSibling(nsIFrame
* aFrame
)
467 NS_PRECONDITION(IsFrameSpecial(aFrame
), "Shouldn't call this");
469 // We only store the "special sibling" annotation with the first
470 // frame in the continuation chain. Walk back to find that frame now.
471 return static_cast<nsIFrame
*>
472 (aFrame
->GetFirstContinuation()->
473 Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
477 GetLastSpecialSibling(nsIFrame
* aFrame
, PRBool aReturnEmptyTrailingInline
)
479 for (nsIFrame
*frame
= aFrame
, *next
; ; frame
= next
) {
480 next
= GetSpecialSibling(frame
);
482 (!aReturnEmptyTrailingInline
&& !next
->GetFirstChild(nsnull
) &&
483 !GetSpecialSibling(next
))) {
484 NS_ASSERTION(!next
|| !IsInlineOutside(frame
),
485 "Should have a block here!");
489 NS_NOTREACHED("unreachable code");
494 SetFrameIsSpecial(nsIFrame
* aFrame
, nsIFrame
* aSpecialSibling
)
496 NS_PRECONDITION(aFrame
, "bad args!");
498 // We should be the only continuation
499 NS_ASSERTION(!aFrame
->GetPrevContinuation(),
500 "assigning special sibling to other than first continuation!");
501 NS_ASSERTION(!aFrame
->GetNextContinuation() ||
502 IsFrameSpecial(aFrame
->GetNextContinuation()),
503 "should have no non-special continuations here");
505 // Mark the frame as "special".
506 aFrame
->AddStateBits(NS_FRAME_IS_SPECIAL
);
508 if (aSpecialSibling
) {
509 NS_ASSERTION(!aSpecialSibling
->GetPrevContinuation(),
510 "assigning something other than the first continuation as the "
513 // Store the "special sibling" (if we were given one) with the
514 // first frame in the flow.
515 FramePropertyTable
* props
= aFrame
->PresContext()->PropertyTable();
516 props
->Set(aFrame
, nsIFrame::IBSplitSpecialSibling(), aSpecialSibling
);
517 props
->Set(aSpecialSibling
, nsIFrame::IBSplitSpecialPrevSibling(), aFrame
);
522 GetIBContainingBlockFor(nsIFrame
* aFrame
)
524 NS_PRECONDITION(IsFrameSpecial(aFrame
),
525 "GetIBContainingBlockFor() should only be called on known IB frames");
527 // Get the first "normal" ancestor of the target frame.
528 nsIFrame
* parentFrame
;
530 parentFrame
= aFrame
->GetParent();
533 NS_ERROR("no unsplit block frame in IB hierarchy");
537 // Note that we ignore non-special frames which have a pseudo on their
538 // style context -- they're not the frames we're looking for! In
539 // particular, they may be hiding a real parent that _is_ special.
540 if (!IsFrameSpecial(parentFrame
) &&
541 !parentFrame
->GetStyleContext()->GetPseudo())
544 aFrame
= parentFrame
;
548 NS_ASSERTION(parentFrame
, "no normal ancestor found for special frame in GetIBContainingBlockFor");
549 NS_ASSERTION(parentFrame
!= aFrame
, "parentFrame is actually the child frame - bogus reslt");
554 //----------------------------------------------------------------------
556 // Block/inline frame construction logic. We maintain a few invariants here:
558 // 1. Block frames contain block and inline frames.
560 // 2. Inline frames only contain inline frames. If an inline parent has a block
561 // child then the block child is migrated upward until it lands in a block
562 // parent (the inline frames containing block is where it will end up).
564 // After this function returns, aLink is pointing to the first link at or
565 // after its starting position for which the next frame is a block. If there
566 // is no such link, it points to the end of the list.
568 FindFirstBlock(nsFrameList::FrameLinkEnumerator
& aLink
)
570 for ( ; !aLink
.AtEnd(); aLink
.Next()) {
571 if (!IsInlineOutside(aLink
.NextFrame())) {
577 // This function returns a frame link enumerator pointing to the first link in
578 // the list for which the next frame is not block. If there is no such link,
579 // it points to the end of the list.
580 static nsFrameList::FrameLinkEnumerator
581 FindFirstNonBlock(const nsFrameList
& aList
)
583 nsFrameList::FrameLinkEnumerator
link(aList
);
584 for (; !link
.AtEnd(); link
.Next()) {
585 if (IsInlineOutside(link
.NextFrame())) {
593 SetInitialSingleChild(nsIFrame
* aParent
, nsIFrame
* aFrame
)
595 NS_PRECONDITION(!aFrame
->GetNextSibling(), "Should be using a frame list");
596 nsFrameList
temp(aFrame
, aFrame
);
597 aParent
->SetInitialChildList(nsnull
, temp
);
600 // -----------------------------------------------------------
602 // Structure used when constructing formatting object trees.
603 struct nsFrameItems
: public nsFrameList
605 // Appends the frame to the end of the list
606 void AddChild(nsIFrame
* aChild
);
610 nsFrameItems::AddChild(nsIFrame
* aChild
)
612 NS_PRECONDITION(aChild
, "nsFrameItems::AddChild");
614 // It'd be really nice if we could just AppendFrames(nsnull, aChild) here,
615 // but some of our callers put frames that have different
616 // parents (caption, I'm looking at you) on the same framelist, and
617 // nsFrameList asserts if you try to do that.
622 NS_ASSERTION(aChild
!= mLastChild
,
623 "Same frame being added to frame list twice?");
624 mLastChild
->SetNextSibling(aChild
);
625 mLastChild
= nsLayoutUtils::GetLastSibling(aChild
);
629 // -----------------------------------------------------------
631 // Structure used when constructing formatting object trees. Contains
632 // state information needed for absolutely positioned elements
633 struct nsAbsoluteItems
: nsFrameItems
{
634 // containing block for absolutely positioned elements
635 nsIFrame
* containingBlock
;
637 nsAbsoluteItems(nsIFrame
* aContainingBlock
);
639 // XXXbz Does this need a debug-only assignment operator that nulls out the
640 // childList in the nsAbsoluteItems we're copying? Introducing a difference
641 // between debug and non-debug behavior seems bad, so I guess not...
643 NS_ASSERTION(!FirstChild(),
644 "Dangling child list. Someone forgot to insert it?");
648 // Appends the frame to the end of the list
649 void AddChild(nsIFrame
* aChild
);
652 nsAbsoluteItems::nsAbsoluteItems(nsIFrame
* aContainingBlock
)
653 : containingBlock(aContainingBlock
)
657 // Additional behavior is that it sets the frame's NS_FRAME_OUT_OF_FLOW flag
659 nsAbsoluteItems::AddChild(nsIFrame
* aChild
)
661 NS_ASSERTION(aChild
->PresContext()->FrameManager()->
662 GetPlaceholderFrameFor(aChild
),
663 "Child without placeholder being added to nsAbsoluteItems?");
664 aChild
->AddStateBits(NS_FRAME_OUT_OF_FLOW
);
665 nsFrameItems::AddChild(aChild
);
668 // -----------------------------------------------------------
670 // Structure for saving the existing state when pushing/poping containing
671 // blocks. The destructor restores the state to its previous state
672 class NS_STACK_CLASS nsFrameConstructorSaveState
{
674 nsFrameConstructorSaveState();
675 ~nsFrameConstructorSaveState();
678 nsAbsoluteItems
* mItems
; // pointer to struct whose data we save/restore
679 PRPackedBool
* mFixedPosIsAbsPos
;
681 nsAbsoluteItems mSavedItems
; // copy of original data
682 PRPackedBool mSavedFixedPosIsAbsPos
;
684 // The name of the child list in which our frames would belong
685 nsIAtom
* mChildListName
;
686 nsFrameConstructorState
* mState
;
688 friend class nsFrameConstructorState
;
691 // Structure used to keep track of a list of bindings we need to call
692 // AddToAttachedQueue on. These should be in post-order depth-first
693 // flattened tree traversal order.
694 struct PendingBinding
: public PRCList
696 #ifdef NS_BUILD_REFCNT_LOGGING
698 MOZ_COUNT_CTOR(PendingBinding
);
701 MOZ_COUNT_DTOR(PendingBinding
);
705 nsRefPtr
<nsXBLBinding
> mBinding
;
708 // Structure used for maintaining state information during the
709 // frame construction process
710 class NS_STACK_CLASS nsFrameConstructorState
{
712 nsPresContext
*mPresContext
;
713 nsIPresShell
*mPresShell
;
714 nsFrameManager
*mFrameManager
;
717 // Frames destined for the nsGkAtoms::popupList.
718 nsAbsoluteItems mPopupItems
;
721 // Containing block information for out-of-flow frames.
722 nsAbsoluteItems mFixedItems
;
723 nsAbsoluteItems mAbsoluteItems
;
724 nsAbsoluteItems mFloatedItems
;
726 nsCOMPtr
<nsILayoutHistoryState
> mFrameState
;
727 // These bits will be added to the state bits of any frame we construct
729 nsFrameState mAdditionalStateBits
;
731 // When working with the -moz-transform property, we want to hook
732 // the abs-pos and fixed-pos lists together, since transformed
733 // elements are fixed-pos containing blocks. This flag determines
734 // whether or not we want to wire the fixed-pos and abs-pos lists
736 PRPackedBool mFixedPosIsAbsPos
;
738 // A boolean to indicate whether we have a "pending" popupgroup. That is, we
739 // have already created the FrameConstructionItem for the root popupgroup but
740 // we have not yet created the relevant frame.
741 PRPackedBool mHavePendingPopupgroup
;
743 // If false (which is the default) then call SetPrimaryFrame() as needed
744 // during frame construction. If true, don't make any SetPrimaryFrame()
745 // calls. The mCreatingExtraFrames == PR_TRUE mode is meant to be used for
746 // construction of random "extra" frames for elements via normal frame
747 // construction APIs (e.g. replication of things across pages in paginated
749 PRPackedBool mCreatingExtraFrames
;
751 nsCOMArray
<nsIContent
> mGeneratedTextNodesWithInitializer
;
754 // Use the passed-in history state.
755 nsFrameConstructorState(nsIPresShell
* aPresShell
,
756 nsIFrame
* aFixedContainingBlock
,
757 nsIFrame
* aAbsoluteContainingBlock
,
758 nsIFrame
* aFloatContainingBlock
,
759 nsILayoutHistoryState
* aHistoryState
);
760 // Get the history state from the pres context's pres shell.
761 nsFrameConstructorState(nsIPresShell
* aPresShell
,
762 nsIFrame
* aFixedContainingBlock
,
763 nsIFrame
* aAbsoluteContainingBlock
,
764 nsIFrame
* aFloatContainingBlock
);
766 ~nsFrameConstructorState();
768 // Function to push the existing absolute containing block state and
769 // create a new scope. Code that uses this function should get matching
770 // logic in GetAbsoluteContainingBlock.
771 void PushAbsoluteContainingBlock(nsIFrame
* aNewAbsoluteContainingBlock
,
772 nsFrameConstructorSaveState
& aSaveState
);
774 // Function to push the existing float containing block state and
775 // create a new scope. Code that uses this function should get matching
776 // logic in GetFloatContainingBlock.
777 // Pushing a null float containing block forbids any frames from being
778 // floated until a new float containing block is pushed.
779 // XXX we should get rid of null float containing blocks and teach the
780 // various frame classes to deal with floats instead.
781 void PushFloatContainingBlock(nsIFrame
* aNewFloatContainingBlock
,
782 nsFrameConstructorSaveState
& aSaveState
);
784 // Function to return the proper geometric parent for a frame with display
785 // struct given by aStyleDisplay and parent's frame given by
786 // aContentParentFrame.
787 nsIFrame
* GetGeometricParent(const nsStyleDisplay
* aStyleDisplay
,
788 nsIFrame
* aContentParentFrame
);
791 * Function to add a new frame to the right frame list. This MUST be called
792 * on frames before their children have been processed if the frames might
793 * conceivably be out-of-flow; otherwise cleanup in error cases won't work
794 * right. Also, this MUST be called on frames after they have been
796 * @param aNewFrame the frame to add
797 * @param aFrameItems the list to add in-flow frames to
798 * @param aContent the content pointer for aNewFrame
799 * @param aStyleContext the style context resolved for aContent
800 * @param aParentFrame the parent frame for the content if it were in-flow
801 * @param aCanBePositioned pass false if the frame isn't allowed to be
803 * @param aCanBeFloated pass false if the frame isn't allowed to be
805 * @param aIsOutOfFlowPopup pass true if the frame is an out-of-flow popup
807 * @throws NS_ERROR_OUT_OF_MEMORY if it happens.
808 * @note If this method throws, that means that aNewFrame was not inserted
809 * into any frame lists. Furthermore, this method will handle cleanup
810 * of aNewFrame (via calling Destroy() on it).
812 nsresult
AddChild(nsIFrame
* aNewFrame
,
813 nsFrameItems
& aFrameItems
,
814 nsIContent
* aContent
,
815 nsStyleContext
* aStyleContext
,
816 nsIFrame
* aParentFrame
,
817 PRBool aCanBePositioned
= PR_TRUE
,
818 PRBool aCanBeFloated
= PR_TRUE
,
819 PRBool aIsOutOfFlowPopup
= PR_FALSE
,
820 PRBool aInsertAfter
= PR_FALSE
,
821 nsIFrame
* aInsertAfterFrame
= nsnull
);
824 * Function to return the fixed-pos element list. Normally this will just hand back the
825 * fixed-pos element list, but in case we're dealing with a transformed element that's
826 * acting as an abs-pos and fixed-pos container, we'll hand back the abs-pos list. Callers should
827 * use this function if they want to get the list acting as the fixed-pos item parent.
829 nsAbsoluteItems
& GetFixedItems()
831 return mFixedPosIsAbsPos
? mAbsoluteItems
: mFixedItems
;
833 const nsAbsoluteItems
& GetFixedItems() const
835 return mFixedPosIsAbsPos
? mAbsoluteItems
: mFixedItems
;
840 * class to automatically push and pop a pending binding in the frame
841 * constructor state. See nsCSSFrameConstructor::FrameConstructionItem
842 * mPendingBinding documentation.
844 class PendingBindingAutoPusher
;
845 friend class PendingBindingAutoPusher
;
846 class NS_STACK_CLASS PendingBindingAutoPusher
{
848 PendingBindingAutoPusher(nsFrameConstructorState
& aState
,
849 PendingBinding
* aPendingBinding
) :
851 mPendingBinding(aState
.mCurrentPendingBindingInsertionPoint
)
853 NS_PRECONDITION(mPendingBinding
, "how did that happen?");
854 if (aPendingBinding
) {
855 aState
.mCurrentPendingBindingInsertionPoint
= aPendingBinding
;
859 ~PendingBindingAutoPusher()
861 mState
.mCurrentPendingBindingInsertionPoint
= mPendingBinding
;
865 nsFrameConstructorState
& mState
;
866 PRCList
* mPendingBinding
;
870 * Add a new pending binding to the list
872 void AddPendingBinding(PendingBinding
* aPendingBinding
) {
873 PR_INSERT_BEFORE(aPendingBinding
, mCurrentPendingBindingInsertionPoint
);
877 friend class nsFrameConstructorSaveState
;
880 * ProcessFrameInsertions takes the frames in aFrameItems and adds them as
881 * kids to the aChildListName child list of |aFrameItems.containingBlock|.
883 void ProcessFrameInsertions(nsAbsoluteItems
& aFrameItems
,
884 nsIAtom
* aChildListName
);
886 // Our list of all pending bindings. When we're done, we need to call
887 // AddToAttachedQueue on all of them, in order.
888 PRCList mPendingBindings
;
890 PRCList
* mCurrentPendingBindingInsertionPoint
;
893 nsFrameConstructorState::nsFrameConstructorState(nsIPresShell
* aPresShell
,
894 nsIFrame
* aFixedContainingBlock
,
895 nsIFrame
* aAbsoluteContainingBlock
,
896 nsIFrame
* aFloatContainingBlock
,
897 nsILayoutHistoryState
* aHistoryState
)
898 : mPresContext(aPresShell
->GetPresContext()),
899 mPresShell(aPresShell
),
900 mFrameManager(aPresShell
->FrameManager()),
904 mFixedItems(aFixedContainingBlock
),
905 mAbsoluteItems(aAbsoluteContainingBlock
),
906 mFloatedItems(aFloatContainingBlock
),
907 // See PushAbsoluteContaningBlock below
908 mFrameState(aHistoryState
),
909 mAdditionalStateBits(0),
910 mFixedPosIsAbsPos(aAbsoluteContainingBlock
&&
911 aAbsoluteContainingBlock
->GetStyleDisplay()->
913 mHavePendingPopupgroup(PR_FALSE
),
914 mCreatingExtraFrames(PR_FALSE
),
915 mCurrentPendingBindingInsertionPoint(&mPendingBindings
)
918 nsIRootBox
* rootBox
= nsIRootBox::GetRootBox(aPresShell
);
920 mPopupItems
.containingBlock
= rootBox
->GetPopupSetFrame();
923 MOZ_COUNT_CTOR(nsFrameConstructorState
);
924 PR_INIT_CLIST(&mPendingBindings
);
927 nsFrameConstructorState::nsFrameConstructorState(nsIPresShell
* aPresShell
,
928 nsIFrame
* aFixedContainingBlock
,
929 nsIFrame
* aAbsoluteContainingBlock
,
930 nsIFrame
* aFloatContainingBlock
)
931 : mPresContext(aPresShell
->GetPresContext()),
932 mPresShell(aPresShell
),
933 mFrameManager(aPresShell
->FrameManager()),
937 mFixedItems(aFixedContainingBlock
),
938 mAbsoluteItems(aAbsoluteContainingBlock
),
939 mFloatedItems(aFloatContainingBlock
),
940 // See PushAbsoluteContaningBlock below
941 mAdditionalStateBits(0),
942 mFixedPosIsAbsPos(aAbsoluteContainingBlock
&&
943 aAbsoluteContainingBlock
->GetStyleDisplay()->
945 mHavePendingPopupgroup(PR_FALSE
),
946 mCreatingExtraFrames(PR_FALSE
),
947 mCurrentPendingBindingInsertionPoint(&mPendingBindings
)
950 nsIRootBox
* rootBox
= nsIRootBox::GetRootBox(aPresShell
);
952 mPopupItems
.containingBlock
= rootBox
->GetPopupSetFrame();
955 MOZ_COUNT_CTOR(nsFrameConstructorState
);
956 mFrameState
= aPresShell
->GetDocument()->GetLayoutHistoryState();
957 PR_INIT_CLIST(&mPendingBindings
);
960 nsFrameConstructorState::~nsFrameConstructorState()
962 // Frame order comparison functions only work properly when the placeholders
963 // have been inserted into the frame tree. So for example if we have a new float
964 // containing the placeholder for a new abs-pos frame, and we process the abs-pos
965 // insertion first, then we won't be able to find the right place to insert in
966 // in the abs-pos list. So put floats in first, because they can contain placeholders
967 // for abs-pos and fixed-pos items whose containing blocks are outside the floats.
968 // Then put abs-pos frames in, because they can contain placeholders for fixed-pos
969 // items whose containing block is outside the abs-pos frames.
970 MOZ_COUNT_DTOR(nsFrameConstructorState
);
971 ProcessFrameInsertions(mFloatedItems
, nsGkAtoms::floatList
);
972 ProcessFrameInsertions(mAbsoluteItems
, nsGkAtoms::absoluteList
);
973 ProcessFrameInsertions(mFixedItems
, nsGkAtoms::fixedList
);
975 ProcessFrameInsertions(mPopupItems
, nsGkAtoms::popupList
);
977 for (PRInt32 i
= mGeneratedTextNodesWithInitializer
.Count() - 1; i
>= 0; --i
) {
978 mGeneratedTextNodesWithInitializer
[i
]->
979 DeleteProperty(nsGkAtoms::genConInitializerProperty
);
981 if (!PR_CLIST_IS_EMPTY(&mPendingBindings
)) {
982 nsBindingManager
* bindingManager
= mPresShell
->GetDocument()->BindingManager();
984 PendingBinding
* pendingBinding
=
985 static_cast<PendingBinding
*>(PR_NEXT_LINK(&mPendingBindings
));
986 PR_REMOVE_LINK(pendingBinding
);
987 bindingManager
->AddToAttachedQueue(pendingBinding
->mBinding
);
988 delete pendingBinding
;
989 } while (!PR_CLIST_IS_EMPTY(&mPendingBindings
));
994 AdjustAbsoluteContainingBlock(nsIFrame
* aContainingBlockIn
)
996 if (!aContainingBlockIn
) {
1000 // Always use the container's first continuation. (Inline frames can have
1001 // non-fluid bidi continuations...)
1002 return aContainingBlockIn
->GetFirstContinuation();
1006 nsFrameConstructorState::PushAbsoluteContainingBlock(nsIFrame
* aNewAbsoluteContainingBlock
,
1007 nsFrameConstructorSaveState
& aSaveState
)
1009 aSaveState
.mItems
= &mAbsoluteItems
;
1010 aSaveState
.mSavedItems
= mAbsoluteItems
;
1011 aSaveState
.mChildListName
= nsGkAtoms::absoluteList
;
1012 aSaveState
.mState
= this;
1014 /* Store whether we're wiring the abs-pos and fixed-pos lists together. */
1015 aSaveState
.mFixedPosIsAbsPos
= &mFixedPosIsAbsPos
;
1016 aSaveState
.mSavedFixedPosIsAbsPos
= mFixedPosIsAbsPos
;
1019 nsAbsoluteItems(AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock
));
1021 /* See if we're wiring the fixed-pos and abs-pos lists together. This happens iff
1022 * we're a transformed element.
1024 mFixedPosIsAbsPos
= (aNewAbsoluteContainingBlock
&&
1025 aNewAbsoluteContainingBlock
->GetStyleDisplay()->HasTransform());
1029 nsFrameConstructorState::PushFloatContainingBlock(nsIFrame
* aNewFloatContainingBlock
,
1030 nsFrameConstructorSaveState
& aSaveState
)
1032 NS_PRECONDITION(!aNewFloatContainingBlock
||
1033 aNewFloatContainingBlock
->IsFloatContainingBlock(),
1034 "Please push a real float containing block!");
1035 aSaveState
.mItems
= &mFloatedItems
;
1036 aSaveState
.mSavedItems
= mFloatedItems
;
1037 aSaveState
.mChildListName
= nsGkAtoms::floatList
;
1038 aSaveState
.mState
= this;
1039 mFloatedItems
= nsAbsoluteItems(aNewFloatContainingBlock
);
1043 nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay
* aStyleDisplay
,
1044 nsIFrame
* aContentParentFrame
)
1046 NS_PRECONDITION(aStyleDisplay
, "Must have display struct!");
1048 // If there is no container for a fixed, absolute, or floating root
1049 // frame, we will ignore the positioning. This hack is originally
1050 // brought to you by the letter T: tables, since other roots don't
1051 // even call into this code. See bug 178855.
1053 // XXX Disabling positioning in this case is a hack. If one was so inclined,
1054 // one could support this either by (1) inserting a dummy block between the
1055 // table and the canvas or (2) teaching the canvas how to reflow positioned
1056 // elements. (1) has the usual problems when multiple frames share the same
1057 // content (notice all the special cases in this file dealing with inner
1058 // tables and outer tables which share the same content). (2) requires some
1059 // work and possible factoring.
1061 // XXXbz couldn't we just force position to "static" on roots and
1062 // float to "none"? That's OK per CSS 2.1, as far as I can tell.
1064 if (aStyleDisplay
->IsFloating() && mFloatedItems
.containingBlock
) {
1065 NS_ASSERTION(!aStyleDisplay
->IsAbsolutelyPositioned(),
1066 "Absolutely positioned _and_ floating?");
1067 return mFloatedItems
.containingBlock
;
1070 if (aStyleDisplay
->mPosition
== NS_STYLE_POSITION_ABSOLUTE
&&
1071 mAbsoluteItems
.containingBlock
) {
1072 return mAbsoluteItems
.containingBlock
;
1075 if (aStyleDisplay
->mPosition
== NS_STYLE_POSITION_FIXED
&&
1076 GetFixedItems().containingBlock
) {
1077 return GetFixedItems().containingBlock
;
1080 return aContentParentFrame
;
1084 nsFrameConstructorState::AddChild(nsIFrame
* aNewFrame
,
1085 nsFrameItems
& aFrameItems
,
1086 nsIContent
* aContent
,
1087 nsStyleContext
* aStyleContext
,
1088 nsIFrame
* aParentFrame
,
1089 PRBool aCanBePositioned
,
1090 PRBool aCanBeFloated
,
1091 PRBool aIsOutOfFlowPopup
,
1092 PRBool aInsertAfter
,
1093 nsIFrame
* aInsertAfterFrame
)
1095 NS_PRECONDITION(!aNewFrame
->GetNextSibling(), "Shouldn't happen");
1097 const nsStyleDisplay
* disp
= aNewFrame
->GetStyleDisplay();
1099 // The comments in GetGeometricParent regarding root table frames
1100 // all apply here, unfortunately.
1102 PRBool needPlaceholder
= PR_FALSE
;
1103 nsFrameState placeholderType
;
1104 nsFrameItems
* frameItems
= &aFrameItems
;
1106 if (NS_UNLIKELY(aIsOutOfFlowPopup
)) {
1107 NS_ASSERTION(aNewFrame
->GetParent() == mPopupItems
.containingBlock
,
1108 "Popup whose parent is not the popup containing block?");
1109 NS_ASSERTION(mPopupItems
.containingBlock
, "Must have a popup set frame!");
1110 needPlaceholder
= PR_TRUE
;
1111 frameItems
= &mPopupItems
;
1112 placeholderType
= PLACEHOLDER_FOR_POPUP
;
1116 if (aCanBeFloated
&& disp
->IsFloating() &&
1117 mFloatedItems
.containingBlock
) {
1118 NS_ASSERTION(aNewFrame
->GetParent() == mFloatedItems
.containingBlock
,
1119 "Float whose parent is not the float containing block?");
1120 needPlaceholder
= PR_TRUE
;
1121 frameItems
= &mFloatedItems
;
1122 placeholderType
= PLACEHOLDER_FOR_FLOAT
;
1124 else if (aCanBePositioned
) {
1125 if (disp
->mPosition
== NS_STYLE_POSITION_ABSOLUTE
&&
1126 mAbsoluteItems
.containingBlock
) {
1127 NS_ASSERTION(aNewFrame
->GetParent() == mAbsoluteItems
.containingBlock
,
1128 "Abs pos whose parent is not the abs pos containing block?");
1129 needPlaceholder
= PR_TRUE
;
1130 frameItems
= &mAbsoluteItems
;
1131 placeholderType
= PLACEHOLDER_FOR_ABSPOS
;
1133 if (disp
->mPosition
== NS_STYLE_POSITION_FIXED
&&
1134 GetFixedItems().containingBlock
) {
1135 NS_ASSERTION(aNewFrame
->GetParent() == GetFixedItems().containingBlock
,
1136 "Fixed pos whose parent is not the fixed pos containing block?");
1137 needPlaceholder
= PR_TRUE
;
1138 frameItems
= &GetFixedItems();
1139 placeholderType
= PLACEHOLDER_FOR_FIXEDPOS
;
1143 if (needPlaceholder
) {
1144 NS_ASSERTION(frameItems
!= &aFrameItems
,
1145 "Putting frame in-flow _and_ want a placeholder?");
1146 nsIFrame
* placeholderFrame
;
1148 nsCSSFrameConstructor::CreatePlaceholderFrameFor(mPresShell
,
1156 if (NS_FAILED(rv
)) {
1157 // Note that aNewFrame could be the top frame for a scrollframe setup,
1158 // hence already set as the primary frame. So we have to clean up here.
1159 // But it shouldn't have any out-of-flow kids.
1160 // XXXbz Maybe add a utility function to assert that?
1161 aNewFrame
->Destroy();
1165 placeholderFrame
->AddStateBits(mAdditionalStateBits
);
1166 // Add the placeholder frame to the flow
1167 aFrameItems
.AddChild(placeholderFrame
);
1171 NS_ASSERTION(aNewFrame
->GetParent() == aParentFrame
,
1172 "In-flow frame has wrong parent");
1177 frameItems
->InsertFrame(nsnull
, aInsertAfterFrame
, aNewFrame
);
1179 frameItems
->AddChild(aNewFrame
);
1186 nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems
& aFrameItems
,
1187 nsIAtom
* aChildListName
)
1189 #define NS_NONXUL_LIST_TEST (&aFrameItems == &mFloatedItems && \
1190 aChildListName == nsGkAtoms::floatList) || \
1191 (&aFrameItems == &mAbsoluteItems && \
1192 aChildListName == nsGkAtoms::absoluteList) || \
1193 (&aFrameItems == &mFixedItems && \
1194 aChildListName == nsGkAtoms::fixedList)
1196 NS_PRECONDITION(NS_NONXUL_LIST_TEST
||
1197 (&aFrameItems
== &mPopupItems
&&
1198 aChildListName
== nsGkAtoms::popupList
),
1199 "Unexpected aFrameItems/aChildListName combination");
1201 NS_PRECONDITION(NS_NONXUL_LIST_TEST
,
1202 "Unexpected aFrameItems/aChildListName combination");
1205 if (aFrameItems
.IsEmpty()) {
1209 nsIFrame
* containingBlock
= aFrameItems
.containingBlock
;
1211 NS_ASSERTION(containingBlock
,
1212 "Child list without containing block?");
1214 // Insert the frames hanging out in aItems. We can use SetInitialChildList()
1215 // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
1216 // is set) and doesn't have any frames in the aChildListName child list yet.
1217 const nsFrameList
& childList
= containingBlock
->GetChildList(aChildListName
);
1218 nsresult rv
= NS_OK
;
1219 if (childList
.IsEmpty() &&
1220 (containingBlock
->GetStateBits() & NS_FRAME_FIRST_REFLOW
)) {
1221 rv
= containingBlock
->SetInitialChildList(aChildListName
, aFrameItems
);
1223 // Note that whether the frame construction context is doing an append or
1224 // not is not helpful here, since it could be appending to some frame in
1225 // the middle of the document, which means we're not necessarily
1226 // appending to the children of the containing block.
1228 // We need to make sure the 'append to the end of document' case is fast.
1229 // So first test the last child of the containing block
1230 nsIFrame
* lastChild
= childList
.LastChild();
1232 // CompareTreePosition uses placeholder hierarchy for out of flow frames,
1233 // so this will make out-of-flows respect the ordering of placeholders,
1234 // which is great because it takes care of anonymous content.
1235 nsIFrame
* firstNewFrame
= aFrameItems
.FirstChild();
1237 nsLayoutUtils::CompareTreePosition(lastChild
, firstNewFrame
, containingBlock
) < 0) {
1238 // no lastChild, or lastChild comes before the new children, so just append
1239 rv
= containingBlock
->AppendFrames(aChildListName
, aFrameItems
);
1241 // try the other children
1242 nsIFrame
* insertionPoint
= nsnull
;
1243 for (nsIFrame
* f
= childList
.FirstChild(); f
!= lastChild
;
1244 f
= f
->GetNextSibling()) {
1246 nsLayoutUtils::CompareTreePosition(f
, firstNewFrame
, containingBlock
);
1248 // f comes after the new children, so stop here and insert after
1249 // the previous frame
1254 rv
= containingBlock
->InsertFrames(aChildListName
, insertionPoint
,
1259 NS_POSTCONDITION(aFrameItems
.IsEmpty(), "How did that happen?");
1261 // XXXbz And if NS_FAILED(rv), what? I guess we need to clean up the list
1262 // and deal with all the placeholders... but what if the placeholders aren't
1263 // in the document yet? Could that happen?
1264 NS_ASSERTION(NS_SUCCEEDED(rv
), "Frames getting lost!");
1268 nsFrameConstructorSaveState::nsFrameConstructorSaveState()
1270 mFixedPosIsAbsPos(nsnull
),
1271 mSavedItems(nsnull
),
1272 mSavedFixedPosIsAbsPos(PR_FALSE
),
1273 mChildListName(nsnull
),
1278 nsFrameConstructorSaveState::~nsFrameConstructorSaveState()
1280 // Restore the state
1282 NS_ASSERTION(mState
, "Can't have mItems set without having a state!");
1283 mState
->ProcessFrameInsertions(*mItems
, mChildListName
);
1284 *mItems
= mSavedItems
;
1286 // We've transferred the child list, so drop the pointer we held to it.
1287 // Note that this only matters for the assert in ~nsAbsoluteItems.
1288 mSavedItems
.Clear();
1291 if (mFixedPosIsAbsPos
) {
1292 *mFixedPosIsAbsPos
= mSavedFixedPosIsAbsPos
;
1297 PRBool
IsBorderCollapse(nsIFrame
* aFrame
)
1299 for (nsIFrame
* frame
= aFrame
; frame
; frame
= frame
->GetParent()) {
1300 if (nsGkAtoms::tableFrame
== frame
->GetType()) {
1301 return ((nsTableFrame
*)frame
)->IsBorderCollapse();
1304 NS_ASSERTION(PR_FALSE
, "program error");
1309 * Moves aFrameList from aOldParent to aNewParent. This updates the parent
1310 * pointer of the frames in the list, and reparents their views as needed.
1311 * nsFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its
1312 * ancestors as needed. Then it sets the list as the initial child list
1313 * on aNewParent, unless aNewParent either already has kids or has been
1314 * reflowed; in that case it appends the new frames. Note that this
1315 * method differs from ReparentFrames in that it doesn't change the kids'
1318 // XXXbz Since this is only used for {ib} splits, could we just copy the view
1319 // bits from aOldParent to aNewParent and then use the
1320 // nsFrameList::ApplySetParent? That would still leave us doing two passes
1321 // over the list, of course; if we really wanted to we could factor out the
1322 // relevant part of ReparentFrameViewList, I suppose... Or just get rid of
1323 // views, which would make most of this function go away.
1325 MoveChildrenTo(nsPresContext
* aPresContext
,
1326 nsIFrame
* aOldParent
,
1327 nsIFrame
* aNewParent
,
1328 nsFrameList
& aFrameList
)
1330 PRBool sameGrandParent
= aOldParent
->GetParent() == aNewParent
->GetParent();
1332 if (aNewParent
->HasView() || aOldParent
->HasView() || !sameGrandParent
) {
1333 // Move the frames into the new view
1334 nsHTMLContainerFrame::ReparentFrameViewList(aPresContext
, aFrameList
,
1335 aOldParent
, aNewParent
);
1338 for (nsFrameList::Enumerator
e(aFrameList
); !e
.AtEnd(); e
.Next()) {
1339 e
.get()->SetParent(aNewParent
);
1342 if (aNewParent
->GetChildList(nsnull
).IsEmpty() &&
1343 (aNewParent
->GetStateBits() & NS_FRAME_FIRST_REFLOW
)) {
1344 aNewParent
->SetInitialChildList(nsnull
, aFrameList
);
1346 aNewParent
->AppendFrames(nsnull
, aFrameList
);
1350 //----------------------------------------------------------------------
1352 nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument
*aDocument
,
1353 nsIPresShell
*aPresShell
)
1354 : mDocument(aDocument
)
1355 , mPresShell(aPresShell
)
1356 , mRootElementFrame(nsnull
)
1357 , mRootElementStyleFrame(nsnull
)
1358 , mFixedContainingBlock(nsnull
)
1359 , mDocElementContainingBlock(nsnull
)
1360 , mGfxScrollFrame(nsnull
)
1361 , mPageSequenceFrame(nsnull
)
1363 , mQuotesDirty(PR_FALSE
)
1364 , mCountersDirty(PR_FALSE
)
1365 , mIsDestroyingFrameTree(PR_FALSE
)
1366 , mRebuildAllStyleData(PR_FALSE
)
1367 , mHasRootAbsPosContainingBlock(PR_FALSE
)
1368 , mObservingRefreshDriver(PR_FALSE
)
1369 , mInStyleRefresh(PR_FALSE
)
1370 , mHoverGeneration(0)
1371 , mRebuildAllExtraHint(nsChangeHint(0))
1372 , mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE
|
1373 ELEMENT_IS_POTENTIAL_RESTYLE_ROOT
, this)
1374 , mPendingAnimationRestyles(ELEMENT_HAS_PENDING_ANIMATION_RESTYLE
|
1375 ELEMENT_IS_POTENTIAL_ANIMATION_RESTYLE_ROOT
, this)
1377 // XXXbz this should be in Init() or something!
1378 if (!mPendingRestyles
.Init() || !mPendingAnimationRestyles
.Init()) {
1383 static PRBool gFirstTime
= PR_TRUE
;
1385 gFirstTime
= PR_FALSE
;
1386 char* flags
= PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS");
1388 PRBool error
= PR_FALSE
;
1390 char* comma
= PL_strchr(flags
, ',');
1394 PRBool found
= PR_FALSE
;
1395 FrameCtorDebugFlags
* flag
= gFlags
;
1396 FrameCtorDebugFlags
* limit
= gFlags
+ NUM_DEBUG_FLAGS
;
1397 while (flag
< limit
) {
1398 if (PL_strcasecmp(flag
->name
, flags
) == 0) {
1399 *(flag
->on
) = PR_TRUE
;
1400 printf("nsCSSFrameConstructor: setting %s debug flag on\n", flag
->name
);
1418 printf("Here are the available GECKO_FRAMECTOR_DEBUG_FLAGS:\n");
1419 FrameCtorDebugFlags
* flag
= gFlags
;
1420 FrameCtorDebugFlags
* limit
= gFlags
+ NUM_DEBUG_FLAGS
;
1421 while (flag
< limit
) {
1422 printf(" %s\n", flag
->name
);
1425 printf("Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of flag\n");
1426 printf("names (no whitespace)\n");
1433 nsIXBLService
* nsCSSFrameConstructor::GetXBLService()
1436 nsresult rv
= CallGetService("@mozilla.org/xbl;1", &gXBLService
);
1438 gXBLService
= nsnull
;
1445 nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame
* aFrame
)
1447 NS_PRECONDITION(mUpdateCount
!= 0,
1448 "Should be in an update while destroying frames");
1450 if (aFrame
->GetStateBits() & NS_FRAME_GENERATED_CONTENT
) {
1451 if (mQuoteList
.DestroyNodesFor(aFrame
))
1455 if (mCounterManager
.DestroyNodesFor(aFrame
)) {
1456 // Technically we don't need to update anything if we destroyed only
1457 // USE nodes. However, this is unlikely to happen in the real world
1458 // since USE nodes generally go along with INCREMENT nodes.
1463 struct nsGenConInitializer
{
1464 nsAutoPtr
<nsGenConNode
> mNode
;
1465 nsGenConList
* mList
;
1466 void (nsCSSFrameConstructor::*mDirtyAll
)();
1468 nsGenConInitializer(nsGenConNode
* aNode
, nsGenConList
* aList
,
1469 void (nsCSSFrameConstructor::*aDirtyAll
)())
1470 : mNode(aNode
), mList(aList
), mDirtyAll(aDirtyAll
) {}
1474 DestroyGenConInitializer(void* aFrame
,
1475 nsIAtom
* aPropertyName
,
1476 void* aPropertyValue
,
1479 delete static_cast<nsGenConInitializer
*>(aPropertyValue
);
1482 already_AddRefed
<nsIContent
>
1483 nsCSSFrameConstructor::CreateGenConTextNode(nsFrameConstructorState
& aState
,
1484 const nsString
& aString
,
1485 nsCOMPtr
<nsIDOMCharacterData
>* aText
,
1486 nsGenConInitializer
* aInitializer
)
1488 nsCOMPtr
<nsIContent
> content
;
1489 NS_NewTextNode(getter_AddRefs(content
), mDocument
->NodeInfoManager());
1491 // XXX The quotes/counters code doesn't like the text pointer
1492 // being null in case of dynamic changes!
1493 NS_ASSERTION(!aText
, "this OOM case isn't handled very well");
1496 content
->SetText(aString
, PR_FALSE
);
1498 *aText
= do_QueryInterface(content
);
1501 content
->SetProperty(nsGkAtoms::genConInitializerProperty
, aInitializer
,
1502 DestroyGenConInitializer
);
1503 aState
.mGeneratedTextNodesWithInitializer
.AppendObject(content
);
1505 return content
.forget();
1508 already_AddRefed
<nsIContent
>
1509 nsCSSFrameConstructor::CreateGeneratedContent(nsFrameConstructorState
& aState
,
1510 nsIContent
* aParentContent
,
1511 nsStyleContext
* aStyleContext
,
1512 PRUint32 aContentIndex
)
1514 // Get the content value
1515 const nsStyleContentData
&data
=
1516 aStyleContext
->GetStyleContent()->ContentAt(aContentIndex
);
1517 nsStyleContentType type
= data
.mType
;
1519 if (eStyleContentType_Image
== type
) {
1520 if (!data
.mContent
.mImage
) {
1521 // CSS had something specified that couldn't be converted to an
1526 // Create an image content object and pass it the image request.
1527 // XXX Check if it's an image type we can handle...
1529 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
1530 nodeInfo
= mDocument
->NodeInfoManager()->GetNodeInfo(nsGkAtoms::mozgeneratedcontentimage
, nsnull
,
1531 kNameSpaceID_XHTML
);
1533 nsCOMPtr
<nsIContent
> content
;
1534 NS_NewGenConImageContent(getter_AddRefs(content
), nodeInfo
.forget(),
1535 data
.mContent
.mImage
);
1536 return content
.forget();
1540 case eStyleContentType_String
:
1541 return CreateGenConTextNode(aState
,
1542 nsDependentString(data
.mContent
.mString
),
1545 case eStyleContentType_Attr
:
1547 nsCOMPtr
<nsIAtom
> attrName
;
1548 PRInt32 attrNameSpace
= kNameSpaceID_None
;
1549 nsAutoString
contentString(data
.mContent
.mString
);
1551 PRInt32 barIndex
= contentString
.FindChar('|'); // CSS namespace delimiter
1552 if (-1 != barIndex
) {
1553 nsAutoString nameSpaceVal
;
1554 contentString
.Left(nameSpaceVal
, barIndex
);
1556 attrNameSpace
= nameSpaceVal
.ToInteger(&error
, 10);
1557 contentString
.Cut(0, barIndex
+ 1);
1558 if (contentString
.Length()) {
1559 if (mDocument
->IsHTML() && aParentContent
->IsHTML()) {
1560 ToLowerCase(contentString
);
1562 attrName
= do_GetAtom(contentString
);
1566 if (mDocument
->IsHTML() && aParentContent
->IsHTML()) {
1567 ToLowerCase(contentString
);
1569 attrName
= do_GetAtom(contentString
);
1576 nsCOMPtr
<nsIContent
> content
;
1577 NS_NewAttributeContent(mDocument
->NodeInfoManager(),
1578 attrNameSpace
, attrName
, getter_AddRefs(content
));
1579 return content
.forget();
1582 case eStyleContentType_Counter
:
1583 case eStyleContentType_Counters
:
1585 nsCSSValue::Array
* counters
= data
.mContent
.mCounters
;
1586 nsCounterList
* counterList
= mCounterManager
.CounterListFor(
1587 nsDependentString(counters
->Item(0).GetStringBufferValue()));
1591 nsCounterUseNode
* node
=
1592 new nsCounterUseNode(counters
, aContentIndex
,
1593 type
== eStyleContentType_Counters
);
1597 nsGenConInitializer
* initializer
=
1598 new nsGenConInitializer(node
, counterList
,
1599 &nsCSSFrameConstructor::CountersDirty
);
1600 return CreateGenConTextNode(aState
, EmptyString(), &node
->mText
,
1604 case eStyleContentType_Image
:
1605 NS_NOTREACHED("handled by if above");
1608 case eStyleContentType_OpenQuote
:
1609 case eStyleContentType_CloseQuote
:
1610 case eStyleContentType_NoOpenQuote
:
1611 case eStyleContentType_NoCloseQuote
:
1614 new nsQuoteNode(type
, aContentIndex
);
1618 nsGenConInitializer
* initializer
=
1619 new nsGenConInitializer(node
, &mQuoteList
,
1620 &nsCSSFrameConstructor::QuotesDirty
);
1621 return CreateGenConTextNode(aState
, EmptyString(), &node
->mText
,
1625 case eStyleContentType_AltContent
:
1627 // Use the "alt" attribute; if that fails and the node is an HTML
1628 // <input>, try the value attribute and then fall back to some default
1629 // localized text we have.
1630 // XXX what if the 'alt' attribute is added later, how will we
1631 // detect that and do the right thing here?
1632 if (aParentContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::alt
)) {
1633 nsCOMPtr
<nsIContent
> content
;
1634 NS_NewAttributeContent(mDocument
->NodeInfoManager(),
1635 kNameSpaceID_None
, nsGkAtoms::alt
, getter_AddRefs(content
));
1636 return content
.forget();
1639 if (aParentContent
->IsHTML() &&
1640 aParentContent
->NodeInfo()->Equals(nsGkAtoms::input
)) {
1641 if (aParentContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::value
)) {
1642 nsCOMPtr
<nsIContent
> content
;
1643 NS_NewAttributeContent(mDocument
->NodeInfoManager(),
1644 kNameSpaceID_None
, nsGkAtoms::value
, getter_AddRefs(content
));
1645 return content
.forget();
1649 nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES
,
1651 return CreateGenConTextNode(aState
, temp
, nsnull
, nsnull
);
1662 * aParentFrame - the frame that should be the parent of the generated
1663 * content. This is the frame for the corresponding content node,
1664 * which must not be a leaf frame.
1666 * Any items created are added to aItems.
1668 * We create an XML element (tag _moz_generated_content_before or
1669 * _moz_generated_content_after) representing the pseudoelement. We
1670 * create a DOM node for each 'content' item and make those nodes the
1671 * children of the XML element. Then we create a frame subtree for
1672 * the XML element as if it were a regular child of
1673 * aParentFrame/aParentContent, giving the XML element the ::before or
1677 nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState
& aState
,
1678 nsIFrame
* aParentFrame
,
1679 nsIContent
* aParentContent
,
1680 nsStyleContext
* aStyleContext
,
1681 nsCSSPseudoElements::Type aPseudoElement
,
1682 FrameConstructionItemList
& aItems
)
1684 // XXXbz is this ever true?
1685 if (!aParentContent
->IsElement()) {
1686 NS_ERROR("Bogus generated content parent");
1690 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
1692 // Probe for the existence of the pseudo-element
1693 nsRefPtr
<nsStyleContext
> pseudoStyleContext
;
1694 pseudoStyleContext
=
1695 styleSet
->ProbePseudoElementStyle(aParentContent
->AsElement(),
1698 if (!pseudoStyleContext
)
1700 // |ProbePseudoStyleFor| checked the 'display' property and the
1701 // |ContentCount()| of the 'content' property for us.
1702 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
1703 nsIAtom
* elemName
= aPseudoElement
== nsCSSPseudoElements::ePseudo_before
?
1704 nsGkAtoms::mozgeneratedcontentbefore
: nsGkAtoms::mozgeneratedcontentafter
;
1705 nodeInfo
= mDocument
->NodeInfoManager()->GetNodeInfo(elemName
, nsnull
,
1707 nsCOMPtr
<nsIContent
> container
;
1708 nsresult rv
= NS_NewXMLElement(getter_AddRefs(container
), nodeInfo
.forget());
1711 container
->SetNativeAnonymous();
1713 rv
= container
->BindToTree(mDocument
, aParentContent
, aParentContent
, PR_TRUE
);
1714 if (NS_FAILED(rv
)) {
1715 container
->UnbindFromTree();
1719 PRUint32 contentCount
= pseudoStyleContext
->GetStyleContent()->ContentCount();
1720 for (PRUint32 contentIndex
= 0; contentIndex
< contentCount
; contentIndex
++) {
1721 nsCOMPtr
<nsIContent
> content
=
1722 CreateGeneratedContent(aState
, aParentContent
, pseudoStyleContext
,
1725 container
->AppendChildTo(content
, PR_FALSE
);
1729 AddFrameConstructionItemsInternal(aState
, container
, aParentFrame
, elemName
,
1730 kNameSpaceID_None
, PR_TRUE
,
1732 ITEM_IS_GENERATED_CONTENT
, aItems
);
1735 /****************************************************
1736 ** BEGIN TABLE SECTION
1737 ****************************************************/
1739 // The term pseudo frame is being used instead of anonymous frame, since anonymous
1740 // frame has been used elsewhere to refer to frames that have generated content
1743 IsTableRelated(nsIAtom
* aParentType
)
1746 nsGkAtoms::tableOuterFrame
== aParentType
||
1747 nsGkAtoms::tableFrame
== aParentType
||
1748 nsGkAtoms::tableRowGroupFrame
== aParentType
||
1749 nsGkAtoms::tableRowFrame
== aParentType
||
1750 nsGkAtoms::tableCaptionFrame
== aParentType
||
1751 nsGkAtoms::tableColGroupFrame
== aParentType
||
1752 nsGkAtoms::tableColFrame
== aParentType
||
1753 IS_TABLE_CELL(aParentType
);
1756 // Return whether the given frame is a table pseudo-frame. Note that
1757 // cell-content and table-outer frames have pseudo-types, but are always
1758 // created, even for non-anonymous cells and tables respectively. So for those
1759 // we have to examine the cell or table frame to see whether it's a pseudo
1760 // frame. In particular, a lone table caption will have an outer table as its
1761 // parent, but will also trigger construction of an empty inner table, which
1762 // will be the one we can examine to see whether the outer was a pseudo-frame.
1764 IsTablePseudo(nsIFrame
* aFrame
)
1766 nsIAtom
* pseudoType
= aFrame
->GetStyleContext()->GetPseudo();
1767 return pseudoType
&&
1768 (pseudoType
== nsCSSAnonBoxes::table
||
1769 pseudoType
== nsCSSAnonBoxes::inlineTable
||
1770 pseudoType
== nsCSSAnonBoxes::tableColGroup
||
1771 pseudoType
== nsCSSAnonBoxes::tableRowGroup
||
1772 pseudoType
== nsCSSAnonBoxes::tableRow
||
1773 pseudoType
== nsCSSAnonBoxes::tableCell
||
1774 (pseudoType
== nsCSSAnonBoxes::cellContent
&&
1775 aFrame
->GetParent()->GetStyleContext()->GetPseudo() ==
1776 nsCSSAnonBoxes::tableCell
) ||
1777 (pseudoType
== nsCSSAnonBoxes::tableOuter
&&
1778 (aFrame
->GetFirstChild(nsnull
)->GetStyleContext()->GetPseudo() ==
1779 nsCSSAnonBoxes::table
||
1780 aFrame
->GetFirstChild(nsnull
)->GetStyleContext()->GetPseudo() ==
1781 nsCSSAnonBoxes::inlineTable
)));
1785 nsCSSFrameConstructor::ParentType
1786 nsCSSFrameConstructor::GetParentType(nsIAtom
* aFrameType
)
1788 if (aFrameType
== nsGkAtoms::tableFrame
) {
1791 if (aFrameType
== nsGkAtoms::tableRowGroupFrame
) {
1792 return eTypeRowGroup
;
1794 if (aFrameType
== nsGkAtoms::tableRowFrame
) {
1797 if (aFrameType
== nsGkAtoms::tableColGroupFrame
) {
1798 return eTypeColGroup
;
1805 AdjustCaptionParentFrame(nsIFrame
* aParentFrame
)
1807 if (nsGkAtoms::tableFrame
== aParentFrame
->GetType()) {
1808 return aParentFrame
->GetParent();;
1810 return aParentFrame
;
1814 * If the parent frame is a |tableFrame| and the child is a
1815 * |captionFrame|, then we want to insert the frames beneath the
1816 * |tableFrame|'s parent frame. Returns |PR_TRUE| if the parent frame
1817 * needed to be fixed up.
1820 GetCaptionAdjustedParent(nsIFrame
* aParentFrame
,
1821 const nsIFrame
* aChildFrame
,
1822 nsIFrame
** aAdjParentFrame
)
1824 *aAdjParentFrame
= aParentFrame
;
1825 PRBool haveCaption
= PR_FALSE
;
1827 if (nsGkAtoms::tableCaptionFrame
== aChildFrame
->GetType()) {
1828 haveCaption
= PR_TRUE
;
1829 *aAdjParentFrame
= AdjustCaptionParentFrame(aParentFrame
);
1835 nsCSSFrameConstructor::AdjustParentFrame(nsIFrame
* & aParentFrame
,
1836 const FrameConstructionData
* aFCData
,
1837 nsStyleContext
* aStyleContext
)
1839 NS_PRECONDITION(aStyleContext
, "Must have child's style context");
1840 NS_PRECONDITION(aFCData
, "Must have frame construction data");
1842 PRBool tablePart
= ((aFCData
->mBits
& FCDATA_IS_TABLE_PART
) != 0);
1844 if (tablePart
&& aStyleContext
->GetStyleDisplay()->mDisplay
==
1845 NS_STYLE_DISPLAY_TABLE_CAPTION
) {
1846 aParentFrame
= AdjustCaptionParentFrame(aParentFrame
);
1850 // Pull all the captions present in aItems out into aCaptions
1852 PullOutCaptionFrames(nsFrameItems
& aItems
, nsFrameItems
& aCaptions
)
1854 nsIFrame
*child
= aItems
.FirstChild();
1856 nsIFrame
*nextSibling
= child
->GetNextSibling();
1857 if (nsGkAtoms::tableCaptionFrame
== child
->GetType()) {
1858 aItems
.RemoveFrame(child
);
1859 aCaptions
.AddChild(child
);
1861 child
= nextSibling
;
1866 // Construct the outer, inner table frames and the children frames for the table.
1867 // XXX Page break frames for pseudo table frames are not constructed to avoid the risk
1868 // associated with revising the pseudo frame mechanism. The long term solution
1869 // of having frames handle page-break-before/after will solve the problem.
1871 nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState
& aState
,
1872 FrameConstructionItem
& aItem
,
1873 nsIFrame
* aParentFrame
,
1874 const nsStyleDisplay
* aDisplay
,
1875 nsFrameItems
& aFrameItems
,
1876 nsIFrame
** aNewFrame
)
1878 NS_PRECONDITION(aDisplay
->mDisplay
== NS_STYLE_DISPLAY_TABLE
||
1879 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_INLINE_TABLE
,
1882 nsIContent
* const content
= aItem
.mContent
;
1883 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
1884 const PRUint32 nameSpaceID
= aItem
.mNameSpaceID
;
1886 nsresult rv
= NS_OK
;
1888 // create the pseudo SC for the outer table as a child of the inner SC
1889 nsRefPtr
<nsStyleContext
> outerStyleContext
;
1890 outerStyleContext
= mPresShell
->StyleSet()->
1891 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::tableOuter
, styleContext
);
1893 // Create the outer table frame which holds the caption and inner table frame
1896 if (kNameSpaceID_MathML
== nameSpaceID
)
1897 newFrame
= NS_NewMathMLmtableOuterFrame(mPresShell
, outerStyleContext
);
1900 newFrame
= NS_NewTableOuterFrame(mPresShell
, outerStyleContext
);
1902 nsIFrame
* geometricParent
=
1903 aState
.GetGeometricParent(outerStyleContext
->GetStyleDisplay(),
1906 // Init the table outer frame and see if we need to create a view, e.g.
1907 // the frame is absolutely positioned
1908 InitAndRestoreFrame(aState
, content
, geometricParent
, nsnull
, newFrame
);
1909 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
1911 // Create the inner table frame
1912 nsIFrame
* innerFrame
;
1914 if (kNameSpaceID_MathML
== nameSpaceID
)
1915 innerFrame
= NS_NewMathMLmtableFrame(mPresShell
, styleContext
);
1918 innerFrame
= NS_NewTableFrame(mPresShell
, styleContext
);
1920 InitAndRestoreFrame(aState
, content
, newFrame
, nsnull
, innerFrame
);
1922 // Put the newly created frames into the right child list
1923 SetInitialSingleChild(newFrame
, innerFrame
);
1925 rv
= aState
.AddChild(newFrame
, aFrameItems
, content
, styleContext
,
1927 if (NS_FAILED(rv
)) {
1931 if (!mRootElementFrame
) {
1932 // The frame we're constructing will be the root element frame.
1933 // Set mRootElementFrame before processing children.
1934 mRootElementFrame
= newFrame
;
1937 nsFrameItems childItems
;
1938 if (aItem
.mFCData
->mBits
& FCDATA_USE_CHILD_ITEMS
) {
1939 rv
= ConstructFramesFromItemList(aState
, aItem
.mChildItems
,
1940 innerFrame
, childItems
);
1942 rv
= ProcessChildren(aState
, content
, styleContext
, innerFrame
,
1943 PR_TRUE
, childItems
, PR_FALSE
, aItem
.mPendingBinding
);
1945 // XXXbz what about cleaning up?
1946 if (NS_FAILED(rv
)) return rv
;
1948 nsFrameItems captionItems
;
1949 PullOutCaptionFrames(childItems
, captionItems
);
1951 // Set the inner table frame's initial primary list
1952 innerFrame
->SetInitialChildList(nsnull
, childItems
);
1954 // Set the outer table frame's secondary childlist lists
1955 if (captionItems
.NotEmpty()) {
1956 newFrame
->SetInitialChildList(nsGkAtoms::captionList
, captionItems
);
1959 *aNewFrame
= newFrame
;
1964 nsCSSFrameConstructor::ConstructTableRow(nsFrameConstructorState
& aState
,
1965 FrameConstructionItem
& aItem
,
1966 nsIFrame
* aParentFrame
,
1967 const nsStyleDisplay
* aDisplay
,
1968 nsFrameItems
& aFrameItems
,
1969 nsIFrame
** aNewFrame
)
1971 NS_PRECONDITION(aDisplay
->mDisplay
== NS_STYLE_DISPLAY_TABLE_ROW
,
1973 nsIContent
* const content
= aItem
.mContent
;
1974 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
1975 const PRUint32 nameSpaceID
= aItem
.mNameSpaceID
;
1979 if (kNameSpaceID_MathML
== nameSpaceID
)
1980 newFrame
= NS_NewMathMLmtrFrame(mPresShell
, styleContext
);
1983 newFrame
= NS_NewTableRowFrame(mPresShell
, styleContext
);
1985 if (NS_UNLIKELY(!newFrame
)) {
1986 return NS_ERROR_OUT_OF_MEMORY
;
1988 InitAndRestoreFrame(aState
, content
, aParentFrame
, nsnull
, newFrame
);
1989 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
1991 nsFrameItems childItems
;
1993 if (aItem
.mFCData
->mBits
& FCDATA_USE_CHILD_ITEMS
) {
1994 rv
= ConstructFramesFromItemList(aState
, aItem
.mChildItems
, newFrame
,
1997 rv
= ProcessChildren(aState
, content
, styleContext
, newFrame
,
1998 PR_TRUE
, childItems
, PR_FALSE
, aItem
.mPendingBinding
);
2000 if (NS_FAILED(rv
)) return rv
;
2002 newFrame
->SetInitialChildList(nsnull
, childItems
);
2003 aFrameItems
.AddChild(newFrame
);
2004 *aNewFrame
= newFrame
;
2010 nsCSSFrameConstructor::ConstructTableCol(nsFrameConstructorState
& aState
,
2011 FrameConstructionItem
& aItem
,
2012 nsIFrame
* aParentFrame
,
2013 const nsStyleDisplay
* aStyleDisplay
,
2014 nsFrameItems
& aFrameItems
,
2015 nsIFrame
** aNewFrame
)
2017 nsIContent
* const content
= aItem
.mContent
;
2018 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
2020 nsTableColFrame
* colFrame
= NS_NewTableColFrame(mPresShell
, styleContext
);
2021 if (NS_UNLIKELY(!colFrame
)) {
2022 return NS_ERROR_OUT_OF_MEMORY
;
2024 InitAndRestoreFrame(aState
, content
, aParentFrame
, nsnull
, colFrame
);
2026 NS_ASSERTION(colFrame
->GetStyleContext() == styleContext
,
2027 "Unexpected style context");
2029 aFrameItems
.AddChild(colFrame
);
2030 *aNewFrame
= colFrame
;
2032 // construct additional col frames if the col frame has a span > 1
2033 PRInt32 span
= colFrame
->GetSpan();
2034 for (PRInt32 spanX
= 1; spanX
< span
; spanX
++) {
2035 nsTableColFrame
* newCol
= NS_NewTableColFrame(mPresShell
, styleContext
);
2036 if (NS_UNLIKELY(!newCol
)) {
2037 return NS_ERROR_OUT_OF_MEMORY
;
2039 InitAndRestoreFrame(aState
, content
, aParentFrame
, nsnull
, newCol
,
2041 aFrameItems
.LastChild()->SetNextContinuation(newCol
);
2042 newCol
->SetPrevContinuation(aFrameItems
.LastChild());
2043 aFrameItems
.AddChild(newCol
);
2044 newCol
->SetColType(eColAnonymousCol
);
2051 nsCSSFrameConstructor::ConstructTableCell(nsFrameConstructorState
& aState
,
2052 FrameConstructionItem
& aItem
,
2053 nsIFrame
* aParentFrame
,
2054 const nsStyleDisplay
* aDisplay
,
2055 nsFrameItems
& aFrameItems
,
2056 nsIFrame
** aNewFrame
)
2058 NS_PRECONDITION(aDisplay
->mDisplay
== NS_STYLE_DISPLAY_TABLE_CELL
,
2061 nsIContent
* const content
= aItem
.mContent
;
2062 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
2063 const PRUint32 nameSpaceID
= aItem
.mNameSpaceID
;
2065 PRBool borderCollapse
= IsBorderCollapse(aParentFrame
);
2068 // <mtable> is border separate in mathml.css and the MathML code doesn't implement
2069 // border collapse. For those users who style <mtable> with border collapse,
2070 // give them the default non-MathML table frames that understand border collapse.
2071 // This won't break us because MathML table frames are all subclasses of the default
2072 // table code, and so we can freely mix <mtable> with <mtr> or <tr>, <mtd> or <td>.
2073 // What will happen is just that non-MathML frames won't understand MathML attributes
2074 // and will therefore miss the special handling that the MathML code does.
2075 if (kNameSpaceID_MathML
== nameSpaceID
&& !borderCollapse
)
2076 newFrame
= NS_NewMathMLmtdFrame(mPresShell
, styleContext
);
2079 // Warning: If you change this and add a wrapper frame around table cell
2080 // frames, make sure Bug 368554 doesn't regress!
2081 // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
2082 newFrame
= NS_NewTableCellFrame(mPresShell
, styleContext
, borderCollapse
);
2084 if (NS_UNLIKELY(!newFrame
)) {
2085 return NS_ERROR_OUT_OF_MEMORY
;
2088 // Initialize the table cell frame
2089 InitAndRestoreFrame(aState
, content
, aParentFrame
, nsnull
, newFrame
);
2090 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
2092 // Resolve pseudo style and initialize the body cell frame
2093 nsRefPtr
<nsStyleContext
> innerPseudoStyle
;
2094 innerPseudoStyle
= mPresShell
->StyleSet()->
2095 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::cellContent
, styleContext
);
2097 // Create a block frame that will format the cell's content
2099 nsIFrame
* cellInnerFrame
;
2101 if (kNameSpaceID_MathML
== nameSpaceID
) {
2102 cellInnerFrame
= NS_NewMathMLmtdInnerFrame(mPresShell
, innerPseudoStyle
);
2108 cellInnerFrame
= NS_NewBlockFormattingContext(mPresShell
, innerPseudoStyle
);
2112 if (NS_UNLIKELY(!cellInnerFrame
)) {
2113 newFrame
->Destroy();
2114 return NS_ERROR_OUT_OF_MEMORY
;
2117 InitAndRestoreFrame(aState
, content
, newFrame
, nsnull
, cellInnerFrame
);
2119 nsFrameItems childItems
;
2121 if (aItem
.mFCData
->mBits
& FCDATA_USE_CHILD_ITEMS
) {
2122 // Need to push ourselves as a float containing block.
2123 // XXXbz it might be nice to work on getting the parent
2124 // FrameConstructionItem down into ProcessChildren and just making use of
2125 // the push there, but that's a bit of work.
2126 nsFrameConstructorSaveState floatSaveState
;
2127 if (!isBlock
) { /* MathML case */
2128 aState
.PushFloatContainingBlock(nsnull
, floatSaveState
);
2130 aState
.PushFloatContainingBlock(cellInnerFrame
, floatSaveState
);
2133 rv
= ConstructFramesFromItemList(aState
, aItem
.mChildItems
, cellInnerFrame
,
2136 // Process the child content
2137 rv
= ProcessChildren(aState
, content
, styleContext
, cellInnerFrame
,
2138 PR_TRUE
, childItems
, isBlock
, aItem
.mPendingBinding
);
2141 if (NS_FAILED(rv
)) {
2143 // XXXbz kids of this stuff need to be cleaned up too!
2144 cellInnerFrame
->Destroy();
2145 newFrame
->Destroy();
2149 cellInnerFrame
->SetInitialChildList(nsnull
, childItems
);
2150 SetInitialSingleChild(newFrame
, cellInnerFrame
);
2151 aFrameItems
.AddChild(newFrame
);
2152 *aNewFrame
= newFrame
;
2157 static inline PRBool
2158 NeedFrameFor(const nsFrameConstructorState
& aState
,
2159 nsIFrame
* aParentFrame
,
2160 nsIContent
* aChildContent
)
2162 // XXX the GetContent() != aChildContent check is needed due to bug 135040.
2163 // Remove it once that's fixed.
2164 NS_PRECONDITION(!aChildContent
->GetPrimaryFrame() ||
2165 aState
.mCreatingExtraFrames
||
2166 aChildContent
->GetPrimaryFrame()->GetContent() != aChildContent
,
2167 "Why did we get called?");
2169 // don't create a whitespace frame if aParentFrame doesn't want it.
2170 // always create frames for children in generated content. counter(),
2171 // quotes, and attr() content can easily change dynamically and we don't
2172 // want to be reconstructing frames. It's not even clear that these
2173 // should be considered ignorable just because they evaluate to
2176 // We could handle all this in CreateNeededTablePseudos or some other place
2177 // after we build our frame construction items, but that would involve
2178 // creating frame construction items for whitespace kids of
2179 // eExcludesIgnorableWhitespace frames, where we know we'll be dropping them
2180 // all anyway, and involve an extra walk down the frame construction item
2182 if (!aParentFrame
->IsFrameOfType(nsIFrame::eExcludesIgnorableWhitespace
) ||
2183 aParentFrame
->IsGeneratedContentFrame() ||
2184 !aChildContent
->IsNodeOfType(nsINode::eTEXT
)) {
2188 aChildContent
->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE
|
2189 NS_REFRAME_IF_WHITESPACE
);
2190 return !aChildContent
->TextIsOnlyWhitespace();
2193 /***********************************************
2195 ***********************************************/
2197 static PRBool
CheckOverflow(nsPresContext
* aPresContext
,
2198 const nsStyleDisplay
* aDisplay
)
2200 if (aDisplay
->mOverflowX
== NS_STYLE_OVERFLOW_VISIBLE
)
2203 if (aDisplay
->mOverflowX
== NS_STYLE_OVERFLOW_CLIP
)
2204 aPresContext
->SetViewportOverflowOverride(NS_STYLE_OVERFLOW_HIDDEN
,
2205 NS_STYLE_OVERFLOW_HIDDEN
);
2207 aPresContext
->SetViewportOverflowOverride(aDisplay
->mOverflowX
,
2208 aDisplay
->mOverflowY
);
2213 * This checks the root element and the HTML BODY, if any, for an "overflow" property
2214 * that should be applied to the viewport. If one is found then we return the
2215 * element that we took the overflow from (which should then be treated as
2216 * "overflow:visible"), and we store the overflow style in the prescontext.
2217 * @return if scroll was propagated from some content node, the content node it
2218 * was propagated from.
2221 nsCSSFrameConstructor::PropagateScrollToViewport()
2224 nsPresContext
* presContext
= mPresShell
->GetPresContext();
2225 presContext
->SetViewportOverflowOverride(NS_STYLE_OVERFLOW_AUTO
,
2226 NS_STYLE_OVERFLOW_AUTO
);
2228 // We never mess with the viewport scroll state
2229 // when printing or in print preview
2230 if (presContext
->IsPaginated()) {
2234 Element
* docElement
= mDocument
->GetRootElement();
2236 // Check the style on the document root element
2237 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
2238 nsRefPtr
<nsStyleContext
> rootStyle
;
2239 rootStyle
= styleSet
->ResolveStyleFor(docElement
, nsnull
);
2243 if (CheckOverflow(presContext
, rootStyle
->GetStyleDisplay())) {
2244 // tell caller we stole the overflow style from the root element
2248 // Don't look in the BODY for non-HTML documents or HTML documents
2249 // with non-HTML roots
2250 // XXX this should be earlier; we shouldn't even look at the document root
2251 // for non-HTML documents. Fix this once we support explicit CSS styling
2253 // XXX what about XHTML?
2254 nsCOMPtr
<nsIDOMHTMLDocument
> htmlDoc(do_QueryInterface(mDocument
));
2255 if (!htmlDoc
|| !docElement
->IsHTML()) {
2259 nsCOMPtr
<nsIDOMHTMLElement
> body
;
2260 htmlDoc
->GetBody(getter_AddRefs(body
));
2261 nsCOMPtr
<nsIContent
> bodyElement
= do_QueryInterface(body
);
2264 !bodyElement
->NodeInfo()->Equals(nsGkAtoms::body
)) {
2265 // The body is not a <body> tag, it's a <frameset>.
2269 nsRefPtr
<nsStyleContext
> bodyStyle
;
2270 bodyStyle
= styleSet
->ResolveStyleFor(bodyElement
->AsElement(), rootStyle
);
2275 if (CheckOverflow(presContext
, bodyStyle
->GetStyleDisplay())) {
2276 // tell caller we stole the overflow style from the body element
2284 nsCSSFrameConstructor::ConstructDocElementFrame(Element
* aDocElement
,
2285 nsILayoutHistoryState
* aFrameState
,
2286 nsIFrame
** aNewFrame
)
2288 NS_PRECONDITION(mFixedContainingBlock
,
2289 "No viewport? Someone forgot to call ConstructRootFrame!");
2290 NS_PRECONDITION(mFixedContainingBlock
== mPresShell
->FrameManager()->GetRootFrame(),
2291 "Unexpected mFixedContainingBlock");
2292 NS_PRECONDITION(!mDocElementContainingBlock
,
2293 "Shouldn't have a doc element containing block here");
2295 *aNewFrame
= nsnull
;
2297 // Make sure to call PropagateScrollToViewport before
2298 // SetUpDocElementContainingBlock, since it sets up our scrollbar state
2300 nsIContent
* propagatedScrollFrom
= PropagateScrollToViewport();
2302 SetUpDocElementContainingBlock(aDocElement
);
2304 NS_ASSERTION(mDocElementContainingBlock
, "Should have parent by now");
2306 nsFrameConstructorState
state(mPresShell
, mFixedContainingBlock
, nsnull
,
2307 nsnull
, aFrameState
);
2309 // XXXbz why, exactly?
2310 if (!mTempFrameTreeState
)
2311 state
.mPresShell
->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState
));
2313 // Make sure that we'll handle restyles for this document element in
2314 // the future. We need this, because the document element might
2315 // have stale restyle bits from a previous frame constructor for
2316 // this document. Unlike in AddFrameConstructionItems, it's safe to
2317 // unset all element restyle flags, since we don't have any
2319 aDocElement
->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS
);
2321 // --------- CREATE AREA OR BOX FRAME -------
2322 nsRefPtr
<nsStyleContext
> styleContext
;
2323 styleContext
= mPresShell
->StyleSet()->ResolveStyleFor(aDocElement
,
2326 const nsStyleDisplay
* display
= styleContext
->GetStyleDisplay();
2328 // Ensure that our XBL bindings are installed.
2329 if (display
->mBinding
) {
2330 // Get the XBL loader.
2332 PRBool resolveStyle
;
2334 nsIXBLService
* xblService
= GetXBLService();
2336 return NS_ERROR_FAILURE
;
2338 nsRefPtr
<nsXBLBinding
> binding
;
2339 rv
= xblService
->LoadBindings(aDocElement
, display
->mBinding
->mURI
,
2340 display
->mBinding
->mOriginPrincipal
,
2341 PR_FALSE
, getter_AddRefs(binding
),
2343 if (NS_FAILED(rv
) && rv
!= NS_ERROR_XBL_BLOCKED
)
2344 return NS_OK
; // Binding will load asynchronously.
2347 // For backwards compat, keep firing the root's constructor
2348 // after all of its kids' constructors. So tell the binding
2349 // manager about it right now.
2350 mDocument
->BindingManager()->AddToAttachedQueue(binding
);
2354 styleContext
= mPresShell
->StyleSet()->ResolveStyleFor(aDocElement
,
2356 display
= styleContext
->GetStyleDisplay();
2360 // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2363 NS_ASSERTION(!display
->IsScrollableOverflow() ||
2364 state
.mPresContext
->IsPaginated() ||
2365 propagatedScrollFrom
== aDocElement
,
2366 "Scrollbars should have been propagated to the viewport");
2369 if (NS_UNLIKELY(display
->mDisplay
== NS_STYLE_DISPLAY_NONE
)) {
2370 state
.mFrameManager
->SetUndisplayedContent(aDocElement
, styleContext
);
2374 nsFrameConstructorSaveState absoluteSaveState
;
2375 if (mHasRootAbsPosContainingBlock
) {
2376 // Push the absolute containing block now so we can absolutely position
2378 state
.PushAbsoluteContainingBlock(mDocElementContainingBlock
,
2384 // The rules from CSS 2.1, section 9.2.4, have already been applied
2385 // by the style system, so we can assume that display->mDisplay is
2386 // either NONE, BLOCK, or TABLE.
2388 // contentFrame is the primary frame for the root element. *aNewFrame
2389 // is the frame that will be the child of the initial containing block.
2390 // These are usually the same frame but they can be different, in
2391 // particular if the root frame is positioned, in which case
2392 // contentFrame is the out-of-flow frame and *aNewFrame is the
2394 nsIFrame
* contentFrame
;
2395 PRBool processChildren
= PR_FALSE
;
2397 // Check whether we need to build a XUL box or SVG root frame
2399 if (aDocElement
->IsXUL()) {
2400 contentFrame
= NS_NewDocElementBoxFrame(mPresShell
, styleContext
);
2401 if (NS_UNLIKELY(!contentFrame
)) {
2402 return NS_ERROR_OUT_OF_MEMORY
;
2404 InitAndRestoreFrame(state
, aDocElement
, mDocElementContainingBlock
, nsnull
,
2406 *aNewFrame
= contentFrame
;
2407 processChildren
= PR_TRUE
;
2412 if (aDocElement
->GetNameSpaceID() == kNameSpaceID_SVG
) {
2413 if (aDocElement
->Tag() == nsGkAtoms::svg
&& NS_SVGEnabled()) {
2414 contentFrame
= NS_NewSVGOuterSVGFrame(mPresShell
, styleContext
);
2415 if (NS_UNLIKELY(!contentFrame
)) {
2416 return NS_ERROR_OUT_OF_MEMORY
;
2418 InitAndRestoreFrame(state
, aDocElement
,
2419 state
.GetGeometricParent(display
,
2420 mDocElementContainingBlock
),
2421 nsnull
, contentFrame
);
2423 // AddChild takes care of transforming the frame tree for fixed-pos
2424 // or abs-pos situations
2425 nsFrameItems frameItems
;
2426 rv
= state
.AddChild(contentFrame
, frameItems
, aDocElement
,
2427 styleContext
, mDocElementContainingBlock
);
2428 if (NS_FAILED(rv
) || frameItems
.IsEmpty()) {
2431 *aNewFrame
= frameItems
.FirstChild();
2432 processChildren
= PR_TRUE
;
2434 // See if we need to create a view
2435 nsHTMLContainerFrame::CreateViewForFrame(contentFrame
, PR_FALSE
);
2437 return NS_ERROR_FAILURE
;
2443 PRBool docElemIsTable
= (display
->mDisplay
== NS_STYLE_DISPLAY_TABLE
);
2444 if (docElemIsTable
) {
2445 // We're going to call the right function ourselves, so no need to give a
2446 // function to this FrameConstructionData.
2448 // XXXbz on the other hand, if we converted this whole function to
2449 // FrameConstructionData/Item, then we'd need the right function
2450 // here... but would probably be able to get away with less code in this
2451 // function in general.
2452 // Use a null PendingBinding, since our binding is not in fact pending.
2453 static const FrameConstructionData rootTableData
= FCDATA_DECL(0, nsnull
);
2454 nsRefPtr
<nsStyleContext
> extraRef(styleContext
);
2455 FrameConstructionItem
item(&rootTableData
, aDocElement
,
2456 aDocElement
->Tag(), kNameSpaceID_None
,
2457 nsnull
, extraRef
.forget(), PR_TRUE
);
2459 nsFrameItems frameItems
;
2460 // if the document is a table then just populate it.
2461 rv
= ConstructTable(state
, item
, mDocElementContainingBlock
,
2462 styleContext
->GetStyleDisplay(),
2463 frameItems
, &contentFrame
);
2466 if (!contentFrame
|| frameItems
.IsEmpty())
2467 return NS_ERROR_FAILURE
;
2468 *aNewFrame
= frameItems
.FirstChild();
2469 NS_ASSERTION(frameItems
.OnlyChild(), "multiple root element frames");
2471 contentFrame
= NS_NewBlockFrame(mPresShell
, styleContext
,
2472 NS_BLOCK_FLOAT_MGR
|NS_BLOCK_MARGIN_ROOT
);
2474 return NS_ERROR_OUT_OF_MEMORY
;
2475 nsFrameItems frameItems
;
2476 // Use a null PendingBinding, since our binding is not in fact pending.
2477 rv
= ConstructBlock(state
, display
, aDocElement
,
2478 state
.GetGeometricParent(display
,
2479 mDocElementContainingBlock
),
2480 mDocElementContainingBlock
, styleContext
,
2481 &contentFrame
, frameItems
, display
->IsPositioned(),
2483 if (NS_FAILED(rv
) || frameItems
.IsEmpty())
2485 *aNewFrame
= frameItems
.FirstChild();
2486 NS_ASSERTION(frameItems
.OnlyChild(), "multiple root element frames");
2490 // set the primary frame
2491 aDocElement
->SetPrimaryFrame(contentFrame
);
2493 NS_ASSERTION(processChildren
? !mRootElementFrame
:
2494 mRootElementFrame
== contentFrame
,
2495 "unexpected mRootElementFrame");
2496 mRootElementFrame
= contentFrame
;
2498 // Figure out which frame has the main style for the document element,
2499 // assigning it to mRootElementStyleFrame.
2500 // Backgrounds should be propagated from that frame to the viewport.
2502 contentFrame
->GetParentStyleContextFrame(state
.mPresContext
,
2503 &mRootElementStyleFrame
, &isChild
);
2505 mRootElementStyleFrame
= mRootElementFrame
;
2508 if (processChildren
) {
2509 // Still need to process the child content
2510 nsFrameItems childItems
;
2512 NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame
),
2513 "Only XUL and SVG frames should reach here");
2514 // Use a null PendingBinding, since our binding is not in fact pending.
2515 ProcessChildren(state
, aDocElement
, styleContext
, contentFrame
, PR_TRUE
,
2516 childItems
, PR_FALSE
, nsnull
);
2518 // Set the initial child lists
2519 contentFrame
->SetInitialChildList(nsnull
, childItems
);
2522 SetInitialSingleChild(mDocElementContainingBlock
, *aNewFrame
);
2529 nsCSSFrameConstructor::ConstructRootFrame(nsIFrame
** aNewFrame
)
2531 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell
->GetPresContext(), FrameC
);
2532 NS_PRECONDITION(aNewFrame
, "null out param");
2534 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
2536 // Set up our style rule observer.
2537 // XXXbz wouldn't this make more sense as part of presshell init?
2539 styleSet
->SetBindingManager(mDocument
->BindingManager());
2542 // --------- BUILD VIEWPORT -----------
2543 nsIFrame
* viewportFrame
= nsnull
;
2544 nsRefPtr
<nsStyleContext
> viewportPseudoStyle
;
2546 viewportPseudoStyle
=
2547 styleSet
->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::viewport
, nsnull
);
2549 viewportFrame
= NS_NewViewportFrame(mPresShell
, viewportPseudoStyle
);
2551 // XXXbz do we _have_ to pass a null content pointer to that frame?
2552 // Would it really kill us to pass in the root element or something?
2553 // What would that break?
2554 viewportFrame
->Init(nsnull
, nsnull
, nsnull
);
2556 // Bind the viewport frame to the root view
2558 mPresShell
->GetViewManager()->GetRootView(rootView
);
2559 viewportFrame
->SetView(rootView
);
2561 nsContainerFrame::SyncFrameViewProperties(mPresShell
->GetPresContext(), viewportFrame
,
2562 viewportPseudoStyle
, rootView
);
2563 nsContainerFrame::SyncWindowProperties(mPresShell
->GetPresContext(), viewportFrame
,
2566 // The viewport is the containing block for 'fixed' elements
2567 mFixedContainingBlock
= viewportFrame
;
2569 *aNewFrame
= viewportFrame
;
2574 nsCSSFrameConstructor::SetUpDocElementContainingBlock(nsIContent
* aDocElement
)
2576 NS_PRECONDITION(aDocElement
, "No element?");
2577 NS_PRECONDITION(!aDocElement
->GetParent(), "Not root content?");
2578 NS_PRECONDITION(aDocElement
->GetCurrentDoc(), "Not in a document?");
2579 NS_PRECONDITION(aDocElement
->GetCurrentDoc()->GetRootElement() ==
2580 aDocElement
, "Not the root of the document?");
2583 how the root frame hierarchy should look
2585 Galley presentation, non-XUL, with scrolling (i.e. not a frameset):
2587 ViewportFrame [fixed-cb]
2589 nsCanvasFrame [abs-cb]
2590 root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2591 nsTableOuterFrame, nsPlaceholderFrame)
2593 Galley presentation, non-XUL, without scrolling (i.e. a frameset):
2595 ViewportFrame [fixed-cb]
2596 nsCanvasFrame [abs-cb]
2597 root element frame (nsBlockFrame)
2599 Galley presentation, XUL
2601 ViewportFrame [fixed-cb]
2603 root element frame (nsDocElementBoxFrame)
2605 Print presentation, non-XUL
2608 nsSimplePageSequenceFrame
2609 nsPageFrame [fixed-cb]
2611 nsCanvasFrame [abs-cb]
2612 root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2613 nsTableOuterFrame, nsPlaceholderFrame)
2615 Print-preview presentation, non-XUL
2619 nsSimplePageSequenceFrame
2620 nsPageFrame [fixed-cb]
2622 nsCanvasFrame [abs-cb]
2623 root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2624 nsTableOuterFrame, nsPlaceholderFrame)
2626 Print/print preview of XUL is not supported.
2627 [fixed-cb]: the default containing block for fixed-pos content
2628 [abs-cb]: the default containing block for abs-pos content
2630 Meaning of nsCSSFrameConstructor fields:
2631 mRootElementFrame is "root element frame". This is the primary frame for
2633 mDocElementContainingBlock is the parent of mRootElementFrame
2634 (i.e. nsCanvasFrame or nsRootBoxFrame)
2635 mFixedContainingBlock is the [fixed-cb]
2636 mGfxScrollFrame is the nsHTMLScrollFrame mentioned above, or null if there isn't one
2637 mPageSequenceFrame is the nsSimplePageSequenceFrame, or null if there isn't one
2640 // --------- CREATE ROOT FRAME -------
2643 // Create the root frame. The document element's frame is a child of the
2646 // The root frame serves two purposes:
2647 // - reserves space for any margins needed for the document element's frame
2648 // - renders the document element's background. This ensures the background covers
2649 // the entire canvas as specified by the CSS2 spec
2651 nsPresContext
* presContext
= mPresShell
->GetPresContext();
2652 PRBool isPaginated
= presContext
->IsRootPaginatedDocument();
2653 nsIFrame
* viewportFrame
= mFixedContainingBlock
;
2654 nsStyleContext
* viewportPseudoStyle
= viewportFrame
->GetStyleContext();
2656 nsIFrame
* rootFrame
= nsnull
;
2657 nsIAtom
* rootPseudo
;
2661 if (aDocElement
->IsXUL())
2663 // pass a temporary stylecontext, the correct one will be set later
2664 rootFrame
= NS_NewRootBoxFrame(mPresShell
, viewportPseudoStyle
);
2668 // pass a temporary stylecontext, the correct one will be set later
2669 rootFrame
= NS_NewCanvasFrame(mPresShell
, viewportPseudoStyle
);
2670 mHasRootAbsPosContainingBlock
= PR_TRUE
;
2673 rootPseudo
= nsCSSAnonBoxes::canvas
;
2674 mDocElementContainingBlock
= rootFrame
;
2676 // Create a page sequence frame
2677 rootFrame
= NS_NewSimplePageSequenceFrame(mPresShell
, viewportPseudoStyle
);
2678 mPageSequenceFrame
= rootFrame
;
2679 rootPseudo
= nsCSSAnonBoxes::pageSequence
;
2683 // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2685 // If the device supports scrolling (e.g., in galley mode on the screen and
2686 // for print-preview, but not when printing), then create a scroll frame that
2687 // will act as the scrolling mechanism for the viewport.
2688 // XXX Do we even need a viewport when printing to a printer?
2690 // As long as the docshell doesn't prohibit it, and the device supports
2691 // it, create a scroll frame that will act as the scolling mechanism for
2694 // Threre are three possible values stored in the docshell:
2695 // 1) nsIScrollable::Scrollbar_Never = no scrollbars
2696 // 2) nsIScrollable::Scrollbar_Auto = scrollbars appear if needed
2697 // 3) nsIScrollable::Scrollbar_Always = scrollbars always
2698 // Only need to create a scroll frame/view for cases 2 and 3.
2700 PRBool isHTML
= aDocElement
->IsHTML();
2701 PRBool isXUL
= PR_FALSE
;
2704 isXUL
= aDocElement
->IsXUL();
2707 // Never create scrollbars for XUL documents
2708 PRBool isScrollable
= !isXUL
;
2710 // Never create scrollbars for frameset documents.
2712 nsCOMPtr
<nsIHTMLDocument
> htmlDoc
= do_QueryInterface(mDocument
);
2713 if (htmlDoc
&& htmlDoc
->GetIsFrameset())
2714 isScrollable
= PR_FALSE
;
2718 isScrollable
= presContext
->HasPaginatedScrolling();
2721 // We no longer need to do overflow propagation here. It's taken care of
2722 // when we construct frames for the element whose overflow might be
2724 NS_ASSERTION(!isScrollable
|| !isXUL
,
2725 "XUL documents should never be scrollable - see above");
2727 nsIFrame
* newFrame
= rootFrame
;
2728 nsRefPtr
<nsStyleContext
> rootPseudoStyle
;
2729 // we must create a state because if the scrollbars are GFX it needs the
2730 // state to build the scrollbar frames.
2731 nsFrameConstructorState
state(mPresShell
, nsnull
, nsnull
, nsnull
);
2733 // Start off with the viewport as parent; we'll adjust it as needed.
2734 nsIFrame
* parentFrame
= viewportFrame
;
2736 nsStyleSet
* styleSet
= mPresShell
->StyleSet();
2737 // If paginated, make sure we don't put scrollbars in
2738 if (!isScrollable
) {
2739 rootPseudoStyle
= styleSet
->ResolveAnonymousBoxStyle(rootPseudo
,
2740 viewportPseudoStyle
);
2742 if (rootPseudo
== nsCSSAnonBoxes::canvas
) {
2743 rootPseudo
= nsCSSAnonBoxes::scrolledCanvas
;
2745 NS_ASSERTION(rootPseudo
== nsCSSAnonBoxes::pageSequence
,
2746 "Unknown root pseudo");
2747 rootPseudo
= nsCSSAnonBoxes::scrolledPageSequence
;
2750 // Build the frame. We give it the content we are wrapping which is the
2751 // document element, the root frame, the parent view port frame, and we
2752 // should get back the new frame and the scrollable view if one was
2755 // resolve a context for the scrollframe
2756 nsRefPtr
<nsStyleContext
> styleContext
;
2757 styleContext
= styleSet
->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::viewportScroll
,
2758 viewportPseudoStyle
);
2760 // Note that the viewport scrollframe is always built with
2761 // overflow:auto style. This forces the scroll frame to create
2762 // anonymous content for both scrollbars. This is necessary even
2763 // if the HTML or BODY elements are overriding the viewport
2764 // scroll style to 'hidden' --- dynamic style changes might put
2765 // scrollbars back on the viewport and we don't want to have to
2766 // reframe the viewport to create the scrollbar content.
2768 rootPseudoStyle
= BeginBuildingScrollFrame( state
,
2775 parentFrame
= newFrame
;
2776 mGfxScrollFrame
= newFrame
;
2779 rootFrame
->SetStyleContextWithoutNotification(rootPseudoStyle
);
2780 rootFrame
->Init(aDocElement
, parentFrame
, nsnull
);
2783 FinishBuildingScrollFrame(parentFrame
, rootFrame
);
2786 if (isPaginated
) { // paginated
2787 // Create the first page
2788 // Set the initial child lists
2789 nsIFrame
*pageFrame
, *canvasFrame
;
2790 ConstructPageFrame(mPresShell
, presContext
, rootFrame
, nsnull
,
2791 pageFrame
, canvasFrame
);
2792 SetInitialSingleChild(rootFrame
, pageFrame
);
2794 // The eventual parent of the document element frame.
2795 // XXX should this be set for every new page (in ConstructPageFrame)?
2796 mDocElementContainingBlock
= canvasFrame
;
2797 mHasRootAbsPosContainingBlock
= PR_TRUE
;
2800 if (viewportFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
) {
2801 SetInitialSingleChild(viewportFrame
, newFrame
);
2803 nsFrameList
newFrameList(newFrame
, newFrame
);
2804 viewportFrame
->AppendFrames(nsnull
, newFrameList
);
2811 nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell
* aPresShell
,
2812 nsPresContext
* aPresContext
,
2813 nsIFrame
* aParentFrame
,
2814 nsIFrame
* aPrevPageFrame
,
2815 nsIFrame
*& aPageFrame
,
2816 nsIFrame
*& aCanvasFrame
)
2818 nsStyleContext
* parentStyleContext
= aParentFrame
->GetStyleContext();
2819 nsStyleSet
*styleSet
= aPresShell
->StyleSet();
2821 nsRefPtr
<nsStyleContext
> pagePseudoStyle
;
2822 pagePseudoStyle
= styleSet
->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::page
,
2823 parentStyleContext
);
2825 aPageFrame
= NS_NewPageFrame(aPresShell
, pagePseudoStyle
);
2826 if (NS_UNLIKELY(!aPageFrame
))
2827 return NS_ERROR_OUT_OF_MEMORY
;
2829 // Initialize the page frame and force it to have a view. This makes printing of
2830 // the pages easier and faster.
2831 aPageFrame
->Init(nsnull
, aParentFrame
, aPrevPageFrame
);
2833 nsRefPtr
<nsStyleContext
> pageContentPseudoStyle
;
2834 pageContentPseudoStyle
=
2835 styleSet
->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::pageContent
,
2838 nsIFrame
* pageContentFrame
= NS_NewPageContentFrame(aPresShell
, pageContentPseudoStyle
);
2839 if (NS_UNLIKELY(!pageContentFrame
))
2840 return NS_ERROR_OUT_OF_MEMORY
;
2842 // Initialize the page content frame and force it to have a view. Also make it the
2843 // containing block for fixed elements which are repeated on every page.
2844 nsIFrame
* prevPageContentFrame
= nsnull
;
2845 if (aPrevPageFrame
) {
2846 prevPageContentFrame
= aPrevPageFrame
->GetFirstChild(nsnull
);
2847 NS_ASSERTION(prevPageContentFrame
, "missing page content frame");
2849 pageContentFrame
->Init(nsnull
, aPageFrame
, prevPageContentFrame
);
2850 SetInitialSingleChild(aPageFrame
, pageContentFrame
);
2851 mFixedContainingBlock
= pageContentFrame
;
2853 nsRefPtr
<nsStyleContext
> canvasPseudoStyle
;
2854 canvasPseudoStyle
= styleSet
->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::canvas
,
2855 pageContentPseudoStyle
);
2857 aCanvasFrame
= NS_NewCanvasFrame(aPresShell
, canvasPseudoStyle
);
2858 if (NS_UNLIKELY(!aCanvasFrame
))
2859 return NS_ERROR_OUT_OF_MEMORY
;
2861 nsIFrame
* prevCanvasFrame
= nsnull
;
2862 if (prevPageContentFrame
) {
2863 prevCanvasFrame
= prevPageContentFrame
->GetFirstChild(nsnull
);
2864 NS_ASSERTION(prevCanvasFrame
, "missing canvas frame");
2866 aCanvasFrame
->Init(nsnull
, pageContentFrame
, prevCanvasFrame
);
2867 SetInitialSingleChild(pageContentFrame
, aCanvasFrame
);
2874 nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell
* aPresShell
,
2875 nsIContent
* aContent
,
2877 nsStyleContext
* aStyleContext
,
2878 nsIFrame
* aParentFrame
,
2879 nsIFrame
* aPrevInFlow
,
2880 nsFrameState aTypeBit
,
2881 nsIFrame
** aPlaceholderFrame
)
2883 nsRefPtr
<nsStyleContext
> placeholderStyle
= aPresShell
->StyleSet()->
2884 ResolveStyleForNonElement(aStyleContext
->GetParent());
2886 // The placeholder frame gets a pseudo style context
2887 nsPlaceholderFrame
* placeholderFrame
=
2888 (nsPlaceholderFrame
*)NS_NewPlaceholderFrame(aPresShell
, placeholderStyle
,
2891 if (placeholderFrame
) {
2892 placeholderFrame
->Init(aContent
, aParentFrame
, aPrevInFlow
);
2894 // The placeholder frame has a pointer back to the out-of-flow frame
2895 placeholderFrame
->SetOutOfFlowFrame(aFrame
);
2897 aFrame
->AddStateBits(NS_FRAME_OUT_OF_FLOW
);
2899 // Add mapping from absolutely positioned frame to its placeholder frame
2900 aPresShell
->FrameManager()->RegisterPlaceholderFrame(placeholderFrame
);
2902 *aPlaceholderFrame
= static_cast<nsIFrame
*>(placeholderFrame
);
2907 return NS_ERROR_OUT_OF_MEMORY
;
2911 // Clears any lazy bits set in the range [aStartContent, aEndContent). If
2912 // aEndContent is null, that means to clear bits in all siblings starting with
2913 // aStartContent. aStartContent must not be null unless aEndContent is also
2914 // null. We do this so that when new children are inserted under elements whose
2915 // frame is a leaf the new children don't cause us to try to construct frames
2916 // for the existing children again.
2918 ClearLazyBits(nsIContent
* aStartContent
, nsIContent
* aEndContent
)
2920 NS_PRECONDITION(aStartContent
|| !aEndContent
,
2921 "Must have start child if we have an end child");
2922 for (nsIContent
* cur
= aStartContent
; cur
!= aEndContent
;
2923 cur
= cur
->GetNextSibling()) {
2924 cur
->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME
);
2929 nsCSSFrameConstructor::ConstructButtonFrame(nsFrameConstructorState
& aState
,
2930 FrameConstructionItem
& aItem
,
2931 nsIFrame
* aParentFrame
,
2932 const nsStyleDisplay
* aStyleDisplay
,
2933 nsFrameItems
& aFrameItems
,
2934 nsIFrame
** aNewFrame
)
2936 *aNewFrame
= nsnull
;
2937 nsIFrame
* buttonFrame
= nsnull
;
2938 nsIContent
* const content
= aItem
.mContent
;
2939 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
2941 if (nsGkAtoms::button
== aItem
.mTag
) {
2942 buttonFrame
= NS_NewHTMLButtonControlFrame(mPresShell
, styleContext
);
2945 buttonFrame
= NS_NewGfxButtonControlFrame(mPresShell
, styleContext
);
2947 if (NS_UNLIKELY(!buttonFrame
)) {
2948 return NS_ERROR_OUT_OF_MEMORY
;
2950 // Initialize the button frame
2951 nsresult rv
= InitAndRestoreFrame(aState
, content
,
2952 aState
.GetGeometricParent(aStyleDisplay
, aParentFrame
),
2953 nsnull
, buttonFrame
);
2954 if (NS_FAILED(rv
)) {
2955 buttonFrame
->Destroy();
2958 // See if we need to create a view
2959 nsHTMLContainerFrame::CreateViewForFrame(buttonFrame
, PR_FALSE
);
2961 nsRefPtr
<nsStyleContext
> innerBlockContext
;
2963 mPresShell
->StyleSet()->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::buttonContent
,
2966 nsIFrame
* blockFrame
= NS_NewBlockFrame(mPresShell
, innerBlockContext
,
2967 NS_BLOCK_FLOAT_MGR
);
2969 if (NS_UNLIKELY(!blockFrame
)) {
2970 buttonFrame
->Destroy();
2971 return NS_ERROR_OUT_OF_MEMORY
;
2973 rv
= InitAndRestoreFrame(aState
, content
, buttonFrame
, nsnull
, blockFrame
);
2974 if (NS_FAILED(rv
)) {
2975 blockFrame
->Destroy();
2976 buttonFrame
->Destroy();
2980 rv
= aState
.AddChild(buttonFrame
, aFrameItems
, content
, styleContext
,
2982 if (NS_FAILED(rv
)) {
2983 blockFrame
->Destroy();
2984 buttonFrame
->Destroy();
2988 PRBool isLeaf
= buttonFrame
->IsLeaf();
2990 // Make sure that we're an anonymous content creator exactly when we're a
2992 nsIAnonymousContentCreator
* creator
= do_QueryFrame(buttonFrame
);
2993 NS_ASSERTION(!creator
== !isLeaf
,
2994 "Should be creator exactly when we're a leaf");
2999 nsFrameConstructorSaveState absoluteSaveState
;
3000 nsFrameItems childItems
;
3002 if (aStyleDisplay
->IsPositioned()) {
3003 // The area frame becomes a container for child frames that are
3004 // absolutely positioned
3005 aState
.PushAbsoluteContainingBlock(blockFrame
, absoluteSaveState
);
3009 // Make sure that anonymous child creation will have no effect in this case
3010 nsIAnonymousContentCreator
* creator
= do_QueryFrame(blockFrame
);
3011 NS_ASSERTION(!creator
, "Shouldn't be an anonymous content creator!");
3014 rv
= ProcessChildren(aState
, content
, styleContext
, blockFrame
, PR_TRUE
,
3015 childItems
, aStyleDisplay
->IsBlockInside(),
3016 aItem
.mPendingBinding
);
3017 if (NS_FAILED(rv
)) return rv
;
3019 // Set the areas frame's initial child lists
3020 blockFrame
->SetInitialChildList(nsnull
, childItems
);
3023 SetInitialSingleChild(buttonFrame
, blockFrame
);
3026 ClearLazyBits(content
->GetFirstChild(), nsnull
);
3028 nsFrameItems anonymousChildItems
;
3029 // if there are any anonymous children create frames for them. Note that
3030 // we're doing this using a different parent frame from the one we pass to
3032 CreateAnonymousFrames(aState
, content
, buttonFrame
, aItem
.mPendingBinding
,
3033 anonymousChildItems
);
3034 if (anonymousChildItems
.NotEmpty()) {
3035 // the anonymous content is already parented to the area frame
3036 aState
.mFrameManager
->AppendFrames(blockFrame
, nsnull
,
3037 anonymousChildItems
);
3041 // our new button frame returned is the top frame.
3042 *aNewFrame
= buttonFrame
;
3048 nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState
& aState
,
3049 FrameConstructionItem
& aItem
,
3050 nsIFrame
* aParentFrame
,
3051 const nsStyleDisplay
* aStyleDisplay
,
3052 nsFrameItems
& aFrameItems
,
3053 nsIFrame
** aNewFrame
)
3055 nsresult rv
= NS_OK
;
3056 const PRInt32 kNoSizeSpecified
= -1;
3058 nsIContent
* const content
= aItem
.mContent
;
3059 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
3061 // Construct a frame-based listbox or combobox
3062 nsCOMPtr
<nsIDOMHTMLSelectElement
> sel(do_QueryInterface(content
));
3065 sel
->GetSize(&size
);
3066 PRBool multipleSelect
= PR_FALSE
;
3067 sel
->GetMultiple(&multipleSelect
);
3068 // Construct a combobox if size=1 or no size is specified and its multiple select
3069 if (((1 == size
|| 0 == size
) || (kNoSizeSpecified
== size
)) && (PR_FALSE
== multipleSelect
)) {
3070 // Construct a frame-based combo box.
3071 // The frame-based combo box is built out of three parts. A display area, a button and
3072 // a dropdown list. The display area and button are created through anonymous content.
3073 // The drop-down list's frame is created explicitly. The combobox frame shares its content
3074 // with the drop-down list.
3075 PRUint32 flags
= NS_BLOCK_FLOAT_MGR
;
3076 nsIFrame
* comboboxFrame
= NS_NewComboboxControlFrame(mPresShell
, styleContext
, flags
);
3078 // Save the history state so we don't restore during construction
3079 // since the complete tree is required before we restore.
3080 nsILayoutHistoryState
*historyState
= aState
.mFrameState
;
3081 aState
.mFrameState
= nsnull
;
3082 // Initialize the combobox frame
3083 InitAndRestoreFrame(aState
, content
,
3084 aState
.GetGeometricParent(aStyleDisplay
, aParentFrame
),
3085 nsnull
, comboboxFrame
);
3087 nsHTMLContainerFrame::CreateViewForFrame(comboboxFrame
, PR_FALSE
);
3089 rv
= aState
.AddChild(comboboxFrame
, aFrameItems
, content
, styleContext
,
3091 if (NS_FAILED(rv
)) {
3095 ///////////////////////////////////////////////////////////////////
3096 // Combobox - Old Native Implementation
3097 ///////////////////////////////////////////////////////////////////
3098 nsIComboboxControlFrame
* comboBox
= do_QueryFrame(comboboxFrame
);
3099 NS_ASSERTION(comboBox
, "NS_NewComboboxControlFrame returned frame that "
3100 "doesn't implement nsIComboboxControlFrame");
3102 // Resolve pseudo element style for the dropdown list
3103 nsRefPtr
<nsStyleContext
> listStyle
;
3104 listStyle
= mPresShell
->StyleSet()->
3105 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::dropDownList
, styleContext
);
3108 nsIFrame
* listFrame
= NS_NewListControlFrame(mPresShell
, listStyle
);
3110 // Notify the listbox that it is being used as a dropdown list.
3111 nsIListControlFrame
* listControlFrame
= do_QueryFrame(listFrame
);
3112 if (listControlFrame
) {
3113 listControlFrame
->SetComboboxFrame(comboboxFrame
);
3115 // Notify combobox that it should use the listbox as it's popup
3116 comboBox
->SetDropDown(listFrame
);
3118 NS_ASSERTION(!listStyle
->GetStyleDisplay()->IsPositioned(),
3119 "Ended up with positioned dropdown list somehow.");
3120 NS_ASSERTION(!listStyle
->GetStyleDisplay()->IsFloating(),
3121 "Ended up with floating dropdown list somehow.");
3123 // Initialize the scroll frame positioned. Note that it is NOT
3124 // initialized as absolutely positioned.
3125 nsIFrame
* scrolledFrame
= NS_NewSelectsAreaFrame(mPresShell
, styleContext
, flags
);
3127 InitializeSelectFrame(aState
, listFrame
, scrolledFrame
, content
,
3128 comboboxFrame
, listStyle
, PR_TRUE
,
3129 aItem
.mPendingBinding
, aFrameItems
);
3131 // Set flag so the events go to the listFrame not child frames.
3132 // XXX: We should replace this with a real widget manager similar
3133 // to how the nsFormControlFrame works. Re-directing events is a temporary Kludge.
3134 NS_ASSERTION(listFrame
->GetView(), "ListFrame's view is nsnull");
3135 //listFrame->GetView()->SetViewFlags(NS_VIEW_PUBLIC_FLAG_DONT_CHECK_CHILDREN);
3137 // Create display and button frames from the combobox's anonymous content.
3138 // The anonymous content is appended to existing anonymous content for this
3139 // element (the scrollbars).
3141 nsFrameItems childItems
;
3142 CreateAnonymousFrames(aState
, content
, comboboxFrame
,
3143 aItem
.mPendingBinding
, childItems
);
3145 comboboxFrame
->SetInitialChildList(nsnull
, childItems
);
3147 // Initialize the additional popup child list which contains the
3148 // dropdown list frame.
3149 nsFrameItems popupItems
;
3150 popupItems
.AddChild(listFrame
);
3151 comboboxFrame
->SetInitialChildList(nsGkAtoms::selectPopupList
,
3154 *aNewFrame
= comboboxFrame
;
3155 aState
.mFrameState
= historyState
;
3156 if (aState
.mFrameState
&& aState
.mFrameManager
) {
3157 // Restore frame state for the entire subtree of |comboboxFrame|.
3158 aState
.mFrameManager
->RestoreFrameState(comboboxFrame
,
3159 aState
.mFrameState
);
3162 ///////////////////////////////////////////////////////////////////
3163 // ListBox - Old Native Implementation
3164 ///////////////////////////////////////////////////////////////////
3165 nsIFrame
* listFrame
= NS_NewListControlFrame(mPresShell
, styleContext
);
3170 rv
= NS_ERROR_OUT_OF_MEMORY
;
3173 nsIFrame
* scrolledFrame
= NS_NewSelectsAreaFrame(
3174 mPresShell
, styleContext
, NS_BLOCK_FLOAT_MGR
);
3176 // ******* this code stolen from Initialze ScrollFrame ********
3177 // please adjust this code to use BuildScrollFrame.
3179 InitializeSelectFrame(aState
, listFrame
, scrolledFrame
, content
,
3180 aParentFrame
, styleContext
, PR_FALSE
,
3181 aItem
.mPendingBinding
, aFrameItems
);
3183 *aNewFrame
= listFrame
;
3191 * Used to be InitializeScrollFrame but now it's only used for the select tag
3192 * But the select tag should really be fixed to use GFX scrollbars that can
3193 * be create with BuildScrollFrame.
3196 nsCSSFrameConstructor::InitializeSelectFrame(nsFrameConstructorState
& aState
,
3197 nsIFrame
* scrollFrame
,
3198 nsIFrame
* scrolledFrame
,
3199 nsIContent
* aContent
,
3200 nsIFrame
* aParentFrame
,
3201 nsStyleContext
* aStyleContext
,
3202 PRBool aBuildCombobox
,
3203 PendingBinding
* aPendingBinding
,
3204 nsFrameItems
& aFrameItems
)
3206 const nsStyleDisplay
* display
= aStyleContext
->GetStyleDisplay();
3209 nsIFrame
* geometricParent
= aState
.GetGeometricParent(display
, aParentFrame
);
3211 // We don't call InitAndRestoreFrame for scrollFrame because we can only
3212 // restore the frame state after its parts have been created (in particular,
3213 // the scrollable view). So we have to split Init and Restore.
3215 // Initialize the frame
3216 scrollFrame
->Init(aContent
, geometricParent
, nsnull
);
3218 if (!aBuildCombobox
) {
3219 nsresult rv
= aState
.AddChild(scrollFrame
, aFrameItems
, aContent
,
3220 aStyleContext
, aParentFrame
);
3221 if (NS_FAILED(rv
)) {
3226 nsHTMLContainerFrame::CreateViewForFrame(scrollFrame
, aBuildCombobox
);
3227 if (aBuildCombobox
) {
3228 // Give the drop-down list a popup widget
3229 nsIView
* view
= scrollFrame
->GetView();
3230 NS_ASSERTION(view
, "We asked for a view but didn't get one");
3232 view
->GetViewManager()->SetViewFloating(view
, PR_TRUE
);
3234 nsWidgetInitData widgetData
;
3235 widgetData
.mWindowType
= eWindowType_popup
;
3236 widgetData
.mBorderStyle
= eBorderStyle_default
;
3237 view
->CreateWidgetForPopup(&widgetData
);
3241 BuildScrollFrame(aState
, aContent
, aStyleContext
, scrolledFrame
,
3242 geometricParent
, scrollFrame
);
3244 if (aState
.mFrameState
&& aState
.mFrameManager
) {
3245 // Restore frame state for the scroll frame
3246 aState
.mFrameManager
->RestoreFrameStateFor(scrollFrame
, aState
.mFrameState
);
3250 nsFrameConstructorSaveState absoluteSaveState
;
3251 nsFrameItems childItems
;
3253 if (display
->IsPositioned()) {
3254 // The area frame becomes a container for child frames that are
3255 // absolutely positioned
3256 aState
.PushAbsoluteContainingBlock(scrolledFrame
, absoluteSaveState
);
3259 ProcessChildren(aState
, aContent
, aStyleContext
, scrolledFrame
, PR_FALSE
,
3260 childItems
, PR_FALSE
, aPendingBinding
);
3262 // Set the scrolled frame's initial child lists
3263 scrolledFrame
->SetInitialChildList(nsnull
, childItems
);
3268 nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState
& aState
,
3269 FrameConstructionItem
& aItem
,
3270 nsIFrame
* aParentFrame
,
3271 const nsStyleDisplay
* aStyleDisplay
,
3272 nsFrameItems
& aFrameItems
,
3273 nsIFrame
** aNewFrame
)
3275 nsIContent
* const content
= aItem
.mContent
;
3276 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
3278 nsIFrame
* newFrame
= NS_NewFieldSetFrame(mPresShell
, styleContext
);
3279 if (NS_UNLIKELY(!newFrame
)) {
3280 return NS_ERROR_OUT_OF_MEMORY
;
3284 InitAndRestoreFrame(aState
, content
,
3285 aState
.GetGeometricParent(aStyleDisplay
, aParentFrame
),
3288 // See if we need to create a view, e.g. the frame is absolutely
3290 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
3292 // Resolve style and initialize the frame
3293 nsRefPtr
<nsStyleContext
> fieldsetContentStyle
;
3294 fieldsetContentStyle
= mPresShell
->StyleSet()->
3295 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::fieldsetContent
, styleContext
);
3297 nsIFrame
* blockFrame
= NS_NewBlockFrame(mPresShell
, fieldsetContentStyle
,
3298 NS_BLOCK_FLOAT_MGR
|
3299 NS_BLOCK_MARGIN_ROOT
);
3300 InitAndRestoreFrame(aState
, content
, newFrame
, nsnull
, blockFrame
);
3302 nsresult rv
= aState
.AddChild(newFrame
, aFrameItems
, content
, styleContext
,
3304 if (NS_FAILED(rv
)) {
3309 nsFrameConstructorSaveState absoluteSaveState
;
3310 nsFrameItems childItems
;
3312 if (aStyleDisplay
->IsPositioned()) {
3313 // The area frame becomes a container for child frames that are
3314 // absolutely positioned
3315 // XXXbz this is probably wrong, and once arbitrary frames can be absolute
3316 // containing blocks we should fix this..
3317 aState
.PushAbsoluteContainingBlock(blockFrame
, absoluteSaveState
);
3320 ProcessChildren(aState
, content
, styleContext
, blockFrame
, PR_TRUE
,
3321 childItems
, PR_TRUE
, aItem
.mPendingBinding
);
3323 nsFrameItems fieldsetKids
;
3324 fieldsetKids
.AddChild(blockFrame
);
3326 for (nsFrameList::Enumerator
e(childItems
); !e
.AtEnd(); e
.Next()) {
3327 nsLegendFrame
* legendFrame
= do_QueryFrame(e
.get());
3329 // We want the legend to be the first frame in the fieldset child list.
3330 // That way the EventStateManager will do the right thing when tabbing
3331 // from a selection point within the legend (bug 236071), which is
3332 // used for implementing legend access keys (bug 81481).
3333 // GetAdjustedParentFrame() below depends on this frame order.
3334 childItems
.RemoveFrame(legendFrame
);
3335 // Make sure to reparent the legend so it has the fieldset as the parent.
3336 fieldsetKids
.InsertFrame(newFrame
, nsnull
, legendFrame
);
3341 // Set the inner frame's initial child lists
3342 blockFrame
->SetInitialChildList(nsnull
, childItems
);
3344 // Set the outer frame's initial child list
3345 newFrame
->SetInitialChildList(nsnull
, fieldsetKids
);
3347 // our new frame returned is the top frame which is the list frame.
3348 *aNewFrame
= newFrame
;
3354 FindAncestorWithGeneratedContentPseudo(nsIFrame
* aFrame
)
3356 for (nsIFrame
* f
= aFrame
->GetParent(); f
; f
= f
->GetParent()) {
3357 NS_ASSERTION(f
->IsGeneratedContentFrame(),
3358 "should not have exited generated content");
3359 nsIAtom
* pseudo
= f
->GetStyleContext()->GetPseudo();
3360 if (pseudo
== nsCSSPseudoElements::before
||
3361 pseudo
== nsCSSPseudoElements::after
)
3367 #define SIMPLE_FCDATA(_func) FCDATA_DECL(0, _func)
3368 #define FULL_CTOR_FCDATA(_flags, _func) \
3369 { _flags | FCDATA_FUNC_IS_FULL_CTOR, { nsnull }, _func }
3372 const nsCSSFrameConstructor::FrameConstructionData
*
3373 nsCSSFrameConstructor::FindTextData(nsIFrame
* aParentFrame
)
3376 if (aParentFrame
&& aParentFrame
->IsFrameOfType(nsIFrame::eSVG
)) {
3377 nsIFrame
*ancestorFrame
=
3378 nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame
);
3379 if (ancestorFrame
) {
3380 nsSVGTextContainerFrame
* metrics
= do_QueryFrame(ancestorFrame
);
3382 static const FrameConstructionData sSVGGlyphData
=
3383 SIMPLE_FCDATA(NS_NewSVGGlyphFrame
);
3384 return &sSVGGlyphData
;
3391 static const FrameConstructionData sTextData
=
3392 FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT
, NS_NewTextFrame
);
3397 nsCSSFrameConstructor::ConstructTextFrame(const FrameConstructionData
* aData
,
3398 nsFrameConstructorState
& aState
,
3399 nsIContent
* aContent
,
3400 nsIFrame
* aParentFrame
,
3401 nsStyleContext
* aStyleContext
,
3402 nsFrameItems
& aFrameItems
)
3404 NS_PRECONDITION(aData
, "Must have frame construction data");
3406 nsIFrame
* newFrame
= (*aData
->mFunc
.mCreationFunc
)(mPresShell
, aStyleContext
);
3408 if (NS_UNLIKELY(!newFrame
))
3409 return NS_ERROR_OUT_OF_MEMORY
;
3411 nsresult rv
= InitAndRestoreFrame(aState
, aContent
, aParentFrame
,
3414 if (NS_FAILED(rv
)) {
3415 newFrame
->Destroy();
3419 // We never need to create a view for a text frame.
3421 if (newFrame
->IsGeneratedContentFrame()) {
3422 nsAutoPtr
<nsGenConInitializer
> initializer
;
3424 static_cast<nsGenConInitializer
*>(
3425 aContent
->UnsetProperty(nsGkAtoms::genConInitializerProperty
));
3427 if (initializer
->mNode
->InitTextFrame(initializer
->mList
,
3428 FindAncestorWithGeneratedContentPseudo(newFrame
), newFrame
)) {
3429 (this->*(initializer
->mDirtyAll
))();
3431 initializer
->mNode
.forget();
3435 // Add the newly constructed frame to the flow
3436 aFrameItems
.AddChild(newFrame
);
3438 if (!aState
.mCreatingExtraFrames
)
3439 aContent
->SetPrimaryFrame(newFrame
);
3445 const nsCSSFrameConstructor::FrameConstructionData
*
3446 nsCSSFrameConstructor::FindDataByInt(PRInt32 aInt
,
3447 nsIContent
* aContent
,
3448 nsStyleContext
* aStyleContext
,
3449 const FrameConstructionDataByInt
* aDataPtr
,
3450 PRUint32 aDataLength
)
3452 for (const FrameConstructionDataByInt
*curData
= aDataPtr
,
3453 *endData
= aDataPtr
+ aDataLength
;
3456 if (curData
->mInt
== aInt
) {
3457 const FrameConstructionData
* data
= &curData
->mData
;
3458 if (data
->mBits
& FCDATA_FUNC_IS_DATA_GETTER
) {
3459 return data
->mFunc
.mDataGetter(aContent
, aStyleContext
);
3470 const nsCSSFrameConstructor::FrameConstructionData
*
3471 nsCSSFrameConstructor::FindDataByTag(nsIAtom
* aTag
,
3472 nsIContent
* aContent
,
3473 nsStyleContext
* aStyleContext
,
3474 const FrameConstructionDataByTag
* aDataPtr
,
3475 PRUint32 aDataLength
)
3477 for (const FrameConstructionDataByTag
*curData
= aDataPtr
,
3478 *endData
= aDataPtr
+ aDataLength
;
3481 if (*curData
->mTag
== aTag
) {
3482 const FrameConstructionData
* data
= &curData
->mData
;
3483 if (data
->mBits
& FCDATA_FUNC_IS_DATA_GETTER
) {
3484 return data
->mFunc
.mDataGetter(aContent
, aStyleContext
);
3494 #define SUPPRESS_FCDATA() FCDATA_DECL(FCDATA_SUPPRESS_FRAME, nsnull)
3495 #define SIMPLE_INT_CREATE(_int, _func) { _int, SIMPLE_FCDATA(_func) }
3496 #define SIMPLE_INT_CHAIN(_int, _func) \
3497 { _int, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
3498 #define COMPLEX_INT_CREATE(_int, _func) \
3499 { _int, FULL_CTOR_FCDATA(0, _func) }
3501 #define SIMPLE_TAG_CREATE(_tag, _func) \
3502 { &nsGkAtoms::_tag, SIMPLE_FCDATA(_func) }
3503 #define SIMPLE_TAG_CHAIN(_tag, _func) \
3504 { &nsGkAtoms::_tag, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
3505 #define COMPLEX_TAG_CREATE(_tag, _func) \
3506 { &nsGkAtoms::_tag, FULL_CTOR_FCDATA(0, _func) }
3509 const nsCSSFrameConstructor::FrameConstructionData
*
3510 nsCSSFrameConstructor::FindHTMLData(nsIContent
* aContent
,
3512 PRInt32 aNameSpaceID
,
3513 nsIFrame
* aParentFrame
,
3514 nsStyleContext
* aStyleContext
)
3516 // Ignore the tag if it's not HTML content and if it doesn't extend (via XBL)
3517 // a valid HTML namespace. This check must match the one in
3518 // ShouldHaveFirstLineStyle.
3519 if (aNameSpaceID
!= kNameSpaceID_XHTML
) {
3523 NS_ASSERTION(!aParentFrame
||
3524 aParentFrame
->GetStyleContext()->GetPseudo() !=
3525 nsCSSAnonBoxes::fieldsetContent
||
3526 aParentFrame
->GetParent()->GetType() == nsGkAtoms::fieldSetFrame
,
3527 "Unexpected parent for fieldset content anon box");
3528 if (aTag
== nsGkAtoms::legend
&&
3530 (aParentFrame
->GetType() != nsGkAtoms::fieldSetFrame
&&
3531 aParentFrame
->GetStyleContext()->GetPseudo() !=
3532 nsCSSAnonBoxes::fieldsetContent
) ||
3533 !aContent
->GetParent() ||
3534 !aContent
->GetParent()->IsHTML() ||
3535 aContent
->GetParent()->Tag() != nsGkAtoms::fieldset
||
3536 aStyleContext
->GetStyleDisplay()->IsFloating() ||
3537 aStyleContext
->GetStyleDisplay()->IsAbsolutelyPositioned())) {
3538 // <legend> is only special inside fieldset, check both the frame tree
3539 // parent and content tree parent due to XBL issues. For floated or
3540 // absolutely positioned legends we want to construct by display type and
3541 // not do special legend stuff.
3542 // XXXbz it would be nice if we could just decide this based on the parent
3543 // tag, and hence just use a SIMPLE_TAG_CHAIN for legend below, but the
3544 // fact that with XBL we could end up with this legend element in some
3545 // totally weird insertion point makes that chancy, I think.
3549 static const FrameConstructionDataByTag sHTMLData
[] = {
3550 SIMPLE_TAG_CHAIN(img
, nsCSSFrameConstructor::FindImgData
),
3551 SIMPLE_TAG_CHAIN(mozgeneratedcontentimage
,
3552 nsCSSFrameConstructor::FindImgData
),
3554 FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT
| FCDATA_IS_LINE_BREAK
,
3556 SIMPLE_TAG_CREATE(wbr
, NS_NewWBRFrame
),
3557 SIMPLE_TAG_CHAIN(input
, nsCSSFrameConstructor::FindInputData
),
3558 SIMPLE_TAG_CREATE(textarea
, NS_NewTextControlFrame
),
3559 COMPLEX_TAG_CREATE(select
, &nsCSSFrameConstructor::ConstructSelectFrame
),
3560 SIMPLE_TAG_CHAIN(object
, nsCSSFrameConstructor::FindObjectData
),
3561 SIMPLE_TAG_CHAIN(applet
, nsCSSFrameConstructor::FindObjectData
),
3562 SIMPLE_TAG_CHAIN(embed
, nsCSSFrameConstructor::FindObjectData
),
3563 COMPLEX_TAG_CREATE(fieldset
,
3564 &nsCSSFrameConstructor::ConstructFieldSetFrame
),
3565 { &nsGkAtoms::legend
,
3566 FCDATA_DECL(FCDATA_ALLOW_BLOCK_STYLES
, NS_NewLegendFrame
) },
3567 SIMPLE_TAG_CREATE(frameset
, NS_NewHTMLFramesetFrame
),
3568 SIMPLE_TAG_CREATE(iframe
, NS_NewSubDocumentFrame
),
3569 COMPLEX_TAG_CREATE(button
, &nsCSSFrameConstructor::ConstructButtonFrame
),
3570 SIMPLE_TAG_CREATE(canvas
, NS_NewHTMLCanvasFrame
),
3571 #if defined(MOZ_MEDIA)
3572 SIMPLE_TAG_CREATE(video
, NS_NewHTMLVideoFrame
),
3573 SIMPLE_TAG_CREATE(audio
, NS_NewHTMLVideoFrame
),
3575 SIMPLE_TAG_CREATE(isindex
, NS_NewIsIndexFrame
)
3578 return FindDataByTag(aTag
, aContent
, aStyleContext
, sHTMLData
,
3579 NS_ARRAY_LENGTH(sHTMLData
));
3583 const nsCSSFrameConstructor::FrameConstructionData
*
3584 nsCSSFrameConstructor::FindImgData(nsIContent
* aContent
,
3585 nsStyleContext
* aStyleContext
)
3587 if (!nsImageFrame::ShouldCreateImageFrameFor(aContent
, aStyleContext
)) {
3591 static const FrameConstructionData sImgData
= SIMPLE_FCDATA(NS_NewImageFrame
);
3596 const nsCSSFrameConstructor::FrameConstructionData
*
3597 nsCSSFrameConstructor::FindImgControlData(nsIContent
* aContent
,
3598 nsStyleContext
* aStyleContext
)
3600 if (!nsImageFrame::ShouldCreateImageFrameFor(aContent
, aStyleContext
)) {
3604 static const FrameConstructionData sImgControlData
=
3605 SIMPLE_FCDATA(NS_NewImageControlFrame
);
3606 return &sImgControlData
;
3610 const nsCSSFrameConstructor::FrameConstructionData
*
3611 nsCSSFrameConstructor::FindInputData(nsIContent
* aContent
,
3612 nsStyleContext
* aStyleContext
)
3614 static const FrameConstructionDataByInt sInputData
[] = {
3615 SIMPLE_INT_CREATE(NS_FORM_INPUT_CHECKBOX
, NS_NewGfxCheckboxControlFrame
),
3616 SIMPLE_INT_CREATE(NS_FORM_INPUT_RADIO
, NS_NewGfxRadioControlFrame
),
3617 SIMPLE_INT_CREATE(NS_FORM_INPUT_FILE
, NS_NewFileControlFrame
),
3618 SIMPLE_INT_CHAIN(NS_FORM_INPUT_IMAGE
,
3619 nsCSSFrameConstructor::FindImgControlData
),
3620 SIMPLE_INT_CREATE(NS_FORM_INPUT_EMAIL
, NS_NewTextControlFrame
),
3621 SIMPLE_INT_CREATE(NS_FORM_INPUT_SEARCH
, NS_NewTextControlFrame
),
3622 SIMPLE_INT_CREATE(NS_FORM_INPUT_TEXT
, NS_NewTextControlFrame
),
3623 SIMPLE_INT_CREATE(NS_FORM_INPUT_TEL
, NS_NewTextControlFrame
),
3624 SIMPLE_INT_CREATE(NS_FORM_INPUT_URL
, NS_NewTextControlFrame
),
3625 SIMPLE_INT_CREATE(NS_FORM_INPUT_PASSWORD
, NS_NewTextControlFrame
),
3626 COMPLEX_INT_CREATE(NS_FORM_INPUT_SUBMIT
,
3627 &nsCSSFrameConstructor::ConstructButtonFrame
),
3628 COMPLEX_INT_CREATE(NS_FORM_INPUT_RESET
,
3629 &nsCSSFrameConstructor::ConstructButtonFrame
),
3630 COMPLEX_INT_CREATE(NS_FORM_INPUT_BUTTON
,
3631 &nsCSSFrameConstructor::ConstructButtonFrame
)
3632 // Keeping hidden inputs out of here on purpose for so they get frames by
3633 // display (in practice, none).
3636 nsCOMPtr
<nsIFormControl
> control
= do_QueryInterface(aContent
);
3637 NS_ASSERTION(control
, "input doesn't implement nsIFormControl?");
3639 return FindDataByInt(control
->GetType(), aContent
, aStyleContext
,
3640 sInputData
, NS_ARRAY_LENGTH(sInputData
));
3644 const nsCSSFrameConstructor::FrameConstructionData
*
3645 nsCSSFrameConstructor::FindObjectData(nsIContent
* aContent
,
3646 nsStyleContext
* aStyleContext
)
3648 // GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for
3649 // cases when the object is broken/suppressed/etc (e.g. a broken image), but
3650 // we want to treat those cases as TYPE_NULL
3652 if (aContent
->IntrinsicState().HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN
|
3653 NS_EVENT_STATE_USERDISABLED
|
3654 NS_EVENT_STATE_SUPPRESSED
)) {
3655 type
= nsIObjectLoadingContent::TYPE_NULL
;
3657 nsCOMPtr
<nsIObjectLoadingContent
> objContent(do_QueryInterface(aContent
));
3658 NS_ASSERTION(objContent
,
3659 "applet, embed and object must implement "
3660 "nsIObjectLoadingContent!");
3662 objContent
->GetDisplayedType(&type
);
3665 static const FrameConstructionDataByInt sObjectData
[] = {
3666 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING
,
3668 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_PLUGIN
,
3670 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE
,
3672 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT
,
3673 NS_NewSubDocumentFrame
)
3674 // Nothing for TYPE_NULL so we'll construct frames by display there
3677 return FindDataByInt((PRInt32
)type
, aContent
, aStyleContext
,
3678 sObjectData
, NS_ARRAY_LENGTH(sObjectData
));
3682 nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem
& aItem
,
3683 nsFrameConstructorState
& aState
,
3684 nsIFrame
* aParentFrame
,
3685 nsFrameItems
& aFrameItems
)
3687 const FrameConstructionData
* data
= aItem
.mFCData
;
3688 NS_ASSERTION(data
, "Must have frame construction data");
3690 PRUint32 bits
= data
->mBits
;
3692 NS_ASSERTION(!(bits
& FCDATA_FUNC_IS_DATA_GETTER
),
3693 "Should have dealt with this inside the data finder");
3695 // Some sets of bits are not compatible with each other
3696 #define CHECK_ONLY_ONE_BIT(_bit1, _bit2) \
3697 NS_ASSERTION(!(bits & _bit1) || !(bits & _bit2), \
3698 "Only one of these bits should be set")
3699 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_FORCE_NULL_ABSPOS_CONTAINER
);
3701 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_WRAP_KIDS_IN_BLOCKS
);
3703 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_MAY_NEED_SCROLLFRAME
);
3704 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_IS_POPUP
);
3705 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_SKIP_ABSPOS_PUSH
);
3706 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_FORCE_VIEW
);
3707 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
,
3708 FCDATA_DISALLOW_GENERATED_CONTENT
);
3709 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_ALLOW_BLOCK_STYLES
);
3710 CHECK_ONLY_ONE_BIT(FCDATA_MAY_NEED_SCROLLFRAME
, FCDATA_FORCE_VIEW
);
3711 #undef CHECK_ONLY_ONE_BIT
3713 // Don't create a subdocument frame for iframes if we're creating extra frames
3714 if (aState
.mCreatingExtraFrames
&& aItem
.mContent
->IsHTML() &&
3715 aItem
.mContent
->Tag() == nsGkAtoms::iframe
)
3720 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
3721 const nsStyleDisplay
* display
= styleContext
->GetStyleDisplay();
3724 nsIFrame
* primaryFrame
;
3725 if (bits
& FCDATA_FUNC_IS_FULL_CTOR
) {
3727 (this->*(data
->mFullConstructor
))(aState
, aItem
, aParentFrame
,
3728 display
, aFrameItems
, &newFrame
);
3729 if (NS_FAILED(rv
)) {
3733 primaryFrame
= newFrame
;
3735 nsIContent
* const content
= aItem
.mContent
;
3738 (*data
->mFunc
.mCreationFunc
)(mPresShell
, styleContext
);
3740 return NS_ERROR_OUT_OF_MEMORY
;
3743 PRBool allowOutOfFlow
= !(bits
& FCDATA_DISALLOW_OUT_OF_FLOW
);
3744 PRBool isPopup
= aItem
.mIsPopup
;
3745 NS_ASSERTION(!isPopup
||
3746 (aState
.mPopupItems
.containingBlock
&&
3747 aState
.mPopupItems
.containingBlock
->GetType() ==
3748 nsGkAtoms::popupSetFrame
),
3749 "Should have a containing block here!");
3751 nsIFrame
* geometricParent
=
3752 isPopup
? aState
.mPopupItems
.containingBlock
:
3753 (allowOutOfFlow
? aState
.GetGeometricParent(display
, aParentFrame
)
3756 nsresult rv
= NS_OK
;
3758 // Must init frameToAddToList to null, since it's inout
3759 nsIFrame
* frameToAddToList
= nsnull
;
3760 if ((bits
& FCDATA_MAY_NEED_SCROLLFRAME
) &&
3761 display
->IsScrollableOverflow()) {
3762 BuildScrollFrame(aState
, content
, styleContext
, newFrame
,
3763 geometricParent
, frameToAddToList
);
3765 rv
= InitAndRestoreFrame(aState
, content
, geometricParent
, nsnull
,
3767 NS_ASSERTION(NS_SUCCEEDED(rv
), "InitAndRestoreFrame failed");
3768 // See whether we need to create a view
3769 nsHTMLContainerFrame::CreateViewForFrame(newFrame
,
3770 (bits
& FCDATA_FORCE_VIEW
) != 0);
3771 frameToAddToList
= newFrame
;
3774 // Use frameToAddToList as the primary frame. In the non-scrollframe case
3775 // they're equal, but in the scrollframe case newFrame is the scrolled
3776 // frame, while frameToAddToList is the scrollframe (and should be the
3778 primaryFrame
= frameToAddToList
;
3780 rv
= aState
.AddChild(frameToAddToList
, aFrameItems
, content
, styleContext
,
3781 aParentFrame
, allowOutOfFlow
, allowOutOfFlow
, isPopup
);
3782 if (NS_FAILED(rv
)) {
3787 // Icky XUL stuff, sadly
3789 if (aItem
.mIsRootPopupgroup
) {
3790 NS_ASSERTION(nsIRootBox::GetRootBox(mPresShell
) &&
3791 nsIRootBox::GetRootBox(mPresShell
)->GetPopupSetFrame() ==
3793 "Unexpected PopupSetFrame");
3794 aState
.mPopupItems
.containingBlock
= newFrame
;
3795 aState
.mHavePendingPopupgroup
= PR_FALSE
;
3797 #endif /* MOZ_XUL */
3799 // Process the child content if requested
3800 nsFrameItems childItems
;
3801 nsFrameConstructorSaveState absoluteSaveState
;
3803 if (bits
& FCDATA_FORCE_NULL_ABSPOS_CONTAINER
) {
3804 aState
.PushAbsoluteContainingBlock(nsnull
, absoluteSaveState
);
3805 } else if (!(bits
& FCDATA_SKIP_ABSPOS_PUSH
) && display
->IsPositioned()) {
3806 aState
.PushAbsoluteContainingBlock(newFrame
, absoluteSaveState
);
3809 if (bits
& FCDATA_USE_CHILD_ITEMS
) {
3810 rv
= ConstructFramesFromItemList(aState
, aItem
.mChildItems
, newFrame
,
3813 // Process the child frames.
3814 rv
= ProcessChildren(aState
, content
, styleContext
, newFrame
,
3815 !(bits
& FCDATA_DISALLOW_GENERATED_CONTENT
),
3817 (bits
& FCDATA_ALLOW_BLOCK_STYLES
) != 0,
3818 aItem
.mPendingBinding
);
3822 // More icky XUL stuff
3823 if (aItem
.mNameSpaceID
== kNameSpaceID_XUL
&&
3824 (aItem
.mTag
== nsGkAtoms::treechildren
|| // trees always need titletips
3825 content
->HasAttr(kNameSpaceID_None
, nsGkAtoms::tooltiptext
) ||
3826 content
->HasAttr(kNameSpaceID_None
, nsGkAtoms::tooltip
))) {
3827 nsIRootBox
* rootBox
= nsIRootBox::GetRootBox(mPresShell
);
3829 rootBox
->AddTooltipSupport(content
);
3835 if (NS_SUCCEEDED(rv
) && (bits
& FCDATA_WRAP_KIDS_IN_BLOCKS
)) {
3836 nsFrameItems newItems
;
3837 nsFrameItems currentBlock
;
3839 while ((f
= childItems
.FirstChild()) != nsnull
) {
3840 PRBool wrapFrame
= IsInlineFrame(f
) || IsFrameSpecial(f
);
3842 rv
= FlushAccumulatedBlock(aState
, content
, newFrame
, ¤tBlock
, &newItems
);
3847 childItems
.RemoveFrame(f
);
3849 currentBlock
.AddChild(f
);
3851 newItems
.AddChild(f
);
3854 rv
= FlushAccumulatedBlock(aState
, content
, newFrame
, ¤tBlock
, &newItems
);
3856 if (childItems
.NotEmpty()) {
3857 // an error must have occurred, delete unprocessed frames
3858 childItems
.DestroyFrames();
3861 childItems
= newItems
;
3865 // Set the frame's initial child list
3866 // Note that MathML depends on this being called even if
3867 // childItems is empty!
3868 newFrame
->SetInitialChildList(nsnull
, childItems
);
3871 NS_ASSERTION(newFrame
->IsFrameOfType(nsIFrame::eLineParticipant
) ==
3872 ((bits
& FCDATA_IS_LINE_PARTICIPANT
) != 0),
3873 "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits");
3875 if (!aState
.mCreatingExtraFrames
&& !(bits
& FCDATA_SKIP_FRAMESET
)) {
3876 aItem
.mContent
->SetPrimaryFrame(primaryFrame
);
3882 // after the node has been constructed and initialized create any
3883 // anonymous content a node needs.
3885 nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState
& aState
,
3886 nsIContent
* aParent
,
3887 nsIFrame
* aParentFrame
,
3888 PendingBinding
* aPendingBinding
,
3889 nsFrameItems
& aChildItems
)
3891 nsAutoTArray
<nsIContent
*, 4> newAnonymousItems
;
3892 nsresult rv
= GetAnonymousContent(aParent
, aParentFrame
, newAnonymousItems
);
3893 NS_ENSURE_SUCCESS(rv
, rv
);
3895 PRUint32 count
= newAnonymousItems
.Length();
3900 nsFrameConstructorState::PendingBindingAutoPusher
pusher(aState
,
3903 nsIAnonymousContentCreator
* creator
= do_QueryFrame(aParentFrame
);
3904 NS_ASSERTION(creator
,
3905 "How can that happen if we have nodes to construct frames for?");
3907 for (PRUint32 i
=0; i
< count
; i
++) {
3908 nsIContent
* content
= newAnonymousItems
[i
];
3909 NS_ASSERTION(content
, "null anonymous content?");
3911 nsIFrame
* newFrame
= creator
->CreateFrameFor(content
);
3913 NS_ASSERTION(content
->GetPrimaryFrame(),
3914 "Content must have a primary frame now");
3915 aChildItems
.AddChild(newFrame
);
3918 // create the frame and attach it to our frame
3919 ConstructFrame(aState
, content
, aParentFrame
, aChildItems
);
3927 nsCSSFrameConstructor::GetAnonymousContent(nsIContent
* aParent
,
3928 nsIFrame
* aParentFrame
,
3929 nsTArray
<nsIContent
*>& aContent
)
3931 nsIAnonymousContentCreator
* creator
= do_QueryFrame(aParentFrame
);
3935 nsresult rv
= creator
->CreateAnonymousContent(aContent
);
3936 NS_ENSURE_SUCCESS(rv
, rv
);
3938 PRUint32 count
= aContent
.Length();
3939 for (PRUint32 i
=0; i
< count
; i
++) {
3940 // get our child's content and set its parent to our content
3941 nsIContent
* content
= aContent
[i
];
3942 NS_ASSERTION(content
, "null anonymous content?");
3945 // least-surprise CSS binding until we do the SVG specified
3946 // cascading rules for <svg:use> - bug 265894
3948 aParent
->NodeInfo()->Equals(nsGkAtoms::use
, kNameSpaceID_SVG
)) {
3949 content
->SetFlags(NODE_IS_ANONYMOUS
);
3953 content
->SetNativeAnonymous();
3956 rv
= content
->BindToTree(mDocument
, aParent
, aParent
, PR_TRUE
);
3957 if (NS_FAILED(rv
)) {
3958 content
->UnbindFromTree();
3967 PRBool
IsXULDisplayType(const nsStyleDisplay
* aDisplay
)
3969 return (aDisplay
->mDisplay
== NS_STYLE_DISPLAY_INLINE_BOX
||
3971 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_INLINE_GRID
||
3972 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_INLINE_STACK
||
3974 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_BOX
3976 || aDisplay
->mDisplay
== NS_STYLE_DISPLAY_GRID
||
3977 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_STACK
||
3978 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_GRID_GROUP
||
3979 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_GRID_LINE
||
3980 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_DECK
||
3981 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_POPUP
||
3982 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_GROUPBOX
3988 // XUL frames are not allowed to be out of flow.
3989 #define SIMPLE_XUL_FCDATA(_func) \
3990 FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH, \
3992 #define SCROLLABLE_XUL_FCDATA(_func) \
3993 FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH | \
3994 FCDATA_MAY_NEED_SCROLLFRAME, _func)
3995 #define SIMPLE_XUL_CREATE(_tag, _func) \
3996 { &nsGkAtoms::_tag, SIMPLE_XUL_FCDATA(_func) }
3997 #define SCROLLABLE_XUL_CREATE(_tag, _func) \
3998 { &nsGkAtoms::_tag, SCROLLABLE_XUL_FCDATA(_func) }
3999 #define SIMPLE_XUL_INT_CREATE(_int, _func) \
4000 { _int, SIMPLE_XUL_FCDATA(_func) }
4001 #define SCROLLABLE_XUL_INT_CREATE(_int, _func) \
4002 { _int, SCROLLABLE_XUL_FCDATA(_func) }
4005 nsIFrame
* NS_NewGridBoxFrame(nsIPresShell
* aPresShell
,
4006 nsStyleContext
* aStyleContext
)
4008 nsCOMPtr
<nsIBoxLayout
> layout
;
4009 NS_NewGridLayout2(aPresShell
, getter_AddRefs(layout
));
4014 return NS_NewBoxFrame(aPresShell
, aStyleContext
, PR_FALSE
, layout
);
4018 const nsCSSFrameConstructor::FrameConstructionData
*
4019 nsCSSFrameConstructor::FindXULTagData(nsIContent
* aContent
,
4021 PRInt32 aNameSpaceID
,
4022 nsStyleContext
* aStyleContext
)
4024 if (aNameSpaceID
!= kNameSpaceID_XUL
) {
4028 static const FrameConstructionDataByTag sXULTagData
[] = {
4030 SCROLLABLE_XUL_CREATE(button
, NS_NewButtonBoxFrame
),
4031 SCROLLABLE_XUL_CREATE(checkbox
, NS_NewButtonBoxFrame
),
4032 SCROLLABLE_XUL_CREATE(radio
, NS_NewButtonBoxFrame
),
4033 SCROLLABLE_XUL_CREATE(autorepeatbutton
, NS_NewAutoRepeatBoxFrame
),
4034 SCROLLABLE_XUL_CREATE(titlebar
, NS_NewTitleBarFrame
),
4035 SCROLLABLE_XUL_CREATE(resizer
, NS_NewResizerFrame
),
4036 SIMPLE_XUL_CREATE(image
, NS_NewImageBoxFrame
),
4037 SIMPLE_XUL_CREATE(spring
, NS_NewLeafBoxFrame
),
4038 SIMPLE_XUL_CREATE(spacer
, NS_NewLeafBoxFrame
),
4039 SIMPLE_XUL_CREATE(treechildren
, NS_NewTreeBodyFrame
),
4040 SIMPLE_XUL_CREATE(treecol
, NS_NewTreeColFrame
),
4041 SIMPLE_XUL_CREATE(text
, NS_NewTextBoxFrame
),
4042 SIMPLE_TAG_CHAIN(label
, nsCSSFrameConstructor::FindXULLabelData
),
4043 SIMPLE_TAG_CHAIN(description
, nsCSSFrameConstructor::FindXULDescriptionData
),
4044 SIMPLE_XUL_CREATE(menu
, NS_NewMenuFrame
),
4045 SIMPLE_XUL_CREATE(menubutton
, NS_NewMenuFrame
),
4046 SIMPLE_XUL_CREATE(menuitem
, NS_NewMenuItemFrame
),
4048 SIMPLE_TAG_CHAIN(menubar
, nsCSSFrameConstructor::FindXULMenubarData
),
4050 SIMPLE_XUL_CREATE(menubar
, NS_NewMenuBarFrame
),
4051 #endif /* XP_MACOSX */
4052 SIMPLE_TAG_CHAIN(popupgroup
, nsCSSFrameConstructor::FindPopupGroupData
),
4053 SIMPLE_XUL_CREATE(iframe
, NS_NewSubDocumentFrame
),
4054 SIMPLE_XUL_CREATE(editor
, NS_NewSubDocumentFrame
),
4055 SIMPLE_XUL_CREATE(browser
, NS_NewSubDocumentFrame
),
4056 SIMPLE_XUL_CREATE(progressmeter
, NS_NewProgressMeterFrame
),
4057 SIMPLE_XUL_CREATE(splitter
, NS_NewSplitterFrame
),
4058 SIMPLE_TAG_CHAIN(listboxbody
,
4059 nsCSSFrameConstructor::FindXULListBoxBodyData
),
4060 SIMPLE_TAG_CHAIN(listitem
, nsCSSFrameConstructor::FindXULListItemData
),
4061 #endif /* MOZ_XUL */
4062 SIMPLE_XUL_CREATE(slider
, NS_NewSliderFrame
),
4063 SIMPLE_XUL_CREATE(scrollbar
, NS_NewScrollbarFrame
),
4064 SIMPLE_XUL_CREATE(scrollbarbutton
, NS_NewScrollbarButtonFrame
)
4067 return FindDataByTag(aTag
, aContent
, aStyleContext
, sXULTagData
,
4068 NS_ARRAY_LENGTH(sXULTagData
));
4073 const nsCSSFrameConstructor::FrameConstructionData
*
4074 nsCSSFrameConstructor::FindPopupGroupData(nsIContent
* aContent
,
4075 nsStyleContext
* /* unused */)
4077 if (!aContent
->IsRootOfNativeAnonymousSubtree()) {
4081 static const FrameConstructionData sPopupSetData
=
4082 SIMPLE_XUL_FCDATA(NS_NewPopupSetFrame
);
4083 return &sPopupSetData
;
4087 const nsCSSFrameConstructor::FrameConstructionData
4088 nsCSSFrameConstructor::sXULTextBoxData
= SIMPLE_XUL_FCDATA(NS_NewTextBoxFrame
);
4091 const nsCSSFrameConstructor::FrameConstructionData
*
4092 nsCSSFrameConstructor::FindXULLabelData(nsIContent
* aContent
,
4093 nsStyleContext
* /* unused */)
4095 if (aContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::value
)) {
4096 return &sXULTextBoxData
;
4099 static const FrameConstructionData sLabelData
=
4100 SIMPLE_XUL_FCDATA(NS_NewXULLabelFrame
);
4105 NS_NewXULDescriptionFrame(nsIPresShell
* aPresShell
, nsStyleContext
*aContext
)
4107 // XXXbz do we really need to set those flags? If the parent is not
4108 // a block we'll get them anyway, and if it is, do we want them?
4109 return NS_NewBlockFrame(aPresShell
, aContext
,
4110 NS_BLOCK_FLOAT_MGR
| NS_BLOCK_MARGIN_ROOT
);
4114 const nsCSSFrameConstructor::FrameConstructionData
*
4115 nsCSSFrameConstructor::FindXULDescriptionData(nsIContent
* aContent
,
4116 nsStyleContext
* /* unused */)
4118 if (aContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::value
)) {
4119 return &sXULTextBoxData
;
4122 static const FrameConstructionData sDescriptionData
=
4123 SIMPLE_XUL_FCDATA(NS_NewXULDescriptionFrame
);
4124 return &sDescriptionData
;
4129 const nsCSSFrameConstructor::FrameConstructionData
*
4130 nsCSSFrameConstructor::FindXULMenubarData(nsIContent
* aContent
,
4131 nsStyleContext
* aStyleContext
)
4133 nsCOMPtr
<nsISupports
> container
=
4134 aStyleContext
->PresContext()->GetContainer();
4136 nsCOMPtr
<nsIDocShellTreeItem
> treeItem(do_QueryInterface(container
));
4139 treeItem
->GetItemType(&type
);
4140 if (nsIDocShellTreeItem::typeChrome
== type
) {
4141 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
4142 treeItem
->GetParent(getter_AddRefs(parent
));
4144 // This is the root. Suppress the menubar, since on Mac
4145 // window menus are not attached to the window.
4146 static const FrameConstructionData sSuppressData
= SUPPRESS_FCDATA();
4147 return &sSuppressData
;
4153 static const FrameConstructionData sMenubarData
=
4154 SIMPLE_XUL_FCDATA(NS_NewMenuBarFrame
);
4155 return &sMenubarData
;
4157 #endif /* XP_MACOSX */
4160 const nsCSSFrameConstructor::FrameConstructionData
*
4161 nsCSSFrameConstructor::FindXULListBoxBodyData(nsIContent
* aContent
,
4162 nsStyleContext
* aStyleContext
)
4164 if (aStyleContext
->GetStyleDisplay()->mDisplay
!=
4165 NS_STYLE_DISPLAY_GRID_GROUP
) {
4169 static const FrameConstructionData sListBoxBodyData
=
4170 SCROLLABLE_XUL_FCDATA(NS_NewListBoxBodyFrame
);
4171 return &sListBoxBodyData
;
4175 const nsCSSFrameConstructor::FrameConstructionData
*
4176 nsCSSFrameConstructor::FindXULListItemData(nsIContent
* aContent
,
4177 nsStyleContext
* aStyleContext
)
4179 if (aStyleContext
->GetStyleDisplay()->mDisplay
!=
4180 NS_STYLE_DISPLAY_GRID_LINE
) {
4184 static const FrameConstructionData sListItemData
=
4185 SCROLLABLE_XUL_FCDATA(NS_NewListItemFrame
);
4186 return &sListItemData
;
4189 #endif /* MOZ_XUL */
4192 const nsCSSFrameConstructor::FrameConstructionData
*
4193 nsCSSFrameConstructor::FindXULDisplayData(const nsStyleDisplay
* aDisplay
,
4194 nsIContent
* aContent
,
4195 nsStyleContext
* aStyleContext
)
4197 static const FrameConstructionDataByInt sXULDisplayData
[] = {
4198 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_BOX
, NS_NewBoxFrame
),
4199 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_BOX
, NS_NewBoxFrame
),
4201 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_GRID
, NS_NewGridBoxFrame
),
4202 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GRID
, NS_NewGridBoxFrame
),
4203 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GRID_GROUP
,
4204 NS_NewGridRowGroupFrame
),
4205 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GRID_LINE
,
4206 NS_NewGridRowLeafFrame
),
4207 SIMPLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_DECK
, NS_NewDeckFrame
),
4208 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GROUPBOX
, NS_NewGroupBoxFrame
),
4209 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_STACK
, NS_NewStackFrame
),
4210 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_STACK
, NS_NewStackFrame
),
4211 { NS_STYLE_DISPLAY_POPUP
,
4212 FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW
| FCDATA_IS_POPUP
|
4213 FCDATA_SKIP_ABSPOS_PUSH
, NS_NewMenuPopupFrame
) }
4214 #endif /* MOZ_XUL */
4217 // Processing by display here:
4218 return FindDataByInt(aDisplay
->mDisplay
, aContent
, aStyleContext
,
4219 sXULDisplayData
, NS_ARRAY_LENGTH(sXULDisplayData
));
4222 already_AddRefed
<nsStyleContext
>
4223 nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState
& aState
,
4224 nsIContent
* aContent
,
4225 nsStyleContext
* aContentStyle
,
4226 nsIFrame
* aParentFrame
,
4227 nsIAtom
* aScrolledPseudo
,
4229 nsIFrame
*& aNewFrame
)
4231 nsIFrame
* gfxScrollFrame
= aNewFrame
;
4233 nsFrameItems anonymousItems
;
4235 nsRefPtr
<nsStyleContext
> contentStyle
= aContentStyle
;
4237 if (!gfxScrollFrame
) {
4238 // Build a XULScrollFrame when the child is a box, otherwise an
4240 // XXXbz this is the lone remaining consumer of IsXULDisplayType.
4241 // I wonder whether we can eliminate that somehow.
4242 if (IsXULDisplayType(aContentStyle
->GetStyleDisplay())) {
4243 gfxScrollFrame
= NS_NewXULScrollFrame(mPresShell
, contentStyle
, aIsRoot
);
4245 gfxScrollFrame
= NS_NewHTMLScrollFrame(mPresShell
, contentStyle
, aIsRoot
);
4248 InitAndRestoreFrame(aState
, aContent
, aParentFrame
, nsnull
, gfxScrollFrame
);
4251 nsHTMLContainerFrame::CreateViewForFrame(gfxScrollFrame
, PR_FALSE
);
4254 // if there are any anonymous children for the scroll frame, create
4256 // Pass a null pending binding: we don't care how constructors for any of
4257 // this anonymous content order with anything else. It's never been
4258 // consistent anyway.
4259 CreateAnonymousFrames(aState
, aContent
, gfxScrollFrame
, nsnull
,
4262 aNewFrame
= gfxScrollFrame
;
4264 // we used the style that was passed in. So resolve another one.
4265 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
4266 nsStyleContext
* aScrolledChildStyle
=
4267 styleSet
->ResolveAnonymousBoxStyle(aScrolledPseudo
, contentStyle
).get();
4269 if (gfxScrollFrame
) {
4270 gfxScrollFrame
->SetInitialChildList(nsnull
, anonymousItems
);
4273 return aScrolledChildStyle
;
4277 nsCSSFrameConstructor::FinishBuildingScrollFrame(nsIFrame
* aScrollFrame
,
4278 nsIFrame
* aScrolledFrame
)
4280 nsFrameList
scrolled(aScrolledFrame
, aScrolledFrame
);
4281 aScrollFrame
->AppendFrames(nsnull
, scrolled
);
4286 * Called to wrap a gfx scrollframe around a frame. The hierarchy will look like this
4288 * ------- for gfx scrollbars ------
4294 * Frame (scrolled frame you passed in)
4297 *-----------------------------------
4300 * ScrollFrame: This is a frame that manages gfx cross platform frame based scrollbars.
4302 * @param aContent the content node of the child to wrap.
4303 * @param aScrolledFrame The frame of the content to wrap. This should not be
4304 * Initialized. This method will initialize it with a scrolled pseudo
4305 * and no nsIContent. The content will be attached to the scrollframe
4307 * @param aContentStyle the style context that has already been resolved for the content being passed in.
4309 * @param aParentFrame The parent to attach the scroll frame to
4311 * @param aNewFrame The new scrollframe or gfx scrollframe that we create. It will contain the
4312 * scrolled frame you passed in. (returned)
4313 * If this is not null, we'll just use it
4314 * @param aScrolledContentStyle the style that was resolved for the scrolled frame. (returned)
4317 nsCSSFrameConstructor::BuildScrollFrame(nsFrameConstructorState
& aState
,
4318 nsIContent
* aContent
,
4319 nsStyleContext
* aContentStyle
,
4320 nsIFrame
* aScrolledFrame
,
4321 nsIFrame
* aParentFrame
,
4322 nsIFrame
*& aNewFrame
)
4324 nsRefPtr
<nsStyleContext
> scrolledContentStyle
=
4325 BeginBuildingScrollFrame(aState
, aContent
, aContentStyle
, aParentFrame
,
4326 nsCSSAnonBoxes::scrolledContent
,
4327 PR_FALSE
, aNewFrame
);
4329 aScrolledFrame
->SetStyleContextWithoutNotification(scrolledContentStyle
);
4330 InitAndRestoreFrame(aState
, aContent
, aNewFrame
, nsnull
, aScrolledFrame
);
4332 FinishBuildingScrollFrame(aNewFrame
, aScrolledFrame
);
4336 const nsCSSFrameConstructor::FrameConstructionData
*
4337 nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay
* aDisplay
,
4338 nsIContent
* aContent
,
4339 nsStyleContext
* aStyleContext
)
4341 PR_STATIC_ASSERT(eParentTypeCount
< (1 << (32 - FCDATA_PARENT_TYPE_OFFSET
)));
4343 // The style system ensures that floated and positioned frames are
4345 NS_ASSERTION(!(aDisplay
->IsFloating() ||
4346 aDisplay
->IsAbsolutelyPositioned()) ||
4347 aDisplay
->IsBlockOutside(),
4348 "Style system did not apply CSS2.1 section 9.7 fixups");
4350 // If this is "body", try propagating its scroll style to the viewport
4351 // Note that we need to do this even if the body is NOT scrollable;
4352 // it might have dynamically changed from scrollable to not scrollable,
4353 // and that might need to be propagated.
4354 // XXXbz is this the right place to do this? If this code moves,
4355 // make this function static.
4356 PRBool propagatedScrollToViewport
= PR_FALSE
;
4357 if (aContent
->NodeInfo()->Equals(nsGkAtoms::body
) &&
4358 aContent
->IsHTML()) {
4359 propagatedScrollToViewport
=
4360 PropagateScrollToViewport() == aContent
;
4363 NS_ASSERTION(!propagatedScrollToViewport
||
4364 !mPresShell
->GetPresContext()->IsPaginated(),
4365 "Shouldn't propagate scroll in paginated contexts");
4367 // If the frame is a block-level frame and is scrollable, then wrap it in a
4368 // scroll frame. Except we don't want to do that for paginated contexts for
4369 // frames that are block-outside and aren't frames for native anonymous stuff.
4370 // The condition on skipping scrollframe construction in the
4371 // paginated case needs to match code in ConstructNonScrollableBlock
4372 // and in nsFrame::ApplyPaginatedOverflowClipping.
4373 // XXX Ignore tables for the time being
4374 // XXXbz it would be nice to combine this with the other block
4375 // case... Think about how do do this?
4376 if (aDisplay
->IsBlockInside() &&
4377 aDisplay
->IsScrollableOverflow() &&
4378 !propagatedScrollToViewport
&&
4379 (!mPresShell
->GetPresContext()->IsPaginated() ||
4380 !aDisplay
->IsBlockOutside() ||
4381 aContent
->IsInNativeAnonymousSubtree())) {
4382 static const FrameConstructionData sScrollableBlockData
=
4383 FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructScrollableBlock
);
4384 return &sScrollableBlockData
;
4387 // Handle various non-scrollable blocks
4388 if (aDisplay
->IsBlockInside() ||
4389 NS_STYLE_DISPLAY_RUN_IN
== aDisplay
->mDisplay
||
4390 NS_STYLE_DISPLAY_COMPACT
== aDisplay
->mDisplay
) {
4391 static const FrameConstructionData sNonScrollableBlockData
=
4392 FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructNonScrollableBlock
);
4393 return &sNonScrollableBlockData
;
4396 static const FrameConstructionDataByInt sDisplayData
[] = {
4397 // To keep the hash table small don't add inline frames (they're
4398 // typically things like FONT and B), because we can quickly
4399 // find them if we need to.
4400 // XXXbz the "quickly" part is a bald-faced lie!
4401 { NS_STYLE_DISPLAY_INLINE
,
4402 FULL_CTOR_FCDATA(FCDATA_IS_INLINE
| FCDATA_IS_LINE_PARTICIPANT
,
4403 &nsCSSFrameConstructor::ConstructInline
) },
4404 { NS_STYLE_DISPLAY_MARKER
,
4405 FULL_CTOR_FCDATA(FCDATA_IS_INLINE
| FCDATA_IS_LINE_PARTICIPANT
,
4406 &nsCSSFrameConstructor::ConstructInline
) },
4407 { NS_STYLE_DISPLAY_TABLE
,
4408 FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable
) },
4409 { NS_STYLE_DISPLAY_INLINE_TABLE
,
4410 FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable
) },
4411 { NS_STYLE_DISPLAY_TABLE_CAPTION
,
4412 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_ALLOW_BLOCK_STYLES
|
4413 FCDATA_DISALLOW_OUT_OF_FLOW
| FCDATA_SKIP_ABSPOS_PUSH
|
4414 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
4415 NS_NewTableCaptionFrame
) },
4416 { NS_STYLE_DISPLAY_TABLE_ROW_GROUP
,
4417 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_DISALLOW_OUT_OF_FLOW
|
4418 FCDATA_SKIP_ABSPOS_PUSH
|
4419 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
4420 NS_NewTableRowGroupFrame
) },
4421 { NS_STYLE_DISPLAY_TABLE_HEADER_GROUP
,
4422 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_DISALLOW_OUT_OF_FLOW
|
4423 FCDATA_SKIP_ABSPOS_PUSH
|
4424 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
4425 NS_NewTableRowGroupFrame
) },
4426 { NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP
,
4427 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_DISALLOW_OUT_OF_FLOW
|
4428 FCDATA_SKIP_ABSPOS_PUSH
|
4429 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
4430 NS_NewTableRowGroupFrame
) },
4431 { NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
,
4432 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_DISALLOW_OUT_OF_FLOW
|
4433 FCDATA_SKIP_ABSPOS_PUSH
|
4434 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
4435 NS_NewTableColGroupFrame
) },
4436 { NS_STYLE_DISPLAY_TABLE_COLUMN
,
4437 FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART
|
4438 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeColGroup
),
4439 &nsCSSFrameConstructor::ConstructTableCol
) },
4440 { NS_STYLE_DISPLAY_TABLE_ROW
,
4441 FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART
|
4442 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup
),
4443 &nsCSSFrameConstructor::ConstructTableRow
) },
4444 { NS_STYLE_DISPLAY_TABLE_CELL
,
4445 FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART
|
4446 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow
),
4447 &nsCSSFrameConstructor::ConstructTableCell
) }
4450 return FindDataByInt(aDisplay
->mDisplay
, aContent
, aStyleContext
,
4451 sDisplayData
, NS_ARRAY_LENGTH(sDisplayData
));
4455 nsCSSFrameConstructor::ConstructScrollableBlock(nsFrameConstructorState
& aState
,
4456 FrameConstructionItem
& aItem
,
4457 nsIFrame
* aParentFrame
,
4458 const nsStyleDisplay
* aDisplay
,
4459 nsFrameItems
& aFrameItems
,
4460 nsIFrame
** aNewFrame
)
4462 nsIContent
* const content
= aItem
.mContent
;
4463 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
4465 *aNewFrame
= nsnull
;
4466 nsRefPtr
<nsStyleContext
> scrolledContentStyle
4467 = BeginBuildingScrollFrame(aState
, content
, styleContext
,
4468 aState
.GetGeometricParent(aDisplay
, aParentFrame
),
4469 nsCSSAnonBoxes::scrolledContent
,
4470 PR_FALSE
, *aNewFrame
);
4472 // Create our block frame
4473 // pass a temporary stylecontext, the correct one will be set later
4474 nsIFrame
* scrolledFrame
=
4475 NS_NewBlockFormattingContext(mPresShell
, styleContext
);
4477 nsFrameItems blockItem
;
4478 nsresult rv
= ConstructBlock(aState
,
4479 scrolledContentStyle
->GetStyleDisplay(), content
,
4480 *aNewFrame
, *aNewFrame
, scrolledContentStyle
,
4481 &scrolledFrame
, blockItem
, aDisplay
->IsPositioned(),
4482 aItem
.mPendingBinding
);
4483 if (NS_UNLIKELY(NS_FAILED(rv
))) {
4484 // XXXbz any cleanup needed here?
4488 NS_ASSERTION(blockItem
.FirstChild() == scrolledFrame
,
4489 "Scrollframe's frameItems should be exactly the scrolled frame");
4490 FinishBuildingScrollFrame(*aNewFrame
, scrolledFrame
);
4492 rv
= aState
.AddChild(*aNewFrame
, aFrameItems
, content
, styleContext
,
4498 nsCSSFrameConstructor::ConstructNonScrollableBlock(nsFrameConstructorState
& aState
,
4499 FrameConstructionItem
& aItem
,
4500 nsIFrame
* aParentFrame
,
4501 const nsStyleDisplay
* aDisplay
,
4502 nsFrameItems
& aFrameItems
,
4503 nsIFrame
** aNewFrame
)
4505 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
4507 if (aDisplay
->IsAbsolutelyPositioned() ||
4508 aDisplay
->IsFloating() ||
4509 NS_STYLE_DISPLAY_INLINE_BLOCK
== aDisplay
->mDisplay
||
4510 // This check just needs to be the same as the check for using scrollable
4511 // blocks in FindDisplayData and the check for clipping in
4512 // nsFrame::ApplyPaginatedOverflowClipping; we want a block formatting
4513 // context root in paginated contexts for every block that would be
4514 // scrollable in a non-paginated context. Note that IsPaginated()
4515 // implies that no propagation to viewport has taken place, so we don't
4516 // need to check for propagation here.
4517 (mPresShell
->GetPresContext()->IsPaginated() &&
4518 aDisplay
->IsBlockInside() &&
4519 aDisplay
->IsScrollableOverflow() &&
4520 aDisplay
->IsBlockOutside() &&
4521 !aItem
.mContent
->IsInNativeAnonymousSubtree())) {
4522 *aNewFrame
= NS_NewBlockFormattingContext(mPresShell
, styleContext
);
4524 *aNewFrame
= NS_NewBlockFrame(mPresShell
, styleContext
);
4527 return ConstructBlock(aState
, aDisplay
, aItem
.mContent
,
4528 aState
.GetGeometricParent(aDisplay
, aParentFrame
),
4529 aParentFrame
, styleContext
, aNewFrame
,
4530 aFrameItems
, aDisplay
->IsPositioned(),
4531 aItem
.mPendingBinding
);
4536 nsCSSFrameConstructor::InitAndRestoreFrame(const nsFrameConstructorState
& aState
,
4537 nsIContent
* aContent
,
4538 nsIFrame
* aParentFrame
,
4539 nsIFrame
* aPrevInFlow
,
4540 nsIFrame
* aNewFrame
,
4541 PRBool aAllowCounters
)
4543 NS_PRECONDITION(mUpdateCount
!= 0,
4544 "Should be in an update while creating frames");
4546 nsresult rv
= NS_OK
;
4548 NS_ASSERTION(aNewFrame
, "Null frame cannot be initialized");
4550 return NS_ERROR_NULL_POINTER
;
4552 // Initialize the frame
4553 rv
= aNewFrame
->Init(aContent
, aParentFrame
, aPrevInFlow
);
4554 aNewFrame
->AddStateBits(aState
.mAdditionalStateBits
);
4556 if (aState
.mFrameState
&& aState
.mFrameManager
) {
4557 // Restore frame state for just the newly created frame.
4558 aState
.mFrameManager
->RestoreFrameStateFor(aNewFrame
, aState
.mFrameState
);
4561 if (aAllowCounters
&& !aPrevInFlow
&&
4562 mCounterManager
.AddCounterResetsAndIncrements(aNewFrame
)) {
4569 already_AddRefed
<nsStyleContext
>
4570 nsCSSFrameConstructor::ResolveStyleContext(nsIFrame
* aParentFrame
,
4571 nsIContent
* aContent
)
4573 nsStyleContext
* parentStyleContext
= nsnull
;
4574 NS_ASSERTION(aContent
->GetParent(), "Must have parent here");
4576 aParentFrame
= nsFrame::CorrectStyleParentFrame(aParentFrame
, nsnull
);
4579 // Resolve the style context based on the content object and the parent
4581 parentStyleContext
= aParentFrame
->GetStyleContext();
4583 // Perhaps aParentFrame is a canvasFrame and we're replicating
4584 // fixed-pos frames.
4585 // XXX should we create a way to tell ConstructFrame which style
4586 // context to use, and pass it the style context for the
4587 // previous page's fixed-pos frame?
4590 return ResolveStyleContext(parentStyleContext
, aContent
);
4593 already_AddRefed
<nsStyleContext
>
4594 nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext
* aParentStyleContext
,
4595 nsIContent
* aContent
)
4597 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
4599 if (aContent
->IsElement()) {
4600 return styleSet
->ResolveStyleFor(aContent
->AsElement(), aParentStyleContext
);
4603 NS_ASSERTION(aContent
->IsNodeOfType(nsINode::eTEXT
),
4604 "shouldn't waste time creating style contexts for "
4605 "comments and processing instructions");
4607 return styleSet
->ResolveStyleForNonElement(aParentStyleContext
);
4613 nsCSSFrameConstructor::FlushAccumulatedBlock(nsFrameConstructorState
& aState
,
4614 nsIContent
* aContent
,
4615 nsIFrame
* aParentFrame
,
4616 nsFrameItems
* aBlockItems
,
4617 nsFrameItems
* aNewItems
)
4619 if (aBlockItems
->IsEmpty()) {
4624 nsStyleContext
* parentContext
=
4625 nsFrame::CorrectStyleParentFrame(aParentFrame
,
4626 nsCSSAnonBoxes::mozMathMLAnonymousBlock
)->GetStyleContext();
4627 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
4628 nsRefPtr
<nsStyleContext
> blockContext
;
4629 blockContext
= styleSet
->
4630 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozMathMLAnonymousBlock
,
4633 // then, create a block frame that will wrap the child frames. Make it a
4634 // MathML frame so that Get(Absolute/Float)ContainingBlockFor know that this
4635 // is not a suitable block.
4636 nsIFrame
* blockFrame
= NS_NewMathMLmathBlockFrame(mPresShell
, blockContext
,
4637 NS_BLOCK_FLOAT_MGR
| NS_BLOCK_MARGIN_ROOT
);
4638 if (NS_UNLIKELY(!blockFrame
))
4639 return NS_ERROR_OUT_OF_MEMORY
;
4641 InitAndRestoreFrame(aState
, aContent
, aParentFrame
, nsnull
, blockFrame
);
4642 ReparentFrames(aState
.mFrameManager
, blockFrame
, *aBlockItems
);
4643 // abs-pos and floats are disabled in MathML children so we don't have to
4644 // worry about messing up those.
4645 blockFrame
->SetInitialChildList(nsnull
, *aBlockItems
);
4646 NS_ASSERTION(aBlockItems
->IsEmpty(), "What happened?");
4647 aBlockItems
->Clear();
4648 aNewItems
->AddChild(blockFrame
);
4652 // Only <math> elements can be floated or positioned. All other MathML
4653 // should be in-flow.
4654 #define SIMPLE_MATHML_CREATE(_tag, _func) \
4655 { &nsGkAtoms::_tag, \
4656 FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \
4657 FCDATA_FORCE_NULL_ABSPOS_CONTAINER | \
4658 FCDATA_WRAP_KIDS_IN_BLOCKS, _func) }
4661 const nsCSSFrameConstructor::FrameConstructionData
*
4662 nsCSSFrameConstructor::FindMathMLData(nsIContent
* aContent
,
4664 PRInt32 aNameSpaceID
,
4665 nsStyleContext
* aStyleContext
)
4667 // Make sure that we remain confined in the MathML world
4668 if (aNameSpaceID
!= kNameSpaceID_MathML
)
4671 // Handle <math> specially, because it sometimes produces inlines
4672 if (aTag
== nsGkAtoms::math
) {
4673 // This needs to match the test in EnsureBlockDisplay in
4674 // nsRuleNode.cpp. Though the behavior here for the display:table
4675 // case is pretty weird...
4676 if (aStyleContext
->GetStyleDisplay()->IsBlockOutside()) {
4677 static const FrameConstructionData sBlockMathData
=
4678 FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER
|
4679 FCDATA_WRAP_KIDS_IN_BLOCKS
,
4680 NS_CreateNewMathMLmathBlockFrame
);
4681 return &sBlockMathData
;
4684 static const FrameConstructionData sInlineMathData
=
4685 FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER
|
4686 FCDATA_IS_LINE_PARTICIPANT
|
4687 FCDATA_WRAP_KIDS_IN_BLOCKS
,
4688 NS_NewMathMLmathInlineFrame
);
4689 return &sInlineMathData
;
4693 static const FrameConstructionDataByTag sMathMLData
[] = {
4694 SIMPLE_MATHML_CREATE(mi_
, NS_NewMathMLTokenFrame
),
4695 SIMPLE_MATHML_CREATE(mn_
, NS_NewMathMLTokenFrame
),
4696 SIMPLE_MATHML_CREATE(ms_
, NS_NewMathMLTokenFrame
),
4697 SIMPLE_MATHML_CREATE(mtext_
, NS_NewMathMLTokenFrame
),
4698 SIMPLE_MATHML_CREATE(mo_
, NS_NewMathMLmoFrame
),
4699 SIMPLE_MATHML_CREATE(mfrac_
, NS_NewMathMLmfracFrame
),
4700 SIMPLE_MATHML_CREATE(msup_
, NS_NewMathMLmsupFrame
),
4701 SIMPLE_MATHML_CREATE(msub_
, NS_NewMathMLmsubFrame
),
4702 SIMPLE_MATHML_CREATE(msubsup_
, NS_NewMathMLmsubsupFrame
),
4703 SIMPLE_MATHML_CREATE(munder_
, NS_NewMathMLmunderFrame
),
4704 SIMPLE_MATHML_CREATE(mover_
, NS_NewMathMLmoverFrame
),
4705 SIMPLE_MATHML_CREATE(munderover_
, NS_NewMathMLmunderoverFrame
),
4706 SIMPLE_MATHML_CREATE(mphantom_
, NS_NewMathMLmphantomFrame
),
4707 SIMPLE_MATHML_CREATE(mpadded_
, NS_NewMathMLmpaddedFrame
),
4708 SIMPLE_MATHML_CREATE(mspace_
, NS_NewMathMLmspaceFrame
),
4709 SIMPLE_MATHML_CREATE(none
, NS_NewMathMLmspaceFrame
),
4710 SIMPLE_MATHML_CREATE(mprescripts_
, NS_NewMathMLmspaceFrame
),
4711 SIMPLE_MATHML_CREATE(mfenced_
, NS_NewMathMLmfencedFrame
),
4712 SIMPLE_MATHML_CREATE(mmultiscripts_
, NS_NewMathMLmmultiscriptsFrame
),
4713 SIMPLE_MATHML_CREATE(mstyle_
, NS_NewMathMLmstyleFrame
),
4714 SIMPLE_MATHML_CREATE(msqrt_
, NS_NewMathMLmsqrtFrame
),
4715 SIMPLE_MATHML_CREATE(mroot_
, NS_NewMathMLmrootFrame
),
4716 SIMPLE_MATHML_CREATE(maction_
, NS_NewMathMLmactionFrame
),
4717 SIMPLE_MATHML_CREATE(mrow_
, NS_NewMathMLmrowFrame
),
4718 SIMPLE_MATHML_CREATE(merror_
, NS_NewMathMLmrowFrame
),
4719 SIMPLE_MATHML_CREATE(menclose_
, NS_NewMathMLmencloseFrame
),
4720 SIMPLE_MATHML_CREATE(semantics_
, NS_NewMathMLsemanticsFrame
)
4723 return FindDataByTag(aTag
, aContent
, aStyleContext
, sMathMLData
,
4724 NS_ARRAY_LENGTH(sMathMLData
));
4726 #endif // MOZ_MATHML
4729 // Only outer <svg> elements can be floated or positioned. All other SVG
4730 // should be in-flow.
4731 #define SIMPLE_SVG_FCDATA(_func) \
4732 FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \
4733 FCDATA_SKIP_ABSPOS_PUSH | \
4734 FCDATA_DISALLOW_GENERATED_CONTENT, _func)
4735 #define SIMPLE_SVG_CREATE(_tag, _func) \
4736 { &nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func) }
4739 const nsCSSFrameConstructor::FrameConstructionData
*
4740 nsCSSFrameConstructor::FindSVGData(nsIContent
* aContent
,
4742 PRInt32 aNameSpaceID
,
4743 nsIFrame
* aParentFrame
,
4744 nsStyleContext
* aStyleContext
)
4746 if (aNameSpaceID
!= kNameSpaceID_SVG
|| !NS_SVGEnabled()) {
4750 static const FrameConstructionData sSuppressData
= SUPPRESS_FCDATA();
4751 static const FrameConstructionData sGenericContainerData
=
4752 SIMPLE_SVG_FCDATA(NS_NewSVGGenericContainerFrame
);
4754 PRBool parentIsSVG
= PR_FALSE
;
4755 nsIContent
* parentContent
=
4756 aParentFrame
? aParentFrame
->GetContent() : nsnull
;
4757 // XXXbz should this really be based on the XBL-resolved tag of the parent
4758 // frame's content? Should it not be based on the type of the parent frame
4759 // (e.g. whether it's an SVG frame)?
4760 if (parentContent
) {
4762 nsIAtom
* parentTag
=
4763 parentContent
->GetOwnerDoc()->BindingManager()->
4764 ResolveTag(aParentFrame
->GetContent(), &parentNSID
);
4766 // It's not clear whether the SVG spec intends to allow any SVG
4767 // content within svg:foreignObject at all (SVG 1.1, section
4768 // 23.2), but if it does, it better be svg:svg. So given that
4769 // we're allowing it, treat it as a non-SVG parent.
4770 parentIsSVG
= parentNSID
== kNameSpaceID_SVG
&&
4771 parentTag
!= nsGkAtoms::foreignObject
;
4774 if ((aTag
!= nsGkAtoms::svg
&& !parentIsSVG
) ||
4775 (aTag
== nsGkAtoms::desc
|| aTag
== nsGkAtoms::title
)) {
4776 // Sections 5.1 and G.4 of SVG 1.1 say that SVG elements other than
4777 // svg:svg not contained within svg:svg are incorrect, although they
4778 // don't seem to specify error handling. Ignore them, since many of
4779 // our frame classes can't deal. It *may* be that the document
4780 // should at that point be considered in error according to F.2, but
4781 // it's hard to tell.
4783 // Style mutation can't change this situation, so don't bother
4784 // adding to the undisplayed content map.
4786 // We don't currently handle any UI for desc/title
4787 return &sSuppressData
;
4790 // We don't need frames for animation elements
4791 if (aContent
->IsNodeOfType(nsINode::eANIMATION
)) {
4792 return &sSuppressData
;
4795 // Reduce the number of frames we create unnecessarily. Note that this is not
4796 // where we select which frame in a <switch> to render! That happens in
4797 // nsSVGSwitchFrame::PaintSVG.
4798 if (!nsSVGFeatures::PassesConditionalProcessingTests(aContent
)) {
4799 // Note that just returning is probably not right. According
4800 // to the spec, <use> is allowed to use an element that fails its
4801 // conditional, but because we never actually create the frame when
4802 // a conditional fails and when we use GetReferencedFrame to find the
4803 // references, things don't work right.
4805 return &sSuppressData
;
4808 // Special case for aTag == nsGkAtoms::svg because we don't want to
4809 // have to recompute parentIsSVG for it.
4810 if (aTag
== nsGkAtoms::svg
) {
4812 static const FrameConstructionData sInnerSVGData
=
4813 SIMPLE_SVG_FCDATA(NS_NewSVGInnerSVGFrame
);
4814 return &sInnerSVGData
;
4817 static const FrameConstructionData sOuterSVGData
=
4818 FCDATA_DECL(FCDATA_FORCE_VIEW
| FCDATA_SKIP_ABSPOS_PUSH
|
4819 FCDATA_DISALLOW_GENERATED_CONTENT
,
4820 NS_NewSVGOuterSVGFrame
);
4821 return &sOuterSVGData
;
4824 // Special cases for text/tspan/textPath, because the kind of frame
4825 // they get depends on the parent frame. We ignore 'a' elements when
4826 // determining the parent, however.
4827 nsIFrame
*ancestorFrame
=
4828 nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame
);
4829 if (ancestorFrame
) {
4830 if (aTag
== nsGkAtoms::tspan
|| aTag
== nsGkAtoms::altGlyph
) {
4831 // tspan and altGlyph must be children of another text content element.
4832 nsSVGTextContainerFrame
* metrics
= do_QueryFrame(ancestorFrame
);
4834 return &sSuppressData
;
4836 } else if (aTag
== nsGkAtoms::textPath
) {
4837 // textPath must be a child of text.
4838 nsIAtom
* ancestorFrameType
= ancestorFrame
->GetType();
4839 if (ancestorFrameType
!= nsGkAtoms::svgTextFrame
) {
4840 return &sSuppressData
;
4842 } else if (aTag
!= nsGkAtoms::a
) {
4843 // Every other element except 'a' must not be a child of a text content
4845 nsSVGTextContainerFrame
* metrics
= do_QueryFrame(ancestorFrame
);
4847 return &sSuppressData
;
4852 static const FrameConstructionDataByTag sSVGData
[] = {
4853 SIMPLE_SVG_CREATE(g
, NS_NewSVGGFrame
),
4854 SIMPLE_SVG_CREATE(svgSwitch
, NS_NewSVGSwitchFrame
),
4855 SIMPLE_SVG_CREATE(polygon
, NS_NewSVGPathGeometryFrame
),
4856 SIMPLE_SVG_CREATE(polyline
, NS_NewSVGPathGeometryFrame
),
4857 SIMPLE_SVG_CREATE(circle
, NS_NewSVGPathGeometryFrame
),
4858 SIMPLE_SVG_CREATE(ellipse
, NS_NewSVGPathGeometryFrame
),
4859 SIMPLE_SVG_CREATE(line
, NS_NewSVGPathGeometryFrame
),
4860 SIMPLE_SVG_CREATE(rect
, NS_NewSVGPathGeometryFrame
),
4861 SIMPLE_SVG_CREATE(path
, NS_NewSVGPathGeometryFrame
),
4862 SIMPLE_SVG_CREATE(defs
, NS_NewSVGContainerFrame
),
4863 { &nsGkAtoms::foreignObject
,
4864 FULL_CTOR_FCDATA(FCDATA_DISALLOW_OUT_OF_FLOW
,
4865 &nsCSSFrameConstructor::ConstructSVGForeignObjectFrame
) },
4866 SIMPLE_SVG_CREATE(a
, NS_NewSVGAFrame
),
4867 SIMPLE_SVG_CREATE(altGlyph
, NS_NewSVGTSpanFrame
),
4868 SIMPLE_SVG_CREATE(text
, NS_NewSVGTextFrame
),
4869 SIMPLE_SVG_CREATE(tspan
, NS_NewSVGTSpanFrame
),
4870 SIMPLE_SVG_CREATE(linearGradient
, NS_NewSVGLinearGradientFrame
),
4871 SIMPLE_SVG_CREATE(radialGradient
, NS_NewSVGRadialGradientFrame
),
4872 SIMPLE_SVG_CREATE(stop
, NS_NewSVGStopFrame
),
4873 SIMPLE_SVG_CREATE(use
, NS_NewSVGUseFrame
),
4874 SIMPLE_SVG_CREATE(marker
, NS_NewSVGMarkerFrame
),
4875 SIMPLE_SVG_CREATE(image
, NS_NewSVGImageFrame
),
4876 SIMPLE_SVG_CREATE(clipPath
, NS_NewSVGClipPathFrame
),
4877 SIMPLE_SVG_CREATE(textPath
, NS_NewSVGTextPathFrame
),
4878 SIMPLE_SVG_CREATE(filter
, NS_NewSVGFilterFrame
),
4879 SIMPLE_SVG_CREATE(pattern
, NS_NewSVGPatternFrame
),
4880 SIMPLE_SVG_CREATE(mask
, NS_NewSVGMaskFrame
),
4881 SIMPLE_SVG_CREATE(feDistantLight
, NS_NewSVGLeafFrame
),
4882 SIMPLE_SVG_CREATE(fePointLight
, NS_NewSVGLeafFrame
),
4883 SIMPLE_SVG_CREATE(feSpotLight
, NS_NewSVGLeafFrame
),
4884 SIMPLE_SVG_CREATE(feBlend
, NS_NewSVGLeafFrame
),
4885 SIMPLE_SVG_CREATE(feColorMatrix
, NS_NewSVGLeafFrame
),
4886 SIMPLE_SVG_CREATE(feFuncR
, NS_NewSVGLeafFrame
),
4887 SIMPLE_SVG_CREATE(feFuncG
, NS_NewSVGLeafFrame
),
4888 SIMPLE_SVG_CREATE(feFuncB
, NS_NewSVGLeafFrame
),
4889 SIMPLE_SVG_CREATE(feFuncA
, NS_NewSVGLeafFrame
),
4890 SIMPLE_SVG_CREATE(feComposite
, NS_NewSVGLeafFrame
),
4891 SIMPLE_SVG_CREATE(feComponentTransfer
, NS_NewSVGLeafFrame
),
4892 SIMPLE_SVG_CREATE(feConvolveMatrix
, NS_NewSVGLeafFrame
),
4893 SIMPLE_SVG_CREATE(feDiffuseLighting
, NS_NewSVGLeafFrame
),
4894 SIMPLE_SVG_CREATE(feDisplacementMap
, NS_NewSVGLeafFrame
),
4895 SIMPLE_SVG_CREATE(feFlood
, NS_NewSVGLeafFrame
),
4896 SIMPLE_SVG_CREATE(feGaussianBlur
, NS_NewSVGLeafFrame
),
4897 SIMPLE_SVG_CREATE(feImage
, NS_NewSVGLeafFrame
),
4898 SIMPLE_SVG_CREATE(feMergeNode
, NS_NewSVGLeafFrame
),
4899 SIMPLE_SVG_CREATE(feMorphology
, NS_NewSVGLeafFrame
),
4900 SIMPLE_SVG_CREATE(feOffset
, NS_NewSVGLeafFrame
),
4901 SIMPLE_SVG_CREATE(feSpecularLighting
, NS_NewSVGLeafFrame
),
4902 SIMPLE_SVG_CREATE(feTile
, NS_NewSVGLeafFrame
),
4903 SIMPLE_SVG_CREATE(feTurbulence
, NS_NewSVGLeafFrame
)
4906 const FrameConstructionData
* data
=
4907 FindDataByTag(aTag
, aContent
, aStyleContext
, sSVGData
,
4908 NS_ARRAY_LENGTH(sSVGData
));
4911 data
= &sSuppressData
;
4918 nsCSSFrameConstructor::ConstructSVGForeignObjectFrame(nsFrameConstructorState
& aState
,
4919 FrameConstructionItem
& aItem
,
4920 nsIFrame
* aParentFrame
,
4921 const nsStyleDisplay
* aStyleDisplay
,
4922 nsFrameItems
& aFrameItems
,
4923 nsIFrame
** aNewFrame
)
4925 nsIContent
* const content
= aItem
.mContent
;
4926 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
4928 nsIFrame
* newFrame
= NS_NewSVGForeignObjectFrame(mPresShell
, styleContext
);
4929 if (NS_UNLIKELY(!newFrame
)) {
4930 return NS_ERROR_OUT_OF_MEMORY
;
4933 // We don't allow this frame to be out of flow
4934 InitAndRestoreFrame(aState
, content
, aParentFrame
, nsnull
, newFrame
);
4935 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
4937 nsresult rv
= aState
.AddChild(newFrame
, aFrameItems
, content
, styleContext
,
4938 aParentFrame
, PR_FALSE
, PR_FALSE
);
4939 if (NS_FAILED(rv
)) {
4943 nsRefPtr
<nsStyleContext
> innerPseudoStyle
;
4944 innerPseudoStyle
= mPresShell
->StyleSet()->
4945 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozSVGForeignContent
, styleContext
);
4947 nsIFrame
* blockFrame
= NS_NewBlockFrame(mPresShell
, innerPseudoStyle
,
4948 NS_BLOCK_FLOAT_MGR
|
4949 NS_BLOCK_MARGIN_ROOT
);
4950 if (NS_UNLIKELY(!blockFrame
)) {
4951 newFrame
->Destroy();
4952 return NS_ERROR_OUT_OF_MEMORY
;
4955 nsFrameItems childItems
;
4956 // Claim to be relatively positioned so that we end up being the
4957 // absolute containing block.
4958 rv
= ConstructBlock(aState
, innerPseudoStyle
->GetStyleDisplay(), content
,
4959 newFrame
, newFrame
, innerPseudoStyle
,
4960 &blockFrame
, childItems
, PR_TRUE
,
4961 aItem
.mPendingBinding
);
4963 // Give the blockFrame a view so that GetOffsetTo works for descendants
4964 // of blockFrame with views...
4965 nsHTMLContainerFrame::CreateViewForFrame(blockFrame
, PR_TRUE
);
4967 newFrame
->SetInitialChildList(nsnull
, childItems
);
4969 *aNewFrame
= newFrame
;
4977 nsCSSFrameConstructor::AddPageBreakItem(nsIContent
* aContent
,
4978 nsStyleContext
* aMainStyleContext
,
4979 FrameConstructionItemList
& aItems
)
4981 nsRefPtr
<nsStyleContext
> pseudoStyle
;
4982 // Use the same parent style context that |aMainStyleContext| has, since
4983 // that's easier to re-resolve and it doesn't matter in practice.
4984 // (Getting different parents can result in framechange hints, e.g.,
4985 // for user-modify.)
4987 mPresShell
->StyleSet()->
4988 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::pageBreak
,
4989 aMainStyleContext
->GetParent());
4991 NS_ASSERTION(pseudoStyle
->GetStyleDisplay()->mDisplay
==
4992 NS_STYLE_DISPLAY_BLOCK
, "Unexpected display");
4994 static const FrameConstructionData sPageBreakData
=
4995 FCDATA_DECL(FCDATA_SKIP_FRAMESET
, NS_NewPageBreakFrame
);
4997 // Lie about the tag and namespace so we don't trigger anything
4998 // interesting during frame construction.
4999 aItems
.AppendItem(&sPageBreakData
, aContent
, nsCSSAnonBoxes::pageBreak
,
5000 kNameSpaceID_None
, nsnull
, pseudoStyle
.forget(), PR_TRUE
);
5004 nsCSSFrameConstructor::ConstructFrame(nsFrameConstructorState
& aState
,
5005 nsIContent
* aContent
,
5006 nsIFrame
* aParentFrame
,
5007 nsFrameItems
& aFrameItems
)
5010 NS_PRECONDITION(nsnull
!= aParentFrame
, "no parent frame");
5011 FrameConstructionItemList items
;
5012 AddFrameConstructionItems(aState
, aContent
, PR_TRUE
, aParentFrame
, items
);
5014 for (FCItemIterator
iter(items
); !iter
.IsDone(); iter
.Next()) {
5015 NS_ASSERTION(iter
.item().DesiredParentType() == GetParentType(aParentFrame
),
5016 "This is not going to work");
5018 ConstructFramesFromItem(aState
, iter
, aParentFrame
, aFrameItems
);
5019 NS_ENSURE_SUCCESS(rv
, rv
);
5026 nsCSSFrameConstructor::AddFrameConstructionItems(nsFrameConstructorState
& aState
,
5027 nsIContent
* aContent
,
5028 PRBool aSuppressWhiteSpaceOptimizations
,
5029 nsIFrame
* aParentFrame
,
5030 FrameConstructionItemList
& aItems
)
5032 aContent
->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME
);
5033 if (aContent
->IsElement()) {
5034 // We can't just remove our pending restyle flags, since we may
5035 // have restyle-later-siblings set on us. But we _can_ remove the
5036 // "is possible restyle root" flags, and need to. Otherwise we can
5037 // end up with stale such flags (e.g. if we used to have a
5038 // display:none parent when our last restyle was posted and
5039 // processed and now no longer do).
5040 aContent
->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS
&
5041 ~ELEMENT_PENDING_RESTYLE_FLAGS
);
5044 // don't create a whitespace frame if aParent doesn't want it
5045 if (!NeedFrameFor(aState
, aParentFrame
, aContent
)) {
5049 // never create frames for comments or PIs
5050 if (aContent
->IsNodeOfType(nsINode::eCOMMENT
) ||
5051 aContent
->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION
))
5054 nsRefPtr
<nsStyleContext
> styleContext
;
5055 styleContext
= ResolveStyleContext(aParentFrame
, aContent
);
5057 AddFrameConstructionItemsInternal(aState
, aContent
, aParentFrame
,
5058 aContent
->Tag(), aContent
->GetNameSpaceID(),
5059 aSuppressWhiteSpaceOptimizations
,
5061 ITEM_ALLOW_XBL_BASE
| ITEM_ALLOW_PAGE_BREAK
,
5066 * Set aContent as undisplayed content with style context aStyleContext. This
5067 * method enforces the invariant that all style contexts in the undisplayed
5068 * content map must be non-pseudo contexts and also handles unbinding
5069 * undisplayed generated content as needed.
5072 SetAsUndisplayedContent(nsFrameManager
* aFrameManager
, nsIContent
* aContent
,
5073 nsStyleContext
* aStyleContext
,
5074 PRBool aIsGeneratedContent
)
5076 if (aStyleContext
->GetPseudo()) {
5077 if (aIsGeneratedContent
) {
5078 aContent
->UnbindFromTree();
5083 NS_ASSERTION(!aIsGeneratedContent
, "Should have had pseudo type");
5084 aFrameManager
->SetUndisplayedContent(aContent
, aStyleContext
);
5088 nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
& aState
,
5089 nsIContent
* aContent
,
5090 nsIFrame
* aParentFrame
,
5092 PRInt32 aNameSpaceID
,
5093 PRBool aSuppressWhiteSpaceOptimizations
,
5094 nsStyleContext
* aStyleContext
,
5096 FrameConstructionItemList
& aItems
)
5098 // The following code allows the user to specify the base tag
5099 // of an element using XBL. XUL and HTML objects (like boxes, menus, etc.)
5100 // can then be extended arbitrarily.
5101 const nsStyleDisplay
* display
= aStyleContext
->GetStyleDisplay();
5102 nsRefPtr
<nsStyleContext
> styleContext(aStyleContext
);
5103 PendingBinding
* pendingBinding
= nsnull
;
5104 if ((aFlags
& ITEM_ALLOW_XBL_BASE
) && display
->mBinding
)
5106 // Ensure that our XBL bindings are installed.
5108 nsIXBLService
* xblService
= GetXBLService();
5112 PRBool resolveStyle
;
5114 nsAutoPtr
<PendingBinding
> newPendingBinding(new PendingBinding());
5115 if (!newPendingBinding
) {
5118 nsresult rv
= xblService
->LoadBindings(aContent
, display
->mBinding
->mURI
,
5119 display
->mBinding
->mOriginPrincipal
,
5121 getter_AddRefs(newPendingBinding
->mBinding
),
5123 if (NS_FAILED(rv
) && rv
!= NS_ERROR_XBL_BLOCKED
)
5126 if (newPendingBinding
->mBinding
) {
5127 pendingBinding
= newPendingBinding
;
5128 // aState takes over owning newPendingBinding
5129 aState
.AddPendingBinding(newPendingBinding
.forget());
5133 styleContext
= ResolveStyleContext(styleContext
->GetParent(), aContent
);
5134 display
= styleContext
->GetStyleDisplay();
5135 aStyleContext
= styleContext
;
5138 aTag
= mDocument
->BindingManager()->ResolveTag(aContent
, &aNameSpaceID
);
5141 PRBool isGeneratedContent
= ((aFlags
& ITEM_IS_GENERATED_CONTENT
) != 0);
5143 // Pre-check for display "none" - if we find that, don't create
5145 if (NS_STYLE_DISPLAY_NONE
== display
->mDisplay
) {
5146 SetAsUndisplayedContent(aState
.mFrameManager
, aContent
, styleContext
,
5147 isGeneratedContent
);
5151 PRBool isText
= aContent
->IsNodeOfType(nsINode::eTEXT
);
5152 PRBool isPopup
= PR_FALSE
;
5153 // Try to find frame construction data for this content
5154 const FrameConstructionData
* data
;
5156 data
= FindTextData(aParentFrame
);
5159 // Nothing to do here; suppressed text inside SVG
5162 #endif /* MOZ_SVG */
5165 // Don't create frames for non-SVG element children of SVG elements.
5166 if (aNameSpaceID
!= kNameSpaceID_SVG
&&
5168 aParentFrame
->IsFrameOfType(nsIFrame::eSVG
) &&
5169 !aParentFrame
->IsFrameOfType(nsIFrame::eSVGForeignObject
)
5171 SetAsUndisplayedContent(aState
.mFrameManager
, aContent
, styleContext
,
5172 isGeneratedContent
);
5175 #endif /* MOZ_SVG */
5177 data
= FindHTMLData(aContent
, aTag
, aNameSpaceID
, aParentFrame
,
5180 data
= FindXULTagData(aContent
, aTag
, aNameSpaceID
, styleContext
);
5184 data
= FindMathMLData(aContent
, aTag
, aNameSpaceID
, styleContext
);
5189 data
= FindSVGData(aContent
, aTag
, aNameSpaceID
, aParentFrame
,
5192 #endif /* MOZ_SVG */
5194 // Now check for XUL display types
5196 data
= FindXULDisplayData(display
, aContent
, styleContext
);
5199 // And general display types
5201 data
= FindDisplayData(display
, aContent
, styleContext
);
5204 NS_ASSERTION(data
, "Should have frame construction data now");
5206 if (data
->mBits
& FCDATA_SUPPRESS_FRAME
) {
5207 SetAsUndisplayedContent(aState
.mFrameManager
, aContent
, styleContext
,
5208 isGeneratedContent
);
5213 if ((data
->mBits
& FCDATA_IS_POPUP
) &&
5214 (!aParentFrame
|| // Parent is inline
5215 aParentFrame
->GetType() != nsGkAtoms::menuFrame
)) {
5216 if (!aState
.mPopupItems
.containingBlock
&&
5217 !aState
.mHavePendingPopupgroup
) {
5218 SetAsUndisplayedContent(aState
.mFrameManager
, aContent
, styleContext
,
5219 isGeneratedContent
);
5225 #endif /* MOZ_XUL */
5228 PRUint32 bits
= data
->mBits
;
5230 // Inside colgroups, suppress everything except columns.
5232 aParentFrame
->GetType() == nsGkAtoms::tableColGroupFrame
&&
5233 (!(bits
& FCDATA_IS_TABLE_PART
) ||
5234 display
->mDisplay
!= NS_STYLE_DISPLAY_TABLE_COLUMN
)) {
5235 SetAsUndisplayedContent(aState
.mFrameManager
, aContent
, styleContext
,
5236 isGeneratedContent
);
5240 PRBool canHavePageBreak
=
5241 (aFlags
& ITEM_ALLOW_PAGE_BREAK
) &&
5242 aState
.mPresContext
->IsPaginated() &&
5243 !display
->IsAbsolutelyPositioned() &&
5244 !(bits
& FCDATA_IS_TABLE_PART
);
5246 if (canHavePageBreak
&& display
->mBreakBefore
) {
5247 AddPageBreakItem(aContent
, aStyleContext
, aItems
);
5250 FrameConstructionItem
* item
=
5251 aItems
.AppendItem(data
, aContent
, aTag
, aNameSpaceID
,
5252 pendingBinding
, styleContext
.forget(),
5253 aSuppressWhiteSpaceOptimizations
);
5255 if (isGeneratedContent
) {
5256 aContent
->UnbindFromTree();
5261 item
->mIsText
= isText
;
5262 item
->mIsGeneratedContent
= isGeneratedContent
;
5263 if (isGeneratedContent
) {
5264 NS_ADDREF(item
->mContent
);
5266 item
->mIsRootPopupgroup
=
5267 aNameSpaceID
== kNameSpaceID_XUL
&& aTag
== nsGkAtoms::popupgroup
&&
5268 aContent
->IsRootOfNativeAnonymousSubtree();
5269 if (item
->mIsRootPopupgroup
) {
5270 aState
.mHavePendingPopupgroup
= PR_TRUE
;
5272 item
->mIsPopup
= isPopup
;
5274 if (canHavePageBreak
&& display
->mBreakAfter
) {
5275 AddPageBreakItem(aContent
, aStyleContext
, aItems
);
5278 if (bits
& FCDATA_IS_INLINE
) {
5279 // To correctly set item->mIsAllInline we need to build up our child items
5281 BuildInlineChildItems(aState
, *item
);
5282 item
->mHasInlineEnds
= PR_TRUE
;
5283 item
->mIsBlock
= PR_FALSE
;
5285 // Compute a boolean isInline which is guaranteed to be false for blocks
5286 // (but may also be false for some inlines).
5288 // Table-internal things are inline-outside if and only if they're kids of
5289 // inlines, since they'll trigger construction of inline-table
5291 ((bits
& FCDATA_IS_TABLE_PART
) &&
5292 (!aParentFrame
|| // No aParentFrame means inline
5293 aParentFrame
->GetStyleDisplay()->mDisplay
== NS_STYLE_DISPLAY_INLINE
)) ||
5294 // Things that are inline-outside but aren't inline frames are inline
5295 display
->IsInlineOutside() ||
5296 // Popups that are certainly out of flow.
5299 // Set mIsAllInline conservatively. It just might be that even an inline
5300 // that has mIsAllInline false doesn't need an {ib} split. So this is just
5301 // an optimization to keep from doing too much work in cases when we can
5302 // show that mIsAllInline is true..
5303 item
->mIsAllInline
= item
->mHasInlineEnds
= isInline
||
5304 // Figure out whether we're guaranteed this item will be out of flow.
5305 // This is not a precise test, since one of our ancestor inlines might add
5306 // an absolute containing block (if it's relatively positioned) when there
5307 // wasn't such a containing block before. But it's conservative in the
5308 // sense that anything that will really end up as an in-flow non-inline
5309 // will test false here. In other words, if this test is true we're
5310 // guaranteed to be inline; if it's false we don't know what we'll end up
5313 // If we make this test precise, we can remove some of the code dealing
5314 // with the imprecision in ConstructInline and adjust the comments on
5315 // mIsAllInline and mIsBlock in the header. And probably remove mIsBlock
5316 // altogether, since then it will always be equal to !mHasInlineEnds.
5317 (!(bits
& FCDATA_DISALLOW_OUT_OF_FLOW
) &&
5318 aState
.GetGeometricParent(display
, nsnull
));
5320 // Set mIsBlock conservatively. It's OK to set it false for some real
5321 // blocks, but not OK to set it true for things that aren't blocks. Since
5322 // isOutOfFlow might be false even in cases when the frame will end up
5323 // out-of-flow, we can't use it here. But we _can_ say that the frame will
5324 // for sure end up in-flow if it's not floated or absolutely positioned.
5326 !isInline
&& !display
->IsAbsolutelyPositioned() && !display
->IsFloating();
5329 if (item
->mIsAllInline
) {
5330 aItems
.InlineItemAdded();
5331 } else if (item
->mIsBlock
) {
5332 aItems
.BlockItemAdded();
5335 // Our item should be treated as a line participant if we have the relevant
5336 // bit and are going to be in-flow. Note that this really only matters if
5337 // our ancestor is a box or some such, so the fact that we might have an
5338 // inline ancestor that might become a containing block is not relevant here.
5339 if ((bits
& FCDATA_IS_LINE_PARTICIPANT
) &&
5340 ((bits
& FCDATA_DISALLOW_OUT_OF_FLOW
) ||
5341 !aState
.GetGeometricParent(display
, nsnull
))) {
5342 item
->mIsLineParticipant
= PR_TRUE
;
5343 aItems
.LineParticipantItemAdded();
5348 DestroyContent(void* aPropertyValue
)
5350 nsIContent
* content
= static_cast<nsIContent
*>(aPropertyValue
);
5351 content
->UnbindFromTree();
5352 NS_RELEASE(content
);
5355 NS_DECLARE_FRAME_PROPERTY(BeforeProperty
, DestroyContent
)
5356 NS_DECLARE_FRAME_PROPERTY(AfterProperty
, DestroyContent
)
5358 static const FramePropertyDescriptor
*
5359 GenConPseudoToProperty(nsIAtom
* aPseudo
)
5361 NS_ASSERTION(aPseudo
== nsCSSPseudoElements::before
||
5362 aPseudo
== nsCSSPseudoElements::after
,
5363 "Bad gen-con pseudo");
5364 return aPseudo
== nsCSSPseudoElements::before
? BeforeProperty()
5369 * Return true if the frame construction item pointed to by aIter will
5370 * create a frame adjacent to a line boundary in the frame tree, and that
5371 * line boundary is induced by a content node adjacent to the frame's
5372 * content node in the content tree. The latter condition is necessary so
5373 * that ContentAppended/ContentInserted/ContentRemoved can easily find any
5374 * text nodes that were suppressed here.
5377 nsCSSFrameConstructor::AtLineBoundary(FCItemIterator
& aIter
)
5379 if (aIter
.item().mSuppressWhiteSpaceOptimizations
) {
5383 if (aIter
.AtStart()) {
5384 if (aIter
.List()->HasLineBoundaryAtStart() &&
5385 !aIter
.item().mContent
->GetPreviousSibling())
5388 FCItemIterator prev
= aIter
;
5390 if (prev
.item().IsLineBoundary() &&
5391 !prev
.item().mSuppressWhiteSpaceOptimizations
&&
5392 aIter
.item().mContent
->GetPreviousSibling() == prev
.item().mContent
)
5396 FCItemIterator next
= aIter
;
5398 if (next
.IsDone()) {
5399 if (aIter
.List()->HasLineBoundaryAtEnd() &&
5400 !aIter
.item().mContent
->GetNextSibling())
5403 if (next
.item().IsLineBoundary() &&
5404 !next
.item().mSuppressWhiteSpaceOptimizations
&&
5405 aIter
.item().mContent
->GetNextSibling() == next
.item().mContent
)
5413 nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState
& aState
,
5414 FCItemIterator
& aIter
,
5415 nsIFrame
* aParentFrame
,
5416 nsFrameItems
& aFrameItems
)
5418 nsIFrame
* adjParentFrame
= aParentFrame
;
5419 FrameConstructionItem
& item
= aIter
.item();
5420 nsStyleContext
* styleContext
= item
.mStyleContext
;
5421 AdjustParentFrame(adjParentFrame
, item
.mFCData
, styleContext
);
5424 // If this is collapsible whitespace next to a line boundary,
5425 // don't create a frame. item.IsWhitespace() also sets the
5426 // NS_CREATE_FRAME_IF_NON_WHITESPACE flag in the text node. (If we
5427 // end up creating a frame, nsTextFrame::Init will clear the flag.)
5428 // We don't do this for generated content, because some generated
5429 // text content is empty text nodes that are about to be initialized.
5430 // (We check mAdditionalStateBits because only the generated content
5431 // container's frame construction item is marked with
5432 // mIsGeneratedContent, and we might not have an aParentFrame.)
5433 // We don't do it for content that may have XBL anonymous siblings,
5434 // because they make it difficult to correctly create the frame
5435 // due to dynamic changes.
5436 // We don't do it for text that's not a line participant (i.e. SVG text).
5437 if (AtLineBoundary(aIter
) &&
5438 !styleContext
->GetStyleText()->NewlineIsSignificant() &&
5439 aIter
.List()->ParentHasNoXBLChildren() &&
5440 !(aState
.mAdditionalStateBits
& NS_FRAME_GENERATED_CONTENT
) &&
5441 (item
.mFCData
->mBits
& FCDATA_IS_LINE_PARTICIPANT
) &&
5442 item
.IsWhitespace(aState
))
5445 return ConstructTextFrame(item
.mFCData
, aState
, item
.mContent
,
5446 adjParentFrame
, styleContext
,
5450 // Start background loads during frame construction. This is just
5451 // a hint; the paint code will do the right thing in any case.
5453 styleContext
->GetStyleBackground();
5456 nsFrameState savedStateBits
= aState
.mAdditionalStateBits
;
5457 if (item
.mIsGeneratedContent
) {
5458 // Ensure that frames created here are all tagged with
5459 // NS_FRAME_GENERATED_CONTENT.
5460 aState
.mAdditionalStateBits
|= NS_FRAME_GENERATED_CONTENT
;
5462 // Note that we're not necessarily setting this property on the primary
5463 // frame for the content for which this is generated content. We might be
5464 // setting it on a table pseudo-frame inserted under that instead. That's
5465 // OK, though; we just need to do the property set so that the content will
5466 // get cleaned up when the frame is destroyed.
5467 aParentFrame
->Properties().Set(GenConPseudoToProperty(styleContext
->GetPseudo()),
5470 // Now that we've passed ownership of item.mContent to the frame, unset
5471 // our generated content flag so we don't release or unbind it ourselves.
5472 item
.mIsGeneratedContent
= PR_FALSE
;
5475 // XXXbz maybe just inline ConstructFrameFromItemInternal here or something?
5476 nsresult rv
= ConstructFrameFromItemInternal(item
, aState
, adjParentFrame
,
5479 aState
.mAdditionalStateBits
= savedStateBits
;
5486 IsRootBoxFrame(nsIFrame
*aFrame
)
5488 return (aFrame
->GetType() == nsGkAtoms::rootFrame
);
5492 nsCSSFrameConstructor::ReconstructDocElementHierarchy()
5494 return RecreateFramesForContent(mPresShell
->GetDocument()->GetRootElement(),
5499 nsCSSFrameConstructor::GetFrameFor(nsIContent
* aContent
)
5501 // Get the primary frame associated with the content
5502 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
5507 // If the content of the frame is not the desired content then this is not
5508 // really a frame for the desired content.
5509 // XXX This check is needed due to bug 135040. Remove it once that's fixed.
5510 if (frame
->GetContent() != aContent
) {
5514 nsIFrame
* insertionFrame
= frame
->GetContentInsertionFrame();
5516 NS_ASSERTION(insertionFrame
== frame
|| !frame
->IsLeaf(),
5517 "The insertion frame is the primary frame or the primary frame isn't a leaf");
5519 return insertionFrame
;
5523 nsCSSFrameConstructor::GetAbsoluteContainingBlock(nsIFrame
* aFrame
)
5525 NS_PRECONDITION(nsnull
!= mRootElementFrame
, "no root element frame");
5527 // Starting with aFrame, look for a frame that is absolutely positioned or
5528 // relatively positioned
5529 nsIFrame
* containingBlock
= nsnull
;
5530 for (nsIFrame
* frame
= aFrame
; frame
&& !containingBlock
;
5531 frame
= frame
->GetParent()) {
5532 if (frame
->IsFrameOfType(nsIFrame::eMathML
)) {
5533 // If it's mathml, bail out -- no absolute positioning out from inside
5534 // mathml frames. Note that we don't make this part of the loop
5535 // condition because of the stuff at the end of this method...
5539 // Is it positioned?
5540 // If it's table-related then ignore it, because for the time
5541 // being table-related frames are not containers for absolutely
5542 // positioned child frames.
5543 const nsStyleDisplay
* disp
= frame
->GetStyleDisplay();
5545 if (disp
->IsPositioned() && !IsTableRelated(frame
->GetType())) {
5546 // Find the outermost wrapped block under this frame
5547 for (nsIFrame
* wrappedFrame
= aFrame
; wrappedFrame
!= frame
->GetParent();
5548 wrappedFrame
= wrappedFrame
->GetParent()) {
5549 nsIAtom
* frameType
= wrappedFrame
->GetType();
5550 if (nsGkAtoms::blockFrame
== frameType
||
5552 nsGkAtoms::XULLabelFrame
== frameType
||
5554 nsGkAtoms::positionedInlineFrame
== frameType
) {
5555 containingBlock
= wrappedFrame
;
5556 } else if (nsGkAtoms::fieldSetFrame
== frameType
) {
5557 // If the positioned frame is a fieldset, use the area frame inside it.
5558 // We don't use GetContentInsertionFrame for fieldsets yet.
5559 containingBlock
= GetFieldSetBlockFrame(wrappedFrame
);
5563 // We sometimes have a null containing block here because we
5564 // haven't yet fixed bug 455338. Once we fix that we shouldn't
5565 // have to loop here.
5569 // If we found an absolutely positioned containing block, then use the
5570 // first-continuation.
5571 if (containingBlock
)
5572 return AdjustAbsoluteContainingBlock(containingBlock
);
5574 // If we didn't find it, then use the document element containing block
5575 return mHasRootAbsPosContainingBlock
? mDocElementContainingBlock
: nsnull
;
5579 nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame
* aFrame
)
5581 // Starting with aFrame, look for a frame that is a float containing block.
5582 // IF we hit a mathml frame, bail out; we don't allow floating out of mathml
5583 // frames, because they don't seem to be able to deal.
5584 // The logic here needs to match the logic in ProcessChildren()
5585 for (nsIFrame
* containingBlock
= aFrame
;
5586 containingBlock
&& !containingBlock
->IsFrameOfType(nsIFrame::eMathML
) &&
5587 !containingBlock
->IsBoxFrame();
5588 containingBlock
= containingBlock
->GetParent()) {
5589 if (containingBlock
->IsFloatContainingBlock()) {
5590 return containingBlock
;
5594 // If we didn't find a containing block, then there just isn't
5595 // one.... return null
5600 * This function will check whether aContainer has :after generated content.
5601 * If so, appending to it should actually insert. The return value is the
5602 * parent to use for newly-appended content. *aAfterFrame points to the :after
5603 * frame before which appended content should go, if there is one.
5606 AdjustAppendParentForAfterContent(nsPresContext
* aPresContext
,
5607 nsIContent
* aContainer
,
5608 nsIFrame
* aParentFrame
,
5609 nsIFrame
** aAfterFrame
)
5611 // See if the parent has an :after pseudo-element. Check for the presence
5612 // of style first, since nsLayoutUtils::GetAfterFrame is sorta expensive.
5613 nsStyleContext
* parentStyle
= aParentFrame
->GetStyleContext();
5614 if (nsLayoutUtils::HasPseudoStyle(aContainer
, parentStyle
,
5615 nsCSSPseudoElements::ePseudo_after
,
5617 nsIFrame
* afterFrame
= nsLayoutUtils::GetAfterFrame(aParentFrame
);
5619 *aAfterFrame
= afterFrame
;
5620 return afterFrame
->GetParent();
5624 *aAfterFrame
= nsnull
;
5626 if (IsFrameSpecial(aParentFrame
)) {
5627 // We might be in a situation where the last part of the {ib} split was
5628 // empty. Since we have no ::after pseudo-element, we do in fact want to be
5629 // appending to that last part, so advance to it if needed. Note that here
5630 // aParentFrame is the result of a GetLastSpecialSibling call, so must be
5631 // either the last or next to last special sibling.
5632 nsIFrame
* trailingInline
= GetSpecialSibling(aParentFrame
);
5633 if (trailingInline
) {
5634 aParentFrame
= trailingInline
;
5637 // Always make sure to look at the last continuation of the frame
5638 // for the {ib} case, even if that continuation is empty. We
5639 // don't do this for the non-special-frame case, since in the
5640 // other cases appending to the last nonempty continuation is fine
5641 // and in fact not doing that can confuse code that doesn't know
5642 // to pull kids from continuations other than its next one.
5643 aParentFrame
= aParentFrame
->GetLastContinuation();
5646 return aParentFrame
;
5650 * This function will get the previous sibling to use for an append operation.
5651 * it takes a parent frame (must not be null) and its :after frame (may be
5655 FindAppendPrevSibling(nsIFrame
* aParentFrame
, nsIFrame
* aAfterFrame
)
5658 NS_ASSERTION(aAfterFrame
->GetParent() == aParentFrame
, "Wrong parent");
5659 return aAfterFrame
->GetPrevSibling();
5662 return aParentFrame
->GetLastChild(nsnull
);
5666 * This function will get the next sibling for a frame insert operation given
5667 * the parent and previous sibling. aPrevSibling may be null.
5670 GetInsertNextSibling(nsIFrame
* aParentFrame
, nsIFrame
* aPrevSibling
)
5673 return aPrevSibling
->GetNextSibling();
5676 return aParentFrame
->GetFirstChild(nsnull
);
5680 * This function is called by ContentAppended() and ContentInserted() when
5681 * appending flowed frames to a parent's principal child list. It handles the
5682 * case where the parent is the trailing inline of an {ib} split.
5685 nsCSSFrameConstructor::AppendFrames(nsFrameConstructorState
& aState
,
5686 nsIFrame
* aParentFrame
,
5687 nsFrameItems
& aFrameList
,
5688 nsIFrame
* aPrevSibling
,
5689 PRBool aIsRecursiveCall
)
5691 NS_PRECONDITION(!IsFrameSpecial(aParentFrame
) ||
5692 !GetSpecialSibling(aParentFrame
) ||
5693 !GetSpecialSibling(aParentFrame
)->GetFirstChild(nsnull
),
5694 "aParentFrame has a special sibling with kids?");
5695 NS_PRECONDITION(!aPrevSibling
|| aPrevSibling
->GetParent() == aParentFrame
,
5696 "Parent and prevsibling don't match");
5698 nsIFrame
* nextSibling
= ::GetInsertNextSibling(aParentFrame
, aPrevSibling
);
5700 NS_ASSERTION(nextSibling
||
5701 !aParentFrame
->GetNextContinuation() ||
5702 !aParentFrame
->GetNextContinuation()->GetFirstChild(nsnull
) ||
5704 "aParentFrame has later continuations with kids?");
5705 NS_ASSERTION(nextSibling
||
5706 !IsFrameSpecial(aParentFrame
) ||
5707 (IsInlineFrame(aParentFrame
) &&
5708 !GetSpecialSibling(aParentFrame
) &&
5709 !aParentFrame
->GetNextContinuation()) ||
5711 "aParentFrame is not last?");
5713 // If we're inserting a list of frames at the end of the trailing inline
5714 // of an {ib} split, we may need to create additional {ib} siblings to parent
5716 if (!nextSibling
&& IsFrameSpecial(aParentFrame
)) {
5717 // When we get here, our frame list might start with a block. If it does
5718 // so, and aParentFrame is an inline, and it and all its previous
5719 // continuations have no siblings, then put the initial blocks from the
5720 // frame list into the previous block of the {ib} split. Note that we
5721 // didn't want to stop at the block part of the split when figuring out
5722 // initial parent, because that could screw up float parenting; it's easier
5723 // to do this little fixup here instead.
5724 if (aFrameList
.NotEmpty() && !IsInlineOutside(aFrameList
.FirstChild())) {
5725 // See whether our trailing inline is empty
5726 nsIFrame
* firstContinuation
= aParentFrame
->GetFirstContinuation();
5727 if (firstContinuation
->GetChildList(nsnull
).IsEmpty()) {
5728 // Our trailing inline is empty. Collect our starting blocks from
5729 // aFrameList, get the right parent frame for them, and put them in.
5730 nsFrameList::FrameLinkEnumerator firstNonBlockEnumerator
=
5731 FindFirstNonBlock(aFrameList
);
5732 nsFrameList blockKids
= aFrameList
.ExtractHead(firstNonBlockEnumerator
);
5733 NS_ASSERTION(blockKids
.NotEmpty(), "No blocks?");
5735 nsIFrame
* prevBlock
=
5736 GetSpecialPrevSibling(firstContinuation
)->GetLastContinuation();
5737 NS_ASSERTION(prevBlock
, "Should have previous block here");
5739 MoveChildrenTo(aState
.mPresContext
, aParentFrame
, prevBlock
, blockKids
);
5743 // We want to put some of the frames into this inline frame.
5744 nsFrameList::FrameLinkEnumerator
firstBlockEnumerator(aFrameList
);
5745 FindFirstBlock(firstBlockEnumerator
);
5747 nsFrameList inlineKids
= aFrameList
.ExtractHead(firstBlockEnumerator
);
5748 if (!inlineKids
.IsEmpty()) {
5749 aState
.mFrameManager
->AppendFrames(aParentFrame
, nsnull
, inlineKids
);
5752 if (!aFrameList
.IsEmpty()) {
5753 const nsStyleDisplay
* parentDisplay
= aParentFrame
->GetStyleDisplay();
5755 parentDisplay
->mPosition
== NS_STYLE_POSITION_RELATIVE
||
5756 parentDisplay
->HasTransform();
5757 nsFrameItems ibSiblings
;
5758 CreateIBSiblings(aState
, aParentFrame
, positioned
, aFrameList
,
5761 // Make sure to trigger reflow of the inline that used to be our
5762 // last one and now isn't anymore, since its GetSkipSides() has
5764 mPresShell
->FrameNeedsReflow(aParentFrame
,
5765 nsIPresShell::eTreeChange
,
5766 NS_FRAME_HAS_DIRTY_CHILDREN
);
5768 // Recurse so we create new ib siblings as needed for aParentFrame's parent
5769 return AppendFrames(aState
, aParentFrame
->GetParent(), ibSiblings
,
5770 aParentFrame
, PR_TRUE
);
5776 // Insert the frames after our aPrevSibling
5777 return aState
.mFrameManager
->InsertFrames(aParentFrame
, nsnull
, aPrevSibling
,
5781 #define UNSET_DISPLAY 255
5783 // This gets called to see if the frames corresponding to aSibling and aContent
5784 // should be siblings in the frame tree. Although (1) rows and cols, (2) row
5785 // groups and col groups, (3) row groups and captions, (4) legends and content
5786 // inside fieldsets, (5) popups and other kids of the menu are siblings from a
5787 // content perspective, they are not considered siblings in the frame tree.
5789 nsCSSFrameConstructor::IsValidSibling(nsIFrame
* aSibling
,
5790 nsIContent
* aContent
,
5793 nsIFrame
* parentFrame
= aSibling
->GetParent();
5794 nsIAtom
* parentType
= nsnull
;
5795 nsIAtom
* grandparentType
= nsnull
;
5797 parentType
= parentFrame
->GetType();
5798 nsIFrame
* grandparentFrame
= parentFrame
->GetParent();
5799 if (grandparentFrame
) {
5800 grandparentType
= grandparentFrame
->GetType();
5804 PRUint8 siblingDisplay
= aSibling
->GetStyleDisplay()->mDisplay
;
5805 if ((NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
== siblingDisplay
) ||
5806 (NS_STYLE_DISPLAY_TABLE_COLUMN
== siblingDisplay
) ||
5807 (NS_STYLE_DISPLAY_TABLE_CAPTION
== siblingDisplay
) ||
5808 (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP
== siblingDisplay
) ||
5809 (NS_STYLE_DISPLAY_TABLE_ROW_GROUP
== siblingDisplay
) ||
5810 (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP
== siblingDisplay
) ||
5811 nsGkAtoms::menuFrame
== parentType
) {
5812 // if we haven't already, construct a style context to find the display type of aContent
5813 if (UNSET_DISPLAY
== aDisplay
) {
5814 nsRefPtr
<nsStyleContext
> styleContext
;
5815 nsIFrame
* styleParent
;
5816 PRBool providerIsChild
;
5817 if (NS_FAILED(aSibling
->
5818 GetParentStyleContextFrame(aSibling
->PresContext(),
5820 &providerIsChild
)) ||
5822 NS_NOTREACHED("Shouldn't happen");
5825 styleContext
= ResolveStyleContext(styleParent
, aContent
);
5826 if (!styleContext
) return PR_FALSE
;
5827 const nsStyleDisplay
* display
= styleContext
->GetStyleDisplay();
5828 aDisplay
= display
->mDisplay
;
5830 if (nsGkAtoms::menuFrame
== parentType
) {
5832 (NS_STYLE_DISPLAY_POPUP
== aDisplay
) ==
5833 (NS_STYLE_DISPLAY_POPUP
== siblingDisplay
);
5835 // To have decent performance we want to return false in cases in which
5836 // reordering the two siblings has no effect on display. To ensure
5837 // correctness, we MUST return false in cases where the two siblings have
5838 // the same desired parent type and live on different display lists.
5839 // Specificaly, columns and column groups should only consider columns and
5840 // column groups as valid siblings. Captions should only consider other
5841 // captions. All other things should consider each other as valid
5842 // siblings. The restriction in the |if| above on siblingDisplay is ok,
5843 // because for correctness the only part that really needs to happen is to
5844 // not consider captions, column groups, and row/header/footer groups
5845 // siblings of each other. Treating a column or colgroup as a valid
5846 // sibling of a non-table-related frame will just mean we end up reframing.
5847 if ((siblingDisplay
== NS_STYLE_DISPLAY_TABLE_CAPTION
) !=
5848 (aDisplay
== NS_STYLE_DISPLAY_TABLE_CAPTION
)) {
5849 // One's a caption and the other is not. Not valid siblings.
5853 if ((siblingDisplay
== NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
||
5854 siblingDisplay
== NS_STYLE_DISPLAY_TABLE_COLUMN
) !=
5855 (aDisplay
== NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
||
5856 aDisplay
== NS_STYLE_DISPLAY_TABLE_COLUMN
)) {
5857 // One's a column or column group and the other is not. Not valid
5864 else if (nsGkAtoms::fieldSetFrame
== parentType
||
5865 (nsGkAtoms::fieldSetFrame
== grandparentType
&&
5866 nsGkAtoms::blockFrame
== parentType
)) {
5867 // Legends can be sibling of legends but not of other content in the fieldset
5868 nsIAtom
* sibType
= aSibling
->GetType();
5869 nsCOMPtr
<nsIDOMHTMLLegendElement
> legendContent(do_QueryInterface(aContent
));
5871 if ((legendContent
&& (nsGkAtoms::legendFrame
!= sibType
)) ||
5872 (!legendContent
&& (nsGkAtoms::legendFrame
== sibType
)))
5880 nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent
* aContent
,
5881 nsIContent
* aTargetContent
,
5882 PRUint8
& aTargetContentDisplay
,
5883 PRBool aPrevSibling
)
5885 nsIFrame
* sibling
= aContent
->GetPrimaryFrame();
5886 if (!sibling
|| sibling
->GetContent() != aContent
) {
5887 // XXX the GetContent() != aContent check is needed due to bug 135040.
5888 // Remove it once that's fixed.
5892 // If the frame is out-of-flow, GetPrimaryFrame() will have returned the
5893 // out-of-flow frame; we want the placeholder.
5894 if (sibling
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
5895 nsIFrame
* placeholderFrame
= mPresShell
->FrameManager()->GetPlaceholderFrameFor(sibling
);
5896 NS_ASSERTION(placeholderFrame
, "no placeholder for out-of-flow frame");
5897 sibling
= placeholderFrame
;
5900 // The frame we have now should never be a continuation
5901 NS_ASSERTION(!sibling
->GetPrevContinuation(), "How did that happen?");
5904 // The frame may be a special frame (a split inline frame that
5905 // contains a block). Get the last part of that split.
5906 if (IsFrameSpecial(sibling
)) {
5907 sibling
= GetLastSpecialSibling(sibling
, PR_TRUE
);
5910 // The frame may have a continuation. If so, we want the last
5911 // non-overflow-container continuation as our previous sibling.
5912 sibling
= sibling
->GetTailContinuation();
5915 if (aTargetContent
&&
5916 !IsValidSibling(sibling
, aTargetContent
, aTargetContentDisplay
)) {
5924 nsCSSFrameConstructor::FindPreviousSibling(const ChildIterator
& aFirst
,
5925 ChildIterator aIter
,
5926 PRUint8
& aTargetContentDisplay
)
5928 nsIContent
* child
= *aIter
;
5930 // Note: not all content objects are associated with a frame (e.g., if it's
5931 // `display: none') so keep looking until we find a previous frame
5932 while (aIter
!= aFirst
) {
5934 nsIFrame
* prevSibling
=
5935 FindFrameForContentSibling(*aIter
, child
, aTargetContentDisplay
, PR_TRUE
);
5938 // Found a previous sibling, we're done!
5947 nsCSSFrameConstructor::FindNextSibling(ChildIterator aIter
,
5948 const ChildIterator
& aLast
,
5949 PRUint8
& aTargetContentDisplay
)
5951 if (aIter
== aLast
) {
5952 // XXXbz Can happen when XBL lies to us about insertion points. This check
5953 // might be able to go away once bug 474324 is fixed.
5957 nsIContent
* child
= *aIter
;
5959 while (++aIter
!= aLast
) {
5960 nsIFrame
* nextSibling
=
5961 FindFrameForContentSibling(*aIter
, child
, aTargetContentDisplay
, PR_FALSE
);
5964 // We found a next sibling, we're done!
5972 // For fieldsets, returns the area frame, if the child is not a legend.
5974 GetAdjustedParentFrame(nsIFrame
* aParentFrame
,
5975 nsIAtom
* aParentFrameType
,
5976 nsIContent
* aChildContent
)
5978 NS_PRECONDITION(nsGkAtoms::tableOuterFrame
!= aParentFrameType
,
5979 "Shouldn't be happening!");
5981 nsIFrame
* newParent
= nsnull
;
5983 if (nsGkAtoms::fieldSetFrame
== aParentFrameType
) {
5984 // If the parent is a fieldSet, use the fieldSet's area frame as the
5985 // parent unless the new content is a legend.
5986 nsCOMPtr
<nsIDOMHTMLLegendElement
> legendContent(do_QueryInterface(aChildContent
));
5987 if (!legendContent
) {
5988 newParent
= GetFieldSetBlockFrame(aParentFrame
);
5991 return (newParent
) ? newParent
: aParentFrame
;
5995 nsCSSFrameConstructor::GetInsertionPrevSibling(nsIFrame
*& aParentFrame
,
5996 nsIContent
* aContainer
,
5999 PRBool
* aIsRangeInsertSafe
,
6000 nsIContent
* aStartSkipChild
,
6001 nsIContent
* aEndSkipChild
)
6003 *aIsAppend
= PR_FALSE
;
6005 // Find the frame that precedes the insertion point. Walk backwards
6006 // from the parent frame to get the parent content, because if an
6007 // XBL insertion point is involved, we'll need to use _that_ to find
6008 // the preceding frame.
6010 NS_PRECONDITION(aParentFrame
, "Must have parent frame to start with");
6011 nsIContent
* container
= aParentFrame
->GetContent();
6013 ChildIterator first
, last
;
6014 ChildIterator::Init(container
, &first
, &last
);
6015 ChildIterator
iter(first
);
6016 PRBool xblCase
= iter
.XBLInvolved() || container
!= aContainer
;
6017 if (xblCase
|| !aChild
->IsRootOfAnonymousSubtree()) {
6018 // The check for IsRootOfAnonymousSubtree() is because editor is
6019 // severely broken and calls us directly for native anonymous
6020 // nodes that it creates.
6021 if (aStartSkipChild
) {
6022 iter
.seek(aStartSkipChild
);
6029 NS_WARNING("Someone passed native anonymous content directly into frame "
6030 "construction. Stop doing that!");
6034 PRUint8 childDisplay
= UNSET_DISPLAY
;
6035 nsIFrame
* prevSibling
= FindPreviousSibling(first
, iter
, childDisplay
);
6037 // Now, find the geometric parent so that we can handle
6038 // continuations properly. Use the prev sibling if we have it;
6039 // otherwise use the next sibling.
6041 aParentFrame
= prevSibling
->GetParent()->GetContentInsertionFrame();
6044 // If there is no previous sibling, then find the frame that follows
6045 if (aEndSkipChild
) {
6046 iter
.seek(aEndSkipChild
);
6049 nsIFrame
* nextSibling
= FindNextSibling(iter
, last
, childDisplay
);
6052 aParentFrame
= nextSibling
->GetParent()->GetContentInsertionFrame();
6055 // No previous or next sibling, so treat this like an appended frame.
6056 *aIsAppend
= PR_TRUE
;
6057 if (IsFrameSpecial(aParentFrame
)) {
6058 // Since we're appending, we'll walk to the last anonymous frame
6059 // that was created for the broken inline frame. But don't walk
6060 // to the trailing inline if it's empty; stop at the block.
6061 aParentFrame
= GetLastSpecialSibling(aParentFrame
, PR_FALSE
);
6063 // Get continuation that parents the last child. This MUST be done
6064 // before the AdjustAppendParentForAfterContent call.
6065 aParentFrame
= nsLayoutUtils::GetLastContinuationWithChild(aParentFrame
);
6066 // Deal with fieldsets
6067 aParentFrame
= ::GetAdjustedParentFrame(aParentFrame
,
6068 aParentFrame
->GetType(),
6070 nsIFrame
* appendAfterFrame
;
6072 ::AdjustAppendParentForAfterContent(mPresShell
->GetPresContext(),
6073 container
, aParentFrame
,
6075 prevSibling
= ::FindAppendPrevSibling(aParentFrame
, appendAfterFrame
);
6079 *aIsRangeInsertSafe
= (childDisplay
== UNSET_DISPLAY
);
6084 IsSpecialFramesetChild(nsIContent
* aContent
)
6086 // IMPORTANT: This must match the conditions in nsHTMLFramesetFrame::Init.
6087 return aContent
->IsHTML() &&
6088 (aContent
->Tag() == nsGkAtoms::frameset
||
6089 aContent
->Tag() == nsGkAtoms::frame
);
6093 InvalidateCanvasIfNeeded(nsIPresShell
* presShell
, nsIContent
* node
);
6099 IsXULListBox(nsIContent
* aContainer
)
6101 return (aContainer
->IsXUL() && aContainer
->Tag() == nsGkAtoms::listbox
);
6106 MaybeGetListBoxBodyFrame(nsIContent
* aContainer
, nsIContent
* aChild
)
6111 if (IsXULListBox(aContainer
) &&
6112 aChild
->IsXUL() && aChild
->Tag() == nsGkAtoms::listitem
) {
6113 nsCOMPtr
<nsIDOMXULElement
> xulElement
= do_QueryInterface(aContainer
);
6114 nsCOMPtr
<nsIBoxObject
> boxObject
;
6115 xulElement
->GetBoxObject(getter_AddRefs(boxObject
));
6116 nsCOMPtr
<nsPIListBoxObject
> listBoxObject
= do_QueryInterface(boxObject
);
6117 if (listBoxObject
) {
6118 return listBoxObject
->GetListBoxBody(PR_FALSE
);
6127 nsCSSFrameConstructor::AddTextItemIfNeeded(nsFrameConstructorState
& aState
,
6128 nsIFrame
* aParentFrame
,
6129 nsIContent
* aPossibleTextContent
,
6130 FrameConstructionItemList
& aItems
)
6132 NS_PRECONDITION(aPossibleTextContent
, "Must have node");
6133 if (!aPossibleTextContent
->IsNodeOfType(nsINode::eTEXT
) ||
6134 !aPossibleTextContent
->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE
)) {
6135 // Not text, or not suppressed due to being all-whitespace (if it
6136 // were being suppressed, it would have the
6137 // NS_CREATE_FRAME_IF_NON_WHITESPACE flag)
6140 NS_ASSERTION(!aPossibleTextContent
->GetPrimaryFrame(),
6141 "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
6142 AddFrameConstructionItems(aState
, aPossibleTextContent
, PR_FALSE
,
6143 aParentFrame
, aItems
);
6147 nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent
* aParentContent
,
6148 nsIContent
* aContent
)
6150 if (!aContent
->IsNodeOfType(nsINode::eTEXT
) ||
6151 !aContent
->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE
)) {
6152 // Not text, or not suppressed due to being all-whitespace (if it
6153 // were being suppressed, it would have the
6154 // NS_CREATE_FRAME_IF_NON_WHITESPACE flag)
6157 NS_ASSERTION(!aContent
->GetPrimaryFrame(),
6158 "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
6159 ContentInserted(aParentContent
, aContent
, nsnull
, PR_FALSE
);
6162 // We want to disable lazy frame construction for nodes that are under an
6163 // editor. We use nsINode::IsEditable, but that includes inputs with type text
6164 // and password and textareas, which are common and aren't really editable (the
6165 // native anonymous content under them is what is actually editable) so we want
6166 // to construct frames for those lazily.
6167 // The logic for this check is based on
6168 // nsGenericHTMLFormElement::UpdateEditableFormControlState and so must be kept
6169 // in sync with that. The presence of the NODE_MAY_HAVE_CONTENT_EDITABLE_ATTR
6170 // flag only indicates a contenteditable attribute, it doesn't indicate if it
6171 // is true or false, so we force eager construction in some cases when the node
6172 // is not editable, but that should be rare.
6173 static inline PRBool
6174 IsActuallyEditable(nsIContent
* aContainer
, nsIContent
* aChild
)
6176 return (aChild
->IsEditable() &&
6177 (aContainer
->IsEditable() ||
6178 aChild
->HasFlag(NODE_MAY_HAVE_CONTENT_EDITABLE_ATTR
)));
6181 // For inserts aChild should be valid, for appends it should be null.
6182 // Returns true if this operation can be lazy, false if not.
6184 nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation
,
6185 nsIContent
* aContainer
,
6188 if (mPresShell
->GetPresContext()->IsChrome() || !aContainer
||
6189 aContainer
->IsInNativeAnonymousSubtree() || aContainer
->IsXUL()) {
6193 if (aOperation
== CONTENTINSERT
) {
6194 if (aChild
->IsRootOfAnonymousSubtree() ||
6195 aChild
->IsXUL() || IsActuallyEditable(aContainer
, aChild
)) {
6198 } else { // CONTENTAPPEND
6199 NS_ASSERTION(aOperation
== CONTENTAPPEND
,
6200 "operation should be either insert or append");
6201 for (nsIContent
* child
= aChild
; child
; child
= child
->GetNextSibling()) {
6202 NS_ASSERTION(!child
->IsRootOfAnonymousSubtree(),
6203 "Should be coming through the CONTENTAPPEND case");
6204 if (child
->IsXUL() || IsActuallyEditable(aContainer
, child
)) {
6210 // We can construct lazily; just need to set suitable bits in the content
6213 // Walk up the tree setting the NODE_DESCENDANTS_NEED_FRAMES bit as we go.
6214 nsIContent
* content
= aContainer
;
6216 // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
6217 // we want to assert, but leaf frames that process their own children and may
6218 // ignore anonymous children (eg framesets) make this complicated. So we set
6219 // these two booleans if we encounter these situations and unset them if we
6220 // hit a node with a leaf frame.
6221 PRBool noPrimaryFrame
= PR_FALSE
;
6222 PRBool needsFrameBitSet
= PR_FALSE
;
6225 !content
->HasFlag(NODE_DESCENDANTS_NEED_FRAMES
)) {
6227 if (content
->GetPrimaryFrame() && content
->GetPrimaryFrame()->IsLeaf()) {
6228 noPrimaryFrame
= needsFrameBitSet
= PR_FALSE
;
6230 if (!noPrimaryFrame
&& !content
->GetPrimaryFrame()) {
6231 noPrimaryFrame
= PR_TRUE
;
6233 if (!needsFrameBitSet
&& content
->HasFlag(NODE_NEEDS_FRAME
)) {
6234 needsFrameBitSet
= PR_TRUE
;
6237 content
->SetFlags(NODE_DESCENDANTS_NEED_FRAMES
);
6238 content
= content
->GetFlattenedTreeParent();
6241 if (content
&& content
->GetPrimaryFrame() &&
6242 content
->GetPrimaryFrame()->IsLeaf()) {
6243 noPrimaryFrame
= needsFrameBitSet
= PR_FALSE
;
6245 NS_ASSERTION(!noPrimaryFrame
, "Ancestors of nodes with frames to be "
6246 "constructed lazily should have frames");
6247 NS_ASSERTION(!needsFrameBitSet
, "Ancestors of nodes with frames to be "
6248 "constructed lazily should not have NEEDS_FRAME bit set");
6251 // Set NODE_NEEDS_FRAME on the new nodes.
6252 if (aOperation
== CONTENTINSERT
) {
6253 NS_ASSERTION(!aChild
->GetPrimaryFrame() ||
6254 aChild
->GetPrimaryFrame()->GetContent() != aChild
,
6255 //XXX the aChild->GetPrimaryFrame()->GetContent() != aChild
6256 // check is needed due to bug 135040. Remove it once that's
6258 "setting NEEDS_FRAME on a node that already has a frame?");
6259 aChild
->SetFlags(NODE_NEEDS_FRAME
);
6260 } else { // CONTENTAPPEND
6261 for (nsIContent
* child
= aChild
; child
; child
= child
->GetNextSibling()) {
6262 NS_ASSERTION(!child
->GetPrimaryFrame() ||
6263 child
->GetPrimaryFrame()->GetContent() != child
,
6264 //XXX the child->GetPrimaryFrame()->GetContent() != child
6265 // check is needed due to bug 135040. Remove it once that's
6267 "setting NEEDS_FRAME on a node that already has a frame?");
6268 child
->SetFlags(NODE_NEEDS_FRAME
);
6272 PostRestyleEventInternal(PR_TRUE
);
6277 nsCSSFrameConstructor::CreateNeededFrames(nsIContent
* aContent
)
6279 NS_ASSERTION(!aContent
->HasFlag(NODE_NEEDS_FRAME
),
6280 "shouldn't get here with a content node that has needs frame bit set");
6281 NS_ASSERTION(aContent
->HasFlag(NODE_DESCENDANTS_NEED_FRAMES
),
6282 "should only get here with a content node that has descendants needing frames");
6284 aContent
->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES
);
6286 // We could either descend first (on nodes that don't have NODE_NEEDS_FRAME
6287 // set) or issue content notifications for our kids first. In absence of
6288 // anything definitive either way we'll go with the latter.
6290 // It might be better to use GetChildArray and scan it completely first and
6291 // then issue all notifications. (We have to scan it completely first because
6292 // constructing frames can set attributes, which can change the storage of
6295 // Scan the children of aContent to see what operations (if any) we need to
6297 PRUint32 childCount
= aContent
->GetChildCount();
6298 PRBool inRun
= PR_FALSE
;
6299 nsIContent
* firstChildInRun
= nsnull
;
6300 for (PRUint32 i
= 0; i
< childCount
; i
++) {
6301 nsIContent
* child
= aContent
->GetChildAt(i
);
6302 if (child
->HasFlag(NODE_NEEDS_FRAME
)) {
6303 NS_ASSERTION(!child
->GetPrimaryFrame() ||
6304 child
->GetPrimaryFrame()->GetContent() != child
,
6305 //XXX the child->GetPrimaryFrame()->GetContent() != child
6306 // check is needed due to bug 135040. Remove it once that's
6308 "NEEDS_FRAME set on a node that already has a frame?");
6311 firstChildInRun
= child
;
6316 // generate a ContentRangeInserted for [startOfRun,i)
6317 ContentRangeInserted(aContent
, firstChildInRun
, child
, nsnull
,
6323 ContentAppended(aContent
, firstChildInRun
, PR_FALSE
);
6327 ChildIterator iter
, last
;
6328 for (ChildIterator::Init(aContent
, &iter
, &last
);
6331 nsIContent
* child
= *iter
;
6332 if (child
->HasFlag(NODE_DESCENDANTS_NEED_FRAMES
)) {
6333 CreateNeededFrames(child
);
6338 void nsCSSFrameConstructor::CreateNeededFrames()
6340 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
6341 "Someone forgot a script blocker");
6343 Element
* rootElement
= mDocument
->GetRootElement();
6344 NS_ASSERTION(!rootElement
|| !rootElement
->HasFlag(NODE_NEEDS_FRAME
),
6345 "root element should not have frame created lazily");
6346 if (rootElement
&& rootElement
->HasFlag(NODE_DESCENDANTS_NEED_FRAMES
)) {
6348 CreateNeededFrames(rootElement
);
6354 nsCSSFrameConstructor::IssueSingleInsertNofications(nsIContent
* aContainer
,
6355 nsIContent
* aStartChild
,
6356 nsIContent
* aEndChild
,
6357 PRBool aAllowLazyConstruction
)
6359 for (nsIContent
* child
= aStartChild
;
6361 child
= child
->GetNextSibling()) {
6362 if ((child
->GetPrimaryFrame() ||
6363 mPresShell
->FrameManager()->GetUndisplayedContent(child
))
6365 // Except listboxes suck, so do NOT skip anything here if
6366 // we plan to notify a listbox.
6367 && !MaybeGetListBoxBodyFrame(aContainer
, child
)
6370 // Already have a frame or undisplayed entry for this content; a
6371 // previous ContentInserted in this loop must have reconstructed
6372 // its insertion parent. Skip it.
6375 // Call ContentInserted with this node.
6376 ContentInserted(aContainer
, child
, mTempFrameTreeState
,
6377 aAllowLazyConstruction
);
6382 nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent
* aContainer
,
6383 nsIFrame
* aParentFrame
,
6384 nsIContent
* aStartChild
,
6385 nsIContent
* aEndChild
,
6386 PRBool aAllowLazyConstruction
)
6388 // See if we have an XBL insertion point. If so, then that's our
6389 // real parent frame; if not, then the frame hasn't been built yet
6390 // and we just bail.
6391 nsIFrame
* insertionPoint
;
6392 PRBool multiple
= PR_FALSE
;
6393 GetInsertionPoint(aParentFrame
, nsnull
, &insertionPoint
, &multiple
);
6394 if (! insertionPoint
)
6395 return nsnull
; // Don't build the frames.
6397 PRBool hasInsertion
= PR_FALSE
;
6399 // XXXbz XBL2/sXBL issue
6400 nsIDocument
* document
= aStartChild
->GetDocument();
6401 // XXXbz how would |document| be null here?
6403 document
->BindingManager()->GetInsertionParent(aStartChild
)) {
6404 hasInsertion
= PR_TRUE
;
6408 if (multiple
|| hasInsertion
) {
6409 // We have an insertion point. There are some additional tests we need to do
6410 // in order to ensure that an append is a safe operation.
6411 PRUint32 childCount
= 0;
6414 // We may need to make multiple ContentInserted calls instead. A
6415 // reasonable heuristic to employ (in order to maintain good performance)
6416 // is to find out if the insertion point's content node contains any
6417 // explicit children. If it does not, then it is highly likely that
6418 // an append is occurring. (Note it is not definite, and there are insane
6419 // cases we will not deal with by employing this heuristic, but it beats
6420 // always falling back to multiple ContentInserted calls).
6422 // In the multiple insertion point case, we know we're going to need to do
6423 // multiple ContentInserted calls anyway.
6424 childCount
= insertionPoint
->GetContent()->GetChildCount();
6427 // If we have multiple insertion points or if we have an insertion point
6428 // and the operation is not a true append or if the insertion point already
6429 // has explicit children, then we must fall back.
6430 if (multiple
|| aEndChild
!= nsnull
|| childCount
> 0) {
6431 // Now comes the fun part. For each inserted child, make a
6432 // ContentInserted call as if it had just gotten inserted and
6433 // let ContentInserted handle the mess.
6434 IssueSingleInsertNofications(aContainer
, aStartChild
, aEndChild
,
6435 aAllowLazyConstruction
);
6440 return insertionPoint
;
6444 nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame
* aParentFrame
,
6445 nsIContent
* aStartChild
,
6446 nsIContent
* aEndChild
)
6448 if (aParentFrame
->GetType() == nsGkAtoms::frameSetFrame
) {
6449 // Check whether we have any kids we care about.
6450 for (nsIContent
* cur
= aStartChild
;
6452 cur
= cur
->GetNextSibling()) {
6453 if (IsSpecialFramesetChild(cur
)) {
6454 // Just reframe the parent, since framesets are weird like that.
6455 RecreateFramesForContent(aParentFrame
->GetContent(), PR_FALSE
);
6464 nsCSSFrameConstructor::ContentAppended(nsIContent
* aContainer
,
6465 nsIContent
* aFirstNewContent
,
6466 PRBool aAllowLazyConstruction
)
6468 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell
->GetPresContext(), FrameC
);
6469 NS_PRECONDITION(mUpdateCount
!= 0,
6470 "Should be in an update while creating frames");
6473 if (gNoisyContentUpdates
) {
6474 printf("nsCSSFrameConstructor::ContentAppended container=%p "
6475 "first-child=%p lazy=%d\n",
6476 static_cast<void*>(aContainer
), aFirstNewContent
,
6477 aAllowLazyConstruction
);
6478 if (gReallyNoisyContentUpdates
&& aContainer
) {
6479 aContainer
->List(stdout
, 0);
6486 PRInt32 namespaceID
;
6488 mDocument
->BindingManager()->ResolveTag(aContainer
, &namespaceID
);
6490 // Just ignore tree tags, anyway we don't create any frames for them.
6491 if (tag
== nsGkAtoms::treechildren
||
6492 tag
== nsGkAtoms::treeitem
||
6493 tag
== nsGkAtoms::treerow
)
6499 // Get the frame associated with the content
6500 nsIFrame
* parentFrame
= GetFrameFor(aContainer
);
6504 if (aAllowLazyConstruction
&&
6505 MaybeConstructLazily(CONTENTAPPEND
, aContainer
, aFirstNewContent
)) {
6509 LAYOUT_PHASE_TEMP_EXIT();
6510 parentFrame
= GetRangeInsertionPoint(aContainer
, parentFrame
,
6511 aFirstNewContent
, nsnull
,
6512 aAllowLazyConstruction
);
6513 LAYOUT_PHASE_TEMP_REENTER();
6518 LAYOUT_PHASE_TEMP_EXIT();
6519 if (MaybeRecreateForFrameset(parentFrame
, aFirstNewContent
, nsnull
)) {
6520 LAYOUT_PHASE_TEMP_REENTER();
6523 LAYOUT_PHASE_TEMP_REENTER();
6525 if (parentFrame
->IsLeaf()) {
6526 // Nothing to do here; we shouldn't be constructing kids of leaves
6527 // Clear lazy bits so we don't try to construct again.
6528 ClearLazyBits(aFirstNewContent
, nsnull
);
6533 if (parentFrame
->IsFrameOfType(nsIFrame::eMathML
)) {
6534 LAYOUT_PHASE_TEMP_EXIT();
6535 nsresult rv
= RecreateFramesForContent(parentFrame
->GetContent(), PR_FALSE
);
6536 LAYOUT_PHASE_TEMP_REENTER();
6541 // If the frame we are manipulating is a ``special'' frame (that is, one
6542 // that's been created as a result of a block-in-inline situation) then we
6543 // need to append to the last special sibling, not to the frame itself.
6544 PRBool parentSpecial
= IsFrameSpecial(parentFrame
);
6545 if (parentSpecial
) {
6547 if (gNoisyContentUpdates
) {
6548 printf("nsCSSFrameConstructor::ContentAppended: parentFrame=");
6549 nsFrame::ListTag(stdout
, parentFrame
);
6550 printf(" is special\n");
6554 // Since we're appending, we'll walk to the last anonymous frame
6555 // that was created for the broken inline frame. But don't walk
6556 // to the trailing inline if it's empty; stop at the block.
6557 parentFrame
= GetLastSpecialSibling(parentFrame
, PR_FALSE
);
6560 // Get continuation that parents the last child. This MUST be done
6561 // before the AdjustAppendParentForAfterContent call.
6562 parentFrame
= nsLayoutUtils::GetLastContinuationWithChild(parentFrame
);
6564 // We should never get here with fieldsets, since they have multiple
6565 // insertion points.
6566 NS_ASSERTION(parentFrame
->GetType() != nsGkAtoms::fieldSetFrame
,
6567 "Unexpected parent");
6569 // Deal with possible :after generated content on the parent
6570 nsIFrame
* parentAfterFrame
;
6572 ::AdjustAppendParentForAfterContent(mPresShell
->GetPresContext(),
6573 aContainer
, parentFrame
,
6576 // Create some new frames
6577 nsFrameConstructorState
state(mPresShell
, mFixedContainingBlock
,
6578 GetAbsoluteContainingBlock(parentFrame
),
6579 GetFloatContainingBlock(parentFrame
));
6581 // See if the containing block has :first-letter style applied.
6582 PRBool haveFirstLetterStyle
= PR_FALSE
, haveFirstLineStyle
= PR_FALSE
;
6583 nsIFrame
* containingBlock
= state
.mFloatedItems
.containingBlock
;
6584 if (containingBlock
) {
6585 haveFirstLetterStyle
= HasFirstLetterStyle(containingBlock
);
6586 haveFirstLineStyle
=
6587 ShouldHaveFirstLineStyle(containingBlock
->GetContent(),
6588 containingBlock
->GetStyleContext());
6591 if (haveFirstLetterStyle
) {
6592 // Before we get going, remove the current letter frames
6593 RemoveLetterFrames(state
.mPresContext
, state
.mPresShell
,
6594 state
.mFrameManager
, containingBlock
);
6597 nsIAtom
* frameType
= parentFrame
->GetType();
6598 PRBool haveNoXBLChildren
=
6599 mDocument
->BindingManager()->GetXBLChildNodesFor(aContainer
) == nsnull
;
6600 FrameConstructionItemList items
;
6601 if (aFirstNewContent
->GetPreviousSibling() &&
6602 GetParentType(frameType
) == eTypeBlock
&&
6603 haveNoXBLChildren
) {
6604 // If there's a text node in the normal content list just before the new
6605 // items, and it has no frame, make a frame construction item for it. If it
6606 // doesn't need a frame, ConstructFramesFromItemList below won't give it
6607 // one. No need to do all this if our parent type is not block, though,
6608 // since WipeContainingBlock already handles that situation.
6610 // Because we're appending, we don't need to worry about any text
6611 // after the appended content; there can only be XBL anonymous content
6612 // (text in an XBL binding is not suppressed) or generated content
6613 // (and bare text nodes are not generated). Native anonymous content
6614 // generated by frames never participates in inline layout.
6615 AddTextItemIfNeeded(state
, parentFrame
,
6616 aFirstNewContent
->GetPreviousSibling(), items
);
6618 for (nsIContent
* child
= aFirstNewContent
;
6620 child
= child
->GetNextSibling()) {
6621 AddFrameConstructionItems(state
, child
, PR_FALSE
, parentFrame
, items
);
6624 nsIFrame
* prevSibling
= ::FindAppendPrevSibling(parentFrame
, parentAfterFrame
);
6626 // Perform special check for diddling around with the frames in
6627 // a special inline frame.
6628 // If we're appending before :after content, then we're not really
6629 // appending, so let WipeContainingBlock know that.
6630 LAYOUT_PHASE_TEMP_EXIT();
6631 if (WipeContainingBlock(state
, containingBlock
, parentFrame
, items
,
6632 PR_TRUE
, prevSibling
)) {
6633 LAYOUT_PHASE_TEMP_REENTER();
6636 LAYOUT_PHASE_TEMP_REENTER();
6638 // If the parent is a block frame, and we're not in a special case
6639 // where frames can be moved around, determine if the list is for the
6640 // start or end of the block.
6641 if (nsLayoutUtils::GetAsBlock(parentFrame
) && !haveFirstLetterStyle
&&
6642 !haveFirstLineStyle
&& !parentSpecial
) {
6643 items
.SetLineBoundaryAtStart(!prevSibling
||
6644 !prevSibling
->GetStyleDisplay()->IsInlineOutside() ||
6645 prevSibling
->GetType() == nsGkAtoms::brFrame
);
6646 // :after content can't be <br> so no need to check it
6647 items
.SetLineBoundaryAtEnd(!parentAfterFrame
||
6648 !parentAfterFrame
->GetStyleDisplay()->IsInlineOutside());
6650 // To suppress whitespace-only text frames, we have to verify that
6651 // our container's DOM child list matches its flattened tree child list.
6652 // This is guaranteed to be true if GetXBLChildNodesFor() returns null.
6653 items
.SetParentHasNoXBLChildren(haveNoXBLChildren
);
6655 nsFrameItems frameItems
;
6656 ConstructFramesFromItemList(state
, items
, parentFrame
, frameItems
);
6658 for (nsIContent
* child
= aFirstNewContent
;
6660 child
= child
->GetNextSibling()) {
6661 // Invalidate now instead of before the WipeContainingBlock call, just in
6662 // case we do wipe; in that case we don't need to do this walk at all.
6663 // XXXbz does that matter? Would it make more sense to save some virtual
6664 // GetChildAt calls instead and do this during construction of our
6665 // FrameConstructionItemList?
6666 InvalidateCanvasIfNeeded(mPresShell
, child
);
6669 // if the container is a table and a caption was appended, it needs to be put
6670 // in the outer table frame's additional child list.
6671 nsFrameItems captionItems
;
6672 if (nsGkAtoms::tableFrame
== frameType
) {
6673 // Pull out the captions. Note that we don't want to do that as we go,
6674 // because processing a single caption can add a whole bunch of things to
6675 // the frame items due to pseudoframe processing. So we'd have to pull
6676 // captions from a list anyway; might as well do that here.
6677 // XXXbz this is no longer true; we could pull captions directly out of the
6678 // FrameConstructionItemList now.
6679 PullOutCaptionFrames(frameItems
, captionItems
);
6682 if (haveFirstLineStyle
&& parentFrame
== containingBlock
) {
6683 // It's possible that some of the new frames go into a
6684 // first-line frame. Look at them and see...
6685 AppendFirstLineFrames(state
, containingBlock
->GetContent(),
6686 containingBlock
, frameItems
);
6689 // Notify the parent frame passing it the list of new frames
6690 // Append the flowed frames to the principal child list; captions
6691 // need special treatment
6692 if (captionItems
.NotEmpty()) { // append the caption to the outer table
6693 NS_ASSERTION(nsGkAtoms::tableFrame
== frameType
, "how did that happen?");
6694 nsIFrame
* outerTable
= parentFrame
->GetParent();
6696 state
.mFrameManager
->AppendFrames(outerTable
, nsGkAtoms::captionList
,
6701 if (frameItems
.NotEmpty()) { // append the in-flow kids
6702 AppendFrames(state
, parentFrame
, frameItems
, prevSibling
);
6705 // Recover first-letter frames
6706 if (haveFirstLetterStyle
) {
6707 RecoverLetterFrames(containingBlock
);
6711 if (gReallyNoisyContentUpdates
) {
6712 printf("nsCSSFrameConstructor::ContentAppended: resulting frame model:\n");
6713 parentFrame
->List(stdout
, 0);
6717 #ifdef ACCESSIBILITY
6718 if (mPresShell
->IsAccessibilityActive()) {
6719 nsCOMPtr
<nsIAccessibilityService
> accService
=
6720 do_GetService("@mozilla.org/accessibilityService;1");
6722 accService
->ContentRangeInserted(mPresShell
, aContainer
,
6723 aFirstNewContent
, nsnull
);
6733 enum content_operation
6739 // Helper function to lookup the listbox body frame and send a notification
6740 // for insertion or removal of content
6742 PRBool
NotifyListBoxBody(nsPresContext
* aPresContext
,
6743 nsIContent
* aContainer
,
6745 // Only used for the removed notification
6746 nsIContent
* aOldNextSibling
,
6747 nsIDocument
* aDocument
,
6748 nsIFrame
* aChildFrame
,
6749 content_operation aOperation
)
6751 nsListBoxBodyFrame
* listBoxBodyFrame
=
6752 MaybeGetListBoxBodyFrame(aContainer
, aChild
);
6753 if (listBoxBodyFrame
) {
6754 if (aOperation
== CONTENT_REMOVED
) {
6755 // Except if we have an aChildFrame and its parent is not the right
6756 // thing, then we don't do this. Pseudo frames are so much fun....
6757 if (!aChildFrame
|| aChildFrame
->GetParent() == listBoxBodyFrame
) {
6758 listBoxBodyFrame
->OnContentRemoved(aPresContext
, aContainer
,
6759 aChildFrame
, aOldNextSibling
);
6763 listBoxBodyFrame
->OnContentInserted(aPresContext
, aChild
);
6773 nsCSSFrameConstructor::ContentInserted(nsIContent
* aContainer
,
6775 nsILayoutHistoryState
* aFrameState
,
6776 PRBool aAllowLazyConstruction
)
6778 return ContentRangeInserted(aContainer
,
6780 aChild
->GetNextSibling(),
6782 aAllowLazyConstruction
);
6785 // ContentRangeInserted handles creating frames for a range of nodes that
6786 // aren't at the end of their childlist. ContentRangeInserted isn't a real
6787 // content notification, but rather it handles regular ContentInserted calls
6788 // for a single node as well as the lazy construction of frames for a range of
6789 // nodes when called from CreateNeededFrames. For a range of nodes to be
6790 // suitable to have its frames constructed all at once they must meet the same
6791 // conditions that ContentAppended imposes (GetRangeInsertionPoint checks
6792 // these), plus more. Namely when finding the insertion prevsibling we must not
6793 // need to consult something specific to any one node in the range, so that the
6794 // insertion prevsibling would be the same for each node in the range. So we
6795 // pass the first node in the range to GetInsertionPrevSibling, and if
6796 // IsValidSibling (the only place GetInsertionPrevSibling might look at the
6797 // passed in node itself) needs to resolve style on the node we record this and
6798 // return that this range needs to be split up and inserted separately. Table
6799 // captions need extra attention as we need to determine where to insert them
6800 // in the caption list, while skipping any nodes in the range being inserted
6801 // (because when we treat the caption frames the other nodes have had their
6802 // frames constructed but not yet inserted into the frame tree).
6804 nsCSSFrameConstructor::ContentRangeInserted(nsIContent
* aContainer
,
6805 nsIContent
* aStartChild
,
6806 nsIContent
* aEndChild
,
6807 nsILayoutHistoryState
* aFrameState
,
6808 PRBool aAllowLazyConstruction
)
6810 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell
->GetPresContext(), FrameC
);
6811 NS_PRECONDITION(mUpdateCount
!= 0,
6812 "Should be in an update while creating frames");
6814 NS_PRECONDITION(aStartChild
, "must always pass a child");
6816 // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
6817 // the :empty pseudo-class?
6819 if (gNoisyContentUpdates
) {
6820 printf("nsCSSFrameConstructor::ContentRangeInserted container=%p "
6821 "start-child=%p end-child=%p lazy=%d\n",
6822 static_cast<void*>(aContainer
),
6823 static_cast<void*>(aStartChild
), static_cast<void*>(aEndChild
),
6824 aAllowLazyConstruction
);
6825 if (gReallyNoisyContentUpdates
) {
6827 aContainer
->List(stdout
,0);
6829 aStartChild
->List(stdout
, 0);
6835 nsresult rv
= NS_OK
;
6837 PRBool isSingleInsert
= (aStartChild
->GetNextSibling() == aEndChild
);
6838 NS_ASSERTION(isSingleInsert
|| !aAllowLazyConstruction
,
6839 "range insert shouldn't be lazy");
6840 NS_ASSERTION(isSingleInsert
|| aEndChild
,
6841 "range should not include all nodes after aStartChild");
6844 if (aContainer
&& IsXULListBox(aContainer
)) {
6845 if (isSingleInsert
) {
6846 if (NotifyListBoxBody(mPresShell
->GetPresContext(), aContainer
,
6847 // The insert case in NotifyListBoxBody
6848 // doesn't use "old next sibling".
6849 aStartChild
, nsnull
,
6850 mDocument
, nsnull
, CONTENT_INSERTED
)) {
6854 // We don't handle a range insert to a listbox parent, issue single
6855 // ContertInserted calls for each node inserted.
6856 LAYOUT_PHASE_TEMP_EXIT();
6857 IssueSingleInsertNofications(aContainer
, aStartChild
, aEndChild
,
6858 aAllowLazyConstruction
);
6859 LAYOUT_PHASE_TEMP_REENTER();
6865 // If we have a null parent, then this must be the document element being
6866 // inserted, or some other child of the document in the DOM (might be a PI,
6869 NS_ASSERTION(isSingleInsert
,
6870 "root node insertion should be a single insertion");
6871 Element
*docElement
= mDocument
->GetRootElement();
6873 if (aStartChild
!= docElement
) {
6874 // Not the root element; just bail out
6878 NS_PRECONDITION(nsnull
== mRootElementFrame
,
6879 "root element frame already created");
6881 // Create frames for the document element and its child elements
6882 nsIFrame
* docElementFrame
;
6883 rv
= ConstructDocElementFrame(docElement
, aFrameState
, &docElementFrame
);
6885 if (NS_SUCCEEDED(rv
) && docElementFrame
) {
6886 InvalidateCanvasIfNeeded(mPresShell
, aStartChild
);
6888 if (gReallyNoisyContentUpdates
) {
6889 printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
6891 mFixedContainingBlock
->List(stdout
, 0);
6896 #ifdef ACCESSIBILITY
6897 if (mPresShell
->IsAccessibilityActive()) {
6898 nsCOMPtr
<nsIAccessibilityService
> accService
=
6899 do_GetService("@mozilla.org/accessibilityService;1");
6901 accService
->ContentRangeInserted(mPresShell
, aContainer
,
6902 aStartChild
, aEndChild
);
6910 // Otherwise, we've got parent content. Find its frame.
6911 nsIFrame
* parentFrame
= GetFrameFor(aContainer
);
6915 if (aAllowLazyConstruction
&&
6916 MaybeConstructLazily(CONTENTINSERT
, aContainer
, aStartChild
)) {
6920 if (isSingleInsert
) {
6921 // See if we have an XBL insertion point. If so, then that's our
6922 // real parent frame; if not, then the frame hasn't been built yet
6923 // and we just bail.
6924 nsIFrame
* insertionPoint
;
6925 GetInsertionPoint(parentFrame
, aStartChild
, &insertionPoint
);
6926 if (! insertionPoint
)
6927 return NS_OK
; // Don't build the frames.
6929 parentFrame
= insertionPoint
;
6931 // Get our insertion point. If we need to issue single ContentInserted's
6932 // GetRangeInsertionPoint will take care of that for us.
6933 LAYOUT_PHASE_TEMP_EXIT();
6934 parentFrame
= GetRangeInsertionPoint(aContainer
, parentFrame
,
6935 aStartChild
, aEndChild
,
6936 aAllowLazyConstruction
);
6937 LAYOUT_PHASE_TEMP_REENTER();
6943 PRBool isAppend
, isRangeInsertSafe
;
6944 nsIFrame
* prevSibling
=
6945 GetInsertionPrevSibling(parentFrame
, aContainer
, aStartChild
,
6946 &isAppend
, &isRangeInsertSafe
);
6948 // check if range insert is safe
6949 if (!isSingleInsert
&& !isRangeInsertSafe
) {
6950 // must fall back to a single ContertInserted for each child in the range
6951 LAYOUT_PHASE_TEMP_EXIT();
6952 IssueSingleInsertNofications(aContainer
, aStartChild
, aEndChild
,
6953 aAllowLazyConstruction
);
6954 LAYOUT_PHASE_TEMP_REENTER();
6958 nsIContent
* container
= parentFrame
->GetContent();
6960 nsIAtom
* frameType
= parentFrame
->GetType();
6961 LAYOUT_PHASE_TEMP_EXIT();
6962 if (MaybeRecreateForFrameset(parentFrame
, aStartChild
, aEndChild
)) {
6963 LAYOUT_PHASE_TEMP_REENTER();
6966 LAYOUT_PHASE_TEMP_REENTER();
6968 // We should only get here with fieldsets when doing a single insert, because
6969 // fieldsets have multiple insertion points.
6970 NS_ASSERTION(isSingleInsert
|| frameType
!= nsGkAtoms::fieldSetFrame
,
6971 "Unexpected parent");
6972 if (frameType
== nsGkAtoms::fieldSetFrame
&&
6973 aStartChild
->Tag() == nsGkAtoms::legend
) {
6974 // Just reframe the parent, since figuring out whether this
6975 // should be the new legend and then handling it is too complex.
6976 // We could do a little better here --- check if the fieldset already
6977 // has a legend which occurs earlier in its child list than this node,
6978 // and if so, proceed. But we'd have to extend nsFieldSetFrame
6979 // to locate this legend in the inserted frames and extract it.
6980 LAYOUT_PHASE_TEMP_EXIT();
6981 nsresult rv
= RecreateFramesForContent(parentFrame
->GetContent(), PR_FALSE
);
6982 LAYOUT_PHASE_TEMP_REENTER();
6986 // Don't construct kids of leaves
6987 if (parentFrame
->IsLeaf()) {
6988 // Clear lazy bits so we don't try to construct again.
6989 ClearLazyBits(aStartChild
, aEndChild
);
6994 if (parentFrame
->IsFrameOfType(nsIFrame::eMathML
)) {
6995 LAYOUT_PHASE_TEMP_EXIT();
6996 nsresult rv
= RecreateFramesForContent(parentFrame
->GetContent(), PR_FALSE
);
6997 LAYOUT_PHASE_TEMP_REENTER();
7002 nsFrameConstructorState
state(mPresShell
, mFixedContainingBlock
,
7003 GetAbsoluteContainingBlock(parentFrame
),
7004 GetFloatContainingBlock(parentFrame
),
7008 // Recover state for the containing block - we need to know if
7009 // it has :first-letter or :first-line style applied to it. The
7010 // reason we care is that the internal structure in these cases
7011 // is not the normal structure and requires custom updating
7013 nsIFrame
* containingBlock
= state
.mFloatedItems
.containingBlock
;
7014 PRBool haveFirstLetterStyle
= PR_FALSE
;
7015 PRBool haveFirstLineStyle
= PR_FALSE
;
7017 // In order to shave off some cycles, we only dig up the
7018 // containing block haveFirst* flags if the parent frame where
7019 // the insertion/append is occurring is an inline or block
7020 // container. For other types of containers this isn't relevant.
7021 const nsStyleDisplay
* parentDisplay
= parentFrame
->GetStyleDisplay();
7023 // Examine the parentFrame where the insertion is taking
7024 // place. If it's a certain kind of container then some special
7025 // processing is done.
7026 if ((NS_STYLE_DISPLAY_BLOCK
== parentDisplay
->mDisplay
) ||
7027 (NS_STYLE_DISPLAY_LIST_ITEM
== parentDisplay
->mDisplay
) ||
7028 (NS_STYLE_DISPLAY_INLINE
== parentDisplay
->mDisplay
) ||
7029 (NS_STYLE_DISPLAY_INLINE_BLOCK
== parentDisplay
->mDisplay
)) {
7030 // Recover the special style flags for the containing block
7031 if (containingBlock
) {
7032 haveFirstLetterStyle
= HasFirstLetterStyle(containingBlock
);
7033 haveFirstLineStyle
=
7034 ShouldHaveFirstLineStyle(containingBlock
->GetContent(),
7035 containingBlock
->GetStyleContext());
7038 if (haveFirstLetterStyle
) {
7039 // If our current parentFrame is a Letter frame, use its parent as our
7041 if (parentFrame
->GetType() == nsGkAtoms::letterFrame
) {
7042 // If parentFrame is out of flow, then we actually want the parent of
7043 // the placeholder frame.
7044 if (parentFrame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
7045 nsPlaceholderFrame
* placeholderFrame
=
7046 state
.mFrameManager
->GetPlaceholderFrameFor(parentFrame
);
7047 NS_ASSERTION(placeholderFrame
, "No placeholder for out-of-flow?");
7048 parentFrame
= placeholderFrame
->GetParent();
7050 parentFrame
= parentFrame
->GetParent();
7054 // Remove the old letter frames before doing the insertion
7055 RemoveLetterFrames(state
.mPresContext
, mPresShell
,
7056 state
.mFrameManager
,
7057 state
.mFloatedItems
.containingBlock
);
7059 // Removing the letterframes messes around with the frame tree, removing
7060 // and creating frames. We need to reget our prevsibling, parent frame,
7062 prevSibling
= GetInsertionPrevSibling(parentFrame
, aContainer
,
7063 aStartChild
, &isAppend
,
7064 &isRangeInsertSafe
);
7066 // Need check whether a range insert is still safe.
7067 if (!isSingleInsert
&& !isRangeInsertSafe
) {
7068 // Need to recover the letter frames first.
7069 RecoverLetterFrames(state
.mFloatedItems
.containingBlock
);
7071 // must fall back to a single ContertInserted for each child in the range
7072 LAYOUT_PHASE_TEMP_EXIT();
7073 IssueSingleInsertNofications(aContainer
, aStartChild
, aEndChild
,
7074 aAllowLazyConstruction
);
7075 LAYOUT_PHASE_TEMP_REENTER();
7079 container
= parentFrame
->GetContent();
7080 frameType
= parentFrame
->GetType();
7085 // We're inserting the new frames as the first child. See if the
7086 // parent has a :before pseudo-element
7087 nsIFrame
* firstChild
= parentFrame
->GetFirstChild(nsnull
);
7090 nsLayoutUtils::IsGeneratedContentFor(container
, firstChild
,
7091 nsCSSPseudoElements::before
)) {
7092 // Insert the new frames after the last continuation of the :before
7093 prevSibling
= firstChild
->GetTailContinuation();
7094 parentFrame
= prevSibling
->GetParent()->GetContentInsertionFrame();
7095 // Don't change isAppend here; we'll can call AppendFrames as needed, and
7096 // the change to our prevSibling doesn't affect that.
7100 FrameConstructionItemList items
;
7101 ParentType parentType
= GetParentType(frameType
);
7102 PRBool haveNoXBLChildren
=
7103 mDocument
->BindingManager()->GetXBLChildNodesFor(aContainer
) == nsnull
;
7104 if (aStartChild
->GetPreviousSibling() &&
7105 parentType
== eTypeBlock
&& haveNoXBLChildren
) {
7106 // If there's a text node in the normal content list just before the
7107 // new nodes, and it has no frame, make a frame construction item for
7108 // it, because it might need a frame now. No need to do this if our
7109 // parent type is not block, though, since WipeContainingBlock
7110 // already handles that sitation.
7111 AddTextItemIfNeeded(state
, parentFrame
, aStartChild
->GetPreviousSibling(),
7115 if (isSingleInsert
) {
7116 AddFrameConstructionItems(state
, aStartChild
,
7117 aStartChild
->IsRootOfAnonymousSubtree(),
7118 parentFrame
, items
);
7120 for (nsIContent
* child
= aStartChild
;
7122 child
= child
->GetNextSibling()){
7123 AddFrameConstructionItems(state
, child
, PR_FALSE
, parentFrame
, items
);
7127 if (aEndChild
&& parentType
== eTypeBlock
&& haveNoXBLChildren
) {
7128 // If there's a text node in the normal content list just after the
7129 // new nodes, and it has no frame, make a frame construction item for
7130 // it, because it might need a frame now. No need to do this if our
7131 // parent type is not block, though, since WipeContainingBlock
7132 // already handles that sitation.
7133 AddTextItemIfNeeded(state
, parentFrame
, aEndChild
, items
);
7136 // Perform special check for diddling around with the frames in
7137 // a special inline frame.
7138 // If we're appending before :after content, then we're not really
7139 // appending, so let WipeContainingBlock know that.
7140 LAYOUT_PHASE_TEMP_EXIT();
7141 if (WipeContainingBlock(state
, containingBlock
, parentFrame
, items
,
7142 isAppend
, prevSibling
)) {
7143 LAYOUT_PHASE_TEMP_REENTER();
7146 LAYOUT_PHASE_TEMP_REENTER();
7148 // If the container is a table and a caption will be appended, it needs to be
7149 // put in the outer table frame's additional child list.
7150 // We make no attempt here to set flags to indicate whether the list
7151 // will be at the start or end of a block. It doesn't seem worthwhile.
7152 nsFrameItems frameItems
, captionItems
;
7153 ConstructFramesFromItemList(state
, items
, parentFrame
, frameItems
);
7155 if (frameItems
.NotEmpty()) {
7156 for (nsIContent
* child
= aStartChild
;
7158 child
= child
->GetNextSibling()){
7159 InvalidateCanvasIfNeeded(mPresShell
, child
);
7162 if (nsGkAtoms::tableFrame
== frameType
||
7163 nsGkAtoms::tableOuterFrame
== frameType
) {
7164 PullOutCaptionFrames(frameItems
, captionItems
);
7168 // If the parent of our current prevSibling is different from the frame we'll
7169 // actually use as the parent, then the calculated insertion point is now
7170 // invalid and as it is unknown where to insert correctly we append instead
7172 // This can affect our prevSibling and isAppend, but should not have any
7173 // effect on the WipeContainingBlock above, since this should only happen
7174 // when neither parent is a special frame and should not affect whitespace
7175 // handling inside table-related frames (and in fact, can only happen when
7176 // one of the parents is an outer table and one is an inner table or when the
7177 // parent is a fieldset or fieldset content frame). So it won't affect the
7178 // {ib} or XUL box cases in WipeContainingBlock(), and the table pseudo
7179 // handling will only be affected by us maybe thinking we're not inserting
7180 // at the beginning, whereas we really are. That would have made us reframe
7181 // unnecessarily, but that's ok.
7182 // XXXbz we should push our frame construction item code up higher, so we
7183 // know what our items are by the time we start figuring out previous
7185 if (prevSibling
&& frameItems
.NotEmpty() &&
7186 frameItems
.FirstChild()->GetParent() != prevSibling
->GetParent()) {
7188 nsIFrame
* frame1
= frameItems
.FirstChild()->GetParent();
7189 nsIFrame
* frame2
= prevSibling
->GetParent();
7190 NS_ASSERTION(!IsFrameSpecial(frame1
) && !IsFrameSpecial(frame2
),
7191 "Neither should be special");
7192 NS_ASSERTION((frame1
->GetType() == nsGkAtoms::tableFrame
&&
7193 frame2
->GetType() == nsGkAtoms::tableOuterFrame
) ||
7194 (frame1
->GetType() == nsGkAtoms::tableOuterFrame
&&
7195 frame2
->GetType() == nsGkAtoms::tableFrame
) ||
7196 frame1
->GetType() == nsGkAtoms::fieldSetFrame
||
7197 (frame1
->GetParent() &&
7198 frame1
->GetParent()->GetType() == nsGkAtoms::fieldSetFrame
),
7199 "Unexpected frame types");
7202 nsIFrame
* appendAfterFrame
;
7204 ::AdjustAppendParentForAfterContent(mPresShell
->GetPresContext(),
7206 frameItems
.FirstChild()->GetParent(),
7208 prevSibling
= ::FindAppendPrevSibling(parentFrame
, appendAfterFrame
);
7211 if (haveFirstLineStyle
&& parentFrame
== containingBlock
) {
7212 // It's possible that the new frame goes into a first-line
7213 // frame. Look at it and see...
7215 // Use append logic when appending
7216 AppendFirstLineFrames(state
, containingBlock
->GetContent(),
7217 containingBlock
, frameItems
);
7220 // Use more complicated insert logic when inserting
7221 // XXXbz this method is a no-op, so it's easy for the args being passed
7222 // here to make no sense without anyone noticing... If it ever stops
7223 // being a no-op, vet them carefully!
7224 InsertFirstLineFrames(state
, container
, containingBlock
, &parentFrame
,
7225 prevSibling
, frameItems
);
7229 // We might have captions; put them into the caption list of the
7230 // outer table frame.
7231 if (captionItems
.NotEmpty()) {
7232 NS_ASSERTION(nsGkAtoms::tableFrame
== frameType
||
7233 nsGkAtoms::tableOuterFrame
== frameType
,
7234 "parent for caption is not table?");
7235 // We need to determine where to put the caption items; start with the
7236 // the parent frame that has already been determined and get the insertion
7237 // prevsibling of the first caption item.
7238 nsIFrame
* captionParent
= parentFrame
;
7239 PRBool captionIsAppend
;
7240 nsIFrame
* captionPrevSibling
= nsnull
;
7242 // aIsRangeInsertSafe is ignored on purpose because it is irrelevant here.
7244 if (isSingleInsert
) {
7245 captionPrevSibling
=
7246 GetInsertionPrevSibling(captionParent
, aContainer
, aStartChild
,
7247 &captionIsAppend
, &ignored
);
7249 nsIContent
* firstCaption
= captionItems
.FirstChild()->GetContent();
7250 // It is very important here that we skip the children in
7251 // [aStartChild,aEndChild) when looking for a
7253 captionPrevSibling
=
7254 GetInsertionPrevSibling(captionParent
, aContainer
, firstCaption
,
7255 &captionIsAppend
, &ignored
,
7256 aStartChild
, aEndChild
);
7259 nsIFrame
* outerTable
= nsnull
;
7260 if (GetCaptionAdjustedParent(captionParent
, captionItems
.FirstChild(),
7262 // If the parent is not an outer table frame we will try to add frames
7263 // to a named child list that the parent does not honour and the frames
7265 NS_ASSERTION(nsGkAtoms::tableOuterFrame
== outerTable
->GetType(),
7266 "Pseudo frame construction failure; "
7267 "a caption can be only a child of an outer table frame");
7269 // If the parent of our current prevSibling is different from the frame
7270 // we'll actually use as the parent, then the calculated insertion
7271 // point is now invalid (bug 341382).
7272 if (captionPrevSibling
&&
7273 captionPrevSibling
->GetParent() != outerTable
) {
7274 captionPrevSibling
= nsnull
;
7276 if (captionIsAppend
) {
7277 state
.mFrameManager
->AppendFrames(outerTable
, nsGkAtoms::captionList
,
7280 state
.mFrameManager
->InsertFrames(outerTable
, nsGkAtoms::captionList
,
7281 captionPrevSibling
, captionItems
);
7286 if (frameItems
.NotEmpty()) {
7287 // Notify the parent frame
7289 AppendFrames(state
, parentFrame
, frameItems
, prevSibling
);
7291 state
.mFrameManager
->InsertFrames(parentFrame
, nsnull
, prevSibling
,
7296 if (haveFirstLetterStyle
) {
7297 // Recover the letter frames for the containing block when
7298 // it has first-letter style.
7299 RecoverLetterFrames(state
.mFloatedItems
.containingBlock
);
7303 if (gReallyNoisyContentUpdates
&& parentFrame
) {
7304 printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame model:\n");
7305 parentFrame
->List(stdout
, 0);
7309 #ifdef ACCESSIBILITY
7310 if (mPresShell
->IsAccessibilityActive()) {
7311 nsCOMPtr
<nsIAccessibilityService
> accService
=
7312 do_GetService("@mozilla.org/accessibilityService;1");
7314 accService
->ContentRangeInserted(mPresShell
, aContainer
,
7315 aStartChild
, aEndChild
);
7324 nsCSSFrameConstructor::ContentRemoved(nsIContent
* aContainer
,
7326 nsIContent
* aOldNextSibling
,
7328 PRBool
* aDidReconstruct
)
7330 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell
->GetPresContext(), FrameC
);
7331 NS_PRECONDITION(mUpdateCount
!= 0,
7332 "Should be in an update while destroying frames");
7334 *aDidReconstruct
= PR_FALSE
;
7336 // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
7337 // the :empty pseudo-class?
7340 if (gNoisyContentUpdates
) {
7341 printf("nsCSSFrameConstructor::ContentRemoved container=%p child=%p "
7342 "old-next-sibling=%p\n",
7343 static_cast<void*>(aContainer
),
7344 static_cast<void*>(aChild
),
7345 static_cast<void*>(aOldNextSibling
));
7346 if (gReallyNoisyContentUpdates
) {
7347 aContainer
->List(stdout
, 0);
7352 nsFrameManager
*frameManager
= mPresShell
->FrameManager();
7353 nsPresContext
*presContext
= mPresShell
->GetPresContext();
7354 nsresult rv
= NS_OK
;
7356 // Find the child frame that maps the content
7357 nsIFrame
* childFrame
= aChild
->GetPrimaryFrame();
7359 if (!childFrame
|| childFrame
->GetContent() != aChild
) {
7360 // XXXbz the GetContent() != aChild check is needed due to bug 135040.
7361 // Remove it once that's fixed.
7362 frameManager
->ClearUndisplayedContentIn(aChild
, aContainer
);
7366 if (NotifyListBoxBody(presContext
, aContainer
, aChild
, aOldNextSibling
,
7367 mDocument
, childFrame
, CONTENT_REMOVED
))
7372 // If we're removing the root, then make sure to remove things starting at
7373 // the viewport's child instead of the primary frame (which might even be
7374 // null if the root had an XBL binding or display:none, even though the
7375 // frames above it got created). We do the adjustment after the childFrame
7376 // check above, because we do want to clear any undisplayed content we might
7377 // have for the root. Detecting removal of a root is a little exciting; in
7378 // particular, having a null aContainer is necessary but NOT sufficient. Due
7379 // to how we process reframes, the content node might not even be in our
7380 // document by now. So explicitly check whether the viewport's first kid's
7381 // content node is aChild.
7382 PRBool isRoot
= PR_FALSE
;
7384 nsIFrame
* viewport
= frameManager
->GetRootFrame();
7386 nsIFrame
* firstChild
= viewport
->GetFirstChild(nsnull
);
7387 if (firstChild
&& firstChild
->GetContent() == aChild
) {
7389 childFrame
= firstChild
;
7390 NS_ASSERTION(!childFrame
->GetNextSibling(), "How did that happen?");
7396 InvalidateCanvasIfNeeded(mPresShell
, aChild
);
7398 // See whether we need to remove more than just childFrame
7399 LAYOUT_PHASE_TEMP_EXIT();
7400 if (MaybeRecreateContainerForFrameRemoval(childFrame
, &rv
)) {
7401 LAYOUT_PHASE_TEMP_REENTER();
7402 *aDidReconstruct
= PR_TRUE
;
7405 LAYOUT_PHASE_TEMP_REENTER();
7407 // Get the childFrame's parent frame
7408 nsIFrame
* parentFrame
= childFrame
->GetParent();
7409 nsIAtom
* parentType
= parentFrame
->GetType();
7411 if (parentType
== nsGkAtoms::frameSetFrame
&&
7412 IsSpecialFramesetChild(aChild
)) {
7413 // Just reframe the parent, since framesets are weird like that.
7414 *aDidReconstruct
= PR_TRUE
;
7415 LAYOUT_PHASE_TEMP_EXIT();
7416 nsresult rv
= RecreateFramesForContent(parentFrame
->GetContent(), PR_FALSE
);
7417 LAYOUT_PHASE_TEMP_REENTER();
7422 // If we're a child of MathML, then we should reframe the MathML content.
7423 // If we're non-MathML, then we would be wrapped in a block so we need to
7424 // check our grandparent in that case.
7425 nsIFrame
* possibleMathMLAncestor
= parentType
== nsGkAtoms::blockFrame
?
7426 parentFrame
->GetParent() : parentFrame
;
7427 if (possibleMathMLAncestor
->IsFrameOfType(nsIFrame::eMathML
)) {
7428 *aDidReconstruct
= PR_TRUE
;
7429 LAYOUT_PHASE_TEMP_EXIT();
7430 nsresult rv
= RecreateFramesForContent(possibleMathMLAncestor
->GetContent(), PR_FALSE
);
7431 LAYOUT_PHASE_TEMP_REENTER();
7436 // Undo XUL wrapping if it's no longer needed.
7437 // (If we're in the XUL block-wrapping situation, parentFrame is the
7439 nsIFrame
* grandparentFrame
= parentFrame
->GetParent();
7440 if (grandparentFrame
&& grandparentFrame
->IsBoxFrame() &&
7441 (grandparentFrame
->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK
) &&
7442 // check if this frame is the only one needing wrapping
7443 aChild
== AnyKidsNeedBlockParent(parentFrame
->GetFirstChild(nsnull
)) &&
7444 !AnyKidsNeedBlockParent(childFrame
->GetNextSibling())) {
7445 *aDidReconstruct
= PR_TRUE
;
7446 LAYOUT_PHASE_TEMP_EXIT();
7447 nsresult rv
= RecreateFramesForContent(grandparentFrame
->GetContent(), PR_TRUE
);
7448 LAYOUT_PHASE_TEMP_REENTER();
7452 #ifdef ACCESSIBILITY
7453 if (mPresShell
->IsAccessibilityActive()) {
7454 nsCOMPtr
<nsIAccessibilityService
> accService
=
7455 do_GetService("@mozilla.org/accessibilityService;1");
7457 accService
->ContentRemoved(mPresShell
, aContainer
, aChild
);
7462 // Examine the containing-block for the removed content and see if
7463 // :first-letter style applies.
7464 nsIFrame
* inflowChild
= childFrame
;
7465 if (childFrame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
7466 inflowChild
= frameManager
->GetPlaceholderFrameFor(childFrame
);
7467 NS_ASSERTION(inflowChild
, "No placeholder for out-of-flow?");
7469 nsIFrame
* containingBlock
=
7470 GetFloatContainingBlock(inflowChild
->GetParent());
7471 PRBool haveFLS
= containingBlock
&& HasFirstLetterStyle(containingBlock
);
7473 // Trap out to special routine that handles adjusting a blocks
7474 // frame tree when first-letter style is present.
7475 #ifdef NOISY_FIRST_LETTER
7476 printf("ContentRemoved: containingBlock=");
7477 nsFrame::ListTag(stdout
, containingBlock
);
7478 printf(" parentFrame=");
7479 nsFrame::ListTag(stdout
, parentFrame
);
7480 printf(" childFrame=");
7481 nsFrame::ListTag(stdout
, childFrame
);
7485 // First update the containing blocks structure by removing the
7486 // existing letter frames. This makes the subsequent logic
7488 RemoveLetterFrames(presContext
, mPresShell
, frameManager
,
7491 // Recover childFrame and parentFrame
7492 childFrame
= aChild
->GetPrimaryFrame();
7493 if (!childFrame
|| childFrame
->GetContent() != aChild
) {
7494 // XXXbz the GetContent() != aChild check is needed due to bug 135040.
7495 // Remove it once that's fixed.
7496 frameManager
->ClearUndisplayedContentIn(aChild
, aContainer
);
7499 parentFrame
= childFrame
->GetParent();
7500 parentType
= parentFrame
->GetType();
7502 #ifdef NOISY_FIRST_LETTER
7503 printf(" ==> revised parentFrame=");
7504 nsFrame::ListTag(stdout
, parentFrame
);
7505 printf(" childFrame=");
7506 nsFrame::ListTag(stdout
, childFrame
);
7512 if (gReallyNoisyContentUpdates
) {
7513 printf("nsCSSFrameConstructor::ContentRemoved: childFrame=");
7514 nsFrame::ListTag(stdout
, childFrame
);
7516 parentFrame
->List(stdout
, 0);
7521 // Notify the parent frame that it should delete the frame
7522 if (childFrame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
7523 childFrame
= frameManager
->GetPlaceholderFrameFor(childFrame
);
7524 NS_ASSERTION(childFrame
, "Missing placeholder frame for out of flow.");
7525 parentFrame
= childFrame
->GetParent();
7527 rv
= frameManager
->RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame
),
7529 //XXXfr NS_ENSURE_SUCCESS(rv, rv) ?
7532 mRootElementFrame
= nsnull
;
7533 mRootElementStyleFrame
= nsnull
;
7534 mDocElementContainingBlock
= nsnull
;
7535 mPageSequenceFrame
= nsnull
;
7536 mGfxScrollFrame
= nsnull
;
7537 mHasRootAbsPosContainingBlock
= PR_FALSE
;
7538 mFixedContainingBlock
= frameManager
->GetRootFrame();
7541 if (haveFLS
&& mRootElementFrame
) {
7542 RecoverLetterFrames(containingBlock
);
7545 // If we're just reconstructing frames for the element, then the
7546 // following ContentInserted notification on the element will
7547 // take care of fixing up any adjacent text nodes. We don't need
7548 // to do this if the table parent type of our parent type is not
7549 // eTypeBlock, though, because in that case the whitespace isn't
7550 // being suppressed due to us anyway.
7551 if (aContainer
&& !aChild
->IsRootOfAnonymousSubtree() &&
7552 aFlags
!= REMOVE_FOR_RECONSTRUCTION
&&
7553 GetParentType(parentType
) == eTypeBlock
) {
7554 // Adjacent whitespace-only text nodes might have been suppressed if
7555 // this node does not have inline ends. Create frames for them now
7557 // Reframe any text node just before the node being removed, if there is
7558 // one, and if it's not the last child or the first child. If a whitespace
7559 // textframe was being suppressed and it's now the last child or first
7560 // child then it can stay suppressed since the parent must be a block
7561 // and hence it's adjacent to a block end.
7562 // If aOldNextSibling is null, then the text node before the node being
7563 // removed is the last node, and we don't need to worry about it.
7564 if (aOldNextSibling
) {
7565 nsIContent
* prevSibling
= aOldNextSibling
->GetPreviousSibling();
7566 if (prevSibling
&& prevSibling
->GetPreviousSibling()) {
7567 LAYOUT_PHASE_TEMP_EXIT();
7568 ReframeTextIfNeeded(aContainer
, prevSibling
);
7569 LAYOUT_PHASE_TEMP_REENTER();
7572 // Reframe any text node just after the node being removed, if there is
7573 // one, and if it's not the last child or the first child.
7574 if (aOldNextSibling
&& aOldNextSibling
->GetNextSibling() &&
7575 aOldNextSibling
->GetPreviousSibling()) {
7576 LAYOUT_PHASE_TEMP_EXIT();
7577 ReframeTextIfNeeded(aContainer
, aOldNextSibling
);
7578 LAYOUT_PHASE_TEMP_REENTER();
7583 if (gReallyNoisyContentUpdates
&& parentFrame
) {
7584 printf("nsCSSFrameConstructor::ContentRemoved: resulting frame model:\n");
7585 parentFrame
->List(stdout
, 0);
7594 // To ensure that the functions below are only called within
7595 // |ApplyRenderingChangeToTree|.
7596 static PRBool gInApplyRenderingChangeToTree
= PR_FALSE
;
7600 DoApplyRenderingChangeToTree(nsIFrame
* aFrame
,
7601 nsIViewManager
* aViewManager
,
7602 nsFrameManager
* aFrameManager
,
7603 nsChangeHint aChange
);
7606 * @param aBoundsRect returns the bounds enclosing the areas covered by aFrame and its childre
7607 * This rect is relative to aFrame's parent
7610 UpdateViewsForTree(nsIFrame
* aFrame
, nsIViewManager
* aViewManager
,
7611 nsFrameManager
* aFrameManager
,
7612 nsChangeHint aChange
)
7614 NS_PRECONDITION(gInApplyRenderingChangeToTree
,
7615 "should only be called within ApplyRenderingChangeToTree");
7617 nsIView
* view
= aFrame
->GetView();
7619 if (aChange
& nsChangeHint_SyncFrameView
) {
7620 nsContainerFrame::SyncFrameViewProperties(aFrame
->PresContext(),
7621 aFrame
, nsnull
, view
);
7625 // now do children of frame
7626 PRInt32 listIndex
= 0;
7627 nsIAtom
* childList
= nsnull
;
7630 nsIFrame
* child
= aFrame
->GetFirstChild(childList
);
7632 if (!(child
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)
7633 || (child
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
7634 // only do frames that don't have placeholders
7635 if (nsGkAtoms::placeholderFrame
== child
->GetType()) {
7636 // do the out-of-flow frame and its continuations
7637 nsIFrame
* outOfFlowFrame
=
7638 nsPlaceholderFrame::GetRealFrameForPlaceholder(child
);
7640 DoApplyRenderingChangeToTree(outOfFlowFrame
, aViewManager
,
7641 aFrameManager
, aChange
);
7642 } while (outOfFlowFrame
= outOfFlowFrame
->GetNextContinuation());
7643 } else if (childList
== nsGkAtoms::popupList
) {
7644 DoApplyRenderingChangeToTree(child
, aViewManager
,
7645 aFrameManager
, aChange
);
7646 } else { // regular frame
7647 if ((child
->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER
) &&
7648 (aChange
& nsChangeHint_RepaintFrame
)) {
7649 FrameLayerBuilder::InvalidateThebesLayerContents(child
,
7650 child
->GetVisualOverflowRectRelativeToSelf());
7652 UpdateViewsForTree(child
, aViewManager
, aFrameManager
, aChange
);
7655 child
= child
->GetNextSibling();
7657 childList
= aFrame
->GetAdditionalChildListName(listIndex
++);
7658 } while (childList
);
7662 DoApplyRenderingChangeToTree(nsIFrame
* aFrame
,
7663 nsIViewManager
* aViewManager
,
7664 nsFrameManager
* aFrameManager
,
7665 nsChangeHint aChange
)
7667 NS_PRECONDITION(gInApplyRenderingChangeToTree
,
7668 "should only be called within ApplyRenderingChangeToTree");
7670 for ( ; aFrame
; aFrame
= nsLayoutUtils::GetNextContinuationOrSpecialSibling(aFrame
)) {
7671 // Get view if this frame has one and trigger an update. If the
7672 // frame doesn't have a view, find the nearest containing view
7673 // (adjusting r's coordinate system to reflect the nesting) and
7675 UpdateViewsForTree(aFrame
, aViewManager
, aFrameManager
, aChange
);
7677 // if frame has view, will already be invalidated
7678 if (aChange
& nsChangeHint_RepaintFrame
) {
7679 if (aFrame
->IsFrameOfType(nsIFrame::eSVG
)) {
7681 if (!(aFrame
->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD
)) {
7682 nsSVGOuterSVGFrame
*outerSVGFrame
= nsSVGUtils::GetOuterSVGFrame(aFrame
);
7683 if (outerSVGFrame
) {
7684 // We need this to invalidate frames when their 'filter' or 'marker'
7685 // property changes. XXX in theory changes to 'marker' should be
7686 // handled in nsSVGPathGeometryFrame::DidSetStyleContext, but for
7687 // some reason that's broken.
7689 // This call is also currently the only mechanism for invalidating
7690 // the area covered by a <foreignObject> when 'opacity' changes on
7691 // it or one of its ancestors. (For 'opacity' changes on <image> or
7692 // a graphical element such as <path>, or on one of their
7693 // ancestors, this is redundant since
7694 // nsSVGPathGeometryFrame::DidSetStyleContext also invalidates.)
7695 outerSVGFrame
->UpdateAndInvalidateCoveredRegion(aFrame
);
7700 aFrame
->InvalidateOverflowRect();
7703 if (aChange
& nsChangeHint_UpdateOpacityLayer
) {
7704 aFrame
->MarkLayersActive();
7705 aFrame
->InvalidateLayer(aFrame
->GetVisualOverflowRectRelativeToSelf(),
7706 nsDisplayItem::TYPE_OPACITY
);
7709 if (aChange
& nsChangeHint_UpdateTransformLayer
) {
7710 aFrame
->MarkLayersActive();
7711 aFrame
->InvalidateLayer(aFrame
->GetVisualOverflowRectRelativeToSelf(),
7712 nsDisplayItem::TYPE_TRANSFORM
);
7718 ApplyRenderingChangeToTree(nsPresContext
* aPresContext
,
7720 nsChangeHint aChange
)
7722 nsIPresShell
*shell
= aPresContext
->PresShell();
7723 if (shell
->IsPaintingSuppressed()) {
7724 // Don't allow synchronous rendering changes when painting is turned off.
7725 aChange
= NS_SubtractHint(aChange
, nsChangeHint_RepaintFrame
);
7731 // If the frame's background is propagated to an ancestor, walk up to
7733 nsStyleContext
*bgSC
;
7734 while (!nsCSSRendering::FindBackground(aPresContext
, aFrame
, &bgSC
)) {
7735 aFrame
= aFrame
->GetParent();
7736 NS_ASSERTION(aFrame
, "root frame must paint");
7739 nsIViewManager
* viewManager
= shell
->GetViewManager();
7741 // Trigger rendering updates by damaging this frame and any
7742 // continuations of this frame.
7744 // XXX this needs to detect the need for a view due to an opacity change and deal with it...
7746 nsIViewManager::UpdateViewBatch
batch(viewManager
);
7749 gInApplyRenderingChangeToTree
= PR_TRUE
;
7751 DoApplyRenderingChangeToTree(aFrame
, viewManager
, shell
->FrameManager(),
7754 gInApplyRenderingChangeToTree
= PR_FALSE
;
7757 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
7761 * This method invalidates the canvas when frames are removed or added for a
7762 * node that might have its background propagated to the canvas, i.e., a
7763 * document root node or an HTML BODY which is a child of the root node.
7765 * @param aFrame a frame for a content node about to be removed or a frame that
7766 * was just created for a content node that was inserted.
7769 InvalidateCanvasIfNeeded(nsIPresShell
* presShell
, nsIContent
* node
)
7771 NS_PRECONDITION(presShell
->GetRootFrame(), "What happened here?");
7772 NS_PRECONDITION(presShell
->GetPresContext(), "Say what?");
7774 // Note that both in ContentRemoved and ContentInserted the content node
7775 // will still have the right parent pointer, so looking at that is ok.
7777 nsIContent
* parent
= node
->GetParent();
7779 // Has a parent; might not be what we want
7780 nsIContent
* grandParent
= parent
->GetParent();
7782 // Has a grandparent, so not what we want
7786 // Check whether it's an HTML body
7787 if (node
->Tag() != nsGkAtoms::body
||
7793 // At this point the node has no parent or it's an HTML <body> child of the
7794 // root. We might not need to invalidate in this case (eg we might be in
7795 // XHTML or something), but chances are we want to. Play it safe.
7796 // Invalidate the viewport.
7798 // Wrap this in a DEFERRED view update batch so we don't try to
7799 // flush out layout here
7801 nsIViewManager::UpdateViewBatch
batch(presShell
->GetViewManager());
7802 nsIFrame
* rootFrame
= presShell
->GetRootFrame();
7803 rootFrame
->InvalidateFrameSubtree();
7804 batch
.EndUpdateViewBatch(NS_VMREFRESH_DEFERRED
);
7808 nsCSSFrameConstructor::StyleChangeReflow(nsIFrame
* aFrame
,
7811 // If the frame hasn't even received an initial reflow, then don't
7812 // send it a style-change reflow!
7813 if (aFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
)
7817 if (gNoisyContentUpdates
) {
7818 printf("nsCSSFrameConstructor::StyleChangeReflow: aFrame=");
7819 nsFrame::ListTag(stdout
, aFrame
);
7824 nsIPresShell::IntrinsicDirty dirtyType
;
7825 if (aHint
& nsChangeHint_ClearDescendantIntrinsics
) {
7826 NS_ASSERTION(aHint
& nsChangeHint_ClearAncestorIntrinsics
,
7827 "Please read the comments in nsChangeHint.h");
7828 dirtyType
= nsIPresShell::eStyleChange
;
7829 } else if (aHint
& nsChangeHint_ClearAncestorIntrinsics
) {
7830 dirtyType
= nsIPresShell::eTreeChange
;
7832 dirtyType
= nsIPresShell::eResize
;
7835 nsFrameState dirtyBits
;
7836 if (aHint
& nsChangeHint_NeedDirtyReflow
) {
7837 dirtyBits
= NS_FRAME_IS_DIRTY
;
7839 dirtyBits
= NS_FRAME_HAS_DIRTY_CHILDREN
;
7843 mPresShell
->FrameNeedsReflow(aFrame
, dirtyType
, dirtyBits
);
7844 aFrame
= nsLayoutUtils::GetNextContinuationOrSpecialSibling(aFrame
);
7851 nsCSSFrameConstructor::CharacterDataChanged(nsIContent
* aContent
,
7852 CharacterDataChangeInfo
* aInfo
)
7854 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell
->GetPresContext(), FrameC
);
7855 nsresult rv
= NS_OK
;
7857 if ((aContent
->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE
) &&
7858 !aContent
->TextIsOnlyWhitespace()) ||
7859 (aContent
->HasFlag(NS_REFRAME_IF_WHITESPACE
) &&
7860 aContent
->TextIsOnlyWhitespace())) {
7862 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
7863 NS_ASSERTION(!frame
|| !frame
->IsGeneratedContentFrame(),
7864 "Bit should never be set on generated content");
7866 LAYOUT_PHASE_TEMP_EXIT();
7867 nsresult rv
= RecreateFramesForContent(aContent
, PR_FALSE
);
7868 LAYOUT_PHASE_TEMP_REENTER();
7872 // Find the child frame
7873 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
7875 // Notify the first frame that maps the content. It will generate a reflow
7878 // It's possible the frame whose content changed isn't inserted into the
7879 // frame hierarchy yet, or that there is no frame that maps the content
7880 if (nsnull
!= frame
) {
7882 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS
,
7883 ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p",
7884 aContent
, ContentTag(aContent
, 0),
7885 aSubContent
, frame
));
7888 // Special check for text content that is a child of a letter frame. If
7889 // this happens, we should remove the letter frame, do whatever we're
7890 // planning to do with this notification, then put the letter frame back.
7891 // Note that this is basically what RecreateFramesForContent ends up doing;
7892 // the reason we dont' want to call that here is that our text content
7893 // could be native anonymous, in which case RecreateFramesForContent would
7894 // completely barf on it. And recreating the non-anonymous ancestor would
7895 // just lead us to come back into this notification (e.g. if quotes or
7896 // counters are involved), leading to a loop.
7897 nsIFrame
* block
= GetFloatContainingBlock(frame
);
7898 PRBool haveFirstLetterStyle
= PR_FALSE
;
7900 // See if the block has first-letter style applied to it.
7901 haveFirstLetterStyle
= HasFirstLetterStyle(block
);
7902 if (haveFirstLetterStyle
) {
7903 RemoveLetterFrames(mPresShell
->GetPresContext(), mPresShell
,
7904 mPresShell
->FrameManager(), block
);
7905 // Reget |frame|, since we might have killed it.
7906 // Do we really need to call CharacterDataChanged in this case, though?
7907 frame
= aContent
->GetPrimaryFrame();
7908 NS_ASSERTION(frame
, "Should have frame here!");
7912 frame
->CharacterDataChanged(aInfo
);
7914 if (haveFirstLetterStyle
) {
7915 RecoverLetterFrames(block
);
7922 NS_DECLARE_FRAME_PROPERTY(ChangeListProperty
, nsnull
)
7925 nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList
& aChangeList
)
7927 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
7928 "Someone forgot a script blocker");
7929 PRInt32 count
= aChangeList
.Count();
7933 // Make sure to not rebuild quote or counter lists while we're
7934 // processing restyles
7937 nsPresContext
* presContext
= mPresShell
->GetPresContext();
7938 FramePropertyTable
* propTable
= presContext
->PropertyTable();
7940 // Mark frames so that we skip frames that die along the way, bug 123049.
7941 // A frame can be in the list multiple times with different hints. Further
7942 // optmization is possible if nsStyleChangeList::AppendChange could coalesce
7943 PRInt32 index
= count
;
7945 while (0 <= --index
) {
7946 const nsStyleChangeData
* changeData
;
7947 aChangeList
.ChangeAt(index
, &changeData
);
7948 if (changeData
->mFrame
) {
7949 propTable
->Set(changeData
->mFrame
, ChangeListProperty(),
7950 NS_INT32_TO_PTR(1));
7955 PRBool didInvalidate
= PR_FALSE
;
7956 PRBool didReflow
= PR_FALSE
;
7958 while (0 <= --index
) {
7960 nsIContent
* content
;
7962 aChangeList
.ChangeAt(index
, frame
, content
, hint
);
7964 NS_ASSERTION(!(hint
& nsChangeHint_ReflowFrame
) ||
7965 (hint
& nsChangeHint_NeedReflow
),
7966 "Reflow hint bits set without actually asking for a reflow");
7968 if (frame
&& frame
->GetContent() != content
) {
7969 // XXXbz this is due to image maps messing with the primary frame of
7970 // <area>s. See bug 135040. Remove this block once that's fixed.
7972 if (!(hint
& nsChangeHint_ReconstructFrame
)) {
7977 // skip any frame that has been destroyed due to a ripple effect
7979 if (!propTable
->Get(frame
, ChangeListProperty()))
7983 if (hint
& nsChangeHint_ReconstructFrame
) {
7984 RecreateFramesForContent(content
, PR_FALSE
);
7986 NS_ASSERTION(frame
, "This shouldn't happen");
7988 if (hint
& nsChangeHint_UpdateEffects
) {
7989 nsSVGEffects::UpdateEffects(frame
);
7992 if (hint
& nsChangeHint_NeedReflow
) {
7993 StyleChangeReflow(frame
, hint
);
7994 didReflow
= PR_TRUE
;
7996 if (hint
& (nsChangeHint_RepaintFrame
| nsChangeHint_SyncFrameView
|
7997 nsChangeHint_UpdateOpacityLayer
| nsChangeHint_UpdateTransformLayer
)) {
7998 ApplyRenderingChangeToTree(presContext
, frame
, hint
);
7999 didInvalidate
= PR_TRUE
;
8001 if (hint
& nsChangeHint_UpdateCursor
) {
8002 mPresShell
->SynthesizeMouseMove(PR_FALSE
);
8009 if (didInvalidate
&& !didReflow
) {
8010 // RepaintFrame changes can indicate changes in opacity etc which
8011 // can require plugin clipping to change. If we requested a reflow,
8012 // we don't need to do this since the reflow will do it for us.
8013 nsIFrame
* rootFrame
= mPresShell
->FrameManager()->GetRootFrame();
8014 nsRootPresContext
* rootPC
= presContext
->GetRootPresContext();
8016 rootPC
->RequestUpdatePluginGeometry(rootFrame
);
8020 // cleanup references and verify the style tree. Note that the latter needs
8021 // to happen once we've processed the whole list, since until then the tree
8022 // is not in fact in a consistent state.
8024 while (0 <= --index
) {
8025 const nsStyleChangeData
* changeData
;
8026 aChangeList
.ChangeAt(index
, &changeData
);
8027 if (changeData
->mFrame
) {
8028 propTable
->Delete(changeData
->mFrame
, ChangeListProperty());
8032 // reget frame from content since it may have been regenerated...
8033 if (changeData
->mContent
) {
8034 nsIFrame
* frame
= changeData
->mContent
->GetPrimaryFrame();
8036 mPresShell
->FrameManager()->DebugVerifyStyleTree(frame
);
8039 NS_WARNING("Unable to test style tree integrity -- no content node");
8044 aChangeList
.Clear();
8049 nsCSSFrameConstructor::RestyleElement(Element
*aElement
,
8050 nsIFrame
*aPrimaryFrame
,
8051 nsChangeHint aMinHint
,
8052 RestyleTracker
& aRestyleTracker
,
8053 PRBool aRestyleDescendants
)
8055 NS_ASSERTION(aPrimaryFrame
== aElement
->GetPrimaryFrame(),
8056 "frame/content mismatch");
8057 if (aPrimaryFrame
&& aPrimaryFrame
->GetContent() != aElement
) {
8058 // XXXbz this is due to image maps messing with the primary frame pointer
8059 // of <area>s. See bug 135040. We can remove this block once that's fixed.
8060 aPrimaryFrame
= nsnull
;
8062 NS_ASSERTION(!aPrimaryFrame
|| aPrimaryFrame
->GetContent() == aElement
,
8063 "frame/content mismatch");
8065 if (aMinHint
& nsChangeHint_ReconstructFrame
) {
8066 RecreateFramesForContent(aElement
, PR_FALSE
);
8067 } else if (aPrimaryFrame
) {
8068 nsStyleChangeList changeList
;
8069 mPresShell
->FrameManager()->
8070 ComputeStyleChangeFor(aPrimaryFrame
, &changeList
, aMinHint
,
8071 aRestyleTracker
, aRestyleDescendants
);
8072 ProcessRestyledFrames(changeList
);
8074 // no frames, reconstruct for content
8075 MaybeRecreateFramesForElement(aElement
);
8080 nsCSSFrameConstructor::ContentStatesChanged(nsIContent
* aContent1
,
8081 nsIContent
* aContent2
,
8082 nsEventStates aStateMask
)
8084 // XXXbz it would be good if this function only took Elements, but
8085 // we'd have to make ESM guarantee that usefully.
8086 if (NS_LIKELY(aContent1
&& aContent1
->IsElement())) {
8087 DoContentStateChanged(aContent1
->AsElement(), aStateMask
);
8089 if (aContent2
&& aContent2
->IsElement()) {
8090 DoContentStateChanged(aContent2
->AsElement(), aStateMask
);
8096 nsCSSFrameConstructor::DoContentStateChanged(Element
* aElement
,
8097 nsEventStates aStateMask
)
8099 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
8100 nsPresContext
*presContext
= mPresShell
->GetPresContext();
8101 NS_ASSERTION(styleSet
, "couldn't get style set");
8103 nsChangeHint hint
= NS_STYLE_HINT_NONE
;
8104 // Any change to a content state that affects which frames we construct
8105 // must lead to a frame reconstruct here if we already have a frame.
8106 // Note that we never decide through non-CSS means to not create frames
8107 // based on content states, so if we already don't have a frame we don't
8108 // need to force a reframe -- if it's needed, the HasStateDependentStyle
8109 // call will handle things.
8110 nsIFrame
* primaryFrame
= aElement
->GetPrimaryFrame();
8112 // If it's generated content, ignore LOADING/etc state changes on it.
8113 if (!primaryFrame
->IsGeneratedContentFrame() &&
8114 aStateMask
.HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN
|
8115 NS_EVENT_STATE_USERDISABLED
|
8116 NS_EVENT_STATE_SUPPRESSED
|
8117 NS_EVENT_STATE_LOADING
)) {
8118 hint
= nsChangeHint_ReconstructFrame
;
8120 PRUint8 app
= primaryFrame
->GetStyleDisplay()->mAppearance
;
8122 nsITheme
*theme
= presContext
->GetTheme();
8123 if (theme
&& theme
->ThemeSupportsWidget(presContext
,
8124 primaryFrame
, app
)) {
8125 PRBool repaint
= PR_FALSE
;
8126 theme
->WidgetStateChanged(primaryFrame
, app
, nsnull
, &repaint
);
8128 NS_UpdateHint(hint
, nsChangeHint_RepaintFrame
);
8135 nsRestyleHint rshint
=
8136 styleSet
->HasStateDependentStyle(presContext
, aElement
, aStateMask
);
8138 if (aStateMask
.HasState(NS_EVENT_STATE_HOVER
) && rshint
!= 0) {
8142 if (aStateMask
.HasState(NS_EVENT_STATE_VISITED
)) {
8143 // Exposing information to the page about whether the link is
8144 // visited or not isn't really something we can worry about here.
8145 // FIXME: We could probably do this a bit better.
8146 NS_UpdateHint(hint
, nsChangeHint_RepaintFrame
);
8149 PostRestyleEvent(aElement
, rshint
, hint
);
8153 nsCSSFrameConstructor::AttributeWillChange(Element
* aElement
,
8154 PRInt32 aNameSpaceID
,
8155 nsIAtom
* aAttribute
,
8158 nsRestyleHint rshint
=
8159 mPresShell
->StyleSet()->HasAttributeDependentStyle(mPresShell
->GetPresContext(),
8164 PostRestyleEvent(aElement
, rshint
, NS_STYLE_HINT_NONE
);
8168 nsCSSFrameConstructor::AttributeChanged(Element
* aElement
,
8169 PRInt32 aNameSpaceID
,
8170 nsIAtom
* aAttribute
,
8173 // Hold onto the PresShell to prevent ourselves from being destroyed.
8174 // XXXbz how, exactly, would this attribute change cause us to be
8175 // destroyed from inside this function?
8176 nsCOMPtr
<nsIPresShell
> shell
= mPresShell
;
8178 // Get the frame associated with the content which is the highest in the frame tree
8179 nsIFrame
* primaryFrame
= aElement
->GetPrimaryFrame();
8182 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS
,
8183 ("HTMLStyleSheet::AttributeChanged: content=%p[%s] frame=%p",
8184 aContent
, ContentTag(aElement
, 0), frame
));
8187 // the style tag has its own interpretation based on aHint
8188 nsChangeHint hint
= aElement
->GetAttributeChangeHint(aAttribute
, aModType
);
8190 PRBool reframe
= (hint
& nsChangeHint_ReconstructFrame
) != 0;
8193 // The following listbox widget trap prevents offscreen listbox widget
8194 // content from being removed and re-inserted (which is what would
8195 // happen otherwise).
8196 if (!primaryFrame
&& !reframe
) {
8197 PRInt32 namespaceID
;
8199 mDocument
->BindingManager()->ResolveTag(aElement
, &namespaceID
);
8201 if (namespaceID
== kNameSpaceID_XUL
&&
8202 (tag
== nsGkAtoms::listitem
||
8203 tag
== nsGkAtoms::listcell
))
8207 if (aAttribute
== nsGkAtoms::tooltiptext
||
8208 aAttribute
== nsGkAtoms::tooltip
)
8210 nsIRootBox
* rootBox
= nsIRootBox::GetRootBox(mPresShell
);
8212 if (aModType
== nsIDOMMutationEvent::REMOVAL
)
8213 rootBox
->RemoveTooltipSupport(aElement
);
8214 if (aModType
== nsIDOMMutationEvent::ADDITION
)
8215 rootBox
->AddTooltipSupport(aElement
);
8222 // See if we have appearance information for a theme.
8223 const nsStyleDisplay
* disp
= primaryFrame
->GetStyleDisplay();
8224 if (disp
->mAppearance
) {
8225 nsPresContext
* presContext
= mPresShell
->GetPresContext();
8226 nsITheme
*theme
= presContext
->GetTheme();
8227 if (theme
&& theme
->ThemeSupportsWidget(presContext
, primaryFrame
, disp
->mAppearance
)) {
8228 PRBool repaint
= PR_FALSE
;
8229 theme
->WidgetStateChanged(primaryFrame
, disp
->mAppearance
, aAttribute
, &repaint
);
8231 NS_UpdateHint(hint
, nsChangeHint_RepaintFrame
);
8235 // let the frame deal with it now, so we don't have to deal later
8236 primaryFrame
->AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
8237 // XXXwaterson should probably check for special IB siblings
8238 // here, and propagate the AttributeChanged notification to
8239 // them, as well. Currently, inline frames don't do anything on
8240 // this notification, so it's not that big a deal.
8243 // See if we can optimize away the style re-resolution -- must be called after
8244 // the frame's AttributeChanged() in case it does something that affects the style
8245 nsRestyleHint rshint
=
8246 mPresShell
->StyleSet()->HasAttributeDependentStyle(mPresShell
->GetPresContext(),
8252 PostRestyleEvent(aElement
, rshint
, hint
);
8256 nsCSSFrameConstructor::BeginUpdate() {
8257 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
8258 "Someone forgot a script blocker");
8260 nsRootPresContext
* rootPresContext
=
8261 mPresShell
->GetPresContext()->GetRootPresContext();
8262 if (rootPresContext
) {
8263 rootPresContext
->IncrementDOMGeneration();
8270 nsCSSFrameConstructor::EndUpdate()
8272 if (mUpdateCount
== 1) {
8273 // This is the end of our last update. Before we decrement
8274 // mUpdateCount, recalc quotes and counters as needed.
8276 RecalcQuotesAndCounters();
8277 NS_ASSERTION(mUpdateCount
== 1, "Odd update count");
8283 nsCSSFrameConstructor::RecalcQuotesAndCounters()
8286 mQuotesDirty
= PR_FALSE
;
8287 mQuoteList
.RecalcAll();
8290 if (mCountersDirty
) {
8291 mCountersDirty
= PR_FALSE
;
8292 mCounterManager
.RecalcAll();
8295 NS_ASSERTION(!mQuotesDirty
, "Quotes updates will be lost");
8296 NS_ASSERTION(!mCountersDirty
, "Counter updates will be lost");
8300 nsCSSFrameConstructor::WillDestroyFrameTree()
8302 #if defined(DEBUG_dbaron_off)
8303 mCounterManager
.Dump();
8306 mIsDestroyingFrameTree
= PR_TRUE
;
8308 // Prevent frame tree destruction from being O(N^2)
8310 mCounterManager
.Clear();
8312 // Remove our presshell as a style flush observer. But leave
8313 // mObservingRefreshDriver true so we don't readd to it even if someone tries
8314 // to post restyle events on us from this point on for some reason.
8315 mPresShell
->GetPresContext()->RefreshDriver()->
8316 RemoveStyleFlushObserver(mPresShell
);
8321 // XXXbz I'd really like this method to go away. Once we have inline-block and
8322 // I can just use that for sized broken images, that can happen, maybe.
8323 void nsCSSFrameConstructor::GetAlternateTextFor(nsIContent
* aContent
,
8324 nsIAtom
* aTag
, // content object's tag
8325 nsXPIDLString
& aAltText
)
8327 // The "alt" attribute specifies alternate text that is rendered
8328 // when the image can not be displayed
8330 // If there's no "alt" attribute, and aContent is an input
8331 // element, then use the value of the "value" attribute
8332 if (!aContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::alt
, aAltText
) &&
8333 nsGkAtoms::input
== aTag
) {
8334 // If there's no "value" attribute either, then use the localized string
8335 // for "Submit" as the alternate text.
8336 if (!aContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::value
, aAltText
)) {
8337 nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES
,
8338 "Submit", aAltText
);
8344 nsCSSFrameConstructor::CreateContinuingOuterTableFrame(nsIPresShell
* aPresShell
,
8345 nsPresContext
* aPresContext
,
8347 nsIFrame
* aParentFrame
,
8348 nsIContent
* aContent
,
8349 nsStyleContext
* aStyleContext
,
8350 nsIFrame
** aContinuingFrame
)
8352 nsIFrame
* newFrame
= NS_NewTableOuterFrame(aPresShell
, aStyleContext
);
8355 newFrame
->Init(aContent
, aParentFrame
, aFrame
);
8356 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8358 // Create a continuing inner table frame, and if there's a caption then
8359 // replicate the caption
8360 nsFrameItems newChildFrames
;
8362 nsIFrame
* childFrame
= aFrame
->GetFirstChild(nsnull
);
8364 nsIFrame
* continuingTableFrame
;
8365 nsresult rv
= CreateContinuingFrame(aPresContext
, childFrame
, newFrame
,
8366 &continuingTableFrame
);
8367 if (NS_FAILED(rv
)) {
8368 newFrame
->Destroy();
8369 *aContinuingFrame
= nsnull
;
8372 newChildFrames
.AddChild(continuingTableFrame
);
8374 NS_ASSERTION(!childFrame
->GetNextSibling(),"there can be only one inner table frame");
8377 // Set the outer table's initial child list
8378 newFrame
->SetInitialChildList(nsnull
, newChildFrames
);
8380 *aContinuingFrame
= newFrame
;
8384 *aContinuingFrame
= nsnull
;
8385 return NS_ERROR_OUT_OF_MEMORY
;
8390 nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell
* aPresShell
,
8391 nsPresContext
* aPresContext
,
8393 nsIFrame
* aParentFrame
,
8394 nsIContent
* aContent
,
8395 nsStyleContext
* aStyleContext
,
8396 nsIFrame
** aContinuingFrame
)
8398 nsIFrame
* newFrame
= NS_NewTableFrame(aPresShell
, aStyleContext
);
8401 newFrame
->Init(aContent
, aParentFrame
, aFrame
);
8402 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8404 // Replicate any header/footer frames
8405 nsFrameItems childFrames
;
8406 nsIFrame
* childFrame
= aFrame
->GetFirstChild(nsnull
);
8407 for ( ; childFrame
; childFrame
= childFrame
->GetNextSibling()) {
8408 // See if it's a header/footer, possibly wrapped in a scroll frame.
8409 nsTableRowGroupFrame
* rowGroupFrame
=
8410 static_cast<nsTableRowGroupFrame
*>(childFrame
);
8411 // If the row group was continued, then don't replicate it.
8412 nsIFrame
* rgNextInFlow
= rowGroupFrame
->GetNextInFlow();
8414 rowGroupFrame
->SetRepeatable(PR_FALSE
);
8416 else if (rowGroupFrame
->IsRepeatable()) {
8417 // Replicate the header/footer frame.
8418 nsTableRowGroupFrame
* headerFooterFrame
;
8419 nsFrameItems childItems
;
8420 nsFrameConstructorState
state(mPresShell
, mFixedContainingBlock
,
8421 GetAbsoluteContainingBlock(newFrame
),
8423 state
.mCreatingExtraFrames
= PR_TRUE
;
8425 headerFooterFrame
= static_cast<nsTableRowGroupFrame
*>
8426 (NS_NewTableRowGroupFrame(aPresShell
, rowGroupFrame
->GetStyleContext()));
8427 nsIContent
* headerFooter
= rowGroupFrame
->GetContent();
8428 headerFooterFrame
->Init(headerFooter
, newFrame
, nsnull
);
8429 ProcessChildren(state
, headerFooter
, rowGroupFrame
->GetStyleContext(),
8430 headerFooterFrame
, PR_TRUE
, childItems
, PR_FALSE
,
8432 NS_ASSERTION(state
.mFloatedItems
.IsEmpty(), "unexpected floated element");
8433 headerFooterFrame
->SetInitialChildList(nsnull
, childItems
);
8434 headerFooterFrame
->SetRepeatable(PR_TRUE
);
8436 // Table specific initialization
8437 headerFooterFrame
->InitRepeatedFrame(aPresContext
, rowGroupFrame
);
8439 // XXX Deal with absolute and fixed frames...
8440 childFrames
.AddChild(headerFooterFrame
);
8444 // Set the table frame's initial child list
8445 newFrame
->SetInitialChildList(nsnull
, childFrames
);
8447 *aContinuingFrame
= newFrame
;
8451 *aContinuingFrame
= nsnull
;
8452 return NS_ERROR_OUT_OF_MEMORY
;
8457 nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext
* aPresContext
,
8459 nsIFrame
* aParentFrame
,
8460 nsIFrame
** aContinuingFrame
,
8463 nsIPresShell
* shell
= aPresContext
->PresShell();
8464 nsStyleContext
* styleContext
= aFrame
->GetStyleContext();
8465 nsIFrame
* newFrame
= nsnull
;
8466 nsresult rv
= NS_OK
;
8467 nsIFrame
* nextContinuation
= aFrame
->GetNextContinuation();
8468 nsIFrame
* nextInFlow
= aFrame
->GetNextInFlow();
8470 // Use the frame type to determine what type of frame to create
8471 nsIAtom
* frameType
= aFrame
->GetType();
8472 nsIContent
* content
= aFrame
->GetContent();
8474 NS_ASSERTION(aFrame
->GetSplittableType() != NS_FRAME_NOT_SPLITTABLE
,
8475 "why CreateContinuingFrame for a non-splittable frame?");
8477 if (nsGkAtoms::textFrame
== frameType
) {
8478 newFrame
= NS_NewContinuingTextFrame(shell
, styleContext
);
8481 newFrame
->Init(content
, aParentFrame
, aFrame
);
8482 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8485 } else if (nsGkAtoms::inlineFrame
== frameType
) {
8486 newFrame
= NS_NewInlineFrame(shell
, styleContext
);
8489 newFrame
->Init(content
, aParentFrame
, aFrame
);
8490 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8493 } else if (nsGkAtoms::blockFrame
== frameType
) {
8494 newFrame
= NS_NewBlockFrame(shell
, styleContext
);
8497 newFrame
->Init(content
, aParentFrame
, aFrame
);
8498 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8502 } else if (nsGkAtoms::XULLabelFrame
== frameType
) {
8503 newFrame
= NS_NewXULLabelFrame(shell
, styleContext
);
8506 newFrame
->Init(content
, aParentFrame
, aFrame
);
8507 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8510 } else if (nsGkAtoms::columnSetFrame
== frameType
) {
8511 newFrame
= NS_NewColumnSetFrame(shell
, styleContext
, 0);
8514 newFrame
->Init(content
, aParentFrame
, aFrame
);
8515 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8518 } else if (nsGkAtoms::positionedInlineFrame
== frameType
) {
8519 newFrame
= NS_NewPositionedInlineFrame(shell
, styleContext
);
8522 newFrame
->Init(content
, aParentFrame
, aFrame
);
8523 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8526 } else if (nsGkAtoms::pageFrame
== frameType
) {
8527 nsIFrame
* canvasFrame
;
8528 rv
= ConstructPageFrame(shell
, aPresContext
, aParentFrame
, aFrame
,
8529 newFrame
, canvasFrame
);
8530 } else if (nsGkAtoms::tableOuterFrame
== frameType
) {
8531 rv
= CreateContinuingOuterTableFrame(shell
, aPresContext
, aFrame
, aParentFrame
,
8532 content
, styleContext
, &newFrame
);
8534 } else if (nsGkAtoms::tableFrame
== frameType
) {
8535 rv
= CreateContinuingTableFrame(shell
, aPresContext
, aFrame
, aParentFrame
,
8536 content
, styleContext
, &newFrame
);
8538 } else if (nsGkAtoms::tableRowGroupFrame
== frameType
) {
8539 newFrame
= NS_NewTableRowGroupFrame(shell
, styleContext
);
8542 newFrame
->Init(content
, aParentFrame
, aFrame
);
8543 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8546 } else if (nsGkAtoms::tableRowFrame
== frameType
) {
8547 newFrame
= NS_NewTableRowFrame(shell
, styleContext
);
8550 newFrame
->Init(content
, aParentFrame
, aFrame
);
8551 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8553 // Create a continuing frame for each table cell frame
8554 nsFrameItems newChildList
;
8555 nsIFrame
* cellFrame
= aFrame
->GetFirstChild(nsnull
);
8557 // See if it's a table cell frame
8558 if (IS_TABLE_CELL(cellFrame
->GetType())) {
8559 nsIFrame
* continuingCellFrame
;
8560 rv
= CreateContinuingFrame(aPresContext
, cellFrame
, newFrame
,
8561 &continuingCellFrame
);
8562 if (NS_FAILED(rv
)) {
8563 newChildList
.DestroyFrames();
8564 newFrame
->Destroy();
8565 *aContinuingFrame
= nsnull
;
8566 return NS_ERROR_OUT_OF_MEMORY
;
8568 newChildList
.AddChild(continuingCellFrame
);
8570 cellFrame
= cellFrame
->GetNextSibling();
8573 // Set the table cell's initial child list
8574 newFrame
->SetInitialChildList(nsnull
, newChildList
);
8577 } else if (IS_TABLE_CELL(frameType
)) {
8578 // Warning: If you change this and add a wrapper frame around table cell
8579 // frames, make sure Bug 368554 doesn't regress!
8580 // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
8581 newFrame
= NS_NewTableCellFrame(shell
, styleContext
, IsBorderCollapse(aParentFrame
));
8584 newFrame
->Init(content
, aParentFrame
, aFrame
);
8585 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8587 // Create a continuing area frame
8588 nsIFrame
* continuingBlockFrame
;
8589 nsIFrame
* blockFrame
= aFrame
->GetFirstChild(nsnull
);
8590 rv
= CreateContinuingFrame(aPresContext
, blockFrame
, newFrame
,
8591 &continuingBlockFrame
);
8592 if (NS_FAILED(rv
)) {
8593 newFrame
->Destroy();
8594 *aContinuingFrame
= nsnull
;
8598 // Set the table cell's initial child list
8599 SetInitialSingleChild(newFrame
, continuingBlockFrame
);
8602 } else if (nsGkAtoms::lineFrame
== frameType
) {
8603 newFrame
= NS_NewFirstLineFrame(shell
, styleContext
);
8606 newFrame
->Init(content
, aParentFrame
, aFrame
);
8607 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8610 } else if (nsGkAtoms::letterFrame
== frameType
) {
8611 newFrame
= NS_NewFirstLetterFrame(shell
, styleContext
);
8614 newFrame
->Init(content
, aParentFrame
, aFrame
);
8615 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8618 } else if (nsGkAtoms::imageFrame
== frameType
) {
8619 newFrame
= NS_NewImageFrame(shell
, styleContext
);
8622 newFrame
->Init(content
, aParentFrame
, aFrame
);
8624 } else if (nsGkAtoms::imageControlFrame
== frameType
) {
8625 newFrame
= NS_NewImageControlFrame(shell
, styleContext
);
8628 newFrame
->Init(content
, aParentFrame
, aFrame
);
8630 } else if (nsGkAtoms::placeholderFrame
== frameType
) {
8631 // create a continuing out of flow frame
8632 nsIFrame
* oofFrame
= nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame
);
8633 nsIFrame
* oofContFrame
;
8634 rv
= CreateContinuingFrame(aPresContext
, oofFrame
, aParentFrame
, &oofContFrame
);
8635 if (NS_FAILED(rv
)) {
8636 *aContinuingFrame
= nsnull
;
8639 // create a continuing placeholder frame
8640 rv
= CreatePlaceholderFrameFor(shell
, content
, oofContFrame
, styleContext
,
8641 aParentFrame
, aFrame
,
8642 aFrame
->GetStateBits() & PLACEHOLDER_TYPE_MASK
,
8644 if (NS_FAILED(rv
)) {
8645 oofContFrame
->Destroy();
8646 *aContinuingFrame
= nsnull
;
8649 } else if (nsGkAtoms::fieldSetFrame
== frameType
) {
8650 newFrame
= NS_NewFieldSetFrame(shell
, styleContext
);
8653 newFrame
->Init(content
, aParentFrame
, aFrame
);
8655 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8657 // Create a continuing area frame
8658 // XXXbz we really shouldn't have to do this by hand!
8659 nsIFrame
* continuingBlockFrame
;
8660 nsIFrame
* blockFrame
= GetFieldSetBlockFrame(aFrame
);
8661 rv
= CreateContinuingFrame(aPresContext
, blockFrame
, newFrame
,
8662 &continuingBlockFrame
);
8663 if (NS_FAILED(rv
)) {
8664 newFrame
->Destroy();
8665 *aContinuingFrame
= nsnull
;
8668 // Set the fieldset's initial child list
8669 SetInitialSingleChild(newFrame
, continuingBlockFrame
);
8671 } else if (nsGkAtoms::legendFrame
== frameType
) {
8672 newFrame
= NS_NewLegendFrame(shell
, styleContext
);
8675 newFrame
->Init(content
, aParentFrame
, aFrame
);
8676 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8679 NS_NOTREACHED("unexpected frame type");
8680 *aContinuingFrame
= nsnull
;
8681 return NS_ERROR_UNEXPECTED
;
8684 *aContinuingFrame
= newFrame
;
8687 return NS_ERROR_OUT_OF_MEMORY
;
8690 // Init() set newFrame to be a fluid continuation of aFrame.
8691 // If we want a non-fluid continuation, we need to call SetPrevContinuation()
8692 // to reset NS_FRAME_IS_FLUID_CONTINUATION.
8694 newFrame
->SetPrevContinuation(aFrame
);
8697 // A continuation of generated content is also generated content
8698 if (aFrame
->GetStateBits() & NS_FRAME_GENERATED_CONTENT
) {
8699 newFrame
->AddStateBits(NS_FRAME_GENERATED_CONTENT
);
8702 // A continuation of an out-of-flow is also an out-of-flow
8703 if (aFrame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
8704 newFrame
->AddStateBits(NS_FRAME_OUT_OF_FLOW
);
8708 nextInFlow
->SetPrevInFlow(newFrame
);
8709 newFrame
->SetNextInFlow(nextInFlow
);
8710 } else if (nextContinuation
) {
8711 nextContinuation
->SetPrevContinuation(newFrame
);
8712 newFrame
->SetNextContinuation(nextContinuation
);
8715 NS_POSTCONDITION(!newFrame
->GetNextSibling(), "unexpected sibling");
8720 nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame
* aParentFrame
)
8722 // Now deal with fixed-pos things.... They should appear on all pages,
8723 // so we want to move over the placeholders when processing the child
8724 // of the pageContentFrame.
8726 nsIFrame
* prevPageContentFrame
= aParentFrame
->GetPrevInFlow();
8727 if (!prevPageContentFrame
) {
8730 nsIFrame
* canvasFrame
= aParentFrame
->GetFirstChild(nsnull
);
8731 nsIFrame
* prevCanvasFrame
= prevPageContentFrame
->GetFirstChild(nsnull
);
8732 if (!canvasFrame
|| !prevCanvasFrame
) {
8733 // document's root element frame missing
8734 return NS_ERROR_UNEXPECTED
;
8737 nsFrameItems fixedPlaceholders
;
8738 nsIFrame
* firstFixed
= prevPageContentFrame
->GetFirstChild(nsGkAtoms::fixedList
);
8743 // Don't allow abs-pos descendants of the fixed content to escape the content.
8744 // This should not normally be possible (because fixed-pos elements should
8745 // be absolute containers) but fixed-pos tables currently aren't abs-pos
8747 nsFrameConstructorState
state(mPresShell
, aParentFrame
,
8750 state
.mCreatingExtraFrames
= PR_TRUE
;
8752 // Iterate across fixed frames and replicate each whose placeholder is a
8753 // descendant of aFrame. (We don't want to explicitly copy placeholders that
8754 // are within fixed frames, because that would cause duplicates on the new
8755 // page - bug 389619)
8756 for (nsIFrame
* fixed
= firstFixed
; fixed
; fixed
= fixed
->GetNextSibling()) {
8757 nsIFrame
* prevPlaceholder
= mPresShell
->FrameManager()->GetPlaceholderFrameFor(fixed
);
8758 if (prevPlaceholder
&&
8759 nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame
, prevPlaceholder
)) {
8760 nsresult rv
= ConstructFrame(state
, fixed
->GetContent(),
8761 canvasFrame
, fixedPlaceholders
);
8762 NS_ENSURE_SUCCESS(rv
, rv
);
8766 // Add the placeholders to our primary child list.
8767 // XXXbz this is a little screwed up, since the fixed frames will have
8768 // broken auto-positioning. Oh, well.
8769 NS_ASSERTION(!canvasFrame
->GetFirstChild(nsnull
),
8770 "leaking frames; doc root continuation must be empty");
8771 canvasFrame
->SetInitialChildList(nsnull
, fixedPlaceholders
);
8776 nsCSSFrameConstructor::GetInsertionPoint(nsIFrame
* aParentFrame
,
8777 nsIContent
* aChildContent
,
8778 nsIFrame
** aInsertionPoint
,
8781 // Make the insertion point be the parent frame by default, in case
8782 // we have to bail early.
8783 *aInsertionPoint
= aParentFrame
;
8785 nsIContent
* container
= aParentFrame
->GetContent();
8789 nsBindingManager
*bindingManager
= mDocument
->BindingManager();
8791 nsIContent
* insertionElement
;
8792 if (aChildContent
) {
8793 // We've got an explicit insertion child. Check to see if it's
8795 if (aChildContent
->GetBindingParent() == container
) {
8796 // This child content is anonymous. Don't use the insertion
8797 // point, since that's only for the explicit kids.
8802 insertionElement
= bindingManager
->GetInsertionPoint(container
,
8809 insertionElement
= bindingManager
->GetSingleInsertionPoint(container
,
8812 if (multiple
&& aMultiple
)
8813 *aMultiple
= multiple
; // Record the fact that filters are in use.
8816 if (insertionElement
) {
8817 nsIFrame
* insertionPoint
= insertionElement
->GetPrimaryFrame();
8818 if (insertionPoint
) {
8819 // Use the content insertion frame of the insertion point.
8820 insertionPoint
= insertionPoint
->GetContentInsertionFrame();
8821 if (insertionPoint
&& insertionPoint
!= aParentFrame
)
8822 GetInsertionPoint(insertionPoint
, aChildContent
, aInsertionPoint
, aMultiple
);
8825 // There was no frame created yet for the insertion point.
8826 *aInsertionPoint
= nsnull
;
8830 // fieldsets have multiple insertion points. Note that we might
8831 // have to look at insertionElement here...
8832 if (aMultiple
&& !*aMultiple
) {
8833 nsIContent
* content
= insertionElement
? insertionElement
: container
;
8834 if (content
->IsHTML() &&
8835 content
->Tag() == nsGkAtoms::fieldset
) {
8836 *aMultiple
= PR_TRUE
;
8843 // Capture state for the frame tree rooted at the frame associated with the
8844 // content object, aContent
8846 nsCSSFrameConstructor::CaptureStateForFramesOf(nsIContent
* aContent
,
8847 nsILayoutHistoryState
* aHistoryState
)
8849 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
8850 if (frame
== mRootElementFrame
) {
8851 frame
= mFixedContainingBlock
;
8854 CaptureStateFor(frame
, aHistoryState
);
8859 // Capture state for the frame tree rooted at aFrame.
8861 nsCSSFrameConstructor::CaptureStateFor(nsIFrame
* aFrame
,
8862 nsILayoutHistoryState
* aHistoryState
)
8864 if (aFrame
&& aHistoryState
) {
8865 mPresShell
->FrameManager()->CaptureFrameState(aFrame
, aHistoryState
);
8871 nsCSSFrameConstructor::MaybeRecreateFramesForElement(Element
* aElement
)
8873 nsresult result
= NS_OK
;
8874 nsFrameManager
*frameManager
= mPresShell
->FrameManager();
8876 nsStyleContext
*oldContext
= frameManager
->GetUndisplayedContent(aElement
);
8878 // The parent has a frame, so try resolving a new context.
8879 nsRefPtr
<nsStyleContext
> newContext
= mPresShell
->StyleSet()->
8880 ResolveStyleFor(aElement
, oldContext
->GetParent());
8882 frameManager
->ChangeUndisplayedContent(aElement
, newContext
);
8883 if (newContext
->GetStyleDisplay()->mDisplay
!= NS_STYLE_DISPLAY_NONE
) {
8884 result
= RecreateFramesForContent(aElement
, PR_FALSE
);
8891 FindFirstNonWhitespaceChild(nsIFrame
* aParentFrame
)
8893 nsIFrame
* f
= aParentFrame
->GetFirstChild(nsnull
);
8894 while (f
&& f
->GetType() == nsGkAtoms::textFrame
&&
8895 f
->GetContent()->TextIsOnlyWhitespace()) {
8896 f
= f
->GetNextSibling();
8902 FindNextNonWhitespaceSibling(nsIFrame
* aFrame
)
8904 nsIFrame
* f
= aFrame
;
8906 f
= f
->GetNextSibling();
8907 } while (f
&& f
->GetType() == nsGkAtoms::textFrame
&&
8908 f
->GetContent()->TextIsOnlyWhitespace());
8913 nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame
* aFrame
,
8916 NS_PRECONDITION(aFrame
, "Must have a frame");
8917 NS_PRECONDITION(aFrame
->GetParent(), "Frame shouldn't be root");
8918 NS_PRECONDITION(aResult
, "Null out param?");
8919 NS_PRECONDITION(aFrame
== aFrame
->GetFirstContinuation(),
8920 "aFrame not the result of GetPrimaryFrame()?");
8922 if (IsFrameSpecial(aFrame
)) {
8923 // The removal functions can't handle removal of an {ib} split directly; we
8924 // need to rebuild the containing block.
8926 if (gNoisyContentUpdates
) {
8927 printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8929 nsFrame::ListTag(stdout
, aFrame
);
8930 printf(" is special\n");
8934 *aResult
= ReframeContainingBlock(aFrame
);
8938 if (aFrame
->GetType() == nsGkAtoms::legendFrame
&&
8939 aFrame
->GetParent()->GetType() == nsGkAtoms::fieldSetFrame
) {
8940 // When we remove the legend for a fieldset, we should reframe
8941 // the fieldset to ensure another legend is used, if there is one
8942 *aResult
= RecreateFramesForContent(aFrame
->GetParent()->GetContent(), PR_FALSE
);
8946 // Now check for possibly needing to reconstruct due to a pseudo parent
8947 nsIFrame
* inFlowFrame
=
8948 (aFrame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) ?
8949 mPresShell
->FrameManager()->GetPlaceholderFrameFor(aFrame
) : aFrame
;
8950 NS_ASSERTION(inFlowFrame
, "How did that happen?");
8951 nsIFrame
* parent
= inFlowFrame
->GetParent();
8952 if (IsTablePseudo(parent
)) {
8953 if (FindFirstNonWhitespaceChild(parent
) == inFlowFrame
||
8954 !FindNextNonWhitespaceSibling(inFlowFrame
->GetLastContinuation()) ||
8955 // If we're a table-column-group, then the GetFirstChild check above is
8956 // not going to catch cases when we're the first child.
8957 (inFlowFrame
->GetType() == nsGkAtoms::tableColGroupFrame
&&
8958 parent
->GetFirstChild(nsGkAtoms::colGroupList
) == inFlowFrame
) ||
8959 // Similar if we're a table-caption.
8960 (inFlowFrame
->GetType() == nsGkAtoms::tableCaptionFrame
&&
8961 parent
->GetFirstChild(nsGkAtoms::captionList
) == inFlowFrame
)) {
8962 // We're the first or last frame in the pseudo. Need to reframe.
8963 // Good enough to recreate frames for |parent|'s content
8964 *aResult
= RecreateFramesForContent(parent
->GetContent(), PR_TRUE
);
8969 // Might need to reconstruct things if this frame's nextSibling is a table
8970 // pseudo, since removal of this frame might mean that this pseudo needs to
8971 // get merged with the frame's prevSibling.
8972 // XXXbz it would be really nice if we had the prevSibling here too, to check
8973 // whether this is in fact the case...
8974 nsIFrame
* nextSibling
=
8975 FindNextNonWhitespaceSibling(inFlowFrame
->GetLastContinuation());
8976 NS_ASSERTION(!IsTablePseudo(inFlowFrame
), "Shouldn't happen here");
8977 if (nextSibling
&& IsTablePseudo(nextSibling
)) {
8979 if (gNoisyContentUpdates
) {
8980 printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8982 nsFrame::ListTag(stdout
, aFrame
);
8983 printf(" has a table pseudo next sibling of different type\n");
8986 // Good enough to recreate frames for aFrame's parent's content; even if
8987 // aFrame's parent is a table pseudo, that'll be the right content node.
8988 *aResult
= RecreateFramesForContent(parent
->GetContent(), PR_TRUE
);
8993 if (aFrame
->GetType() == nsGkAtoms::popupSetFrame
) {
8994 nsIRootBox
* rootBox
= nsIRootBox::GetRootBox(mPresShell
);
8995 if (rootBox
&& rootBox
->GetPopupSetFrame() == aFrame
) {
8996 *aResult
= ReconstructDocElementHierarchy();
9002 // We might still need to reconstruct things if the parent of inFlowFrame is
9003 // special, since in that case the removal of aFrame might affect the
9004 // splitting of its parent.
9005 if (!IsFrameSpecial(parent
)) {
9009 // If inFlowFrame is not the only in-flow child of |parent|, then removing
9010 // it will change nothing about the {ib} split.
9011 if (inFlowFrame
!= parent
->GetFirstChild(nsnull
) ||
9012 inFlowFrame
->GetLastContinuation()->GetNextSibling()) {
9016 // If the parent is the first or last part of the {ib} split, then
9017 // removing one of its kids will have no effect on the splitting.
9018 // Get the first continuation up front so we don't have to do it twice.
9019 nsIFrame
* parentFirstContinuation
= parent
->GetFirstContinuation();
9020 if (!GetSpecialSibling(parentFirstContinuation
) ||
9021 !GetSpecialPrevSibling(parentFirstContinuation
)) {
9026 if (gNoisyContentUpdates
) {
9027 printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
9029 nsFrame::ListTag(stdout
, parent
);
9030 printf(" is special\n");
9034 *aResult
= ReframeContainingBlock(parent
);
9039 nsCSSFrameConstructor::RecreateFramesForContent(nsIContent
* aContent
,
9040 PRBool aAsyncInsert
)
9042 NS_PRECONDITION(!aAsyncInsert
|| aContent
->IsElement(),
9043 "Can only insert elements async");
9044 // If there is no document, we don't want to recreate frames for it. (You
9045 // shouldn't generally be giving this method content without a document
9047 // Rebuilding the frame tree can have bad effects, especially if it's the
9048 // frame tree for chrome (see bug 157322).
9049 NS_ENSURE_TRUE(aContent
->GetDocument(), NS_ERROR_FAILURE
);
9051 // Is the frame `special'? If so, we need to reframe the containing
9052 // block *here*, rather than trying to remove and re-insert the
9053 // content (which would otherwise result in *two* nested reframe
9054 // containing block from ContentRemoved() and ContentInserted(),
9055 // below!). We'd really like to optimize away one of those
9056 // containing block reframes, hence the code here.
9058 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
9059 if (frame
&& frame
->IsFrameOfType(nsIFrame::eMathML
)) {
9060 // Reframe the topmost MathML element to prevent exponential blowup
9063 nsIContent
* parentContent
= aContent
->GetParent();
9064 nsIFrame
* parentContentFrame
= parentContent
->GetPrimaryFrame();
9065 if (!parentContentFrame
|| !parentContentFrame
->IsFrameOfType(nsIFrame::eMathML
))
9067 aContent
= parentContent
;
9068 frame
= parentContentFrame
;
9073 nsIFrame
* nonGeneratedAncestor
= nsLayoutUtils::GetNonGeneratedAncestor(frame
);
9074 if (nonGeneratedAncestor
->GetContent() != aContent
) {
9075 return RecreateFramesForContent(nonGeneratedAncestor
->GetContent(), aAsyncInsert
);
9078 nsIFrame
* parent
= frame
->GetParent();
9079 nsIContent
* parentContent
= parent
? parent
->GetContent() : nsnull
;
9080 // If the parent frame is a leaf then the subsequent insert will fail to
9081 // create a frame, so we need to recreate the parent content. This happens
9082 // with native anonymous content from the editor.
9083 if (parent
&& parent
->IsLeaf() && parentContent
&&
9084 parentContent
!= aContent
) {
9085 return RecreateFramesForContent(parentContent
, aAsyncInsert
);
9089 nsresult rv
= NS_OK
;
9091 if (frame
&& MaybeRecreateContainerForFrameRemoval(frame
, &rv
)) {
9095 nsINode
* containerNode
= aContent
->GetNodeParent();
9096 // XXXbz how can containerNode be null here?
9097 if (containerNode
) {
9098 // Before removing the frames associated with the content object,
9099 // ask them to save their state onto a temporary state object.
9100 CaptureStateForFramesOf(aContent
, mTempFrameTreeState
);
9102 // Need the nsIContent parent, which might be null here, since we need to
9103 // pass it to ContentInserted and ContentRemoved.
9104 nsCOMPtr
<nsIContent
> container
= aContent
->GetParent();
9106 // Remove the frames associated with the content object.
9107 PRBool didReconstruct
;
9108 rv
= ContentRemoved(container
, aContent
,
9109 aContent
->IsRootOfAnonymousSubtree() ?
9111 aContent
->GetNextSibling(),
9112 REMOVE_FOR_RECONSTRUCTION
, &didReconstruct
);
9114 if (NS_SUCCEEDED(rv
) && !didReconstruct
) {
9115 // Now, recreate the frames associated with this content object. If
9116 // ContentRemoved triggered reconstruction, then we don't need to do this
9117 // because the frames will already have been built.
9119 PostRestyleEvent(aContent
->AsElement(), nsRestyleHint(0),
9120 nsChangeHint_ReconstructFrame
);
9122 rv
= ContentInserted(container
, aContent
, mTempFrameTreeState
, PR_FALSE
);
9130 //////////////////////////////////////////////////////////////////////
9132 // Block frame construction code
9134 already_AddRefed
<nsStyleContext
>
9135 nsCSSFrameConstructor::GetFirstLetterStyle(nsIContent
* aContent
,
9136 nsStyleContext
* aStyleContext
)
9139 return mPresShell
->StyleSet()->
9140 ResolvePseudoElementStyle(aContent
->AsElement(),
9141 nsCSSPseudoElements::ePseudo_firstLetter
,
9147 already_AddRefed
<nsStyleContext
>
9148 nsCSSFrameConstructor::GetFirstLineStyle(nsIContent
* aContent
,
9149 nsStyleContext
* aStyleContext
)
9152 return mPresShell
->StyleSet()->
9153 ResolvePseudoElementStyle(aContent
->AsElement(),
9154 nsCSSPseudoElements::ePseudo_firstLine
,
9160 // Predicate to see if a given content (block element) has
9161 // first-letter style applied to it.
9163 nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(nsIContent
* aContent
,
9164 nsStyleContext
* aStyleContext
)
9166 return nsLayoutUtils::HasPseudoStyle(aContent
, aStyleContext
,
9167 nsCSSPseudoElements::ePseudo_firstLetter
,
9168 mPresShell
->GetPresContext());
9172 nsCSSFrameConstructor::HasFirstLetterStyle(nsIFrame
* aBlockFrame
)
9174 NS_PRECONDITION(aBlockFrame
, "Need a frame");
9175 NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame
),
9176 "Not a block frame?");
9178 return (aBlockFrame
->GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE
) != 0;
9182 nsCSSFrameConstructor::ShouldHaveFirstLineStyle(nsIContent
* aContent
,
9183 nsStyleContext
* aStyleContext
)
9185 PRBool hasFirstLine
=
9186 nsLayoutUtils::HasPseudoStyle(aContent
, aStyleContext
,
9187 nsCSSPseudoElements::ePseudo_firstLine
,
9188 mPresShell
->GetPresContext());
9190 // But disable for fieldsets
9191 PRInt32 namespaceID
;
9192 nsIAtom
* tag
= mDocument
->BindingManager()->ResolveTag(aContent
,
9194 // This check must match the one in FindHTMLData.
9195 hasFirstLine
= tag
!= nsGkAtoms::fieldset
||
9196 namespaceID
!= kNameSpaceID_XHTML
;
9199 return hasFirstLine
;
9203 nsCSSFrameConstructor::ShouldHaveSpecialBlockStyle(nsIContent
* aContent
,
9204 nsStyleContext
* aStyleContext
,
9205 PRBool
* aHaveFirstLetterStyle
,
9206 PRBool
* aHaveFirstLineStyle
)
9208 *aHaveFirstLetterStyle
=
9209 ShouldHaveFirstLetterStyle(aContent
, aStyleContext
);
9210 *aHaveFirstLineStyle
=
9211 ShouldHaveFirstLineStyle(aContent
, aStyleContext
);
9215 const nsCSSFrameConstructor::PseudoParentData
9216 nsCSSFrameConstructor::sPseudoParentData
[eParentTypeCount
] = {
9218 FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART
| FCDATA_SKIP_FRAMESET
|
9219 FCDATA_USE_CHILD_ITEMS
|
9220 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow
),
9221 &nsCSSFrameConstructor::ConstructTableCell
),
9222 &nsCSSAnonBoxes::tableCell
9225 FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART
| FCDATA_SKIP_FRAMESET
|
9226 FCDATA_USE_CHILD_ITEMS
|
9227 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup
),
9228 &nsCSSFrameConstructor::ConstructTableRow
),
9229 &nsCSSAnonBoxes::tableRow
9232 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_SKIP_FRAMESET
|
9233 FCDATA_DISALLOW_OUT_OF_FLOW
| FCDATA_USE_CHILD_ITEMS
|
9234 FCDATA_SKIP_ABSPOS_PUSH
|
9235 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
9236 NS_NewTableRowGroupFrame
),
9237 &nsCSSAnonBoxes::tableRowGroup
9240 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_SKIP_FRAMESET
|
9241 FCDATA_DISALLOW_OUT_OF_FLOW
| FCDATA_USE_CHILD_ITEMS
|
9242 FCDATA_SKIP_ABSPOS_PUSH
|
9243 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
9244 NS_NewTableColGroupFrame
),
9245 &nsCSSAnonBoxes::tableColGroup
9248 FULL_CTOR_FCDATA(FCDATA_SKIP_FRAMESET
| FCDATA_USE_CHILD_ITEMS
,
9249 &nsCSSFrameConstructor::ConstructTable
),
9250 &nsCSSAnonBoxes::table
9255 * This function works as follows: we walk through the child list (aItems) and
9256 * find items that cannot have aParentFrame as their parent. We wrap
9257 * continuous runs of such items into a FrameConstructionItem for a frame that
9258 * gets them closer to their desired parents. For example, a run of non-row
9259 * children of a row-group will get wrapped in a row. When we later construct
9260 * the frame for this wrapper (in this case for the row), it'll be the correct
9261 * parent for the cells in the set of items we wrapped or we'll wrap cells
9262 * around everything else. At the end of this method, aItems is guaranteed to
9263 * contain only items for frames that can be direct kids of aParentFrame.
9266 nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState
& aState
,
9267 FrameConstructionItemList
& aItems
,
9268 nsIFrame
* aParentFrame
)
9270 ParentType ourParentType
= GetParentType(aParentFrame
);
9271 if (aItems
.AllWantParentType(ourParentType
)) {
9272 // Nothing to do here
9276 FCItemIterator
iter(aItems
);
9278 if (iter
.SkipItemsWantingParentType(ourParentType
)) {
9279 // Nothing else to do here; we're finished
9283 // Now we're pointing to the first child that wants a different parent
9286 // Now try to figure out what kids we can group together. We can generally
9287 // group everything that has a different desired parent type from us. Two
9288 // exceptions to this:
9289 // 1) If our parent type is table, we can't group columns with anything
9290 // else other than whitespace.
9291 // 2) Whitespace that lies between two things we can group which both want
9292 // a non-block parent should be dropped, even if we can't group them
9293 // with each other and even if the whitespace wants a parent of
9294 // ourParentType. Ends of the list count as things that don't want a
9295 // block parent (so that for example we'll drop a whitespace-only list).
9297 FCItemIterator
endIter(iter
); /* iterator to find the end of the group */
9298 ParentType groupingParentType
= endIter
.item().DesiredParentType();
9299 if (aItems
.AllWantParentType(groupingParentType
) &&
9300 groupingParentType
!= eTypeBlock
) {
9301 // Just group them all and be done with it. We need the check for
9302 // eTypeBlock here to catch the "all the items are whitespace" case
9306 // Locate the end of the group.
9308 // Keep track of the type the previous item wanted, in case we have to
9309 // deal with whitespace. Start it off with ourParentType, since that's
9310 // the last thing |iter| would have skipped over.
9311 ParentType prevParentType
= ourParentType
;
9313 /* Walk an iterator past any whitespace that we might be able to drop from the list */
9314 FCItemIterator
spaceEndIter(endIter
);
9315 if (prevParentType
!= eTypeBlock
&&
9316 !aParentFrame
->IsGeneratedContentFrame() &&
9317 spaceEndIter
.item().IsWhitespace(aState
)) {
9318 PRBool trailingSpaces
= spaceEndIter
.SkipWhitespace(aState
);
9320 // See whether we can drop the whitespace
9321 if (trailingSpaces
||
9322 spaceEndIter
.item().DesiredParentType() != eTypeBlock
) {
9323 PRBool updateStart
= (iter
== endIter
);
9324 endIter
.DeleteItemsTo(spaceEndIter
);
9325 NS_ASSERTION(trailingSpaces
== endIter
.IsDone(), "These should match");
9331 if (trailingSpaces
) {
9332 break; /* Found group end */
9336 // Update groupingParentType, since it might have been eTypeBlock
9337 // just because of the whitespace.
9338 groupingParentType
= iter
.item().DesiredParentType();
9343 // Now endIter points to a non-whitespace item or a non-droppable
9344 // whitespace item. In the latter case, if this is the end of the group
9345 // we'll traverse this whitespace again. But it'll all just be quick
9346 // DesiredParentType() checks which will match ourParentType (that's
9347 // what it means that this is the group end), so it's OK.
9348 prevParentType
= endIter
.item().DesiredParentType();
9349 if (prevParentType
== ourParentType
) {
9350 // End the group at endIter.
9354 if (ourParentType
== eTypeTable
&&
9355 (prevParentType
== eTypeColGroup
) !=
9356 (groupingParentType
== eTypeColGroup
)) {
9357 // Either we started with columns and now found something else, or vice
9358 // versa. In any case, end the grouping.
9362 // Include the whitespace we didn't drop (if any) in the group, since
9363 // this is not the end of the group. Note that this doesn't change
9364 // prevParentType, since if we didn't drop the whitespace then we ended
9365 // at something that wants a block parent.
9366 endIter
= spaceEndIter
;
9369 } while (!endIter
.IsDone());
9372 if (iter
== endIter
) {
9373 // Nothing to wrap here; just skipped some whitespace
9377 // Now group together all the items between iter and endIter. The right
9378 // parent type to use depends on ourParentType.
9379 ParentType wrapperType
;
9380 switch (ourParentType
) {
9382 wrapperType
= eTypeTable
;
9385 // The parent type for a cell is eTypeBlock, since that's what a cell
9386 // looks like to its kids.
9387 wrapperType
= eTypeBlock
;
9390 wrapperType
= eTypeRow
;
9393 // Either colgroup or rowgroup, depending on what we're grouping.
9394 wrapperType
= groupingParentType
== eTypeColGroup
?
9395 eTypeColGroup
: eTypeRowGroup
;
9398 NS_NOTREACHED("Colgroups should be suppresing non-col child items");
9402 const PseudoParentData
& pseudoData
= sPseudoParentData
[wrapperType
];
9403 nsIAtom
* pseudoType
= *pseudoData
.mPseudoType
;
9404 nsStyleContext
* parentStyle
= aParentFrame
->GetStyleContext();
9405 nsIContent
* parentContent
= aParentFrame
->GetContent();
9407 if (pseudoType
== nsCSSAnonBoxes::table
&&
9408 parentStyle
->GetStyleDisplay()->mDisplay
== NS_STYLE_DISPLAY_INLINE
) {
9409 pseudoType
= nsCSSAnonBoxes::inlineTable
;
9412 nsRefPtr
<nsStyleContext
> wrapperStyle
=
9413 mPresShell
->StyleSet()->ResolveAnonymousBoxStyle(pseudoType
, parentStyle
);
9414 FrameConstructionItem
* newItem
=
9415 new FrameConstructionItem(&pseudoData
.mFCData
,
9416 // Use the content of our parent frame
9418 // Lie about the tag; it doesn't matter anyway
9420 // The namespace does matter, however; it needs
9421 // to match that of our first child item to
9422 // match the old behavior
9423 iter
.item().mNameSpaceID
,
9424 // no pending binding
9426 wrapperStyle
.forget(),
9430 return NS_ERROR_OUT_OF_MEMORY
;
9433 // Here we're cheating a tad... technically, table-internal items should be
9434 // inline if aParentFrame is inline, but they'll get wrapped in an
9435 // inline-table in the end, so it'll all work out. In any case, arguably
9436 // we don't need to maintain this state at this point... but it's better
9438 newItem
->mIsAllInline
= newItem
->mHasInlineEnds
=
9439 newItem
->mStyleContext
->GetStyleDisplay()->IsInlineOutside();
9441 // Table pseudo frames always induce line boundaries around their
9443 newItem
->mChildItems
.SetLineBoundaryAtStart(PR_TRUE
);
9444 newItem
->mChildItems
.SetLineBoundaryAtEnd(PR_TRUE
);
9445 // The parent of the items in aItems is also the parent of the items
9447 newItem
->mChildItems
.SetParentHasNoXBLChildren(
9448 aItems
.ParentHasNoXBLChildren());
9450 // Eat up all items between |iter| and |endIter| and put them in our wrapper
9451 // Advances |iter| to point to |endIter|.
9452 iter
.AppendItemsToList(endIter
, newItem
->mChildItems
);
9454 iter
.InsertItem(newItem
);
9456 // Now |iter| points to the item that was the first one we didn't wrap;
9457 // loop and see whether we need to skip it or wrap it in something
9459 } while (!iter
.IsDone());
9465 nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState
& aState
,
9466 FrameConstructionItemList
& aItems
,
9467 nsIFrame
* aParentFrame
,
9468 nsFrameItems
& aFrameItems
)
9470 nsresult rv
= CreateNeededTablePseudos(aState
, aItems
, aParentFrame
);
9471 NS_ENSURE_SUCCESS(rv
, rv
);
9474 for (FCItemIterator
iter(aItems
); !iter
.IsDone(); iter
.Next()) {
9475 NS_ASSERTION(iter
.item().DesiredParentType() == GetParentType(aParentFrame
),
9476 "Needed pseudos didn't get created; expect bad things");
9480 for (FCItemIterator
iter(aItems
); !iter
.IsDone(); iter
.Next()) {
9481 rv
= ConstructFramesFromItem(aState
, iter
, aParentFrame
, aFrameItems
);
9482 NS_ENSURE_SUCCESS(rv
, rv
);
9485 NS_ASSERTION(!aState
.mHavePendingPopupgroup
,
9486 "Should have proccessed it by now");
9492 nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState
& aState
,
9493 nsIContent
* aContent
,
9494 nsStyleContext
* aStyleContext
,
9496 const PRBool aCanHaveGeneratedContent
,
9497 nsFrameItems
& aFrameItems
,
9498 const PRBool aAllowBlockStyles
,
9499 PendingBinding
* aPendingBinding
)
9501 NS_PRECONDITION(aFrame
, "Must have parent frame here");
9502 NS_PRECONDITION(aFrame
->GetContentInsertionFrame() == aFrame
,
9503 "Parent frame in ProcessChildren should be its own "
9504 "content insertion frame");
9506 // XXXbz ideally, this would do all the pushing of various
9507 // containing blocks as needed, so callers don't have to do it...
9509 PRBool haveFirstLetterStyle
= PR_FALSE
, haveFirstLineStyle
= PR_FALSE
;
9510 if (aAllowBlockStyles
) {
9511 ShouldHaveSpecialBlockStyle(aContent
, aStyleContext
, &haveFirstLetterStyle
,
9512 &haveFirstLineStyle
);
9515 // The logic here needs to match the logic in GetFloatContainingBlock()
9516 nsFrameConstructorSaveState floatSaveState
;
9517 if (aFrame
->IsFrameOfType(nsIFrame::eMathML
) ||
9518 aFrame
->IsBoxFrame()) {
9519 aState
.PushFloatContainingBlock(nsnull
, floatSaveState
);
9520 } else if (aFrame
->IsFloatContainingBlock()) {
9521 aState
.PushFloatContainingBlock(aFrame
, floatSaveState
);
9524 nsFrameConstructorState::PendingBindingAutoPusher
pusher(aState
,
9527 FrameConstructionItemList itemsToConstruct
;
9528 nsresult rv
= NS_OK
;
9530 // If we have first-letter or first-line style then frames can get
9531 // moved around so don't set these flags.
9532 if (aAllowBlockStyles
&& !haveFirstLetterStyle
&& !haveFirstLineStyle
) {
9533 itemsToConstruct
.SetLineBoundaryAtStart(PR_TRUE
);
9534 itemsToConstruct
.SetLineBoundaryAtEnd(PR_TRUE
);
9537 // Create any anonymous frames we need here. This must happen before the
9538 // non-anonymous children are processed to ensure that popups are never
9539 // constructed before the popupset.
9540 nsAutoTArray
<nsIContent
*, 4> anonymousItems
;
9541 GetAnonymousContent(aContent
, aFrame
, anonymousItems
);
9542 for (PRUint32 i
= 0; i
< anonymousItems
.Length(); ++i
) {
9544 nsIAnonymousContentCreator
* creator
= do_QueryFrame(aFrame
);
9545 NS_ASSERTION(!creator
|| !creator
->CreateFrameFor(anonymousItems
[i
]),
9546 "If you need to use CreateFrameFor, you need to call "
9547 "CreateAnonymousFrames manually and not follow the standard "
9548 "ProcessChildren() codepath for this frame");
9550 AddFrameConstructionItems(aState
, anonymousItems
[i
], PR_TRUE
, aFrame
,
9554 if (!aFrame
->IsLeaf()) {
9555 // :before/:after content should have the same style context parent
9557 // Note that we don't use this style context for looking up things like
9558 // special block styles because in some cases involving table pseudo-frames
9559 // it has nothing to do with the parent frame's desired behavior.
9560 nsStyleContext
* styleContext
;
9562 if (aCanHaveGeneratedContent
) {
9564 nsFrame::CorrectStyleParentFrame(aFrame
, nsnull
)->GetStyleContext();
9565 // Probe for generated content before
9566 CreateGeneratedContentItem(aState
, aFrame
, aContent
, styleContext
,
9567 nsCSSPseudoElements::ePseudo_before
,
9571 ChildIterator iter
, last
;
9572 for (ChildIterator::Init(aContent
, &iter
, &last
);
9575 nsIContent
* child
= *iter
;
9576 // Frame construction item construction should not post
9577 // restyles, so removing restyle flags here is safe.
9578 if (child
->IsElement()) {
9579 child
->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS
);
9581 AddFrameConstructionItems(aState
, child
, iter
.XBLInvolved(), aFrame
,
9584 itemsToConstruct
.SetParentHasNoXBLChildren(!iter
.XBLInvolved());
9586 if (aCanHaveGeneratedContent
) {
9587 // Probe for generated content after
9588 CreateGeneratedContentItem(aState
, aFrame
, aContent
, styleContext
,
9589 nsCSSPseudoElements::ePseudo_after
,
9593 ClearLazyBits(aContent
->GetFirstChild(), nsnull
);
9596 rv
= ConstructFramesFromItemList(aState
, itemsToConstruct
, aFrame
,
9598 NS_ENSURE_SUCCESS(rv
, rv
);
9600 NS_ASSERTION(!aAllowBlockStyles
|| !aFrame
->IsBoxFrame(),
9601 "can't be both block and box");
9603 if (haveFirstLetterStyle
) {
9604 rv
= WrapFramesInFirstLetterFrame(aContent
, aFrame
, aFrameItems
);
9606 if (haveFirstLineStyle
) {
9607 rv
= WrapFramesInFirstLineFrame(aState
, aContent
, aFrame
, nsnull
,
9611 // We might end up with first-line frames that change
9612 // AnyKidsNeedBlockParent() without changing itemsToConstruct, but that
9613 // should never happen for cases whan aFrame->IsBoxFrame().
9614 NS_ASSERTION(!haveFirstLineStyle
|| !aFrame
->IsBoxFrame(),
9615 "Shouldn't have first-line style if we're a box");
9616 NS_ASSERTION(!aFrame
->IsBoxFrame() ||
9617 itemsToConstruct
.AnyItemsNeedBlockParent() ==
9618 (AnyKidsNeedBlockParent(aFrameItems
.FirstChild()) != nsnull
),
9619 "Something went awry in our block parent calculations");
9621 if (aFrame
->IsBoxFrame() && itemsToConstruct
.AnyItemsNeedBlockParent()) {
9622 // XXXbz we could do this on the FrameConstructionItemList level,
9623 // no? And if we cared we could look through the item list
9624 // instead of groveling through the framelist here..
9625 nsIContent
*badKid
= AnyKidsNeedBlockParent(aFrameItems
.FirstChild());
9626 nsDependentAtomString
parentTag(aContent
->Tag()), kidTag(badKid
->Tag());
9627 const PRUnichar
* params
[] = { parentTag
.get(), kidTag
.get() };
9628 nsStyleContext
*frameStyleContext
= aFrame
->GetStyleContext();
9629 const nsStyleDisplay
*display
= frameStyleContext
->GetStyleDisplay();
9630 const char *message
=
9631 (display
->mDisplay
== NS_STYLE_DISPLAY_INLINE_BOX
)
9632 ? "NeededToWrapXULInlineBox" : "NeededToWrapXUL";
9633 nsContentUtils::ReportToConsole(nsContentUtils::eXUL_PROPERTIES
,
9635 params
, NS_ARRAY_LENGTH(params
),
9636 mDocument
->GetDocumentURI(),
9637 EmptyString(), 0, 0, // not useful
9638 nsIScriptError::warningFlag
,
9639 "FrameConstructor");
9641 nsRefPtr
<nsStyleContext
> blockSC
= mPresShell
->StyleSet()->
9642 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozXULAnonymousBlock
,
9644 nsIFrame
*blockFrame
= NS_NewBlockFrame(mPresShell
, blockSC
);
9645 // We might, in theory, want to set NS_BLOCK_FLOAT_MGR and
9646 // NS_BLOCK_MARGIN_ROOT, but I think it's a bad idea given that
9647 // a real block placed here wouldn't get those set on it.
9649 InitAndRestoreFrame(aState
, aContent
, aFrame
, nsnull
,
9650 blockFrame
, PR_FALSE
);
9652 NS_ASSERTION(!blockFrame
->HasView(), "need to do view reparenting");
9653 ReparentFrames(aState
.mFrameManager
, blockFrame
, aFrameItems
);
9655 blockFrame
->SetInitialChildList(nsnull
, aFrameItems
);
9656 NS_ASSERTION(aFrameItems
.IsEmpty(), "How did that happen?");
9657 aFrameItems
.Clear();
9658 aFrameItems
.AddChild(blockFrame
);
9660 aFrame
->AddStateBits(NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK
);
9666 //----------------------------------------------------------------------
9668 // Support for :first-line style
9670 // Special routine to handle placing a list of frames into a block
9671 // frame that has first-line style. The routine ensures that the first
9672 // collection of inline frames end up in a first-line frame.
9673 // NOTE: aState may have containing block information related to a
9674 // different part of the frame tree than where the first line occurs.
9675 // In particular aState may be set up for where ContentInserted or
9676 // ContentAppended is inserting content, which may be some
9677 // non-first-in-flow continuation of the block to which the first-line
9678 // belongs. So this function needs to be careful about how it uses
9681 nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
9682 nsFrameConstructorState
& aState
,
9683 nsIContent
* aBlockContent
,
9684 nsIFrame
* aBlockFrame
,
9685 nsIFrame
* aLineFrame
,
9686 nsFrameItems
& aFrameItems
)
9688 nsresult rv
= NS_OK
;
9690 // Find the part of aFrameItems that we want to put in the first-line
9691 nsFrameList::FrameLinkEnumerator
link(aFrameItems
);
9692 while (!link
.AtEnd() && IsInlineOutside(link
.NextFrame())) {
9696 nsFrameList firstLineChildren
= aFrameItems
.ExtractHead(link
);
9698 if (firstLineChildren
.IsEmpty()) {
9699 // Nothing is supposed to go into the first-line; nothing to do
9704 // Create line frame
9705 nsStyleContext
* parentStyle
=
9706 nsFrame::CorrectStyleParentFrame(aBlockFrame
,
9707 nsCSSPseudoElements::firstLine
)->
9709 nsRefPtr
<nsStyleContext
> firstLineStyle
= GetFirstLineStyle(aBlockContent
,
9712 aLineFrame
= NS_NewFirstLineFrame(mPresShell
, firstLineStyle
);
9715 // Initialize the line frame
9716 rv
= InitAndRestoreFrame(aState
, aBlockContent
, aBlockFrame
, nsnull
,
9719 // The lineFrame will be the block's first child; the rest of the
9720 // frame list (after lastInlineFrame) will be the second and
9721 // subsequent children; insert lineFrame into aFrameItems.
9722 aFrameItems
.InsertFrame(nsnull
, nsnull
, aLineFrame
);
9724 NS_ASSERTION(aLineFrame
->GetStyleContext() == firstLineStyle
,
9725 "Bogus style context on line frame");
9730 // Give the inline frames to the lineFrame <b>after</b> reparenting them
9731 ReparentFrames(aState
.mFrameManager
, aLineFrame
, firstLineChildren
);
9732 if (aLineFrame
->GetChildList(nsnull
).IsEmpty() &&
9733 (aLineFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
)) {
9734 aLineFrame
->SetInitialChildList(nsnull
, firstLineChildren
);
9736 aState
.mFrameManager
->AppendFrames(aLineFrame
, nsnull
, firstLineChildren
);
9740 rv
= NS_ERROR_OUT_OF_MEMORY
;
9746 // Special routine to handle appending a new frame to a block frame's
9747 // child list. Takes care of placing the new frame into the right
9748 // place when first-line style is present.
9750 nsCSSFrameConstructor::AppendFirstLineFrames(
9751 nsFrameConstructorState
& aState
,
9752 nsIContent
* aBlockContent
,
9753 nsIFrame
* aBlockFrame
,
9754 nsFrameItems
& aFrameItems
)
9756 // It's possible that aBlockFrame needs to have a first-line frame
9757 // created because it doesn't currently have any children.
9758 const nsFrameList
& blockKids
= aBlockFrame
->GetChildList(nsnull
);
9759 if (blockKids
.IsEmpty()) {
9760 return WrapFramesInFirstLineFrame(aState
, aBlockContent
,
9761 aBlockFrame
, nsnull
, aFrameItems
);
9764 // Examine the last block child - if it's a first-line frame then
9765 // appended frames need special treatment.
9766 nsIFrame
* lastBlockKid
= blockKids
.LastChild();
9767 if (lastBlockKid
->GetType() != nsGkAtoms::lineFrame
) {
9768 // No first-line frame at the end of the list, therefore there is
9769 // an intervening block between any first-line frame the frames
9770 // we are appending. Therefore, we don't need any special
9771 // treatment of the appended frames.
9775 return WrapFramesInFirstLineFrame(aState
, aBlockContent
, aBlockFrame
,
9776 lastBlockKid
, aFrameItems
);
9779 // Special routine to handle inserting a new frame into a block
9780 // frame's child list. Takes care of placing the new frame into the
9781 // right place when first-line style is present.
9783 nsCSSFrameConstructor::InsertFirstLineFrames(
9784 nsFrameConstructorState
& aState
,
9785 nsIContent
* aContent
,
9786 nsIFrame
* aBlockFrame
,
9787 nsIFrame
** aParentFrame
,
9788 nsIFrame
* aPrevSibling
,
9789 nsFrameItems
& aFrameItems
)
9791 nsresult rv
= NS_OK
;
9792 // XXXbz If you make this method actually do something, check to
9793 // make sure that the caller is passing what you expect. In
9794 // particular, which content is aContent? And audit the rest of
9795 // this code too; it makes bogus assumptions and may not build.
9797 nsIFrame
* parentFrame
= *aParentFrame
;
9798 nsIFrame
* newFrame
= aFrameItems
.childList
;
9799 PRBool isInline
= IsInlineOutside(newFrame
);
9801 if (!aPrevSibling
) {
9802 // Insertion will become the first frame. Two cases: we either
9803 // already have a first-line frame or we don't.
9804 nsIFrame
* firstBlockKid
= aBlockFrame
->GetFirstChild(nsnull
);
9805 if (firstBlockKid
->GetType() == nsGkAtoms::lineFrame
) {
9806 // We already have a first-line frame
9807 nsIFrame
* lineFrame
= firstBlockKid
;
9810 // Easy case: the new inline frame will go into the lineFrame.
9811 ReparentFrame(aState
.mFrameManager
, lineFrame
, newFrame
);
9812 aState
.mFrameManager
->InsertFrames(lineFrame
, nsnull
, nsnull
,
9815 // Since the frame is going into the lineFrame, don't let it
9816 // go into the block too.
9817 aFrameItems
.childList
= nsnull
;
9818 aFrameItems
.lastChild
= nsnull
;
9821 // Harder case: We are about to insert a block level element
9822 // before the first-line frame.
9823 // XXX need a method to steal away frames from the line-frame
9827 // We do not have a first-line frame
9829 // We now need a first-line frame to contain the inline frame.
9830 nsIFrame
* lineFrame
= NS_NewFirstLineFrame(firstLineStyle
);
9832 rv
= NS_ERROR_OUT_OF_MEMORY
;
9835 if (NS_SUCCEEDED(rv
)) {
9836 // Lookup first-line style context
9837 nsStyleContext
* parentStyle
=
9838 nsFrame::CorrectStyleParentFrame(aBlockFrame
,
9839 nsCSSPseudoElements::firstLine
)->
9841 nsRefPtr
<nsStyleContext
> firstLineStyle
=
9842 GetFirstLineStyle(aContent
, parentStyle
);
9844 // Initialize the line frame
9845 rv
= InitAndRestoreFrame(aState
, aContent
, aBlockFrame
,
9848 // Make sure the caller inserts the lineFrame into the
9849 // blocks list of children.
9850 aFrameItems
.childList
= lineFrame
;
9851 aFrameItems
.lastChild
= lineFrame
;
9853 // Give the inline frames to the lineFrame <b>after</b>
9855 NS_ASSERTION(lineFrame
->GetStyleContext() == firstLineStyle
,
9856 "Bogus style context on line frame");
9857 ReparentFrame(aPresContext
, lineFrame
, newFrame
);
9858 lineFrame
->SetInitialChildList(nsnull
, newFrame
);
9862 // Easy case: the regular insertion logic can insert the new
9863 // frame because it's a block frame.
9868 // Insertion will not be the first frame.
9869 nsIFrame
* prevSiblingParent
= aPrevSibling
->GetParent();
9870 if (prevSiblingParent
== aBlockFrame
) {
9871 // Easy case: The prev-siblings parent is the block
9872 // frame. Therefore the prev-sibling is not currently in a
9873 // line-frame. Therefore the new frame which is going after it,
9874 // regardless of type, is not going into a line-frame.
9877 // If the prevSiblingParent is not the block-frame then it must
9878 // be a line-frame (if it were a letter-frame, that logic would
9879 // already have adjusted the prev-sibling to be the
9882 // Easy case: the insertion can go where the caller thinks it
9883 // should go (which is into prevSiblingParent).
9886 // Block elements don't end up in line-frames, therefore
9887 // change the insertion point to aBlockFrame. However, there
9888 // might be more inline elements following aPrevSibling that
9889 // need to be pulled out of the line-frame and become children
9891 nsIFrame
* nextSibling
= aPrevSibling
->GetNextSibling();
9892 nsIFrame
* nextLineFrame
= prevSiblingParent
->GetNextInFlow();
9893 if (nextSibling
|| nextLineFrame
) {
9894 // Oy. We have work to do. Create a list of the new frames
9895 // that are going into the block by stripping them away from
9896 // the line-frame(s).
9898 nsLineFrame
* lineFrame
= (nsLineFrame
*) prevSiblingParent
;
9899 nsFrameList tail
= lineFrame
->StealFramesAfter(aPrevSibling
);
9900 // XXX do something with 'tail'
9903 nsLineFrame
* nextLineFrame
= (nsLineFrame
*) lineFrame
;
9905 nextLineFrame
= nextLineFrame
->GetNextInFlow();
9906 if (!nextLineFrame
) {
9909 nsIFrame
* kids
= nextLineFrame
->GetFirstChild(nsnull
);
9913 // We got lucky: aPrevSibling was the last inline frame in
9915 ReparentFrame(aState
.mFrameManager
, aBlockFrame
, newFrame
);
9916 aState
.mFrameManager
->InsertFrames(aBlockFrame
, nsnull
,
9917 prevSiblingParent
, newFrame
);
9918 aFrameItems
.childList
= nsnull
;
9919 aFrameItems
.lastChild
= nsnull
;
9929 //----------------------------------------------------------------------
9931 // First-letter support
9933 // Determine how many characters in the text fragment apply to the
9936 FirstLetterCount(const nsTextFragment
* aFragment
)
9939 PRInt32 firstLetterLength
= 0;
9940 PRBool done
= PR_FALSE
;
9942 PRInt32 i
, n
= aFragment
->GetLength();
9943 for (i
= 0; i
< n
; i
++) {
9944 PRUnichar ch
= aFragment
->CharAt(i
);
9945 if (XP_IS_SPACE(ch
)) {
9946 if (firstLetterLength
) {
9954 if ((ch
== '\'') || (ch
== '\"')) {
9955 if (firstLetterLength
) {
9960 firstLetterLength
= 1;
9973 NeedFirstLetterContinuation(nsIContent
* aContent
)
9975 NS_PRECONDITION(aContent
, "null ptr");
9977 PRBool result
= PR_FALSE
;
9979 const nsTextFragment
* frag
= aContent
->GetText();
9981 PRInt32 flc
= FirstLetterCount(frag
);
9982 PRInt32 tl
= frag
->GetLength();
9991 static PRBool
IsFirstLetterContent(nsIContent
* aContent
)
9993 return aContent
->TextLength() &&
9994 !aContent
->TextIsOnlyWhitespace();
9998 * Create a letter frame, only make it a floating frame.
10001 nsCSSFrameConstructor::CreateFloatingLetterFrame(
10002 nsFrameConstructorState
& aState
,
10003 nsIFrame
* aBlockFrame
,
10004 nsIContent
* aTextContent
,
10005 nsIFrame
* aTextFrame
,
10006 nsIContent
* aBlockContent
,
10007 nsIFrame
* aParentFrame
,
10008 nsStyleContext
* aStyleContext
,
10009 nsFrameItems
& aResult
)
10011 // Create the first-letter-frame
10013 nsIFrame
* letterFrame
;
10014 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
10016 letterFrame
= NS_NewFirstLetterFrame(mPresShell
, aStyleContext
);
10017 // We don't want to use a text content for a non-text frame (because we want
10018 // its primary frame to be a text frame). So use its parent for the
10020 nsIContent
* letterContent
= aTextContent
->GetParent();
10021 nsIFrame
* containingBlock
= aState
.GetGeometricParent(
10022 aStyleContext
->GetStyleDisplay(), aParentFrame
);
10023 InitAndRestoreFrame(aState
, letterContent
, containingBlock
, nsnull
,
10026 // Init the text frame to refer to the letter frame. Make sure we
10027 // get a proper style context for it (the one passed in is for the
10028 // letter frame and will have the float property set on it; the text
10029 // frame shouldn't have that set).
10030 nsRefPtr
<nsStyleContext
> textSC
;
10031 textSC
= styleSet
->ResolveStyleForNonElement(aStyleContext
);
10032 aTextFrame
->SetStyleContextWithoutNotification(textSC
);
10033 InitAndRestoreFrame(aState
, aTextContent
, letterFrame
, nsnull
, aTextFrame
);
10035 // And then give the text frame to the letter frame
10036 SetInitialSingleChild(letterFrame
, aTextFrame
);
10038 // See if we will need to continue the text frame (does it contain
10039 // more than just the first-letter text or not?) If it does, then we
10040 // create (in advance) a continuation frame for it.
10041 nsIFrame
* nextTextFrame
= nsnull
;
10042 if (NeedFirstLetterContinuation(aTextContent
)) {
10043 // Create continuation
10044 rv
= CreateContinuingFrame(aState
.mPresContext
, aTextFrame
, aParentFrame
,
10046 if (NS_FAILED(rv
)) {
10047 letterFrame
->Destroy();
10050 // Repair the continuations style context
10051 nsStyleContext
* parentStyleContext
= aStyleContext
->GetParent();
10052 if (parentStyleContext
) {
10053 nsRefPtr
<nsStyleContext
> newSC
;
10054 newSC
= styleSet
->ResolveStyleForNonElement(parentStyleContext
);
10056 nextTextFrame
->SetStyleContext(newSC
);
10061 NS_ASSERTION(aResult
.IsEmpty(), "aResult should be an empty nsFrameItems!");
10062 // Put the new float before any of the floats in the block we're doing
10063 // first-letter for, that is, before any floats whose parent is
10064 // containingBlock.
10065 nsFrameList::FrameLinkEnumerator
link(aState
.mFloatedItems
);
10066 while (!link
.AtEnd() && link
.NextFrame()->GetParent() != containingBlock
) {
10070 rv
= aState
.AddChild(letterFrame
, aResult
, letterContent
, aStyleContext
,
10071 aParentFrame
, PR_FALSE
, PR_TRUE
, PR_FALSE
, PR_TRUE
,
10074 if (nextTextFrame
) {
10075 if (NS_FAILED(rv
)) {
10076 nextTextFrame
->Destroy();
10078 aResult
.AddChild(nextTextFrame
);
10084 * Create a new letter frame for aTextFrame. The letter frame will be
10085 * a child of aParentFrame.
10088 nsCSSFrameConstructor::CreateLetterFrame(nsIFrame
* aBlockFrame
,
10089 nsIFrame
* aBlockContinuation
,
10090 nsIContent
* aTextContent
,
10091 nsIFrame
* aParentFrame
,
10092 nsFrameItems
& aResult
)
10094 NS_PRECONDITION(aTextContent
->IsNodeOfType(nsINode::eTEXT
),
10095 "aTextContent isn't text");
10096 NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame
),
10097 "Not a block frame?");
10099 // Get style context for the first-letter-frame
10100 nsStyleContext
* parentStyleContext
=
10101 nsFrame::CorrectStyleParentFrame(aParentFrame
,
10102 nsCSSPseudoElements::firstLetter
)->
10105 // Use content from containing block so that we can actually
10106 // find a matching style rule.
10107 nsIContent
* blockContent
= aBlockFrame
->GetContent();
10109 // Create first-letter style rule
10110 nsRefPtr
<nsStyleContext
> sc
= GetFirstLetterStyle(blockContent
,
10111 parentStyleContext
);
10113 nsRefPtr
<nsStyleContext
> textSC
;
10114 textSC
= mPresShell
->StyleSet()->ResolveStyleForNonElement(sc
);
10116 // Create a new text frame (the original one will be discarded)
10117 // pass a temporary stylecontext, the correct one will be set
10118 // later. Start off by unsetting the primary frame for
10119 // aTextContent, so it's no longer pointing to the to-be-destroyed
10121 // XXXbz it would be really nice to destroy the old frame _first_,
10122 // then create the new one, so we could avoid this hack.
10123 aTextContent
->SetPrimaryFrame(nsnull
);
10124 nsIFrame
* textFrame
= NS_NewTextFrame(mPresShell
, textSC
);
10126 NS_ASSERTION(aBlockContinuation
== GetFloatContainingBlock(aParentFrame
),
10127 "Containing block is confused");
10128 nsFrameConstructorState
state(mPresShell
, mFixedContainingBlock
,
10129 GetAbsoluteContainingBlock(aParentFrame
),
10130 aBlockContinuation
);
10132 // Create the right type of first-letter frame
10133 const nsStyleDisplay
* display
= sc
->GetStyleDisplay();
10134 if (display
->IsFloating()) {
10135 // Make a floating first-letter frame
10136 CreateFloatingLetterFrame(state
, aBlockFrame
, aTextContent
, textFrame
,
10137 blockContent
, aParentFrame
, sc
, aResult
);
10140 // Make an inflow first-letter frame
10141 nsIFrame
* letterFrame
= NS_NewFirstLetterFrame(mPresShell
, sc
);
10144 // Initialize the first-letter-frame. We don't want to use a text
10145 // content for a non-text frame (because we want its primary frame to
10146 // be a text frame). So use its parent for the first-letter.
10147 nsIContent
* letterContent
= aTextContent
->GetParent();
10148 letterFrame
->Init(letterContent
, aParentFrame
, nsnull
);
10150 InitAndRestoreFrame(state
, aTextContent
, letterFrame
, nsnull
,
10153 SetInitialSingleChild(letterFrame
, textFrame
);
10155 aResult
.AddChild(letterFrame
);
10156 NS_ASSERTION(!aBlockFrame
->GetPrevContinuation(),
10157 "should have the first continuation here");
10158 aBlockFrame
->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD
);
10161 aTextContent
->SetPrimaryFrame(textFrame
);
10168 nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
10169 nsIContent
* aBlockContent
,
10170 nsIFrame
* aBlockFrame
,
10171 nsFrameItems
& aBlockFrames
)
10173 nsresult rv
= NS_OK
;
10175 aBlockFrame
->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE
);
10177 nsIFrame
* parentFrame
= nsnull
;
10178 nsIFrame
* textFrame
= nsnull
;
10179 nsIFrame
* prevFrame
= nsnull
;
10180 nsFrameItems letterFrames
;
10181 PRBool stopLooking
= PR_FALSE
;
10182 rv
= WrapFramesInFirstLetterFrame(aBlockFrame
, aBlockFrame
, aBlockFrame
,
10183 aBlockFrames
.FirstChild(),
10184 &parentFrame
, &textFrame
, &prevFrame
,
10185 letterFrames
, &stopLooking
);
10186 if (NS_FAILED(rv
)) {
10190 if (parentFrame
== aBlockFrame
) {
10191 // Take textFrame out of the block's frame list and substitute the
10192 // letter frame(s) instead.
10193 aBlockFrames
.DestroyFrame(textFrame
);
10194 aBlockFrames
.InsertFrames(nsnull
, prevFrame
, letterFrames
);
10197 // Take the old textFrame out of the inline parent's child list
10198 mPresShell
->FrameManager()->RemoveFrame(nsnull
, textFrame
);
10200 // Insert in the letter frame(s)
10201 parentFrame
->InsertFrames(nsnull
, prevFrame
, letterFrames
);
10209 nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
10210 nsIFrame
* aBlockFrame
,
10211 nsIFrame
* aBlockContinuation
,
10212 nsIFrame
* aParentFrame
,
10213 nsIFrame
* aParentFrameList
,
10214 nsIFrame
** aModifiedParent
,
10215 nsIFrame
** aTextFrame
,
10216 nsIFrame
** aPrevFrame
,
10217 nsFrameItems
& aLetterFrames
,
10218 PRBool
* aStopLooking
)
10220 nsresult rv
= NS_OK
;
10222 nsIFrame
* prevFrame
= nsnull
;
10223 nsIFrame
* frame
= aParentFrameList
;
10226 nsIFrame
* nextFrame
= frame
->GetNextSibling();
10228 nsIAtom
* frameType
= frame
->GetType();
10229 if (nsGkAtoms::textFrame
== frameType
) {
10230 // Wrap up first-letter content in a letter frame
10231 nsIContent
* textContent
= frame
->GetContent();
10232 if (IsFirstLetterContent(textContent
)) {
10233 // Create letter frame to wrap up the text
10234 rv
= CreateLetterFrame(aBlockFrame
, aBlockContinuation
, textContent
,
10235 aParentFrame
, aLetterFrames
);
10236 if (NS_FAILED(rv
)) {
10240 // Provide adjustment information for parent
10241 *aModifiedParent
= aParentFrame
;
10242 *aTextFrame
= frame
;
10243 *aPrevFrame
= prevFrame
;
10244 *aStopLooking
= PR_TRUE
;
10248 else if (IsInlineFrame(frame
) && frameType
!= nsGkAtoms::brFrame
) {
10249 nsIFrame
* kids
= frame
->GetFirstChild(nsnull
);
10250 WrapFramesInFirstLetterFrame(aBlockFrame
, aBlockContinuation
, frame
,
10251 kids
, aModifiedParent
, aTextFrame
,
10252 aPrevFrame
, aLetterFrames
, aStopLooking
);
10253 if (*aStopLooking
) {
10258 // This will stop us looking to create more letter frames. For
10259 // example, maybe the frame-type is "letterFrame" or
10260 // "placeholderFrame". This keeps us from creating extra letter
10261 // frames, and also prevents us from creating letter frames when
10262 // the first real content child of a block is not text (e.g. an
10263 // image, hr, etc.)
10264 *aStopLooking
= PR_TRUE
;
10276 nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
10277 nsPresContext
* aPresContext
,
10278 nsIPresShell
* aPresShell
,
10279 nsFrameManager
* aFrameManager
,
10280 nsIFrame
* aBlockFrame
,
10281 PRBool
* aStopLooking
)
10283 // First look for the float frame that is a letter frame
10284 nsIFrame
* floatFrame
= aBlockFrame
->GetFirstChild(nsGkAtoms::floatList
);
10285 while (floatFrame
) {
10286 // See if we found a floating letter frame
10287 if (nsGkAtoms::letterFrame
== floatFrame
->GetType()) {
10290 floatFrame
= floatFrame
->GetNextSibling();
10297 // Take the text frame away from the letter frame (so it isn't
10298 // destroyed when we destroy the letter frame).
10299 nsIFrame
* textFrame
= floatFrame
->GetFirstChild(nsnull
);
10304 // Discover the placeholder frame for the letter frame
10305 nsIFrame
* parentFrame
;
10306 nsPlaceholderFrame
* placeholderFrame
=
10307 aFrameManager
->GetPlaceholderFrameFor(floatFrame
);
10309 if (!placeholderFrame
) {
10310 // Somethings really wrong
10313 parentFrame
= placeholderFrame
->GetParent();
10314 if (!parentFrame
) {
10315 // Somethings really wrong
10319 // Create a new text frame with the right style context that maps
10320 // all of the content that was previously part of the letter frame
10321 // (and probably continued elsewhere).
10322 nsStyleContext
* parentSC
= parentFrame
->GetStyleContext();
10326 nsIContent
* textContent
= textFrame
->GetContent();
10327 if (!textContent
) {
10330 nsRefPtr
<nsStyleContext
> newSC
;
10331 newSC
= aPresShell
->StyleSet()->ResolveStyleForNonElement(parentSC
);
10335 nsIFrame
* newTextFrame
= NS_NewTextFrame(aPresShell
, newSC
);
10336 if (NS_UNLIKELY(!newTextFrame
)) {
10337 return NS_ERROR_OUT_OF_MEMORY
;;
10339 newTextFrame
->Init(textContent
, parentFrame
, nsnull
);
10341 // Destroy the old text frame's continuations (the old text frame
10342 // will be destroyed when its letter frame is destroyed).
10343 nsIFrame
* frameToDelete
= textFrame
->GetLastContinuation();
10344 while (frameToDelete
!= textFrame
) {
10345 nsIFrame
* nextFrameToDelete
= frameToDelete
->GetPrevContinuation();
10346 aFrameManager
->RemoveFrame(nsnull
, frameToDelete
);
10347 frameToDelete
= nextFrameToDelete
;
10350 nsIFrame
* prevSibling
= placeholderFrame
->GetPrevSibling();
10352 // Now that everything is set...
10353 #ifdef NOISY_FIRST_LETTER
10354 printf("RemoveFloatingFirstLetterFrames: textContent=%p oldTextFrame=%p newTextFrame=%p\n",
10355 textContent
.get(), textFrame
, newTextFrame
);
10358 // Remove placeholder frame and the float
10359 aFrameManager
->RemoveFrame(nsnull
, placeholderFrame
);
10361 // Now that the old frames are gone, we can start pointing to our
10362 // new primary frame.
10363 textContent
->SetPrimaryFrame(newTextFrame
);
10365 // Insert text frame in its place
10366 nsFrameList
textList(newTextFrame
, newTextFrame
);
10367 aFrameManager
->InsertFrames(parentFrame
, nsnull
, prevSibling
, textList
);
10373 nsCSSFrameConstructor::RemoveFirstLetterFrames(nsPresContext
* aPresContext
,
10374 nsIPresShell
* aPresShell
,
10375 nsFrameManager
* aFrameManager
,
10377 nsIFrame
* aBlockFrame
,
10378 PRBool
* aStopLooking
)
10380 nsIFrame
* prevSibling
= nsnull
;
10381 nsIFrame
* kid
= aFrame
->GetFirstChild(nsnull
);
10384 if (nsGkAtoms::letterFrame
== kid
->GetType()) {
10385 // Bingo. Found it. First steal away the text frame.
10386 nsIFrame
* textFrame
= kid
->GetFirstChild(nsnull
);
10391 // Create a new textframe
10392 nsStyleContext
* parentSC
= aFrame
->GetStyleContext();
10396 nsIContent
* textContent
= textFrame
->GetContent();
10397 if (!textContent
) {
10400 nsRefPtr
<nsStyleContext
> newSC
;
10401 newSC
= aPresShell
->StyleSet()->ResolveStyleForNonElement(parentSC
);
10405 textFrame
= NS_NewTextFrame(aPresShell
, newSC
);
10406 textFrame
->Init(textContent
, aFrame
, nsnull
);
10408 // Next rip out the kid and replace it with the text frame
10409 aFrameManager
->RemoveFrame(nsnull
, kid
);
10411 // Now that the old frames are gone, we can start pointing to our
10412 // new primary frame.
10413 textContent
->SetPrimaryFrame(textFrame
);
10415 // Insert text frame in its place
10416 nsFrameList
textList(textFrame
, textFrame
);
10417 aFrameManager
->InsertFrames(aFrame
, nsnull
, prevSibling
, textList
);
10419 *aStopLooking
= PR_TRUE
;
10420 NS_ASSERTION(!aBlockFrame
->GetPrevContinuation(),
10421 "should have the first continuation here");
10422 aBlockFrame
->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD
);
10425 else if (IsInlineFrame(kid
)) {
10426 // Look inside child inline frame for the letter frame
10427 RemoveFirstLetterFrames(aPresContext
, aPresShell
, aFrameManager
,
10428 kid
, aBlockFrame
, aStopLooking
);
10429 if (*aStopLooking
) {
10434 kid
= kid
->GetNextSibling();
10441 nsCSSFrameConstructor::RemoveLetterFrames(nsPresContext
* aPresContext
,
10442 nsIPresShell
* aPresShell
,
10443 nsFrameManager
* aFrameManager
,
10444 nsIFrame
* aBlockFrame
)
10446 aBlockFrame
= aBlockFrame
->GetFirstContinuation();
10447 nsIFrame
* continuation
= aBlockFrame
;
10449 PRBool stopLooking
= PR_FALSE
;
10452 rv
= RemoveFloatingFirstLetterFrames(aPresContext
, aPresShell
,
10454 continuation
, &stopLooking
);
10455 if (NS_SUCCEEDED(rv
) && !stopLooking
) {
10456 rv
= RemoveFirstLetterFrames(aPresContext
, aPresShell
, aFrameManager
,
10457 continuation
, aBlockFrame
, &stopLooking
);
10462 continuation
= continuation
->GetNextContinuation();
10463 } while (continuation
);
10467 // Fixup the letter frame situation for the given block
10469 nsCSSFrameConstructor::RecoverLetterFrames(nsIFrame
* aBlockFrame
)
10471 aBlockFrame
= aBlockFrame
->GetFirstContinuation();
10472 nsIFrame
* continuation
= aBlockFrame
;
10474 nsIFrame
* parentFrame
= nsnull
;
10475 nsIFrame
* textFrame
= nsnull
;
10476 nsIFrame
* prevFrame
= nsnull
;
10477 nsFrameItems letterFrames
;
10478 PRBool stopLooking
= PR_FALSE
;
10481 // XXX shouldn't this bit be set already (bug 408493), assert instead?
10482 continuation
->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE
);
10483 rv
= WrapFramesInFirstLetterFrame(aBlockFrame
, continuation
, continuation
,
10484 continuation
->GetFirstChild(nsnull
),
10485 &parentFrame
, &textFrame
, &prevFrame
,
10486 letterFrames
, &stopLooking
);
10487 if (NS_FAILED(rv
)) {
10493 continuation
= continuation
->GetNextContinuation();
10494 } while (continuation
);
10497 // Take the old textFrame out of the parents child list
10498 mPresShell
->FrameManager()->RemoveFrame(nsnull
, textFrame
);
10500 // Insert in the letter frame(s)
10501 parentFrame
->InsertFrames(nsnull
, prevFrame
, letterFrames
);
10506 //----------------------------------------------------------------------
10508 // listbox Widget Routines
10511 nsCSSFrameConstructor::CreateListBoxContent(nsPresContext
* aPresContext
,
10512 nsIFrame
* aParentFrame
,
10513 nsIFrame
* aPrevFrame
,
10514 nsIContent
* aChild
,
10515 nsIFrame
** aNewFrame
,
10517 PRBool aIsScrollbar
,
10518 nsILayoutHistoryState
* aFrameState
)
10521 nsresult rv
= NS_OK
;
10523 // Construct a new frame
10524 if (nsnull
!= aParentFrame
) {
10525 nsFrameItems frameItems
;
10526 nsFrameConstructorState
state(mPresShell
, mFixedContainingBlock
,
10527 GetAbsoluteContainingBlock(aParentFrame
),
10528 GetFloatContainingBlock(aParentFrame
),
10529 mTempFrameTreeState
);
10531 nsRefPtr
<nsStyleContext
> styleContext
;
10532 styleContext
= ResolveStyleContext(aParentFrame
, aChild
);
10534 // Pre-check for display "none" - only if we find that, do we create
10535 // any frame at all
10536 const nsStyleDisplay
* display
= styleContext
->GetStyleDisplay();
10538 if (NS_STYLE_DISPLAY_NONE
== display
->mDisplay
) {
10539 *aNewFrame
= nsnull
;
10545 FrameConstructionItemList items
;
10546 AddFrameConstructionItemsInternal(state
, aChild
, aParentFrame
,
10547 aChild
->Tag(), aChild
->GetNameSpaceID(),
10548 PR_TRUE
, styleContext
,
10549 ITEM_ALLOW_XBL_BASE
, items
);
10550 ConstructFramesFromItemList(state
, items
, aParentFrame
, frameItems
);
10552 nsIFrame
* newFrame
= frameItems
.FirstChild();
10553 *aNewFrame
= newFrame
;
10555 if (NS_SUCCEEDED(rv
) && (nsnull
!= newFrame
)) {
10556 // Notify the parent frame
10558 rv
= ((nsListBoxBodyFrame
*)aParentFrame
)->ListBoxAppendFrames(frameItems
);
10560 rv
= ((nsListBoxBodyFrame
*)aParentFrame
)->ListBoxInsertFrames(aPrevFrame
, frameItems
);
10568 return NS_ERROR_FAILURE
;
10572 //----------------------------------------
10575 nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState
& aState
,
10576 const nsStyleDisplay
* aDisplay
,
10577 nsIContent
* aContent
,
10578 nsIFrame
* aParentFrame
,
10579 nsIFrame
* aContentParentFrame
,
10580 nsStyleContext
* aStyleContext
,
10581 nsIFrame
** aNewFrame
,
10582 nsFrameItems
& aFrameItems
,
10583 PRBool aAbsPosContainer
,
10584 PendingBinding
* aPendingBinding
)
10586 // Create column wrapper if necessary
10587 nsIFrame
* blockFrame
= *aNewFrame
;
10588 nsIFrame
* parent
= aParentFrame
;
10589 nsRefPtr
<nsStyleContext
> blockStyle
= aStyleContext
;
10590 const nsStyleColumn
* columns
= aStyleContext
->GetStyleColumn();
10592 if (columns
->mColumnCount
!= NS_STYLE_COLUMN_COUNT_AUTO
10593 || columns
->mColumnWidth
.GetUnit() != eStyleUnit_Auto
) {
10594 nsIFrame
* columnSetFrame
= nsnull
;
10595 columnSetFrame
= NS_NewColumnSetFrame(mPresShell
, aStyleContext
, 0);
10596 if (!columnSetFrame
) {
10597 return NS_ERROR_OUT_OF_MEMORY
;
10600 InitAndRestoreFrame(aState
, aContent
, aParentFrame
, nsnull
, columnSetFrame
);
10601 // See if we need to create a view
10602 nsHTMLContainerFrame::CreateViewForFrame(columnSetFrame
, PR_FALSE
);
10603 blockStyle
= mPresShell
->StyleSet()->
10604 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::columnContent
, aStyleContext
);
10605 parent
= columnSetFrame
;
10606 *aNewFrame
= columnSetFrame
;
10608 SetInitialSingleChild(columnSetFrame
, blockFrame
);
10611 blockFrame
->SetStyleContextWithoutNotification(blockStyle
);
10612 InitAndRestoreFrame(aState
, aContent
, parent
, nsnull
, blockFrame
);
10614 nsresult rv
= aState
.AddChild(*aNewFrame
, aFrameItems
, aContent
,
10616 aContentParentFrame
? aContentParentFrame
:
10618 if (NS_FAILED(rv
)) {
10622 // See if we need to create a view, e.g. the frame is absolutely positioned
10623 nsHTMLContainerFrame::CreateViewForFrame(blockFrame
, PR_FALSE
);
10625 if (!mRootElementFrame
) {
10626 // The frame we're constructing will be the root element frame.
10627 // Set mRootElementFrame before processing children.
10628 mRootElementFrame
= *aNewFrame
;
10631 // We should make the outer frame be the absolute containing block,
10632 // if one is required. We have to do this because absolute
10633 // positioning must be computed with respect to the CSS dimensions
10634 // of the element, which are the dimensions of the outer block. But
10635 // we can't really do that because only blocks can have absolute
10636 // children. So use the block and try to compensate with hacks
10637 // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
10638 nsFrameConstructorSaveState absoluteSaveState
;
10639 if (aAbsPosContainer
) {
10640 // NS_ASSERTION(aRelPos, "should have made area frame for this");
10641 aState
.PushAbsoluteContainingBlock(blockFrame
, absoluteSaveState
);
10644 // Process the child content
10645 nsFrameItems childItems
;
10646 rv
= ProcessChildren(aState
, aContent
, aStyleContext
, blockFrame
, PR_TRUE
,
10647 childItems
, PR_TRUE
, aPendingBinding
);
10649 // Set the frame's initial child list
10650 blockFrame
->SetInitialChildList(nsnull
, childItems
);
10656 nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState
& aState
,
10657 FrameConstructionItem
& aItem
,
10658 nsIFrame
* aParentFrame
,
10659 const nsStyleDisplay
* aDisplay
,
10660 nsFrameItems
& aFrameItems
,
10661 nsIFrame
** aNewFrame
)
10663 // If an inline frame has non-inline kids, then we chop up the child list
10664 // into runs of blocks and runs of inlines, create anonymous block frames to
10665 // contain the runs of blocks, inline frames with our style context for the
10666 // runs of inlines, and put all these frames, in order, into aFrameItems. We
10667 // put the first one into *aNewFrame. The whole setup is called an {ib}
10668 // split; in what follows "frames in the split" refers to the anonymous blocks
10669 // and inlines that contain our children.
10671 // {ib} splits maintain the following invariants:
10672 // 1) All frames in the split have the NS_FRAME_IS_SPECIAL bit set.
10673 // 2) Each frame in the split has the nsIFrame::IBSplitSpecialSibling
10674 // property pointing to the next frame in the split, except for the last
10675 // one, which does not have it set.
10676 // 3) Each frame in the split has the nsIFrame::IBSplitSpecialPrevSibling
10677 // property pointing to the previous frame in the split, except for the
10678 // first one, which does not have it set.
10679 // 4) The first and last frame in the split are always inlines.
10681 // An invariant that is NOT maintained is that the wrappers are actually
10682 // linked via GetNextSibling linkage. A simple example is an inline
10683 // containing an inline that contains a block. The three parts of the inner
10684 // inline end up with three different parents.
10686 // For example, this HTML:
10697 // Gives the following frame tree:
10699 // Inline (outer span)
10700 // Block (anonymous, outer span)
10703 // Inline (outer span)
10704 // Inline (inner span)
10706 // Block (anonymous, outer span)
10707 // Block (anonymous, inner span)
10710 // Inline (outer span)
10711 // Inline (inner span)
10713 // Block (anonymous, outer span)
10716 // Inline (outer span)
10719 nsIContent
* const content
= aItem
.mContent
;
10720 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
10722 nsIFrame
*newFrame
;
10724 PRBool positioned
=
10725 NS_STYLE_DISPLAY_INLINE
== aDisplay
->mDisplay
&&
10726 (NS_STYLE_POSITION_RELATIVE
== aDisplay
->mPosition
||
10727 aDisplay
->HasTransform());
10729 newFrame
= NS_NewPositionedInlineFrame(mPresShell
, styleContext
);
10731 newFrame
= NS_NewInlineFrame(mPresShell
, styleContext
);
10734 // Initialize the frame
10735 InitAndRestoreFrame(aState
, content
, aParentFrame
, nsnull
, newFrame
);
10737 nsFrameConstructorSaveState absoluteSaveState
; // definition cannot be inside next block
10738 // because the object's destructor is significant
10739 // this is part of the fix for bug 42372
10741 // Any inline frame might need a view (because of opacity, or fixed background)
10742 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
10745 // Relatively positioned frames becomes a container for child
10746 // frames that are positioned
10747 aState
.PushAbsoluteContainingBlock(newFrame
, absoluteSaveState
);
10750 // Process the child content
10751 nsFrameItems childItems
;
10752 nsresult rv
= ConstructFramesFromItemList(aState
, aItem
.mChildItems
, newFrame
,
10754 if (NS_FAILED(rv
)) {
10759 nsFrameList::FrameLinkEnumerator
firstBlockEnumerator(childItems
);
10760 if (!aItem
.mIsAllInline
) {
10761 FindFirstBlock(firstBlockEnumerator
);
10764 if (aItem
.mIsAllInline
|| firstBlockEnumerator
.AtEnd()) {
10765 // This part is easy. We either already know we have no non-inline kids,
10766 // or haven't found any when constructing actual frames (the latter can
10767 // happen only if out-of-flows that we thought had no containing block
10768 // acquired one when ancestor inline frames and {ib} splits got
10769 // constructed). Just put all the kids into the single inline frame and
10771 newFrame
->SetInitialChildList(nsnull
, childItems
);
10772 if (NS_SUCCEEDED(rv
)) {
10773 aState
.AddChild(newFrame
, aFrameItems
, content
, styleContext
, aParentFrame
);
10774 *aNewFrame
= newFrame
;
10779 // This inline frame contains several types of children. Therefore this frame
10780 // has to be chopped into several pieces, as described above.
10782 // Grab the first inline's kids
10783 nsFrameList firstInlineKids
= childItems
.ExtractHead(firstBlockEnumerator
);
10784 newFrame
->SetInitialChildList(nsnull
, firstInlineKids
);
10786 aFrameItems
.AddChild(newFrame
);
10788 CreateIBSiblings(aState
, newFrame
, positioned
, childItems
, aFrameItems
);
10790 *aNewFrame
= newFrame
;
10795 nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState
& aState
,
10796 nsIFrame
* aInitialInline
,
10797 PRBool aIsPositioned
,
10798 nsFrameItems
& aChildItems
,
10799 nsFrameItems
& aSiblings
)
10801 nsIContent
* content
= aInitialInline
->GetContent();
10802 nsStyleContext
* styleContext
= aInitialInline
->GetStyleContext();
10803 nsIFrame
* parentFrame
= aInitialInline
->GetParent();
10805 // Resolve the right style context for our anonymous blocks.
10806 nsRefPtr
<nsStyleContext
> blockSC
=
10807 mPresShell
->StyleSet()->
10808 ResolveAnonymousBoxStyle(aIsPositioned
?
10809 nsCSSAnonBoxes::mozAnonymousPositionedBlock
:
10810 nsCSSAnonBoxes::mozAnonymousBlock
,
10813 nsIFrame
* lastNewInline
= aInitialInline
->GetFirstContinuation();
10815 // On entry to this loop aChildItems is not empty and the first frame in it
10817 NS_PRECONDITION(aChildItems
.NotEmpty(), "Should have child items");
10818 NS_PRECONDITION(!IsInlineOutside(aChildItems
.FirstChild()),
10819 "Must have list starting with block");
10821 // The initial run of blocks belongs to an anonymous block that we create
10822 // right now. The anonymous block will be the parent of these block
10823 // children of the inline.
10824 nsIFrame
* blockFrame
;
10825 blockFrame
= NS_NewBlockFrame(mPresShell
, blockSC
);
10827 InitAndRestoreFrame(aState
, content
, parentFrame
, nsnull
, blockFrame
,
10830 // Any frame could have a view
10831 nsHTMLContainerFrame::CreateViewForFrame(blockFrame
, PR_FALSE
);
10833 // Find the first non-block child which defines the end of our block kids
10834 // and the start of our next inline's kids
10835 nsFrameList::FrameLinkEnumerator firstNonBlock
=
10836 FindFirstNonBlock(aChildItems
);
10837 nsFrameList blockKids
= aChildItems
.ExtractHead(firstNonBlock
);
10839 MoveChildrenTo(aState
.mPresContext
, aInitialInline
, blockFrame
, blockKids
);
10841 SetFrameIsSpecial(lastNewInline
, blockFrame
);
10842 aSiblings
.AddChild(blockFrame
);
10844 // Now grab the initial inlines in aChildItems and put them into an inline
10846 nsIFrame
* inlineFrame
;
10847 if (aIsPositioned
) {
10848 inlineFrame
= NS_NewPositionedInlineFrame(mPresShell
, styleContext
);
10851 inlineFrame
= NS_NewInlineFrame(mPresShell
, styleContext
);
10854 InitAndRestoreFrame(aState
, content
, parentFrame
, nsnull
, inlineFrame
,
10857 // Any frame might need a view
10858 nsHTMLContainerFrame::CreateViewForFrame(inlineFrame
, PR_FALSE
);
10860 if (aChildItems
.NotEmpty()) {
10861 nsFrameList::FrameLinkEnumerator
firstBlock(aChildItems
);
10862 FindFirstBlock(firstBlock
);
10863 nsFrameList inlineKids
= aChildItems
.ExtractHead(firstBlock
);
10865 MoveChildrenTo(aState
.mPresContext
, aInitialInline
, inlineFrame
,
10869 SetFrameIsSpecial(blockFrame
, inlineFrame
);
10870 aSiblings
.AddChild(inlineFrame
);
10871 lastNewInline
= inlineFrame
;
10872 } while (aChildItems
.NotEmpty());
10874 SetFrameIsSpecial(lastNewInline
, nsnull
);
10878 nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState
& aState
,
10879 FrameConstructionItem
& aParentItem
)
10881 // XXXbz should we preallocate aParentItem.mChildItems to some sane
10882 // length? Maybe even to parentContent->GetChildCount()?
10883 nsFrameConstructorState::PendingBindingAutoPusher
10884 pusher(aState
, aParentItem
.mPendingBinding
);
10886 // Probe for generated content before
10887 nsStyleContext
* const parentStyleContext
= aParentItem
.mStyleContext
;
10888 nsIContent
* const parentContent
= aParentItem
.mContent
;
10889 CreateGeneratedContentItem(aState
, nsnull
, parentContent
, parentStyleContext
,
10890 nsCSSPseudoElements::ePseudo_before
,
10891 aParentItem
.mChildItems
);
10893 ChildIterator iter
, last
;
10894 for (ChildIterator::Init(parentContent
, &iter
, &last
);
10897 // Manually check for comments/PIs, since we do't have a frame to pass to
10898 // AddFrameConstructionItems. We know our parent is a non-replaced inline,
10899 // so there is no need to do the NeedFrameFor check.
10900 nsIContent
* content
= *iter
;
10901 content
->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME
);
10902 if (content
->IsNodeOfType(nsINode::eCOMMENT
) ||
10903 content
->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION
)) {
10906 if (content
->IsElement()) {
10907 // See comment explaining why we need to remove the "is possible
10908 // restyle root" flags in AddFrameConstructionItems. But note
10909 // that we can remove all restyle flags, just like in
10910 // ProcessChildren and for the same reason.
10911 content
->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS
);
10914 nsRefPtr
<nsStyleContext
> childContext
=
10915 ResolveStyleContext(parentStyleContext
, content
);
10917 AddFrameConstructionItemsInternal(aState
, content
, nsnull
, content
->Tag(),
10918 content
->GetNameSpaceID(),
10919 iter
.XBLInvolved(), childContext
,
10920 ITEM_ALLOW_XBL_BASE
| ITEM_ALLOW_PAGE_BREAK
,
10921 aParentItem
.mChildItems
);
10924 // Probe for generated content after
10925 CreateGeneratedContentItem(aState
, nsnull
, parentContent
, parentStyleContext
,
10926 nsCSSPseudoElements::ePseudo_after
,
10927 aParentItem
.mChildItems
);
10929 aParentItem
.mIsAllInline
= aParentItem
.mChildItems
.AreAllItemsInline();
10932 // return whether it's ok to append (in the AppendFrames sense) to
10933 // aParentFrame if our nextSibling is aNextSibling. aParentFrame must
10934 // be an {ib} special inline.
10936 IsSafeToAppendToSpecialInline(nsIFrame
* aParentFrame
, nsIFrame
* aNextSibling
)
10938 NS_PRECONDITION(IsInlineFrame(aParentFrame
),
10939 "Must have an inline parent here");
10941 NS_ASSERTION(IsFrameSpecial(aParentFrame
), "How is this not special?");
10942 if (aNextSibling
|| aParentFrame
->GetNextContinuation() ||
10943 GetSpecialSibling(aParentFrame
)) {
10947 aNextSibling
= aParentFrame
->GetNextSibling();
10948 aParentFrame
= aParentFrame
->GetParent();
10949 } while (IsInlineFrame(aParentFrame
));
10955 nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState
& aState
,
10956 nsIFrame
* aContainingBlock
,
10958 FrameConstructionItemList
& aItems
,
10960 nsIFrame
* aPrevSibling
)
10962 if (aItems
.IsEmpty()) {
10966 // Before we go and append the frames, we must check for several
10967 // special situations.
10969 // Situation #1 is a XUL frame that contains frames that are required
10970 // to be wrapped in blocks.
10971 if (aFrame
->IsBoxFrame() &&
10972 !(aFrame
->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK
) &&
10973 aItems
.AnyItemsNeedBlockParent()) {
10974 RecreateFramesForContent(aFrame
->GetContent(), PR_TRUE
);
10978 nsIFrame
* nextSibling
= ::GetInsertNextSibling(aFrame
, aPrevSibling
);
10980 // Situation #2 is a case when table pseudo-frames don't work out right
10981 ParentType parentType
= GetParentType(aFrame
);
10982 // If all the kids want a parent of the type that aFrame is, then we're all
10983 // set to go. Indeed, there won't be any table pseudo-frames created between
10984 // aFrame and the kids, so those won't need to be merged with any table
10985 // pseudo-frames that might already be kids of aFrame. If aFrame itself is a
10986 // table pseudo-frame, then all the kids in this list would have wanted a
10987 // frame of that type wrapping them anyway, so putting them inside it is ok.
10988 if (!aItems
.AllWantParentType(parentType
)) {
10989 // Don't give up yet. If parentType is not eTypeBlock and the parent is
10990 // not a generated content frame, then try filtering whitespace out of the
10992 if (parentType
!= eTypeBlock
&& !aFrame
->IsGeneratedContentFrame()) {
10993 // For leading whitespace followed by a kid that wants our parent type,
10994 // there are four cases:
10995 // 1) We have a previous sibling which is not a table pseudo. That means
10996 // that previous sibling wanted a (non-block) parent of the type we're
10997 // looking at. Then the whitespace comes between two table-internal
10998 // elements, so should be collapsed out.
10999 // 2) We have a previous sibling which is a table pseudo. It might have
11000 // kids who want this whitespace, so we need to reframe.
11001 // 3) We have no previous sibling and our parent frame is not a table
11002 // pseudo. That means that we'll be at the beginning of our actual
11003 // non-block-type parent, and the whitespace is OK to collapse out.
11004 // If something is ever inserted before us, it'll find our own parent
11005 // as its parent and if it's something that would care about the
11006 // whitespace it'll want a block parent, so it'll trigger a reframe at
11008 // 4) We have no previous sibling and our parent frame is a table pseudo.
11009 // Need to reframe.
11010 // All that is predicated on finding the correct previous sibling. We
11011 // might have to walk backwards along continuations from aFrame to do so.
11013 // It's always OK to drop whitespace between any two items that want a
11014 // parent of type parentType.
11016 // For trailing whitespace preceded by a kid that wants our parent type,
11017 // there are four cases:
11018 // 1) We have a next sibling which is not a table pseudo. That means
11019 // that next sibling wanted a (non-block) parent of the type we're
11020 // looking at. Then the whitespace comes between two table-internal
11021 // elements, so should be collapsed out.
11022 // 2) We have a next sibling which is a table pseudo. It might have
11023 // kids who want this whitespace, so we need to reframe.
11024 // 3) We have no next sibling and our parent frame is not a table
11025 // pseudo. That means that we'll be at the end of our actual
11026 // non-block-type parent, and the whitespace is OK to collapse out.
11027 // If something is ever inserted after us, it'll find our own parent
11028 // as its parent and if it's something that would care about the
11029 // whitespace it'll want a block parent, so it'll trigger a reframe at
11031 // 4) We have no next sibling and our parent frame is a table pseudo.
11032 // Need to reframe.
11033 // All that is predicated on finding the correct next sibling. We might
11034 // have to walk forward along continuations from aFrame to do so. That
11035 // said, in the case when nextSibling is null at this point and aIsAppend
11036 // is true, we know we're in case 3. Furthermore, in that case we don't
11037 // even have to worry about the table pseudo situation; we know our
11038 // parent is not a table pseudo there.
11039 FCItemIterator
iter(aItems
);
11040 FCItemIterator
start(iter
);
11042 if (iter
.SkipItemsWantingParentType(parentType
)) {
11046 // iter points to an item that wants a different parent. If it's not
11047 // whitespace, we're done; no more point scanning the list.
11048 if (!iter
.item().IsWhitespace(aState
)) {
11052 if (iter
== start
) {
11053 // Leading whitespace. How to handle this depends on our
11054 // previous sibling and aFrame. See the long comment above.
11055 nsIFrame
* prevSibling
= aPrevSibling
;
11056 if (!prevSibling
) {
11057 // Try to find one after all
11058 nsIFrame
* parentPrevCont
= aFrame
->GetPrevContinuation();
11059 while (parentPrevCont
) {
11060 prevSibling
= parentPrevCont
->GetLastChild(nsnull
);
11064 parentPrevCont
= parentPrevCont
->GetPrevContinuation();
11068 if (IsTablePseudo(prevSibling
)) {
11072 } else if (IsTablePseudo(aFrame
)) {
11078 FCItemIterator
spaceEndIter(iter
);
11079 // Advance spaceEndIter past any whitespace
11080 PRBool trailingSpaces
= spaceEndIter
.SkipWhitespace(aState
);
11083 if (trailingSpaces
) {
11084 // Trailing whitespace. How to handle this depeds on aIsAppend, our
11085 // next sibling and aFrame. See the long comment above.
11086 okToDrop
= aIsAppend
&& !nextSibling
;
11088 if (!nextSibling
) {
11089 // Try to find one after all
11090 nsIFrame
* parentNextCont
= aFrame
->GetNextContinuation();
11091 while (parentNextCont
) {
11092 nextSibling
= parentNextCont
->GetFirstChild(nsnull
);
11096 parentNextCont
= parentNextCont
->GetNextContinuation();
11100 okToDrop
= (nextSibling
&& !IsTablePseudo(nextSibling
)) ||
11101 (!nextSibling
&& !IsTablePseudo(aFrame
));
11105 NS_ASSERTION(!IsTablePseudo(aFrame
), "How did that happen?");
11109 okToDrop
= (spaceEndIter
.item().DesiredParentType() == parentType
);
11113 iter
.DeleteItemsTo(spaceEndIter
);
11115 // We're done: we don't want to drop the whitespace, and it has the
11116 // wrong parent type.
11120 // Now loop, since |iter| points to item right after the whitespace we
11122 } while (!iter
.IsDone());
11125 // We might be able to figure out some sort of optimizations here, but they
11126 // would have to depend on having a correct aPrevSibling and a correct next
11127 // sibling. For example, we can probably avoid reframing if none of
11128 // aFrame, aPrevSibling, and next sibling are table pseudo-frames. But it
11129 // doesn't seem worth it to worry about that for now, especially since we
11130 // in fact do not have a reliable aPrevSibling, nor any next sibling, in
11133 // aItems might have changed, so recheck the parent type thing. In fact,
11134 // it might be empty, so recheck that too.
11135 if (aItems
.IsEmpty()) {
11139 if (!aItems
.AllWantParentType(parentType
)) {
11140 // Reframing aFrame->GetContent() is good enough, since the content of
11141 // table pseudo-frames is the ancestor content.
11142 RecreateFramesForContent(aFrame
->GetContent(), PR_TRUE
);
11147 // Now we have several cases involving {ib} splits. Put them all in a
11148 // do/while with breaks to take us to the "go and reconstruct" code.
11150 if (IsInlineFrame(aFrame
)) {
11151 if (aItems
.AreAllItemsInline()) {
11152 // We can just put the kids in.
11156 if (!IsFrameSpecial(aFrame
)) {
11157 // Need to go ahead and reconstruct.
11161 // Now we're adding kids including some blocks to an inline part of an
11162 // {ib} split. If we plan to call AppendFrames, and don't have a next
11163 // sibling for the new frames, and our parent is the last continuation of
11164 // the last part of the {ib} split, and the same is true of all our
11165 // ancestor inlines (they have no following continuations and they're the
11166 // last part of their {ib} splits and we'd be adding to the end for all
11167 // of them), then AppendFrames will handle things for us. Bail out in
11169 if (aIsAppend
&& IsSafeToAppendToSpecialInline(aFrame
, nextSibling
)) {
11173 // Need to reconstruct.
11177 // Now we know we have a block parent. If it's not special, we're all set.
11178 if (!IsFrameSpecial(aFrame
)) {
11182 // We're adding some kids to a block part of an {ib} split. If all the
11183 // kids are blocks, we don't need to reconstruct.
11184 if (aItems
.AreAllItemsBlock()) {
11188 // We might have some inline kids for this block. Just reconstruct.
11192 // If we don't have a containing block, start with aFrame and look for one.
11193 if (!aContainingBlock
) {
11194 aContainingBlock
= aFrame
;
11197 // To find the right block to reframe, just walk up the tree until we find a
11199 // 1) Not part of an IB split (not special)
11200 // 2) Not a pseudo-frame
11201 // 3) Not an inline frame
11202 // We're guaranteed to find one, since nsStyleContext::ApplyStyleFixups
11203 // enforces that the root is display:none, display:table, or display:block.
11204 // Note that walking up "too far" is OK in terms of correctness, even if it
11205 // might be a little inefficient. This is why we walk out of all
11206 // pseudo-frames -- telling which ones are or are not OK to walk out of is
11207 // too hard (and I suspect that we do in fact need to walk out of all of
11209 while (IsFrameSpecial(aContainingBlock
) || IsInlineOutside(aContainingBlock
) ||
11210 aContainingBlock
->GetStyleContext()->GetPseudo()) {
11211 aContainingBlock
= aContainingBlock
->GetParent();
11212 NS_ASSERTION(aContainingBlock
,
11213 "Must have non-inline, non-special, non-pseudo frame as root "
11214 "(or child of root, for a table root)!");
11217 // Tell parent of the containing block to reformulate the
11218 // entire block. This is painful and definitely not optimal
11219 // but it will *always* get the right answer.
11221 nsIContent
*blockContent
= aContainingBlock
->GetContent();
11223 if (gNoisyContentUpdates
) {
11224 printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p\n",
11225 static_cast<void*>(blockContent
));
11228 RecreateFramesForContent(blockContent
, PR_TRUE
);
11233 nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame
* aFrame
)
11237 // ReframeContainingBlock is a NASTY routine, it causes terrible performance problems
11238 // so I want to see when it is happening! Unfortunately, it is happening way to often because
11239 // so much content on the web causes 'special' block-in-inline frame situations and we handle them
11241 if (gNoisyContentUpdates
) {
11242 printf("nsCSSFrameConstructor::ReframeContainingBlock frame=%p\n",
11243 static_cast<void*>(aFrame
));
11247 // XXXbz how exactly would we get here while isReflowing anyway? Should this
11248 // whole test be ifdef DEBUG?
11249 if (mPresShell
->IsReflowLocked()) {
11250 // don't ReframeContainingBlock, this will result in a crash
11251 // if we remove a tree that's in reflow - see bug 121368 for testcase
11252 NS_ERROR("Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a Reflow!!!");
11256 // Get the first "normal" ancestor of the target frame.
11257 nsIFrame
* containingBlock
= GetIBContainingBlockFor(aFrame
);
11258 if (containingBlock
) {
11259 // From here we look for the containing block in case the target
11260 // frame is already a block (which can happen when an inline frame
11261 // wraps some of its content in an anonymous block; see
11262 // ConstructInline)
11264 // NOTE: We used to get the FloatContainingBlock here, but it was often wrong.
11265 // GetIBContainingBlock works much better and provides the correct container in all cases
11266 // so GetFloatContainingBlock(aFrame) has been removed
11268 // And get the containingBlock's content
11269 nsCOMPtr
<nsIContent
> blockContent
= containingBlock
->GetContent();
11270 if (blockContent
) {
11272 if (gNoisyContentUpdates
) {
11273 printf(" ==> blockContent=%p\n", static_cast<void*>(blockContent
));
11276 return RecreateFramesForContent(blockContent
, PR_TRUE
);
11280 // If we get here, we're screwed!
11281 return RecreateFramesForContent(mPresShell
->GetDocument()->GetRootElement(),
11286 nsCSSFrameConstructor::RestyleForEmptyChange(Element
* aContainer
)
11288 // In some cases (:empty + E, :empty ~ E), a change if the content of
11289 // an element requires restyling its parent's siblings.
11290 nsRestyleHint hint
= eRestyle_Subtree
;
11291 nsIContent
* grandparent
= aContainer
->GetParent();
11293 (grandparent
->GetFlags() & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS
)) {
11294 hint
= nsRestyleHint(hint
| eRestyle_LaterSiblings
);
11296 PostRestyleEvent(aContainer
, hint
, NS_STYLE_HINT_NONE
);
11300 nsCSSFrameConstructor::RestyleForAppend(Element
* aContainer
,
11301 nsIContent
* aFirstNewContent
)
11303 NS_ASSERTION(aContainer
, "must have container for append");
11306 for (nsIContent
* cur
= aFirstNewContent
; cur
; cur
= cur
->GetNextSibling()) {
11307 NS_ASSERTION(!cur
->IsRootOfAnonymousSubtree(),
11308 "anonymous nodes should not be in child lists");
11312 PRUint32 selectorFlags
=
11313 aContainer
->GetFlags() & (NODE_ALL_SELECTOR_FLAGS
&
11314 ~NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS
);
11315 if (selectorFlags
== 0)
11318 if (selectorFlags
& NODE_HAS_EMPTY_SELECTOR
) {
11319 // see whether we need to restyle the container
11320 PRBool wasEmpty
= PR_TRUE
; // :empty or :-moz-only-whitespace
11321 for (nsIContent
* cur
= aContainer
->GetFirstChild();
11322 cur
!= aFirstNewContent
;
11323 cur
= cur
->GetNextSibling()) {
11324 // We don't know whether we're testing :empty or :-moz-only-whitespace,
11325 // so be conservative and assume :-moz-only-whitespace (i.e., make
11326 // IsSignificantChild less likely to be true, and thus make us more
11327 // likely to restyle).
11328 if (nsStyleUtil::IsSignificantChild(cur
, PR_TRUE
, PR_FALSE
)) {
11329 wasEmpty
= PR_FALSE
;
11334 RestyleForEmptyChange(aContainer
);
11339 if (selectorFlags
& NODE_HAS_SLOW_SELECTOR
) {
11340 PostRestyleEvent(aContainer
, eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
11341 // Restyling the container is the most we can do here, so we're done.
11345 if (selectorFlags
& NODE_HAS_EDGE_CHILD_SELECTOR
) {
11346 // restyle the last element child before this node
11347 for (nsIContent
* cur
= aFirstNewContent
->GetPreviousSibling();
11349 cur
= cur
->GetPreviousSibling()) {
11350 if (cur
->IsElement()) {
11351 PostRestyleEvent(cur
->AsElement(), eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
11358 // Needed since we can't use PostRestyleEvent on non-elements (with
11359 // eRestyle_LaterSiblings or nsRestyleHint(eRestyle_Subtree |
11360 // eRestyle_LaterSiblings) as appropriate).
11362 RestyleSiblingsStartingWith(nsCSSFrameConstructor
*aFrameConstructor
,
11363 nsIContent
*aStartingSibling
/* may be null */)
11365 for (nsIContent
*sibling
= aStartingSibling
; sibling
;
11366 sibling
= sibling
->GetNextSibling()) {
11367 if (sibling
->IsElement()) {
11368 aFrameConstructor
->
11369 PostRestyleEvent(sibling
->AsElement(),
11370 nsRestyleHint(eRestyle_Subtree
| eRestyle_LaterSiblings
),
11371 NS_STYLE_HINT_NONE
);
11377 // Restyling for a ContentInserted or CharacterDataChanged notification.
11378 // This could be used for ContentRemoved as well if we got the
11379 // notification before the removal happened (and sometimes
11380 // CharacterDataChanged is more like a removal than an addition).
11381 // The comments are written and variables are named in terms of it being
11382 // a ContentInserted notification.
11384 nsCSSFrameConstructor::RestyleForInsertOrChange(Element
* aContainer
,
11385 nsIContent
* aChild
)
11387 NS_ASSERTION(!aChild
->IsRootOfAnonymousSubtree(),
11388 "anonymous nodes should not be in child lists");
11389 PRUint32 selectorFlags
=
11390 aContainer
? (aContainer
->GetFlags() & NODE_ALL_SELECTOR_FLAGS
) : 0;
11391 if (selectorFlags
== 0)
11394 if (selectorFlags
& NODE_HAS_EMPTY_SELECTOR
) {
11395 // see whether we need to restyle the container
11396 PRBool wasEmpty
= PR_TRUE
; // :empty or :-moz-only-whitespace
11397 for (nsIContent
* child
= aContainer
->GetFirstChild();
11399 child
= child
->GetNextSibling()) {
11400 if (child
== aChild
)
11402 // We don't know whether we're testing :empty or :-moz-only-whitespace,
11403 // so be conservative and assume :-moz-only-whitespace (i.e., make
11404 // IsSignificantChild less likely to be true, and thus make us more
11405 // likely to restyle).
11406 if (nsStyleUtil::IsSignificantChild(child
, PR_TRUE
, PR_FALSE
)) {
11407 wasEmpty
= PR_FALSE
;
11412 RestyleForEmptyChange(aContainer
);
11417 if (selectorFlags
& NODE_HAS_SLOW_SELECTOR
) {
11418 PostRestyleEvent(aContainer
, eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
11419 // Restyling the container is the most we can do here, so we're done.
11423 if (selectorFlags
& NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS
) {
11424 // Restyle all later siblings.
11425 RestyleSiblingsStartingWith(this, aChild
->GetNextSibling());
11428 if (selectorFlags
& NODE_HAS_EDGE_CHILD_SELECTOR
) {
11429 // restyle the previously-first element child if it is after this node
11430 PRBool passedChild
= PR_FALSE
;
11431 for (nsIContent
* content
= aContainer
->GetFirstChild();
11433 content
= content
->GetNextSibling()) {
11434 if (content
== aChild
) {
11435 passedChild
= PR_TRUE
;
11438 if (content
->IsElement()) {
11440 PostRestyleEvent(content
->AsElement(), eRestyle_Subtree
,
11441 NS_STYLE_HINT_NONE
);
11446 // restyle the previously-last element child if it is before this node
11447 passedChild
= PR_FALSE
;
11448 for (nsIContent
* content
= aContainer
->GetLastChild();
11450 content
= content
->GetPreviousSibling()) {
11451 if (content
== aChild
) {
11452 passedChild
= PR_TRUE
;
11455 if (content
->IsElement()) {
11457 PostRestyleEvent(content
->AsElement(), eRestyle_Subtree
,
11458 NS_STYLE_HINT_NONE
);
11467 nsCSSFrameConstructor::RestyleForRemove(Element
* aContainer
,
11468 nsIContent
* aOldChild
,
11469 nsIContent
* aFollowingSibling
)
11471 NS_ASSERTION(!aOldChild
->IsRootOfAnonymousSubtree(),
11472 "anonymous nodes should not be in child lists");
11473 PRUint32 selectorFlags
=
11474 aContainer
? (aContainer
->GetFlags() & NODE_ALL_SELECTOR_FLAGS
) : 0;
11475 if (selectorFlags
== 0)
11478 if (selectorFlags
& NODE_HAS_EMPTY_SELECTOR
) {
11479 // see whether we need to restyle the container
11480 PRBool isEmpty
= PR_TRUE
; // :empty or :-moz-only-whitespace
11481 for (nsIContent
* child
= aContainer
->GetFirstChild();
11483 child
= child
->GetNextSibling()) {
11484 // We don't know whether we're testing :empty or :-moz-only-whitespace,
11485 // so be conservative and assume :-moz-only-whitespace (i.e., make
11486 // IsSignificantChild less likely to be true, and thus make us more
11487 // likely to restyle).
11488 if (nsStyleUtil::IsSignificantChild(child
, PR_TRUE
, PR_FALSE
)) {
11489 isEmpty
= PR_FALSE
;
11494 RestyleForEmptyChange(aContainer
);
11499 if (selectorFlags
& NODE_HAS_SLOW_SELECTOR
) {
11500 PostRestyleEvent(aContainer
, eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
11501 // Restyling the container is the most we can do here, so we're done.
11505 if (selectorFlags
& NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS
) {
11506 // Restyle all later siblings.
11507 RestyleSiblingsStartingWith(this, aFollowingSibling
);
11510 if (selectorFlags
& NODE_HAS_EDGE_CHILD_SELECTOR
) {
11511 // restyle the now-first element child if it was after aOldChild
11512 PRBool reachedFollowingSibling
= PR_FALSE
;
11513 for (nsIContent
* content
= aContainer
->GetFirstChild();
11515 content
= content
->GetNextSibling()) {
11516 if (content
== aFollowingSibling
) {
11517 reachedFollowingSibling
= PR_TRUE
;
11518 // do NOT continue here; we might want to restyle this node
11520 if (content
->IsElement()) {
11521 if (reachedFollowingSibling
) {
11522 PostRestyleEvent(content
->AsElement(), eRestyle_Subtree
,
11523 NS_STYLE_HINT_NONE
);
11528 // restyle the now-last element child if it was before aOldChild
11529 reachedFollowingSibling
= (aFollowingSibling
== nsnull
);
11530 for (nsIContent
* content
= aContainer
->GetLastChild();
11532 content
= content
->GetPreviousSibling()) {
11533 if (content
->IsElement()) {
11534 if (reachedFollowingSibling
) {
11535 PostRestyleEvent(content
->AsElement(), eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
11539 if (content
== aFollowingSibling
) {
11540 reachedFollowingSibling
= PR_TRUE
;
11548 nsCSSFrameConstructor::RebuildAllStyleData(nsChangeHint aExtraHint
)
11550 NS_ASSERTION(!(aExtraHint
& nsChangeHint_ReconstructFrame
),
11551 "Should not reconstruct the root of the frame tree. "
11552 "Use ReconstructDocElementHierarchy instead.");
11554 mRebuildAllStyleData
= PR_FALSE
;
11555 NS_UpdateHint(aExtraHint
, mRebuildAllExtraHint
);
11556 mRebuildAllExtraHint
= nsChangeHint(0);
11558 if (!mPresShell
|| !mPresShell
->GetRootFrame())
11561 // Make sure that the viewmanager will outlive the presshell
11562 nsIViewManager::UpdateViewBatch
batch(mPresShell
->GetViewManager());
11564 // Processing the style changes could cause a flush that propagates to
11565 // the parent frame and thus destroys the pres shell.
11566 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(mPresShell
);
11568 // We may reconstruct frames below and hence process anything that is in the
11569 // tree. We don't want to get notified to process those items again after.
11570 mPresShell
->GetDocument()->FlushPendingNotifications(Flush_ContentAndNotify
);
11572 nsAutoScriptBlocker scriptBlocker
;
11574 // Tell the style set to get the old rule tree out of the way
11575 // so we can recalculate while maintaining rule tree immutability
11576 nsresult rv
= mPresShell
->StyleSet()->BeginReconstruct();
11577 if (NS_FAILED(rv
)) {
11578 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
11582 // Recalculate all of the style contexts for the document
11583 // Note that we can ignore the return value of ComputeStyleChangeFor
11584 // because we never need to reframe the root frame
11585 // XXX This could be made faster by not rerunning rule matching
11586 // (but note that nsPresShell::SetPreferenceStyleRules currently depends
11587 // on us re-running rule matching here
11588 nsStyleChangeList changeList
;
11589 // XXX Does it matter that we're passing aExtraHint to the real root
11590 // frame and not the root node's primary frame?
11591 // Note: The restyle tracker we pass in here doesn't matter.
11592 mPresShell
->FrameManager()->ComputeStyleChangeFor(mPresShell
->GetRootFrame(),
11593 &changeList
, aExtraHint
,
11594 mPendingRestyles
, PR_TRUE
);
11595 // Process the required changes
11596 ProcessRestyledFrames(changeList
);
11597 // Tell the style set it's safe to destroy the old rule tree. We
11598 // must do this after the ProcessRestyledFrames call in case the
11599 // change list has frame reconstructs in it (since frames to be
11600 // reconstructed will still have their old style context pointers
11601 // until they are destroyed).
11602 mPresShell
->StyleSet()->EndReconstruct();
11603 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
11607 nsCSSFrameConstructor::ProcessPendingRestyles()
11609 NS_PRECONDITION(mDocument
, "No document? Pshaw!");
11610 NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
11611 "Missing a script blocker!");
11613 // Process non-animation restyles...
11614 nsPresContext
*presContext
= mPresShell
->GetPresContext();
11615 NS_ABORT_IF_FALSE(!presContext
->IsProcessingRestyles(),
11616 "Nesting calls to ProcessPendingRestyles?");
11617 presContext
->SetProcessingRestyles(PR_TRUE
);
11619 mPendingRestyles
.ProcessRestyles();
11622 PRUint32 oldPendingRestyleCount
= mPendingRestyles
.Count();
11625 // ...and then process animation restyles. This needs to happen
11626 // second because we need to start animations that resulted from the
11627 // first set of restyles (e.g., CSS transitions with negative
11628 // transition-delay), and because we need to immediately
11629 // restyle-with-animation any just-restyled elements that are
11630 // mid-transition (since processing the non-animation restyle ignores
11631 // the running transition so it can check for a new change on the same
11632 // property, and then posts an immediate animation style change).
11633 presContext
->SetProcessingAnimationStyleChange(PR_TRUE
);
11634 mPendingAnimationRestyles
.ProcessRestyles();
11635 presContext
->SetProcessingAnimationStyleChange(PR_FALSE
);
11637 presContext
->SetProcessingRestyles(PR_FALSE
);
11638 NS_POSTCONDITION(mPendingRestyles
.Count() == oldPendingRestyleCount
,
11639 "We should not have posted new non-animation restyles while "
11640 "processing animation restyles");
11642 if (mRebuildAllStyleData
) {
11643 // We probably wasted a lot of work up above, but this seems safest
11644 // and it should be rarely used.
11645 // This might add us as a refresh observer again; that's ok.
11646 RebuildAllStyleData(nsChangeHint(0));
11651 nsCSSFrameConstructor::PostRestyleEventCommon(Element
* aElement
,
11652 nsRestyleHint aRestyleHint
,
11653 nsChangeHint aMinChangeHint
,
11654 PRBool aForAnimation
)
11656 if (NS_UNLIKELY(mPresShell
->IsDestroying())) {
11660 if (aRestyleHint
== 0 && !aMinChangeHint
) {
11661 // Nothing to do here
11665 RestyleTracker
& tracker
=
11666 aForAnimation
? mPendingAnimationRestyles
: mPendingRestyles
;
11667 tracker
.AddPendingRestyle(aElement
, aRestyleHint
, aMinChangeHint
);
11669 PostRestyleEventInternal(PR_FALSE
);
11673 nsCSSFrameConstructor::PostRestyleEventInternal(PRBool aForLazyConstruction
)
11675 // Make sure we're not in a style refresh; if we are, we still have
11676 // a call to ProcessPendingRestyles coming and there's no need to
11677 // add ourselves as a refresh observer until then.
11678 PRBool inRefresh
= !aForLazyConstruction
&& mInStyleRefresh
;
11679 if (!mObservingRefreshDriver
&& !inRefresh
) {
11680 mObservingRefreshDriver
= mPresShell
->GetPresContext()->RefreshDriver()->
11681 AddStyleFlushObserver(mPresShell
);
11686 nsCSSFrameConstructor::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint
)
11688 NS_ASSERTION(!(aExtraHint
& nsChangeHint_ReconstructFrame
),
11689 "Should not reconstruct the root of the frame tree. "
11690 "Use ReconstructDocElementHierarchy instead.");
11692 mRebuildAllStyleData
= PR_TRUE
;
11693 NS_UpdateHint(mRebuildAllExtraHint
, aExtraHint
);
11694 // Get a restyle event posted if necessary
11695 PostRestyleEventInternal(PR_FALSE
);
11699 nsCSSFrameConstructor::GenerateChildFrames(nsIFrame
* aFrame
)
11702 nsAutoScriptBlocker scriptBlocker
;
11705 nsFrameItems childItems
;
11706 nsFrameConstructorState
state(mPresShell
, nsnull
, nsnull
, nsnull
);
11707 // We don't have a parent frame with a pending binding constructor here,
11708 // so no need to worry about ordering of the kids' constructors with it.
11709 // Pass null for the PendingBinding.
11710 nsresult rv
= ProcessChildren(state
, aFrame
->GetContent(), aFrame
->GetStyleContext(),
11711 aFrame
, PR_FALSE
, childItems
, PR_FALSE
,
11713 if (NS_FAILED(rv
)) {
11718 aFrame
->SetInitialChildList(nsnull
, childItems
);
11723 // call XBL constructors after the frames are created
11724 mPresShell
->GetDocument()->BindingManager()->ProcessAttachedQueue();
11729 //////////////////////////////////////////////////////////
11730 // nsCSSFrameConstructor::FrameConstructionItem methods //
11731 //////////////////////////////////////////////////////////
11733 nsCSSFrameConstructor::
11734 FrameConstructionItem::IsWhitespace(nsFrameConstructorState
& aState
) const
11736 NS_PRECONDITION(aState
.mCreatingExtraFrames
||
11737 !mContent
->GetPrimaryFrame(), "How did that happen?");
11741 mContent
->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE
|
11742 NS_REFRAME_IF_WHITESPACE
);
11743 return mContent
->TextIsOnlyWhitespace();
11746 //////////////////////////////////////////////////////////////
11747 // nsCSSFrameConstructor::FrameConstructionItemList methods //
11748 //////////////////////////////////////////////////////////////
11750 nsCSSFrameConstructor::FrameConstructionItemList::
11751 AdjustCountsForItem(FrameConstructionItem
* aItem
, PRInt32 aDelta
)
11753 NS_PRECONDITION(aDelta
== 1 || aDelta
== -1, "Unexpected delta");
11754 mItemCount
+= aDelta
;
11755 if (aItem
->mIsAllInline
) {
11756 mInlineCount
+= aDelta
;
11758 if (aItem
->mIsBlock
) {
11759 mBlockCount
+= aDelta
;
11761 if (aItem
->mIsLineParticipant
) {
11762 mLineParticipantCount
+= aDelta
;
11764 mDesiredParentCounts
[aItem
->DesiredParentType()] += aDelta
;
11767 ////////////////////////////////////////////////////////////////////////
11768 // nsCSSFrameConstructor::FrameConstructionItemList::Iterator methods //
11769 ////////////////////////////////////////////////////////////////////////
11771 nsCSSFrameConstructor::FrameConstructionItemList::
11772 Iterator::SkipItemsWantingParentType(ParentType aParentType
)
11774 NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
11775 while (item().DesiredParentType() == aParentType
) {
11785 nsCSSFrameConstructor::FrameConstructionItemList::
11786 Iterator::SkipWhitespace(nsFrameConstructorState
& aState
)
11788 NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
11789 NS_PRECONDITION(item().IsWhitespace(aState
), "Not pointing to whitespace?");
11795 } while (item().IsWhitespace(aState
));
11801 nsCSSFrameConstructor::FrameConstructionItemList::
11802 Iterator::AppendItemToList(FrameConstructionItemList
& aTargetList
)
11804 NS_ASSERTION(&aTargetList
!= &mList
, "Unexpected call");
11805 NS_PRECONDITION(!IsDone(), "should not be done");
11807 FrameConstructionItem
* item
= ToItem(mCurrent
);
11809 PR_REMOVE_LINK(item
);
11810 PR_APPEND_LINK(item
, &aTargetList
.mItems
);
11812 mList
.AdjustCountsForItem(item
, -1);
11813 aTargetList
.AdjustCountsForItem(item
, 1);
11817 nsCSSFrameConstructor::FrameConstructionItemList::
11818 Iterator::AppendItemsToList(const Iterator
& aEnd
,
11819 FrameConstructionItemList
& aTargetList
)
11821 NS_ASSERTION(&aTargetList
!= &mList
, "Unexpected call");
11822 NS_PRECONDITION(mEnd
== aEnd
.mEnd
, "end iterator for some other list?");
11824 if (!AtStart() || !aEnd
.IsDone() || !aTargetList
.IsEmpty()) {
11826 AppendItemToList(aTargetList
);
11827 } while (*this != aEnd
);
11831 // move over the list of items
11832 PR_INSERT_AFTER(&aTargetList
.mItems
, &mList
.mItems
);
11833 PR_REMOVE_LINK(&mList
.mItems
);
11835 // Copy over the various counters
11836 aTargetList
.mInlineCount
= mList
.mInlineCount
;
11837 aTargetList
.mBlockCount
= mList
.mBlockCount
;
11838 aTargetList
.mLineParticipantCount
= mList
.mLineParticipantCount
;
11839 aTargetList
.mItemCount
= mList
.mItemCount
;
11840 memcpy(aTargetList
.mDesiredParentCounts
, mList
.mDesiredParentCounts
,
11841 sizeof(aTargetList
.mDesiredParentCounts
));
11844 new (&mList
) FrameConstructionItemList();
11846 // Point ourselves to aEnd, as advertised
11847 mCurrent
= mEnd
= &mList
.mItems
;
11848 NS_POSTCONDITION(*this == aEnd
, "How did that happen?");
11852 nsCSSFrameConstructor::FrameConstructionItemList::
11853 Iterator::InsertItem(FrameConstructionItem
* aItem
)
11855 // Just insert the item before us. There's no magic here.
11856 PR_INSERT_BEFORE(aItem
, mCurrent
);
11857 mList
.AdjustCountsForItem(aItem
, 1);
11859 NS_POSTCONDITION(PR_NEXT_LINK(aItem
) == mCurrent
, "How did that happen?");
11863 nsCSSFrameConstructor::FrameConstructionItemList::
11864 Iterator::DeleteItemsTo(const Iterator
& aEnd
)
11866 NS_PRECONDITION(mEnd
== aEnd
.mEnd
, "end iterator for some other list?");
11867 NS_PRECONDITION(*this != aEnd
, "Shouldn't be at aEnd yet");
11870 NS_ASSERTION(!IsDone(), "Ran off end of list?");
11871 FrameConstructionItem
* item
= ToItem(mCurrent
);
11873 PR_REMOVE_LINK(item
);
11874 mList
.AdjustCountsForItem(item
, -1);
11876 } while (*this != aEnd
);