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"
133 #include "nsIAccessibleEvent.h"
136 #include "nsInlineFrame.h"
137 #include "nsBlockFrame.h"
139 #include "nsIScrollableFrame.h"
141 #include "nsIXBLService.h"
143 #undef NOISY_FIRST_LETTER
146 #include "nsMathMLParts.h"
149 #include "nsSVGFeatures.h"
150 #include "nsSVGEffects.h"
151 #include "nsSVGUtils.h"
152 #include "nsSVGOuterSVGFrame.h"
155 #include "nsRefreshDriver.h"
157 using namespace mozilla
;
158 using namespace mozilla::dom
;
161 NS_NewHTMLCanvasFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
163 #if defined(MOZ_MEDIA)
165 NS_NewHTMLVideoFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
169 #include "nsSVGTextContainerFrame.h"
174 NS_NewSVGOuterSVGFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
176 NS_NewSVGInnerSVGFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
178 NS_NewSVGPathGeometryFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
180 NS_NewSVGGFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
182 NS_NewSVGGenericContainerFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
184 NS_NewSVGForeignObjectFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
186 NS_NewSVGAFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
188 NS_NewSVGGlyphFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
190 NS_NewSVGSwitchFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
192 NS_NewSVGTextFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
194 NS_NewSVGTSpanFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
196 NS_NewSVGContainerFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
198 NS_NewSVGUseFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
200 NS_NewSVGLinearGradientFrame(nsIPresShell
*aPresShell
, nsStyleContext
* aContext
);
202 NS_NewSVGRadialGradientFrame(nsIPresShell
*aPresShell
, nsStyleContext
* aContext
);
204 NS_NewSVGStopFrame(nsIPresShell
*aPresShell
, nsStyleContext
* aContext
);
206 NS_NewSVGMarkerFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
208 NS_NewSVGImageFrame(nsIPresShell
*aPresShell
, nsStyleContext
* aContext
);
210 NS_NewSVGClipPathFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
212 NS_NewSVGTextPathFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
214 NS_NewSVGFilterFrame(nsIPresShell
*aPresShell
, nsStyleContext
* aContext
);
216 NS_NewSVGPatternFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
218 NS_NewSVGMaskFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
220 NS_NewSVGLeafFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
223 #include "nsIDocument.h"
224 #include "nsIDOMElement.h"
225 #include "nsIDOMNodeList.h"
226 #include "nsIDOMDocument.h"
227 #include "nsIDOMDocumentXBL.h"
228 #include "nsIScrollable.h"
229 #include "nsINodeInfo.h"
231 #include "nsWidgetsCID.h"
232 #include "nsNodeInfoManager.h"
233 #include "nsContentCreatorFunctions.h"
234 #include "nsIServiceManager.h"
236 // Global object maintenance
237 nsIXBLService
* nsCSSFrameConstructor::gXBLService
= nsnull
;
240 // Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or
241 // more of the following flags (comma separated) for handy debug
243 static PRBool gNoisyContentUpdates
= PR_FALSE
;
244 static PRBool gReallyNoisyContentUpdates
= PR_FALSE
;
245 static PRBool gNoisyInlineConstruction
= PR_FALSE
;
247 struct FrameCtorDebugFlags
{
252 static FrameCtorDebugFlags gFlags
[] = {
253 { "content-updates", &gNoisyContentUpdates
},
254 { "really-noisy-content-updates", &gReallyNoisyContentUpdates
},
255 { "noisy-inline", &gNoisyInlineConstruction
}
258 #define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
263 #include "nsMenuFrame.h"
264 #include "nsMenuPopupFrame.h"
265 #include "nsPopupSetFrame.h"
266 #include "nsTreeColFrame.h"
267 #include "nsIBoxObject.h"
268 #include "nsPIListBoxObject.h"
269 #include "nsListBoxBodyFrame.h"
270 #include "nsListItemFrame.h"
271 #include "nsXULLabelFrame.h"
273 //------------------------------------------------------------------
276 NS_NewAutoRepeatBoxFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
279 NS_NewRootBoxFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
282 NS_NewDocElementBoxFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
285 NS_NewThumbFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
288 NS_NewDeckFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
291 NS_NewLeafBoxFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
294 NS_NewStackFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
297 NS_NewProgressMeterFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
300 NS_NewImageBoxFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
303 NS_NewTextBoxFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
306 NS_NewGroupBoxFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
309 NS_NewButtonBoxFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
312 NS_NewSplitterFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
315 NS_NewMenuPopupFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
318 NS_NewPopupSetFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
321 NS_NewMenuFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
, PRUint32 aFlags
);
324 NS_NewMenuBarFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
327 NS_NewTreeBodyFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
331 NS_NewGridLayout2 ( nsIPresShell
* aPresShell
, nsIBoxLayout
** aNewLayout
);
333 NS_NewGridRowLeafFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
335 NS_NewGridRowGroupFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
340 NS_NewTitleBarFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
343 NS_NewResizerFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
349 NS_NewHTMLScrollFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
, PRBool aIsRoot
);
352 NS_NewXULScrollFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
, PRBool aIsRoot
);
355 NS_NewSliderFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
358 NS_NewScrollbarFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
361 NS_NewScrollbarButtonFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
364 #ifdef NOISY_FINDFRAME
365 static PRInt32 FFWC_totalCount
=0;
366 static PRInt32 FFWC_doLoop
=0;
367 static PRInt32 FFWC_doSibling
=0;
368 static PRInt32 FFWC_recursions
=0;
369 static PRInt32 FFWC_nextInFlows
=0;
372 static inline nsIFrame
*
373 GetFieldSetBlockFrame(nsIFrame
* aFieldsetFrame
)
375 // Depends on the fieldset child frame order - see ConstructFieldSetFrame() below.
376 nsIFrame
* firstChild
= aFieldsetFrame
->GetFirstChild(nsnull
);
377 return firstChild
&& firstChild
->GetNextSibling() ? firstChild
->GetNextSibling() : firstChild
;
380 #define FCDATA_DECL(_flags, _func) \
381 { _flags, { (FrameCreationFunc)_func } }
383 //----------------------------------------------------------------------
386 IsInlineOutside(nsIFrame
* aFrame
)
388 return aFrame
->GetStyleDisplay()->IsInlineOutside();
392 * True if aFrame is an actual inline frame in the sense of non-replaced
393 * display:inline CSS boxes. In other words, it can be affected by {ib}
394 * splitting and can contain first-letter frames. Basically, this is either an
395 * inline frame (positioned or otherwise) or an line frame (this last because
396 * it can contain first-letter and because inserting blocks in the middle of it
397 * needs to terminate it).
400 IsInlineFrame(const nsIFrame
* aFrame
)
402 return aFrame
->IsFrameOfType(nsIFrame::eLineParticipant
);
406 * If any children require a block parent, return the first such child.
407 * Otherwise return null.
410 AnyKidsNeedBlockParent(nsIFrame
*aFrameList
)
412 for (nsIFrame
*k
= aFrameList
; k
; k
= k
->GetNextSibling()) {
413 // Line participants, such as text and inline frames, can't be
414 // directly inside a XUL box; they must be wrapped in an
415 // intermediate block.
416 if (k
->IsFrameOfType(nsIFrame::eLineParticipant
)) {
417 return k
->GetContent();
423 // Reparent a frame into a wrapper frame that is a child of its old parent.
425 ReparentFrame(nsFrameManager
* aFrameManager
,
426 nsIFrame
* aNewParentFrame
,
429 aFrame
->SetParent(aNewParentFrame
);
430 aFrameManager
->ReparentStyleContext(aFrame
);
434 ReparentFrames(nsFrameManager
* aFrameManager
,
435 nsIFrame
* aNewParentFrame
,
436 const nsFrameList
& aFrameList
)
438 for (nsFrameList::Enumerator
e(aFrameList
); !e
.AtEnd(); e
.Next()) {
439 ReparentFrame(aFrameManager
, aNewParentFrame
, e
.get());
443 //----------------------------------------------------------------------
445 // When inline frames get weird and have block frames in them, we
446 // annotate them to help us respond to incremental content changes
450 IsFrameSpecial(nsIFrame
* aFrame
)
452 return (aFrame
->GetStateBits() & NS_FRAME_IS_SPECIAL
) != 0;
455 static nsIFrame
* GetSpecialSibling(nsIFrame
* aFrame
)
457 NS_PRECONDITION(IsFrameSpecial(aFrame
), "Shouldn't call this");
459 // We only store the "special sibling" annotation with the first
460 // frame in the continuation chain. Walk back to find that frame now.
461 return static_cast<nsIFrame
*>
462 (aFrame
->GetFirstContinuation()->
463 Properties().Get(nsIFrame::IBSplitSpecialSibling()));
466 static nsIFrame
* GetSpecialPrevSibling(nsIFrame
* aFrame
)
468 NS_PRECONDITION(IsFrameSpecial(aFrame
), "Shouldn't call this");
470 // We only store the "special sibling" annotation with the first
471 // frame in the continuation chain. Walk back to find that frame now.
472 return static_cast<nsIFrame
*>
473 (aFrame
->GetFirstContinuation()->
474 Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
478 GetLastSpecialSibling(nsIFrame
* aFrame
, PRBool aReturnEmptyTrailingInline
)
480 for (nsIFrame
*frame
= aFrame
, *next
; ; frame
= next
) {
481 next
= GetSpecialSibling(frame
);
483 (!aReturnEmptyTrailingInline
&& !next
->GetFirstChild(nsnull
) &&
484 !GetSpecialSibling(next
))) {
485 NS_ASSERTION(!next
|| !IsInlineOutside(frame
),
486 "Should have a block here!");
490 NS_NOTREACHED("unreachable code");
495 SetFrameIsSpecial(nsIFrame
* aFrame
, nsIFrame
* aSpecialSibling
)
497 NS_PRECONDITION(aFrame
, "bad args!");
499 // We should be the only continuation
500 NS_ASSERTION(!aFrame
->GetPrevContinuation(),
501 "assigning special sibling to other than first continuation!");
502 NS_ASSERTION(!aFrame
->GetNextContinuation() ||
503 IsFrameSpecial(aFrame
->GetNextContinuation()),
504 "should have no non-special continuations here");
506 // Mark the frame as "special".
507 aFrame
->AddStateBits(NS_FRAME_IS_SPECIAL
);
509 if (aSpecialSibling
) {
510 NS_ASSERTION(!aSpecialSibling
->GetPrevContinuation(),
511 "assigning something other than the first continuation as the "
514 // Store the "special sibling" (if we were given one) with the
515 // first frame in the flow.
516 FramePropertyTable
* props
= aFrame
->PresContext()->PropertyTable();
517 props
->Set(aFrame
, nsIFrame::IBSplitSpecialSibling(), aSpecialSibling
);
518 props
->Set(aSpecialSibling
, nsIFrame::IBSplitSpecialPrevSibling(), aFrame
);
523 GetIBContainingBlockFor(nsIFrame
* aFrame
)
525 NS_PRECONDITION(IsFrameSpecial(aFrame
),
526 "GetIBContainingBlockFor() should only be called on known IB frames");
528 // Get the first "normal" ancestor of the target frame.
529 nsIFrame
* parentFrame
;
531 parentFrame
= aFrame
->GetParent();
534 NS_ERROR("no unsplit block frame in IB hierarchy");
538 // Note that we ignore non-special frames which have a pseudo on their
539 // style context -- they're not the frames we're looking for! In
540 // particular, they may be hiding a real parent that _is_ special.
541 if (!IsFrameSpecial(parentFrame
) &&
542 !parentFrame
->GetStyleContext()->GetPseudo())
545 aFrame
= parentFrame
;
549 NS_ASSERTION(parentFrame
, "no normal ancestor found for special frame in GetIBContainingBlockFor");
550 NS_ASSERTION(parentFrame
!= aFrame
, "parentFrame is actually the child frame - bogus reslt");
555 //----------------------------------------------------------------------
557 // Block/inline frame construction logic. We maintain a few invariants here:
559 // 1. Block frames contain block and inline frames.
561 // 2. Inline frames only contain inline frames. If an inline parent has a block
562 // child then the block child is migrated upward until it lands in a block
563 // parent (the inline frames containing block is where it will end up).
565 // After this function returns, aLink is pointing to the first link at or
566 // after its starting position for which the next frame is a block. If there
567 // is no such link, it points to the end of the list.
569 FindFirstBlock(nsFrameList::FrameLinkEnumerator
& aLink
)
571 for ( ; !aLink
.AtEnd(); aLink
.Next()) {
572 if (!IsInlineOutside(aLink
.NextFrame())) {
578 // This function returns a frame link enumerator pointing to the first link in
579 // the list for which the next frame is not block. If there is no such link,
580 // it points to the end of the list.
581 static nsFrameList::FrameLinkEnumerator
582 FindFirstNonBlock(const nsFrameList
& aList
)
584 nsFrameList::FrameLinkEnumerator
link(aList
);
585 for (; !link
.AtEnd(); link
.Next()) {
586 if (IsInlineOutside(link
.NextFrame())) {
594 SetInitialSingleChild(nsIFrame
* aParent
, nsIFrame
* aFrame
)
596 NS_PRECONDITION(!aFrame
->GetNextSibling(), "Should be using a frame list");
597 nsFrameList
temp(aFrame
, aFrame
);
598 aParent
->SetInitialChildList(nsnull
, temp
);
601 // -----------------------------------------------------------
603 // Structure used when constructing formatting object trees.
604 struct nsFrameItems
: public nsFrameList
606 // Appends the frame to the end of the list
607 void AddChild(nsIFrame
* aChild
);
611 nsFrameItems::AddChild(nsIFrame
* aChild
)
613 NS_PRECONDITION(aChild
, "nsFrameItems::AddChild");
615 // It'd be really nice if we could just AppendFrames(nsnull, aChild) here,
616 // but some of our callers put frames that have different
617 // parents (caption, I'm looking at you) on the same framelist, and
618 // nsFrameList asserts if you try to do that.
623 NS_ASSERTION(aChild
!= mLastChild
,
624 "Same frame being added to frame list twice?");
625 mLastChild
->SetNextSibling(aChild
);
626 mLastChild
= nsLayoutUtils::GetLastSibling(aChild
);
630 // -----------------------------------------------------------
632 // Structure used when constructing formatting object trees. Contains
633 // state information needed for absolutely positioned elements
634 struct nsAbsoluteItems
: nsFrameItems
{
635 // containing block for absolutely positioned elements
636 nsIFrame
* containingBlock
;
638 nsAbsoluteItems(nsIFrame
* aContainingBlock
);
640 // XXXbz Does this need a debug-only assignment operator that nulls out the
641 // childList in the nsAbsoluteItems we're copying? Introducing a difference
642 // between debug and non-debug behavior seems bad, so I guess not...
644 NS_ASSERTION(!FirstChild(),
645 "Dangling child list. Someone forgot to insert it?");
649 // Appends the frame to the end of the list
650 void AddChild(nsIFrame
* aChild
);
653 nsAbsoluteItems::nsAbsoluteItems(nsIFrame
* aContainingBlock
)
654 : containingBlock(aContainingBlock
)
658 // Additional behavior is that it sets the frame's NS_FRAME_OUT_OF_FLOW flag
660 nsAbsoluteItems::AddChild(nsIFrame
* aChild
)
662 NS_ASSERTION(aChild
->PresContext()->FrameManager()->
663 GetPlaceholderFrameFor(aChild
),
664 "Child without placeholder being added to nsAbsoluteItems?");
665 aChild
->AddStateBits(NS_FRAME_OUT_OF_FLOW
);
666 nsFrameItems::AddChild(aChild
);
669 // -----------------------------------------------------------
671 // Structure for saving the existing state when pushing/poping containing
672 // blocks. The destructor restores the state to its previous state
673 class NS_STACK_CLASS nsFrameConstructorSaveState
{
675 nsFrameConstructorSaveState();
676 ~nsFrameConstructorSaveState();
679 nsAbsoluteItems
* mItems
; // pointer to struct whose data we save/restore
680 PRPackedBool
* mFixedPosIsAbsPos
;
682 nsAbsoluteItems mSavedItems
; // copy of original data
683 PRPackedBool mSavedFixedPosIsAbsPos
;
685 // The name of the child list in which our frames would belong
686 nsIAtom
* mChildListName
;
687 nsFrameConstructorState
* mState
;
689 friend class nsFrameConstructorState
;
692 // Structure used to keep track of a list of bindings we need to call
693 // AddToAttachedQueue on. These should be in post-order depth-first
694 // flattened tree traversal order.
695 struct PendingBinding
: public PRCList
697 #ifdef NS_BUILD_REFCNT_LOGGING
699 MOZ_COUNT_CTOR(PendingBinding
);
702 MOZ_COUNT_DTOR(PendingBinding
);
706 nsRefPtr
<nsXBLBinding
> mBinding
;
709 // Structure used for maintaining state information during the
710 // frame construction process
711 class NS_STACK_CLASS nsFrameConstructorState
{
713 nsPresContext
*mPresContext
;
714 nsIPresShell
*mPresShell
;
715 nsFrameManager
*mFrameManager
;
718 // Frames destined for the nsGkAtoms::popupList.
719 nsAbsoluteItems mPopupItems
;
722 // Containing block information for out-of-flow frames.
723 nsAbsoluteItems mFixedItems
;
724 nsAbsoluteItems mAbsoluteItems
;
725 nsAbsoluteItems mFloatedItems
;
727 nsCOMPtr
<nsILayoutHistoryState
> mFrameState
;
728 // These bits will be added to the state bits of any frame we construct
730 nsFrameState mAdditionalStateBits
;
732 // When working with the -moz-transform property, we want to hook
733 // the abs-pos and fixed-pos lists together, since transformed
734 // elements are fixed-pos containing blocks. This flag determines
735 // whether or not we want to wire the fixed-pos and abs-pos lists
737 PRPackedBool mFixedPosIsAbsPos
;
739 // A boolean to indicate whether we have a "pending" popupgroup. That is, we
740 // have already created the FrameConstructionItem for the root popupgroup but
741 // we have not yet created the relevant frame.
742 PRPackedBool mHavePendingPopupgroup
;
744 // If true (which is the default) then call SetPrimaryFrame() as needed
745 // during frame construction. If false, don't make any SetPrimaryFrame()
746 // calls. The mSetPrimaryFrames == PR_FALSE mode is meant to be used for
747 // construction of random "extra" frames for elements via normal frame
748 // construction APIs (e.g. replication of things across pages in paginated
750 PRPackedBool mSetPrimaryFrames
;
752 nsCOMArray
<nsIContent
> mGeneratedTextNodesWithInitializer
;
755 // Use the passed-in history state.
756 nsFrameConstructorState(nsIPresShell
* aPresShell
,
757 nsIFrame
* aFixedContainingBlock
,
758 nsIFrame
* aAbsoluteContainingBlock
,
759 nsIFrame
* aFloatContainingBlock
,
760 nsILayoutHistoryState
* aHistoryState
);
761 // Get the history state from the pres context's pres shell.
762 nsFrameConstructorState(nsIPresShell
* aPresShell
,
763 nsIFrame
* aFixedContainingBlock
,
764 nsIFrame
* aAbsoluteContainingBlock
,
765 nsIFrame
* aFloatContainingBlock
);
767 ~nsFrameConstructorState();
769 // Function to push the existing absolute containing block state and
770 // create a new scope. Code that uses this function should get matching
771 // logic in GetAbsoluteContainingBlock.
772 void PushAbsoluteContainingBlock(nsIFrame
* aNewAbsoluteContainingBlock
,
773 nsFrameConstructorSaveState
& aSaveState
);
775 // Function to push the existing float containing block state and
776 // create a new scope. Code that uses this function should get matching
777 // logic in GetFloatContainingBlock.
778 // Pushing a null float containing block forbids any frames from being
779 // floated until a new float containing block is pushed.
780 // XXX we should get rid of null float containing blocks and teach the
781 // various frame classes to deal with floats instead.
782 void PushFloatContainingBlock(nsIFrame
* aNewFloatContainingBlock
,
783 nsFrameConstructorSaveState
& aSaveState
);
785 // Function to return the proper geometric parent for a frame with display
786 // struct given by aStyleDisplay and parent's frame given by
787 // aContentParentFrame.
788 nsIFrame
* GetGeometricParent(const nsStyleDisplay
* aStyleDisplay
,
789 nsIFrame
* aContentParentFrame
);
792 * Function to add a new frame to the right frame list. This MUST be called
793 * on frames before their children have been processed if the frames might
794 * conceivably be out-of-flow; otherwise cleanup in error cases won't work
795 * right. Also, this MUST be called on frames after they have been
797 * @param aNewFrame the frame to add
798 * @param aFrameItems the list to add in-flow frames to
799 * @param aContent the content pointer for aNewFrame
800 * @param aStyleContext the style context resolved for aContent
801 * @param aParentFrame the parent frame for the content if it were in-flow
802 * @param aCanBePositioned pass false if the frame isn't allowed to be
804 * @param aCanBeFloated pass false if the frame isn't allowed to be
806 * @param aIsOutOfFlowPopup pass true if the frame is an out-of-flow popup
808 * @throws NS_ERROR_OUT_OF_MEMORY if it happens.
809 * @note If this method throws, that means that aNewFrame was not inserted
810 * into any frame lists. Furthermore, this method will handle cleanup
811 * of aNewFrame (via calling Destroy() on it).
813 nsresult
AddChild(nsIFrame
* aNewFrame
,
814 nsFrameItems
& aFrameItems
,
815 nsIContent
* aContent
,
816 nsStyleContext
* aStyleContext
,
817 nsIFrame
* aParentFrame
,
818 PRBool aCanBePositioned
= PR_TRUE
,
819 PRBool aCanBeFloated
= PR_TRUE
,
820 PRBool aIsOutOfFlowPopup
= PR_FALSE
,
821 PRBool aInsertAfter
= PR_FALSE
,
822 nsIFrame
* aInsertAfterFrame
= nsnull
);
825 * Function to return the fixed-pos element list. Normally this will just hand back the
826 * fixed-pos element list, but in case we're dealing with a transformed element that's
827 * acting as an abs-pos and fixed-pos container, we'll hand back the abs-pos list. Callers should
828 * use this function if they want to get the list acting as the fixed-pos item parent.
830 nsAbsoluteItems
& GetFixedItems()
832 return mFixedPosIsAbsPos
? mAbsoluteItems
: mFixedItems
;
834 const nsAbsoluteItems
& GetFixedItems() const
836 return mFixedPosIsAbsPos
? mAbsoluteItems
: mFixedItems
;
841 * class to automatically push and pop a pending binding in the frame
842 * constructor state. See nsCSSFrameConstructor::FrameConstructionItem
843 * mPendingBinding documentation.
845 class PendingBindingAutoPusher
;
846 friend class PendingBindingAutoPusher
;
847 class NS_STACK_CLASS PendingBindingAutoPusher
{
849 PendingBindingAutoPusher(nsFrameConstructorState
& aState
,
850 PendingBinding
* aPendingBinding
) :
852 mPendingBinding(aState
.mCurrentPendingBindingInsertionPoint
)
854 NS_PRECONDITION(mPendingBinding
, "how did that happen?");
855 if (aPendingBinding
) {
856 aState
.mCurrentPendingBindingInsertionPoint
= aPendingBinding
;
860 ~PendingBindingAutoPusher()
862 mState
.mCurrentPendingBindingInsertionPoint
= mPendingBinding
;
866 nsFrameConstructorState
& mState
;
867 PRCList
* mPendingBinding
;
871 * Add a new pending binding to the list
873 void AddPendingBinding(PendingBinding
* aPendingBinding
) {
874 PR_INSERT_BEFORE(aPendingBinding
, mCurrentPendingBindingInsertionPoint
);
878 friend class nsFrameConstructorSaveState
;
881 * ProcessFrameInsertions takes the frames in aFrameItems and adds them as
882 * kids to the aChildListName child list of |aFrameItems.containingBlock|.
884 void ProcessFrameInsertions(nsAbsoluteItems
& aFrameItems
,
885 nsIAtom
* aChildListName
);
887 // Our list of all pending bindings. When we're done, we need to call
888 // AddToAttachedQueue on all of them, in order.
889 PRCList mPendingBindings
;
891 PRCList
* mCurrentPendingBindingInsertionPoint
;
894 nsFrameConstructorState::nsFrameConstructorState(nsIPresShell
* aPresShell
,
895 nsIFrame
* aFixedContainingBlock
,
896 nsIFrame
* aAbsoluteContainingBlock
,
897 nsIFrame
* aFloatContainingBlock
,
898 nsILayoutHistoryState
* aHistoryState
)
899 : mPresContext(aPresShell
->GetPresContext()),
900 mPresShell(aPresShell
),
901 mFrameManager(aPresShell
->FrameManager()),
905 mFixedItems(aFixedContainingBlock
),
906 mAbsoluteItems(aAbsoluteContainingBlock
),
907 mFloatedItems(aFloatContainingBlock
),
908 // See PushAbsoluteContaningBlock below
909 mFrameState(aHistoryState
),
910 mAdditionalStateBits(0),
911 mFixedPosIsAbsPos(aAbsoluteContainingBlock
&&
912 aAbsoluteContainingBlock
->GetStyleDisplay()->
914 mHavePendingPopupgroup(PR_FALSE
),
915 mSetPrimaryFrames(PR_TRUE
),
916 mCurrentPendingBindingInsertionPoint(&mPendingBindings
)
919 nsIRootBox
* rootBox
= nsIRootBox::GetRootBox(aPresShell
);
921 mPopupItems
.containingBlock
= rootBox
->GetPopupSetFrame();
924 MOZ_COUNT_CTOR(nsFrameConstructorState
);
925 PR_INIT_CLIST(&mPendingBindings
);
928 nsFrameConstructorState::nsFrameConstructorState(nsIPresShell
* aPresShell
,
929 nsIFrame
* aFixedContainingBlock
,
930 nsIFrame
* aAbsoluteContainingBlock
,
931 nsIFrame
* aFloatContainingBlock
)
932 : mPresContext(aPresShell
->GetPresContext()),
933 mPresShell(aPresShell
),
934 mFrameManager(aPresShell
->FrameManager()),
938 mFixedItems(aFixedContainingBlock
),
939 mAbsoluteItems(aAbsoluteContainingBlock
),
940 mFloatedItems(aFloatContainingBlock
),
941 // See PushAbsoluteContaningBlock below
942 mAdditionalStateBits(0),
943 mFixedPosIsAbsPos(aAbsoluteContainingBlock
&&
944 aAbsoluteContainingBlock
->GetStyleDisplay()->
946 mHavePendingPopupgroup(PR_FALSE
),
947 mSetPrimaryFrames(PR_TRUE
),
948 mCurrentPendingBindingInsertionPoint(&mPendingBindings
)
951 nsIRootBox
* rootBox
= nsIRootBox::GetRootBox(aPresShell
);
953 mPopupItems
.containingBlock
= rootBox
->GetPopupSetFrame();
956 MOZ_COUNT_CTOR(nsFrameConstructorState
);
957 mFrameState
= aPresShell
->GetDocument()->GetLayoutHistoryState();
958 PR_INIT_CLIST(&mPendingBindings
);
961 nsFrameConstructorState::~nsFrameConstructorState()
963 // Frame order comparison functions only work properly when the placeholders
964 // have been inserted into the frame tree. So for example if we have a new float
965 // containing the placeholder for a new abs-pos frame, and we process the abs-pos
966 // insertion first, then we won't be able to find the right place to insert in
967 // in the abs-pos list. So put floats in first, because they can contain placeholders
968 // for abs-pos and fixed-pos items whose containing blocks are outside the floats.
969 // Then put abs-pos frames in, because they can contain placeholders for fixed-pos
970 // items whose containing block is outside the abs-pos frames.
971 MOZ_COUNT_DTOR(nsFrameConstructorState
);
972 ProcessFrameInsertions(mFloatedItems
, nsGkAtoms::floatList
);
973 ProcessFrameInsertions(mAbsoluteItems
, nsGkAtoms::absoluteList
);
974 ProcessFrameInsertions(mFixedItems
, nsGkAtoms::fixedList
);
976 ProcessFrameInsertions(mPopupItems
, nsGkAtoms::popupList
);
978 for (PRInt32 i
= mGeneratedTextNodesWithInitializer
.Count() - 1; i
>= 0; --i
) {
979 mGeneratedTextNodesWithInitializer
[i
]->
980 DeleteProperty(nsGkAtoms::genConInitializerProperty
);
982 if (!PR_CLIST_IS_EMPTY(&mPendingBindings
)) {
983 nsBindingManager
* bindingManager
= mPresShell
->GetDocument()->BindingManager();
985 PendingBinding
* pendingBinding
=
986 static_cast<PendingBinding
*>(PR_NEXT_LINK(&mPendingBindings
));
987 PR_REMOVE_LINK(pendingBinding
);
988 bindingManager
->AddToAttachedQueue(pendingBinding
->mBinding
);
989 delete pendingBinding
;
990 } while (!PR_CLIST_IS_EMPTY(&mPendingBindings
));
995 AdjustAbsoluteContainingBlock(nsIFrame
* aContainingBlockIn
)
997 if (!aContainingBlockIn
) {
1001 // Always use the container's first continuation. (Inline frames can have
1002 // non-fluid bidi continuations...)
1003 return aContainingBlockIn
->GetFirstContinuation();
1007 nsFrameConstructorState::PushAbsoluteContainingBlock(nsIFrame
* aNewAbsoluteContainingBlock
,
1008 nsFrameConstructorSaveState
& aSaveState
)
1010 aSaveState
.mItems
= &mAbsoluteItems
;
1011 aSaveState
.mSavedItems
= mAbsoluteItems
;
1012 aSaveState
.mChildListName
= nsGkAtoms::absoluteList
;
1013 aSaveState
.mState
= this;
1015 /* Store whether we're wiring the abs-pos and fixed-pos lists together. */
1016 aSaveState
.mFixedPosIsAbsPos
= &mFixedPosIsAbsPos
;
1017 aSaveState
.mSavedFixedPosIsAbsPos
= mFixedPosIsAbsPos
;
1020 nsAbsoluteItems(AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock
));
1022 /* See if we're wiring the fixed-pos and abs-pos lists together. This happens iff
1023 * we're a transformed element.
1025 mFixedPosIsAbsPos
= (aNewAbsoluteContainingBlock
&&
1026 aNewAbsoluteContainingBlock
->GetStyleDisplay()->HasTransform());
1030 nsFrameConstructorState::PushFloatContainingBlock(nsIFrame
* aNewFloatContainingBlock
,
1031 nsFrameConstructorSaveState
& aSaveState
)
1033 NS_PRECONDITION(!aNewFloatContainingBlock
||
1034 aNewFloatContainingBlock
->IsFloatContainingBlock(),
1035 "Please push a real float containing block!");
1036 aSaveState
.mItems
= &mFloatedItems
;
1037 aSaveState
.mSavedItems
= mFloatedItems
;
1038 aSaveState
.mChildListName
= nsGkAtoms::floatList
;
1039 aSaveState
.mState
= this;
1040 mFloatedItems
= nsAbsoluteItems(aNewFloatContainingBlock
);
1044 nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay
* aStyleDisplay
,
1045 nsIFrame
* aContentParentFrame
)
1047 NS_PRECONDITION(aStyleDisplay
, "Must have display struct!");
1049 // If there is no container for a fixed, absolute, or floating root
1050 // frame, we will ignore the positioning. This hack is originally
1051 // brought to you by the letter T: tables, since other roots don't
1052 // even call into this code. See bug 178855.
1054 // XXX Disabling positioning in this case is a hack. If one was so inclined,
1055 // one could support this either by (1) inserting a dummy block between the
1056 // table and the canvas or (2) teaching the canvas how to reflow positioned
1057 // elements. (1) has the usual problems when multiple frames share the same
1058 // content (notice all the special cases in this file dealing with inner
1059 // tables and outer tables which share the same content). (2) requires some
1060 // work and possible factoring.
1062 // XXXbz couldn't we just force position to "static" on roots and
1063 // float to "none"? That's OK per CSS 2.1, as far as I can tell.
1065 if (aStyleDisplay
->IsFloating() && mFloatedItems
.containingBlock
) {
1066 NS_ASSERTION(!aStyleDisplay
->IsAbsolutelyPositioned(),
1067 "Absolutely positioned _and_ floating?");
1068 return mFloatedItems
.containingBlock
;
1071 if (aStyleDisplay
->mPosition
== NS_STYLE_POSITION_ABSOLUTE
&&
1072 mAbsoluteItems
.containingBlock
) {
1073 return mAbsoluteItems
.containingBlock
;
1076 if (aStyleDisplay
->mPosition
== NS_STYLE_POSITION_FIXED
&&
1077 GetFixedItems().containingBlock
) {
1078 return GetFixedItems().containingBlock
;
1081 return aContentParentFrame
;
1085 nsFrameConstructorState::AddChild(nsIFrame
* aNewFrame
,
1086 nsFrameItems
& aFrameItems
,
1087 nsIContent
* aContent
,
1088 nsStyleContext
* aStyleContext
,
1089 nsIFrame
* aParentFrame
,
1090 PRBool aCanBePositioned
,
1091 PRBool aCanBeFloated
,
1092 PRBool aIsOutOfFlowPopup
,
1093 PRBool aInsertAfter
,
1094 nsIFrame
* aInsertAfterFrame
)
1096 NS_PRECONDITION(!aNewFrame
->GetNextSibling(), "Shouldn't happen");
1098 const nsStyleDisplay
* disp
= aNewFrame
->GetStyleDisplay();
1100 // The comments in GetGeometricParent regarding root table frames
1101 // all apply here, unfortunately.
1103 PRBool needPlaceholder
= PR_FALSE
;
1104 nsFrameState placeholderType
;
1105 nsFrameItems
* frameItems
= &aFrameItems
;
1107 if (NS_UNLIKELY(aIsOutOfFlowPopup
)) {
1108 NS_ASSERTION(aNewFrame
->GetParent() == mPopupItems
.containingBlock
,
1109 "Popup whose parent is not the popup containing block?");
1110 NS_ASSERTION(mPopupItems
.containingBlock
, "Must have a popup set frame!");
1111 needPlaceholder
= PR_TRUE
;
1112 frameItems
= &mPopupItems
;
1113 placeholderType
= PLACEHOLDER_FOR_POPUP
;
1117 if (aCanBeFloated
&& disp
->IsFloating() &&
1118 mFloatedItems
.containingBlock
) {
1119 NS_ASSERTION(aNewFrame
->GetParent() == mFloatedItems
.containingBlock
,
1120 "Float whose parent is not the float containing block?");
1121 needPlaceholder
= PR_TRUE
;
1122 frameItems
= &mFloatedItems
;
1123 placeholderType
= PLACEHOLDER_FOR_FLOAT
;
1125 else if (aCanBePositioned
) {
1126 if (disp
->mPosition
== NS_STYLE_POSITION_ABSOLUTE
&&
1127 mAbsoluteItems
.containingBlock
) {
1128 NS_ASSERTION(aNewFrame
->GetParent() == mAbsoluteItems
.containingBlock
,
1129 "Abs pos whose parent is not the abs pos containing block?");
1130 needPlaceholder
= PR_TRUE
;
1131 frameItems
= &mAbsoluteItems
;
1132 placeholderType
= PLACEHOLDER_FOR_ABSPOS
;
1134 if (disp
->mPosition
== NS_STYLE_POSITION_FIXED
&&
1135 GetFixedItems().containingBlock
) {
1136 NS_ASSERTION(aNewFrame
->GetParent() == GetFixedItems().containingBlock
,
1137 "Fixed pos whose parent is not the fixed pos containing block?");
1138 needPlaceholder
= PR_TRUE
;
1139 frameItems
= &GetFixedItems();
1140 placeholderType
= PLACEHOLDER_FOR_FIXEDPOS
;
1144 if (needPlaceholder
) {
1145 NS_ASSERTION(frameItems
!= &aFrameItems
,
1146 "Putting frame in-flow _and_ want a placeholder?");
1147 nsIFrame
* placeholderFrame
;
1149 nsCSSFrameConstructor::CreatePlaceholderFrameFor(mPresShell
,
1157 if (NS_FAILED(rv
)) {
1158 // Note that aNewFrame could be the top frame for a scrollframe setup,
1159 // hence already set as the primary frame. So we have to clean up here.
1160 // But it shouldn't have any out-of-flow kids.
1161 // XXXbz Maybe add a utility function to assert that?
1162 aNewFrame
->Destroy();
1166 placeholderFrame
->AddStateBits(mAdditionalStateBits
);
1167 // Add the placeholder frame to the flow
1168 aFrameItems
.AddChild(placeholderFrame
);
1172 NS_ASSERTION(aNewFrame
->GetParent() == aParentFrame
,
1173 "In-flow frame has wrong parent");
1178 frameItems
->InsertFrame(nsnull
, aInsertAfterFrame
, aNewFrame
);
1180 frameItems
->AddChild(aNewFrame
);
1187 nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems
& aFrameItems
,
1188 nsIAtom
* aChildListName
)
1190 #define NS_NONXUL_LIST_TEST (&aFrameItems == &mFloatedItems && \
1191 aChildListName == nsGkAtoms::floatList) || \
1192 (&aFrameItems == &mAbsoluteItems && \
1193 aChildListName == nsGkAtoms::absoluteList) || \
1194 (&aFrameItems == &mFixedItems && \
1195 aChildListName == nsGkAtoms::fixedList)
1197 NS_PRECONDITION(NS_NONXUL_LIST_TEST
||
1198 (&aFrameItems
== &mPopupItems
&&
1199 aChildListName
== nsGkAtoms::popupList
),
1200 "Unexpected aFrameItems/aChildListName combination");
1202 NS_PRECONDITION(NS_NONXUL_LIST_TEST
,
1203 "Unexpected aFrameItems/aChildListName combination");
1206 if (aFrameItems
.IsEmpty()) {
1210 nsIFrame
* containingBlock
= aFrameItems
.containingBlock
;
1212 NS_ASSERTION(containingBlock
,
1213 "Child list without containing block?");
1215 // Insert the frames hanging out in aItems. We can use SetInitialChildList()
1216 // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
1217 // is set) and doesn't have any frames in the aChildListName child list yet.
1218 const nsFrameList
& childList
= containingBlock
->GetChildList(aChildListName
);
1219 nsresult rv
= NS_OK
;
1220 if (childList
.IsEmpty() &&
1221 (containingBlock
->GetStateBits() & NS_FRAME_FIRST_REFLOW
)) {
1222 rv
= containingBlock
->SetInitialChildList(aChildListName
, aFrameItems
);
1224 // Note that whether the frame construction context is doing an append or
1225 // not is not helpful here, since it could be appending to some frame in
1226 // the middle of the document, which means we're not necessarily
1227 // appending to the children of the containing block.
1229 // We need to make sure the 'append to the end of document' case is fast.
1230 // So first test the last child of the containing block
1231 nsIFrame
* lastChild
= childList
.LastChild();
1233 // CompareTreePosition uses placeholder hierarchy for out of flow frames,
1234 // so this will make out-of-flows respect the ordering of placeholders,
1235 // which is great because it takes care of anonymous content.
1236 nsIFrame
* firstNewFrame
= aFrameItems
.FirstChild();
1238 nsLayoutUtils::CompareTreePosition(lastChild
, firstNewFrame
, containingBlock
) < 0) {
1239 // no lastChild, or lastChild comes before the new children, so just append
1240 rv
= containingBlock
->AppendFrames(aChildListName
, aFrameItems
);
1242 // try the other children
1243 nsIFrame
* insertionPoint
= nsnull
;
1244 for (nsIFrame
* f
= childList
.FirstChild(); f
!= lastChild
;
1245 f
= f
->GetNextSibling()) {
1247 nsLayoutUtils::CompareTreePosition(f
, firstNewFrame
, containingBlock
);
1249 // f comes after the new children, so stop here and insert after
1250 // the previous frame
1255 rv
= containingBlock
->InsertFrames(aChildListName
, insertionPoint
,
1260 NS_POSTCONDITION(aFrameItems
.IsEmpty(), "How did that happen?");
1262 // XXXbz And if NS_FAILED(rv), what? I guess we need to clean up the list
1263 // and deal with all the placeholders... but what if the placeholders aren't
1264 // in the document yet? Could that happen?
1265 NS_ASSERTION(NS_SUCCEEDED(rv
), "Frames getting lost!");
1269 nsFrameConstructorSaveState::nsFrameConstructorSaveState()
1271 mFixedPosIsAbsPos(nsnull
),
1272 mSavedItems(nsnull
),
1273 mSavedFixedPosIsAbsPos(PR_FALSE
),
1274 mChildListName(nsnull
),
1279 nsFrameConstructorSaveState::~nsFrameConstructorSaveState()
1281 // Restore the state
1283 NS_ASSERTION(mState
, "Can't have mItems set without having a state!");
1284 mState
->ProcessFrameInsertions(*mItems
, mChildListName
);
1285 *mItems
= mSavedItems
;
1287 // We've transferred the child list, so drop the pointer we held to it.
1288 // Note that this only matters for the assert in ~nsAbsoluteItems.
1289 mSavedItems
.Clear();
1292 if (mFixedPosIsAbsPos
) {
1293 *mFixedPosIsAbsPos
= mSavedFixedPosIsAbsPos
;
1298 PRBool
IsBorderCollapse(nsIFrame
* aFrame
)
1300 for (nsIFrame
* frame
= aFrame
; frame
; frame
= frame
->GetParent()) {
1301 if (nsGkAtoms::tableFrame
== frame
->GetType()) {
1302 return ((nsTableFrame
*)frame
)->IsBorderCollapse();
1305 NS_ASSERTION(PR_FALSE
, "program error");
1310 * Moves aFrameList from aOldParent to aNewParent. This updates the parent
1311 * pointer of the frames in the list, and reparents their views as needed.
1312 * nsFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its
1313 * ancestors as needed. Then it sets the list as the initial child list
1314 * on aNewParent, unless aNewParent either already has kids or has been
1315 * reflowed; in that case it appends the new frames. Note that this
1316 * method differs from ReparentFrames in that it doesn't change the kids'
1319 // XXXbz Since this is only used for {ib} splits, could we just copy the view
1320 // bits from aOldParent to aNewParent and then use the
1321 // nsFrameList::ApplySetParent? That would still leave us doing two passes
1322 // over the list, of course; if we really wanted to we could factor out the
1323 // relevant part of ReparentFrameViewList, I suppose... Or just get rid of
1324 // views, which would make most of this function go away.
1326 MoveChildrenTo(nsPresContext
* aPresContext
,
1327 nsIFrame
* aOldParent
,
1328 nsIFrame
* aNewParent
,
1329 nsFrameList
& aFrameList
)
1331 PRBool sameGrandParent
= aOldParent
->GetParent() == aNewParent
->GetParent();
1333 if (aNewParent
->HasView() || aOldParent
->HasView() || !sameGrandParent
) {
1334 // Move the frames into the new view
1335 nsHTMLContainerFrame::ReparentFrameViewList(aPresContext
, aFrameList
,
1336 aOldParent
, aNewParent
);
1339 for (nsFrameList::Enumerator
e(aFrameList
); !e
.AtEnd(); e
.Next()) {
1340 e
.get()->SetParent(aNewParent
);
1343 if (aNewParent
->GetChildList(nsnull
).IsEmpty() &&
1344 (aNewParent
->GetStateBits() & NS_FRAME_FIRST_REFLOW
)) {
1345 aNewParent
->SetInitialChildList(nsnull
, aFrameList
);
1347 aNewParent
->AppendFrames(nsnull
, aFrameList
);
1351 //----------------------------------------------------------------------
1353 nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument
*aDocument
,
1354 nsIPresShell
*aPresShell
)
1355 : mDocument(aDocument
)
1356 , mPresShell(aPresShell
)
1357 , mRootElementFrame(nsnull
)
1358 , mRootElementStyleFrame(nsnull
)
1359 , mFixedContainingBlock(nsnull
)
1360 , mDocElementContainingBlock(nsnull
)
1361 , mGfxScrollFrame(nsnull
)
1362 , mPageSequenceFrame(nsnull
)
1364 , mQuotesDirty(PR_FALSE
)
1365 , mCountersDirty(PR_FALSE
)
1366 , mIsDestroyingFrameTree(PR_FALSE
)
1367 , mRebuildAllStyleData(PR_FALSE
)
1368 , mHasRootAbsPosContainingBlock(PR_FALSE
)
1369 , mObservingRefreshDriver(PR_FALSE
)
1370 , mInStyleRefresh(PR_FALSE
)
1371 , mHoverGeneration(0)
1372 , mRebuildAllExtraHint(nsChangeHint(0))
1373 , mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE
|
1374 ELEMENT_IS_POTENTIAL_RESTYLE_ROOT
, this)
1375 , mPendingAnimationRestyles(ELEMENT_HAS_PENDING_ANIMATION_RESTYLE
|
1376 ELEMENT_IS_POTENTIAL_ANIMATION_RESTYLE_ROOT
, this)
1378 // XXXbz this should be in Init() or something!
1379 if (!mPendingRestyles
.Init() || !mPendingAnimationRestyles
.Init()) {
1384 static PRBool gFirstTime
= PR_TRUE
;
1386 gFirstTime
= PR_FALSE
;
1387 char* flags
= PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS");
1389 PRBool error
= PR_FALSE
;
1391 char* comma
= PL_strchr(flags
, ',');
1395 PRBool found
= PR_FALSE
;
1396 FrameCtorDebugFlags
* flag
= gFlags
;
1397 FrameCtorDebugFlags
* limit
= gFlags
+ NUM_DEBUG_FLAGS
;
1398 while (flag
< limit
) {
1399 if (PL_strcasecmp(flag
->name
, flags
) == 0) {
1400 *(flag
->on
) = PR_TRUE
;
1401 printf("nsCSSFrameConstructor: setting %s debug flag on\n", flag
->name
);
1419 printf("Here are the available GECKO_FRAMECTOR_DEBUG_FLAGS:\n");
1420 FrameCtorDebugFlags
* flag
= gFlags
;
1421 FrameCtorDebugFlags
* limit
= gFlags
+ NUM_DEBUG_FLAGS
;
1422 while (flag
< limit
) {
1423 printf(" %s\n", flag
->name
);
1426 printf("Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of flag\n");
1427 printf("names (no whitespace)\n");
1434 nsIXBLService
* nsCSSFrameConstructor::GetXBLService()
1437 nsresult rv
= CallGetService("@mozilla.org/xbl;1", &gXBLService
);
1439 gXBLService
= nsnull
;
1446 nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame
* aFrame
)
1448 NS_PRECONDITION(mUpdateCount
!= 0,
1449 "Should be in an update while destroying frames");
1451 if (aFrame
->GetStateBits() & NS_FRAME_GENERATED_CONTENT
) {
1452 if (mQuoteList
.DestroyNodesFor(aFrame
))
1456 if (mCounterManager
.DestroyNodesFor(aFrame
)) {
1457 // Technically we don't need to update anything if we destroyed only
1458 // USE nodes. However, this is unlikely to happen in the real world
1459 // since USE nodes generally go along with INCREMENT nodes.
1464 struct nsGenConInitializer
{
1465 nsAutoPtr
<nsGenConNode
> mNode
;
1466 nsGenConList
* mList
;
1467 void (nsCSSFrameConstructor::*mDirtyAll
)();
1469 nsGenConInitializer(nsGenConNode
* aNode
, nsGenConList
* aList
,
1470 void (nsCSSFrameConstructor::*aDirtyAll
)())
1471 : mNode(aNode
), mList(aList
), mDirtyAll(aDirtyAll
) {}
1475 DestroyGenConInitializer(void* aFrame
,
1476 nsIAtom
* aPropertyName
,
1477 void* aPropertyValue
,
1480 delete static_cast<nsGenConInitializer
*>(aPropertyValue
);
1483 already_AddRefed
<nsIContent
>
1484 nsCSSFrameConstructor::CreateGenConTextNode(nsFrameConstructorState
& aState
,
1485 const nsString
& aString
,
1486 nsCOMPtr
<nsIDOMCharacterData
>* aText
,
1487 nsGenConInitializer
* aInitializer
)
1489 nsCOMPtr
<nsIContent
> content
;
1490 NS_NewTextNode(getter_AddRefs(content
), mDocument
->NodeInfoManager());
1492 // XXX The quotes/counters code doesn't like the text pointer
1493 // being null in case of dynamic changes!
1494 NS_ASSERTION(!aText
, "this OOM case isn't handled very well");
1497 content
->SetText(aString
, PR_FALSE
);
1499 *aText
= do_QueryInterface(content
);
1502 content
->SetProperty(nsGkAtoms::genConInitializerProperty
, aInitializer
,
1503 DestroyGenConInitializer
);
1504 aState
.mGeneratedTextNodesWithInitializer
.AppendObject(content
);
1506 return content
.forget();
1509 already_AddRefed
<nsIContent
>
1510 nsCSSFrameConstructor::CreateGeneratedContent(nsFrameConstructorState
& aState
,
1511 nsIContent
* aParentContent
,
1512 nsStyleContext
* aStyleContext
,
1513 PRUint32 aContentIndex
)
1515 // Get the content value
1516 const nsStyleContentData
&data
=
1517 aStyleContext
->GetStyleContent()->ContentAt(aContentIndex
);
1518 nsStyleContentType type
= data
.mType
;
1520 if (eStyleContentType_Image
== type
) {
1521 if (!data
.mContent
.mImage
) {
1522 // CSS had something specified that couldn't be converted to an
1527 // Create an image content object and pass it the image request.
1528 // XXX Check if it's an image type we can handle...
1530 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
1531 nodeInfo
= mDocument
->NodeInfoManager()->GetNodeInfo(nsGkAtoms::mozgeneratedcontentimage
, nsnull
,
1532 kNameSpaceID_XHTML
);
1534 nsCOMPtr
<nsIContent
> content
;
1535 NS_NewGenConImageContent(getter_AddRefs(content
), nodeInfo
.forget(),
1536 data
.mContent
.mImage
);
1537 return content
.forget();
1541 case eStyleContentType_String
:
1542 return CreateGenConTextNode(aState
,
1543 nsDependentString(data
.mContent
.mString
),
1546 case eStyleContentType_Attr
:
1548 nsCOMPtr
<nsIAtom
> attrName
;
1549 PRInt32 attrNameSpace
= kNameSpaceID_None
;
1550 nsAutoString
contentString(data
.mContent
.mString
);
1552 PRInt32 barIndex
= contentString
.FindChar('|'); // CSS namespace delimiter
1553 if (-1 != barIndex
) {
1554 nsAutoString nameSpaceVal
;
1555 contentString
.Left(nameSpaceVal
, barIndex
);
1557 attrNameSpace
= nameSpaceVal
.ToInteger(&error
, 10);
1558 contentString
.Cut(0, barIndex
+ 1);
1559 if (contentString
.Length()) {
1560 if (mDocument
->IsHTML() && aParentContent
->IsHTML()) {
1561 ToLowerCase(contentString
);
1563 attrName
= do_GetAtom(contentString
);
1567 if (mDocument
->IsHTML() && aParentContent
->IsHTML()) {
1568 ToLowerCase(contentString
);
1570 attrName
= do_GetAtom(contentString
);
1577 nsCOMPtr
<nsIContent
> content
;
1578 NS_NewAttributeContent(mDocument
->NodeInfoManager(),
1579 attrNameSpace
, attrName
, getter_AddRefs(content
));
1580 return content
.forget();
1583 case eStyleContentType_Counter
:
1584 case eStyleContentType_Counters
:
1586 nsCSSValue::Array
* counters
= data
.mContent
.mCounters
;
1587 nsCounterList
* counterList
= mCounterManager
.CounterListFor(
1588 nsDependentString(counters
->Item(0).GetStringBufferValue()));
1592 nsCounterUseNode
* node
=
1593 new nsCounterUseNode(counters
, aContentIndex
,
1594 type
== eStyleContentType_Counters
);
1598 nsGenConInitializer
* initializer
=
1599 new nsGenConInitializer(node
, counterList
,
1600 &nsCSSFrameConstructor::CountersDirty
);
1601 return CreateGenConTextNode(aState
, EmptyString(), &node
->mText
,
1605 case eStyleContentType_Image
:
1606 NS_NOTREACHED("handled by if above");
1609 case eStyleContentType_OpenQuote
:
1610 case eStyleContentType_CloseQuote
:
1611 case eStyleContentType_NoOpenQuote
:
1612 case eStyleContentType_NoCloseQuote
:
1615 new nsQuoteNode(type
, aContentIndex
);
1619 nsGenConInitializer
* initializer
=
1620 new nsGenConInitializer(node
, &mQuoteList
,
1621 &nsCSSFrameConstructor::QuotesDirty
);
1622 return CreateGenConTextNode(aState
, EmptyString(), &node
->mText
,
1626 case eStyleContentType_AltContent
:
1628 // Use the "alt" attribute; if that fails and the node is an HTML
1629 // <input>, try the value attribute and then fall back to some default
1630 // localized text we have.
1631 // XXX what if the 'alt' attribute is added later, how will we
1632 // detect that and do the right thing here?
1633 if (aParentContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::alt
)) {
1634 nsCOMPtr
<nsIContent
> content
;
1635 NS_NewAttributeContent(mDocument
->NodeInfoManager(),
1636 kNameSpaceID_None
, nsGkAtoms::alt
, getter_AddRefs(content
));
1637 return content
.forget();
1640 if (aParentContent
->IsHTML() &&
1641 aParentContent
->NodeInfo()->Equals(nsGkAtoms::input
)) {
1642 if (aParentContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::value
)) {
1643 nsCOMPtr
<nsIContent
> content
;
1644 NS_NewAttributeContent(mDocument
->NodeInfoManager(),
1645 kNameSpaceID_None
, nsGkAtoms::value
, getter_AddRefs(content
));
1646 return content
.forget();
1650 nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES
,
1652 return CreateGenConTextNode(aState
, temp
, nsnull
, nsnull
);
1663 * aParentFrame - the frame that should be the parent of the generated
1664 * content. This is the frame for the corresponding content node,
1665 * which must not be a leaf frame.
1667 * Any items created are added to aItems.
1669 * We create an XML element (tag _moz_generated_content_before or
1670 * _moz_generated_content_after) representing the pseudoelement. We
1671 * create a DOM node for each 'content' item and make those nodes the
1672 * children of the XML element. Then we create a frame subtree for
1673 * the XML element as if it were a regular child of
1674 * aParentFrame/aParentContent, giving the XML element the ::before or
1678 nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState
& aState
,
1679 nsIFrame
* aParentFrame
,
1680 nsIContent
* aParentContent
,
1681 nsStyleContext
* aStyleContext
,
1682 nsCSSPseudoElements::Type aPseudoElement
,
1683 FrameConstructionItemList
& aItems
)
1685 // XXXbz is this ever true?
1686 if (!aParentContent
->IsElement()) {
1687 NS_ERROR("Bogus generated content parent");
1691 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
1693 // Probe for the existence of the pseudo-element
1694 nsRefPtr
<nsStyleContext
> pseudoStyleContext
;
1695 pseudoStyleContext
=
1696 styleSet
->ProbePseudoElementStyle(aParentContent
->AsElement(),
1699 if (!pseudoStyleContext
)
1701 // |ProbePseudoStyleFor| checked the 'display' property and the
1702 // |ContentCount()| of the 'content' property for us.
1703 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
1704 nsIAtom
* elemName
= aPseudoElement
== nsCSSPseudoElements::ePseudo_before
?
1705 nsGkAtoms::mozgeneratedcontentbefore
: nsGkAtoms::mozgeneratedcontentafter
;
1706 nodeInfo
= mDocument
->NodeInfoManager()->GetNodeInfo(elemName
, nsnull
,
1708 nsCOMPtr
<nsIContent
> container
;
1709 nsresult rv
= NS_NewXMLElement(getter_AddRefs(container
), nodeInfo
.forget());
1712 container
->SetNativeAnonymous();
1714 rv
= container
->BindToTree(mDocument
, aParentContent
, aParentContent
, PR_TRUE
);
1715 if (NS_FAILED(rv
)) {
1716 container
->UnbindFromTree();
1720 PRUint32 contentCount
= pseudoStyleContext
->GetStyleContent()->ContentCount();
1721 for (PRUint32 contentIndex
= 0; contentIndex
< contentCount
; contentIndex
++) {
1722 nsCOMPtr
<nsIContent
> content
=
1723 CreateGeneratedContent(aState
, aParentContent
, pseudoStyleContext
,
1726 container
->AppendChildTo(content
, PR_FALSE
);
1730 AddFrameConstructionItemsInternal(aState
, container
, aParentFrame
, elemName
,
1731 kNameSpaceID_None
, PR_TRUE
,
1733 ITEM_IS_GENERATED_CONTENT
, aItems
);
1736 /****************************************************
1737 ** BEGIN TABLE SECTION
1738 ****************************************************/
1740 // The term pseudo frame is being used instead of anonymous frame, since anonymous
1741 // frame has been used elsewhere to refer to frames that have generated content
1744 IsTableRelated(nsIAtom
* aParentType
)
1747 nsGkAtoms::tableOuterFrame
== aParentType
||
1748 nsGkAtoms::tableFrame
== aParentType
||
1749 nsGkAtoms::tableRowGroupFrame
== aParentType
||
1750 nsGkAtoms::tableRowFrame
== aParentType
||
1751 nsGkAtoms::tableCaptionFrame
== aParentType
||
1752 nsGkAtoms::tableColGroupFrame
== aParentType
||
1753 nsGkAtoms::tableColFrame
== aParentType
||
1754 IS_TABLE_CELL(aParentType
);
1757 // Return whether the given frame is a table pseudo-frame. Note that
1758 // cell-content and table-outer frames have pseudo-types, but are always
1759 // created, even for non-anonymous cells and tables respectively. So for those
1760 // we have to examine the cell or table frame to see whether it's a pseudo
1761 // frame. In particular, a lone table caption will have an outer table as its
1762 // parent, but will also trigger construction of an empty inner table, which
1763 // will be the one we can examine to see whether the outer was a pseudo-frame.
1765 IsTablePseudo(nsIFrame
* aFrame
)
1767 nsIAtom
* pseudoType
= aFrame
->GetStyleContext()->GetPseudo();
1768 return pseudoType
&&
1769 (pseudoType
== nsCSSAnonBoxes::table
||
1770 pseudoType
== nsCSSAnonBoxes::inlineTable
||
1771 pseudoType
== nsCSSAnonBoxes::tableColGroup
||
1772 pseudoType
== nsCSSAnonBoxes::tableRowGroup
||
1773 pseudoType
== nsCSSAnonBoxes::tableRow
||
1774 pseudoType
== nsCSSAnonBoxes::tableCell
||
1775 (pseudoType
== nsCSSAnonBoxes::cellContent
&&
1776 aFrame
->GetParent()->GetStyleContext()->GetPseudo() ==
1777 nsCSSAnonBoxes::tableCell
) ||
1778 (pseudoType
== nsCSSAnonBoxes::tableOuter
&&
1779 (aFrame
->GetFirstChild(nsnull
)->GetStyleContext()->GetPseudo() ==
1780 nsCSSAnonBoxes::table
||
1781 aFrame
->GetFirstChild(nsnull
)->GetStyleContext()->GetPseudo() ==
1782 nsCSSAnonBoxes::inlineTable
)));
1786 nsCSSFrameConstructor::ParentType
1787 nsCSSFrameConstructor::GetParentType(nsIAtom
* aFrameType
)
1789 if (aFrameType
== nsGkAtoms::tableFrame
) {
1792 if (aFrameType
== nsGkAtoms::tableRowGroupFrame
) {
1793 return eTypeRowGroup
;
1795 if (aFrameType
== nsGkAtoms::tableRowFrame
) {
1798 if (aFrameType
== nsGkAtoms::tableColGroupFrame
) {
1799 return eTypeColGroup
;
1806 AdjustCaptionParentFrame(nsIFrame
* aParentFrame
)
1808 if (nsGkAtoms::tableFrame
== aParentFrame
->GetType()) {
1809 return aParentFrame
->GetParent();;
1811 return aParentFrame
;
1815 * If the parent frame is a |tableFrame| and the child is a
1816 * |captionFrame|, then we want to insert the frames beneath the
1817 * |tableFrame|'s parent frame. Returns |PR_TRUE| if the parent frame
1818 * needed to be fixed up.
1821 GetCaptionAdjustedParent(nsIFrame
* aParentFrame
,
1822 const nsIFrame
* aChildFrame
,
1823 nsIFrame
** aAdjParentFrame
)
1825 *aAdjParentFrame
= aParentFrame
;
1826 PRBool haveCaption
= PR_FALSE
;
1828 if (nsGkAtoms::tableCaptionFrame
== aChildFrame
->GetType()) {
1829 haveCaption
= PR_TRUE
;
1830 *aAdjParentFrame
= AdjustCaptionParentFrame(aParentFrame
);
1836 nsCSSFrameConstructor::AdjustParentFrame(nsIFrame
* & aParentFrame
,
1837 const FrameConstructionData
* aFCData
,
1838 nsStyleContext
* aStyleContext
)
1840 NS_PRECONDITION(aStyleContext
, "Must have child's style context");
1841 NS_PRECONDITION(aFCData
, "Must have frame construction data");
1843 PRBool tablePart
= ((aFCData
->mBits
& FCDATA_IS_TABLE_PART
) != 0);
1845 if (tablePart
&& aStyleContext
->GetStyleDisplay()->mDisplay
==
1846 NS_STYLE_DISPLAY_TABLE_CAPTION
) {
1847 aParentFrame
= AdjustCaptionParentFrame(aParentFrame
);
1851 // Pull all the captions present in aItems out into aCaptions
1853 PullOutCaptionFrames(nsFrameItems
& aItems
, nsFrameItems
& aCaptions
)
1855 nsIFrame
*child
= aItems
.FirstChild();
1857 nsIFrame
*nextSibling
= child
->GetNextSibling();
1858 if (nsGkAtoms::tableCaptionFrame
== child
->GetType()) {
1859 aItems
.RemoveFrame(child
);
1860 aCaptions
.AddChild(child
);
1862 child
= nextSibling
;
1867 // Construct the outer, inner table frames and the children frames for the table.
1868 // XXX Page break frames for pseudo table frames are not constructed to avoid the risk
1869 // associated with revising the pseudo frame mechanism. The long term solution
1870 // of having frames handle page-break-before/after will solve the problem.
1872 nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState
& aState
,
1873 FrameConstructionItem
& aItem
,
1874 nsIFrame
* aParentFrame
,
1875 const nsStyleDisplay
* aDisplay
,
1876 nsFrameItems
& aFrameItems
,
1877 nsIFrame
** aNewFrame
)
1879 NS_PRECONDITION(aDisplay
->mDisplay
== NS_STYLE_DISPLAY_TABLE
||
1880 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_INLINE_TABLE
,
1883 nsIContent
* const content
= aItem
.mContent
;
1884 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
1885 const PRUint32 nameSpaceID
= aItem
.mNameSpaceID
;
1887 nsresult rv
= NS_OK
;
1889 // create the pseudo SC for the outer table as a child of the inner SC
1890 nsRefPtr
<nsStyleContext
> outerStyleContext
;
1891 outerStyleContext
= mPresShell
->StyleSet()->
1892 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::tableOuter
, styleContext
);
1894 // Create the outer table frame which holds the caption and inner table frame
1897 if (kNameSpaceID_MathML
== nameSpaceID
)
1898 newFrame
= NS_NewMathMLmtableOuterFrame(mPresShell
, outerStyleContext
);
1901 newFrame
= NS_NewTableOuterFrame(mPresShell
, outerStyleContext
);
1903 nsIFrame
* geometricParent
=
1904 aState
.GetGeometricParent(outerStyleContext
->GetStyleDisplay(),
1907 // Init the table outer frame and see if we need to create a view, e.g.
1908 // the frame is absolutely positioned
1909 InitAndRestoreFrame(aState
, content
, geometricParent
, nsnull
, newFrame
);
1910 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
1912 // Create the inner table frame
1913 nsIFrame
* innerFrame
;
1915 if (kNameSpaceID_MathML
== nameSpaceID
)
1916 innerFrame
= NS_NewMathMLmtableFrame(mPresShell
, styleContext
);
1919 innerFrame
= NS_NewTableFrame(mPresShell
, styleContext
);
1921 InitAndRestoreFrame(aState
, content
, newFrame
, nsnull
, innerFrame
);
1923 // Put the newly created frames into the right child list
1924 SetInitialSingleChild(newFrame
, innerFrame
);
1926 rv
= aState
.AddChild(newFrame
, aFrameItems
, content
, styleContext
,
1928 if (NS_FAILED(rv
)) {
1932 if (!mRootElementFrame
) {
1933 // The frame we're constructing will be the root element frame.
1934 // Set mRootElementFrame before processing children.
1935 mRootElementFrame
= newFrame
;
1938 nsFrameItems childItems
;
1939 if (aItem
.mFCData
->mBits
& FCDATA_USE_CHILD_ITEMS
) {
1940 rv
= ConstructFramesFromItemList(aState
, aItem
.mChildItems
,
1941 innerFrame
, childItems
);
1943 rv
= ProcessChildren(aState
, content
, styleContext
, innerFrame
,
1944 PR_TRUE
, childItems
, PR_FALSE
, aItem
.mPendingBinding
);
1946 // XXXbz what about cleaning up?
1947 if (NS_FAILED(rv
)) return rv
;
1949 nsFrameItems captionItems
;
1950 PullOutCaptionFrames(childItems
, captionItems
);
1952 // Set the inner table frame's initial primary list
1953 innerFrame
->SetInitialChildList(nsnull
, childItems
);
1955 // Set the outer table frame's secondary childlist lists
1956 if (captionItems
.NotEmpty()) {
1957 newFrame
->SetInitialChildList(nsGkAtoms::captionList
, captionItems
);
1960 *aNewFrame
= newFrame
;
1965 nsCSSFrameConstructor::ConstructTableRow(nsFrameConstructorState
& aState
,
1966 FrameConstructionItem
& aItem
,
1967 nsIFrame
* aParentFrame
,
1968 const nsStyleDisplay
* aDisplay
,
1969 nsFrameItems
& aFrameItems
,
1970 nsIFrame
** aNewFrame
)
1972 NS_PRECONDITION(aDisplay
->mDisplay
== NS_STYLE_DISPLAY_TABLE_ROW
,
1974 nsIContent
* const content
= aItem
.mContent
;
1975 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
1976 const PRUint32 nameSpaceID
= aItem
.mNameSpaceID
;
1980 if (kNameSpaceID_MathML
== nameSpaceID
)
1981 newFrame
= NS_NewMathMLmtrFrame(mPresShell
, styleContext
);
1984 newFrame
= NS_NewTableRowFrame(mPresShell
, styleContext
);
1986 if (NS_UNLIKELY(!newFrame
)) {
1987 return NS_ERROR_OUT_OF_MEMORY
;
1989 InitAndRestoreFrame(aState
, content
, aParentFrame
, nsnull
, newFrame
);
1990 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
1992 nsFrameItems childItems
;
1994 if (aItem
.mFCData
->mBits
& FCDATA_USE_CHILD_ITEMS
) {
1995 rv
= ConstructFramesFromItemList(aState
, aItem
.mChildItems
, newFrame
,
1998 rv
= ProcessChildren(aState
, content
, styleContext
, newFrame
,
1999 PR_TRUE
, childItems
, PR_FALSE
, aItem
.mPendingBinding
);
2001 if (NS_FAILED(rv
)) return rv
;
2003 newFrame
->SetInitialChildList(nsnull
, childItems
);
2004 aFrameItems
.AddChild(newFrame
);
2005 *aNewFrame
= newFrame
;
2011 nsCSSFrameConstructor::ConstructTableCol(nsFrameConstructorState
& aState
,
2012 FrameConstructionItem
& aItem
,
2013 nsIFrame
* aParentFrame
,
2014 const nsStyleDisplay
* aStyleDisplay
,
2015 nsFrameItems
& aFrameItems
,
2016 nsIFrame
** aNewFrame
)
2018 nsIContent
* const content
= aItem
.mContent
;
2019 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
2021 nsTableColFrame
* colFrame
= NS_NewTableColFrame(mPresShell
, styleContext
);
2022 if (NS_UNLIKELY(!colFrame
)) {
2023 return NS_ERROR_OUT_OF_MEMORY
;
2025 InitAndRestoreFrame(aState
, content
, aParentFrame
, nsnull
, colFrame
);
2027 NS_ASSERTION(colFrame
->GetStyleContext() == styleContext
,
2028 "Unexpected style context");
2030 aFrameItems
.AddChild(colFrame
);
2031 *aNewFrame
= colFrame
;
2033 // construct additional col frames if the col frame has a span > 1
2034 PRInt32 span
= colFrame
->GetSpan();
2035 for (PRInt32 spanX
= 1; spanX
< span
; spanX
++) {
2036 nsTableColFrame
* newCol
= NS_NewTableColFrame(mPresShell
, styleContext
);
2037 if (NS_UNLIKELY(!newCol
)) {
2038 return NS_ERROR_OUT_OF_MEMORY
;
2040 InitAndRestoreFrame(aState
, content
, aParentFrame
, nsnull
, newCol
,
2042 aFrameItems
.LastChild()->SetNextContinuation(newCol
);
2043 newCol
->SetPrevContinuation(aFrameItems
.LastChild());
2044 aFrameItems
.AddChild(newCol
);
2045 newCol
->SetColType(eColAnonymousCol
);
2052 nsCSSFrameConstructor::ConstructTableCell(nsFrameConstructorState
& aState
,
2053 FrameConstructionItem
& aItem
,
2054 nsIFrame
* aParentFrame
,
2055 const nsStyleDisplay
* aDisplay
,
2056 nsFrameItems
& aFrameItems
,
2057 nsIFrame
** aNewFrame
)
2059 NS_PRECONDITION(aDisplay
->mDisplay
== NS_STYLE_DISPLAY_TABLE_CELL
,
2062 nsIContent
* const content
= aItem
.mContent
;
2063 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
2064 const PRUint32 nameSpaceID
= aItem
.mNameSpaceID
;
2066 PRBool borderCollapse
= IsBorderCollapse(aParentFrame
);
2069 // <mtable> is border separate in mathml.css and the MathML code doesn't implement
2070 // border collapse. For those users who style <mtable> with border collapse,
2071 // give them the default non-MathML table frames that understand border collapse.
2072 // This won't break us because MathML table frames are all subclasses of the default
2073 // table code, and so we can freely mix <mtable> with <mtr> or <tr>, <mtd> or <td>.
2074 // What will happen is just that non-MathML frames won't understand MathML attributes
2075 // and will therefore miss the special handling that the MathML code does.
2076 if (kNameSpaceID_MathML
== nameSpaceID
&& !borderCollapse
)
2077 newFrame
= NS_NewMathMLmtdFrame(mPresShell
, styleContext
);
2080 // Warning: If you change this and add a wrapper frame around table cell
2081 // frames, make sure Bug 368554 doesn't regress!
2082 // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
2083 newFrame
= NS_NewTableCellFrame(mPresShell
, styleContext
, borderCollapse
);
2085 if (NS_UNLIKELY(!newFrame
)) {
2086 return NS_ERROR_OUT_OF_MEMORY
;
2089 // Initialize the table cell frame
2090 InitAndRestoreFrame(aState
, content
, aParentFrame
, nsnull
, newFrame
);
2091 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
2093 // Resolve pseudo style and initialize the body cell frame
2094 nsRefPtr
<nsStyleContext
> innerPseudoStyle
;
2095 innerPseudoStyle
= mPresShell
->StyleSet()->
2096 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::cellContent
, styleContext
);
2098 // Create a block frame that will format the cell's content
2100 nsIFrame
* cellInnerFrame
;
2102 if (kNameSpaceID_MathML
== nameSpaceID
) {
2103 cellInnerFrame
= NS_NewMathMLmtdInnerFrame(mPresShell
, innerPseudoStyle
);
2109 cellInnerFrame
= NS_NewBlockFormattingContext(mPresShell
, innerPseudoStyle
);
2113 if (NS_UNLIKELY(!cellInnerFrame
)) {
2114 newFrame
->Destroy();
2115 return NS_ERROR_OUT_OF_MEMORY
;
2118 InitAndRestoreFrame(aState
, content
, newFrame
, nsnull
, cellInnerFrame
);
2120 nsFrameItems childItems
;
2122 if (aItem
.mFCData
->mBits
& FCDATA_USE_CHILD_ITEMS
) {
2123 // Need to push ourselves as a float containing block.
2124 // XXXbz it might be nice to work on getting the parent
2125 // FrameConstructionItem down into ProcessChildren and just making use of
2126 // the push there, but that's a bit of work.
2127 nsFrameConstructorSaveState floatSaveState
;
2128 if (!isBlock
) { /* MathML case */
2129 aState
.PushFloatContainingBlock(nsnull
, floatSaveState
);
2131 aState
.PushFloatContainingBlock(cellInnerFrame
, floatSaveState
);
2134 rv
= ConstructFramesFromItemList(aState
, aItem
.mChildItems
, cellInnerFrame
,
2137 // Process the child content
2138 rv
= ProcessChildren(aState
, content
, styleContext
, cellInnerFrame
,
2139 PR_TRUE
, childItems
, isBlock
, aItem
.mPendingBinding
);
2142 if (NS_FAILED(rv
)) {
2144 // XXXbz kids of this stuff need to be cleaned up too!
2145 cellInnerFrame
->Destroy();
2146 newFrame
->Destroy();
2150 cellInnerFrame
->SetInitialChildList(nsnull
, childItems
);
2151 SetInitialSingleChild(newFrame
, cellInnerFrame
);
2152 aFrameItems
.AddChild(newFrame
);
2153 *aNewFrame
= newFrame
;
2158 static inline PRBool
2159 NeedFrameFor(const nsFrameConstructorState
& aState
,
2160 nsIFrame
* aParentFrame
,
2161 nsIContent
* aChildContent
)
2163 // XXX the GetContent() != aChildContent check is needed due to bug 135040.
2164 // Remove it once that's fixed.
2165 NS_PRECONDITION(!aChildContent
->GetPrimaryFrame() ||
2166 !aState
.mSetPrimaryFrames
||
2167 aChildContent
->GetPrimaryFrame()->GetContent() != aChildContent
,
2168 "Why did we get called?");
2170 // don't create a whitespace frame if aParentFrame doesn't want it.
2171 // always create frames for children in generated content. counter(),
2172 // quotes, and attr() content can easily change dynamically and we don't
2173 // want to be reconstructing frames. It's not even clear that these
2174 // should be considered ignorable just because they evaluate to
2177 // We could handle all this in CreateNeededTablePseudos or some other place
2178 // after we build our frame construction items, but that would involve
2179 // creating frame construction items for whitespace kids of
2180 // eExcludesIgnorableWhitespace frames, where we know we'll be dropping them
2181 // all anyway, and involve an extra walk down the frame construction item
2183 if (!aParentFrame
->IsFrameOfType(nsIFrame::eExcludesIgnorableWhitespace
) ||
2184 aParentFrame
->IsGeneratedContentFrame() ||
2185 !aChildContent
->IsNodeOfType(nsINode::eTEXT
)) {
2189 aChildContent
->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE
|
2190 NS_REFRAME_IF_WHITESPACE
);
2191 return !aChildContent
->TextIsOnlyWhitespace();
2194 /***********************************************
2196 ***********************************************/
2198 static PRBool
CheckOverflow(nsPresContext
* aPresContext
,
2199 const nsStyleDisplay
* aDisplay
)
2201 if (aDisplay
->mOverflowX
== NS_STYLE_OVERFLOW_VISIBLE
)
2204 if (aDisplay
->mOverflowX
== NS_STYLE_OVERFLOW_CLIP
)
2205 aPresContext
->SetViewportOverflowOverride(NS_STYLE_OVERFLOW_HIDDEN
,
2206 NS_STYLE_OVERFLOW_HIDDEN
);
2208 aPresContext
->SetViewportOverflowOverride(aDisplay
->mOverflowX
,
2209 aDisplay
->mOverflowY
);
2214 * This checks the root element and the HTML BODY, if any, for an "overflow" property
2215 * that should be applied to the viewport. If one is found then we return the
2216 * element that we took the overflow from (which should then be treated as
2217 * "overflow:visible"), and we store the overflow style in the prescontext.
2218 * @return if scroll was propagated from some content node, the content node it
2219 * was propagated from.
2222 nsCSSFrameConstructor::PropagateScrollToViewport()
2225 nsPresContext
* presContext
= mPresShell
->GetPresContext();
2226 presContext
->SetViewportOverflowOverride(NS_STYLE_OVERFLOW_AUTO
,
2227 NS_STYLE_OVERFLOW_AUTO
);
2229 // We never mess with the viewport scroll state
2230 // when printing or in print preview
2231 if (presContext
->IsPaginated()) {
2235 Element
* docElement
= mDocument
->GetRootElement();
2237 // Check the style on the document root element
2238 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
2239 nsRefPtr
<nsStyleContext
> rootStyle
;
2240 rootStyle
= styleSet
->ResolveStyleFor(docElement
, nsnull
);
2244 if (CheckOverflow(presContext
, rootStyle
->GetStyleDisplay())) {
2245 // tell caller we stole the overflow style from the root element
2249 // Don't look in the BODY for non-HTML documents or HTML documents
2250 // with non-HTML roots
2251 // XXX this should be earlier; we shouldn't even look at the document root
2252 // for non-HTML documents. Fix this once we support explicit CSS styling
2254 // XXX what about XHTML?
2255 nsCOMPtr
<nsIDOMHTMLDocument
> htmlDoc(do_QueryInterface(mDocument
));
2256 if (!htmlDoc
|| !docElement
->IsHTML()) {
2260 nsCOMPtr
<nsIDOMHTMLElement
> body
;
2261 htmlDoc
->GetBody(getter_AddRefs(body
));
2262 nsCOMPtr
<nsIContent
> bodyElement
= do_QueryInterface(body
);
2265 !bodyElement
->NodeInfo()->Equals(nsGkAtoms::body
)) {
2266 // The body is not a <body> tag, it's a <frameset>.
2270 nsRefPtr
<nsStyleContext
> bodyStyle
;
2271 bodyStyle
= styleSet
->ResolveStyleFor(bodyElement
->AsElement(), rootStyle
);
2276 if (CheckOverflow(presContext
, bodyStyle
->GetStyleDisplay())) {
2277 // tell caller we stole the overflow style from the body element
2285 nsCSSFrameConstructor::ConstructDocElementFrame(Element
* aDocElement
,
2286 nsILayoutHistoryState
* aFrameState
,
2287 nsIFrame
** aNewFrame
)
2289 NS_PRECONDITION(mFixedContainingBlock
,
2290 "No viewport? Someone forgot to call ConstructRootFrame!");
2291 NS_PRECONDITION(mFixedContainingBlock
== mPresShell
->FrameManager()->GetRootFrame(),
2292 "Unexpected mFixedContainingBlock");
2293 NS_PRECONDITION(!mDocElementContainingBlock
,
2294 "Shouldn't have a doc element containing block here");
2296 *aNewFrame
= nsnull
;
2298 // Make sure to call PropagateScrollToViewport before
2299 // SetUpDocElementContainingBlock, since it sets up our scrollbar state
2301 nsIContent
* propagatedScrollFrom
= PropagateScrollToViewport();
2303 SetUpDocElementContainingBlock(aDocElement
);
2305 NS_ASSERTION(mDocElementContainingBlock
, "Should have parent by now");
2307 nsFrameConstructorState
state(mPresShell
, mFixedContainingBlock
, nsnull
,
2308 nsnull
, aFrameState
);
2310 // XXXbz why, exactly?
2311 if (!mTempFrameTreeState
)
2312 state
.mPresShell
->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState
));
2314 // Make sure that we'll handle restyles for this document element in
2315 // the future. We need this, because the document element might
2316 // have stale restyle bits from a previous frame constructor for
2317 // this document. Unlike in AddFrameConstructionItems, it's safe to
2318 // unset all element restyle flags, since we don't have any
2320 aDocElement
->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS
);
2322 // --------- CREATE AREA OR BOX FRAME -------
2323 nsRefPtr
<nsStyleContext
> styleContext
;
2324 styleContext
= mPresShell
->StyleSet()->ResolveStyleFor(aDocElement
,
2327 const nsStyleDisplay
* display
= styleContext
->GetStyleDisplay();
2329 // Ensure that our XBL bindings are installed.
2330 if (display
->mBinding
) {
2331 // Get the XBL loader.
2333 PRBool resolveStyle
;
2335 nsIXBLService
* xblService
= GetXBLService();
2337 return NS_ERROR_FAILURE
;
2339 nsRefPtr
<nsXBLBinding
> binding
;
2340 rv
= xblService
->LoadBindings(aDocElement
, display
->mBinding
->mURI
,
2341 display
->mBinding
->mOriginPrincipal
,
2342 PR_FALSE
, getter_AddRefs(binding
),
2344 if (NS_FAILED(rv
) && rv
!= NS_ERROR_XBL_BLOCKED
)
2345 return NS_OK
; // Binding will load asynchronously.
2348 // For backwards compat, keep firing the root's constructor
2349 // after all of its kids' constructors. So tell the binding
2350 // manager about it right now.
2351 mDocument
->BindingManager()->AddToAttachedQueue(binding
);
2355 styleContext
= mPresShell
->StyleSet()->ResolveStyleFor(aDocElement
,
2357 display
= styleContext
->GetStyleDisplay();
2361 // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2364 NS_ASSERTION(!display
->IsScrollableOverflow() ||
2365 state
.mPresContext
->IsPaginated() ||
2366 propagatedScrollFrom
== aDocElement
,
2367 "Scrollbars should have been propagated to the viewport");
2370 if (NS_UNLIKELY(display
->mDisplay
== NS_STYLE_DISPLAY_NONE
)) {
2371 state
.mFrameManager
->SetUndisplayedContent(aDocElement
, styleContext
);
2375 nsFrameConstructorSaveState absoluteSaveState
;
2376 if (mHasRootAbsPosContainingBlock
) {
2377 // Push the absolute containing block now so we can absolutely position
2379 state
.PushAbsoluteContainingBlock(mDocElementContainingBlock
,
2385 // The rules from CSS 2.1, section 9.2.4, have already been applied
2386 // by the style system, so we can assume that display->mDisplay is
2387 // either NONE, BLOCK, or TABLE.
2389 // contentFrame is the primary frame for the root element. *aNewFrame
2390 // is the frame that will be the child of the initial containing block.
2391 // These are usually the same frame but they can be different, in
2392 // particular if the root frame is positioned, in which case
2393 // contentFrame is the out-of-flow frame and *aNewFrame is the
2395 nsIFrame
* contentFrame
;
2396 PRBool processChildren
= PR_FALSE
;
2398 // Check whether we need to build a XUL box or SVG root frame
2400 if (aDocElement
->IsXUL()) {
2401 contentFrame
= NS_NewDocElementBoxFrame(mPresShell
, styleContext
);
2402 if (NS_UNLIKELY(!contentFrame
)) {
2403 return NS_ERROR_OUT_OF_MEMORY
;
2405 InitAndRestoreFrame(state
, aDocElement
, mDocElementContainingBlock
, nsnull
,
2407 *aNewFrame
= contentFrame
;
2408 processChildren
= PR_TRUE
;
2413 if (aDocElement
->GetNameSpaceID() == kNameSpaceID_SVG
) {
2414 if (aDocElement
->Tag() == nsGkAtoms::svg
&& NS_SVGEnabled()) {
2415 contentFrame
= NS_NewSVGOuterSVGFrame(mPresShell
, styleContext
);
2416 if (NS_UNLIKELY(!contentFrame
)) {
2417 return NS_ERROR_OUT_OF_MEMORY
;
2419 InitAndRestoreFrame(state
, aDocElement
,
2420 state
.GetGeometricParent(display
,
2421 mDocElementContainingBlock
),
2422 nsnull
, contentFrame
);
2424 // AddChild takes care of transforming the frame tree for fixed-pos
2425 // or abs-pos situations
2426 nsFrameItems frameItems
;
2427 rv
= state
.AddChild(contentFrame
, frameItems
, aDocElement
,
2428 styleContext
, mDocElementContainingBlock
);
2429 if (NS_FAILED(rv
) || frameItems
.IsEmpty()) {
2432 *aNewFrame
= frameItems
.FirstChild();
2433 processChildren
= PR_TRUE
;
2435 // See if we need to create a view
2436 nsHTMLContainerFrame::CreateViewForFrame(contentFrame
, PR_FALSE
);
2438 return NS_ERROR_FAILURE
;
2444 PRBool docElemIsTable
= (display
->mDisplay
== NS_STYLE_DISPLAY_TABLE
);
2445 if (docElemIsTable
) {
2446 // We're going to call the right function ourselves, so no need to give a
2447 // function to this FrameConstructionData.
2449 // XXXbz on the other hand, if we converted this whole function to
2450 // FrameConstructionData/Item, then we'd need the right function
2451 // here... but would probably be able to get away with less code in this
2452 // function in general.
2453 // Use a null PendingBinding, since our binding is not in fact pending.
2454 static const FrameConstructionData rootTableData
= FCDATA_DECL(0, nsnull
);
2455 nsRefPtr
<nsStyleContext
> extraRef(styleContext
);
2456 FrameConstructionItem
item(&rootTableData
, aDocElement
,
2457 aDocElement
->Tag(), kNameSpaceID_None
,
2458 nsnull
, extraRef
.forget(), PR_TRUE
);
2460 nsFrameItems frameItems
;
2461 // if the document is a table then just populate it.
2462 rv
= ConstructTable(state
, item
, mDocElementContainingBlock
,
2463 styleContext
->GetStyleDisplay(),
2464 frameItems
, &contentFrame
);
2467 if (!contentFrame
|| frameItems
.IsEmpty())
2468 return NS_ERROR_FAILURE
;
2469 *aNewFrame
= frameItems
.FirstChild();
2470 NS_ASSERTION(frameItems
.OnlyChild(), "multiple root element frames");
2472 contentFrame
= NS_NewBlockFrame(mPresShell
, styleContext
,
2473 NS_BLOCK_FLOAT_MGR
|NS_BLOCK_MARGIN_ROOT
);
2475 return NS_ERROR_OUT_OF_MEMORY
;
2476 nsFrameItems frameItems
;
2477 // Use a null PendingBinding, since our binding is not in fact pending.
2478 rv
= ConstructBlock(state
, display
, aDocElement
,
2479 state
.GetGeometricParent(display
,
2480 mDocElementContainingBlock
),
2481 mDocElementContainingBlock
, styleContext
,
2482 &contentFrame
, frameItems
, display
->IsPositioned(),
2484 if (NS_FAILED(rv
) || frameItems
.IsEmpty())
2486 *aNewFrame
= frameItems
.FirstChild();
2487 NS_ASSERTION(frameItems
.OnlyChild(), "multiple root element frames");
2491 // set the primary frame
2492 aDocElement
->SetPrimaryFrame(contentFrame
);
2494 NS_ASSERTION(processChildren
? !mRootElementFrame
:
2495 mRootElementFrame
== contentFrame
,
2496 "unexpected mRootElementFrame");
2497 mRootElementFrame
= contentFrame
;
2499 // Figure out which frame has the main style for the document element,
2500 // assigning it to mRootElementStyleFrame.
2501 // Backgrounds should be propagated from that frame to the viewport.
2503 contentFrame
->GetParentStyleContextFrame(state
.mPresContext
,
2504 &mRootElementStyleFrame
, &isChild
);
2506 mRootElementStyleFrame
= mRootElementFrame
;
2509 if (processChildren
) {
2510 // Still need to process the child content
2511 nsFrameItems childItems
;
2513 NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame
),
2514 "Only XUL and SVG frames should reach here");
2515 // Use a null PendingBinding, since our binding is not in fact pending.
2516 ProcessChildren(state
, aDocElement
, styleContext
, contentFrame
, PR_TRUE
,
2517 childItems
, PR_FALSE
, nsnull
);
2519 // Set the initial child lists
2520 contentFrame
->SetInitialChildList(nsnull
, childItems
);
2523 SetInitialSingleChild(mDocElementContainingBlock
, *aNewFrame
);
2530 nsCSSFrameConstructor::ConstructRootFrame(nsIFrame
** aNewFrame
)
2532 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell
->GetPresContext(), FrameC
);
2533 NS_PRECONDITION(aNewFrame
, "null out param");
2535 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
2537 // Set up our style rule observer.
2538 // XXXbz wouldn't this make more sense as part of presshell init?
2540 styleSet
->SetBindingManager(mDocument
->BindingManager());
2543 // --------- BUILD VIEWPORT -----------
2544 nsIFrame
* viewportFrame
= nsnull
;
2545 nsRefPtr
<nsStyleContext
> viewportPseudoStyle
;
2547 viewportPseudoStyle
=
2548 styleSet
->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::viewport
, nsnull
);
2550 viewportFrame
= NS_NewViewportFrame(mPresShell
, viewportPseudoStyle
);
2552 // XXXbz do we _have_ to pass a null content pointer to that frame?
2553 // Would it really kill us to pass in the root element or something?
2554 // What would that break?
2555 viewportFrame
->Init(nsnull
, nsnull
, nsnull
);
2557 // Bind the viewport frame to the root view
2559 mPresShell
->GetViewManager()->GetRootView(rootView
);
2560 viewportFrame
->SetView(rootView
);
2562 nsContainerFrame::SyncFrameViewProperties(mPresShell
->GetPresContext(), viewportFrame
,
2563 viewportPseudoStyle
, rootView
);
2564 nsContainerFrame::SyncWindowProperties(mPresShell
->GetPresContext(), viewportFrame
,
2567 // The viewport is the containing block for 'fixed' elements
2568 mFixedContainingBlock
= viewportFrame
;
2570 *aNewFrame
= viewportFrame
;
2575 nsCSSFrameConstructor::SetUpDocElementContainingBlock(nsIContent
* aDocElement
)
2577 NS_PRECONDITION(aDocElement
, "No element?");
2578 NS_PRECONDITION(!aDocElement
->GetParent(), "Not root content?");
2579 NS_PRECONDITION(aDocElement
->GetCurrentDoc(), "Not in a document?");
2580 NS_PRECONDITION(aDocElement
->GetCurrentDoc()->GetRootElement() ==
2581 aDocElement
, "Not the root of the document?");
2584 how the root frame hierarchy should look
2586 Galley presentation, non-XUL, with scrolling (i.e. not a frameset):
2588 ViewportFrame [fixed-cb]
2590 nsCanvasFrame [abs-cb]
2591 root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2592 nsTableOuterFrame, nsPlaceholderFrame)
2594 Galley presentation, non-XUL, without scrolling (i.e. a frameset):
2596 ViewportFrame [fixed-cb]
2597 nsCanvasFrame [abs-cb]
2598 root element frame (nsBlockFrame)
2600 Galley presentation, XUL
2602 ViewportFrame [fixed-cb]
2604 root element frame (nsDocElementBoxFrame)
2606 Print presentation, non-XUL
2609 nsSimplePageSequenceFrame
2610 nsPageFrame [fixed-cb]
2612 nsCanvasFrame [abs-cb]
2613 root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2614 nsTableOuterFrame, nsPlaceholderFrame)
2616 Print-preview presentation, non-XUL
2620 nsSimplePageSequenceFrame
2621 nsPageFrame [fixed-cb]
2623 nsCanvasFrame [abs-cb]
2624 root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2625 nsTableOuterFrame, nsPlaceholderFrame)
2627 Print/print preview of XUL is not supported.
2628 [fixed-cb]: the default containing block for fixed-pos content
2629 [abs-cb]: the default containing block for abs-pos content
2631 Meaning of nsCSSFrameConstructor fields:
2632 mRootElementFrame is "root element frame". This is the primary frame for
2634 mDocElementContainingBlock is the parent of mRootElementFrame
2635 (i.e. nsCanvasFrame or nsRootBoxFrame)
2636 mFixedContainingBlock is the [fixed-cb]
2637 mGfxScrollFrame is the nsHTMLScrollFrame mentioned above, or null if there isn't one
2638 mPageSequenceFrame is the nsSimplePageSequenceFrame, or null if there isn't one
2641 // --------- CREATE ROOT FRAME -------
2644 // Create the root frame. The document element's frame is a child of the
2647 // The root frame serves two purposes:
2648 // - reserves space for any margins needed for the document element's frame
2649 // - renders the document element's background. This ensures the background covers
2650 // the entire canvas as specified by the CSS2 spec
2652 nsPresContext
* presContext
= mPresShell
->GetPresContext();
2653 PRBool isPaginated
= presContext
->IsRootPaginatedDocument();
2654 nsIFrame
* viewportFrame
= mFixedContainingBlock
;
2655 nsStyleContext
* viewportPseudoStyle
= viewportFrame
->GetStyleContext();
2657 nsIFrame
* rootFrame
= nsnull
;
2658 nsIAtom
* rootPseudo
;
2662 if (aDocElement
->IsXUL())
2664 // pass a temporary stylecontext, the correct one will be set later
2665 rootFrame
= NS_NewRootBoxFrame(mPresShell
, viewportPseudoStyle
);
2669 // pass a temporary stylecontext, the correct one will be set later
2670 rootFrame
= NS_NewCanvasFrame(mPresShell
, viewportPseudoStyle
);
2671 mHasRootAbsPosContainingBlock
= PR_TRUE
;
2674 rootPseudo
= nsCSSAnonBoxes::canvas
;
2675 mDocElementContainingBlock
= rootFrame
;
2677 // Create a page sequence frame
2678 rootFrame
= NS_NewSimplePageSequenceFrame(mPresShell
, viewportPseudoStyle
);
2679 mPageSequenceFrame
= rootFrame
;
2680 rootPseudo
= nsCSSAnonBoxes::pageSequence
;
2684 // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2686 // If the device supports scrolling (e.g., in galley mode on the screen and
2687 // for print-preview, but not when printing), then create a scroll frame that
2688 // will act as the scrolling mechanism for the viewport.
2689 // XXX Do we even need a viewport when printing to a printer?
2691 // As long as the docshell doesn't prohibit it, and the device supports
2692 // it, create a scroll frame that will act as the scolling mechanism for
2695 // Threre are three possible values stored in the docshell:
2696 // 1) nsIScrollable::Scrollbar_Never = no scrollbars
2697 // 2) nsIScrollable::Scrollbar_Auto = scrollbars appear if needed
2698 // 3) nsIScrollable::Scrollbar_Always = scrollbars always
2699 // Only need to create a scroll frame/view for cases 2 and 3.
2701 PRBool isHTML
= aDocElement
->IsHTML();
2702 PRBool isXUL
= PR_FALSE
;
2705 isXUL
= aDocElement
->IsXUL();
2708 // Never create scrollbars for XUL documents
2709 PRBool isScrollable
= !isXUL
;
2711 // Never create scrollbars for frameset documents.
2713 nsCOMPtr
<nsIHTMLDocument
> htmlDoc
= do_QueryInterface(mDocument
);
2714 if (htmlDoc
&& htmlDoc
->GetIsFrameset())
2715 isScrollable
= PR_FALSE
;
2719 isScrollable
= presContext
->HasPaginatedScrolling();
2722 // We no longer need to do overflow propagation here. It's taken care of
2723 // when we construct frames for the element whose overflow might be
2725 NS_ASSERTION(!isScrollable
|| !isXUL
,
2726 "XUL documents should never be scrollable - see above");
2728 nsIFrame
* newFrame
= rootFrame
;
2729 nsRefPtr
<nsStyleContext
> rootPseudoStyle
;
2730 // we must create a state because if the scrollbars are GFX it needs the
2731 // state to build the scrollbar frames.
2732 nsFrameConstructorState
state(mPresShell
, nsnull
, nsnull
, nsnull
);
2734 // Start off with the viewport as parent; we'll adjust it as needed.
2735 nsIFrame
* parentFrame
= viewportFrame
;
2737 nsStyleSet
* styleSet
= mPresShell
->StyleSet();
2738 // If paginated, make sure we don't put scrollbars in
2739 if (!isScrollable
) {
2740 rootPseudoStyle
= styleSet
->ResolveAnonymousBoxStyle(rootPseudo
,
2741 viewportPseudoStyle
);
2743 if (rootPseudo
== nsCSSAnonBoxes::canvas
) {
2744 rootPseudo
= nsCSSAnonBoxes::scrolledCanvas
;
2746 NS_ASSERTION(rootPseudo
== nsCSSAnonBoxes::pageSequence
,
2747 "Unknown root pseudo");
2748 rootPseudo
= nsCSSAnonBoxes::scrolledPageSequence
;
2751 // Build the frame. We give it the content we are wrapping which is the
2752 // document element, the root frame, the parent view port frame, and we
2753 // should get back the new frame and the scrollable view if one was
2756 // resolve a context for the scrollframe
2757 nsRefPtr
<nsStyleContext
> styleContext
;
2758 styleContext
= styleSet
->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::viewportScroll
,
2759 viewportPseudoStyle
);
2761 // Note that the viewport scrollframe is always built with
2762 // overflow:auto style. This forces the scroll frame to create
2763 // anonymous content for both scrollbars. This is necessary even
2764 // if the HTML or BODY elements are overriding the viewport
2765 // scroll style to 'hidden' --- dynamic style changes might put
2766 // scrollbars back on the viewport and we don't want to have to
2767 // reframe the viewport to create the scrollbar content.
2769 rootPseudoStyle
= BeginBuildingScrollFrame( state
,
2776 parentFrame
= newFrame
;
2777 mGfxScrollFrame
= newFrame
;
2780 rootFrame
->SetStyleContextWithoutNotification(rootPseudoStyle
);
2781 rootFrame
->Init(aDocElement
, parentFrame
, nsnull
);
2784 FinishBuildingScrollFrame(parentFrame
, rootFrame
);
2787 if (isPaginated
) { // paginated
2788 // Create the first page
2789 // Set the initial child lists
2790 nsIFrame
*pageFrame
, *canvasFrame
;
2791 ConstructPageFrame(mPresShell
, presContext
, rootFrame
, nsnull
,
2792 pageFrame
, canvasFrame
);
2793 SetInitialSingleChild(rootFrame
, pageFrame
);
2795 // The eventual parent of the document element frame.
2796 // XXX should this be set for every new page (in ConstructPageFrame)?
2797 mDocElementContainingBlock
= canvasFrame
;
2798 mHasRootAbsPosContainingBlock
= PR_TRUE
;
2801 if (viewportFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
) {
2802 SetInitialSingleChild(viewportFrame
, newFrame
);
2804 nsFrameList
newFrameList(newFrame
, newFrame
);
2805 viewportFrame
->AppendFrames(nsnull
, newFrameList
);
2812 nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell
* aPresShell
,
2813 nsPresContext
* aPresContext
,
2814 nsIFrame
* aParentFrame
,
2815 nsIFrame
* aPrevPageFrame
,
2816 nsIFrame
*& aPageFrame
,
2817 nsIFrame
*& aCanvasFrame
)
2819 nsStyleContext
* parentStyleContext
= aParentFrame
->GetStyleContext();
2820 nsStyleSet
*styleSet
= aPresShell
->StyleSet();
2822 nsRefPtr
<nsStyleContext
> pagePseudoStyle
;
2823 pagePseudoStyle
= styleSet
->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::page
,
2824 parentStyleContext
);
2826 aPageFrame
= NS_NewPageFrame(aPresShell
, pagePseudoStyle
);
2827 if (NS_UNLIKELY(!aPageFrame
))
2828 return NS_ERROR_OUT_OF_MEMORY
;
2830 // Initialize the page frame and force it to have a view. This makes printing of
2831 // the pages easier and faster.
2832 aPageFrame
->Init(nsnull
, aParentFrame
, aPrevPageFrame
);
2834 nsRefPtr
<nsStyleContext
> pageContentPseudoStyle
;
2835 pageContentPseudoStyle
=
2836 styleSet
->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::pageContent
,
2839 nsIFrame
* pageContentFrame
= NS_NewPageContentFrame(aPresShell
, pageContentPseudoStyle
);
2840 if (NS_UNLIKELY(!pageContentFrame
))
2841 return NS_ERROR_OUT_OF_MEMORY
;
2843 // Initialize the page content frame and force it to have a view. Also make it the
2844 // containing block for fixed elements which are repeated on every page.
2845 nsIFrame
* prevPageContentFrame
= nsnull
;
2846 if (aPrevPageFrame
) {
2847 prevPageContentFrame
= aPrevPageFrame
->GetFirstChild(nsnull
);
2848 NS_ASSERTION(prevPageContentFrame
, "missing page content frame");
2850 pageContentFrame
->Init(nsnull
, aPageFrame
, prevPageContentFrame
);
2851 SetInitialSingleChild(aPageFrame
, pageContentFrame
);
2852 mFixedContainingBlock
= pageContentFrame
;
2854 nsRefPtr
<nsStyleContext
> canvasPseudoStyle
;
2855 canvasPseudoStyle
= styleSet
->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::canvas
,
2856 pageContentPseudoStyle
);
2858 aCanvasFrame
= NS_NewCanvasFrame(aPresShell
, canvasPseudoStyle
);
2859 if (NS_UNLIKELY(!aCanvasFrame
))
2860 return NS_ERROR_OUT_OF_MEMORY
;
2862 nsIFrame
* prevCanvasFrame
= nsnull
;
2863 if (prevPageContentFrame
) {
2864 prevCanvasFrame
= prevPageContentFrame
->GetFirstChild(nsnull
);
2865 NS_ASSERTION(prevCanvasFrame
, "missing canvas frame");
2867 aCanvasFrame
->Init(nsnull
, pageContentFrame
, prevCanvasFrame
);
2868 SetInitialSingleChild(pageContentFrame
, aCanvasFrame
);
2875 nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell
* aPresShell
,
2876 nsIContent
* aContent
,
2878 nsStyleContext
* aStyleContext
,
2879 nsIFrame
* aParentFrame
,
2880 nsIFrame
* aPrevInFlow
,
2881 nsFrameState aTypeBit
,
2882 nsIFrame
** aPlaceholderFrame
)
2884 nsRefPtr
<nsStyleContext
> placeholderStyle
= aPresShell
->StyleSet()->
2885 ResolveStyleForNonElement(aStyleContext
->GetParent());
2887 // The placeholder frame gets a pseudo style context
2888 nsPlaceholderFrame
* placeholderFrame
=
2889 (nsPlaceholderFrame
*)NS_NewPlaceholderFrame(aPresShell
, placeholderStyle
,
2892 if (placeholderFrame
) {
2893 placeholderFrame
->Init(aContent
, aParentFrame
, aPrevInFlow
);
2895 // The placeholder frame has a pointer back to the out-of-flow frame
2896 placeholderFrame
->SetOutOfFlowFrame(aFrame
);
2898 aFrame
->AddStateBits(NS_FRAME_OUT_OF_FLOW
);
2900 // Add mapping from absolutely positioned frame to its placeholder frame
2901 aPresShell
->FrameManager()->RegisterPlaceholderFrame(placeholderFrame
);
2903 *aPlaceholderFrame
= static_cast<nsIFrame
*>(placeholderFrame
);
2908 return NS_ERROR_OUT_OF_MEMORY
;
2912 // Clears any lazy bits set in the range [aStartContent, aEndContent). If
2913 // aEndContent is null, that means to clear bits in all siblings starting with
2914 // aStartContent. aStartContent must not be null unless aEndContent is also
2915 // null. We do this so that when new children are inserted under elements whose
2916 // frame is a leaf the new children don't cause us to try to construct frames
2917 // for the existing children again.
2919 ClearLazyBits(nsIContent
* aStartContent
, nsIContent
* aEndContent
)
2921 NS_PRECONDITION(aStartContent
|| !aEndContent
,
2922 "Must have start child if we have an end child");
2923 for (nsIContent
* cur
= aStartContent
; cur
!= aEndContent
;
2924 cur
= cur
->GetNextSibling()) {
2925 cur
->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME
);
2930 nsCSSFrameConstructor::ConstructButtonFrame(nsFrameConstructorState
& aState
,
2931 FrameConstructionItem
& aItem
,
2932 nsIFrame
* aParentFrame
,
2933 const nsStyleDisplay
* aStyleDisplay
,
2934 nsFrameItems
& aFrameItems
,
2935 nsIFrame
** aNewFrame
)
2937 *aNewFrame
= nsnull
;
2938 nsIFrame
* buttonFrame
= nsnull
;
2939 nsIContent
* const content
= aItem
.mContent
;
2940 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
2942 if (nsGkAtoms::button
== aItem
.mTag
) {
2943 buttonFrame
= NS_NewHTMLButtonControlFrame(mPresShell
, styleContext
);
2946 buttonFrame
= NS_NewGfxButtonControlFrame(mPresShell
, styleContext
);
2948 if (NS_UNLIKELY(!buttonFrame
)) {
2949 return NS_ERROR_OUT_OF_MEMORY
;
2951 // Initialize the button frame
2952 nsresult rv
= InitAndRestoreFrame(aState
, content
,
2953 aState
.GetGeometricParent(aStyleDisplay
, aParentFrame
),
2954 nsnull
, buttonFrame
);
2955 if (NS_FAILED(rv
)) {
2956 buttonFrame
->Destroy();
2959 // See if we need to create a view
2960 nsHTMLContainerFrame::CreateViewForFrame(buttonFrame
, PR_FALSE
);
2962 nsRefPtr
<nsStyleContext
> innerBlockContext
;
2964 mPresShell
->StyleSet()->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::buttonContent
,
2967 nsIFrame
* blockFrame
= NS_NewBlockFrame(mPresShell
, innerBlockContext
,
2968 NS_BLOCK_FLOAT_MGR
);
2970 if (NS_UNLIKELY(!blockFrame
)) {
2971 buttonFrame
->Destroy();
2972 return NS_ERROR_OUT_OF_MEMORY
;
2974 rv
= InitAndRestoreFrame(aState
, content
, buttonFrame
, nsnull
, blockFrame
);
2975 if (NS_FAILED(rv
)) {
2976 blockFrame
->Destroy();
2977 buttonFrame
->Destroy();
2981 rv
= aState
.AddChild(buttonFrame
, aFrameItems
, content
, styleContext
,
2983 if (NS_FAILED(rv
)) {
2984 blockFrame
->Destroy();
2985 buttonFrame
->Destroy();
2989 PRBool isLeaf
= buttonFrame
->IsLeaf();
2991 // Make sure that we're an anonymous content creator exactly when we're a
2993 nsIAnonymousContentCreator
* creator
= do_QueryFrame(buttonFrame
);
2994 NS_ASSERTION(!creator
== !isLeaf
,
2995 "Should be creator exactly when we're a leaf");
3000 nsFrameConstructorSaveState absoluteSaveState
;
3001 nsFrameItems childItems
;
3003 if (aStyleDisplay
->IsPositioned()) {
3004 // The area frame becomes a container for child frames that are
3005 // absolutely positioned
3006 aState
.PushAbsoluteContainingBlock(blockFrame
, absoluteSaveState
);
3010 // Make sure that anonymous child creation will have no effect in this case
3011 nsIAnonymousContentCreator
* creator
= do_QueryFrame(blockFrame
);
3012 NS_ASSERTION(!creator
, "Shouldn't be an anonymous content creator!");
3015 rv
= ProcessChildren(aState
, content
, styleContext
, blockFrame
, PR_TRUE
,
3016 childItems
, aStyleDisplay
->IsBlockInside(),
3017 aItem
.mPendingBinding
);
3018 if (NS_FAILED(rv
)) return rv
;
3020 // Set the areas frame's initial child lists
3021 blockFrame
->SetInitialChildList(nsnull
, childItems
);
3024 SetInitialSingleChild(buttonFrame
, blockFrame
);
3027 ClearLazyBits(content
->GetFirstChild(), nsnull
);
3029 nsFrameItems anonymousChildItems
;
3030 // if there are any anonymous children create frames for them. Note that
3031 // we're doing this using a different parent frame from the one we pass to
3033 CreateAnonymousFrames(aState
, content
, buttonFrame
, aItem
.mPendingBinding
,
3034 anonymousChildItems
);
3035 if (anonymousChildItems
.NotEmpty()) {
3036 // the anonymous content is already parented to the area frame
3037 aState
.mFrameManager
->AppendFrames(blockFrame
, nsnull
,
3038 anonymousChildItems
);
3042 // our new button frame returned is the top frame.
3043 *aNewFrame
= buttonFrame
;
3049 nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState
& aState
,
3050 FrameConstructionItem
& aItem
,
3051 nsIFrame
* aParentFrame
,
3052 const nsStyleDisplay
* aStyleDisplay
,
3053 nsFrameItems
& aFrameItems
,
3054 nsIFrame
** aNewFrame
)
3056 nsresult rv
= NS_OK
;
3057 const PRInt32 kNoSizeSpecified
= -1;
3059 nsIContent
* const content
= aItem
.mContent
;
3060 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
3062 // Construct a frame-based listbox or combobox
3063 nsCOMPtr
<nsIDOMHTMLSelectElement
> sel(do_QueryInterface(content
));
3066 sel
->GetSize(&size
);
3067 PRBool multipleSelect
= PR_FALSE
;
3068 sel
->GetMultiple(&multipleSelect
);
3069 // Construct a combobox if size=1 or no size is specified and its multiple select
3070 if (((1 == size
|| 0 == size
) || (kNoSizeSpecified
== size
)) && (PR_FALSE
== multipleSelect
)) {
3071 // Construct a frame-based combo box.
3072 // The frame-based combo box is built out of three parts. A display area, a button and
3073 // a dropdown list. The display area and button are created through anonymous content.
3074 // The drop-down list's frame is created explicitly. The combobox frame shares its content
3075 // with the drop-down list.
3076 PRUint32 flags
= NS_BLOCK_FLOAT_MGR
;
3077 nsIFrame
* comboboxFrame
= NS_NewComboboxControlFrame(mPresShell
, styleContext
, flags
);
3079 // Save the history state so we don't restore during construction
3080 // since the complete tree is required before we restore.
3081 nsILayoutHistoryState
*historyState
= aState
.mFrameState
;
3082 aState
.mFrameState
= nsnull
;
3083 // Initialize the combobox frame
3084 InitAndRestoreFrame(aState
, content
,
3085 aState
.GetGeometricParent(aStyleDisplay
, aParentFrame
),
3086 nsnull
, comboboxFrame
);
3088 nsHTMLContainerFrame::CreateViewForFrame(comboboxFrame
, PR_FALSE
);
3090 rv
= aState
.AddChild(comboboxFrame
, aFrameItems
, content
, styleContext
,
3092 if (NS_FAILED(rv
)) {
3096 ///////////////////////////////////////////////////////////////////
3097 // Combobox - Old Native Implementation
3098 ///////////////////////////////////////////////////////////////////
3099 nsIComboboxControlFrame
* comboBox
= do_QueryFrame(comboboxFrame
);
3100 NS_ASSERTION(comboBox
, "NS_NewComboboxControlFrame returned frame that "
3101 "doesn't implement nsIComboboxControlFrame");
3103 // Resolve pseudo element style for the dropdown list
3104 nsRefPtr
<nsStyleContext
> listStyle
;
3105 listStyle
= mPresShell
->StyleSet()->
3106 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::dropDownList
, styleContext
);
3109 nsIFrame
* listFrame
= NS_NewListControlFrame(mPresShell
, listStyle
);
3111 // Notify the listbox that it is being used as a dropdown list.
3112 nsIListControlFrame
* listControlFrame
= do_QueryFrame(listFrame
);
3113 if (listControlFrame
) {
3114 listControlFrame
->SetComboboxFrame(comboboxFrame
);
3116 // Notify combobox that it should use the listbox as it's popup
3117 comboBox
->SetDropDown(listFrame
);
3119 NS_ASSERTION(!listStyle
->GetStyleDisplay()->IsPositioned(),
3120 "Ended up with positioned dropdown list somehow.");
3121 NS_ASSERTION(!listStyle
->GetStyleDisplay()->IsFloating(),
3122 "Ended up with floating dropdown list somehow.");
3124 // Initialize the scroll frame positioned. Note that it is NOT
3125 // initialized as absolutely positioned.
3126 nsIFrame
* scrolledFrame
= NS_NewSelectsAreaFrame(mPresShell
, styleContext
, flags
);
3128 InitializeSelectFrame(aState
, listFrame
, scrolledFrame
, content
,
3129 comboboxFrame
, listStyle
, PR_TRUE
,
3130 aItem
.mPendingBinding
, aFrameItems
);
3132 // Set flag so the events go to the listFrame not child frames.
3133 // XXX: We should replace this with a real widget manager similar
3134 // to how the nsFormControlFrame works. Re-directing events is a temporary Kludge.
3135 NS_ASSERTION(listFrame
->GetView(), "ListFrame's view is nsnull");
3136 //listFrame->GetView()->SetViewFlags(NS_VIEW_PUBLIC_FLAG_DONT_CHECK_CHILDREN);
3138 // Create display and button frames from the combobox's anonymous content.
3139 // The anonymous content is appended to existing anonymous content for this
3140 // element (the scrollbars).
3142 nsFrameItems childItems
;
3143 CreateAnonymousFrames(aState
, content
, comboboxFrame
,
3144 aItem
.mPendingBinding
, childItems
);
3146 comboboxFrame
->SetInitialChildList(nsnull
, childItems
);
3148 // Initialize the additional popup child list which contains the
3149 // dropdown list frame.
3150 nsFrameItems popupItems
;
3151 popupItems
.AddChild(listFrame
);
3152 comboboxFrame
->SetInitialChildList(nsGkAtoms::selectPopupList
,
3155 *aNewFrame
= comboboxFrame
;
3156 aState
.mFrameState
= historyState
;
3157 if (aState
.mFrameState
&& aState
.mFrameManager
) {
3158 // Restore frame state for the entire subtree of |comboboxFrame|.
3159 aState
.mFrameManager
->RestoreFrameState(comboboxFrame
,
3160 aState
.mFrameState
);
3163 ///////////////////////////////////////////////////////////////////
3164 // ListBox - Old Native Implementation
3165 ///////////////////////////////////////////////////////////////////
3166 nsIFrame
* listFrame
= NS_NewListControlFrame(mPresShell
, styleContext
);
3171 rv
= NS_ERROR_OUT_OF_MEMORY
;
3174 nsIFrame
* scrolledFrame
= NS_NewSelectsAreaFrame(
3175 mPresShell
, styleContext
, NS_BLOCK_FLOAT_MGR
);
3177 // ******* this code stolen from Initialze ScrollFrame ********
3178 // please adjust this code to use BuildScrollFrame.
3180 InitializeSelectFrame(aState
, listFrame
, scrolledFrame
, content
,
3181 aParentFrame
, styleContext
, PR_FALSE
,
3182 aItem
.mPendingBinding
, aFrameItems
);
3184 *aNewFrame
= listFrame
;
3192 * Used to be InitializeScrollFrame but now it's only used for the select tag
3193 * But the select tag should really be fixed to use GFX scrollbars that can
3194 * be create with BuildScrollFrame.
3197 nsCSSFrameConstructor::InitializeSelectFrame(nsFrameConstructorState
& aState
,
3198 nsIFrame
* scrollFrame
,
3199 nsIFrame
* scrolledFrame
,
3200 nsIContent
* aContent
,
3201 nsIFrame
* aParentFrame
,
3202 nsStyleContext
* aStyleContext
,
3203 PRBool aBuildCombobox
,
3204 PendingBinding
* aPendingBinding
,
3205 nsFrameItems
& aFrameItems
)
3207 const nsStyleDisplay
* display
= aStyleContext
->GetStyleDisplay();
3210 nsIFrame
* geometricParent
= aState
.GetGeometricParent(display
, aParentFrame
);
3212 // We don't call InitAndRestoreFrame for scrollFrame because we can only
3213 // restore the frame state after its parts have been created (in particular,
3214 // the scrollable view). So we have to split Init and Restore.
3216 // Initialize the frame
3217 scrollFrame
->Init(aContent
, geometricParent
, nsnull
);
3219 if (!aBuildCombobox
) {
3220 nsresult rv
= aState
.AddChild(scrollFrame
, aFrameItems
, aContent
,
3221 aStyleContext
, aParentFrame
);
3222 if (NS_FAILED(rv
)) {
3227 nsHTMLContainerFrame::CreateViewForFrame(scrollFrame
, aBuildCombobox
);
3228 if (aBuildCombobox
) {
3229 // Give the drop-down list a popup widget
3230 nsIView
* view
= scrollFrame
->GetView();
3231 NS_ASSERTION(view
, "We asked for a view but didn't get one");
3233 view
->GetViewManager()->SetViewFloating(view
, PR_TRUE
);
3235 nsWidgetInitData widgetData
;
3236 widgetData
.mWindowType
= eWindowType_popup
;
3237 widgetData
.mBorderStyle
= eBorderStyle_default
;
3238 view
->CreateWidgetForPopup(&widgetData
);
3242 BuildScrollFrame(aState
, aContent
, aStyleContext
, scrolledFrame
,
3243 geometricParent
, scrollFrame
);
3245 if (aState
.mFrameState
&& aState
.mFrameManager
) {
3246 // Restore frame state for the scroll frame
3247 aState
.mFrameManager
->RestoreFrameStateFor(scrollFrame
, aState
.mFrameState
);
3251 nsFrameConstructorSaveState absoluteSaveState
;
3252 nsFrameItems childItems
;
3254 if (display
->IsPositioned()) {
3255 // The area frame becomes a container for child frames that are
3256 // absolutely positioned
3257 aState
.PushAbsoluteContainingBlock(scrolledFrame
, absoluteSaveState
);
3260 ProcessChildren(aState
, aContent
, aStyleContext
, scrolledFrame
, PR_FALSE
,
3261 childItems
, PR_FALSE
, aPendingBinding
);
3263 // Set the scrolled frame's initial child lists
3264 scrolledFrame
->SetInitialChildList(nsnull
, childItems
);
3269 nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState
& aState
,
3270 FrameConstructionItem
& aItem
,
3271 nsIFrame
* aParentFrame
,
3272 const nsStyleDisplay
* aStyleDisplay
,
3273 nsFrameItems
& aFrameItems
,
3274 nsIFrame
** aNewFrame
)
3276 nsIContent
* const content
= aItem
.mContent
;
3277 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
3279 nsIFrame
* newFrame
= NS_NewFieldSetFrame(mPresShell
, styleContext
);
3280 if (NS_UNLIKELY(!newFrame
)) {
3281 return NS_ERROR_OUT_OF_MEMORY
;
3285 InitAndRestoreFrame(aState
, content
,
3286 aState
.GetGeometricParent(aStyleDisplay
, aParentFrame
),
3289 // See if we need to create a view, e.g. the frame is absolutely
3291 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
3293 // Resolve style and initialize the frame
3294 nsRefPtr
<nsStyleContext
> fieldsetContentStyle
;
3295 fieldsetContentStyle
= mPresShell
->StyleSet()->
3296 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::fieldsetContent
, styleContext
);
3298 nsIFrame
* blockFrame
= NS_NewBlockFrame(mPresShell
, fieldsetContentStyle
,
3299 NS_BLOCK_FLOAT_MGR
|
3300 NS_BLOCK_MARGIN_ROOT
);
3301 InitAndRestoreFrame(aState
, content
, newFrame
, nsnull
, blockFrame
);
3303 nsresult rv
= aState
.AddChild(newFrame
, aFrameItems
, content
, styleContext
,
3305 if (NS_FAILED(rv
)) {
3310 nsFrameConstructorSaveState absoluteSaveState
;
3311 nsFrameItems childItems
;
3313 if (aStyleDisplay
->IsPositioned()) {
3314 // The area frame becomes a container for child frames that are
3315 // absolutely positioned
3316 // XXXbz this is probably wrong, and once arbitrary frames can be absolute
3317 // containing blocks we should fix this..
3318 aState
.PushAbsoluteContainingBlock(blockFrame
, absoluteSaveState
);
3321 ProcessChildren(aState
, content
, styleContext
, blockFrame
, PR_TRUE
,
3322 childItems
, PR_TRUE
, aItem
.mPendingBinding
);
3324 nsFrameItems fieldsetKids
;
3325 fieldsetKids
.AddChild(blockFrame
);
3327 for (nsFrameList::Enumerator
e(childItems
); !e
.AtEnd(); e
.Next()) {
3328 nsLegendFrame
* legendFrame
= do_QueryFrame(e
.get());
3330 // We want the legend to be the first frame in the fieldset child list.
3331 // That way the EventStateManager will do the right thing when tabbing
3332 // from a selection point within the legend (bug 236071), which is
3333 // used for implementing legend access keys (bug 81481).
3334 // GetAdjustedParentFrame() below depends on this frame order.
3335 childItems
.RemoveFrame(legendFrame
);
3336 // Make sure to reparent the legend so it has the fieldset as the parent.
3337 fieldsetKids
.InsertFrame(newFrame
, nsnull
, legendFrame
);
3342 // Set the inner frame's initial child lists
3343 blockFrame
->SetInitialChildList(nsnull
, childItems
);
3345 // Set the outer frame's initial child list
3346 newFrame
->SetInitialChildList(nsnull
, fieldsetKids
);
3348 // our new frame returned is the top frame which is the list frame.
3349 *aNewFrame
= newFrame
;
3355 FindAncestorWithGeneratedContentPseudo(nsIFrame
* aFrame
)
3357 for (nsIFrame
* f
= aFrame
->GetParent(); f
; f
= f
->GetParent()) {
3358 NS_ASSERTION(f
->IsGeneratedContentFrame(),
3359 "should not have exited generated content");
3360 nsIAtom
* pseudo
= f
->GetStyleContext()->GetPseudo();
3361 if (pseudo
== nsCSSPseudoElements::before
||
3362 pseudo
== nsCSSPseudoElements::after
)
3368 #define SIMPLE_FCDATA(_func) FCDATA_DECL(0, _func)
3369 #define FULL_CTOR_FCDATA(_flags, _func) \
3370 { _flags | FCDATA_FUNC_IS_FULL_CTOR, { nsnull }, _func }
3373 const nsCSSFrameConstructor::FrameConstructionData
*
3374 nsCSSFrameConstructor::FindTextData(nsIFrame
* aParentFrame
)
3377 if (aParentFrame
&& aParentFrame
->IsFrameOfType(nsIFrame::eSVG
)) {
3378 nsIFrame
*ancestorFrame
=
3379 nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame
);
3380 if (ancestorFrame
) {
3381 nsSVGTextContainerFrame
* metrics
= do_QueryFrame(ancestorFrame
);
3383 static const FrameConstructionData sSVGGlyphData
=
3384 SIMPLE_FCDATA(NS_NewSVGGlyphFrame
);
3385 return &sSVGGlyphData
;
3392 static const FrameConstructionData sTextData
=
3393 FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT
, NS_NewTextFrame
);
3398 nsCSSFrameConstructor::ConstructTextFrame(const FrameConstructionData
* aData
,
3399 nsFrameConstructorState
& aState
,
3400 nsIContent
* aContent
,
3401 nsIFrame
* aParentFrame
,
3402 nsStyleContext
* aStyleContext
,
3403 nsFrameItems
& aFrameItems
)
3405 NS_PRECONDITION(aData
, "Must have frame construction data");
3407 nsIFrame
* newFrame
= (*aData
->mFunc
.mCreationFunc
)(mPresShell
, aStyleContext
);
3409 if (NS_UNLIKELY(!newFrame
))
3410 return NS_ERROR_OUT_OF_MEMORY
;
3412 nsresult rv
= InitAndRestoreFrame(aState
, aContent
, aParentFrame
,
3415 if (NS_FAILED(rv
)) {
3416 newFrame
->Destroy();
3420 // We never need to create a view for a text frame.
3422 if (newFrame
->IsGeneratedContentFrame()) {
3423 nsAutoPtr
<nsGenConInitializer
> initializer
;
3425 static_cast<nsGenConInitializer
*>(
3426 aContent
->UnsetProperty(nsGkAtoms::genConInitializerProperty
));
3428 if (initializer
->mNode
->InitTextFrame(initializer
->mList
,
3429 FindAncestorWithGeneratedContentPseudo(newFrame
), newFrame
)) {
3430 (this->*(initializer
->mDirtyAll
))();
3432 initializer
->mNode
.forget();
3436 // Add the newly constructed frame to the flow
3437 aFrameItems
.AddChild(newFrame
);
3439 if (aState
.mSetPrimaryFrames
)
3440 aContent
->SetPrimaryFrame(newFrame
);
3446 const nsCSSFrameConstructor::FrameConstructionData
*
3447 nsCSSFrameConstructor::FindDataByInt(PRInt32 aInt
,
3448 nsIContent
* aContent
,
3449 nsStyleContext
* aStyleContext
,
3450 const FrameConstructionDataByInt
* aDataPtr
,
3451 PRUint32 aDataLength
)
3453 for (const FrameConstructionDataByInt
*curData
= aDataPtr
,
3454 *endData
= aDataPtr
+ aDataLength
;
3457 if (curData
->mInt
== aInt
) {
3458 const FrameConstructionData
* data
= &curData
->mData
;
3459 if (data
->mBits
& FCDATA_FUNC_IS_DATA_GETTER
) {
3460 return data
->mFunc
.mDataGetter(aContent
, aStyleContext
);
3471 const nsCSSFrameConstructor::FrameConstructionData
*
3472 nsCSSFrameConstructor::FindDataByTag(nsIAtom
* aTag
,
3473 nsIContent
* aContent
,
3474 nsStyleContext
* aStyleContext
,
3475 const FrameConstructionDataByTag
* aDataPtr
,
3476 PRUint32 aDataLength
)
3478 for (const FrameConstructionDataByTag
*curData
= aDataPtr
,
3479 *endData
= aDataPtr
+ aDataLength
;
3482 if (*curData
->mTag
== aTag
) {
3483 const FrameConstructionData
* data
= &curData
->mData
;
3484 if (data
->mBits
& FCDATA_FUNC_IS_DATA_GETTER
) {
3485 return data
->mFunc
.mDataGetter(aContent
, aStyleContext
);
3495 #define SUPPRESS_FCDATA() FCDATA_DECL(FCDATA_SUPPRESS_FRAME, nsnull)
3496 #define SIMPLE_INT_CREATE(_int, _func) { _int, SIMPLE_FCDATA(_func) }
3497 #define SIMPLE_INT_CHAIN(_int, _func) \
3498 { _int, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
3499 #define COMPLEX_INT_CREATE(_int, _func) \
3500 { _int, FULL_CTOR_FCDATA(0, _func) }
3502 #define SIMPLE_TAG_CREATE(_tag, _func) \
3503 { &nsGkAtoms::_tag, SIMPLE_FCDATA(_func) }
3504 #define SIMPLE_TAG_CHAIN(_tag, _func) \
3505 { &nsGkAtoms::_tag, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
3506 #define COMPLEX_TAG_CREATE(_tag, _func) \
3507 { &nsGkAtoms::_tag, FULL_CTOR_FCDATA(0, _func) }
3510 const nsCSSFrameConstructor::FrameConstructionData
*
3511 nsCSSFrameConstructor::FindHTMLData(nsIContent
* aContent
,
3513 PRInt32 aNameSpaceID
,
3514 nsIFrame
* aParentFrame
,
3515 nsStyleContext
* aStyleContext
)
3517 // Ignore the tag if it's not HTML content and if it doesn't extend (via XBL)
3518 // a valid HTML namespace. This check must match the one in
3519 // ShouldHaveFirstLineStyle.
3520 if (aNameSpaceID
!= kNameSpaceID_XHTML
) {
3524 NS_ASSERTION(!aParentFrame
||
3525 aParentFrame
->GetStyleContext()->GetPseudo() !=
3526 nsCSSAnonBoxes::fieldsetContent
||
3527 aParentFrame
->GetParent()->GetType() == nsGkAtoms::fieldSetFrame
,
3528 "Unexpected parent for fieldset content anon box");
3529 if (aTag
== nsGkAtoms::legend
&&
3531 (aParentFrame
->GetType() != nsGkAtoms::fieldSetFrame
&&
3532 aParentFrame
->GetStyleContext()->GetPseudo() !=
3533 nsCSSAnonBoxes::fieldsetContent
) ||
3534 !aContent
->GetParent() ||
3535 !aContent
->GetParent()->IsHTML() ||
3536 aContent
->GetParent()->Tag() != nsGkAtoms::fieldset
||
3537 aStyleContext
->GetStyleDisplay()->IsFloating() ||
3538 aStyleContext
->GetStyleDisplay()->IsAbsolutelyPositioned())) {
3539 // <legend> is only special inside fieldset, check both the frame tree
3540 // parent and content tree parent due to XBL issues. For floated or
3541 // absolutely positioned legends we want to construct by display type and
3542 // not do special legend stuff.
3543 // XXXbz it would be nice if we could just decide this based on the parent
3544 // tag, and hence just use a SIMPLE_TAG_CHAIN for legend below, but the
3545 // fact that with XBL we could end up with this legend element in some
3546 // totally weird insertion point makes that chancy, I think.
3550 static const FrameConstructionDataByTag sHTMLData
[] = {
3551 SIMPLE_TAG_CHAIN(img
, nsCSSFrameConstructor::FindImgData
),
3552 SIMPLE_TAG_CHAIN(mozgeneratedcontentimage
,
3553 nsCSSFrameConstructor::FindImgData
),
3555 FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT
| FCDATA_IS_LINE_BREAK
,
3557 SIMPLE_TAG_CREATE(wbr
, NS_NewWBRFrame
),
3558 SIMPLE_TAG_CHAIN(input
, nsCSSFrameConstructor::FindInputData
),
3559 SIMPLE_TAG_CREATE(textarea
, NS_NewTextControlFrame
),
3560 COMPLEX_TAG_CREATE(select
, &nsCSSFrameConstructor::ConstructSelectFrame
),
3561 SIMPLE_TAG_CHAIN(object
, nsCSSFrameConstructor::FindObjectData
),
3562 SIMPLE_TAG_CHAIN(applet
, nsCSSFrameConstructor::FindObjectData
),
3563 SIMPLE_TAG_CHAIN(embed
, nsCSSFrameConstructor::FindObjectData
),
3564 COMPLEX_TAG_CREATE(fieldset
,
3565 &nsCSSFrameConstructor::ConstructFieldSetFrame
),
3566 { &nsGkAtoms::legend
,
3567 FCDATA_DECL(FCDATA_ALLOW_BLOCK_STYLES
, NS_NewLegendFrame
) },
3568 SIMPLE_TAG_CREATE(frameset
, NS_NewHTMLFramesetFrame
),
3569 SIMPLE_TAG_CREATE(iframe
, NS_NewSubDocumentFrame
),
3570 COMPLEX_TAG_CREATE(button
, &nsCSSFrameConstructor::ConstructButtonFrame
),
3571 SIMPLE_TAG_CREATE(canvas
, NS_NewHTMLCanvasFrame
),
3572 #if defined(MOZ_MEDIA)
3573 SIMPLE_TAG_CREATE(video
, NS_NewHTMLVideoFrame
),
3574 SIMPLE_TAG_CREATE(audio
, NS_NewHTMLVideoFrame
),
3576 SIMPLE_TAG_CREATE(isindex
, NS_NewIsIndexFrame
)
3579 return FindDataByTag(aTag
, aContent
, aStyleContext
, sHTMLData
,
3580 NS_ARRAY_LENGTH(sHTMLData
));
3584 const nsCSSFrameConstructor::FrameConstructionData
*
3585 nsCSSFrameConstructor::FindImgData(nsIContent
* aContent
,
3586 nsStyleContext
* aStyleContext
)
3588 if (!nsImageFrame::ShouldCreateImageFrameFor(aContent
, aStyleContext
)) {
3592 static const FrameConstructionData sImgData
= SIMPLE_FCDATA(NS_NewImageFrame
);
3597 const nsCSSFrameConstructor::FrameConstructionData
*
3598 nsCSSFrameConstructor::FindImgControlData(nsIContent
* aContent
,
3599 nsStyleContext
* aStyleContext
)
3601 if (!nsImageFrame::ShouldCreateImageFrameFor(aContent
, aStyleContext
)) {
3605 static const FrameConstructionData sImgControlData
=
3606 SIMPLE_FCDATA(NS_NewImageControlFrame
);
3607 return &sImgControlData
;
3611 const nsCSSFrameConstructor::FrameConstructionData
*
3612 nsCSSFrameConstructor::FindInputData(nsIContent
* aContent
,
3613 nsStyleContext
* aStyleContext
)
3615 static const FrameConstructionDataByInt sInputData
[] = {
3616 SIMPLE_INT_CREATE(NS_FORM_INPUT_CHECKBOX
, NS_NewGfxCheckboxControlFrame
),
3617 SIMPLE_INT_CREATE(NS_FORM_INPUT_RADIO
, NS_NewGfxRadioControlFrame
),
3618 SIMPLE_INT_CREATE(NS_FORM_INPUT_FILE
, NS_NewFileControlFrame
),
3619 SIMPLE_INT_CHAIN(NS_FORM_INPUT_IMAGE
,
3620 nsCSSFrameConstructor::FindImgControlData
),
3621 SIMPLE_INT_CREATE(NS_FORM_INPUT_EMAIL
, NS_NewTextControlFrame
),
3622 SIMPLE_INT_CREATE(NS_FORM_INPUT_SEARCH
, NS_NewTextControlFrame
),
3623 SIMPLE_INT_CREATE(NS_FORM_INPUT_TEXT
, NS_NewTextControlFrame
),
3624 SIMPLE_INT_CREATE(NS_FORM_INPUT_TEL
, NS_NewTextControlFrame
),
3625 SIMPLE_INT_CREATE(NS_FORM_INPUT_URL
, NS_NewTextControlFrame
),
3626 SIMPLE_INT_CREATE(NS_FORM_INPUT_PASSWORD
, NS_NewTextControlFrame
),
3627 COMPLEX_INT_CREATE(NS_FORM_INPUT_SUBMIT
,
3628 &nsCSSFrameConstructor::ConstructButtonFrame
),
3629 COMPLEX_INT_CREATE(NS_FORM_INPUT_RESET
,
3630 &nsCSSFrameConstructor::ConstructButtonFrame
),
3631 COMPLEX_INT_CREATE(NS_FORM_INPUT_BUTTON
,
3632 &nsCSSFrameConstructor::ConstructButtonFrame
)
3633 // Keeping hidden inputs out of here on purpose for so they get frames by
3634 // display (in practice, none).
3637 nsCOMPtr
<nsIFormControl
> control
= do_QueryInterface(aContent
);
3638 NS_ASSERTION(control
, "input doesn't implement nsIFormControl?");
3640 return FindDataByInt(control
->GetType(), aContent
, aStyleContext
,
3641 sInputData
, NS_ARRAY_LENGTH(sInputData
));
3645 const nsCSSFrameConstructor::FrameConstructionData
*
3646 nsCSSFrameConstructor::FindObjectData(nsIContent
* aContent
,
3647 nsStyleContext
* aStyleContext
)
3649 // GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for
3650 // cases when the object is broken/suppressed/etc (e.g. a broken image), but
3651 // we want to treat those cases as TYPE_NULL
3653 if (aContent
->IntrinsicState() &
3654 (NS_EVENT_STATE_BROKEN
| NS_EVENT_STATE_USERDISABLED
|
3655 NS_EVENT_STATE_SUPPRESSED
)) {
3656 type
= nsIObjectLoadingContent::TYPE_NULL
;
3658 nsCOMPtr
<nsIObjectLoadingContent
> objContent(do_QueryInterface(aContent
));
3659 NS_ASSERTION(objContent
,
3660 "applet, embed and object must implement "
3661 "nsIObjectLoadingContent!");
3663 objContent
->GetDisplayedType(&type
);
3666 static const FrameConstructionDataByInt sObjectData
[] = {
3667 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING
,
3669 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_PLUGIN
,
3671 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE
,
3673 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT
,
3674 NS_NewSubDocumentFrame
)
3675 // Nothing for TYPE_NULL so we'll construct frames by display there
3678 return FindDataByInt((PRInt32
)type
, aContent
, aStyleContext
,
3679 sObjectData
, NS_ARRAY_LENGTH(sObjectData
));
3683 nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem
& aItem
,
3684 nsFrameConstructorState
& aState
,
3685 nsIFrame
* aParentFrame
,
3686 nsFrameItems
& aFrameItems
)
3688 const FrameConstructionData
* data
= aItem
.mFCData
;
3689 NS_ASSERTION(data
, "Must have frame construction data");
3691 PRUint32 bits
= data
->mBits
;
3693 NS_ASSERTION(!(bits
& FCDATA_FUNC_IS_DATA_GETTER
),
3694 "Should have dealt with this inside the data finder");
3696 // Some sets of bits are not compatible with each other
3697 #define CHECK_ONLY_ONE_BIT(_bit1, _bit2) \
3698 NS_ASSERTION(!(bits & _bit1) || !(bits & _bit2), \
3699 "Only one of these bits should be set")
3700 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_FORCE_NULL_ABSPOS_CONTAINER
);
3702 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_WRAP_KIDS_IN_BLOCKS
);
3704 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_MAY_NEED_SCROLLFRAME
);
3705 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_IS_POPUP
);
3706 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_SKIP_ABSPOS_PUSH
);
3707 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_FORCE_VIEW
);
3708 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
,
3709 FCDATA_DISALLOW_GENERATED_CONTENT
);
3710 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR
, FCDATA_ALLOW_BLOCK_STYLES
);
3711 CHECK_ONLY_ONE_BIT(FCDATA_MAY_NEED_SCROLLFRAME
, FCDATA_FORCE_VIEW
);
3712 #undef CHECK_ONLY_ONE_BIT
3714 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
3715 const nsStyleDisplay
* display
= styleContext
->GetStyleDisplay();
3718 nsIFrame
* primaryFrame
;
3719 if (bits
& FCDATA_FUNC_IS_FULL_CTOR
) {
3721 (this->*(data
->mFullConstructor
))(aState
, aItem
, aParentFrame
,
3722 display
, aFrameItems
, &newFrame
);
3723 if (NS_FAILED(rv
)) {
3727 primaryFrame
= newFrame
;
3729 nsIContent
* const content
= aItem
.mContent
;
3732 (*data
->mFunc
.mCreationFunc
)(mPresShell
, styleContext
);
3734 return NS_ERROR_OUT_OF_MEMORY
;
3737 PRBool allowOutOfFlow
= !(bits
& FCDATA_DISALLOW_OUT_OF_FLOW
);
3738 PRBool isPopup
= aItem
.mIsPopup
;
3739 NS_ASSERTION(!isPopup
||
3740 (aState
.mPopupItems
.containingBlock
&&
3741 aState
.mPopupItems
.containingBlock
->GetType() ==
3742 nsGkAtoms::popupSetFrame
),
3743 "Should have a containing block here!");
3745 nsIFrame
* geometricParent
=
3746 isPopup
? aState
.mPopupItems
.containingBlock
:
3747 (allowOutOfFlow
? aState
.GetGeometricParent(display
, aParentFrame
)
3750 nsresult rv
= NS_OK
;
3752 // Must init frameToAddToList to null, since it's inout
3753 nsIFrame
* frameToAddToList
= nsnull
;
3754 if ((bits
& FCDATA_MAY_NEED_SCROLLFRAME
) &&
3755 display
->IsScrollableOverflow()) {
3756 BuildScrollFrame(aState
, content
, styleContext
, newFrame
,
3757 geometricParent
, frameToAddToList
);
3759 rv
= InitAndRestoreFrame(aState
, content
, geometricParent
, nsnull
,
3761 NS_ASSERTION(NS_SUCCEEDED(rv
), "InitAndRestoreFrame failed");
3762 // See whether we need to create a view
3763 nsHTMLContainerFrame::CreateViewForFrame(newFrame
,
3764 (bits
& FCDATA_FORCE_VIEW
) != 0);
3765 frameToAddToList
= newFrame
;
3768 // Use frameToAddToList as the primary frame. In the non-scrollframe case
3769 // they're equal, but in the scrollframe case newFrame is the scrolled
3770 // frame, while frameToAddToList is the scrollframe (and should be the
3772 primaryFrame
= frameToAddToList
;
3774 rv
= aState
.AddChild(frameToAddToList
, aFrameItems
, content
, styleContext
,
3775 aParentFrame
, allowOutOfFlow
, allowOutOfFlow
, isPopup
);
3776 if (NS_FAILED(rv
)) {
3781 // Icky XUL stuff, sadly
3783 if (aItem
.mIsRootPopupgroup
) {
3784 NS_ASSERTION(nsIRootBox::GetRootBox(mPresShell
) &&
3785 nsIRootBox::GetRootBox(mPresShell
)->GetPopupSetFrame() ==
3787 "Unexpected PopupSetFrame");
3788 aState
.mPopupItems
.containingBlock
= newFrame
;
3789 aState
.mHavePendingPopupgroup
= PR_FALSE
;
3791 #endif /* MOZ_XUL */
3793 // Process the child content if requested
3794 nsFrameItems childItems
;
3795 nsFrameConstructorSaveState absoluteSaveState
;
3797 if (bits
& FCDATA_FORCE_NULL_ABSPOS_CONTAINER
) {
3798 aState
.PushAbsoluteContainingBlock(nsnull
, absoluteSaveState
);
3799 } else if (!(bits
& FCDATA_SKIP_ABSPOS_PUSH
) && display
->IsPositioned()) {
3800 aState
.PushAbsoluteContainingBlock(newFrame
, absoluteSaveState
);
3803 if (bits
& FCDATA_USE_CHILD_ITEMS
) {
3804 rv
= ConstructFramesFromItemList(aState
, aItem
.mChildItems
, newFrame
,
3807 // Process the child frames.
3808 rv
= ProcessChildren(aState
, content
, styleContext
, newFrame
,
3809 !(bits
& FCDATA_DISALLOW_GENERATED_CONTENT
),
3811 (bits
& FCDATA_ALLOW_BLOCK_STYLES
) != 0,
3812 aItem
.mPendingBinding
);
3816 // More icky XUL stuff
3817 if (aItem
.mNameSpaceID
== kNameSpaceID_XUL
&&
3818 (aItem
.mTag
== nsGkAtoms::treechildren
|| // trees always need titletips
3819 content
->HasAttr(kNameSpaceID_None
, nsGkAtoms::tooltiptext
) ||
3820 content
->HasAttr(kNameSpaceID_None
, nsGkAtoms::tooltip
))) {
3821 nsIRootBox
* rootBox
= nsIRootBox::GetRootBox(mPresShell
);
3823 rootBox
->AddTooltipSupport(content
);
3829 if (NS_SUCCEEDED(rv
) && (bits
& FCDATA_WRAP_KIDS_IN_BLOCKS
)) {
3830 nsFrameItems newItems
;
3831 nsFrameItems currentBlock
;
3833 while ((f
= childItems
.FirstChild()) != nsnull
) {
3834 PRBool wrapFrame
= IsInlineFrame(f
) || IsFrameSpecial(f
);
3836 rv
= FlushAccumulatedBlock(aState
, content
, newFrame
, ¤tBlock
, &newItems
);
3841 childItems
.RemoveFrame(f
);
3843 currentBlock
.AddChild(f
);
3845 newItems
.AddChild(f
);
3848 rv
= FlushAccumulatedBlock(aState
, content
, newFrame
, ¤tBlock
, &newItems
);
3850 if (childItems
.NotEmpty()) {
3851 // an error must have occurred, delete unprocessed frames
3852 childItems
.DestroyFrames();
3855 childItems
= newItems
;
3859 // Set the frame's initial child list
3860 // Note that MathML depends on this being called even if
3861 // childItems is empty!
3862 newFrame
->SetInitialChildList(nsnull
, childItems
);
3865 NS_ASSERTION(newFrame
->IsFrameOfType(nsIFrame::eLineParticipant
) ==
3866 ((bits
& FCDATA_IS_LINE_PARTICIPANT
) != 0),
3867 "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits");
3869 if (aState
.mSetPrimaryFrames
&& !(bits
& FCDATA_SKIP_FRAMESET
)) {
3870 aItem
.mContent
->SetPrimaryFrame(primaryFrame
);
3876 // after the node has been constructed and initialized create any
3877 // anonymous content a node needs.
3879 nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState
& aState
,
3880 nsIContent
* aParent
,
3881 nsIFrame
* aParentFrame
,
3882 PendingBinding
* aPendingBinding
,
3883 nsFrameItems
& aChildItems
)
3885 nsAutoTArray
<nsIContent
*, 4> newAnonymousItems
;
3886 nsresult rv
= GetAnonymousContent(aParent
, aParentFrame
, newAnonymousItems
);
3887 NS_ENSURE_SUCCESS(rv
, rv
);
3889 PRUint32 count
= newAnonymousItems
.Length();
3894 nsFrameConstructorState::PendingBindingAutoPusher
pusher(aState
,
3897 nsIAnonymousContentCreator
* creator
= do_QueryFrame(aParentFrame
);
3898 NS_ASSERTION(creator
,
3899 "How can that happen if we have nodes to construct frames for?");
3901 for (PRUint32 i
=0; i
< count
; i
++) {
3902 nsIContent
* content
= newAnonymousItems
[i
];
3903 NS_ASSERTION(content
, "null anonymous content?");
3905 nsIFrame
* newFrame
= creator
->CreateFrameFor(content
);
3907 NS_ASSERTION(content
->GetPrimaryFrame(),
3908 "Content must have a primary frame now");
3909 aChildItems
.AddChild(newFrame
);
3912 // create the frame and attach it to our frame
3913 ConstructFrame(aState
, content
, aParentFrame
, aChildItems
);
3921 nsCSSFrameConstructor::GetAnonymousContent(nsIContent
* aParent
,
3922 nsIFrame
* aParentFrame
,
3923 nsTArray
<nsIContent
*>& aContent
)
3925 nsIAnonymousContentCreator
* creator
= do_QueryFrame(aParentFrame
);
3929 nsresult rv
= creator
->CreateAnonymousContent(aContent
);
3930 NS_ENSURE_SUCCESS(rv
, rv
);
3932 PRUint32 count
= aContent
.Length();
3933 for (PRUint32 i
=0; i
< count
; i
++) {
3934 // get our child's content and set its parent to our content
3935 nsIContent
* content
= aContent
[i
];
3936 NS_ASSERTION(content
, "null anonymous content?");
3939 // least-surprise CSS binding until we do the SVG specified
3940 // cascading rules for <svg:use> - bug 265894
3942 aParent
->NodeInfo()->Equals(nsGkAtoms::use
, kNameSpaceID_SVG
)) {
3943 content
->SetFlags(NODE_IS_ANONYMOUS
);
3947 content
->SetNativeAnonymous();
3950 rv
= content
->BindToTree(mDocument
, aParent
, aParent
, PR_TRUE
);
3951 if (NS_FAILED(rv
)) {
3952 content
->UnbindFromTree();
3961 PRBool
IsXULDisplayType(const nsStyleDisplay
* aDisplay
)
3963 return (aDisplay
->mDisplay
== NS_STYLE_DISPLAY_INLINE_BOX
||
3965 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_INLINE_GRID
||
3966 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_INLINE_STACK
||
3968 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_BOX
3970 || aDisplay
->mDisplay
== NS_STYLE_DISPLAY_GRID
||
3971 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_STACK
||
3972 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_GRID_GROUP
||
3973 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_GRID_LINE
||
3974 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_DECK
||
3975 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_POPUP
||
3976 aDisplay
->mDisplay
== NS_STYLE_DISPLAY_GROUPBOX
3982 // XUL frames are not allowed to be out of flow.
3983 #define SIMPLE_XUL_FCDATA(_func) \
3984 FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH, \
3986 #define SCROLLABLE_XUL_FCDATA(_func) \
3987 FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH | \
3988 FCDATA_MAY_NEED_SCROLLFRAME, _func)
3989 #define SIMPLE_XUL_CREATE(_tag, _func) \
3990 { &nsGkAtoms::_tag, SIMPLE_XUL_FCDATA(_func) }
3991 #define SCROLLABLE_XUL_CREATE(_tag, _func) \
3992 { &nsGkAtoms::_tag, SCROLLABLE_XUL_FCDATA(_func) }
3993 #define SIMPLE_XUL_INT_CREATE(_int, _func) \
3994 { _int, SIMPLE_XUL_FCDATA(_func) }
3995 #define SCROLLABLE_XUL_INT_CREATE(_int, _func) \
3996 { _int, SCROLLABLE_XUL_FCDATA(_func) }
3999 nsIFrame
* NS_NewGridBoxFrame(nsIPresShell
* aPresShell
,
4000 nsStyleContext
* aStyleContext
)
4002 nsCOMPtr
<nsIBoxLayout
> layout
;
4003 NS_NewGridLayout2(aPresShell
, getter_AddRefs(layout
));
4008 return NS_NewBoxFrame(aPresShell
, aStyleContext
, PR_FALSE
, layout
);
4012 const nsCSSFrameConstructor::FrameConstructionData
*
4013 nsCSSFrameConstructor::FindXULTagData(nsIContent
* aContent
,
4015 PRInt32 aNameSpaceID
,
4016 nsStyleContext
* aStyleContext
)
4018 if (aNameSpaceID
!= kNameSpaceID_XUL
) {
4022 static const FrameConstructionDataByTag sXULTagData
[] = {
4024 SCROLLABLE_XUL_CREATE(button
, NS_NewButtonBoxFrame
),
4025 SCROLLABLE_XUL_CREATE(checkbox
, NS_NewButtonBoxFrame
),
4026 SCROLLABLE_XUL_CREATE(radio
, NS_NewButtonBoxFrame
),
4027 SCROLLABLE_XUL_CREATE(autorepeatbutton
, NS_NewAutoRepeatBoxFrame
),
4028 SCROLLABLE_XUL_CREATE(titlebar
, NS_NewTitleBarFrame
),
4029 SCROLLABLE_XUL_CREATE(resizer
, NS_NewResizerFrame
),
4030 SIMPLE_XUL_CREATE(image
, NS_NewImageBoxFrame
),
4031 SIMPLE_XUL_CREATE(spring
, NS_NewLeafBoxFrame
),
4032 SIMPLE_XUL_CREATE(spacer
, NS_NewLeafBoxFrame
),
4033 SIMPLE_XUL_CREATE(treechildren
, NS_NewTreeBodyFrame
),
4034 SIMPLE_XUL_CREATE(treecol
, NS_NewTreeColFrame
),
4035 SIMPLE_XUL_CREATE(text
, NS_NewTextBoxFrame
),
4036 SIMPLE_TAG_CHAIN(label
, nsCSSFrameConstructor::FindXULLabelData
),
4037 SIMPLE_TAG_CHAIN(description
, nsCSSFrameConstructor::FindXULDescriptionData
),
4038 SIMPLE_XUL_CREATE(menu
, NS_NewMenuFrame
),
4039 SIMPLE_XUL_CREATE(menubutton
, NS_NewMenuFrame
),
4040 SIMPLE_XUL_CREATE(menuitem
, NS_NewMenuItemFrame
),
4042 SIMPLE_TAG_CHAIN(menubar
, nsCSSFrameConstructor::FindXULMenubarData
),
4044 SIMPLE_XUL_CREATE(menubar
, NS_NewMenuBarFrame
),
4045 #endif /* XP_MACOSX */
4046 SIMPLE_TAG_CHAIN(popupgroup
, nsCSSFrameConstructor::FindPopupGroupData
),
4047 SIMPLE_XUL_CREATE(iframe
, NS_NewSubDocumentFrame
),
4048 SIMPLE_XUL_CREATE(editor
, NS_NewSubDocumentFrame
),
4049 SIMPLE_XUL_CREATE(browser
, NS_NewSubDocumentFrame
),
4050 SIMPLE_XUL_CREATE(progressmeter
, NS_NewProgressMeterFrame
),
4051 SIMPLE_XUL_CREATE(splitter
, NS_NewSplitterFrame
),
4052 SIMPLE_TAG_CHAIN(listboxbody
,
4053 nsCSSFrameConstructor::FindXULListBoxBodyData
),
4054 SIMPLE_TAG_CHAIN(listitem
, nsCSSFrameConstructor::FindXULListItemData
),
4055 #endif /* MOZ_XUL */
4056 SIMPLE_XUL_CREATE(slider
, NS_NewSliderFrame
),
4057 SIMPLE_XUL_CREATE(scrollbar
, NS_NewScrollbarFrame
),
4058 SIMPLE_XUL_CREATE(scrollbarbutton
, NS_NewScrollbarButtonFrame
)
4061 return FindDataByTag(aTag
, aContent
, aStyleContext
, sXULTagData
,
4062 NS_ARRAY_LENGTH(sXULTagData
));
4067 const nsCSSFrameConstructor::FrameConstructionData
*
4068 nsCSSFrameConstructor::FindPopupGroupData(nsIContent
* aContent
,
4069 nsStyleContext
* /* unused */)
4071 if (!aContent
->IsRootOfNativeAnonymousSubtree()) {
4075 static const FrameConstructionData sPopupSetData
=
4076 SIMPLE_XUL_FCDATA(NS_NewPopupSetFrame
);
4077 return &sPopupSetData
;
4081 const nsCSSFrameConstructor::FrameConstructionData
4082 nsCSSFrameConstructor::sXULTextBoxData
= SIMPLE_XUL_FCDATA(NS_NewTextBoxFrame
);
4085 const nsCSSFrameConstructor::FrameConstructionData
*
4086 nsCSSFrameConstructor::FindXULLabelData(nsIContent
* aContent
,
4087 nsStyleContext
* /* unused */)
4089 if (aContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::value
)) {
4090 return &sXULTextBoxData
;
4093 static const FrameConstructionData sLabelData
=
4094 SIMPLE_XUL_FCDATA(NS_NewXULLabelFrame
);
4099 NS_NewXULDescriptionFrame(nsIPresShell
* aPresShell
, nsStyleContext
*aContext
)
4101 // XXXbz do we really need to set those flags? If the parent is not
4102 // a block we'll get them anyway, and if it is, do we want them?
4103 return NS_NewBlockFrame(aPresShell
, aContext
,
4104 NS_BLOCK_FLOAT_MGR
| NS_BLOCK_MARGIN_ROOT
);
4108 const nsCSSFrameConstructor::FrameConstructionData
*
4109 nsCSSFrameConstructor::FindXULDescriptionData(nsIContent
* aContent
,
4110 nsStyleContext
* /* unused */)
4112 if (aContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::value
)) {
4113 return &sXULTextBoxData
;
4116 static const FrameConstructionData sDescriptionData
=
4117 SIMPLE_XUL_FCDATA(NS_NewXULDescriptionFrame
);
4118 return &sDescriptionData
;
4123 const nsCSSFrameConstructor::FrameConstructionData
*
4124 nsCSSFrameConstructor::FindXULMenubarData(nsIContent
* aContent
,
4125 nsStyleContext
* aStyleContext
)
4127 nsCOMPtr
<nsISupports
> container
=
4128 aStyleContext
->PresContext()->GetContainer();
4130 nsCOMPtr
<nsIDocShellTreeItem
> treeItem(do_QueryInterface(container
));
4133 treeItem
->GetItemType(&type
);
4134 if (nsIDocShellTreeItem::typeChrome
== type
) {
4135 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
4136 treeItem
->GetParent(getter_AddRefs(parent
));
4138 // This is the root. Suppress the menubar, since on Mac
4139 // window menus are not attached to the window.
4140 static const FrameConstructionData sSuppressData
= SUPPRESS_FCDATA();
4141 return &sSuppressData
;
4147 static const FrameConstructionData sMenubarData
=
4148 SIMPLE_XUL_FCDATA(NS_NewMenuBarFrame
);
4149 return &sMenubarData
;
4151 #endif /* XP_MACOSX */
4154 const nsCSSFrameConstructor::FrameConstructionData
*
4155 nsCSSFrameConstructor::FindXULListBoxBodyData(nsIContent
* aContent
,
4156 nsStyleContext
* aStyleContext
)
4158 if (aStyleContext
->GetStyleDisplay()->mDisplay
!=
4159 NS_STYLE_DISPLAY_GRID_GROUP
) {
4163 static const FrameConstructionData sListBoxBodyData
=
4164 SCROLLABLE_XUL_FCDATA(NS_NewListBoxBodyFrame
);
4165 return &sListBoxBodyData
;
4169 const nsCSSFrameConstructor::FrameConstructionData
*
4170 nsCSSFrameConstructor::FindXULListItemData(nsIContent
* aContent
,
4171 nsStyleContext
* aStyleContext
)
4173 if (aStyleContext
->GetStyleDisplay()->mDisplay
!=
4174 NS_STYLE_DISPLAY_GRID_LINE
) {
4178 static const FrameConstructionData sListItemData
=
4179 SCROLLABLE_XUL_FCDATA(NS_NewListItemFrame
);
4180 return &sListItemData
;
4183 #endif /* MOZ_XUL */
4186 const nsCSSFrameConstructor::FrameConstructionData
*
4187 nsCSSFrameConstructor::FindXULDisplayData(const nsStyleDisplay
* aDisplay
,
4188 nsIContent
* aContent
,
4189 nsStyleContext
* aStyleContext
)
4191 static const FrameConstructionDataByInt sXULDisplayData
[] = {
4192 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_BOX
, NS_NewBoxFrame
),
4193 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_BOX
, NS_NewBoxFrame
),
4195 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_GRID
, NS_NewGridBoxFrame
),
4196 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GRID
, NS_NewGridBoxFrame
),
4197 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GRID_GROUP
,
4198 NS_NewGridRowGroupFrame
),
4199 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GRID_LINE
,
4200 NS_NewGridRowLeafFrame
),
4201 SIMPLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_DECK
, NS_NewDeckFrame
),
4202 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GROUPBOX
, NS_NewGroupBoxFrame
),
4203 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_STACK
, NS_NewStackFrame
),
4204 SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_STACK
, NS_NewStackFrame
),
4205 { NS_STYLE_DISPLAY_POPUP
,
4206 FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW
| FCDATA_IS_POPUP
|
4207 FCDATA_SKIP_ABSPOS_PUSH
, NS_NewMenuPopupFrame
) }
4208 #endif /* MOZ_XUL */
4211 // Processing by display here:
4212 return FindDataByInt(aDisplay
->mDisplay
, aContent
, aStyleContext
,
4213 sXULDisplayData
, NS_ARRAY_LENGTH(sXULDisplayData
));
4216 already_AddRefed
<nsStyleContext
>
4217 nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState
& aState
,
4218 nsIContent
* aContent
,
4219 nsStyleContext
* aContentStyle
,
4220 nsIFrame
* aParentFrame
,
4221 nsIAtom
* aScrolledPseudo
,
4223 nsIFrame
*& aNewFrame
)
4225 nsIFrame
* gfxScrollFrame
= aNewFrame
;
4227 nsFrameItems anonymousItems
;
4229 nsRefPtr
<nsStyleContext
> contentStyle
= aContentStyle
;
4231 if (!gfxScrollFrame
) {
4232 // Build a XULScrollFrame when the child is a box, otherwise an
4234 // XXXbz this is the lone remaining consumer of IsXULDisplayType.
4235 // I wonder whether we can eliminate that somehow.
4236 if (IsXULDisplayType(aContentStyle
->GetStyleDisplay())) {
4237 gfxScrollFrame
= NS_NewXULScrollFrame(mPresShell
, contentStyle
, aIsRoot
);
4239 gfxScrollFrame
= NS_NewHTMLScrollFrame(mPresShell
, contentStyle
, aIsRoot
);
4242 InitAndRestoreFrame(aState
, aContent
, aParentFrame
, nsnull
, gfxScrollFrame
);
4245 nsHTMLContainerFrame::CreateViewForFrame(gfxScrollFrame
, PR_FALSE
);
4248 // if there are any anonymous children for the scroll frame, create
4250 // Pass a null pending binding: we don't care how constructors for any of
4251 // this anonymous content order with anything else. It's never been
4252 // consistent anyway.
4253 CreateAnonymousFrames(aState
, aContent
, gfxScrollFrame
, nsnull
,
4256 aNewFrame
= gfxScrollFrame
;
4258 // we used the style that was passed in. So resolve another one.
4259 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
4260 nsStyleContext
* aScrolledChildStyle
=
4261 styleSet
->ResolveAnonymousBoxStyle(aScrolledPseudo
, contentStyle
).get();
4263 if (gfxScrollFrame
) {
4264 gfxScrollFrame
->SetInitialChildList(nsnull
, anonymousItems
);
4267 return aScrolledChildStyle
;
4271 nsCSSFrameConstructor::FinishBuildingScrollFrame(nsIFrame
* aScrollFrame
,
4272 nsIFrame
* aScrolledFrame
)
4274 nsFrameList
scrolled(aScrolledFrame
, aScrolledFrame
);
4275 aScrollFrame
->AppendFrames(nsnull
, scrolled
);
4280 * Called to wrap a gfx scrollframe around a frame. The hierarchy will look like this
4282 * ------- for gfx scrollbars ------
4288 * Frame (scrolled frame you passed in)
4291 *-----------------------------------
4294 * ScrollFrame: This is a frame that manages gfx cross platform frame based scrollbars.
4296 * @param aContent the content node of the child to wrap.
4297 * @param aScrolledFrame The frame of the content to wrap. This should not be
4298 * Initialized. This method will initialize it with a scrolled pseudo
4299 * and no nsIContent. The content will be attached to the scrollframe
4301 * @param aContentStyle the style context that has already been resolved for the content being passed in.
4303 * @param aParentFrame The parent to attach the scroll frame to
4305 * @param aNewFrame The new scrollframe or gfx scrollframe that we create. It will contain the
4306 * scrolled frame you passed in. (returned)
4307 * If this is not null, we'll just use it
4308 * @param aScrolledContentStyle the style that was resolved for the scrolled frame. (returned)
4311 nsCSSFrameConstructor::BuildScrollFrame(nsFrameConstructorState
& aState
,
4312 nsIContent
* aContent
,
4313 nsStyleContext
* aContentStyle
,
4314 nsIFrame
* aScrolledFrame
,
4315 nsIFrame
* aParentFrame
,
4316 nsIFrame
*& aNewFrame
)
4318 nsRefPtr
<nsStyleContext
> scrolledContentStyle
=
4319 BeginBuildingScrollFrame(aState
, aContent
, aContentStyle
, aParentFrame
,
4320 nsCSSAnonBoxes::scrolledContent
,
4321 PR_FALSE
, aNewFrame
);
4323 aScrolledFrame
->SetStyleContextWithoutNotification(scrolledContentStyle
);
4324 InitAndRestoreFrame(aState
, aContent
, aNewFrame
, nsnull
, aScrolledFrame
);
4326 FinishBuildingScrollFrame(aNewFrame
, aScrolledFrame
);
4330 const nsCSSFrameConstructor::FrameConstructionData
*
4331 nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay
* aDisplay
,
4332 nsIContent
* aContent
,
4333 nsStyleContext
* aStyleContext
)
4335 PR_STATIC_ASSERT(eParentTypeCount
< (1 << (32 - FCDATA_PARENT_TYPE_OFFSET
)));
4337 // The style system ensures that floated and positioned frames are
4339 NS_ASSERTION(!(aDisplay
->IsFloating() ||
4340 aDisplay
->IsAbsolutelyPositioned()) ||
4341 aDisplay
->IsBlockOutside(),
4342 "Style system did not apply CSS2.1 section 9.7 fixups");
4344 // If this is "body", try propagating its scroll style to the viewport
4345 // Note that we need to do this even if the body is NOT scrollable;
4346 // it might have dynamically changed from scrollable to not scrollable,
4347 // and that might need to be propagated.
4348 // XXXbz is this the right place to do this? If this code moves,
4349 // make this function static.
4350 PRBool propagatedScrollToViewport
= PR_FALSE
;
4351 if (aContent
->NodeInfo()->Equals(nsGkAtoms::body
) &&
4352 aContent
->IsHTML()) {
4353 propagatedScrollToViewport
=
4354 PropagateScrollToViewport() == aContent
;
4357 // If the frame is a block-level frame and is scrollable, then wrap it
4358 // in a scroll frame.
4359 // XXX Ignore tables for the time being
4360 // XXXbz it would be nice to combine this with the other block
4361 // case... Think about how do do this?
4362 if (aDisplay
->IsBlockInside() &&
4363 aDisplay
->IsScrollableOverflow() &&
4364 !propagatedScrollToViewport
) {
4365 static const FrameConstructionData sScrollableBlockData
=
4366 FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructScrollableBlock
);
4367 return &sScrollableBlockData
;
4370 // Handle various non-scrollable blocks
4371 if (aDisplay
->IsBlockInside() ||
4372 NS_STYLE_DISPLAY_RUN_IN
== aDisplay
->mDisplay
||
4373 NS_STYLE_DISPLAY_COMPACT
== aDisplay
->mDisplay
) {
4374 static const FrameConstructionData sNonScrollableBlockData
=
4375 FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructNonScrollableBlock
);
4376 return &sNonScrollableBlockData
;
4379 static const FrameConstructionDataByInt sDisplayData
[] = {
4380 // To keep the hash table small don't add inline frames (they're
4381 // typically things like FONT and B), because we can quickly
4382 // find them if we need to.
4383 // XXXbz the "quickly" part is a bald-faced lie!
4384 { NS_STYLE_DISPLAY_INLINE
,
4385 FULL_CTOR_FCDATA(FCDATA_IS_INLINE
| FCDATA_IS_LINE_PARTICIPANT
,
4386 &nsCSSFrameConstructor::ConstructInline
) },
4387 { NS_STYLE_DISPLAY_MARKER
,
4388 FULL_CTOR_FCDATA(FCDATA_IS_INLINE
| FCDATA_IS_LINE_PARTICIPANT
,
4389 &nsCSSFrameConstructor::ConstructInline
) },
4390 { NS_STYLE_DISPLAY_TABLE
,
4391 FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable
) },
4392 { NS_STYLE_DISPLAY_INLINE_TABLE
,
4393 FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable
) },
4394 { NS_STYLE_DISPLAY_TABLE_CAPTION
,
4395 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_ALLOW_BLOCK_STYLES
|
4396 FCDATA_DISALLOW_OUT_OF_FLOW
| FCDATA_SKIP_ABSPOS_PUSH
|
4397 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
4398 NS_NewTableCaptionFrame
) },
4399 { NS_STYLE_DISPLAY_TABLE_ROW_GROUP
,
4400 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_DISALLOW_OUT_OF_FLOW
|
4401 FCDATA_SKIP_ABSPOS_PUSH
|
4402 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
4403 NS_NewTableRowGroupFrame
) },
4404 { NS_STYLE_DISPLAY_TABLE_HEADER_GROUP
,
4405 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_DISALLOW_OUT_OF_FLOW
|
4406 FCDATA_SKIP_ABSPOS_PUSH
|
4407 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
4408 NS_NewTableRowGroupFrame
) },
4409 { NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP
,
4410 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_DISALLOW_OUT_OF_FLOW
|
4411 FCDATA_SKIP_ABSPOS_PUSH
|
4412 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
4413 NS_NewTableRowGroupFrame
) },
4414 { NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
,
4415 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_DISALLOW_OUT_OF_FLOW
|
4416 FCDATA_SKIP_ABSPOS_PUSH
|
4417 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
4418 NS_NewTableColGroupFrame
) },
4419 { NS_STYLE_DISPLAY_TABLE_COLUMN
,
4420 FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART
|
4421 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeColGroup
),
4422 &nsCSSFrameConstructor::ConstructTableCol
) },
4423 { NS_STYLE_DISPLAY_TABLE_ROW
,
4424 FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART
|
4425 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup
),
4426 &nsCSSFrameConstructor::ConstructTableRow
) },
4427 { NS_STYLE_DISPLAY_TABLE_CELL
,
4428 FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART
|
4429 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow
),
4430 &nsCSSFrameConstructor::ConstructTableCell
) }
4433 return FindDataByInt(aDisplay
->mDisplay
, aContent
, aStyleContext
,
4434 sDisplayData
, NS_ARRAY_LENGTH(sDisplayData
));
4438 nsCSSFrameConstructor::ConstructScrollableBlock(nsFrameConstructorState
& aState
,
4439 FrameConstructionItem
& aItem
,
4440 nsIFrame
* aParentFrame
,
4441 const nsStyleDisplay
* aDisplay
,
4442 nsFrameItems
& aFrameItems
,
4443 nsIFrame
** aNewFrame
)
4445 nsIContent
* const content
= aItem
.mContent
;
4446 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
4448 *aNewFrame
= nsnull
;
4449 nsRefPtr
<nsStyleContext
> scrolledContentStyle
4450 = BeginBuildingScrollFrame(aState
, content
, styleContext
,
4451 aState
.GetGeometricParent(aDisplay
, aParentFrame
),
4452 nsCSSAnonBoxes::scrolledContent
,
4453 PR_FALSE
, *aNewFrame
);
4455 // Create our block frame
4456 // pass a temporary stylecontext, the correct one will be set later
4457 nsIFrame
* scrolledFrame
=
4458 NS_NewBlockFormattingContext(mPresShell
, styleContext
);
4460 nsFrameItems blockItem
;
4461 nsresult rv
= ConstructBlock(aState
,
4462 scrolledContentStyle
->GetStyleDisplay(), content
,
4463 *aNewFrame
, *aNewFrame
, scrolledContentStyle
,
4464 &scrolledFrame
, blockItem
, aDisplay
->IsPositioned(),
4465 aItem
.mPendingBinding
);
4466 if (NS_UNLIKELY(NS_FAILED(rv
))) {
4467 // XXXbz any cleanup needed here?
4471 NS_ASSERTION(blockItem
.FirstChild() == scrolledFrame
,
4472 "Scrollframe's frameItems should be exactly the scrolled frame");
4473 FinishBuildingScrollFrame(*aNewFrame
, scrolledFrame
);
4475 rv
= aState
.AddChild(*aNewFrame
, aFrameItems
, content
, styleContext
,
4481 nsCSSFrameConstructor::ConstructNonScrollableBlock(nsFrameConstructorState
& aState
,
4482 FrameConstructionItem
& aItem
,
4483 nsIFrame
* aParentFrame
,
4484 const nsStyleDisplay
* aDisplay
,
4485 nsFrameItems
& aFrameItems
,
4486 nsIFrame
** aNewFrame
)
4488 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
4490 if (aDisplay
->IsAbsolutelyPositioned() ||
4491 aDisplay
->IsFloating() ||
4492 NS_STYLE_DISPLAY_INLINE_BLOCK
== aDisplay
->mDisplay
) {
4493 *aNewFrame
= NS_NewBlockFormattingContext(mPresShell
, styleContext
);
4495 *aNewFrame
= NS_NewBlockFrame(mPresShell
, styleContext
);
4498 return ConstructBlock(aState
, aDisplay
, aItem
.mContent
,
4499 aState
.GetGeometricParent(aDisplay
, aParentFrame
),
4500 aParentFrame
, styleContext
, aNewFrame
,
4501 aFrameItems
, aDisplay
->IsPositioned(),
4502 aItem
.mPendingBinding
);
4507 nsCSSFrameConstructor::InitAndRestoreFrame(const nsFrameConstructorState
& aState
,
4508 nsIContent
* aContent
,
4509 nsIFrame
* aParentFrame
,
4510 nsIFrame
* aPrevInFlow
,
4511 nsIFrame
* aNewFrame
,
4512 PRBool aAllowCounters
)
4514 NS_PRECONDITION(mUpdateCount
!= 0,
4515 "Should be in an update while creating frames");
4517 nsresult rv
= NS_OK
;
4519 NS_ASSERTION(aNewFrame
, "Null frame cannot be initialized");
4521 return NS_ERROR_NULL_POINTER
;
4523 // Initialize the frame
4524 rv
= aNewFrame
->Init(aContent
, aParentFrame
, aPrevInFlow
);
4525 aNewFrame
->AddStateBits(aState
.mAdditionalStateBits
);
4527 if (aState
.mFrameState
&& aState
.mFrameManager
) {
4528 // Restore frame state for just the newly created frame.
4529 aState
.mFrameManager
->RestoreFrameStateFor(aNewFrame
, aState
.mFrameState
);
4532 if (aAllowCounters
&& !aPrevInFlow
&&
4533 mCounterManager
.AddCounterResetsAndIncrements(aNewFrame
)) {
4540 already_AddRefed
<nsStyleContext
>
4541 nsCSSFrameConstructor::ResolveStyleContext(nsIFrame
* aParentFrame
,
4542 nsIContent
* aContent
)
4544 nsStyleContext
* parentStyleContext
= nsnull
;
4545 NS_ASSERTION(aContent
->GetParent(), "Must have parent here");
4547 aParentFrame
= nsFrame::CorrectStyleParentFrame(aParentFrame
, nsnull
);
4550 // Resolve the style context based on the content object and the parent
4552 parentStyleContext
= aParentFrame
->GetStyleContext();
4554 // Perhaps aParentFrame is a canvasFrame and we're replicating
4555 // fixed-pos frames.
4556 // XXX should we create a way to tell ConstructFrame which style
4557 // context to use, and pass it the style context for the
4558 // previous page's fixed-pos frame?
4561 return ResolveStyleContext(parentStyleContext
, aContent
);
4564 already_AddRefed
<nsStyleContext
>
4565 nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext
* aParentStyleContext
,
4566 nsIContent
* aContent
)
4568 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
4570 if (aContent
->IsElement()) {
4571 return styleSet
->ResolveStyleFor(aContent
->AsElement(), aParentStyleContext
);
4574 NS_ASSERTION(aContent
->IsNodeOfType(nsINode::eTEXT
),
4575 "shouldn't waste time creating style contexts for "
4576 "comments and processing instructions");
4578 return styleSet
->ResolveStyleForNonElement(aParentStyleContext
);
4584 nsCSSFrameConstructor::FlushAccumulatedBlock(nsFrameConstructorState
& aState
,
4585 nsIContent
* aContent
,
4586 nsIFrame
* aParentFrame
,
4587 nsFrameItems
* aBlockItems
,
4588 nsFrameItems
* aNewItems
)
4590 if (aBlockItems
->IsEmpty()) {
4595 nsStyleContext
* parentContext
=
4596 nsFrame::CorrectStyleParentFrame(aParentFrame
,
4597 nsCSSAnonBoxes::mozMathMLAnonymousBlock
)->GetStyleContext();
4598 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
4599 nsRefPtr
<nsStyleContext
> blockContext
;
4600 blockContext
= styleSet
->
4601 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozMathMLAnonymousBlock
,
4604 // then, create a block frame that will wrap the child frames. Make it a
4605 // MathML frame so that Get(Absolute/Float)ContainingBlockFor know that this
4606 // is not a suitable block.
4607 nsIFrame
* blockFrame
= NS_NewMathMLmathBlockFrame(mPresShell
, blockContext
,
4608 NS_BLOCK_FLOAT_MGR
| NS_BLOCK_MARGIN_ROOT
);
4609 if (NS_UNLIKELY(!blockFrame
))
4610 return NS_ERROR_OUT_OF_MEMORY
;
4612 InitAndRestoreFrame(aState
, aContent
, aParentFrame
, nsnull
, blockFrame
);
4613 ReparentFrames(aState
.mFrameManager
, blockFrame
, *aBlockItems
);
4614 // abs-pos and floats are disabled in MathML children so we don't have to
4615 // worry about messing up those.
4616 blockFrame
->SetInitialChildList(nsnull
, *aBlockItems
);
4617 NS_ASSERTION(aBlockItems
->IsEmpty(), "What happened?");
4618 aBlockItems
->Clear();
4619 aNewItems
->AddChild(blockFrame
);
4623 // Only <math> elements can be floated or positioned. All other MathML
4624 // should be in-flow.
4625 #define SIMPLE_MATHML_CREATE(_tag, _func) \
4626 { &nsGkAtoms::_tag, \
4627 FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \
4628 FCDATA_FORCE_NULL_ABSPOS_CONTAINER | \
4629 FCDATA_WRAP_KIDS_IN_BLOCKS, _func) }
4632 const nsCSSFrameConstructor::FrameConstructionData
*
4633 nsCSSFrameConstructor::FindMathMLData(nsIContent
* aContent
,
4635 PRInt32 aNameSpaceID
,
4636 nsStyleContext
* aStyleContext
)
4638 // Make sure that we remain confined in the MathML world
4639 if (aNameSpaceID
!= kNameSpaceID_MathML
)
4642 // Handle <math> specially, because it sometimes produces inlines
4643 if (aTag
== nsGkAtoms::math
) {
4644 // This needs to match the test in EnsureBlockDisplay in
4645 // nsRuleNode.cpp. Though the behavior here for the display:table
4646 // case is pretty weird...
4647 if (aStyleContext
->GetStyleDisplay()->IsBlockOutside()) {
4648 static const FrameConstructionData sBlockMathData
=
4649 FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER
|
4650 FCDATA_WRAP_KIDS_IN_BLOCKS
,
4651 NS_CreateNewMathMLmathBlockFrame
);
4652 return &sBlockMathData
;
4655 static const FrameConstructionData sInlineMathData
=
4656 FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER
|
4657 FCDATA_IS_LINE_PARTICIPANT
|
4658 FCDATA_WRAP_KIDS_IN_BLOCKS
,
4659 NS_NewMathMLmathInlineFrame
);
4660 return &sInlineMathData
;
4664 static const FrameConstructionDataByTag sMathMLData
[] = {
4665 SIMPLE_MATHML_CREATE(mi_
, NS_NewMathMLTokenFrame
),
4666 SIMPLE_MATHML_CREATE(mn_
, NS_NewMathMLTokenFrame
),
4667 SIMPLE_MATHML_CREATE(ms_
, NS_NewMathMLTokenFrame
),
4668 SIMPLE_MATHML_CREATE(mtext_
, NS_NewMathMLTokenFrame
),
4669 SIMPLE_MATHML_CREATE(mo_
, NS_NewMathMLmoFrame
),
4670 SIMPLE_MATHML_CREATE(mfrac_
, NS_NewMathMLmfracFrame
),
4671 SIMPLE_MATHML_CREATE(msup_
, NS_NewMathMLmsupFrame
),
4672 SIMPLE_MATHML_CREATE(msub_
, NS_NewMathMLmsubFrame
),
4673 SIMPLE_MATHML_CREATE(msubsup_
, NS_NewMathMLmsubsupFrame
),
4674 SIMPLE_MATHML_CREATE(munder_
, NS_NewMathMLmunderFrame
),
4675 SIMPLE_MATHML_CREATE(mover_
, NS_NewMathMLmoverFrame
),
4676 SIMPLE_MATHML_CREATE(munderover_
, NS_NewMathMLmunderoverFrame
),
4677 SIMPLE_MATHML_CREATE(mphantom_
, NS_NewMathMLmphantomFrame
),
4678 SIMPLE_MATHML_CREATE(mpadded_
, NS_NewMathMLmpaddedFrame
),
4679 SIMPLE_MATHML_CREATE(mspace_
, NS_NewMathMLmspaceFrame
),
4680 SIMPLE_MATHML_CREATE(none
, NS_NewMathMLmspaceFrame
),
4681 SIMPLE_MATHML_CREATE(mprescripts_
, NS_NewMathMLmspaceFrame
),
4682 SIMPLE_MATHML_CREATE(mfenced_
, NS_NewMathMLmfencedFrame
),
4683 SIMPLE_MATHML_CREATE(mmultiscripts_
, NS_NewMathMLmmultiscriptsFrame
),
4684 SIMPLE_MATHML_CREATE(mstyle_
, NS_NewMathMLmstyleFrame
),
4685 SIMPLE_MATHML_CREATE(msqrt_
, NS_NewMathMLmsqrtFrame
),
4686 SIMPLE_MATHML_CREATE(mroot_
, NS_NewMathMLmrootFrame
),
4687 SIMPLE_MATHML_CREATE(maction_
, NS_NewMathMLmactionFrame
),
4688 SIMPLE_MATHML_CREATE(mrow_
, NS_NewMathMLmrowFrame
),
4689 SIMPLE_MATHML_CREATE(merror_
, NS_NewMathMLmrowFrame
),
4690 SIMPLE_MATHML_CREATE(menclose_
, NS_NewMathMLmencloseFrame
),
4691 SIMPLE_MATHML_CREATE(semantics_
, NS_NewMathMLsemanticsFrame
)
4694 return FindDataByTag(aTag
, aContent
, aStyleContext
, sMathMLData
,
4695 NS_ARRAY_LENGTH(sMathMLData
));
4697 #endif // MOZ_MATHML
4700 // Only outer <svg> elements can be floated or positioned. All other SVG
4701 // should be in-flow.
4702 #define SIMPLE_SVG_FCDATA(_func) \
4703 FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \
4704 FCDATA_SKIP_ABSPOS_PUSH | \
4705 FCDATA_DISALLOW_GENERATED_CONTENT, _func)
4706 #define SIMPLE_SVG_CREATE(_tag, _func) \
4707 { &nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func) }
4710 const nsCSSFrameConstructor::FrameConstructionData
*
4711 nsCSSFrameConstructor::FindSVGData(nsIContent
* aContent
,
4713 PRInt32 aNameSpaceID
,
4714 nsIFrame
* aParentFrame
,
4715 nsStyleContext
* aStyleContext
)
4717 if (aNameSpaceID
!= kNameSpaceID_SVG
|| !NS_SVGEnabled()) {
4721 static const FrameConstructionData sSuppressData
= SUPPRESS_FCDATA();
4722 static const FrameConstructionData sGenericContainerData
=
4723 SIMPLE_SVG_FCDATA(NS_NewSVGGenericContainerFrame
);
4725 PRBool parentIsSVG
= PR_FALSE
;
4726 nsIContent
* parentContent
=
4727 aParentFrame
? aParentFrame
->GetContent() : nsnull
;
4728 // XXXbz should this really be based on the XBL-resolved tag of the parent
4729 // frame's content? Should it not be based on the type of the parent frame
4730 // (e.g. whether it's an SVG frame)?
4731 if (parentContent
) {
4733 nsIAtom
* parentTag
=
4734 parentContent
->GetOwnerDoc()->BindingManager()->
4735 ResolveTag(aParentFrame
->GetContent(), &parentNSID
);
4737 // It's not clear whether the SVG spec intends to allow any SVG
4738 // content within svg:foreignObject at all (SVG 1.1, section
4739 // 23.2), but if it does, it better be svg:svg. So given that
4740 // we're allowing it, treat it as a non-SVG parent.
4741 parentIsSVG
= parentNSID
== kNameSpaceID_SVG
&&
4742 parentTag
!= nsGkAtoms::foreignObject
;
4745 if ((aTag
!= nsGkAtoms::svg
&& !parentIsSVG
) ||
4746 (aTag
== nsGkAtoms::desc
|| aTag
== nsGkAtoms::title
)) {
4747 // Sections 5.1 and G.4 of SVG 1.1 say that SVG elements other than
4748 // svg:svg not contained within svg:svg are incorrect, although they
4749 // don't seem to specify error handling. Ignore them, since many of
4750 // our frame classes can't deal. It *may* be that the document
4751 // should at that point be considered in error according to F.2, but
4752 // it's hard to tell.
4754 // Style mutation can't change this situation, so don't bother
4755 // adding to the undisplayed content map.
4757 // We don't currently handle any UI for desc/title
4758 return &sSuppressData
;
4761 // We don't need frames for animation elements
4762 if (aContent
->IsNodeOfType(nsINode::eANIMATION
)) {
4763 return &sSuppressData
;
4766 // Reduce the number of frames we create unnecessarily. Note that this is not
4767 // where we select which frame in a <switch> to render! That happens in
4768 // nsSVGSwitchFrame::PaintSVG.
4769 if (!nsSVGFeatures::PassesConditionalProcessingTests(aContent
)) {
4770 // Note that just returning is probably not right. According
4771 // to the spec, <use> is allowed to use an element that fails its
4772 // conditional, but because we never actually create the frame when
4773 // a conditional fails and when we use GetReferencedFrame to find the
4774 // references, things don't work right.
4776 return &sSuppressData
;
4779 // Special case for aTag == nsGkAtoms::svg because we don't want to
4780 // have to recompute parentIsSVG for it.
4781 if (aTag
== nsGkAtoms::svg
) {
4783 static const FrameConstructionData sInnerSVGData
=
4784 SIMPLE_SVG_FCDATA(NS_NewSVGInnerSVGFrame
);
4785 return &sInnerSVGData
;
4788 static const FrameConstructionData sOuterSVGData
=
4789 FCDATA_DECL(FCDATA_FORCE_VIEW
| FCDATA_SKIP_ABSPOS_PUSH
|
4790 FCDATA_DISALLOW_GENERATED_CONTENT
,
4791 NS_NewSVGOuterSVGFrame
);
4792 return &sOuterSVGData
;
4795 // Special cases for text/tspan/textpath, because the kind of frame
4796 // they get depends on the parent frame.
4797 if (aTag
== nsGkAtoms::text
) {
4798 NS_ASSERTION(aParentFrame
, "Should have aParentFrame here");
4799 nsIFrame
*ancestorFrame
=
4800 nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame
);
4801 if (ancestorFrame
) {
4802 nsSVGTextContainerFrame
* metrics
= do_QueryFrame(ancestorFrame
);
4803 // Text cannot be nested
4805 return &sGenericContainerData
;
4809 else if (aTag
== nsGkAtoms::tspan
|| aTag
== nsGkAtoms::altGlyph
) {
4810 NS_ASSERTION(aParentFrame
, "Should have aParentFrame here");
4811 nsIFrame
*ancestorFrame
=
4812 nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame
);
4813 if (ancestorFrame
) {
4814 nsSVGTextContainerFrame
* metrics
= do_QueryFrame(ancestorFrame
);
4816 return &sGenericContainerData
;
4820 else if (aTag
== nsGkAtoms::textPath
) {
4821 NS_ASSERTION(aParentFrame
, "Should have aParentFrame here");
4822 nsIFrame
*ancestorFrame
=
4823 nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame
);
4824 if (!ancestorFrame
||
4825 ancestorFrame
->GetType() != nsGkAtoms::svgTextFrame
) {
4826 return &sGenericContainerData
;
4830 static const FrameConstructionDataByTag sSVGData
[] = {
4831 SIMPLE_SVG_CREATE(g
, NS_NewSVGGFrame
),
4832 SIMPLE_SVG_CREATE(svgSwitch
, NS_NewSVGSwitchFrame
),
4833 SIMPLE_SVG_CREATE(polygon
, NS_NewSVGPathGeometryFrame
),
4834 SIMPLE_SVG_CREATE(polyline
, NS_NewSVGPathGeometryFrame
),
4835 SIMPLE_SVG_CREATE(circle
, NS_NewSVGPathGeometryFrame
),
4836 SIMPLE_SVG_CREATE(ellipse
, NS_NewSVGPathGeometryFrame
),
4837 SIMPLE_SVG_CREATE(line
, NS_NewSVGPathGeometryFrame
),
4838 SIMPLE_SVG_CREATE(rect
, NS_NewSVGPathGeometryFrame
),
4839 SIMPLE_SVG_CREATE(path
, NS_NewSVGPathGeometryFrame
),
4840 SIMPLE_SVG_CREATE(defs
, NS_NewSVGContainerFrame
),
4841 { &nsGkAtoms::foreignObject
,
4842 FULL_CTOR_FCDATA(FCDATA_DISALLOW_OUT_OF_FLOW
,
4843 &nsCSSFrameConstructor::ConstructSVGForeignObjectFrame
) },
4844 SIMPLE_SVG_CREATE(a
, NS_NewSVGAFrame
),
4845 SIMPLE_SVG_CREATE(altGlyph
, NS_NewSVGTSpanFrame
),
4846 SIMPLE_SVG_CREATE(text
, NS_NewSVGTextFrame
),
4847 SIMPLE_SVG_CREATE(tspan
, NS_NewSVGTSpanFrame
),
4848 SIMPLE_SVG_CREATE(linearGradient
, NS_NewSVGLinearGradientFrame
),
4849 SIMPLE_SVG_CREATE(radialGradient
, NS_NewSVGRadialGradientFrame
),
4850 SIMPLE_SVG_CREATE(stop
, NS_NewSVGStopFrame
),
4851 SIMPLE_SVG_CREATE(use
, NS_NewSVGUseFrame
),
4852 SIMPLE_SVG_CREATE(marker
, NS_NewSVGMarkerFrame
),
4853 SIMPLE_SVG_CREATE(image
, NS_NewSVGImageFrame
),
4854 SIMPLE_SVG_CREATE(clipPath
, NS_NewSVGClipPathFrame
),
4855 SIMPLE_SVG_CREATE(textPath
, NS_NewSVGTextPathFrame
),
4856 SIMPLE_SVG_CREATE(filter
, NS_NewSVGFilterFrame
),
4857 SIMPLE_SVG_CREATE(pattern
, NS_NewSVGPatternFrame
),
4858 SIMPLE_SVG_CREATE(mask
, NS_NewSVGMaskFrame
),
4859 SIMPLE_SVG_CREATE(feDistantLight
, NS_NewSVGLeafFrame
),
4860 SIMPLE_SVG_CREATE(fePointLight
, NS_NewSVGLeafFrame
),
4861 SIMPLE_SVG_CREATE(feSpotLight
, NS_NewSVGLeafFrame
),
4862 SIMPLE_SVG_CREATE(feBlend
, NS_NewSVGLeafFrame
),
4863 SIMPLE_SVG_CREATE(feColorMatrix
, NS_NewSVGLeafFrame
),
4864 SIMPLE_SVG_CREATE(feFuncR
, NS_NewSVGLeafFrame
),
4865 SIMPLE_SVG_CREATE(feFuncG
, NS_NewSVGLeafFrame
),
4866 SIMPLE_SVG_CREATE(feFuncB
, NS_NewSVGLeafFrame
),
4867 SIMPLE_SVG_CREATE(feFuncA
, NS_NewSVGLeafFrame
),
4868 SIMPLE_SVG_CREATE(feComposite
, NS_NewSVGLeafFrame
),
4869 SIMPLE_SVG_CREATE(feConvolveMatrix
, NS_NewSVGLeafFrame
),
4870 SIMPLE_SVG_CREATE(feDisplacementMap
, NS_NewSVGLeafFrame
),
4871 SIMPLE_SVG_CREATE(feFlood
, NS_NewSVGLeafFrame
),
4872 SIMPLE_SVG_CREATE(feGaussianBlur
, NS_NewSVGLeafFrame
),
4873 SIMPLE_SVG_CREATE(feImage
, NS_NewSVGLeafFrame
),
4874 SIMPLE_SVG_CREATE(feMergeNode
, NS_NewSVGLeafFrame
),
4875 SIMPLE_SVG_CREATE(feMorphology
, NS_NewSVGLeafFrame
),
4876 SIMPLE_SVG_CREATE(feOffset
, NS_NewSVGLeafFrame
),
4877 SIMPLE_SVG_CREATE(feTile
, NS_NewSVGLeafFrame
),
4878 SIMPLE_SVG_CREATE(feTurbulence
, NS_NewSVGLeafFrame
)
4881 const FrameConstructionData
* data
=
4882 FindDataByTag(aTag
, aContent
, aStyleContext
, sSVGData
,
4883 NS_ARRAY_LENGTH(sSVGData
));
4886 data
= &sGenericContainerData
;
4893 nsCSSFrameConstructor::ConstructSVGForeignObjectFrame(nsFrameConstructorState
& aState
,
4894 FrameConstructionItem
& aItem
,
4895 nsIFrame
* aParentFrame
,
4896 const nsStyleDisplay
* aStyleDisplay
,
4897 nsFrameItems
& aFrameItems
,
4898 nsIFrame
** aNewFrame
)
4900 nsIContent
* const content
= aItem
.mContent
;
4901 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
4903 nsIFrame
* newFrame
= NS_NewSVGForeignObjectFrame(mPresShell
, styleContext
);
4904 if (NS_UNLIKELY(!newFrame
)) {
4905 return NS_ERROR_OUT_OF_MEMORY
;
4908 // We don't allow this frame to be out of flow
4909 InitAndRestoreFrame(aState
, content
, aParentFrame
, nsnull
, newFrame
);
4910 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
4912 nsresult rv
= aState
.AddChild(newFrame
, aFrameItems
, content
, styleContext
,
4913 aParentFrame
, PR_FALSE
, PR_FALSE
);
4914 if (NS_FAILED(rv
)) {
4918 nsRefPtr
<nsStyleContext
> innerPseudoStyle
;
4919 innerPseudoStyle
= mPresShell
->StyleSet()->
4920 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozSVGForeignContent
, styleContext
);
4922 nsIFrame
* blockFrame
= NS_NewBlockFrame(mPresShell
, innerPseudoStyle
,
4923 NS_BLOCK_FLOAT_MGR
|
4924 NS_BLOCK_MARGIN_ROOT
);
4925 if (NS_UNLIKELY(!blockFrame
)) {
4926 newFrame
->Destroy();
4927 return NS_ERROR_OUT_OF_MEMORY
;
4930 nsFrameItems childItems
;
4931 // Claim to be relatively positioned so that we end up being the
4932 // absolute containing block.
4933 rv
= ConstructBlock(aState
, innerPseudoStyle
->GetStyleDisplay(), content
,
4934 newFrame
, newFrame
, innerPseudoStyle
,
4935 &blockFrame
, childItems
, PR_TRUE
,
4936 aItem
.mPendingBinding
);
4938 // Give the blockFrame a view so that GetOffsetTo works for descendants
4939 // of blockFrame with views...
4940 nsHTMLContainerFrame::CreateViewForFrame(blockFrame
, PR_TRUE
);
4942 newFrame
->SetInitialChildList(nsnull
, childItems
);
4944 *aNewFrame
= newFrame
;
4952 nsCSSFrameConstructor::AddPageBreakItem(nsIContent
* aContent
,
4953 nsStyleContext
* aMainStyleContext
,
4954 FrameConstructionItemList
& aItems
)
4956 nsRefPtr
<nsStyleContext
> pseudoStyle
;
4957 // Use the same parent style context that |aMainStyleContext| has, since
4958 // that's easier to re-resolve and it doesn't matter in practice.
4959 // (Getting different parents can result in framechange hints, e.g.,
4960 // for user-modify.)
4962 mPresShell
->StyleSet()->
4963 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::pageBreak
,
4964 aMainStyleContext
->GetParent());
4966 NS_ASSERTION(pseudoStyle
->GetStyleDisplay()->mDisplay
==
4967 NS_STYLE_DISPLAY_BLOCK
, "Unexpected display");
4969 static const FrameConstructionData sPageBreakData
=
4970 FCDATA_DECL(FCDATA_SKIP_FRAMESET
, NS_NewPageBreakFrame
);
4972 // Lie about the tag and namespace so we don't trigger anything
4973 // interesting during frame construction.
4974 aItems
.AppendItem(&sPageBreakData
, aContent
, nsCSSAnonBoxes::pageBreak
,
4975 kNameSpaceID_None
, nsnull
, pseudoStyle
.forget(), PR_TRUE
);
4979 nsCSSFrameConstructor::ConstructFrame(nsFrameConstructorState
& aState
,
4980 nsIContent
* aContent
,
4981 nsIFrame
* aParentFrame
,
4982 nsFrameItems
& aFrameItems
)
4985 NS_PRECONDITION(nsnull
!= aParentFrame
, "no parent frame");
4986 FrameConstructionItemList items
;
4987 AddFrameConstructionItems(aState
, aContent
, PR_TRUE
, aParentFrame
, items
);
4989 for (FCItemIterator
iter(items
); !iter
.IsDone(); iter
.Next()) {
4990 NS_ASSERTION(iter
.item().DesiredParentType() == GetParentType(aParentFrame
),
4991 "This is not going to work");
4993 ConstructFramesFromItem(aState
, iter
, aParentFrame
, aFrameItems
);
4994 NS_ENSURE_SUCCESS(rv
, rv
);
5001 nsCSSFrameConstructor::AddFrameConstructionItems(nsFrameConstructorState
& aState
,
5002 nsIContent
* aContent
,
5003 PRBool aSuppressWhiteSpaceOptimizations
,
5004 nsIFrame
* aParentFrame
,
5005 FrameConstructionItemList
& aItems
)
5007 aContent
->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME
);
5008 if (aContent
->IsElement()) {
5009 // We can't just remove our pending restyle flags, since we may
5010 // have restyle-later-siblings set on us. But we _can_ remove the
5011 // "is possible restyle root" flags, and need to. Otherwise we can
5012 // end up with stale such flags (e.g. if we used to have a
5013 // display:none parent when our last restyle was posted and
5014 // processed and now no longer do).
5015 aContent
->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS
&
5016 ~ELEMENT_PENDING_RESTYLE_FLAGS
);
5019 // don't create a whitespace frame if aParent doesn't want it
5020 if (!NeedFrameFor(aState
, aParentFrame
, aContent
)) {
5024 // never create frames for comments or PIs
5025 if (aContent
->IsNodeOfType(nsINode::eCOMMENT
) ||
5026 aContent
->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION
))
5029 nsRefPtr
<nsStyleContext
> styleContext
;
5030 styleContext
= ResolveStyleContext(aParentFrame
, aContent
);
5032 AddFrameConstructionItemsInternal(aState
, aContent
, aParentFrame
,
5033 aContent
->Tag(), aContent
->GetNameSpaceID(),
5034 aSuppressWhiteSpaceOptimizations
,
5036 ITEM_ALLOW_XBL_BASE
| ITEM_ALLOW_PAGE_BREAK
,
5041 * Set aContent as undisplayed content with style context aStyleContext. This
5042 * method enforces the invariant that all style contexts in the undisplayed
5043 * content map must be non-pseudo contexts and also handles unbinding
5044 * undisplayed generated content as needed.
5047 SetAsUndisplayedContent(nsFrameManager
* aFrameManager
, nsIContent
* aContent
,
5048 nsStyleContext
* aStyleContext
,
5049 PRBool aIsGeneratedContent
)
5051 if (aStyleContext
->GetPseudo()) {
5052 if (aIsGeneratedContent
) {
5053 aContent
->UnbindFromTree();
5058 NS_ASSERTION(!aIsGeneratedContent
, "Should have had pseudo type");
5059 aFrameManager
->SetUndisplayedContent(aContent
, aStyleContext
);
5063 nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
& aState
,
5064 nsIContent
* aContent
,
5065 nsIFrame
* aParentFrame
,
5067 PRInt32 aNameSpaceID
,
5068 PRBool aSuppressWhiteSpaceOptimizations
,
5069 nsStyleContext
* aStyleContext
,
5071 FrameConstructionItemList
& aItems
)
5073 // The following code allows the user to specify the base tag
5074 // of an element using XBL. XUL and HTML objects (like boxes, menus, etc.)
5075 // can then be extended arbitrarily.
5076 const nsStyleDisplay
* display
= aStyleContext
->GetStyleDisplay();
5077 nsRefPtr
<nsStyleContext
> styleContext(aStyleContext
);
5078 PendingBinding
* pendingBinding
= nsnull
;
5079 if ((aFlags
& ITEM_ALLOW_XBL_BASE
) && display
->mBinding
)
5081 // Ensure that our XBL bindings are installed.
5083 nsIXBLService
* xblService
= GetXBLService();
5087 PRBool resolveStyle
;
5089 nsAutoPtr
<PendingBinding
> newPendingBinding(new PendingBinding());
5090 if (!newPendingBinding
) {
5093 nsresult rv
= xblService
->LoadBindings(aContent
, display
->mBinding
->mURI
,
5094 display
->mBinding
->mOriginPrincipal
,
5096 getter_AddRefs(newPendingBinding
->mBinding
),
5098 if (NS_FAILED(rv
) && rv
!= NS_ERROR_XBL_BLOCKED
)
5101 if (newPendingBinding
->mBinding
) {
5102 pendingBinding
= newPendingBinding
;
5103 // aState takes over owning newPendingBinding
5104 aState
.AddPendingBinding(newPendingBinding
.forget());
5108 styleContext
= ResolveStyleContext(styleContext
->GetParent(), aContent
);
5109 display
= styleContext
->GetStyleDisplay();
5110 aStyleContext
= styleContext
;
5113 aTag
= mDocument
->BindingManager()->ResolveTag(aContent
, &aNameSpaceID
);
5116 PRBool isGeneratedContent
= ((aFlags
& ITEM_IS_GENERATED_CONTENT
) != 0);
5118 // Pre-check for display "none" - if we find that, don't create
5120 if (NS_STYLE_DISPLAY_NONE
== display
->mDisplay
) {
5121 SetAsUndisplayedContent(aState
.mFrameManager
, aContent
, styleContext
,
5122 isGeneratedContent
);
5126 PRBool isText
= aContent
->IsNodeOfType(nsINode::eTEXT
);
5127 PRBool isPopup
= PR_FALSE
;
5128 // Try to find frame construction data for this content
5129 const FrameConstructionData
* data
;
5131 data
= FindTextData(aParentFrame
);
5134 // Nothing to do here; suppressed text inside SVG
5137 #endif /* MOZ_SVG */
5140 // Don't create frames for non-SVG element children of SVG elements.
5141 if (aNameSpaceID
!= kNameSpaceID_SVG
&&
5143 aParentFrame
->IsFrameOfType(nsIFrame::eSVG
) &&
5144 !aParentFrame
->IsFrameOfType(nsIFrame::eSVGForeignObject
)
5146 SetAsUndisplayedContent(aState
.mFrameManager
, aContent
, styleContext
,
5147 isGeneratedContent
);
5150 #endif /* MOZ_SVG */
5152 data
= FindHTMLData(aContent
, aTag
, aNameSpaceID
, aParentFrame
,
5155 data
= FindXULTagData(aContent
, aTag
, aNameSpaceID
, styleContext
);
5159 data
= FindMathMLData(aContent
, aTag
, aNameSpaceID
, styleContext
);
5164 data
= FindSVGData(aContent
, aTag
, aNameSpaceID
, aParentFrame
,
5167 #endif /* MOZ_SVG */
5169 // Now check for XUL display types
5171 data
= FindXULDisplayData(display
, aContent
, styleContext
);
5174 // And general display types
5176 data
= FindDisplayData(display
, aContent
, styleContext
);
5179 NS_ASSERTION(data
, "Should have frame construction data now");
5181 if (data
->mBits
& FCDATA_SUPPRESS_FRAME
) {
5182 SetAsUndisplayedContent(aState
.mFrameManager
, aContent
, styleContext
,
5183 isGeneratedContent
);
5188 if ((data
->mBits
& FCDATA_IS_POPUP
) &&
5189 (!aParentFrame
|| // Parent is inline
5190 aParentFrame
->GetType() != nsGkAtoms::menuFrame
)) {
5191 if (!aState
.mPopupItems
.containingBlock
&&
5192 !aState
.mHavePendingPopupgroup
) {
5193 SetAsUndisplayedContent(aState
.mFrameManager
, aContent
, styleContext
,
5194 isGeneratedContent
);
5200 #endif /* MOZ_XUL */
5203 PRUint32 bits
= data
->mBits
;
5205 // Inside colgroups, suppress everything except columns.
5207 aParentFrame
->GetType() == nsGkAtoms::tableColGroupFrame
&&
5208 (!(bits
& FCDATA_IS_TABLE_PART
) ||
5209 display
->mDisplay
!= NS_STYLE_DISPLAY_TABLE_COLUMN
)) {
5210 SetAsUndisplayedContent(aState
.mFrameManager
, aContent
, styleContext
,
5211 isGeneratedContent
);
5215 PRBool canHavePageBreak
=
5216 (aFlags
& ITEM_ALLOW_PAGE_BREAK
) &&
5217 aState
.mPresContext
->IsPaginated() &&
5218 !display
->IsAbsolutelyPositioned() &&
5219 !(bits
& FCDATA_IS_TABLE_PART
);
5221 if (canHavePageBreak
&& display
->mBreakBefore
) {
5222 AddPageBreakItem(aContent
, aStyleContext
, aItems
);
5225 FrameConstructionItem
* item
=
5226 aItems
.AppendItem(data
, aContent
, aTag
, aNameSpaceID
,
5227 pendingBinding
, styleContext
.forget(),
5228 aSuppressWhiteSpaceOptimizations
);
5230 if (isGeneratedContent
) {
5231 aContent
->UnbindFromTree();
5236 item
->mIsText
= isText
;
5237 item
->mIsGeneratedContent
= isGeneratedContent
;
5238 if (isGeneratedContent
) {
5239 NS_ADDREF(item
->mContent
);
5241 item
->mIsRootPopupgroup
=
5242 aNameSpaceID
== kNameSpaceID_XUL
&& aTag
== nsGkAtoms::popupgroup
&&
5243 aContent
->IsRootOfNativeAnonymousSubtree();
5244 if (item
->mIsRootPopupgroup
) {
5245 aState
.mHavePendingPopupgroup
= PR_TRUE
;
5247 item
->mIsPopup
= isPopup
;
5249 if (canHavePageBreak
&& display
->mBreakAfter
) {
5250 AddPageBreakItem(aContent
, aStyleContext
, aItems
);
5253 if (bits
& FCDATA_IS_INLINE
) {
5254 // To correctly set item->mIsAllInline we need to build up our child items
5256 BuildInlineChildItems(aState
, *item
);
5257 item
->mHasInlineEnds
= PR_TRUE
;
5258 item
->mIsBlock
= PR_FALSE
;
5260 // Compute a boolean isInline which is guaranteed to be false for blocks
5261 // (but may also be false for some inlines).
5263 // Table-internal things are inline-outside if and only if they're kids of
5264 // inlines, since they'll trigger construction of inline-table
5266 ((bits
& FCDATA_IS_TABLE_PART
) &&
5267 (!aParentFrame
|| // No aParentFrame means inline
5268 aParentFrame
->GetStyleDisplay()->mDisplay
== NS_STYLE_DISPLAY_INLINE
)) ||
5269 // Things that are inline-outside but aren't inline frames are inline
5270 display
->IsInlineOutside() ||
5271 // Popups that are certainly out of flow.
5274 // Set mIsAllInline conservatively. It just might be that even an inline
5275 // that has mIsAllInline false doesn't need an {ib} split. So this is just
5276 // an optimization to keep from doing too much work in cases when we can
5277 // show that mIsAllInline is true..
5278 item
->mIsAllInline
= item
->mHasInlineEnds
= isInline
||
5279 // Figure out whether we're guaranteed this item will be out of flow.
5280 // This is not a precise test, since one of our ancestor inlines might add
5281 // an absolute containing block (if it's relatively positioned) when there
5282 // wasn't such a containing block before. But it's conservative in the
5283 // sense that anything that will really end up as an in-flow non-inline
5284 // will test false here. In other words, if this test is true we're
5285 // guaranteed to be inline; if it's false we don't know what we'll end up
5288 // If we make this test precise, we can remove some of the code dealing
5289 // with the imprecision in ConstructInline and adjust the comments on
5290 // mIsAllInline and mIsBlock in the header. And probably remove mIsBlock
5291 // altogether, since then it will always be equal to !mHasInlineEnds.
5292 (!(bits
& FCDATA_DISALLOW_OUT_OF_FLOW
) &&
5293 aState
.GetGeometricParent(display
, nsnull
));
5295 // Set mIsBlock conservatively. It's OK to set it false for some real
5296 // blocks, but not OK to set it true for things that aren't blocks. Since
5297 // isOutOfFlow might be false even in cases when the frame will end up
5298 // out-of-flow, we can't use it here. But we _can_ say that the frame will
5299 // for sure end up in-flow if it's not floated or absolutely positioned.
5301 !isInline
&& !display
->IsAbsolutelyPositioned() && !display
->IsFloating();
5304 if (item
->mIsAllInline
) {
5305 aItems
.InlineItemAdded();
5306 } else if (item
->mIsBlock
) {
5307 aItems
.BlockItemAdded();
5310 // Our item should be treated as a line participant if we have the relevant
5311 // bit and are going to be in-flow. Note that this really only matters if
5312 // our ancestor is a box or some such, so the fact that we might have an
5313 // inline ancestor that might become a containing block is not relevant here.
5314 if ((bits
& FCDATA_IS_LINE_PARTICIPANT
) &&
5315 ((bits
& FCDATA_DISALLOW_OUT_OF_FLOW
) ||
5316 !aState
.GetGeometricParent(display
, nsnull
))) {
5317 item
->mIsLineParticipant
= PR_TRUE
;
5318 aItems
.LineParticipantItemAdded();
5323 DestroyContent(void* aPropertyValue
)
5325 nsIContent
* content
= static_cast<nsIContent
*>(aPropertyValue
);
5326 content
->UnbindFromTree();
5327 NS_RELEASE(content
);
5330 NS_DECLARE_FRAME_PROPERTY(BeforeProperty
, DestroyContent
)
5331 NS_DECLARE_FRAME_PROPERTY(AfterProperty
, DestroyContent
)
5333 static const FramePropertyDescriptor
*
5334 GenConPseudoToProperty(nsIAtom
* aPseudo
)
5336 NS_ASSERTION(aPseudo
== nsCSSPseudoElements::before
||
5337 aPseudo
== nsCSSPseudoElements::after
,
5338 "Bad gen-con pseudo");
5339 return aPseudo
== nsCSSPseudoElements::before
? BeforeProperty()
5344 * Return true if the frame construction item pointed to by aIter will
5345 * create a frame adjacent to a line boundary in the frame tree, and that
5346 * line boundary is induced by a content node adjacent to the frame's
5347 * content node in the content tree. The latter condition is necessary so
5348 * that ContentAppended/ContentInserted/ContentRemoved can easily find any
5349 * text nodes that were suppressed here.
5352 nsCSSFrameConstructor::AtLineBoundary(FCItemIterator
& aIter
)
5354 if (aIter
.item().mSuppressWhiteSpaceOptimizations
) {
5358 if (aIter
.AtStart()) {
5359 if (aIter
.List()->HasLineBoundaryAtStart() &&
5360 !aIter
.item().mContent
->GetPreviousSibling())
5363 FCItemIterator prev
= aIter
;
5365 if (prev
.item().IsLineBoundary() &&
5366 !prev
.item().mSuppressWhiteSpaceOptimizations
&&
5367 aIter
.item().mContent
->GetPreviousSibling() == prev
.item().mContent
)
5371 FCItemIterator next
= aIter
;
5373 if (next
.IsDone()) {
5374 if (aIter
.List()->HasLineBoundaryAtEnd() &&
5375 !aIter
.item().mContent
->GetNextSibling())
5378 if (next
.item().IsLineBoundary() &&
5379 !next
.item().mSuppressWhiteSpaceOptimizations
&&
5380 aIter
.item().mContent
->GetNextSibling() == next
.item().mContent
)
5388 nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState
& aState
,
5389 FCItemIterator
& aIter
,
5390 nsIFrame
* aParentFrame
,
5391 nsFrameItems
& aFrameItems
)
5393 nsIFrame
* adjParentFrame
= aParentFrame
;
5394 FrameConstructionItem
& item
= aIter
.item();
5395 nsStyleContext
* styleContext
= item
.mStyleContext
;
5396 AdjustParentFrame(adjParentFrame
, item
.mFCData
, styleContext
);
5399 // If this is collapsible whitespace next to a line boundary,
5400 // don't create a frame. item.IsWhitespace() also sets the
5401 // NS_CREATE_FRAME_IF_NON_WHITESPACE flag in the text node. (If we
5402 // end up creating a frame, nsTextFrame::Init will clear the flag.)
5403 // We don't do this for generated content, because some generated
5404 // text content is empty text nodes that are about to be initialized.
5405 // (We check mAdditionalStateBits because only the generated content
5406 // container's frame construction item is marked with
5407 // mIsGeneratedContent, and we might not have an aParentFrame.)
5408 // We don't do it for content that may have XBL anonymous siblings,
5409 // because they make it difficult to correctly create the frame
5410 // due to dynamic changes.
5411 // We don't do it for text that's not a line participant (i.e. SVG text).
5412 if (AtLineBoundary(aIter
) &&
5413 !styleContext
->GetStyleText()->NewlineIsSignificant() &&
5414 aIter
.List()->ParentHasNoXBLChildren() &&
5415 !(aState
.mAdditionalStateBits
& NS_FRAME_GENERATED_CONTENT
) &&
5416 (item
.mFCData
->mBits
& FCDATA_IS_LINE_PARTICIPANT
) &&
5417 item
.IsWhitespace(aState
))
5420 return ConstructTextFrame(item
.mFCData
, aState
, item
.mContent
,
5421 adjParentFrame
, styleContext
,
5425 // Start background loads during frame construction. This is just
5426 // a hint; the paint code will do the right thing in any case.
5428 styleContext
->GetStyleBackground();
5431 nsFrameState savedStateBits
= aState
.mAdditionalStateBits
;
5432 if (item
.mIsGeneratedContent
) {
5433 // Ensure that frames created here are all tagged with
5434 // NS_FRAME_GENERATED_CONTENT.
5435 aState
.mAdditionalStateBits
|= NS_FRAME_GENERATED_CONTENT
;
5437 // Note that we're not necessarily setting this property on the primary
5438 // frame for the content for which this is generated content. We might be
5439 // setting it on a table pseudo-frame inserted under that instead. That's
5440 // OK, though; we just need to do the property set so that the content will
5441 // get cleaned up when the frame is destroyed.
5442 aParentFrame
->Properties().Set(GenConPseudoToProperty(styleContext
->GetPseudo()),
5445 // Now that we've passed ownership of item.mContent to the frame, unset
5446 // our generated content flag so we don't release or unbind it ourselves.
5447 item
.mIsGeneratedContent
= PR_FALSE
;
5450 // XXXbz maybe just inline ConstructFrameFromItemInternal here or something?
5451 nsresult rv
= ConstructFrameFromItemInternal(item
, aState
, adjParentFrame
,
5454 aState
.mAdditionalStateBits
= savedStateBits
;
5461 IsRootBoxFrame(nsIFrame
*aFrame
)
5463 return (aFrame
->GetType() == nsGkAtoms::rootFrame
);
5467 nsCSSFrameConstructor::ReconstructDocElementHierarchy()
5469 return RecreateFramesForContent(mPresShell
->GetDocument()->GetRootElement(),
5474 nsCSSFrameConstructor::GetFrameFor(nsIContent
* aContent
)
5476 // Get the primary frame associated with the content
5477 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
5482 // If the content of the frame is not the desired content then this is not
5483 // really a frame for the desired content.
5484 // XXX This check is needed due to bug 135040. Remove it once that's fixed.
5485 if (frame
->GetContent() != aContent
) {
5489 nsIFrame
* insertionFrame
= frame
->GetContentInsertionFrame();
5491 NS_ASSERTION(insertionFrame
== frame
|| !frame
->IsLeaf(),
5492 "The insertion frame is the primary frame or the primary frame isn't a leaf");
5494 return insertionFrame
;
5498 nsCSSFrameConstructor::GetAbsoluteContainingBlock(nsIFrame
* aFrame
)
5500 NS_PRECONDITION(nsnull
!= mRootElementFrame
, "no root element frame");
5502 // Starting with aFrame, look for a frame that is absolutely positioned or
5503 // relatively positioned
5504 nsIFrame
* containingBlock
= nsnull
;
5505 for (nsIFrame
* frame
= aFrame
; frame
&& !containingBlock
;
5506 frame
= frame
->GetParent()) {
5507 if (frame
->IsFrameOfType(nsIFrame::eMathML
)) {
5508 // If it's mathml, bail out -- no absolute positioning out from inside
5509 // mathml frames. Note that we don't make this part of the loop
5510 // condition because of the stuff at the end of this method...
5514 // Is it positioned?
5515 // If it's table-related then ignore it, because for the time
5516 // being table-related frames are not containers for absolutely
5517 // positioned child frames.
5518 const nsStyleDisplay
* disp
= frame
->GetStyleDisplay();
5520 if (disp
->IsPositioned() && !IsTableRelated(frame
->GetType())) {
5521 // Find the outermost wrapped block under this frame
5522 for (nsIFrame
* wrappedFrame
= aFrame
; wrappedFrame
!= frame
->GetParent();
5523 wrappedFrame
= wrappedFrame
->GetParent()) {
5524 nsIAtom
* frameType
= wrappedFrame
->GetType();
5525 if (nsGkAtoms::blockFrame
== frameType
||
5527 nsGkAtoms::XULLabelFrame
== frameType
||
5529 nsGkAtoms::positionedInlineFrame
== frameType
) {
5530 containingBlock
= wrappedFrame
;
5531 } else if (nsGkAtoms::fieldSetFrame
== frameType
) {
5532 // If the positioned frame is a fieldset, use the area frame inside it.
5533 // We don't use GetContentInsertionFrame for fieldsets yet.
5534 containingBlock
= GetFieldSetBlockFrame(wrappedFrame
);
5539 if (!containingBlock
)
5540 NS_WARNING("Positioned frame that does not handle positioned kids; looking further up the parent chain");
5545 // If we found an absolutely positioned containing block, then use the
5546 // first-continuation.
5547 if (containingBlock
)
5548 return AdjustAbsoluteContainingBlock(containingBlock
);
5550 // If we didn't find it, then use the document element containing block
5551 return mHasRootAbsPosContainingBlock
? mDocElementContainingBlock
: nsnull
;
5555 nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame
* aFrame
)
5557 // Starting with aFrame, look for a frame that is a float containing block.
5558 // IF we hit a mathml frame, bail out; we don't allow floating out of mathml
5559 // frames, because they don't seem to be able to deal.
5560 // The logic here needs to match the logic in ProcessChildren()
5561 for (nsIFrame
* containingBlock
= aFrame
;
5562 containingBlock
&& !containingBlock
->IsFrameOfType(nsIFrame::eMathML
) &&
5563 !containingBlock
->IsBoxFrame();
5564 containingBlock
= containingBlock
->GetParent()) {
5565 if (containingBlock
->IsFloatContainingBlock()) {
5566 return containingBlock
;
5570 // If we didn't find a containing block, then there just isn't
5571 // one.... return null
5576 * This function will check whether aContainer has :after generated content.
5577 * If so, appending to it should actually insert. The return value is the
5578 * parent to use for newly-appended content. *aAfterFrame points to the :after
5579 * frame before which appended content should go, if there is one.
5582 AdjustAppendParentForAfterContent(nsPresContext
* aPresContext
,
5583 nsIContent
* aContainer
,
5584 nsIFrame
* aParentFrame
,
5585 nsIFrame
** aAfterFrame
)
5587 // See if the parent has an :after pseudo-element. Check for the presence
5588 // of style first, since nsLayoutUtils::GetAfterFrame is sorta expensive.
5589 nsStyleContext
* parentStyle
= aParentFrame
->GetStyleContext();
5590 if (nsLayoutUtils::HasPseudoStyle(aContainer
, parentStyle
,
5591 nsCSSPseudoElements::ePseudo_after
,
5593 nsIFrame
* afterFrame
= nsLayoutUtils::GetAfterFrame(aParentFrame
);
5595 *aAfterFrame
= afterFrame
;
5596 return afterFrame
->GetParent();
5600 *aAfterFrame
= nsnull
;
5602 if (IsFrameSpecial(aParentFrame
)) {
5603 // We might be in a situation where the last part of the {ib} split was
5604 // empty. Since we have no ::after pseudo-element, we do in fact want to be
5605 // appending to that last part, so advance to it if needed. Note that here
5606 // aParentFrame is the result of a GetLastSpecialSibling call, so must be
5607 // either the last or next to last special sibling.
5608 nsIFrame
* trailingInline
= GetSpecialSibling(aParentFrame
);
5609 if (trailingInline
) {
5610 aParentFrame
= trailingInline
;
5613 // Always make sure to look at the last continuation of the frame
5614 // for the {ib} case, even if that continuation is empty. We
5615 // don't do this for the non-special-frame case, since in the
5616 // other cases appending to the last nonempty continuation is fine
5617 // and in fact not doing that can confuse code that doesn't know
5618 // to pull kids from continuations other than its next one.
5619 aParentFrame
= aParentFrame
->GetLastContinuation();
5622 return aParentFrame
;
5626 * This function will get the previous sibling to use for an append operation.
5627 * it takes a parent frame (must not be null) and its :after frame (may be
5631 FindAppendPrevSibling(nsIFrame
* aParentFrame
, nsIFrame
* aAfterFrame
)
5634 NS_ASSERTION(aAfterFrame
->GetParent() == aParentFrame
, "Wrong parent");
5635 return aAfterFrame
->GetPrevSibling();
5638 return aParentFrame
->GetLastChild(nsnull
);
5642 * This function will get the next sibling for a frame insert operation given
5643 * the parent and previous sibling. aPrevSibling may be null.
5646 GetInsertNextSibling(nsIFrame
* aParentFrame
, nsIFrame
* aPrevSibling
)
5649 return aPrevSibling
->GetNextSibling();
5652 return aParentFrame
->GetFirstChild(nsnull
);
5656 * This function is called by ContentAppended() and ContentInserted() when
5657 * appending flowed frames to a parent's principal child list. It handles the
5658 * case where the parent is the trailing inline of an {ib} split.
5661 nsCSSFrameConstructor::AppendFrames(nsFrameConstructorState
& aState
,
5662 nsIFrame
* aParentFrame
,
5663 nsFrameItems
& aFrameList
,
5664 nsIFrame
* aPrevSibling
,
5665 PRBool aIsRecursiveCall
)
5667 NS_PRECONDITION(!IsFrameSpecial(aParentFrame
) ||
5668 !GetSpecialSibling(aParentFrame
) ||
5669 !GetSpecialSibling(aParentFrame
)->GetFirstChild(nsnull
),
5670 "aParentFrame has a special sibling with kids?");
5671 NS_PRECONDITION(!aPrevSibling
|| aPrevSibling
->GetParent() == aParentFrame
,
5672 "Parent and prevsibling don't match");
5674 nsIFrame
* nextSibling
= ::GetInsertNextSibling(aParentFrame
, aPrevSibling
);
5676 NS_ASSERTION(nextSibling
||
5677 !aParentFrame
->GetNextContinuation() ||
5678 !aParentFrame
->GetNextContinuation()->GetFirstChild(nsnull
) ||
5680 "aParentFrame has later continuations with kids?");
5681 NS_ASSERTION(nextSibling
||
5682 !IsFrameSpecial(aParentFrame
) ||
5683 (IsInlineFrame(aParentFrame
) &&
5684 !GetSpecialSibling(aParentFrame
) &&
5685 !aParentFrame
->GetNextContinuation()) ||
5687 "aParentFrame is not last?");
5689 // If we're inserting a list of frames at the end of the trailing inline
5690 // of an {ib} split, we may need to create additional {ib} siblings to parent
5692 if (!nextSibling
&& IsFrameSpecial(aParentFrame
)) {
5693 // When we get here, our frame list might start with a block. If it does
5694 // so, and aParentFrame is an inline, and it and all its previous
5695 // continuations have no siblings, then put the initial blocks from the
5696 // frame list into the previous block of the {ib} split. Note that we
5697 // didn't want to stop at the block part of the split when figuring out
5698 // initial parent, because that could screw up float parenting; it's easier
5699 // to do this little fixup here instead.
5700 if (aFrameList
.NotEmpty() && !IsInlineOutside(aFrameList
.FirstChild())) {
5701 // See whether our trailing inline is empty
5702 nsIFrame
* firstContinuation
= aParentFrame
->GetFirstContinuation();
5703 if (firstContinuation
->GetChildList(nsnull
).IsEmpty()) {
5704 // Our trailing inline is empty. Collect our starting blocks from
5705 // aFrameList, get the right parent frame for them, and put them in.
5706 nsFrameList::FrameLinkEnumerator firstNonBlockEnumerator
=
5707 FindFirstNonBlock(aFrameList
);
5708 nsFrameList blockKids
= aFrameList
.ExtractHead(firstNonBlockEnumerator
);
5709 NS_ASSERTION(blockKids
.NotEmpty(), "No blocks?");
5711 nsIFrame
* prevBlock
=
5712 GetSpecialPrevSibling(firstContinuation
)->GetLastContinuation();
5713 NS_ASSERTION(prevBlock
, "Should have previous block here");
5715 MoveChildrenTo(aState
.mPresContext
, aParentFrame
, prevBlock
, blockKids
);
5719 // We want to put some of the frames into this inline frame.
5720 nsFrameList::FrameLinkEnumerator
firstBlockEnumerator(aFrameList
);
5721 FindFirstBlock(firstBlockEnumerator
);
5723 nsFrameList inlineKids
= aFrameList
.ExtractHead(firstBlockEnumerator
);
5724 if (!inlineKids
.IsEmpty()) {
5725 aState
.mFrameManager
->AppendFrames(aParentFrame
, nsnull
, inlineKids
);
5728 if (!aFrameList
.IsEmpty()) {
5729 const nsStyleDisplay
* parentDisplay
= aParentFrame
->GetStyleDisplay();
5731 parentDisplay
->mPosition
== NS_STYLE_POSITION_RELATIVE
||
5732 parentDisplay
->HasTransform();
5733 nsFrameItems ibSiblings
;
5734 CreateIBSiblings(aState
, aParentFrame
, positioned
, aFrameList
,
5737 // Make sure to trigger reflow of the inline that used to be our
5738 // last one and now isn't anymore, since its GetSkipSides() has
5740 mPresShell
->FrameNeedsReflow(aParentFrame
,
5741 nsIPresShell::eTreeChange
,
5742 NS_FRAME_HAS_DIRTY_CHILDREN
);
5744 // Recurse so we create new ib siblings as needed for aParentFrame's parent
5745 return AppendFrames(aState
, aParentFrame
->GetParent(), ibSiblings
,
5746 aParentFrame
, PR_TRUE
);
5752 // Insert the frames after our aPrevSibling
5753 return aState
.mFrameManager
->InsertFrames(aParentFrame
, nsnull
, aPrevSibling
,
5757 #define UNSET_DISPLAY 255
5759 // This gets called to see if the frames corresponding to aSibling and aContent
5760 // should be siblings in the frame tree. Although (1) rows and cols, (2) row
5761 // groups and col groups, (3) row groups and captions, (4) legends and content
5762 // inside fieldsets, (5) popups and other kids of the menu are siblings from a
5763 // content perspective, they are not considered siblings in the frame tree.
5765 nsCSSFrameConstructor::IsValidSibling(nsIFrame
* aSibling
,
5766 nsIContent
* aContent
,
5769 nsIFrame
* parentFrame
= aSibling
->GetParent();
5770 nsIAtom
* parentType
= nsnull
;
5771 nsIAtom
* grandparentType
= nsnull
;
5773 parentType
= parentFrame
->GetType();
5774 nsIFrame
* grandparentFrame
= parentFrame
->GetParent();
5775 if (grandparentFrame
) {
5776 grandparentType
= grandparentFrame
->GetType();
5780 PRUint8 siblingDisplay
= aSibling
->GetStyleDisplay()->mDisplay
;
5781 if ((NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
== siblingDisplay
) ||
5782 (NS_STYLE_DISPLAY_TABLE_COLUMN
== siblingDisplay
) ||
5783 (NS_STYLE_DISPLAY_TABLE_CAPTION
== siblingDisplay
) ||
5784 (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP
== siblingDisplay
) ||
5785 (NS_STYLE_DISPLAY_TABLE_ROW_GROUP
== siblingDisplay
) ||
5786 (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP
== siblingDisplay
) ||
5787 nsGkAtoms::menuFrame
== parentType
) {
5788 // if we haven't already, construct a style context to find the display type of aContent
5789 if (UNSET_DISPLAY
== aDisplay
) {
5790 nsRefPtr
<nsStyleContext
> styleContext
;
5791 nsIFrame
* styleParent
;
5792 PRBool providerIsChild
;
5793 if (NS_FAILED(aSibling
->
5794 GetParentStyleContextFrame(aSibling
->PresContext(),
5796 &providerIsChild
)) ||
5798 NS_NOTREACHED("Shouldn't happen");
5801 styleContext
= ResolveStyleContext(styleParent
, aContent
);
5802 if (!styleContext
) return PR_FALSE
;
5803 const nsStyleDisplay
* display
= styleContext
->GetStyleDisplay();
5804 aDisplay
= display
->mDisplay
;
5806 if (nsGkAtoms::menuFrame
== parentType
) {
5808 (NS_STYLE_DISPLAY_POPUP
== aDisplay
) ==
5809 (NS_STYLE_DISPLAY_POPUP
== siblingDisplay
);
5811 // To have decent performance we want to return false in cases in which
5812 // reordering the two siblings has no effect on display. To ensure
5813 // correctness, we MUST return false in cases where the two siblings have
5814 // the same desired parent type and live on different display lists.
5815 // Specificaly, columns and column groups should only consider columns and
5816 // column groups as valid siblings. Captions should only consider other
5817 // captions. All other things should consider each other as valid
5818 // siblings. The restriction in the |if| above on siblingDisplay is ok,
5819 // because for correctness the only part that really needs to happen is to
5820 // not consider captions, column groups, and row/header/footer groups
5821 // siblings of each other. Treating a column or colgroup as a valid
5822 // sibling of a non-table-related frame will just mean we end up reframing.
5823 if ((siblingDisplay
== NS_STYLE_DISPLAY_TABLE_CAPTION
) !=
5824 (aDisplay
== NS_STYLE_DISPLAY_TABLE_CAPTION
)) {
5825 // One's a caption and the other is not. Not valid siblings.
5829 if ((siblingDisplay
== NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
||
5830 siblingDisplay
== NS_STYLE_DISPLAY_TABLE_COLUMN
) !=
5831 (aDisplay
== NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
||
5832 aDisplay
== NS_STYLE_DISPLAY_TABLE_COLUMN
)) {
5833 // One's a column or column group and the other is not. Not valid
5840 else if (nsGkAtoms::fieldSetFrame
== parentType
||
5841 (nsGkAtoms::fieldSetFrame
== grandparentType
&&
5842 nsGkAtoms::blockFrame
== parentType
)) {
5843 // Legends can be sibling of legends but not of other content in the fieldset
5844 nsIAtom
* sibType
= aSibling
->GetType();
5845 nsCOMPtr
<nsIDOMHTMLLegendElement
> legendContent(do_QueryInterface(aContent
));
5847 if ((legendContent
&& (nsGkAtoms::legendFrame
!= sibType
)) ||
5848 (!legendContent
&& (nsGkAtoms::legendFrame
== sibType
)))
5856 nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent
* aContent
,
5857 nsIContent
* aTargetContent
,
5858 PRUint8
& aTargetContentDisplay
,
5859 PRBool aPrevSibling
)
5861 nsIFrame
* sibling
= aContent
->GetPrimaryFrame();
5862 if (!sibling
|| sibling
->GetContent() != aContent
) {
5863 // XXX the GetContent() != aContent check is needed due to bug 135040.
5864 // Remove it once that's fixed.
5868 // If the frame is out-of-flow, GetPrimaryFrame() will have returned the
5869 // out-of-flow frame; we want the placeholder.
5870 if (sibling
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
5871 nsIFrame
* placeholderFrame
= mPresShell
->FrameManager()->GetPlaceholderFrameFor(sibling
);
5872 NS_ASSERTION(placeholderFrame
, "no placeholder for out-of-flow frame");
5873 sibling
= placeholderFrame
;
5876 // The frame we have now should never be a continuation
5877 NS_ASSERTION(!sibling
->GetPrevContinuation(), "How did that happen?");
5880 // The frame may be a special frame (a split inline frame that
5881 // contains a block). Get the last part of that split.
5882 if (IsFrameSpecial(sibling
)) {
5883 sibling
= GetLastSpecialSibling(sibling
, PR_TRUE
);
5886 // The frame may have a continuation. If so, we want the last
5887 // non-overflow-container continuation as our previous sibling.
5888 sibling
= sibling
->GetTailContinuation();
5891 if (aTargetContent
&&
5892 !IsValidSibling(sibling
, aTargetContent
, aTargetContentDisplay
)) {
5900 nsCSSFrameConstructor::FindPreviousSibling(const ChildIterator
& aFirst
,
5901 ChildIterator aIter
,
5902 PRUint8
& aTargetContentDisplay
)
5904 nsIContent
* child
= *aIter
;
5906 // Note: not all content objects are associated with a frame (e.g., if it's
5907 // `display: none') so keep looking until we find a previous frame
5908 while (aIter
!= aFirst
) {
5910 nsIFrame
* prevSibling
=
5911 FindFrameForContentSibling(*aIter
, child
, aTargetContentDisplay
, PR_TRUE
);
5914 // Found a previous sibling, we're done!
5923 nsCSSFrameConstructor::FindNextSibling(ChildIterator aIter
,
5924 const ChildIterator
& aLast
,
5925 PRUint8
& aTargetContentDisplay
)
5927 if (aIter
== aLast
) {
5928 // XXXbz Can happen when XBL lies to us about insertion points. This check
5929 // might be able to go away once bug 474324 is fixed.
5933 nsIContent
* child
= *aIter
;
5935 while (++aIter
!= aLast
) {
5936 nsIFrame
* nextSibling
=
5937 FindFrameForContentSibling(*aIter
, child
, aTargetContentDisplay
, PR_FALSE
);
5940 // We found a next sibling, we're done!
5948 // For fieldsets, returns the area frame, if the child is not a legend.
5950 GetAdjustedParentFrame(nsIFrame
* aParentFrame
,
5951 nsIAtom
* aParentFrameType
,
5952 nsIContent
* aChildContent
)
5954 NS_PRECONDITION(nsGkAtoms::tableOuterFrame
!= aParentFrameType
,
5955 "Shouldn't be happening!");
5957 nsIFrame
* newParent
= nsnull
;
5959 if (nsGkAtoms::fieldSetFrame
== aParentFrameType
) {
5960 // If the parent is a fieldSet, use the fieldSet's area frame as the
5961 // parent unless the new content is a legend.
5962 nsCOMPtr
<nsIDOMHTMLLegendElement
> legendContent(do_QueryInterface(aChildContent
));
5963 if (!legendContent
) {
5964 newParent
= GetFieldSetBlockFrame(aParentFrame
);
5967 return (newParent
) ? newParent
: aParentFrame
;
5971 nsCSSFrameConstructor::GetInsertionPrevSibling(nsIFrame
*& aParentFrame
,
5972 nsIContent
* aContainer
,
5975 PRBool
* aIsRangeInsertSafe
,
5976 nsIContent
* aStartSkipChild
,
5977 nsIContent
* aEndSkipChild
)
5979 *aIsAppend
= PR_FALSE
;
5981 // Find the frame that precedes the insertion point. Walk backwards
5982 // from the parent frame to get the parent content, because if an
5983 // XBL insertion point is involved, we'll need to use _that_ to find
5984 // the preceding frame.
5986 NS_PRECONDITION(aParentFrame
, "Must have parent frame to start with");
5987 nsIContent
* container
= aParentFrame
->GetContent();
5989 ChildIterator first
, last
;
5990 ChildIterator::Init(container
, &first
, &last
);
5991 ChildIterator
iter(first
);
5992 PRBool xblCase
= iter
.XBLInvolved() || container
!= aContainer
;
5993 if (xblCase
|| !aChild
->IsRootOfAnonymousSubtree()) {
5994 // The check for IsRootOfAnonymousSubtree() is because editor is
5995 // severely broken and calls us directly for native anonymous
5996 // nodes that it creates.
5997 if (aStartSkipChild
) {
5998 iter
.seek(aStartSkipChild
);
6005 NS_WARNING("Someone passed native anonymous content directly into frame "
6006 "construction. Stop doing that!");
6010 PRUint8 childDisplay
= UNSET_DISPLAY
;
6011 nsIFrame
* prevSibling
= FindPreviousSibling(first
, iter
, childDisplay
);
6013 // Now, find the geometric parent so that we can handle
6014 // continuations properly. Use the prev sibling if we have it;
6015 // otherwise use the next sibling.
6017 aParentFrame
= prevSibling
->GetParent()->GetContentInsertionFrame();
6020 // If there is no previous sibling, then find the frame that follows
6021 if (aEndSkipChild
) {
6022 iter
.seek(aEndSkipChild
);
6025 nsIFrame
* nextSibling
= FindNextSibling(iter
, last
, childDisplay
);
6028 aParentFrame
= nextSibling
->GetParent()->GetContentInsertionFrame();
6031 // No previous or next sibling, so treat this like an appended frame.
6032 *aIsAppend
= PR_TRUE
;
6033 if (IsFrameSpecial(aParentFrame
)) {
6034 // Since we're appending, we'll walk to the last anonymous frame
6035 // that was created for the broken inline frame. But don't walk
6036 // to the trailing inline if it's empty; stop at the block.
6037 aParentFrame
= GetLastSpecialSibling(aParentFrame
, PR_FALSE
);
6039 // Get continuation that parents the last child. This MUST be done
6040 // before the AdjustAppendParentForAfterContent call.
6041 aParentFrame
= nsLayoutUtils::GetLastContinuationWithChild(aParentFrame
);
6042 // Deal with fieldsets
6043 aParentFrame
= ::GetAdjustedParentFrame(aParentFrame
,
6044 aParentFrame
->GetType(),
6046 nsIFrame
* appendAfterFrame
;
6048 ::AdjustAppendParentForAfterContent(mPresShell
->GetPresContext(),
6049 container
, aParentFrame
,
6051 prevSibling
= ::FindAppendPrevSibling(aParentFrame
, appendAfterFrame
);
6055 *aIsRangeInsertSafe
= (childDisplay
== UNSET_DISPLAY
);
6060 IsSpecialFramesetChild(nsIContent
* aContent
)
6062 // IMPORTANT: This must match the conditions in nsHTMLFramesetFrame::Init.
6063 return aContent
->IsHTML() &&
6064 (aContent
->Tag() == nsGkAtoms::frameset
||
6065 aContent
->Tag() == nsGkAtoms::frame
);
6069 InvalidateCanvasIfNeeded(nsIPresShell
* presShell
, nsIContent
* node
);
6075 IsXULListBox(nsIContent
* aContainer
)
6077 return (aContainer
->IsXUL() && aContainer
->Tag() == nsGkAtoms::listbox
);
6082 MaybeGetListBoxBodyFrame(nsIContent
* aContainer
, nsIContent
* aChild
)
6087 if (IsXULListBox(aContainer
) &&
6088 aChild
->IsXUL() && aChild
->Tag() == nsGkAtoms::listitem
) {
6089 nsCOMPtr
<nsIDOMXULElement
> xulElement
= do_QueryInterface(aContainer
);
6090 nsCOMPtr
<nsIBoxObject
> boxObject
;
6091 xulElement
->GetBoxObject(getter_AddRefs(boxObject
));
6092 nsCOMPtr
<nsPIListBoxObject
> listBoxObject
= do_QueryInterface(boxObject
);
6093 if (listBoxObject
) {
6094 return listBoxObject
->GetListBoxBody(PR_FALSE
);
6103 nsCSSFrameConstructor::AddTextItemIfNeeded(nsFrameConstructorState
& aState
,
6104 nsIFrame
* aParentFrame
,
6105 nsIContent
* aPossibleTextContent
,
6106 FrameConstructionItemList
& aItems
)
6108 NS_PRECONDITION(aPossibleTextContent
, "Must have node");
6109 if (!aPossibleTextContent
->IsNodeOfType(nsINode::eTEXT
) ||
6110 !aPossibleTextContent
->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE
)) {
6111 // Not text, or not suppressed due to being all-whitespace (if it
6112 // were being suppressed, it would have the
6113 // NS_CREATE_FRAME_IF_NON_WHITESPACE flag)
6116 NS_ASSERTION(!aPossibleTextContent
->GetPrimaryFrame(),
6117 "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
6118 AddFrameConstructionItems(aState
, aPossibleTextContent
, PR_FALSE
,
6119 aParentFrame
, aItems
);
6123 nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent
* aParentContent
,
6124 nsIContent
* aContent
)
6126 if (!aContent
->IsNodeOfType(nsINode::eTEXT
) ||
6127 !aContent
->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE
)) {
6128 // Not text, or not suppressed due to being all-whitespace (if it
6129 // were being suppressed, it would have the
6130 // NS_CREATE_FRAME_IF_NON_WHITESPACE flag)
6133 NS_ASSERTION(!aContent
->GetPrimaryFrame(),
6134 "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
6135 ContentInserted(aParentContent
, aContent
, nsnull
, PR_FALSE
);
6138 // We want to disable lazy frame construction for nodes that are under an
6139 // editor. We use nsINode::IsEditable, but that includes inputs with type text
6140 // and password and textareas, which are common and aren't really editable (the
6141 // native anonymous content under them is what is actually editable) so we want
6142 // to construct frames for those lazily.
6143 // The logic for this check is based on
6144 // nsGenericHTMLFormElement::UpdateEditableFormControlState and so must be kept
6145 // in sync with that. The presence of the NODE_MAY_HAVE_CONTENT_EDITABLE_ATTR
6146 // flag only indicates a contenteditable attribute, it doesn't indicate if it
6147 // is true or false, so we force eager construction in some cases when the node
6148 // is not editable, but that should be rare.
6149 static inline PRBool
6150 IsActuallyEditable(nsIContent
* aContainer
, nsIContent
* aChild
)
6152 return (aChild
->IsEditable() &&
6153 (aContainer
->IsEditable() ||
6154 aChild
->HasFlag(NODE_MAY_HAVE_CONTENT_EDITABLE_ATTR
)));
6157 // For inserts aChild should be valid, for appends it should be null.
6158 // Returns true if this operation can be lazy, false if not.
6160 nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation
,
6161 nsIContent
* aContainer
,
6164 if (mPresShell
->GetPresContext()->IsChrome() || !aContainer
||
6165 aContainer
->IsInNativeAnonymousSubtree() || aContainer
->IsXUL()) {
6169 if (aOperation
== CONTENTINSERT
) {
6170 if (aChild
->IsRootOfAnonymousSubtree() ||
6171 aChild
->IsXUL() || IsActuallyEditable(aContainer
, aChild
)) {
6174 } else { // CONTENTAPPEND
6175 NS_ASSERTION(aOperation
== CONTENTAPPEND
,
6176 "operation should be either insert or append");
6177 for (nsIContent
* child
= aChild
; child
; child
= child
->GetNextSibling()) {
6178 NS_ASSERTION(!child
->IsRootOfAnonymousSubtree(),
6179 "Should be coming through the CONTENTAPPEND case");
6180 if (child
->IsXUL() || IsActuallyEditable(aContainer
, child
)) {
6186 // We can construct lazily; just need to set suitable bits in the content
6189 // Walk up the tree setting the NODE_DESCENDANTS_NEED_FRAMES bit as we go.
6190 nsIContent
* content
= aContainer
;
6192 // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
6193 // we want to assert, but leaf frames that process their own children and may
6194 // ignore anonymous children (eg framesets) make this complicated. So we set
6195 // these two booleans if we encounter these situations and unset them if we
6196 // hit a node with a leaf frame.
6197 PRBool noPrimaryFrame
= PR_FALSE
;
6198 PRBool needsFrameBitSet
= PR_FALSE
;
6201 !content
->HasFlag(NODE_DESCENDANTS_NEED_FRAMES
)) {
6203 if (content
->GetPrimaryFrame() && content
->GetPrimaryFrame()->IsLeaf()) {
6204 noPrimaryFrame
= needsFrameBitSet
= PR_FALSE
;
6206 if (!noPrimaryFrame
&& !content
->GetPrimaryFrame()) {
6207 noPrimaryFrame
= PR_TRUE
;
6209 if (!needsFrameBitSet
&& content
->HasFlag(NODE_NEEDS_FRAME
)) {
6210 needsFrameBitSet
= PR_TRUE
;
6213 content
->SetFlags(NODE_DESCENDANTS_NEED_FRAMES
);
6214 content
= content
->GetFlattenedTreeParent();
6217 if (content
&& content
->GetPrimaryFrame() &&
6218 content
->GetPrimaryFrame()->IsLeaf()) {
6219 noPrimaryFrame
= needsFrameBitSet
= PR_FALSE
;
6221 NS_ASSERTION(!noPrimaryFrame
, "Ancestors of nodes with frames to be "
6222 "constructed lazily should have frames");
6223 NS_ASSERTION(!needsFrameBitSet
, "Ancestors of nodes with frames to be "
6224 "constructed lazily should not have NEEDS_FRAME bit set");
6227 // Set NODE_NEEDS_FRAME on the new nodes.
6228 if (aOperation
== CONTENTINSERT
) {
6229 NS_ASSERTION(!aChild
->GetPrimaryFrame() ||
6230 aChild
->GetPrimaryFrame()->GetContent() != aChild
,
6231 //XXX the aChild->GetPrimaryFrame()->GetContent() != aChild
6232 // check is needed due to bug 135040. Remove it once that's
6234 "setting NEEDS_FRAME on a node that already has a frame?");
6235 aChild
->SetFlags(NODE_NEEDS_FRAME
);
6236 } else { // CONTENTAPPEND
6237 for (nsIContent
* child
= aChild
; child
; child
= child
->GetNextSibling()) {
6238 NS_ASSERTION(!child
->GetPrimaryFrame() ||
6239 child
->GetPrimaryFrame()->GetContent() != child
,
6240 //XXX the child->GetPrimaryFrame()->GetContent() != child
6241 // check is needed due to bug 135040. Remove it once that's
6243 "setting NEEDS_FRAME on a node that already has a frame?");
6244 child
->SetFlags(NODE_NEEDS_FRAME
);
6248 PostRestyleEventInternal(PR_TRUE
);
6253 nsCSSFrameConstructor::CreateNeededFrames(nsIContent
* aContent
)
6255 NS_ASSERTION(!aContent
->HasFlag(NODE_NEEDS_FRAME
),
6256 "shouldn't get here with a content node that has needs frame bit set");
6257 NS_ASSERTION(aContent
->HasFlag(NODE_DESCENDANTS_NEED_FRAMES
),
6258 "should only get here with a content node that has descendants needing frames");
6260 aContent
->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES
);
6262 // We could either descend first (on nodes that don't have NODE_NEEDS_FRAME
6263 // set) or issue content notifications for our kids first. In absence of
6264 // anything definitive either way we'll go with the latter.
6266 // It might be better to use GetChildArray and scan it completely first and
6267 // then issue all notifications. (We have to scan it completely first because
6268 // constructing frames can set attributes, which can change the storage of
6271 // Scan the children of aContent to see what operations (if any) we need to
6273 PRUint32 childCount
= aContent
->GetChildCount();
6274 PRBool inRun
= PR_FALSE
;
6275 nsIContent
* firstChildInRun
= nsnull
;
6276 for (PRUint32 i
= 0; i
< childCount
; i
++) {
6277 nsIContent
* child
= aContent
->GetChildAt(i
);
6278 if (child
->HasFlag(NODE_NEEDS_FRAME
)) {
6279 NS_ASSERTION(!child
->GetPrimaryFrame() ||
6280 child
->GetPrimaryFrame()->GetContent() != child
,
6281 //XXX the child->GetPrimaryFrame()->GetContent() != child
6282 // check is needed due to bug 135040. Remove it once that's
6284 "NEEDS_FRAME set on a node that already has a frame?");
6287 firstChildInRun
= child
;
6292 // generate a ContentRangeInserted for [startOfRun,i)
6293 ContentRangeInserted(aContent
, firstChildInRun
, child
, nsnull
,
6299 ContentAppended(aContent
, firstChildInRun
, PR_FALSE
);
6303 ChildIterator iter
, last
;
6304 for (ChildIterator::Init(aContent
, &iter
, &last
);
6307 nsIContent
* child
= *iter
;
6308 if (child
->HasFlag(NODE_DESCENDANTS_NEED_FRAMES
)) {
6309 CreateNeededFrames(child
);
6314 void nsCSSFrameConstructor::CreateNeededFrames()
6316 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
6317 "Someone forgot a script blocker");
6319 Element
* rootElement
= mDocument
->GetRootElement();
6320 NS_ASSERTION(!rootElement
|| !rootElement
->HasFlag(NODE_NEEDS_FRAME
),
6321 "root element should not have frame created lazily");
6322 if (rootElement
&& rootElement
->HasFlag(NODE_DESCENDANTS_NEED_FRAMES
)) {
6324 CreateNeededFrames(rootElement
);
6330 nsCSSFrameConstructor::IssueSingleInsertNofications(nsIContent
* aContainer
,
6331 nsIContent
* aStartChild
,
6332 nsIContent
* aEndChild
,
6333 PRBool aAllowLazyConstruction
)
6335 for (nsIContent
* child
= aStartChild
;
6337 child
= child
->GetNextSibling()) {
6338 if ((child
->GetPrimaryFrame() ||
6339 mPresShell
->FrameManager()->GetUndisplayedContent(child
))
6341 // Except listboxes suck, so do NOT skip anything here if
6342 // we plan to notify a listbox.
6343 && !MaybeGetListBoxBodyFrame(aContainer
, child
)
6346 // Already have a frame or undisplayed entry for this content; a
6347 // previous ContentInserted in this loop must have reconstructed
6348 // its insertion parent. Skip it.
6351 // Call ContentInserted with this node.
6352 ContentInserted(aContainer
, child
, mTempFrameTreeState
,
6353 aAllowLazyConstruction
);
6358 nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent
* aContainer
,
6359 nsIFrame
* aParentFrame
,
6360 nsIContent
* aStartChild
,
6361 nsIContent
* aEndChild
,
6362 PRBool aAllowLazyConstruction
)
6364 // See if we have an XBL insertion point. If so, then that's our
6365 // real parent frame; if not, then the frame hasn't been built yet
6366 // and we just bail.
6367 nsIFrame
* insertionPoint
;
6368 PRBool multiple
= PR_FALSE
;
6369 GetInsertionPoint(aParentFrame
, nsnull
, &insertionPoint
, &multiple
);
6370 if (! insertionPoint
)
6371 return nsnull
; // Don't build the frames.
6373 PRBool hasInsertion
= PR_FALSE
;
6375 // XXXbz XBL2/sXBL issue
6376 nsIDocument
* document
= aStartChild
->GetDocument();
6377 // XXXbz how would |document| be null here?
6379 document
->BindingManager()->GetInsertionParent(aStartChild
)) {
6380 hasInsertion
= PR_TRUE
;
6384 if (multiple
|| hasInsertion
) {
6385 // We have an insertion point. There are some additional tests we need to do
6386 // in order to ensure that an append is a safe operation.
6387 PRUint32 childCount
= 0;
6390 // We may need to make multiple ContentInserted calls instead. A
6391 // reasonable heuristic to employ (in order to maintain good performance)
6392 // is to find out if the insertion point's content node contains any
6393 // explicit children. If it does not, then it is highly likely that
6394 // an append is occurring. (Note it is not definite, and there are insane
6395 // cases we will not deal with by employing this heuristic, but it beats
6396 // always falling back to multiple ContentInserted calls).
6398 // In the multiple insertion point case, we know we're going to need to do
6399 // multiple ContentInserted calls anyway.
6400 childCount
= insertionPoint
->GetContent()->GetChildCount();
6403 // If we have multiple insertion points or if we have an insertion point
6404 // and the operation is not a true append or if the insertion point already
6405 // has explicit children, then we must fall back.
6406 if (multiple
|| aEndChild
!= nsnull
|| childCount
> 0) {
6407 // Now comes the fun part. For each inserted child, make a
6408 // ContentInserted call as if it had just gotten inserted and
6409 // let ContentInserted handle the mess.
6410 IssueSingleInsertNofications(aContainer
, aStartChild
, aEndChild
,
6411 aAllowLazyConstruction
);
6416 return insertionPoint
;
6420 nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame
* aParentFrame
,
6421 nsIContent
* aStartChild
,
6422 nsIContent
* aEndChild
)
6424 if (aParentFrame
->GetType() == nsGkAtoms::frameSetFrame
) {
6425 // Check whether we have any kids we care about.
6426 for (nsIContent
* cur
= aStartChild
;
6428 cur
= cur
->GetNextSibling()) {
6429 if (IsSpecialFramesetChild(cur
)) {
6430 // Just reframe the parent, since framesets are weird like that.
6431 RecreateFramesForContent(aParentFrame
->GetContent(), PR_FALSE
);
6440 nsCSSFrameConstructor::ContentAppended(nsIContent
* aContainer
,
6441 nsIContent
* aFirstNewContent
,
6442 PRBool aAllowLazyConstruction
)
6444 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell
->GetPresContext(), FrameC
);
6445 NS_PRECONDITION(mUpdateCount
!= 0,
6446 "Should be in an update while creating frames");
6449 if (gNoisyContentUpdates
) {
6450 printf("nsCSSFrameConstructor::ContentAppended container=%p "
6451 "first-child=%p lazy=%d\n",
6452 static_cast<void*>(aContainer
), aFirstNewContent
,
6453 aAllowLazyConstruction
);
6454 if (gReallyNoisyContentUpdates
&& aContainer
) {
6455 aContainer
->List(stdout
, 0);
6462 PRInt32 namespaceID
;
6464 mDocument
->BindingManager()->ResolveTag(aContainer
, &namespaceID
);
6466 // Just ignore tree tags, anyway we don't create any frames for them.
6467 if (tag
== nsGkAtoms::treechildren
||
6468 tag
== nsGkAtoms::treeitem
||
6469 tag
== nsGkAtoms::treerow
)
6475 // Get the frame associated with the content
6476 nsIFrame
* parentFrame
= GetFrameFor(aContainer
);
6480 if (aAllowLazyConstruction
&&
6481 MaybeConstructLazily(CONTENTAPPEND
, aContainer
, aFirstNewContent
)) {
6485 LAYOUT_PHASE_TEMP_EXIT();
6486 parentFrame
= GetRangeInsertionPoint(aContainer
, parentFrame
,
6487 aFirstNewContent
, nsnull
,
6488 aAllowLazyConstruction
);
6489 LAYOUT_PHASE_TEMP_REENTER();
6494 LAYOUT_PHASE_TEMP_EXIT();
6495 if (MaybeRecreateForFrameset(parentFrame
, aFirstNewContent
, nsnull
)) {
6496 LAYOUT_PHASE_TEMP_REENTER();
6499 LAYOUT_PHASE_TEMP_REENTER();
6501 if (parentFrame
->IsLeaf()) {
6502 // Nothing to do here; we shouldn't be constructing kids of leaves
6503 // Clear lazy bits so we don't try to construct again.
6504 ClearLazyBits(aFirstNewContent
, nsnull
);
6509 if (parentFrame
->IsFrameOfType(nsIFrame::eMathML
)) {
6510 LAYOUT_PHASE_TEMP_EXIT();
6511 nsresult rv
= RecreateFramesForContent(parentFrame
->GetContent(), PR_FALSE
);
6512 LAYOUT_PHASE_TEMP_REENTER();
6517 // If the frame we are manipulating is a ``special'' frame (that is, one
6518 // that's been created as a result of a block-in-inline situation) then we
6519 // need to append to the last special sibling, not to the frame itself.
6520 PRBool parentSpecial
= IsFrameSpecial(parentFrame
);
6521 if (parentSpecial
) {
6523 if (gNoisyContentUpdates
) {
6524 printf("nsCSSFrameConstructor::ContentAppended: parentFrame=");
6525 nsFrame::ListTag(stdout
, parentFrame
);
6526 printf(" is special\n");
6530 // Since we're appending, we'll walk to the last anonymous frame
6531 // that was created for the broken inline frame. But don't walk
6532 // to the trailing inline if it's empty; stop at the block.
6533 parentFrame
= GetLastSpecialSibling(parentFrame
, PR_FALSE
);
6536 // Get continuation that parents the last child. This MUST be done
6537 // before the AdjustAppendParentForAfterContent call.
6538 parentFrame
= nsLayoutUtils::GetLastContinuationWithChild(parentFrame
);
6540 // We should never get here with fieldsets, since they have multiple
6541 // insertion points.
6542 NS_ASSERTION(parentFrame
->GetType() != nsGkAtoms::fieldSetFrame
,
6543 "Unexpected parent");
6545 // Deal with possible :after generated content on the parent
6546 nsIFrame
* parentAfterFrame
;
6548 ::AdjustAppendParentForAfterContent(mPresShell
->GetPresContext(),
6549 aContainer
, parentFrame
,
6552 // Create some new frames
6553 nsFrameConstructorState
state(mPresShell
, mFixedContainingBlock
,
6554 GetAbsoluteContainingBlock(parentFrame
),
6555 GetFloatContainingBlock(parentFrame
));
6557 // See if the containing block has :first-letter style applied.
6558 PRBool haveFirstLetterStyle
= PR_FALSE
, haveFirstLineStyle
= PR_FALSE
;
6559 nsIFrame
* containingBlock
= state
.mFloatedItems
.containingBlock
;
6560 if (containingBlock
) {
6561 haveFirstLetterStyle
= HasFirstLetterStyle(containingBlock
);
6562 haveFirstLineStyle
=
6563 ShouldHaveFirstLineStyle(containingBlock
->GetContent(),
6564 containingBlock
->GetStyleContext());
6567 if (haveFirstLetterStyle
) {
6568 // Before we get going, remove the current letter frames
6569 RemoveLetterFrames(state
.mPresContext
, state
.mPresShell
,
6570 state
.mFrameManager
, containingBlock
);
6573 nsIAtom
* frameType
= parentFrame
->GetType();
6574 PRBool haveNoXBLChildren
=
6575 mDocument
->BindingManager()->GetXBLChildNodesFor(aContainer
) == nsnull
;
6576 FrameConstructionItemList items
;
6577 if (aFirstNewContent
->GetPreviousSibling() &&
6578 GetParentType(frameType
) == eTypeBlock
&&
6579 haveNoXBLChildren
) {
6580 // If there's a text node in the normal content list just before the new
6581 // items, and it has no frame, make a frame construction item for it. If it
6582 // doesn't need a frame, ConstructFramesFromItemList below won't give it
6583 // one. No need to do all this if our parent type is not block, though,
6584 // since WipeContainingBlock already handles that situation.
6586 // Because we're appending, we don't need to worry about any text
6587 // after the appended content; there can only be XBL anonymous content
6588 // (text in an XBL binding is not suppressed) or generated content
6589 // (and bare text nodes are not generated). Native anonymous content
6590 // generated by frames never participates in inline layout.
6591 AddTextItemIfNeeded(state
, parentFrame
,
6592 aFirstNewContent
->GetPreviousSibling(), items
);
6594 for (nsIContent
* child
= aFirstNewContent
;
6596 child
= child
->GetNextSibling()) {
6597 AddFrameConstructionItems(state
, child
, PR_FALSE
, parentFrame
, items
);
6600 nsIFrame
* prevSibling
= ::FindAppendPrevSibling(parentFrame
, parentAfterFrame
);
6602 // Perform special check for diddling around with the frames in
6603 // a special inline frame.
6604 // If we're appending before :after content, then we're not really
6605 // appending, so let WipeContainingBlock know that.
6606 LAYOUT_PHASE_TEMP_EXIT();
6607 if (WipeContainingBlock(state
, containingBlock
, parentFrame
, items
,
6608 PR_TRUE
, prevSibling
)) {
6609 LAYOUT_PHASE_TEMP_REENTER();
6612 LAYOUT_PHASE_TEMP_REENTER();
6614 // If the parent is a block frame, and we're not in a special case
6615 // where frames can be moved around, determine if the list is for the
6616 // start or end of the block.
6617 if (nsLayoutUtils::GetAsBlock(parentFrame
) && !haveFirstLetterStyle
&&
6618 !haveFirstLineStyle
&& !parentSpecial
) {
6619 items
.SetLineBoundaryAtStart(!prevSibling
||
6620 !prevSibling
->GetStyleDisplay()->IsInlineOutside() ||
6621 prevSibling
->GetType() == nsGkAtoms::brFrame
);
6622 // :after content can't be <br> so no need to check it
6623 items
.SetLineBoundaryAtEnd(!parentAfterFrame
||
6624 !parentAfterFrame
->GetStyleDisplay()->IsInlineOutside());
6626 // To suppress whitespace-only text frames, we have to verify that
6627 // our container's DOM child list matches its flattened tree child list.
6628 // This is guaranteed to be true if GetXBLChildNodesFor() returns null.
6629 items
.SetParentHasNoXBLChildren(haveNoXBLChildren
);
6631 nsFrameItems frameItems
;
6632 ConstructFramesFromItemList(state
, items
, parentFrame
, frameItems
);
6634 for (nsIContent
* child
= aFirstNewContent
;
6636 child
= child
->GetNextSibling()) {
6637 // Invalidate now instead of before the WipeContainingBlock call, just in
6638 // case we do wipe; in that case we don't need to do this walk at all.
6639 // XXXbz does that matter? Would it make more sense to save some virtual
6640 // GetChildAt calls instead and do this during construction of our
6641 // FrameConstructionItemList?
6642 InvalidateCanvasIfNeeded(mPresShell
, child
);
6645 // if the container is a table and a caption was appended, it needs to be put
6646 // in the outer table frame's additional child list.
6647 nsFrameItems captionItems
;
6648 if (nsGkAtoms::tableFrame
== frameType
) {
6649 // Pull out the captions. Note that we don't want to do that as we go,
6650 // because processing a single caption can add a whole bunch of things to
6651 // the frame items due to pseudoframe processing. So we'd have to pull
6652 // captions from a list anyway; might as well do that here.
6653 // XXXbz this is no longer true; we could pull captions directly out of the
6654 // FrameConstructionItemList now.
6655 PullOutCaptionFrames(frameItems
, captionItems
);
6658 if (haveFirstLineStyle
&& parentFrame
== containingBlock
) {
6659 // It's possible that some of the new frames go into a
6660 // first-line frame. Look at them and see...
6661 AppendFirstLineFrames(state
, containingBlock
->GetContent(),
6662 containingBlock
, frameItems
);
6665 // Notify the parent frame passing it the list of new frames
6666 // Append the flowed frames to the principal child list; captions
6667 // need special treatment
6668 if (captionItems
.NotEmpty()) { // append the caption to the outer table
6669 NS_ASSERTION(nsGkAtoms::tableFrame
== frameType
, "how did that happen?");
6670 nsIFrame
* outerTable
= parentFrame
->GetParent();
6672 state
.mFrameManager
->AppendFrames(outerTable
, nsGkAtoms::captionList
,
6677 if (frameItems
.NotEmpty()) { // append the in-flow kids
6678 AppendFrames(state
, parentFrame
, frameItems
, prevSibling
);
6681 // Recover first-letter frames
6682 if (haveFirstLetterStyle
) {
6683 RecoverLetterFrames(containingBlock
);
6687 if (gReallyNoisyContentUpdates
) {
6688 printf("nsCSSFrameConstructor::ContentAppended: resulting frame model:\n");
6689 parentFrame
->List(stdout
, 0);
6698 enum content_operation
6704 // Helper function to lookup the listbox body frame and send a notification
6705 // for insertion or removal of content
6707 PRBool
NotifyListBoxBody(nsPresContext
* aPresContext
,
6708 nsIContent
* aContainer
,
6710 // Only used for the removed notification
6711 nsIContent
* aOldNextSibling
,
6712 nsIDocument
* aDocument
,
6713 nsIFrame
* aChildFrame
,
6714 content_operation aOperation
)
6716 nsListBoxBodyFrame
* listBoxBodyFrame
=
6717 MaybeGetListBoxBodyFrame(aContainer
, aChild
);
6718 if (listBoxBodyFrame
) {
6719 if (aOperation
== CONTENT_REMOVED
) {
6720 // Except if we have an aChildFrame and its parent is not the right
6721 // thing, then we don't do this. Pseudo frames are so much fun....
6722 if (!aChildFrame
|| aChildFrame
->GetParent() == listBoxBodyFrame
) {
6723 listBoxBodyFrame
->OnContentRemoved(aPresContext
, aContainer
,
6724 aChildFrame
, aOldNextSibling
);
6728 listBoxBodyFrame
->OnContentInserted(aPresContext
, aChild
);
6738 nsCSSFrameConstructor::ContentInserted(nsIContent
* aContainer
,
6740 nsILayoutHistoryState
* aFrameState
,
6741 PRBool aAllowLazyConstruction
)
6743 return ContentRangeInserted(aContainer
,
6745 aChild
->GetNextSibling(),
6747 aAllowLazyConstruction
);
6750 // ContentRangeInserted handles creating frames for a range of nodes that
6751 // aren't at the end of their childlist. ContentRangeInserted isn't a real
6752 // content notification, but rather it handles regular ContentInserted calls
6753 // for a single node as well as the lazy construction of frames for a range of
6754 // nodes when called from CreateNeededFrames. For a range of nodes to be
6755 // suitable to have its frames constructed all at once they must meet the same
6756 // conditions that ContentAppended imposes (GetRangeInsertionPoint checks
6757 // these), plus more. Namely when finding the insertion prevsibling we must not
6758 // need to consult something specific to any one node in the range, so that the
6759 // insertion prevsibling would be the same for each node in the range. So we
6760 // pass the first node in the range to GetInsertionPrevSibling, and if
6761 // IsValidSibling (the only place GetInsertionPrevSibling might look at the
6762 // passed in node itself) needs to resolve style on the node we record this and
6763 // return that this range needs to be split up and inserted separately. Table
6764 // captions need extra attention as we need to determine where to insert them
6765 // in the caption list, while skipping any nodes in the range being inserted
6766 // (because when we treat the caption frames the other nodes have had their
6767 // frames constructed but not yet inserted into the frame tree).
6769 nsCSSFrameConstructor::ContentRangeInserted(nsIContent
* aContainer
,
6770 nsIContent
* aStartChild
,
6771 nsIContent
* aEndChild
,
6772 nsILayoutHistoryState
* aFrameState
,
6773 PRBool aAllowLazyConstruction
)
6775 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell
->GetPresContext(), FrameC
);
6776 NS_PRECONDITION(mUpdateCount
!= 0,
6777 "Should be in an update while creating frames");
6779 NS_PRECONDITION(aStartChild
, "must always pass a child");
6781 // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
6782 // the :empty pseudo-class?
6784 if (gNoisyContentUpdates
) {
6785 printf("nsCSSFrameConstructor::ContentRangeInserted container=%p "
6786 "start-child=%p end-child=%p lazy=%d\n",
6787 static_cast<void*>(aContainer
),
6788 static_cast<void*>(aStartChild
), static_cast<void*>(aEndChild
),
6789 aAllowLazyConstruction
);
6790 if (gReallyNoisyContentUpdates
) {
6792 aContainer
->List(stdout
,0);
6794 aStartChild
->List(stdout
, 0);
6800 nsresult rv
= NS_OK
;
6802 PRBool isSingleInsert
= (aStartChild
->GetNextSibling() == aEndChild
);
6803 NS_ASSERTION(isSingleInsert
|| !aAllowLazyConstruction
,
6804 "range insert shouldn't be lazy");
6805 NS_ASSERTION(isSingleInsert
|| aEndChild
,
6806 "range should not include all nodes after aStartChild");
6809 if (aContainer
&& IsXULListBox(aContainer
)) {
6810 if (isSingleInsert
) {
6811 if (NotifyListBoxBody(mPresShell
->GetPresContext(), aContainer
,
6812 // The insert case in NotifyListBoxBody
6813 // doesn't use "old next sibling".
6814 aStartChild
, nsnull
,
6815 mDocument
, nsnull
, CONTENT_INSERTED
)) {
6819 // We don't handle a range insert to a listbox parent, issue single
6820 // ContertInserted calls for each node inserted.
6821 LAYOUT_PHASE_TEMP_EXIT();
6822 IssueSingleInsertNofications(aContainer
, aStartChild
, aEndChild
,
6823 aAllowLazyConstruction
);
6824 LAYOUT_PHASE_TEMP_REENTER();
6830 // If we have a null parent, then this must be the document element being
6831 // inserted, or some other child of the document in the DOM (might be a PI,
6834 NS_ASSERTION(isSingleInsert
,
6835 "root node insertion should be a single insertion");
6836 Element
*docElement
= mDocument
->GetRootElement();
6838 if (aStartChild
!= docElement
) {
6839 // Not the root element; just bail out
6843 NS_PRECONDITION(nsnull
== mRootElementFrame
,
6844 "root element frame already created");
6846 // Create frames for the document element and its child elements
6847 nsIFrame
* docElementFrame
;
6848 rv
= ConstructDocElementFrame(docElement
, aFrameState
, &docElementFrame
);
6850 if (NS_SUCCEEDED(rv
) && docElementFrame
) {
6851 InvalidateCanvasIfNeeded(mPresShell
, aStartChild
);
6853 if (gReallyNoisyContentUpdates
) {
6854 printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
6856 mFixedContainingBlock
->List(stdout
, 0);
6864 // Otherwise, we've got parent content. Find its frame.
6865 nsIFrame
* parentFrame
= GetFrameFor(aContainer
);
6869 if (aAllowLazyConstruction
&&
6870 MaybeConstructLazily(CONTENTINSERT
, aContainer
, aStartChild
)) {
6874 if (isSingleInsert
) {
6875 // See if we have an XBL insertion point. If so, then that's our
6876 // real parent frame; if not, then the frame hasn't been built yet
6877 // and we just bail.
6878 nsIFrame
* insertionPoint
;
6879 GetInsertionPoint(parentFrame
, aStartChild
, &insertionPoint
);
6880 if (! insertionPoint
)
6881 return NS_OK
; // Don't build the frames.
6883 parentFrame
= insertionPoint
;
6885 // Get our insertion point. If we need to issue single ContentInserted's
6886 // GetRangeInsertionPoint will take care of that for us.
6887 LAYOUT_PHASE_TEMP_EXIT();
6888 parentFrame
= GetRangeInsertionPoint(aContainer
, parentFrame
,
6889 aStartChild
, aEndChild
,
6890 aAllowLazyConstruction
);
6891 LAYOUT_PHASE_TEMP_REENTER();
6897 PRBool isAppend
, isRangeInsertSafe
;
6898 nsIFrame
* prevSibling
=
6899 GetInsertionPrevSibling(parentFrame
, aContainer
, aStartChild
,
6900 &isAppend
, &isRangeInsertSafe
);
6902 // check if range insert is safe
6903 if (!isSingleInsert
&& !isRangeInsertSafe
) {
6904 // must fall back to a single ContertInserted for each child in the range
6905 LAYOUT_PHASE_TEMP_EXIT();
6906 IssueSingleInsertNofications(aContainer
, aStartChild
, aEndChild
,
6907 aAllowLazyConstruction
);
6908 LAYOUT_PHASE_TEMP_REENTER();
6912 nsIContent
* container
= parentFrame
->GetContent();
6914 nsIAtom
* frameType
= parentFrame
->GetType();
6915 LAYOUT_PHASE_TEMP_EXIT();
6916 if (MaybeRecreateForFrameset(parentFrame
, aStartChild
, aEndChild
)) {
6917 LAYOUT_PHASE_TEMP_REENTER();
6920 LAYOUT_PHASE_TEMP_REENTER();
6922 // We should only get here with fieldsets when doing a single insert, because
6923 // fieldsets have multiple insertion points.
6924 NS_ASSERTION(isSingleInsert
|| frameType
!= nsGkAtoms::fieldSetFrame
,
6925 "Unexpected parent");
6926 if (frameType
== nsGkAtoms::fieldSetFrame
&&
6927 aStartChild
->Tag() == nsGkAtoms::legend
) {
6928 // Just reframe the parent, since figuring out whether this
6929 // should be the new legend and then handling it is too complex.
6930 // We could do a little better here --- check if the fieldset already
6931 // has a legend which occurs earlier in its child list than this node,
6932 // and if so, proceed. But we'd have to extend nsFieldSetFrame
6933 // to locate this legend in the inserted frames and extract it.
6934 LAYOUT_PHASE_TEMP_EXIT();
6935 nsresult rv
= RecreateFramesForContent(parentFrame
->GetContent(), PR_FALSE
);
6936 LAYOUT_PHASE_TEMP_REENTER();
6940 // Don't construct kids of leaves
6941 if (parentFrame
->IsLeaf()) {
6942 // Clear lazy bits so we don't try to construct again.
6943 ClearLazyBits(aStartChild
, aEndChild
);
6948 if (parentFrame
->IsFrameOfType(nsIFrame::eMathML
)) {
6949 LAYOUT_PHASE_TEMP_EXIT();
6950 nsresult rv
= RecreateFramesForContent(parentFrame
->GetContent(), PR_FALSE
);
6951 LAYOUT_PHASE_TEMP_REENTER();
6956 nsFrameConstructorState
state(mPresShell
, mFixedContainingBlock
,
6957 GetAbsoluteContainingBlock(parentFrame
),
6958 GetFloatContainingBlock(parentFrame
),
6962 // Recover state for the containing block - we need to know if
6963 // it has :first-letter or :first-line style applied to it. The
6964 // reason we care is that the internal structure in these cases
6965 // is not the normal structure and requires custom updating
6967 nsIFrame
* containingBlock
= state
.mFloatedItems
.containingBlock
;
6968 PRBool haveFirstLetterStyle
= PR_FALSE
;
6969 PRBool haveFirstLineStyle
= PR_FALSE
;
6971 // In order to shave off some cycles, we only dig up the
6972 // containing block haveFirst* flags if the parent frame where
6973 // the insertion/append is occurring is an inline or block
6974 // container. For other types of containers this isn't relevant.
6975 const nsStyleDisplay
* parentDisplay
= parentFrame
->GetStyleDisplay();
6977 // Examine the parentFrame where the insertion is taking
6978 // place. If it's a certain kind of container then some special
6979 // processing is done.
6980 if ((NS_STYLE_DISPLAY_BLOCK
== parentDisplay
->mDisplay
) ||
6981 (NS_STYLE_DISPLAY_LIST_ITEM
== parentDisplay
->mDisplay
) ||
6982 (NS_STYLE_DISPLAY_INLINE
== parentDisplay
->mDisplay
) ||
6983 (NS_STYLE_DISPLAY_INLINE_BLOCK
== parentDisplay
->mDisplay
)) {
6984 // Recover the special style flags for the containing block
6985 if (containingBlock
) {
6986 haveFirstLetterStyle
= HasFirstLetterStyle(containingBlock
);
6987 haveFirstLineStyle
=
6988 ShouldHaveFirstLineStyle(containingBlock
->GetContent(),
6989 containingBlock
->GetStyleContext());
6992 if (haveFirstLetterStyle
) {
6993 // If our current parentFrame is a Letter frame, use its parent as our
6995 if (parentFrame
->GetType() == nsGkAtoms::letterFrame
) {
6996 // If parentFrame is out of flow, then we actually want the parent of
6997 // the placeholder frame.
6998 if (parentFrame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
6999 nsPlaceholderFrame
* placeholderFrame
=
7000 state
.mFrameManager
->GetPlaceholderFrameFor(parentFrame
);
7001 NS_ASSERTION(placeholderFrame
, "No placeholder for out-of-flow?");
7002 parentFrame
= placeholderFrame
->GetParent();
7004 parentFrame
= parentFrame
->GetParent();
7008 // Remove the old letter frames before doing the insertion
7009 RemoveLetterFrames(state
.mPresContext
, mPresShell
,
7010 state
.mFrameManager
,
7011 state
.mFloatedItems
.containingBlock
);
7013 // Removing the letterframes messes around with the frame tree, removing
7014 // and creating frames. We need to reget our prevsibling, parent frame,
7016 prevSibling
= GetInsertionPrevSibling(parentFrame
, aContainer
,
7017 aStartChild
, &isAppend
,
7018 &isRangeInsertSafe
);
7020 // Need check whether a range insert is still safe.
7021 if (!isSingleInsert
&& !isRangeInsertSafe
) {
7022 // Need to recover the letter frames first.
7023 RecoverLetterFrames(state
.mFloatedItems
.containingBlock
);
7025 // must fall back to a single ContertInserted for each child in the range
7026 LAYOUT_PHASE_TEMP_EXIT();
7027 IssueSingleInsertNofications(aContainer
, aStartChild
, aEndChild
,
7028 aAllowLazyConstruction
);
7029 LAYOUT_PHASE_TEMP_REENTER();
7033 container
= parentFrame
->GetContent();
7034 frameType
= parentFrame
->GetType();
7039 // We're inserting the new frames as the first child. See if the
7040 // parent has a :before pseudo-element
7041 nsIFrame
* firstChild
= parentFrame
->GetFirstChild(nsnull
);
7044 nsLayoutUtils::IsGeneratedContentFor(container
, firstChild
,
7045 nsCSSPseudoElements::before
)) {
7046 // Insert the new frames after the last continuation of the :before
7047 prevSibling
= firstChild
->GetTailContinuation();
7048 parentFrame
= prevSibling
->GetParent()->GetContentInsertionFrame();
7049 // Don't change isAppend here; we'll can call AppendFrames as needed, and
7050 // the change to our prevSibling doesn't affect that.
7054 FrameConstructionItemList items
;
7055 ParentType parentType
= GetParentType(frameType
);
7056 PRBool haveNoXBLChildren
=
7057 mDocument
->BindingManager()->GetXBLChildNodesFor(aContainer
) == nsnull
;
7058 if (aStartChild
->GetPreviousSibling() &&
7059 parentType
== eTypeBlock
&& haveNoXBLChildren
) {
7060 // If there's a text node in the normal content list just before the
7061 // new nodes, and it has no frame, make a frame construction item for
7062 // it, because it might need a frame now. No need to do this if our
7063 // parent type is not block, though, since WipeContainingBlock
7064 // already handles that sitation.
7065 AddTextItemIfNeeded(state
, parentFrame
, aStartChild
->GetPreviousSibling(),
7069 if (isSingleInsert
) {
7070 AddFrameConstructionItems(state
, aStartChild
,
7071 aStartChild
->IsRootOfAnonymousSubtree(),
7072 parentFrame
, items
);
7074 for (nsIContent
* child
= aStartChild
;
7076 child
= child
->GetNextSibling()){
7077 AddFrameConstructionItems(state
, child
, PR_FALSE
, parentFrame
, items
);
7081 if (aEndChild
&& parentType
== eTypeBlock
&& haveNoXBLChildren
) {
7082 // If there's a text node in the normal content list just after the
7083 // new nodes, and it has no frame, make a frame construction item for
7084 // it, because it might need a frame now. No need to do this if our
7085 // parent type is not block, though, since WipeContainingBlock
7086 // already handles that sitation.
7087 AddTextItemIfNeeded(state
, parentFrame
, aEndChild
, items
);
7090 // Perform special check for diddling around with the frames in
7091 // a special inline frame.
7092 // If we're appending before :after content, then we're not really
7093 // appending, so let WipeContainingBlock know that.
7094 LAYOUT_PHASE_TEMP_EXIT();
7095 if (WipeContainingBlock(state
, containingBlock
, parentFrame
, items
,
7096 isAppend
, prevSibling
)) {
7097 LAYOUT_PHASE_TEMP_REENTER();
7100 LAYOUT_PHASE_TEMP_REENTER();
7102 // If the container is a table and a caption will be appended, it needs to be
7103 // put in the outer table frame's additional child list.
7104 // We make no attempt here to set flags to indicate whether the list
7105 // will be at the start or end of a block. It doesn't seem worthwhile.
7106 nsFrameItems frameItems
, captionItems
;
7107 ConstructFramesFromItemList(state
, items
, parentFrame
, frameItems
);
7109 if (frameItems
.NotEmpty()) {
7110 for (nsIContent
* child
= aStartChild
;
7112 child
= child
->GetNextSibling()){
7113 InvalidateCanvasIfNeeded(mPresShell
, child
);
7116 if (nsGkAtoms::tableFrame
== frameType
||
7117 nsGkAtoms::tableOuterFrame
== frameType
) {
7118 PullOutCaptionFrames(frameItems
, captionItems
);
7122 // If the parent of our current prevSibling is different from the frame we'll
7123 // actually use as the parent, then the calculated insertion point is now
7124 // invalid and as it is unknown where to insert correctly we append instead
7126 // This can affect our prevSibling and isAppend, but should not have any
7127 // effect on the WipeContainingBlock above, since this should only happen
7128 // when neither parent is a special frame and should not affect whitespace
7129 // handling inside table-related frames (and in fact, can only happen when
7130 // one of the parents is an outer table and one is an inner table or when the
7131 // parent is a fieldset or fieldset content frame). So it won't affect the
7132 // {ib} or XUL box cases in WipeContainingBlock(), and the table pseudo
7133 // handling will only be affected by us maybe thinking we're not inserting
7134 // at the beginning, whereas we really are. That would have made us reframe
7135 // unnecessarily, but that's ok.
7136 // XXXbz we should push our frame construction item code up higher, so we
7137 // know what our items are by the time we start figuring out previous
7139 if (prevSibling
&& frameItems
.NotEmpty() &&
7140 frameItems
.FirstChild()->GetParent() != prevSibling
->GetParent()) {
7142 nsIFrame
* frame1
= frameItems
.FirstChild()->GetParent();
7143 nsIFrame
* frame2
= prevSibling
->GetParent();
7144 NS_ASSERTION(!IsFrameSpecial(frame1
) && !IsFrameSpecial(frame2
),
7145 "Neither should be special");
7146 NS_ASSERTION((frame1
->GetType() == nsGkAtoms::tableFrame
&&
7147 frame2
->GetType() == nsGkAtoms::tableOuterFrame
) ||
7148 (frame1
->GetType() == nsGkAtoms::tableOuterFrame
&&
7149 frame2
->GetType() == nsGkAtoms::tableFrame
) ||
7150 frame1
->GetType() == nsGkAtoms::fieldSetFrame
||
7151 (frame1
->GetParent() &&
7152 frame1
->GetParent()->GetType() == nsGkAtoms::fieldSetFrame
),
7153 "Unexpected frame types");
7156 nsIFrame
* appendAfterFrame
;
7158 ::AdjustAppendParentForAfterContent(mPresShell
->GetPresContext(),
7160 frameItems
.FirstChild()->GetParent(),
7162 prevSibling
= ::FindAppendPrevSibling(parentFrame
, appendAfterFrame
);
7165 if (haveFirstLineStyle
&& parentFrame
== containingBlock
) {
7166 // It's possible that the new frame goes into a first-line
7167 // frame. Look at it and see...
7169 // Use append logic when appending
7170 AppendFirstLineFrames(state
, containingBlock
->GetContent(),
7171 containingBlock
, frameItems
);
7174 // Use more complicated insert logic when inserting
7175 // XXXbz this method is a no-op, so it's easy for the args being passed
7176 // here to make no sense without anyone noticing... If it ever stops
7177 // being a no-op, vet them carefully!
7178 InsertFirstLineFrames(state
, container
, containingBlock
, &parentFrame
,
7179 prevSibling
, frameItems
);
7183 // We might have captions; put them into the caption list of the
7184 // outer table frame.
7185 if (captionItems
.NotEmpty()) {
7186 NS_ASSERTION(nsGkAtoms::tableFrame
== frameType
||
7187 nsGkAtoms::tableOuterFrame
== frameType
,
7188 "parent for caption is not table?");
7189 // We need to determine where to put the caption items; start with the
7190 // the parent frame that has already been determined and get the insertion
7191 // prevsibling of the first caption item.
7192 nsIFrame
* captionParent
= parentFrame
;
7193 PRBool captionIsAppend
;
7194 nsIFrame
* captionPrevSibling
= nsnull
;
7196 // aIsRangeInsertSafe is ignored on purpose because it is irrelevant here.
7198 if (isSingleInsert
) {
7199 captionPrevSibling
=
7200 GetInsertionPrevSibling(captionParent
, aContainer
, aStartChild
,
7201 &captionIsAppend
, &ignored
);
7203 nsIContent
* firstCaption
= captionItems
.FirstChild()->GetContent();
7204 // It is very important here that we skip the children in
7205 // [aStartChild,aEndChild) when looking for a
7207 captionPrevSibling
=
7208 GetInsertionPrevSibling(captionParent
, aContainer
, firstCaption
,
7209 &captionIsAppend
, &ignored
,
7210 aStartChild
, aEndChild
);
7213 nsIFrame
* outerTable
= nsnull
;
7214 if (GetCaptionAdjustedParent(captionParent
, captionItems
.FirstChild(),
7216 // If the parent is not an outer table frame we will try to add frames
7217 // to a named child list that the parent does not honour and the frames
7219 NS_ASSERTION(nsGkAtoms::tableOuterFrame
== outerTable
->GetType(),
7220 "Pseudo frame construction failure; "
7221 "a caption can be only a child of an outer table frame");
7223 // If the parent of our current prevSibling is different from the frame
7224 // we'll actually use as the parent, then the calculated insertion
7225 // point is now invalid (bug 341382).
7226 if (captionPrevSibling
&&
7227 captionPrevSibling
->GetParent() != outerTable
) {
7228 captionPrevSibling
= nsnull
;
7230 if (captionIsAppend
) {
7231 state
.mFrameManager
->AppendFrames(outerTable
, nsGkAtoms::captionList
,
7234 state
.mFrameManager
->InsertFrames(outerTable
, nsGkAtoms::captionList
,
7235 captionPrevSibling
, captionItems
);
7240 if (frameItems
.NotEmpty()) {
7241 // Notify the parent frame
7243 AppendFrames(state
, parentFrame
, frameItems
, prevSibling
);
7245 state
.mFrameManager
->InsertFrames(parentFrame
, nsnull
, prevSibling
,
7250 if (haveFirstLetterStyle
) {
7251 // Recover the letter frames for the containing block when
7252 // it has first-letter style.
7253 RecoverLetterFrames(state
.mFloatedItems
.containingBlock
);
7257 if (gReallyNoisyContentUpdates
&& parentFrame
) {
7258 printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame model:\n");
7259 parentFrame
->List(stdout
, 0);
7267 nsCSSFrameConstructor::ContentRemoved(nsIContent
* aContainer
,
7269 nsIContent
* aOldNextSibling
,
7271 PRBool
* aDidReconstruct
)
7273 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell
->GetPresContext(), FrameC
);
7274 NS_PRECONDITION(mUpdateCount
!= 0,
7275 "Should be in an update while destroying frames");
7277 *aDidReconstruct
= PR_FALSE
;
7279 // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
7280 // the :empty pseudo-class?
7283 if (gNoisyContentUpdates
) {
7284 printf("nsCSSFrameConstructor::ContentRemoved container=%p child=%p "
7285 "old-next-sibling=%p\n",
7286 static_cast<void*>(aContainer
),
7287 static_cast<void*>(aChild
),
7288 static_cast<void*>(aOldNextSibling
));
7289 if (gReallyNoisyContentUpdates
) {
7290 aContainer
->List(stdout
, 0);
7295 nsFrameManager
*frameManager
= mPresShell
->FrameManager();
7296 nsPresContext
*presContext
= mPresShell
->GetPresContext();
7297 nsresult rv
= NS_OK
;
7299 // Find the child frame that maps the content
7300 nsIFrame
* childFrame
= aChild
->GetPrimaryFrame();
7302 if (!childFrame
|| childFrame
->GetContent() != aChild
) {
7303 // XXXbz the GetContent() != aChild check is needed due to bug 135040.
7304 // Remove it once that's fixed.
7305 frameManager
->ClearUndisplayedContentIn(aChild
, aContainer
);
7309 if (NotifyListBoxBody(presContext
, aContainer
, aChild
, aOldNextSibling
,
7310 mDocument
, childFrame
, CONTENT_REMOVED
))
7315 // If we're removing the root, then make sure to remove things starting at
7316 // the viewport's child instead of the primary frame (which might even be
7317 // null if the root had an XBL binding or display:none, even though the
7318 // frames above it got created). We do the adjustment after the childFrame
7319 // check above, because we do want to clear any undisplayed content we might
7320 // have for the root. Detecting removal of a root is a little exciting; in
7321 // particular, having a null aContainer is necessary but NOT sufficient. Due
7322 // to how we process reframes, the content node might not even be in our
7323 // document by now. So explicitly check whether the viewport's first kid's
7324 // content node is aChild.
7325 PRBool isRoot
= PR_FALSE
;
7327 nsIFrame
* viewport
= frameManager
->GetRootFrame();
7329 nsIFrame
* firstChild
= viewport
->GetFirstChild(nsnull
);
7330 if (firstChild
&& firstChild
->GetContent() == aChild
) {
7332 childFrame
= firstChild
;
7333 NS_ASSERTION(!childFrame
->GetNextSibling(), "How did that happen?");
7339 InvalidateCanvasIfNeeded(mPresShell
, aChild
);
7341 // See whether we need to remove more than just childFrame
7342 LAYOUT_PHASE_TEMP_EXIT();
7343 if (MaybeRecreateContainerForFrameRemoval(childFrame
, &rv
)) {
7344 LAYOUT_PHASE_TEMP_REENTER();
7345 *aDidReconstruct
= PR_TRUE
;
7348 LAYOUT_PHASE_TEMP_REENTER();
7350 // Get the childFrame's parent frame
7351 nsIFrame
* parentFrame
= childFrame
->GetParent();
7352 nsIAtom
* parentType
= parentFrame
->GetType();
7354 if (parentType
== nsGkAtoms::frameSetFrame
&&
7355 IsSpecialFramesetChild(aChild
)) {
7356 // Just reframe the parent, since framesets are weird like that.
7357 *aDidReconstruct
= PR_TRUE
;
7358 LAYOUT_PHASE_TEMP_EXIT();
7359 nsresult rv
= RecreateFramesForContent(parentFrame
->GetContent(), PR_FALSE
);
7360 LAYOUT_PHASE_TEMP_REENTER();
7365 // If we're a child of MathML, then we should reframe the MathML content.
7366 // If we're non-MathML, then we would be wrapped in a block so we need to
7367 // check our grandparent in that case.
7368 nsIFrame
* possibleMathMLAncestor
= parentType
== nsGkAtoms::blockFrame
?
7369 parentFrame
->GetParent() : parentFrame
;
7370 if (possibleMathMLAncestor
->IsFrameOfType(nsIFrame::eMathML
)) {
7371 *aDidReconstruct
= PR_TRUE
;
7372 LAYOUT_PHASE_TEMP_EXIT();
7373 nsresult rv
= RecreateFramesForContent(possibleMathMLAncestor
->GetContent(), PR_FALSE
);
7374 LAYOUT_PHASE_TEMP_REENTER();
7379 // Undo XUL wrapping if it's no longer needed.
7380 // (If we're in the XUL block-wrapping situation, parentFrame is the
7382 nsIFrame
* grandparentFrame
= parentFrame
->GetParent();
7383 if (grandparentFrame
&& grandparentFrame
->IsBoxFrame() &&
7384 (grandparentFrame
->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK
) &&
7385 // check if this frame is the only one needing wrapping
7386 aChild
== AnyKidsNeedBlockParent(parentFrame
->GetFirstChild(nsnull
)) &&
7387 !AnyKidsNeedBlockParent(childFrame
->GetNextSibling())) {
7388 *aDidReconstruct
= PR_TRUE
;
7389 LAYOUT_PHASE_TEMP_EXIT();
7390 nsresult rv
= RecreateFramesForContent(grandparentFrame
->GetContent(), PR_TRUE
);
7391 LAYOUT_PHASE_TEMP_REENTER();
7395 // Examine the containing-block for the removed content and see if
7396 // :first-letter style applies.
7397 nsIFrame
* inflowChild
= childFrame
;
7398 if (childFrame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
7399 inflowChild
= frameManager
->GetPlaceholderFrameFor(childFrame
);
7400 NS_ASSERTION(inflowChild
, "No placeholder for out-of-flow?");
7402 nsIFrame
* containingBlock
=
7403 GetFloatContainingBlock(inflowChild
->GetParent());
7404 PRBool haveFLS
= containingBlock
&& HasFirstLetterStyle(containingBlock
);
7406 // Trap out to special routine that handles adjusting a blocks
7407 // frame tree when first-letter style is present.
7408 #ifdef NOISY_FIRST_LETTER
7409 printf("ContentRemoved: containingBlock=");
7410 nsFrame::ListTag(stdout
, containingBlock
);
7411 printf(" parentFrame=");
7412 nsFrame::ListTag(stdout
, parentFrame
);
7413 printf(" childFrame=");
7414 nsFrame::ListTag(stdout
, childFrame
);
7418 // First update the containing blocks structure by removing the
7419 // existing letter frames. This makes the subsequent logic
7421 RemoveLetterFrames(presContext
, mPresShell
, frameManager
,
7424 // Recover childFrame and parentFrame
7425 childFrame
= aChild
->GetPrimaryFrame();
7426 if (!childFrame
|| childFrame
->GetContent() != aChild
) {
7427 // XXXbz the GetContent() != aChild check is needed due to bug 135040.
7428 // Remove it once that's fixed.
7429 frameManager
->ClearUndisplayedContentIn(aChild
, aContainer
);
7432 parentFrame
= childFrame
->GetParent();
7433 parentType
= parentFrame
->GetType();
7435 #ifdef NOISY_FIRST_LETTER
7436 printf(" ==> revised parentFrame=");
7437 nsFrame::ListTag(stdout
, parentFrame
);
7438 printf(" childFrame=");
7439 nsFrame::ListTag(stdout
, childFrame
);
7445 if (gReallyNoisyContentUpdates
) {
7446 printf("nsCSSFrameConstructor::ContentRemoved: childFrame=");
7447 nsFrame::ListTag(stdout
, childFrame
);
7449 parentFrame
->List(stdout
, 0);
7454 // Notify the parent frame that it should delete the frame
7455 if (childFrame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
7456 childFrame
= frameManager
->GetPlaceholderFrameFor(childFrame
);
7457 NS_ASSERTION(childFrame
, "Missing placeholder frame for out of flow.");
7458 parentFrame
= childFrame
->GetParent();
7460 rv
= frameManager
->RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame
),
7462 //XXXfr NS_ENSURE_SUCCESS(rv, rv) ?
7465 mRootElementFrame
= nsnull
;
7466 mRootElementStyleFrame
= nsnull
;
7467 mDocElementContainingBlock
= nsnull
;
7468 mPageSequenceFrame
= nsnull
;
7469 mGfxScrollFrame
= nsnull
;
7470 mHasRootAbsPosContainingBlock
= PR_FALSE
;
7471 mFixedContainingBlock
= frameManager
->GetRootFrame();
7474 if (haveFLS
&& mRootElementFrame
) {
7475 RecoverLetterFrames(containingBlock
);
7478 // If we're just reconstructing frames for the element, then the
7479 // following ContentInserted notification on the element will
7480 // take care of fixing up any adjacent text nodes. We don't need
7481 // to do this if the table parent type of our parent type is not
7482 // eTypeBlock, though, because in that case the whitespace isn't
7483 // being suppressed due to us anyway.
7484 if (aContainer
&& !aChild
->IsRootOfAnonymousSubtree() &&
7485 aFlags
!= REMOVE_FOR_RECONSTRUCTION
&&
7486 GetParentType(parentType
) == eTypeBlock
) {
7487 // Adjacent whitespace-only text nodes might have been suppressed if
7488 // this node does not have inline ends. Create frames for them now
7490 // Reframe any text node just before the node being removed, if there is
7491 // one, and if it's not the last child or the first child. If a whitespace
7492 // textframe was being suppressed and it's now the last child or first
7493 // child then it can stay suppressed since the parent must be a block
7494 // and hence it's adjacent to a block end.
7495 // If aOldNextSibling is null, then the text node before the node being
7496 // removed is the last node, and we don't need to worry about it.
7497 if (aOldNextSibling
) {
7498 nsIContent
* prevSibling
= aOldNextSibling
->GetPreviousSibling();
7499 if (prevSibling
&& prevSibling
->GetPreviousSibling()) {
7500 LAYOUT_PHASE_TEMP_EXIT();
7501 ReframeTextIfNeeded(aContainer
, prevSibling
);
7502 LAYOUT_PHASE_TEMP_REENTER();
7505 // Reframe any text node just after the node being removed, if there is
7506 // one, and if it's not the last child or the first child.
7507 if (aOldNextSibling
&& aOldNextSibling
->GetNextSibling() &&
7508 aOldNextSibling
->GetPreviousSibling()) {
7509 LAYOUT_PHASE_TEMP_EXIT();
7510 ReframeTextIfNeeded(aContainer
, aOldNextSibling
);
7511 LAYOUT_PHASE_TEMP_REENTER();
7516 if (gReallyNoisyContentUpdates
&& parentFrame
) {
7517 printf("nsCSSFrameConstructor::ContentRemoved: resulting frame model:\n");
7518 parentFrame
->List(stdout
, 0);
7527 // To ensure that the functions below are only called within
7528 // |ApplyRenderingChangeToTree|.
7529 static PRBool gInApplyRenderingChangeToTree
= PR_FALSE
;
7533 DoApplyRenderingChangeToTree(nsIFrame
* aFrame
,
7534 nsIViewManager
* aViewManager
,
7535 nsFrameManager
* aFrameManager
,
7536 nsChangeHint aChange
);
7539 * @param aBoundsRect returns the bounds enclosing the areas covered by aFrame and its childre
7540 * This rect is relative to aFrame's parent
7543 UpdateViewsForTree(nsIFrame
* aFrame
, nsIViewManager
* aViewManager
,
7544 nsFrameManager
* aFrameManager
,
7545 nsChangeHint aChange
)
7547 NS_PRECONDITION(gInApplyRenderingChangeToTree
,
7548 "should only be called within ApplyRenderingChangeToTree");
7550 nsIView
* view
= aFrame
->GetView();
7552 if (aChange
& nsChangeHint_SyncFrameView
) {
7553 nsContainerFrame::SyncFrameViewProperties(aFrame
->PresContext(),
7554 aFrame
, nsnull
, view
);
7558 // now do children of frame
7559 PRInt32 listIndex
= 0;
7560 nsIAtom
* childList
= nsnull
;
7563 nsIFrame
* child
= aFrame
->GetFirstChild(childList
);
7565 if (!(child
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)
7566 || (child
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
7567 // only do frames that don't have placeholders
7568 if (nsGkAtoms::placeholderFrame
== child
->GetType()) {
7569 // do the out-of-flow frame and its continuations
7570 nsIFrame
* outOfFlowFrame
=
7571 nsPlaceholderFrame::GetRealFrameForPlaceholder(child
);
7573 DoApplyRenderingChangeToTree(outOfFlowFrame
, aViewManager
,
7574 aFrameManager
, aChange
);
7575 } while (outOfFlowFrame
= outOfFlowFrame
->GetNextContinuation());
7576 } else if (childList
== nsGkAtoms::popupList
) {
7577 DoApplyRenderingChangeToTree(child
, aViewManager
,
7578 aFrameManager
, aChange
);
7579 } else { // regular frame
7580 if ((child
->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER
) &&
7581 (aChange
& nsChangeHint_RepaintFrame
)) {
7582 FrameLayerBuilder::InvalidateThebesLayerContents(child
,
7583 child
->GetOverflowRectRelativeToSelf());
7585 UpdateViewsForTree(child
, aViewManager
, aFrameManager
, aChange
);
7588 child
= child
->GetNextSibling();
7590 childList
= aFrame
->GetAdditionalChildListName(listIndex
++);
7591 } while (childList
);
7595 DoApplyRenderingChangeToTree(nsIFrame
* aFrame
,
7596 nsIViewManager
* aViewManager
,
7597 nsFrameManager
* aFrameManager
,
7598 nsChangeHint aChange
)
7600 NS_PRECONDITION(gInApplyRenderingChangeToTree
,
7601 "should only be called within ApplyRenderingChangeToTree");
7603 for ( ; aFrame
; aFrame
= nsLayoutUtils::GetNextContinuationOrSpecialSibling(aFrame
)) {
7604 // Get view if this frame has one and trigger an update. If the
7605 // frame doesn't have a view, find the nearest containing view
7606 // (adjusting r's coordinate system to reflect the nesting) and
7608 UpdateViewsForTree(aFrame
, aViewManager
, aFrameManager
, aChange
);
7610 // if frame has view, will already be invalidated
7611 if (aChange
& nsChangeHint_RepaintFrame
) {
7612 if (aFrame
->IsFrameOfType(nsIFrame::eSVG
)) {
7614 if (!(aFrame
->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD
)) {
7615 nsSVGOuterSVGFrame
*outerSVGFrame
= nsSVGUtils::GetOuterSVGFrame(aFrame
);
7616 if (outerSVGFrame
) {
7617 // We need this to invalidate frames when their 'filter' or 'marker'
7618 // property changes. XXX in theory changes to 'marker' should be
7619 // handled in nsSVGPathGeometryFrame::DidSetStyleContext, but for
7620 // some reason that's broken.
7622 // This call is also currently the only mechanism for invalidating
7623 // the area covered by a <foreignObject> when 'opacity' changes on
7624 // it or one of its ancestors. (For 'opacity' changes on <image> or
7625 // a graphical element such as <path>, or on one of their
7626 // ancestors, this is redundant since
7627 // nsSVGPathGeometryFrame::DidSetStyleContext also invalidates.)
7628 outerSVGFrame
->UpdateAndInvalidateCoveredRegion(aFrame
);
7633 aFrame
->InvalidateOverflowRect();
7636 if (aChange
& nsChangeHint_UpdateOpacityLayer
) {
7637 aFrame
->MarkLayersActive();
7638 aFrame
->InvalidateLayer(aFrame
->GetOverflowRectRelativeToSelf(),
7639 nsDisplayItem::TYPE_OPACITY
);
7642 if (aChange
& nsChangeHint_UpdateTransformLayer
) {
7643 aFrame
->MarkLayersActive();
7644 aFrame
->InvalidateLayer(aFrame
->GetOverflowRectRelativeToSelf(),
7645 nsDisplayItem::TYPE_TRANSFORM
);
7651 ApplyRenderingChangeToTree(nsPresContext
* aPresContext
,
7653 nsChangeHint aChange
)
7655 nsIPresShell
*shell
= aPresContext
->PresShell();
7656 if (shell
->IsPaintingSuppressed()) {
7657 // Don't allow synchronous rendering changes when painting is turned off.
7658 aChange
= NS_SubtractHint(aChange
, nsChangeHint_RepaintFrame
);
7664 // If the frame's background is propagated to an ancestor, walk up to
7666 nsStyleContext
*bgSC
;
7667 while (!nsCSSRendering::FindBackground(aPresContext
, aFrame
, &bgSC
)) {
7668 aFrame
= aFrame
->GetParent();
7669 NS_ASSERTION(aFrame
, "root frame must paint");
7672 nsIViewManager
* viewManager
= shell
->GetViewManager();
7674 // Trigger rendering updates by damaging this frame and any
7675 // continuations of this frame.
7677 // XXX this needs to detect the need for a view due to an opacity change and deal with it...
7679 nsIViewManager::UpdateViewBatch
batch(viewManager
);
7682 gInApplyRenderingChangeToTree
= PR_TRUE
;
7684 DoApplyRenderingChangeToTree(aFrame
, viewManager
, shell
->FrameManager(),
7687 gInApplyRenderingChangeToTree
= PR_FALSE
;
7690 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
7694 * This method invalidates the canvas when frames are removed or added for a
7695 * node that might have its background propagated to the canvas, i.e., a
7696 * document root node or an HTML BODY which is a child of the root node.
7698 * @param aFrame a frame for a content node about to be removed or a frame that
7699 * was just created for a content node that was inserted.
7702 InvalidateCanvasIfNeeded(nsIPresShell
* presShell
, nsIContent
* node
)
7704 NS_PRECONDITION(presShell
->GetRootFrame(), "What happened here?");
7705 NS_PRECONDITION(presShell
->GetPresContext(), "Say what?");
7707 // Note that both in ContentRemoved and ContentInserted the content node
7708 // will still have the right parent pointer, so looking at that is ok.
7710 nsIContent
* parent
= node
->GetParent();
7712 // Has a parent; might not be what we want
7713 nsIContent
* grandParent
= parent
->GetParent();
7715 // Has a grandparent, so not what we want
7719 // Check whether it's an HTML body
7720 if (node
->Tag() != nsGkAtoms::body
||
7726 // At this point the node has no parent or it's an HTML <body> child of the
7727 // root. We might not need to invalidate in this case (eg we might be in
7728 // XHTML or something), but chances are we want to. Play it safe.
7729 // Invalidate the viewport.
7731 // Wrap this in a DEFERRED view update batch so we don't try to
7732 // flush out layout here
7734 nsIViewManager::UpdateViewBatch
batch(presShell
->GetViewManager());
7735 nsIFrame
* rootFrame
= presShell
->GetRootFrame();
7736 rootFrame
->InvalidateFrameSubtree();
7737 batch
.EndUpdateViewBatch(NS_VMREFRESH_DEFERRED
);
7741 nsCSSFrameConstructor::StyleChangeReflow(nsIFrame
* aFrame
,
7744 // If the frame hasn't even received an initial reflow, then don't
7745 // send it a style-change reflow!
7746 if (aFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
)
7750 if (gNoisyContentUpdates
) {
7751 printf("nsCSSFrameConstructor::StyleChangeReflow: aFrame=");
7752 nsFrame::ListTag(stdout
, aFrame
);
7757 nsIPresShell::IntrinsicDirty dirtyType
;
7758 if (aHint
& nsChangeHint_ClearDescendantIntrinsics
) {
7759 NS_ASSERTION(aHint
& nsChangeHint_ClearAncestorIntrinsics
,
7760 "Please read the comments in nsChangeHint.h");
7761 dirtyType
= nsIPresShell::eStyleChange
;
7762 } else if (aHint
& nsChangeHint_ClearAncestorIntrinsics
) {
7763 dirtyType
= nsIPresShell::eTreeChange
;
7765 dirtyType
= nsIPresShell::eResize
;
7768 nsFrameState dirtyBits
;
7769 if (aHint
& nsChangeHint_NeedDirtyReflow
) {
7770 dirtyBits
= NS_FRAME_IS_DIRTY
;
7772 dirtyBits
= NS_FRAME_HAS_DIRTY_CHILDREN
;
7776 mPresShell
->FrameNeedsReflow(aFrame
, dirtyType
, dirtyBits
);
7777 aFrame
= nsLayoutUtils::GetNextContinuationOrSpecialSibling(aFrame
);
7784 nsCSSFrameConstructor::CharacterDataChanged(nsIContent
* aContent
,
7785 CharacterDataChangeInfo
* aInfo
)
7787 AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell
->GetPresContext(), FrameC
);
7788 nsresult rv
= NS_OK
;
7790 if ((aContent
->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE
) &&
7791 !aContent
->TextIsOnlyWhitespace()) ||
7792 (aContent
->HasFlag(NS_REFRAME_IF_WHITESPACE
) &&
7793 aContent
->TextIsOnlyWhitespace())) {
7795 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
7796 NS_ASSERTION(!frame
|| !frame
->IsGeneratedContentFrame(),
7797 "Bit should never be set on generated content");
7799 LAYOUT_PHASE_TEMP_EXIT();
7800 nsresult rv
= RecreateFramesForContent(aContent
, PR_FALSE
);
7801 LAYOUT_PHASE_TEMP_REENTER();
7805 // Find the child frame
7806 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
7808 // Notify the first frame that maps the content. It will generate a reflow
7811 // It's possible the frame whose content changed isn't inserted into the
7812 // frame hierarchy yet, or that there is no frame that maps the content
7813 if (nsnull
!= frame
) {
7815 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS
,
7816 ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p",
7817 aContent
, ContentTag(aContent
, 0),
7818 aSubContent
, frame
));
7821 // Special check for text content that is a child of a letter frame. If
7822 // this happens, we should remove the letter frame, do whatever we're
7823 // planning to do with this notification, then put the letter frame back.
7824 // Note that this is basically what RecreateFramesForContent ends up doing;
7825 // the reason we dont' want to call that here is that our text content
7826 // could be native anonymous, in which case RecreateFramesForContent would
7827 // completely barf on it. And recreating the non-anonymous ancestor would
7828 // just lead us to come back into this notification (e.g. if quotes or
7829 // counters are involved), leading to a loop.
7830 nsIFrame
* block
= GetFloatContainingBlock(frame
);
7831 PRBool haveFirstLetterStyle
= PR_FALSE
;
7833 // See if the block has first-letter style applied to it.
7834 haveFirstLetterStyle
= HasFirstLetterStyle(block
);
7835 if (haveFirstLetterStyle
) {
7836 RemoveLetterFrames(mPresShell
->GetPresContext(), mPresShell
,
7837 mPresShell
->FrameManager(), block
);
7838 // Reget |frame|, since we might have killed it.
7839 // Do we really need to call CharacterDataChanged in this case, though?
7840 frame
= aContent
->GetPrimaryFrame();
7841 NS_ASSERTION(frame
, "Should have frame here!");
7845 frame
->CharacterDataChanged(aInfo
);
7847 if (haveFirstLetterStyle
) {
7848 RecoverLetterFrames(block
);
7855 NS_DECLARE_FRAME_PROPERTY(ChangeListProperty
, nsnull
)
7858 nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList
& aChangeList
)
7860 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
7861 "Someone forgot a script blocker");
7862 PRInt32 count
= aChangeList
.Count();
7866 // Make sure to not rebuild quote or counter lists while we're
7867 // processing restyles
7870 nsPresContext
* presContext
= mPresShell
->GetPresContext();
7871 FramePropertyTable
* propTable
= presContext
->PropertyTable();
7873 // Mark frames so that we skip frames that die along the way, bug 123049.
7874 // A frame can be in the list multiple times with different hints. Further
7875 // optmization is possible if nsStyleChangeList::AppendChange could coalesce
7876 PRInt32 index
= count
;
7878 while (0 <= --index
) {
7879 const nsStyleChangeData
* changeData
;
7880 aChangeList
.ChangeAt(index
, &changeData
);
7881 if (changeData
->mFrame
) {
7882 propTable
->Set(changeData
->mFrame
, ChangeListProperty(),
7883 NS_INT32_TO_PTR(1));
7888 PRBool didInvalidate
= PR_FALSE
;
7889 PRBool didReflow
= PR_FALSE
;
7891 while (0 <= --index
) {
7893 nsIContent
* content
;
7895 aChangeList
.ChangeAt(index
, frame
, content
, hint
);
7897 NS_ASSERTION(!(hint
& nsChangeHint_ReflowFrame
) ||
7898 (hint
& nsChangeHint_NeedReflow
),
7899 "Reflow hint bits set without actually asking for a reflow");
7901 if (frame
&& frame
->GetContent() != content
) {
7902 // XXXbz this is due to image maps messing with the primary frame of
7903 // <area>s. See bug 135040. Remove this block once that's fixed.
7905 if (!(hint
& nsChangeHint_ReconstructFrame
)) {
7910 // skip any frame that has been destroyed due to a ripple effect
7912 if (!propTable
->Get(frame
, ChangeListProperty()))
7916 if (hint
& nsChangeHint_ReconstructFrame
) {
7917 RecreateFramesForContent(content
, PR_FALSE
);
7919 NS_ASSERTION(frame
, "This shouldn't happen");
7921 if (hint
& nsChangeHint_UpdateEffects
) {
7922 nsSVGEffects::UpdateEffects(frame
);
7925 if (hint
& nsChangeHint_NeedReflow
) {
7926 StyleChangeReflow(frame
, hint
);
7927 didReflow
= PR_TRUE
;
7929 if (hint
& (nsChangeHint_RepaintFrame
| nsChangeHint_SyncFrameView
|
7930 nsChangeHint_UpdateOpacityLayer
| nsChangeHint_UpdateTransformLayer
)) {
7931 ApplyRenderingChangeToTree(presContext
, frame
, hint
);
7932 didInvalidate
= PR_TRUE
;
7934 if (hint
& nsChangeHint_UpdateCursor
) {
7935 mPresShell
->SynthesizeMouseMove(PR_FALSE
);
7942 if (didInvalidate
&& !didReflow
) {
7943 // RepaintFrame changes can indicate changes in opacity etc which
7944 // can require plugin clipping to change. If we requested a reflow,
7945 // we don't need to do this since the reflow will do it for us.
7946 nsIFrame
* rootFrame
= mPresShell
->FrameManager()->GetRootFrame();
7947 nsRootPresContext
* rootPC
= presContext
->GetRootPresContext();
7949 rootPC
->RequestUpdatePluginGeometry(rootFrame
);
7953 // cleanup references and verify the style tree. Note that the latter needs
7954 // to happen once we've processed the whole list, since until then the tree
7955 // is not in fact in a consistent state.
7957 while (0 <= --index
) {
7958 const nsStyleChangeData
* changeData
;
7959 aChangeList
.ChangeAt(index
, &changeData
);
7960 if (changeData
->mFrame
) {
7961 propTable
->Delete(changeData
->mFrame
, ChangeListProperty());
7965 // reget frame from content since it may have been regenerated...
7966 if (changeData
->mContent
) {
7967 nsIFrame
* frame
= changeData
->mContent
->GetPrimaryFrame();
7969 mPresShell
->FrameManager()->DebugVerifyStyleTree(frame
);
7972 NS_WARNING("Unable to test style tree integrity -- no content node");
7977 aChangeList
.Clear();
7982 nsCSSFrameConstructor::RestyleElement(Element
*aElement
,
7983 nsIFrame
*aPrimaryFrame
,
7984 nsChangeHint aMinHint
,
7985 RestyleTracker
& aRestyleTracker
,
7986 PRBool aRestyleDescendants
)
7988 NS_ASSERTION(aPrimaryFrame
== aElement
->GetPrimaryFrame(),
7989 "frame/content mismatch");
7990 if (aPrimaryFrame
&& aPrimaryFrame
->GetContent() != aElement
) {
7991 // XXXbz this is due to image maps messing with the primary frame pointer
7992 // of <area>s. See bug 135040. We can remove this block once that's fixed.
7993 aPrimaryFrame
= nsnull
;
7995 NS_ASSERTION(!aPrimaryFrame
|| aPrimaryFrame
->GetContent() == aElement
,
7996 "frame/content mismatch");
7998 if (aMinHint
& nsChangeHint_ReconstructFrame
) {
7999 RecreateFramesForContent(aElement
, PR_FALSE
);
8000 } else if (aPrimaryFrame
) {
8001 nsStyleChangeList changeList
;
8002 mPresShell
->FrameManager()->
8003 ComputeStyleChangeFor(aPrimaryFrame
, &changeList
, aMinHint
,
8004 aRestyleTracker
, aRestyleDescendants
);
8005 ProcessRestyledFrames(changeList
);
8007 // no frames, reconstruct for content
8008 MaybeRecreateFramesForElement(aElement
);
8013 nsCSSFrameConstructor::ContentStatesChanged(nsIContent
* aContent1
,
8014 nsIContent
* aContent2
,
8017 // XXXbz it would be good if this function only took Elements, but
8018 // we'd have to make ESM guarantee that usefully.
8019 if (NS_LIKELY(aContent1
&& aContent1
->IsElement())) {
8020 DoContentStateChanged(aContent1
->AsElement(), aStateMask
);
8022 if (aContent2
&& aContent2
->IsElement()) {
8023 DoContentStateChanged(aContent2
->AsElement(), aStateMask
);
8029 nsCSSFrameConstructor::DoContentStateChanged(Element
* aElement
,
8032 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
8033 nsPresContext
*presContext
= mPresShell
->GetPresContext();
8034 NS_ASSERTION(styleSet
, "couldn't get style set");
8036 nsChangeHint hint
= NS_STYLE_HINT_NONE
;
8037 // Any change to a content state that affects which frames we construct
8038 // must lead to a frame reconstruct here if we already have a frame.
8039 // Note that we never decide through non-CSS means to not create frames
8040 // based on content states, so if we already don't have a frame we don't
8041 // need to force a reframe -- if it's needed, the HasStateDependentStyle
8042 // call will handle things.
8043 nsIFrame
* primaryFrame
= aElement
->GetPrimaryFrame();
8045 // If it's generated content, ignore LOADING/etc state changes on it.
8046 if (!primaryFrame
->IsGeneratedContentFrame() &&
8047 (aStateMask
& (NS_EVENT_STATE_BROKEN
| NS_EVENT_STATE_USERDISABLED
|
8048 NS_EVENT_STATE_SUPPRESSED
| NS_EVENT_STATE_LOADING
))) {
8049 hint
= nsChangeHint_ReconstructFrame
;
8051 PRUint8 app
= primaryFrame
->GetStyleDisplay()->mAppearance
;
8053 nsITheme
*theme
= presContext
->GetTheme();
8054 if (theme
&& theme
->ThemeSupportsWidget(presContext
,
8055 primaryFrame
, app
)) {
8056 PRBool repaint
= PR_FALSE
;
8057 theme
->WidgetStateChanged(primaryFrame
, app
, nsnull
, &repaint
);
8059 NS_UpdateHint(hint
, nsChangeHint_RepaintFrame
);
8066 nsRestyleHint rshint
=
8067 styleSet
->HasStateDependentStyle(presContext
, aElement
, aStateMask
);
8069 if ((aStateMask
& NS_EVENT_STATE_HOVER
) && rshint
!= 0) {
8073 if (aStateMask
& NS_EVENT_STATE_VISITED
) {
8074 // Exposing information to the page about whether the link is
8075 // visited or not isn't really something we can worry about here.
8076 // FIXME: We could probably do this a bit better.
8077 NS_UpdateHint(hint
, nsChangeHint_RepaintFrame
);
8080 PostRestyleEvent(aElement
, rshint
, hint
);
8084 nsCSSFrameConstructor::AttributeWillChange(Element
* aElement
,
8085 PRInt32 aNameSpaceID
,
8086 nsIAtom
* aAttribute
,
8089 nsRestyleHint rshint
=
8090 mPresShell
->StyleSet()->HasAttributeDependentStyle(mPresShell
->GetPresContext(),
8095 PostRestyleEvent(aElement
, rshint
, NS_STYLE_HINT_NONE
);
8099 nsCSSFrameConstructor::AttributeChanged(Element
* aElement
,
8100 PRInt32 aNameSpaceID
,
8101 nsIAtom
* aAttribute
,
8104 // Hold onto the PresShell to prevent ourselves from being destroyed.
8105 // XXXbz how, exactly, would this attribute change cause us to be
8106 // destroyed from inside this function?
8107 nsCOMPtr
<nsIPresShell
> shell
= mPresShell
;
8109 // Get the frame associated with the content which is the highest in the frame tree
8110 nsIFrame
* primaryFrame
= aElement
->GetPrimaryFrame();
8113 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS
,
8114 ("HTMLStyleSheet::AttributeChanged: content=%p[%s] frame=%p",
8115 aContent
, ContentTag(aElement
, 0), frame
));
8118 // the style tag has its own interpretation based on aHint
8119 nsChangeHint hint
= aElement
->GetAttributeChangeHint(aAttribute
, aModType
);
8121 PRBool reframe
= (hint
& nsChangeHint_ReconstructFrame
) != 0;
8124 // The following listbox widget trap prevents offscreen listbox widget
8125 // content from being removed and re-inserted (which is what would
8126 // happen otherwise).
8127 if (!primaryFrame
&& !reframe
) {
8128 PRInt32 namespaceID
;
8130 mDocument
->BindingManager()->ResolveTag(aElement
, &namespaceID
);
8132 if (namespaceID
== kNameSpaceID_XUL
&&
8133 (tag
== nsGkAtoms::listitem
||
8134 tag
== nsGkAtoms::listcell
))
8138 if (aAttribute
== nsGkAtoms::tooltiptext
||
8139 aAttribute
== nsGkAtoms::tooltip
)
8141 nsIRootBox
* rootBox
= nsIRootBox::GetRootBox(mPresShell
);
8143 if (aModType
== nsIDOMMutationEvent::REMOVAL
)
8144 rootBox
->RemoveTooltipSupport(aElement
);
8145 if (aModType
== nsIDOMMutationEvent::ADDITION
)
8146 rootBox
->AddTooltipSupport(aElement
);
8153 // See if we have appearance information for a theme.
8154 const nsStyleDisplay
* disp
= primaryFrame
->GetStyleDisplay();
8155 if (disp
->mAppearance
) {
8156 nsPresContext
* presContext
= mPresShell
->GetPresContext();
8157 nsITheme
*theme
= presContext
->GetTheme();
8158 if (theme
&& theme
->ThemeSupportsWidget(presContext
, primaryFrame
, disp
->mAppearance
)) {
8159 PRBool repaint
= PR_FALSE
;
8160 theme
->WidgetStateChanged(primaryFrame
, disp
->mAppearance
, aAttribute
, &repaint
);
8162 NS_UpdateHint(hint
, nsChangeHint_RepaintFrame
);
8166 // let the frame deal with it now, so we don't have to deal later
8167 primaryFrame
->AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
8168 // XXXwaterson should probably check for special IB siblings
8169 // here, and propagate the AttributeChanged notification to
8170 // them, as well. Currently, inline frames don't do anything on
8171 // this notification, so it's not that big a deal.
8174 // See if we can optimize away the style re-resolution -- must be called after
8175 // the frame's AttributeChanged() in case it does something that affects the style
8176 nsRestyleHint rshint
=
8177 mPresShell
->StyleSet()->HasAttributeDependentStyle(mPresShell
->GetPresContext(),
8183 PostRestyleEvent(aElement
, rshint
, hint
);
8187 nsCSSFrameConstructor::BeginUpdate() {
8188 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
8189 "Someone forgot a script blocker");
8195 nsCSSFrameConstructor::EndUpdate()
8197 if (mUpdateCount
== 1) {
8198 // This is the end of our last update. Before we decrement
8199 // mUpdateCount, recalc quotes and counters as needed.
8201 RecalcQuotesAndCounters();
8202 NS_ASSERTION(mUpdateCount
== 1, "Odd update count");
8208 nsCSSFrameConstructor::RecalcQuotesAndCounters()
8211 mQuotesDirty
= PR_FALSE
;
8212 mQuoteList
.RecalcAll();
8215 if (mCountersDirty
) {
8216 mCountersDirty
= PR_FALSE
;
8217 mCounterManager
.RecalcAll();
8220 NS_ASSERTION(!mQuotesDirty
, "Quotes updates will be lost");
8221 NS_ASSERTION(!mCountersDirty
, "Counter updates will be lost");
8225 nsCSSFrameConstructor::WillDestroyFrameTree()
8227 #if defined(DEBUG_dbaron_off)
8228 mCounterManager
.Dump();
8231 mIsDestroyingFrameTree
= PR_TRUE
;
8233 // Prevent frame tree destruction from being O(N^2)
8235 mCounterManager
.Clear();
8237 // Remove our presshell as a style flush observer. But leave
8238 // mObservingRefreshDriver true so we don't readd to it even if someone tries
8239 // to post restyle events on us from this point on for some reason.
8240 mPresShell
->GetPresContext()->RefreshDriver()->
8241 RemoveStyleFlushObserver(mPresShell
);
8246 // XXXbz I'd really like this method to go away. Once we have inline-block and
8247 // I can just use that for sized broken images, that can happen, maybe.
8248 void nsCSSFrameConstructor::GetAlternateTextFor(nsIContent
* aContent
,
8249 nsIAtom
* aTag
, // content object's tag
8250 nsXPIDLString
& aAltText
)
8252 // The "alt" attribute specifies alternate text that is rendered
8253 // when the image can not be displayed
8255 // If there's no "alt" attribute, and aContent is an input
8256 // element, then use the value of the "value" attribute
8257 if (!aContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::alt
, aAltText
) &&
8258 nsGkAtoms::input
== aTag
) {
8259 // If there's no "value" attribute either, then use the localized string
8260 // for "Submit" as the alternate text.
8261 if (!aContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::value
, aAltText
)) {
8262 nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES
,
8263 "Submit", aAltText
);
8269 nsCSSFrameConstructor::CreateContinuingOuterTableFrame(nsIPresShell
* aPresShell
,
8270 nsPresContext
* aPresContext
,
8272 nsIFrame
* aParentFrame
,
8273 nsIContent
* aContent
,
8274 nsStyleContext
* aStyleContext
,
8275 nsIFrame
** aContinuingFrame
)
8277 nsIFrame
* newFrame
= NS_NewTableOuterFrame(aPresShell
, aStyleContext
);
8280 newFrame
->Init(aContent
, aParentFrame
, aFrame
);
8281 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8283 // Create a continuing inner table frame, and if there's a caption then
8284 // replicate the caption
8285 nsFrameItems newChildFrames
;
8287 nsIFrame
* childFrame
= aFrame
->GetFirstChild(nsnull
);
8289 nsIFrame
* continuingTableFrame
;
8290 nsresult rv
= CreateContinuingFrame(aPresContext
, childFrame
, newFrame
,
8291 &continuingTableFrame
);
8292 if (NS_FAILED(rv
)) {
8293 newFrame
->Destroy();
8294 *aContinuingFrame
= nsnull
;
8297 newChildFrames
.AddChild(continuingTableFrame
);
8299 NS_ASSERTION(!childFrame
->GetNextSibling(),"there can be only one inner table frame");
8302 // Set the outer table's initial child list
8303 newFrame
->SetInitialChildList(nsnull
, newChildFrames
);
8305 *aContinuingFrame
= newFrame
;
8309 *aContinuingFrame
= nsnull
;
8310 return NS_ERROR_OUT_OF_MEMORY
;
8315 nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell
* aPresShell
,
8316 nsPresContext
* aPresContext
,
8318 nsIFrame
* aParentFrame
,
8319 nsIContent
* aContent
,
8320 nsStyleContext
* aStyleContext
,
8321 nsIFrame
** aContinuingFrame
)
8323 nsIFrame
* newFrame
= NS_NewTableFrame(aPresShell
, aStyleContext
);
8326 newFrame
->Init(aContent
, aParentFrame
, aFrame
);
8327 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8329 // Replicate any header/footer frames
8330 nsFrameItems childFrames
;
8331 nsIFrame
* childFrame
= aFrame
->GetFirstChild(nsnull
);
8332 for ( ; childFrame
; childFrame
= childFrame
->GetNextSibling()) {
8333 // See if it's a header/footer, possibly wrapped in a scroll frame.
8334 nsTableRowGroupFrame
* rowGroupFrame
=
8335 static_cast<nsTableRowGroupFrame
*>(childFrame
);
8336 // If the row group was continued, then don't replicate it.
8337 nsIFrame
* rgNextInFlow
= rowGroupFrame
->GetNextInFlow();
8339 rowGroupFrame
->SetRepeatable(PR_FALSE
);
8341 else if (rowGroupFrame
->IsRepeatable()) {
8342 // Replicate the header/footer frame.
8343 nsTableRowGroupFrame
* headerFooterFrame
;
8344 nsFrameItems childItems
;
8345 nsFrameConstructorState
state(mPresShell
, mFixedContainingBlock
,
8346 GetAbsoluteContainingBlock(newFrame
),
8348 state
.mSetPrimaryFrames
= PR_FALSE
;
8350 headerFooterFrame
= static_cast<nsTableRowGroupFrame
*>
8351 (NS_NewTableRowGroupFrame(aPresShell
, rowGroupFrame
->GetStyleContext()));
8352 nsIContent
* headerFooter
= rowGroupFrame
->GetContent();
8353 headerFooterFrame
->Init(headerFooter
, newFrame
, nsnull
);
8354 ProcessChildren(state
, headerFooter
, rowGroupFrame
->GetStyleContext(),
8355 headerFooterFrame
, PR_TRUE
, childItems
, PR_FALSE
,
8357 NS_ASSERTION(state
.mFloatedItems
.IsEmpty(), "unexpected floated element");
8358 headerFooterFrame
->SetInitialChildList(nsnull
, childItems
);
8359 headerFooterFrame
->SetRepeatable(PR_TRUE
);
8361 // Table specific initialization
8362 headerFooterFrame
->InitRepeatedFrame(aPresContext
, rowGroupFrame
);
8364 // XXX Deal with absolute and fixed frames...
8365 childFrames
.AddChild(headerFooterFrame
);
8369 // Set the table frame's initial child list
8370 newFrame
->SetInitialChildList(nsnull
, childFrames
);
8372 *aContinuingFrame
= newFrame
;
8376 *aContinuingFrame
= nsnull
;
8377 return NS_ERROR_OUT_OF_MEMORY
;
8382 nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext
* aPresContext
,
8384 nsIFrame
* aParentFrame
,
8385 nsIFrame
** aContinuingFrame
,
8388 nsIPresShell
* shell
= aPresContext
->PresShell();
8389 nsStyleContext
* styleContext
= aFrame
->GetStyleContext();
8390 nsIFrame
* newFrame
= nsnull
;
8391 nsresult rv
= NS_OK
;
8392 nsIFrame
* nextContinuation
= aFrame
->GetNextContinuation();
8393 nsIFrame
* nextInFlow
= aFrame
->GetNextInFlow();
8395 // Use the frame type to determine what type of frame to create
8396 nsIAtom
* frameType
= aFrame
->GetType();
8397 nsIContent
* content
= aFrame
->GetContent();
8399 NS_ASSERTION(aFrame
->GetSplittableType() != NS_FRAME_NOT_SPLITTABLE
,
8400 "why CreateContinuingFrame for a non-splittable frame?");
8402 if (nsGkAtoms::textFrame
== frameType
) {
8403 newFrame
= NS_NewContinuingTextFrame(shell
, styleContext
);
8406 newFrame
->Init(content
, aParentFrame
, aFrame
);
8407 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8410 } else if (nsGkAtoms::inlineFrame
== frameType
) {
8411 newFrame
= NS_NewInlineFrame(shell
, styleContext
);
8414 newFrame
->Init(content
, aParentFrame
, aFrame
);
8415 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8418 } else if (nsGkAtoms::blockFrame
== frameType
) {
8419 newFrame
= NS_NewBlockFrame(shell
, styleContext
);
8422 newFrame
->Init(content
, aParentFrame
, aFrame
);
8423 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8427 } else if (nsGkAtoms::XULLabelFrame
== frameType
) {
8428 newFrame
= NS_NewXULLabelFrame(shell
, styleContext
);
8431 newFrame
->Init(content
, aParentFrame
, aFrame
);
8432 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8435 } else if (nsGkAtoms::columnSetFrame
== frameType
) {
8436 newFrame
= NS_NewColumnSetFrame(shell
, styleContext
, 0);
8439 newFrame
->Init(content
, aParentFrame
, aFrame
);
8440 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8443 } else if (nsGkAtoms::positionedInlineFrame
== frameType
) {
8444 newFrame
= NS_NewPositionedInlineFrame(shell
, styleContext
);
8447 newFrame
->Init(content
, aParentFrame
, aFrame
);
8448 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8451 } else if (nsGkAtoms::pageFrame
== frameType
) {
8452 nsIFrame
* canvasFrame
;
8453 rv
= ConstructPageFrame(shell
, aPresContext
, aParentFrame
, aFrame
,
8454 newFrame
, canvasFrame
);
8455 } else if (nsGkAtoms::tableOuterFrame
== frameType
) {
8456 rv
= CreateContinuingOuterTableFrame(shell
, aPresContext
, aFrame
, aParentFrame
,
8457 content
, styleContext
, &newFrame
);
8459 } else if (nsGkAtoms::tableFrame
== frameType
) {
8460 rv
= CreateContinuingTableFrame(shell
, aPresContext
, aFrame
, aParentFrame
,
8461 content
, styleContext
, &newFrame
);
8463 } else if (nsGkAtoms::tableRowGroupFrame
== frameType
) {
8464 newFrame
= NS_NewTableRowGroupFrame(shell
, styleContext
);
8467 newFrame
->Init(content
, aParentFrame
, aFrame
);
8468 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8471 } else if (nsGkAtoms::tableRowFrame
== frameType
) {
8472 newFrame
= NS_NewTableRowFrame(shell
, styleContext
);
8475 newFrame
->Init(content
, aParentFrame
, aFrame
);
8476 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8478 // Create a continuing frame for each table cell frame
8479 nsFrameItems newChildList
;
8480 nsIFrame
* cellFrame
= aFrame
->GetFirstChild(nsnull
);
8482 // See if it's a table cell frame
8483 if (IS_TABLE_CELL(cellFrame
->GetType())) {
8484 nsIFrame
* continuingCellFrame
;
8485 rv
= CreateContinuingFrame(aPresContext
, cellFrame
, newFrame
,
8486 &continuingCellFrame
);
8487 if (NS_FAILED(rv
)) {
8488 newChildList
.DestroyFrames();
8489 newFrame
->Destroy();
8490 *aContinuingFrame
= nsnull
;
8491 return NS_ERROR_OUT_OF_MEMORY
;
8493 newChildList
.AddChild(continuingCellFrame
);
8495 cellFrame
= cellFrame
->GetNextSibling();
8498 // Set the table cell's initial child list
8499 newFrame
->SetInitialChildList(nsnull
, newChildList
);
8502 } else if (IS_TABLE_CELL(frameType
)) {
8503 // Warning: If you change this and add a wrapper frame around table cell
8504 // frames, make sure Bug 368554 doesn't regress!
8505 // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
8506 newFrame
= NS_NewTableCellFrame(shell
, styleContext
, IsBorderCollapse(aParentFrame
));
8509 newFrame
->Init(content
, aParentFrame
, aFrame
);
8510 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8512 // Create a continuing area frame
8513 nsIFrame
* continuingBlockFrame
;
8514 nsIFrame
* blockFrame
= aFrame
->GetFirstChild(nsnull
);
8515 rv
= CreateContinuingFrame(aPresContext
, blockFrame
, newFrame
,
8516 &continuingBlockFrame
);
8517 if (NS_FAILED(rv
)) {
8518 newFrame
->Destroy();
8519 *aContinuingFrame
= nsnull
;
8523 // Set the table cell's initial child list
8524 SetInitialSingleChild(newFrame
, continuingBlockFrame
);
8527 } else if (nsGkAtoms::lineFrame
== frameType
) {
8528 newFrame
= NS_NewFirstLineFrame(shell
, styleContext
);
8531 newFrame
->Init(content
, aParentFrame
, aFrame
);
8532 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8535 } else if (nsGkAtoms::letterFrame
== frameType
) {
8536 newFrame
= NS_NewFirstLetterFrame(shell
, styleContext
);
8539 newFrame
->Init(content
, aParentFrame
, aFrame
);
8540 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8543 } else if (nsGkAtoms::imageFrame
== frameType
) {
8544 newFrame
= NS_NewImageFrame(shell
, styleContext
);
8547 newFrame
->Init(content
, aParentFrame
, aFrame
);
8549 } else if (nsGkAtoms::imageControlFrame
== frameType
) {
8550 newFrame
= NS_NewImageControlFrame(shell
, styleContext
);
8553 newFrame
->Init(content
, aParentFrame
, aFrame
);
8555 } else if (nsGkAtoms::placeholderFrame
== frameType
) {
8556 // create a continuing out of flow frame
8557 nsIFrame
* oofFrame
= nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame
);
8558 nsIFrame
* oofContFrame
;
8559 rv
= CreateContinuingFrame(aPresContext
, oofFrame
, aParentFrame
, &oofContFrame
);
8560 if (NS_FAILED(rv
)) {
8561 *aContinuingFrame
= nsnull
;
8564 // create a continuing placeholder frame
8565 rv
= CreatePlaceholderFrameFor(shell
, content
, oofContFrame
, styleContext
,
8566 aParentFrame
, aFrame
,
8567 aFrame
->GetStateBits() & PLACEHOLDER_TYPE_MASK
,
8569 if (NS_FAILED(rv
)) {
8570 oofContFrame
->Destroy();
8571 *aContinuingFrame
= nsnull
;
8574 } else if (nsGkAtoms::fieldSetFrame
== frameType
) {
8575 newFrame
= NS_NewFieldSetFrame(shell
, styleContext
);
8578 newFrame
->Init(content
, aParentFrame
, aFrame
);
8580 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8582 // Create a continuing area frame
8583 // XXXbz we really shouldn't have to do this by hand!
8584 nsIFrame
* continuingBlockFrame
;
8585 nsIFrame
* blockFrame
= GetFieldSetBlockFrame(aFrame
);
8586 rv
= CreateContinuingFrame(aPresContext
, blockFrame
, newFrame
,
8587 &continuingBlockFrame
);
8588 if (NS_FAILED(rv
)) {
8589 newFrame
->Destroy();
8590 *aContinuingFrame
= nsnull
;
8593 // Set the fieldset's initial child list
8594 SetInitialSingleChild(newFrame
, continuingBlockFrame
);
8596 } else if (nsGkAtoms::legendFrame
== frameType
) {
8597 newFrame
= NS_NewLegendFrame(shell
, styleContext
);
8600 newFrame
->Init(content
, aParentFrame
, aFrame
);
8601 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
8604 NS_NOTREACHED("unexpected frame type");
8605 *aContinuingFrame
= nsnull
;
8606 return NS_ERROR_UNEXPECTED
;
8609 *aContinuingFrame
= newFrame
;
8612 return NS_ERROR_OUT_OF_MEMORY
;
8615 // Init() set newFrame to be a fluid continuation of aFrame.
8616 // If we want a non-fluid continuation, we need to call SetPrevContinuation()
8617 // to reset NS_FRAME_IS_FLUID_CONTINUATION.
8619 newFrame
->SetPrevContinuation(aFrame
);
8622 // A continuation of generated content is also generated content
8623 if (aFrame
->GetStateBits() & NS_FRAME_GENERATED_CONTENT
) {
8624 newFrame
->AddStateBits(NS_FRAME_GENERATED_CONTENT
);
8627 // A continuation of an out-of-flow is also an out-of-flow
8628 if (aFrame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
8629 newFrame
->AddStateBits(NS_FRAME_OUT_OF_FLOW
);
8633 nextInFlow
->SetPrevInFlow(newFrame
);
8634 newFrame
->SetNextInFlow(nextInFlow
);
8635 } else if (nextContinuation
) {
8636 nextContinuation
->SetPrevContinuation(newFrame
);
8637 newFrame
->SetNextContinuation(nextContinuation
);
8640 NS_POSTCONDITION(!newFrame
->GetNextSibling(), "unexpected sibling");
8645 nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame
* aParentFrame
)
8647 // Now deal with fixed-pos things.... They should appear on all pages,
8648 // so we want to move over the placeholders when processing the child
8649 // of the pageContentFrame.
8651 nsIFrame
* prevPageContentFrame
= aParentFrame
->GetPrevInFlow();
8652 if (!prevPageContentFrame
) {
8655 nsIFrame
* canvasFrame
= aParentFrame
->GetFirstChild(nsnull
);
8656 nsIFrame
* prevCanvasFrame
= prevPageContentFrame
->GetFirstChild(nsnull
);
8657 if (!canvasFrame
|| !prevCanvasFrame
) {
8658 // document's root element frame missing
8659 return NS_ERROR_UNEXPECTED
;
8662 nsFrameItems fixedPlaceholders
;
8663 nsIFrame
* firstFixed
= prevPageContentFrame
->GetFirstChild(nsGkAtoms::fixedList
);
8668 // Don't allow abs-pos descendants of the fixed content to escape the content.
8669 // This should not normally be possible (because fixed-pos elements should
8670 // be absolute containers) but fixed-pos tables currently aren't abs-pos
8672 nsFrameConstructorState
state(mPresShell
, aParentFrame
,
8675 state
.mSetPrimaryFrames
= PR_FALSE
;
8677 // Iterate across fixed frames and replicate each whose placeholder is a
8678 // descendant of aFrame. (We don't want to explicitly copy placeholders that
8679 // are within fixed frames, because that would cause duplicates on the new
8680 // page - bug 389619)
8681 for (nsIFrame
* fixed
= firstFixed
; fixed
; fixed
= fixed
->GetNextSibling()) {
8682 nsIFrame
* prevPlaceholder
= mPresShell
->FrameManager()->GetPlaceholderFrameFor(fixed
);
8683 if (prevPlaceholder
&&
8684 nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame
, prevPlaceholder
)) {
8685 nsresult rv
= ConstructFrame(state
, fixed
->GetContent(),
8686 canvasFrame
, fixedPlaceholders
);
8687 NS_ENSURE_SUCCESS(rv
, rv
);
8691 // Add the placeholders to our primary child list.
8692 // XXXbz this is a little screwed up, since the fixed frames will have
8693 // broken auto-positioning. Oh, well.
8694 NS_ASSERTION(!canvasFrame
->GetFirstChild(nsnull
),
8695 "leaking frames; doc root continuation must be empty");
8696 canvasFrame
->SetInitialChildList(nsnull
, fixedPlaceholders
);
8701 nsCSSFrameConstructor::GetInsertionPoint(nsIFrame
* aParentFrame
,
8702 nsIContent
* aChildContent
,
8703 nsIFrame
** aInsertionPoint
,
8706 // Make the insertion point be the parent frame by default, in case
8707 // we have to bail early.
8708 *aInsertionPoint
= aParentFrame
;
8710 nsIContent
* container
= aParentFrame
->GetContent();
8714 nsBindingManager
*bindingManager
= mDocument
->BindingManager();
8716 nsIContent
* insertionElement
;
8717 if (aChildContent
) {
8718 // We've got an explicit insertion child. Check to see if it's
8720 if (aChildContent
->GetBindingParent() == container
) {
8721 // This child content is anonymous. Don't use the insertion
8722 // point, since that's only for the explicit kids.
8727 insertionElement
= bindingManager
->GetInsertionPoint(container
,
8734 insertionElement
= bindingManager
->GetSingleInsertionPoint(container
,
8737 if (multiple
&& aMultiple
)
8738 *aMultiple
= multiple
; // Record the fact that filters are in use.
8741 if (insertionElement
) {
8742 nsIFrame
* insertionPoint
= insertionElement
->GetPrimaryFrame();
8743 if (insertionPoint
) {
8744 // Use the content insertion frame of the insertion point.
8745 insertionPoint
= insertionPoint
->GetContentInsertionFrame();
8746 if (insertionPoint
&& insertionPoint
!= aParentFrame
)
8747 GetInsertionPoint(insertionPoint
, aChildContent
, aInsertionPoint
, aMultiple
);
8750 // There was no frame created yet for the insertion point.
8751 *aInsertionPoint
= nsnull
;
8755 // fieldsets have multiple insertion points. Note that we might
8756 // have to look at insertionElement here...
8757 if (aMultiple
&& !*aMultiple
) {
8758 nsIContent
* content
= insertionElement
? insertionElement
: container
;
8759 if (content
->IsHTML() &&
8760 content
->Tag() == nsGkAtoms::fieldset
) {
8761 *aMultiple
= PR_TRUE
;
8768 // Capture state for the frame tree rooted at the frame associated with the
8769 // content object, aContent
8771 nsCSSFrameConstructor::CaptureStateForFramesOf(nsIContent
* aContent
,
8772 nsILayoutHistoryState
* aHistoryState
)
8774 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
8775 if (frame
== mRootElementFrame
) {
8776 frame
= mFixedContainingBlock
;
8779 CaptureStateFor(frame
, aHistoryState
);
8784 // Capture state for the frame tree rooted at aFrame.
8786 nsCSSFrameConstructor::CaptureStateFor(nsIFrame
* aFrame
,
8787 nsILayoutHistoryState
* aHistoryState
)
8789 if (aFrame
&& aHistoryState
) {
8790 mPresShell
->FrameManager()->CaptureFrameState(aFrame
, aHistoryState
);
8796 nsCSSFrameConstructor::MaybeRecreateFramesForElement(Element
* aElement
)
8798 nsresult result
= NS_OK
;
8799 nsFrameManager
*frameManager
= mPresShell
->FrameManager();
8801 nsStyleContext
*oldContext
= frameManager
->GetUndisplayedContent(aElement
);
8803 // The parent has a frame, so try resolving a new context.
8804 nsRefPtr
<nsStyleContext
> newContext
= mPresShell
->StyleSet()->
8805 ResolveStyleFor(aElement
, oldContext
->GetParent());
8807 frameManager
->ChangeUndisplayedContent(aElement
, newContext
);
8808 if (newContext
->GetStyleDisplay()->mDisplay
!= NS_STYLE_DISPLAY_NONE
) {
8809 result
= RecreateFramesForContent(aElement
, PR_FALSE
);
8816 FindFirstNonWhitespaceChild(nsIFrame
* aParentFrame
)
8818 nsIFrame
* f
= aParentFrame
->GetFirstChild(nsnull
);
8819 while (f
&& f
->GetType() == nsGkAtoms::textFrame
&&
8820 f
->GetContent()->TextIsOnlyWhitespace()) {
8821 f
= f
->GetNextSibling();
8827 FindNextNonWhitespaceSibling(nsIFrame
* aFrame
)
8829 nsIFrame
* f
= aFrame
;
8831 f
= f
->GetNextSibling();
8832 } while (f
&& f
->GetType() == nsGkAtoms::textFrame
&&
8833 f
->GetContent()->TextIsOnlyWhitespace());
8838 nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame
* aFrame
,
8841 NS_PRECONDITION(aFrame
, "Must have a frame");
8842 NS_PRECONDITION(aFrame
->GetParent(), "Frame shouldn't be root");
8843 NS_PRECONDITION(aResult
, "Null out param?");
8844 NS_PRECONDITION(aFrame
== aFrame
->GetFirstContinuation(),
8845 "aFrame not the result of GetPrimaryFrame()?");
8847 if (IsFrameSpecial(aFrame
)) {
8848 // The removal functions can't handle removal of an {ib} split directly; we
8849 // need to rebuild the containing block.
8851 if (gNoisyContentUpdates
) {
8852 printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8854 nsFrame::ListTag(stdout
, aFrame
);
8855 printf(" is special\n");
8859 *aResult
= ReframeContainingBlock(aFrame
);
8863 if (aFrame
->GetType() == nsGkAtoms::legendFrame
&&
8864 aFrame
->GetParent()->GetType() == nsGkAtoms::fieldSetFrame
) {
8865 // When we remove the legend for a fieldset, we should reframe
8866 // the fieldset to ensure another legend is used, if there is one
8867 *aResult
= RecreateFramesForContent(aFrame
->GetParent()->GetContent(), PR_FALSE
);
8871 // Now check for possibly needing to reconstruct due to a pseudo parent
8872 nsIFrame
* inFlowFrame
=
8873 (aFrame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) ?
8874 mPresShell
->FrameManager()->GetPlaceholderFrameFor(aFrame
) : aFrame
;
8875 NS_ASSERTION(inFlowFrame
, "How did that happen?");
8876 nsIFrame
* parent
= inFlowFrame
->GetParent();
8877 if (IsTablePseudo(parent
)) {
8878 if (FindFirstNonWhitespaceChild(parent
) == inFlowFrame
||
8879 !FindNextNonWhitespaceSibling(inFlowFrame
->GetLastContinuation()) ||
8880 // If we're a table-column-group, then the GetFirstChild check above is
8881 // not going to catch cases when we're the first child.
8882 (inFlowFrame
->GetType() == nsGkAtoms::tableColGroupFrame
&&
8883 parent
->GetFirstChild(nsGkAtoms::colGroupList
) == inFlowFrame
) ||
8884 // Similar if we're a table-caption.
8885 (inFlowFrame
->GetType() == nsGkAtoms::tableCaptionFrame
&&
8886 parent
->GetFirstChild(nsGkAtoms::captionList
) == inFlowFrame
)) {
8887 // We're the first or last frame in the pseudo. Need to reframe.
8888 // Good enough to recreate frames for |parent|'s content
8889 *aResult
= RecreateFramesForContent(parent
->GetContent(), PR_TRUE
);
8894 // Might need to reconstruct things if this frame's nextSibling is a table
8895 // pseudo, since removal of this frame might mean that this pseudo needs to
8896 // get merged with the frame's prevSibling.
8897 // XXXbz it would be really nice if we had the prevSibling here too, to check
8898 // whether this is in fact the case...
8899 nsIFrame
* nextSibling
=
8900 FindNextNonWhitespaceSibling(inFlowFrame
->GetLastContinuation());
8901 NS_ASSERTION(!IsTablePseudo(inFlowFrame
), "Shouldn't happen here");
8902 if (nextSibling
&& IsTablePseudo(nextSibling
)) {
8904 if (gNoisyContentUpdates
) {
8905 printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8907 nsFrame::ListTag(stdout
, aFrame
);
8908 printf(" has a table pseudo next sibling of different type\n");
8911 // Good enough to recreate frames for aFrame's parent's content; even if
8912 // aFrame's parent is a table pseudo, that'll be the right content node.
8913 *aResult
= RecreateFramesForContent(parent
->GetContent(), PR_TRUE
);
8918 if (aFrame
->GetType() == nsGkAtoms::popupSetFrame
) {
8919 nsIRootBox
* rootBox
= nsIRootBox::GetRootBox(mPresShell
);
8920 if (rootBox
&& rootBox
->GetPopupSetFrame() == aFrame
) {
8921 *aResult
= ReconstructDocElementHierarchy();
8927 // We might still need to reconstruct things if the parent of inFlowFrame is
8928 // special, since in that case the removal of aFrame might affect the
8929 // splitting of its parent.
8930 if (!IsFrameSpecial(parent
)) {
8934 // If inFlowFrame is not the only in-flow child of |parent|, then removing
8935 // it will change nothing about the {ib} split.
8936 if (inFlowFrame
!= parent
->GetFirstChild(nsnull
) ||
8937 inFlowFrame
->GetLastContinuation()->GetNextSibling()) {
8941 // If the parent is the first or last part of the {ib} split, then
8942 // removing one of its kids will have no effect on the splitting.
8943 // Get the first continuation up front so we don't have to do it twice.
8944 nsIFrame
* parentFirstContinuation
= parent
->GetFirstContinuation();
8945 if (!GetSpecialSibling(parentFirstContinuation
) ||
8946 !GetSpecialPrevSibling(parentFirstContinuation
)) {
8951 if (gNoisyContentUpdates
) {
8952 printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8954 nsFrame::ListTag(stdout
, parent
);
8955 printf(" is special\n");
8959 *aResult
= ReframeContainingBlock(parent
);
8964 nsCSSFrameConstructor::RecreateFramesForContent(nsIContent
* aContent
,
8965 PRBool aAsyncInsert
)
8967 NS_PRECONDITION(!aAsyncInsert
|| aContent
->IsElement(),
8968 "Can only insert elements async");
8969 // If there is no document, we don't want to recreate frames for it. (You
8970 // shouldn't generally be giving this method content without a document
8972 // Rebuilding the frame tree can have bad effects, especially if it's the
8973 // frame tree for chrome (see bug 157322).
8974 NS_ENSURE_TRUE(aContent
->GetDocument(), NS_ERROR_FAILURE
);
8976 // Is the frame `special'? If so, we need to reframe the containing
8977 // block *here*, rather than trying to remove and re-insert the
8978 // content (which would otherwise result in *two* nested reframe
8979 // containing block from ContentRemoved() and ContentInserted(),
8980 // below!). We'd really like to optimize away one of those
8981 // containing block reframes, hence the code here.
8983 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
8984 if (frame
&& frame
->IsFrameOfType(nsIFrame::eMathML
)) {
8985 // Reframe the topmost MathML element to prevent exponential blowup
8988 nsIContent
* parentContent
= aContent
->GetParent();
8989 nsIFrame
* parentContentFrame
= parentContent
->GetPrimaryFrame();
8990 if (!parentContentFrame
|| !parentContentFrame
->IsFrameOfType(nsIFrame::eMathML
))
8992 aContent
= parentContent
;
8993 frame
= parentContentFrame
;
8998 nsIFrame
* nonGeneratedAncestor
= nsLayoutUtils::GetNonGeneratedAncestor(frame
);
8999 if (nonGeneratedAncestor
->GetContent() != aContent
) {
9000 return RecreateFramesForContent(nonGeneratedAncestor
->GetContent(), aAsyncInsert
);
9003 nsIFrame
* parent
= frame
->GetParent();
9004 nsIContent
* parentContent
= parent
? parent
->GetContent() : nsnull
;
9005 // If the parent frame is a leaf then the subsequent insert will fail to
9006 // create a frame, so we need to recreate the parent content. This happens
9007 // with native anonymous content from the editor.
9008 if (parent
&& parent
->IsLeaf() && parentContent
&&
9009 parentContent
!= aContent
) {
9010 return RecreateFramesForContent(parentContent
, aAsyncInsert
);
9014 nsresult rv
= NS_OK
;
9016 if (frame
&& MaybeRecreateContainerForFrameRemoval(frame
, &rv
)) {
9020 nsINode
* containerNode
= aContent
->GetNodeParent();
9021 // XXXbz how can containerNode be null here?
9022 if (containerNode
) {
9023 // Before removing the frames associated with the content object,
9024 // ask them to save their state onto a temporary state object.
9025 CaptureStateForFramesOf(aContent
, mTempFrameTreeState
);
9027 // Need the nsIContent parent, which might be null here, since we need to
9028 // pass it to ContentInserted and ContentRemoved.
9029 nsCOMPtr
<nsIContent
> container
= aContent
->GetParent();
9031 // Remove the frames associated with the content object.
9032 PRBool didReconstruct
;
9033 rv
= ContentRemoved(container
, aContent
,
9034 aContent
->IsRootOfAnonymousSubtree() ?
9036 aContent
->GetNextSibling(),
9037 REMOVE_FOR_RECONSTRUCTION
, &didReconstruct
);
9039 if (NS_SUCCEEDED(rv
) && !didReconstruct
) {
9040 // Now, recreate the frames associated with this content object. If
9041 // ContentRemoved triggered reconstruction, then we don't need to do this
9042 // because the frames will already have been built.
9044 PostRestyleEvent(aContent
->AsElement(), nsRestyleHint(0),
9045 nsChangeHint_ReconstructFrame
);
9047 rv
= ContentInserted(container
, aContent
, mTempFrameTreeState
, PR_FALSE
);
9052 #ifdef ACCESSIBILITY
9053 if (mPresShell
->IsAccessibilityActive()) {
9054 PRUint32 changeType
;
9056 nsIFrame
*newFrame
= aContent
->GetPrimaryFrame();
9057 changeType
= newFrame
? nsIAccessibilityService::FRAME_SIGNIFICANT_CHANGE
:
9058 nsIAccessibilityService::FRAME_HIDE
;
9061 changeType
= nsIAccessibilityService::FRAME_SHOW
;
9064 // A significant enough change occurred that this part
9065 // of the accessible tree is no longer valid.
9066 nsCOMPtr
<nsIAccessibilityService
> accService
=
9067 do_GetService("@mozilla.org/accessibilityService;1");
9069 accService
->InvalidateSubtreeFor(mPresShell
, aContent
, changeType
);
9077 //////////////////////////////////////////////////////////////////////
9079 // Block frame construction code
9081 already_AddRefed
<nsStyleContext
>
9082 nsCSSFrameConstructor::GetFirstLetterStyle(nsIContent
* aContent
,
9083 nsStyleContext
* aStyleContext
)
9086 return mPresShell
->StyleSet()->
9087 ResolvePseudoElementStyle(aContent
->AsElement(),
9088 nsCSSPseudoElements::ePseudo_firstLetter
,
9094 already_AddRefed
<nsStyleContext
>
9095 nsCSSFrameConstructor::GetFirstLineStyle(nsIContent
* aContent
,
9096 nsStyleContext
* aStyleContext
)
9099 return mPresShell
->StyleSet()->
9100 ResolvePseudoElementStyle(aContent
->AsElement(),
9101 nsCSSPseudoElements::ePseudo_firstLine
,
9107 // Predicate to see if a given content (block element) has
9108 // first-letter style applied to it.
9110 nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(nsIContent
* aContent
,
9111 nsStyleContext
* aStyleContext
)
9113 return nsLayoutUtils::HasPseudoStyle(aContent
, aStyleContext
,
9114 nsCSSPseudoElements::ePseudo_firstLetter
,
9115 mPresShell
->GetPresContext());
9119 nsCSSFrameConstructor::HasFirstLetterStyle(nsIFrame
* aBlockFrame
)
9121 NS_PRECONDITION(aBlockFrame
, "Need a frame");
9122 NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame
),
9123 "Not a block frame?");
9125 return (aBlockFrame
->GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE
) != 0;
9129 nsCSSFrameConstructor::ShouldHaveFirstLineStyle(nsIContent
* aContent
,
9130 nsStyleContext
* aStyleContext
)
9132 PRBool hasFirstLine
=
9133 nsLayoutUtils::HasPseudoStyle(aContent
, aStyleContext
,
9134 nsCSSPseudoElements::ePseudo_firstLine
,
9135 mPresShell
->GetPresContext());
9137 // But disable for fieldsets
9138 PRInt32 namespaceID
;
9139 nsIAtom
* tag
= mDocument
->BindingManager()->ResolveTag(aContent
,
9141 // This check must match the one in FindHTMLData.
9142 hasFirstLine
= tag
!= nsGkAtoms::fieldset
||
9143 namespaceID
!= kNameSpaceID_XHTML
;
9146 return hasFirstLine
;
9150 nsCSSFrameConstructor::ShouldHaveSpecialBlockStyle(nsIContent
* aContent
,
9151 nsStyleContext
* aStyleContext
,
9152 PRBool
* aHaveFirstLetterStyle
,
9153 PRBool
* aHaveFirstLineStyle
)
9155 *aHaveFirstLetterStyle
=
9156 ShouldHaveFirstLetterStyle(aContent
, aStyleContext
);
9157 *aHaveFirstLineStyle
=
9158 ShouldHaveFirstLineStyle(aContent
, aStyleContext
);
9162 const nsCSSFrameConstructor::PseudoParentData
9163 nsCSSFrameConstructor::sPseudoParentData
[eParentTypeCount
] = {
9165 FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART
| FCDATA_SKIP_FRAMESET
|
9166 FCDATA_USE_CHILD_ITEMS
|
9167 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow
),
9168 &nsCSSFrameConstructor::ConstructTableCell
),
9169 &nsCSSAnonBoxes::tableCell
9172 FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART
| FCDATA_SKIP_FRAMESET
|
9173 FCDATA_USE_CHILD_ITEMS
|
9174 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup
),
9175 &nsCSSFrameConstructor::ConstructTableRow
),
9176 &nsCSSAnonBoxes::tableRow
9179 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_SKIP_FRAMESET
|
9180 FCDATA_DISALLOW_OUT_OF_FLOW
| FCDATA_USE_CHILD_ITEMS
|
9181 FCDATA_SKIP_ABSPOS_PUSH
|
9182 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
9183 NS_NewTableRowGroupFrame
),
9184 &nsCSSAnonBoxes::tableRowGroup
9187 FCDATA_DECL(FCDATA_IS_TABLE_PART
| FCDATA_SKIP_FRAMESET
|
9188 FCDATA_DISALLOW_OUT_OF_FLOW
| FCDATA_USE_CHILD_ITEMS
|
9189 FCDATA_SKIP_ABSPOS_PUSH
|
9190 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable
),
9191 NS_NewTableColGroupFrame
),
9192 &nsCSSAnonBoxes::tableColGroup
9195 FULL_CTOR_FCDATA(FCDATA_SKIP_FRAMESET
| FCDATA_USE_CHILD_ITEMS
,
9196 &nsCSSFrameConstructor::ConstructTable
),
9197 &nsCSSAnonBoxes::table
9202 * This function works as follows: we walk through the child list (aItems) and
9203 * find items that cannot have aParentFrame as their parent. We wrap
9204 * continuous runs of such items into a FrameConstructionItem for a frame that
9205 * gets them closer to their desired parents. For example, a run of non-row
9206 * children of a row-group will get wrapped in a row. When we later construct
9207 * the frame for this wrapper (in this case for the row), it'll be the correct
9208 * parent for the cells in the set of items we wrapped or we'll wrap cells
9209 * around everything else. At the end of this method, aItems is guaranteed to
9210 * contain only items for frames that can be direct kids of aParentFrame.
9213 nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState
& aState
,
9214 FrameConstructionItemList
& aItems
,
9215 nsIFrame
* aParentFrame
)
9217 ParentType ourParentType
= GetParentType(aParentFrame
);
9218 if (aItems
.AllWantParentType(ourParentType
)) {
9219 // Nothing to do here
9223 FCItemIterator
iter(aItems
);
9225 if (iter
.SkipItemsWantingParentType(ourParentType
)) {
9226 // Nothing else to do here; we're finished
9230 // Now we're pointing to the first child that wants a different parent
9233 // Now try to figure out what kids we can group together. We can generally
9234 // group everything that has a different desired parent type from us. Two
9235 // exceptions to this:
9236 // 1) If our parent type is table, we can't group columns with anything
9237 // else other than whitespace.
9238 // 2) Whitespace that lies between two things we can group which both want
9239 // a non-block parent should be dropped, even if we can't group them
9240 // with each other and even if the whitespace wants a parent of
9241 // ourParentType. Ends of the list count as things that don't want a
9242 // block parent (so that for example we'll drop a whitespace-only list).
9244 FCItemIterator
endIter(iter
); /* iterator to find the end of the group */
9245 ParentType groupingParentType
= endIter
.item().DesiredParentType();
9246 if (aItems
.AllWantParentType(groupingParentType
) &&
9247 groupingParentType
!= eTypeBlock
) {
9248 // Just group them all and be done with it. We need the check for
9249 // eTypeBlock here to catch the "all the items are whitespace" case
9253 // Locate the end of the group.
9255 // Keep track of the type the previous item wanted, in case we have to
9256 // deal with whitespace. Start it off with ourParentType, since that's
9257 // the last thing |iter| would have skipped over.
9258 ParentType prevParentType
= ourParentType
;
9260 /* Walk an iterator past any whitespace that we might be able to drop from the list */
9261 FCItemIterator
spaceEndIter(endIter
);
9262 if (prevParentType
!= eTypeBlock
&&
9263 !aParentFrame
->IsGeneratedContentFrame() &&
9264 spaceEndIter
.item().IsWhitespace(aState
)) {
9265 PRBool trailingSpaces
= spaceEndIter
.SkipWhitespace(aState
);
9267 // See whether we can drop the whitespace
9268 if (trailingSpaces
||
9269 spaceEndIter
.item().DesiredParentType() != eTypeBlock
) {
9270 PRBool updateStart
= (iter
== endIter
);
9271 endIter
.DeleteItemsTo(spaceEndIter
);
9272 NS_ASSERTION(trailingSpaces
== endIter
.IsDone(), "These should match");
9278 if (trailingSpaces
) {
9279 break; /* Found group end */
9283 // Update groupingParentType, since it might have been eTypeBlock
9284 // just because of the whitespace.
9285 groupingParentType
= iter
.item().DesiredParentType();
9290 // Now endIter points to a non-whitespace item or a non-droppable
9291 // whitespace item. In the latter case, if this is the end of the group
9292 // we'll traverse this whitespace again. But it'll all just be quick
9293 // DesiredParentType() checks which will match ourParentType (that's
9294 // what it means that this is the group end), so it's OK.
9295 prevParentType
= endIter
.item().DesiredParentType();
9296 if (prevParentType
== ourParentType
) {
9297 // End the group at endIter.
9301 if (ourParentType
== eTypeTable
&&
9302 (prevParentType
== eTypeColGroup
) !=
9303 (groupingParentType
== eTypeColGroup
)) {
9304 // Either we started with columns and now found something else, or vice
9305 // versa. In any case, end the grouping.
9309 // Include the whitespace we didn't drop (if any) in the group, since
9310 // this is not the end of the group. Note that this doesn't change
9311 // prevParentType, since if we didn't drop the whitespace then we ended
9312 // at something that wants a block parent.
9313 endIter
= spaceEndIter
;
9316 } while (!endIter
.IsDone());
9319 if (iter
== endIter
) {
9320 // Nothing to wrap here; just skipped some whitespace
9324 // Now group together all the items between iter and endIter. The right
9325 // parent type to use depends on ourParentType.
9326 ParentType wrapperType
;
9327 switch (ourParentType
) {
9329 wrapperType
= eTypeTable
;
9332 // The parent type for a cell is eTypeBlock, since that's what a cell
9333 // looks like to its kids.
9334 wrapperType
= eTypeBlock
;
9337 wrapperType
= eTypeRow
;
9340 // Either colgroup or rowgroup, depending on what we're grouping.
9341 wrapperType
= groupingParentType
== eTypeColGroup
?
9342 eTypeColGroup
: eTypeRowGroup
;
9345 NS_NOTREACHED("Colgroups should be suppresing non-col child items");
9349 const PseudoParentData
& pseudoData
= sPseudoParentData
[wrapperType
];
9350 nsIAtom
* pseudoType
= *pseudoData
.mPseudoType
;
9351 nsStyleContext
* parentStyle
= aParentFrame
->GetStyleContext();
9352 nsIContent
* parentContent
= aParentFrame
->GetContent();
9354 if (pseudoType
== nsCSSAnonBoxes::table
&&
9355 parentStyle
->GetStyleDisplay()->mDisplay
== NS_STYLE_DISPLAY_INLINE
) {
9356 pseudoType
= nsCSSAnonBoxes::inlineTable
;
9359 nsRefPtr
<nsStyleContext
> wrapperStyle
=
9360 mPresShell
->StyleSet()->ResolveAnonymousBoxStyle(pseudoType
, parentStyle
);
9361 FrameConstructionItem
* newItem
=
9362 new FrameConstructionItem(&pseudoData
.mFCData
,
9363 // Use the content of our parent frame
9365 // Lie about the tag; it doesn't matter anyway
9367 // The namespace does matter, however; it needs
9368 // to match that of our first child item to
9369 // match the old behavior
9370 iter
.item().mNameSpaceID
,
9371 // no pending binding
9373 wrapperStyle
.forget(),
9377 return NS_ERROR_OUT_OF_MEMORY
;
9380 // Here we're cheating a tad... technically, table-internal items should be
9381 // inline if aParentFrame is inline, but they'll get wrapped in an
9382 // inline-table in the end, so it'll all work out. In any case, arguably
9383 // we don't need to maintain this state at this point... but it's better
9385 newItem
->mIsAllInline
= newItem
->mHasInlineEnds
=
9386 newItem
->mStyleContext
->GetStyleDisplay()->IsInlineOutside();
9388 // Table pseudo frames always induce line boundaries around their
9390 newItem
->mChildItems
.SetLineBoundaryAtStart(PR_TRUE
);
9391 newItem
->mChildItems
.SetLineBoundaryAtEnd(PR_TRUE
);
9392 // The parent of the items in aItems is also the parent of the items
9394 newItem
->mChildItems
.SetParentHasNoXBLChildren(
9395 aItems
.ParentHasNoXBLChildren());
9397 // Eat up all items between |iter| and |endIter| and put them in our wrapper
9398 // Advances |iter| to point to |endIter|.
9399 iter
.AppendItemsToList(endIter
, newItem
->mChildItems
);
9401 iter
.InsertItem(newItem
);
9403 // Now |iter| points to the item that was the first one we didn't wrap;
9404 // loop and see whether we need to skip it or wrap it in something
9406 } while (!iter
.IsDone());
9412 nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState
& aState
,
9413 FrameConstructionItemList
& aItems
,
9414 nsIFrame
* aParentFrame
,
9415 nsFrameItems
& aFrameItems
)
9417 nsresult rv
= CreateNeededTablePseudos(aState
, aItems
, aParentFrame
);
9418 NS_ENSURE_SUCCESS(rv
, rv
);
9421 for (FCItemIterator
iter(aItems
); !iter
.IsDone(); iter
.Next()) {
9422 NS_ASSERTION(iter
.item().DesiredParentType() == GetParentType(aParentFrame
),
9423 "Needed pseudos didn't get created; expect bad things");
9427 for (FCItemIterator
iter(aItems
); !iter
.IsDone(); iter
.Next()) {
9428 rv
= ConstructFramesFromItem(aState
, iter
, aParentFrame
, aFrameItems
);
9429 NS_ENSURE_SUCCESS(rv
, rv
);
9432 NS_ASSERTION(!aState
.mHavePendingPopupgroup
,
9433 "Should have proccessed it by now");
9439 nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState
& aState
,
9440 nsIContent
* aContent
,
9441 nsStyleContext
* aStyleContext
,
9443 const PRBool aCanHaveGeneratedContent
,
9444 nsFrameItems
& aFrameItems
,
9445 const PRBool aAllowBlockStyles
,
9446 PendingBinding
* aPendingBinding
)
9448 NS_PRECONDITION(aFrame
, "Must have parent frame here");
9449 NS_PRECONDITION(aFrame
->GetContentInsertionFrame() == aFrame
,
9450 "Parent frame in ProcessChildren should be its own "
9451 "content insertion frame");
9453 // XXXbz ideally, this would do all the pushing of various
9454 // containing blocks as needed, so callers don't have to do it...
9456 PRBool haveFirstLetterStyle
= PR_FALSE
, haveFirstLineStyle
= PR_FALSE
;
9457 if (aAllowBlockStyles
) {
9458 ShouldHaveSpecialBlockStyle(aContent
, aStyleContext
, &haveFirstLetterStyle
,
9459 &haveFirstLineStyle
);
9462 // The logic here needs to match the logic in GetFloatContainingBlock()
9463 nsFrameConstructorSaveState floatSaveState
;
9464 if (aFrame
->IsFrameOfType(nsIFrame::eMathML
) ||
9465 aFrame
->IsBoxFrame()) {
9466 aState
.PushFloatContainingBlock(nsnull
, floatSaveState
);
9467 } else if (aFrame
->IsFloatContainingBlock()) {
9468 aState
.PushFloatContainingBlock(aFrame
, floatSaveState
);
9471 nsFrameConstructorState::PendingBindingAutoPusher
pusher(aState
,
9474 FrameConstructionItemList itemsToConstruct
;
9475 nsresult rv
= NS_OK
;
9477 // If we have first-letter or first-line style then frames can get
9478 // moved around so don't set these flags.
9479 if (aAllowBlockStyles
&& !haveFirstLetterStyle
&& !haveFirstLineStyle
) {
9480 itemsToConstruct
.SetLineBoundaryAtStart(PR_TRUE
);
9481 itemsToConstruct
.SetLineBoundaryAtEnd(PR_TRUE
);
9484 // Create any anonymous frames we need here. This must happen before the
9485 // non-anonymous children are processed to ensure that popups are never
9486 // constructed before the popupset.
9487 nsAutoTArray
<nsIContent
*, 4> anonymousItems
;
9488 GetAnonymousContent(aContent
, aFrame
, anonymousItems
);
9489 for (PRUint32 i
= 0; i
< anonymousItems
.Length(); ++i
) {
9491 nsIAnonymousContentCreator
* creator
= do_QueryFrame(aFrame
);
9492 NS_ASSERTION(!creator
|| !creator
->CreateFrameFor(anonymousItems
[i
]),
9493 "If you need to use CreateFrameFor, you need to call "
9494 "CreateAnonymousFrames manually and not follow the standard "
9495 "ProcessChildren() codepath for this frame");
9497 AddFrameConstructionItems(aState
, anonymousItems
[i
], PR_TRUE
, aFrame
,
9501 if (!aFrame
->IsLeaf()) {
9502 // :before/:after content should have the same style context parent
9504 // Note that we don't use this style context for looking up things like
9505 // special block styles because in some cases involving table pseudo-frames
9506 // it has nothing to do with the parent frame's desired behavior.
9507 nsStyleContext
* styleContext
;
9509 if (aCanHaveGeneratedContent
) {
9511 nsFrame::CorrectStyleParentFrame(aFrame
, nsnull
)->GetStyleContext();
9512 // Probe for generated content before
9513 CreateGeneratedContentItem(aState
, aFrame
, aContent
, styleContext
,
9514 nsCSSPseudoElements::ePseudo_before
,
9518 ChildIterator iter
, last
;
9519 for (ChildIterator::Init(aContent
, &iter
, &last
);
9522 nsIContent
* child
= *iter
;
9523 // Frame construction item construction should not post
9524 // restyles, so removing restyle flags here is safe.
9525 if (child
->IsElement()) {
9526 child
->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS
);
9528 AddFrameConstructionItems(aState
, child
, iter
.XBLInvolved(), aFrame
,
9531 itemsToConstruct
.SetParentHasNoXBLChildren(!iter
.XBLInvolved());
9533 if (aCanHaveGeneratedContent
) {
9534 // Probe for generated content after
9535 CreateGeneratedContentItem(aState
, aFrame
, aContent
, styleContext
,
9536 nsCSSPseudoElements::ePseudo_after
,
9540 ClearLazyBits(aContent
->GetFirstChild(), nsnull
);
9543 rv
= ConstructFramesFromItemList(aState
, itemsToConstruct
, aFrame
,
9545 NS_ENSURE_SUCCESS(rv
, rv
);
9547 NS_ASSERTION(!aAllowBlockStyles
|| !aFrame
->IsBoxFrame(),
9548 "can't be both block and box");
9550 if (haveFirstLetterStyle
) {
9551 rv
= WrapFramesInFirstLetterFrame(aContent
, aFrame
, aFrameItems
);
9553 if (haveFirstLineStyle
) {
9554 rv
= WrapFramesInFirstLineFrame(aState
, aContent
, aFrame
, nsnull
,
9558 // We might end up with first-line frames that change
9559 // AnyKidsNeedBlockParent() without changing itemsToConstruct, but that
9560 // should never happen for cases whan aFrame->IsBoxFrame().
9561 NS_ASSERTION(!haveFirstLineStyle
|| !aFrame
->IsBoxFrame(),
9562 "Shouldn't have first-line style if we're a box");
9563 NS_ASSERTION(!aFrame
->IsBoxFrame() ||
9564 itemsToConstruct
.AnyItemsNeedBlockParent() ==
9565 (AnyKidsNeedBlockParent(aFrameItems
.FirstChild()) != nsnull
),
9566 "Something went awry in our block parent calculations");
9568 if (aFrame
->IsBoxFrame() && itemsToConstruct
.AnyItemsNeedBlockParent()) {
9569 // XXXbz we could do this on the FrameConstructionItemList level,
9570 // no? And if we cared we could look through the item list
9571 // instead of groveling through the framelist here..
9572 nsIContent
*badKid
= AnyKidsNeedBlockParent(aFrameItems
.FirstChild());
9573 nsDependentAtomString
parentTag(aContent
->Tag()), kidTag(badKid
->Tag());
9574 const PRUnichar
* params
[] = { parentTag
.get(), kidTag
.get() };
9575 nsStyleContext
*frameStyleContext
= aFrame
->GetStyleContext();
9576 const nsStyleDisplay
*display
= frameStyleContext
->GetStyleDisplay();
9577 const char *message
=
9578 (display
->mDisplay
== NS_STYLE_DISPLAY_INLINE_BOX
)
9579 ? "NeededToWrapXULInlineBox" : "NeededToWrapXUL";
9580 nsContentUtils::ReportToConsole(nsContentUtils::eXUL_PROPERTIES
,
9582 params
, NS_ARRAY_LENGTH(params
),
9583 mDocument
->GetDocumentURI(),
9584 EmptyString(), 0, 0, // not useful
9585 nsIScriptError::warningFlag
,
9586 "FrameConstructor");
9588 nsRefPtr
<nsStyleContext
> blockSC
= mPresShell
->StyleSet()->
9589 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozXULAnonymousBlock
,
9591 nsIFrame
*blockFrame
= NS_NewBlockFrame(mPresShell
, blockSC
);
9592 // We might, in theory, want to set NS_BLOCK_FLOAT_MGR and
9593 // NS_BLOCK_MARGIN_ROOT, but I think it's a bad idea given that
9594 // a real block placed here wouldn't get those set on it.
9596 InitAndRestoreFrame(aState
, aContent
, aFrame
, nsnull
,
9597 blockFrame
, PR_FALSE
);
9599 NS_ASSERTION(!blockFrame
->HasView(), "need to do view reparenting");
9600 ReparentFrames(aState
.mFrameManager
, blockFrame
, aFrameItems
);
9602 blockFrame
->SetInitialChildList(nsnull
, aFrameItems
);
9603 NS_ASSERTION(aFrameItems
.IsEmpty(), "How did that happen?");
9604 aFrameItems
.Clear();
9605 aFrameItems
.AddChild(blockFrame
);
9607 aFrame
->AddStateBits(NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK
);
9613 //----------------------------------------------------------------------
9615 // Support for :first-line style
9617 // Special routine to handle placing a list of frames into a block
9618 // frame that has first-line style. The routine ensures that the first
9619 // collection of inline frames end up in a first-line frame.
9620 // NOTE: aState may have containing block information related to a
9621 // different part of the frame tree than where the first line occurs.
9622 // In particular aState may be set up for where ContentInserted or
9623 // ContentAppended is inserting content, which may be some
9624 // non-first-in-flow continuation of the block to which the first-line
9625 // belongs. So this function needs to be careful about how it uses
9628 nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
9629 nsFrameConstructorState
& aState
,
9630 nsIContent
* aBlockContent
,
9631 nsIFrame
* aBlockFrame
,
9632 nsIFrame
* aLineFrame
,
9633 nsFrameItems
& aFrameItems
)
9635 nsresult rv
= NS_OK
;
9637 // Find the part of aFrameItems that we want to put in the first-line
9638 nsFrameList::FrameLinkEnumerator
link(aFrameItems
);
9639 while (!link
.AtEnd() && IsInlineOutside(link
.NextFrame())) {
9643 nsFrameList firstLineChildren
= aFrameItems
.ExtractHead(link
);
9645 if (firstLineChildren
.IsEmpty()) {
9646 // Nothing is supposed to go into the first-line; nothing to do
9651 // Create line frame
9652 nsStyleContext
* parentStyle
=
9653 nsFrame::CorrectStyleParentFrame(aBlockFrame
,
9654 nsCSSPseudoElements::firstLine
)->
9656 nsRefPtr
<nsStyleContext
> firstLineStyle
= GetFirstLineStyle(aBlockContent
,
9659 aLineFrame
= NS_NewFirstLineFrame(mPresShell
, firstLineStyle
);
9662 // Initialize the line frame
9663 rv
= InitAndRestoreFrame(aState
, aBlockContent
, aBlockFrame
, nsnull
,
9666 // The lineFrame will be the block's first child; the rest of the
9667 // frame list (after lastInlineFrame) will be the second and
9668 // subsequent children; insert lineFrame into aFrameItems.
9669 aFrameItems
.InsertFrame(nsnull
, nsnull
, aLineFrame
);
9671 NS_ASSERTION(aLineFrame
->GetStyleContext() == firstLineStyle
,
9672 "Bogus style context on line frame");
9677 // Give the inline frames to the lineFrame <b>after</b> reparenting them
9678 ReparentFrames(aState
.mFrameManager
, aLineFrame
, firstLineChildren
);
9679 if (aLineFrame
->GetChildList(nsnull
).IsEmpty() &&
9680 (aLineFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
)) {
9681 aLineFrame
->SetInitialChildList(nsnull
, firstLineChildren
);
9683 aState
.mFrameManager
->AppendFrames(aLineFrame
, nsnull
, firstLineChildren
);
9687 rv
= NS_ERROR_OUT_OF_MEMORY
;
9693 // Special routine to handle appending a new frame to a block frame's
9694 // child list. Takes care of placing the new frame into the right
9695 // place when first-line style is present.
9697 nsCSSFrameConstructor::AppendFirstLineFrames(
9698 nsFrameConstructorState
& aState
,
9699 nsIContent
* aBlockContent
,
9700 nsIFrame
* aBlockFrame
,
9701 nsFrameItems
& aFrameItems
)
9703 // It's possible that aBlockFrame needs to have a first-line frame
9704 // created because it doesn't currently have any children.
9705 const nsFrameList
& blockKids
= aBlockFrame
->GetChildList(nsnull
);
9706 if (blockKids
.IsEmpty()) {
9707 return WrapFramesInFirstLineFrame(aState
, aBlockContent
,
9708 aBlockFrame
, nsnull
, aFrameItems
);
9711 // Examine the last block child - if it's a first-line frame then
9712 // appended frames need special treatment.
9713 nsIFrame
* lastBlockKid
= blockKids
.LastChild();
9714 if (lastBlockKid
->GetType() != nsGkAtoms::lineFrame
) {
9715 // No first-line frame at the end of the list, therefore there is
9716 // an intervening block between any first-line frame the frames
9717 // we are appending. Therefore, we don't need any special
9718 // treatment of the appended frames.
9722 return WrapFramesInFirstLineFrame(aState
, aBlockContent
, aBlockFrame
,
9723 lastBlockKid
, aFrameItems
);
9726 // Special routine to handle inserting a new frame into a block
9727 // frame's child list. Takes care of placing the new frame into the
9728 // right place when first-line style is present.
9730 nsCSSFrameConstructor::InsertFirstLineFrames(
9731 nsFrameConstructorState
& aState
,
9732 nsIContent
* aContent
,
9733 nsIFrame
* aBlockFrame
,
9734 nsIFrame
** aParentFrame
,
9735 nsIFrame
* aPrevSibling
,
9736 nsFrameItems
& aFrameItems
)
9738 nsresult rv
= NS_OK
;
9739 // XXXbz If you make this method actually do something, check to
9740 // make sure that the caller is passing what you expect. In
9741 // particular, which content is aContent? And audit the rest of
9742 // this code too; it makes bogus assumptions and may not build.
9744 nsIFrame
* parentFrame
= *aParentFrame
;
9745 nsIFrame
* newFrame
= aFrameItems
.childList
;
9746 PRBool isInline
= IsInlineOutside(newFrame
);
9748 if (!aPrevSibling
) {
9749 // Insertion will become the first frame. Two cases: we either
9750 // already have a first-line frame or we don't.
9751 nsIFrame
* firstBlockKid
= aBlockFrame
->GetFirstChild(nsnull
);
9752 if (firstBlockKid
->GetType() == nsGkAtoms::lineFrame
) {
9753 // We already have a first-line frame
9754 nsIFrame
* lineFrame
= firstBlockKid
;
9757 // Easy case: the new inline frame will go into the lineFrame.
9758 ReparentFrame(aState
.mFrameManager
, lineFrame
, newFrame
);
9759 aState
.mFrameManager
->InsertFrames(lineFrame
, nsnull
, nsnull
,
9762 // Since the frame is going into the lineFrame, don't let it
9763 // go into the block too.
9764 aFrameItems
.childList
= nsnull
;
9765 aFrameItems
.lastChild
= nsnull
;
9768 // Harder case: We are about to insert a block level element
9769 // before the first-line frame.
9770 // XXX need a method to steal away frames from the line-frame
9774 // We do not have a first-line frame
9776 // We now need a first-line frame to contain the inline frame.
9777 nsIFrame
* lineFrame
= NS_NewFirstLineFrame(firstLineStyle
);
9779 rv
= NS_ERROR_OUT_OF_MEMORY
;
9782 if (NS_SUCCEEDED(rv
)) {
9783 // Lookup first-line style context
9784 nsStyleContext
* parentStyle
=
9785 nsFrame::CorrectStyleParentFrame(aBlockFrame
,
9786 nsCSSPseudoElements::firstLine
)->
9788 nsRefPtr
<nsStyleContext
> firstLineStyle
=
9789 GetFirstLineStyle(aContent
, parentStyle
);
9791 // Initialize the line frame
9792 rv
= InitAndRestoreFrame(aState
, aContent
, aBlockFrame
,
9795 // Make sure the caller inserts the lineFrame into the
9796 // blocks list of children.
9797 aFrameItems
.childList
= lineFrame
;
9798 aFrameItems
.lastChild
= lineFrame
;
9800 // Give the inline frames to the lineFrame <b>after</b>
9802 NS_ASSERTION(lineFrame
->GetStyleContext() == firstLineStyle
,
9803 "Bogus style context on line frame");
9804 ReparentFrame(aPresContext
, lineFrame
, newFrame
);
9805 lineFrame
->SetInitialChildList(nsnull
, newFrame
);
9809 // Easy case: the regular insertion logic can insert the new
9810 // frame because it's a block frame.
9815 // Insertion will not be the first frame.
9816 nsIFrame
* prevSiblingParent
= aPrevSibling
->GetParent();
9817 if (prevSiblingParent
== aBlockFrame
) {
9818 // Easy case: The prev-siblings parent is the block
9819 // frame. Therefore the prev-sibling is not currently in a
9820 // line-frame. Therefore the new frame which is going after it,
9821 // regardless of type, is not going into a line-frame.
9824 // If the prevSiblingParent is not the block-frame then it must
9825 // be a line-frame (if it were a letter-frame, that logic would
9826 // already have adjusted the prev-sibling to be the
9829 // Easy case: the insertion can go where the caller thinks it
9830 // should go (which is into prevSiblingParent).
9833 // Block elements don't end up in line-frames, therefore
9834 // change the insertion point to aBlockFrame. However, there
9835 // might be more inline elements following aPrevSibling that
9836 // need to be pulled out of the line-frame and become children
9838 nsIFrame
* nextSibling
= aPrevSibling
->GetNextSibling();
9839 nsIFrame
* nextLineFrame
= prevSiblingParent
->GetNextInFlow();
9840 if (nextSibling
|| nextLineFrame
) {
9841 // Oy. We have work to do. Create a list of the new frames
9842 // that are going into the block by stripping them away from
9843 // the line-frame(s).
9845 nsLineFrame
* lineFrame
= (nsLineFrame
*) prevSiblingParent
;
9846 nsFrameList tail
= lineFrame
->StealFramesAfter(aPrevSibling
);
9847 // XXX do something with 'tail'
9850 nsLineFrame
* nextLineFrame
= (nsLineFrame
*) lineFrame
;
9852 nextLineFrame
= nextLineFrame
->GetNextInFlow();
9853 if (!nextLineFrame
) {
9856 nsIFrame
* kids
= nextLineFrame
->GetFirstChild(nsnull
);
9860 // We got lucky: aPrevSibling was the last inline frame in
9862 ReparentFrame(aState
.mFrameManager
, aBlockFrame
, newFrame
);
9863 aState
.mFrameManager
->InsertFrames(aBlockFrame
, nsnull
,
9864 prevSiblingParent
, newFrame
);
9865 aFrameItems
.childList
= nsnull
;
9866 aFrameItems
.lastChild
= nsnull
;
9876 //----------------------------------------------------------------------
9878 // First-letter support
9880 // Determine how many characters in the text fragment apply to the
9883 FirstLetterCount(const nsTextFragment
* aFragment
)
9886 PRInt32 firstLetterLength
= 0;
9887 PRBool done
= PR_FALSE
;
9889 PRInt32 i
, n
= aFragment
->GetLength();
9890 for (i
= 0; i
< n
; i
++) {
9891 PRUnichar ch
= aFragment
->CharAt(i
);
9892 if (XP_IS_SPACE(ch
)) {
9893 if (firstLetterLength
) {
9901 if ((ch
== '\'') || (ch
== '\"')) {
9902 if (firstLetterLength
) {
9907 firstLetterLength
= 1;
9920 NeedFirstLetterContinuation(nsIContent
* aContent
)
9922 NS_PRECONDITION(aContent
, "null ptr");
9924 PRBool result
= PR_FALSE
;
9926 const nsTextFragment
* frag
= aContent
->GetText();
9928 PRInt32 flc
= FirstLetterCount(frag
);
9929 PRInt32 tl
= frag
->GetLength();
9938 static PRBool
IsFirstLetterContent(nsIContent
* aContent
)
9940 return aContent
->TextLength() &&
9941 !aContent
->TextIsOnlyWhitespace();
9945 * Create a letter frame, only make it a floating frame.
9948 nsCSSFrameConstructor::CreateFloatingLetterFrame(
9949 nsFrameConstructorState
& aState
,
9950 nsIFrame
* aBlockFrame
,
9951 nsIContent
* aTextContent
,
9952 nsIFrame
* aTextFrame
,
9953 nsIContent
* aBlockContent
,
9954 nsIFrame
* aParentFrame
,
9955 nsStyleContext
* aStyleContext
,
9956 nsFrameItems
& aResult
)
9958 // Create the first-letter-frame
9960 nsIFrame
* letterFrame
;
9961 nsStyleSet
*styleSet
= mPresShell
->StyleSet();
9963 letterFrame
= NS_NewFirstLetterFrame(mPresShell
, aStyleContext
);
9964 // We don't want to use a text content for a non-text frame (because we want
9965 // its primary frame to be a text frame). So use its parent for the
9967 nsIContent
* letterContent
= aTextContent
->GetParent();
9968 nsIFrame
* containingBlock
= aState
.GetGeometricParent(
9969 aStyleContext
->GetStyleDisplay(), aParentFrame
);
9970 InitAndRestoreFrame(aState
, letterContent
, containingBlock
, nsnull
,
9973 // Init the text frame to refer to the letter frame. Make sure we
9974 // get a proper style context for it (the one passed in is for the
9975 // letter frame and will have the float property set on it; the text
9976 // frame shouldn't have that set).
9977 nsRefPtr
<nsStyleContext
> textSC
;
9978 textSC
= styleSet
->ResolveStyleForNonElement(aStyleContext
);
9979 aTextFrame
->SetStyleContextWithoutNotification(textSC
);
9980 InitAndRestoreFrame(aState
, aTextContent
, letterFrame
, nsnull
, aTextFrame
);
9982 // And then give the text frame to the letter frame
9983 SetInitialSingleChild(letterFrame
, aTextFrame
);
9985 // See if we will need to continue the text frame (does it contain
9986 // more than just the first-letter text or not?) If it does, then we
9987 // create (in advance) a continuation frame for it.
9988 nsIFrame
* nextTextFrame
= nsnull
;
9989 if (NeedFirstLetterContinuation(aTextContent
)) {
9990 // Create continuation
9991 rv
= CreateContinuingFrame(aState
.mPresContext
, aTextFrame
, aParentFrame
,
9993 if (NS_FAILED(rv
)) {
9994 letterFrame
->Destroy();
9997 // Repair the continuations style context
9998 nsStyleContext
* parentStyleContext
= aStyleContext
->GetParent();
9999 if (parentStyleContext
) {
10000 nsRefPtr
<nsStyleContext
> newSC
;
10001 newSC
= styleSet
->ResolveStyleForNonElement(parentStyleContext
);
10003 nextTextFrame
->SetStyleContext(newSC
);
10008 NS_ASSERTION(aResult
.IsEmpty(), "aResult should be an empty nsFrameItems!");
10009 // Put the new float before any of the floats in the block we're doing
10010 // first-letter for, that is, before any floats whose parent is
10011 // containingBlock.
10012 nsFrameList::FrameLinkEnumerator
link(aState
.mFloatedItems
);
10013 while (!link
.AtEnd() && link
.NextFrame()->GetParent() != containingBlock
) {
10017 rv
= aState
.AddChild(letterFrame
, aResult
, letterContent
, aStyleContext
,
10018 aParentFrame
, PR_FALSE
, PR_TRUE
, PR_FALSE
, PR_TRUE
,
10021 if (nextTextFrame
) {
10022 if (NS_FAILED(rv
)) {
10023 nextTextFrame
->Destroy();
10025 aResult
.AddChild(nextTextFrame
);
10031 * Create a new letter frame for aTextFrame. The letter frame will be
10032 * a child of aParentFrame.
10035 nsCSSFrameConstructor::CreateLetterFrame(nsIFrame
* aBlockFrame
,
10036 nsIFrame
* aBlockContinuation
,
10037 nsIContent
* aTextContent
,
10038 nsIFrame
* aParentFrame
,
10039 nsFrameItems
& aResult
)
10041 NS_PRECONDITION(aTextContent
->IsNodeOfType(nsINode::eTEXT
),
10042 "aTextContent isn't text");
10043 NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame
),
10044 "Not a block frame?");
10046 // Get style context for the first-letter-frame
10047 nsStyleContext
* parentStyleContext
=
10048 nsFrame::CorrectStyleParentFrame(aParentFrame
,
10049 nsCSSPseudoElements::firstLetter
)->
10052 // Use content from containing block so that we can actually
10053 // find a matching style rule.
10054 nsIContent
* blockContent
= aBlockFrame
->GetContent();
10056 // Create first-letter style rule
10057 nsRefPtr
<nsStyleContext
> sc
= GetFirstLetterStyle(blockContent
,
10058 parentStyleContext
);
10060 nsRefPtr
<nsStyleContext
> textSC
;
10061 textSC
= mPresShell
->StyleSet()->ResolveStyleForNonElement(sc
);
10063 // Create a new text frame (the original one will be discarded)
10064 // pass a temporary stylecontext, the correct one will be set
10065 // later. Start off by unsetting the primary frame for
10066 // aTextContent, so it's no longer pointing to the to-be-destroyed
10068 // XXXbz it would be really nice to destroy the old frame _first_,
10069 // then create the new one, so we could avoid this hack.
10070 aTextContent
->SetPrimaryFrame(nsnull
);
10071 nsIFrame
* textFrame
= NS_NewTextFrame(mPresShell
, textSC
);
10073 NS_ASSERTION(aBlockContinuation
== GetFloatContainingBlock(aParentFrame
),
10074 "Containing block is confused");
10075 nsFrameConstructorState
state(mPresShell
, mFixedContainingBlock
,
10076 GetAbsoluteContainingBlock(aParentFrame
),
10077 aBlockContinuation
);
10079 // Create the right type of first-letter frame
10080 const nsStyleDisplay
* display
= sc
->GetStyleDisplay();
10081 if (display
->IsFloating()) {
10082 // Make a floating first-letter frame
10083 CreateFloatingLetterFrame(state
, aBlockFrame
, aTextContent
, textFrame
,
10084 blockContent
, aParentFrame
, sc
, aResult
);
10087 // Make an inflow first-letter frame
10088 nsIFrame
* letterFrame
= NS_NewFirstLetterFrame(mPresShell
, sc
);
10091 // Initialize the first-letter-frame. We don't want to use a text
10092 // content for a non-text frame (because we want its primary frame to
10093 // be a text frame). So use its parent for the first-letter.
10094 nsIContent
* letterContent
= aTextContent
->GetParent();
10095 letterFrame
->Init(letterContent
, aParentFrame
, nsnull
);
10097 InitAndRestoreFrame(state
, aTextContent
, letterFrame
, nsnull
,
10100 SetInitialSingleChild(letterFrame
, textFrame
);
10102 aResult
.AddChild(letterFrame
);
10103 NS_ASSERTION(!aBlockFrame
->GetPrevContinuation(),
10104 "should have the first continuation here");
10105 aBlockFrame
->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD
);
10108 aTextContent
->SetPrimaryFrame(textFrame
);
10115 nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
10116 nsIContent
* aBlockContent
,
10117 nsIFrame
* aBlockFrame
,
10118 nsFrameItems
& aBlockFrames
)
10120 nsresult rv
= NS_OK
;
10122 aBlockFrame
->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE
);
10124 nsIFrame
* parentFrame
= nsnull
;
10125 nsIFrame
* textFrame
= nsnull
;
10126 nsIFrame
* prevFrame
= nsnull
;
10127 nsFrameItems letterFrames
;
10128 PRBool stopLooking
= PR_FALSE
;
10129 rv
= WrapFramesInFirstLetterFrame(aBlockFrame
, aBlockFrame
, aBlockFrame
,
10130 aBlockFrames
.FirstChild(),
10131 &parentFrame
, &textFrame
, &prevFrame
,
10132 letterFrames
, &stopLooking
);
10133 if (NS_FAILED(rv
)) {
10137 if (parentFrame
== aBlockFrame
) {
10138 // Take textFrame out of the block's frame list and substitute the
10139 // letter frame(s) instead.
10140 aBlockFrames
.DestroyFrame(textFrame
);
10141 aBlockFrames
.InsertFrames(nsnull
, prevFrame
, letterFrames
);
10144 // Take the old textFrame out of the inline parent's child list
10145 mPresShell
->FrameManager()->RemoveFrame(nsnull
, textFrame
);
10147 // Insert in the letter frame(s)
10148 parentFrame
->InsertFrames(nsnull
, prevFrame
, letterFrames
);
10156 nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
10157 nsIFrame
* aBlockFrame
,
10158 nsIFrame
* aBlockContinuation
,
10159 nsIFrame
* aParentFrame
,
10160 nsIFrame
* aParentFrameList
,
10161 nsIFrame
** aModifiedParent
,
10162 nsIFrame
** aTextFrame
,
10163 nsIFrame
** aPrevFrame
,
10164 nsFrameItems
& aLetterFrames
,
10165 PRBool
* aStopLooking
)
10167 nsresult rv
= NS_OK
;
10169 nsIFrame
* prevFrame
= nsnull
;
10170 nsIFrame
* frame
= aParentFrameList
;
10173 nsIFrame
* nextFrame
= frame
->GetNextSibling();
10175 nsIAtom
* frameType
= frame
->GetType();
10176 if (nsGkAtoms::textFrame
== frameType
) {
10177 // Wrap up first-letter content in a letter frame
10178 nsIContent
* textContent
= frame
->GetContent();
10179 if (IsFirstLetterContent(textContent
)) {
10180 // Create letter frame to wrap up the text
10181 rv
= CreateLetterFrame(aBlockFrame
, aBlockContinuation
, textContent
,
10182 aParentFrame
, aLetterFrames
);
10183 if (NS_FAILED(rv
)) {
10187 // Provide adjustment information for parent
10188 *aModifiedParent
= aParentFrame
;
10189 *aTextFrame
= frame
;
10190 *aPrevFrame
= prevFrame
;
10191 *aStopLooking
= PR_TRUE
;
10195 else if (IsInlineFrame(frame
) && frameType
!= nsGkAtoms::brFrame
) {
10196 nsIFrame
* kids
= frame
->GetFirstChild(nsnull
);
10197 WrapFramesInFirstLetterFrame(aBlockFrame
, aBlockContinuation
, frame
,
10198 kids
, aModifiedParent
, aTextFrame
,
10199 aPrevFrame
, aLetterFrames
, aStopLooking
);
10200 if (*aStopLooking
) {
10205 // This will stop us looking to create more letter frames. For
10206 // example, maybe the frame-type is "letterFrame" or
10207 // "placeholderFrame". This keeps us from creating extra letter
10208 // frames, and also prevents us from creating letter frames when
10209 // the first real content child of a block is not text (e.g. an
10210 // image, hr, etc.)
10211 *aStopLooking
= PR_TRUE
;
10223 nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
10224 nsPresContext
* aPresContext
,
10225 nsIPresShell
* aPresShell
,
10226 nsFrameManager
* aFrameManager
,
10227 nsIFrame
* aBlockFrame
,
10228 PRBool
* aStopLooking
)
10230 // First look for the float frame that is a letter frame
10231 nsIFrame
* floatFrame
= aBlockFrame
->GetFirstChild(nsGkAtoms::floatList
);
10232 while (floatFrame
) {
10233 // See if we found a floating letter frame
10234 if (nsGkAtoms::letterFrame
== floatFrame
->GetType()) {
10237 floatFrame
= floatFrame
->GetNextSibling();
10244 // Take the text frame away from the letter frame (so it isn't
10245 // destroyed when we destroy the letter frame).
10246 nsIFrame
* textFrame
= floatFrame
->GetFirstChild(nsnull
);
10251 // Discover the placeholder frame for the letter frame
10252 nsIFrame
* parentFrame
;
10253 nsPlaceholderFrame
* placeholderFrame
=
10254 aFrameManager
->GetPlaceholderFrameFor(floatFrame
);
10256 if (!placeholderFrame
) {
10257 // Somethings really wrong
10260 parentFrame
= placeholderFrame
->GetParent();
10261 if (!parentFrame
) {
10262 // Somethings really wrong
10266 // Create a new text frame with the right style context that maps
10267 // all of the content that was previously part of the letter frame
10268 // (and probably continued elsewhere).
10269 nsStyleContext
* parentSC
= parentFrame
->GetStyleContext();
10273 nsIContent
* textContent
= textFrame
->GetContent();
10274 if (!textContent
) {
10277 nsRefPtr
<nsStyleContext
> newSC
;
10278 newSC
= aPresShell
->StyleSet()->ResolveStyleForNonElement(parentSC
);
10282 nsIFrame
* newTextFrame
= NS_NewTextFrame(aPresShell
, newSC
);
10283 if (NS_UNLIKELY(!newTextFrame
)) {
10284 return NS_ERROR_OUT_OF_MEMORY
;;
10286 newTextFrame
->Init(textContent
, parentFrame
, nsnull
);
10288 // Destroy the old text frame's continuations (the old text frame
10289 // will be destroyed when its letter frame is destroyed).
10290 nsIFrame
* frameToDelete
= textFrame
->GetLastContinuation();
10291 while (frameToDelete
!= textFrame
) {
10292 nsIFrame
* nextFrameToDelete
= frameToDelete
->GetPrevContinuation();
10293 aFrameManager
->RemoveFrame(nsnull
, frameToDelete
);
10294 frameToDelete
= nextFrameToDelete
;
10297 nsIFrame
* prevSibling
= placeholderFrame
->GetPrevSibling();
10299 // Now that everything is set...
10300 #ifdef NOISY_FIRST_LETTER
10301 printf("RemoveFloatingFirstLetterFrames: textContent=%p oldTextFrame=%p newTextFrame=%p\n",
10302 textContent
.get(), textFrame
, newTextFrame
);
10305 // Remove placeholder frame and the float
10306 aFrameManager
->RemoveFrame(nsnull
, placeholderFrame
);
10308 // Now that the old frames are gone, we can start pointing to our
10309 // new primary frame.
10310 textContent
->SetPrimaryFrame(newTextFrame
);
10312 // Insert text frame in its place
10313 nsFrameList
textList(newTextFrame
, newTextFrame
);
10314 aFrameManager
->InsertFrames(parentFrame
, nsnull
, prevSibling
, textList
);
10320 nsCSSFrameConstructor::RemoveFirstLetterFrames(nsPresContext
* aPresContext
,
10321 nsIPresShell
* aPresShell
,
10322 nsFrameManager
* aFrameManager
,
10324 nsIFrame
* aBlockFrame
,
10325 PRBool
* aStopLooking
)
10327 nsIFrame
* prevSibling
= nsnull
;
10328 nsIFrame
* kid
= aFrame
->GetFirstChild(nsnull
);
10331 if (nsGkAtoms::letterFrame
== kid
->GetType()) {
10332 // Bingo. Found it. First steal away the text frame.
10333 nsIFrame
* textFrame
= kid
->GetFirstChild(nsnull
);
10338 // Create a new textframe
10339 nsStyleContext
* parentSC
= aFrame
->GetStyleContext();
10343 nsIContent
* textContent
= textFrame
->GetContent();
10344 if (!textContent
) {
10347 nsRefPtr
<nsStyleContext
> newSC
;
10348 newSC
= aPresShell
->StyleSet()->ResolveStyleForNonElement(parentSC
);
10352 textFrame
= NS_NewTextFrame(aPresShell
, newSC
);
10353 textFrame
->Init(textContent
, aFrame
, nsnull
);
10355 // Next rip out the kid and replace it with the text frame
10356 aFrameManager
->RemoveFrame(nsnull
, kid
);
10358 // Now that the old frames are gone, we can start pointing to our
10359 // new primary frame.
10360 textContent
->SetPrimaryFrame(textFrame
);
10362 // Insert text frame in its place
10363 nsFrameList
textList(textFrame
, textFrame
);
10364 aFrameManager
->InsertFrames(aFrame
, nsnull
, prevSibling
, textList
);
10366 *aStopLooking
= PR_TRUE
;
10367 NS_ASSERTION(!aBlockFrame
->GetPrevContinuation(),
10368 "should have the first continuation here");
10369 aBlockFrame
->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD
);
10372 else if (IsInlineFrame(kid
)) {
10373 // Look inside child inline frame for the letter frame
10374 RemoveFirstLetterFrames(aPresContext
, aPresShell
, aFrameManager
,
10375 kid
, aBlockFrame
, aStopLooking
);
10376 if (*aStopLooking
) {
10381 kid
= kid
->GetNextSibling();
10388 nsCSSFrameConstructor::RemoveLetterFrames(nsPresContext
* aPresContext
,
10389 nsIPresShell
* aPresShell
,
10390 nsFrameManager
* aFrameManager
,
10391 nsIFrame
* aBlockFrame
)
10393 aBlockFrame
= aBlockFrame
->GetFirstContinuation();
10394 nsIFrame
* continuation
= aBlockFrame
;
10396 PRBool stopLooking
= PR_FALSE
;
10399 rv
= RemoveFloatingFirstLetterFrames(aPresContext
, aPresShell
,
10401 continuation
, &stopLooking
);
10402 if (NS_SUCCEEDED(rv
) && !stopLooking
) {
10403 rv
= RemoveFirstLetterFrames(aPresContext
, aPresShell
, aFrameManager
,
10404 continuation
, aBlockFrame
, &stopLooking
);
10409 continuation
= continuation
->GetNextContinuation();
10410 } while (continuation
);
10414 // Fixup the letter frame situation for the given block
10416 nsCSSFrameConstructor::RecoverLetterFrames(nsIFrame
* aBlockFrame
)
10418 aBlockFrame
= aBlockFrame
->GetFirstContinuation();
10419 nsIFrame
* continuation
= aBlockFrame
;
10421 nsIFrame
* parentFrame
= nsnull
;
10422 nsIFrame
* textFrame
= nsnull
;
10423 nsIFrame
* prevFrame
= nsnull
;
10424 nsFrameItems letterFrames
;
10425 PRBool stopLooking
= PR_FALSE
;
10428 // XXX shouldn't this bit be set already (bug 408493), assert instead?
10429 continuation
->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE
);
10430 rv
= WrapFramesInFirstLetterFrame(aBlockFrame
, continuation
, continuation
,
10431 continuation
->GetFirstChild(nsnull
),
10432 &parentFrame
, &textFrame
, &prevFrame
,
10433 letterFrames
, &stopLooking
);
10434 if (NS_FAILED(rv
)) {
10440 continuation
= continuation
->GetNextContinuation();
10441 } while (continuation
);
10444 // Take the old textFrame out of the parents child list
10445 mPresShell
->FrameManager()->RemoveFrame(nsnull
, textFrame
);
10447 // Insert in the letter frame(s)
10448 parentFrame
->InsertFrames(nsnull
, prevFrame
, letterFrames
);
10453 //----------------------------------------------------------------------
10455 // listbox Widget Routines
10458 nsCSSFrameConstructor::CreateListBoxContent(nsPresContext
* aPresContext
,
10459 nsIFrame
* aParentFrame
,
10460 nsIFrame
* aPrevFrame
,
10461 nsIContent
* aChild
,
10462 nsIFrame
** aNewFrame
,
10464 PRBool aIsScrollbar
,
10465 nsILayoutHistoryState
* aFrameState
)
10468 nsresult rv
= NS_OK
;
10470 // Construct a new frame
10471 if (nsnull
!= aParentFrame
) {
10472 nsFrameItems frameItems
;
10473 nsFrameConstructorState
state(mPresShell
, mFixedContainingBlock
,
10474 GetAbsoluteContainingBlock(aParentFrame
),
10475 GetFloatContainingBlock(aParentFrame
),
10476 mTempFrameTreeState
);
10478 nsRefPtr
<nsStyleContext
> styleContext
;
10479 styleContext
= ResolveStyleContext(aParentFrame
, aChild
);
10481 // Pre-check for display "none" - only if we find that, do we create
10482 // any frame at all
10483 const nsStyleDisplay
* display
= styleContext
->GetStyleDisplay();
10485 if (NS_STYLE_DISPLAY_NONE
== display
->mDisplay
) {
10486 *aNewFrame
= nsnull
;
10492 FrameConstructionItemList items
;
10493 AddFrameConstructionItemsInternal(state
, aChild
, aParentFrame
,
10494 aChild
->Tag(), aChild
->GetNameSpaceID(),
10495 PR_TRUE
, styleContext
,
10496 ITEM_ALLOW_XBL_BASE
, items
);
10497 ConstructFramesFromItemList(state
, items
, aParentFrame
, frameItems
);
10499 nsIFrame
* newFrame
= frameItems
.FirstChild();
10500 *aNewFrame
= newFrame
;
10502 if (NS_SUCCEEDED(rv
) && (nsnull
!= newFrame
)) {
10503 // Notify the parent frame
10505 rv
= ((nsListBoxBodyFrame
*)aParentFrame
)->ListBoxAppendFrames(frameItems
);
10507 rv
= ((nsListBoxBodyFrame
*)aParentFrame
)->ListBoxInsertFrames(aPrevFrame
, frameItems
);
10515 return NS_ERROR_FAILURE
;
10519 //----------------------------------------
10522 nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState
& aState
,
10523 const nsStyleDisplay
* aDisplay
,
10524 nsIContent
* aContent
,
10525 nsIFrame
* aParentFrame
,
10526 nsIFrame
* aContentParentFrame
,
10527 nsStyleContext
* aStyleContext
,
10528 nsIFrame
** aNewFrame
,
10529 nsFrameItems
& aFrameItems
,
10530 PRBool aAbsPosContainer
,
10531 PendingBinding
* aPendingBinding
)
10533 // Create column wrapper if necessary
10534 nsIFrame
* blockFrame
= *aNewFrame
;
10535 nsIFrame
* parent
= aParentFrame
;
10536 nsRefPtr
<nsStyleContext
> blockStyle
= aStyleContext
;
10537 const nsStyleColumn
* columns
= aStyleContext
->GetStyleColumn();
10539 if (columns
->mColumnCount
!= NS_STYLE_COLUMN_COUNT_AUTO
10540 || columns
->mColumnWidth
.GetUnit() != eStyleUnit_Auto
) {
10541 nsIFrame
* columnSetFrame
= nsnull
;
10542 columnSetFrame
= NS_NewColumnSetFrame(mPresShell
, aStyleContext
, 0);
10543 if (!columnSetFrame
) {
10544 return NS_ERROR_OUT_OF_MEMORY
;
10547 InitAndRestoreFrame(aState
, aContent
, aParentFrame
, nsnull
, columnSetFrame
);
10548 // See if we need to create a view
10549 nsHTMLContainerFrame::CreateViewForFrame(columnSetFrame
, PR_FALSE
);
10550 blockStyle
= mPresShell
->StyleSet()->
10551 ResolveAnonymousBoxStyle(nsCSSAnonBoxes::columnContent
, aStyleContext
);
10552 parent
= columnSetFrame
;
10553 *aNewFrame
= columnSetFrame
;
10555 SetInitialSingleChild(columnSetFrame
, blockFrame
);
10558 blockFrame
->SetStyleContextWithoutNotification(blockStyle
);
10559 InitAndRestoreFrame(aState
, aContent
, parent
, nsnull
, blockFrame
);
10561 nsresult rv
= aState
.AddChild(*aNewFrame
, aFrameItems
, aContent
,
10563 aContentParentFrame
? aContentParentFrame
:
10565 if (NS_FAILED(rv
)) {
10569 // See if we need to create a view, e.g. the frame is absolutely positioned
10570 nsHTMLContainerFrame::CreateViewForFrame(blockFrame
, PR_FALSE
);
10572 if (!mRootElementFrame
) {
10573 // The frame we're constructing will be the root element frame.
10574 // Set mRootElementFrame before processing children.
10575 mRootElementFrame
= *aNewFrame
;
10578 // We should make the outer frame be the absolute containing block,
10579 // if one is required. We have to do this because absolute
10580 // positioning must be computed with respect to the CSS dimensions
10581 // of the element, which are the dimensions of the outer block. But
10582 // we can't really do that because only blocks can have absolute
10583 // children. So use the block and try to compensate with hacks
10584 // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
10585 nsFrameConstructorSaveState absoluteSaveState
;
10586 if (aAbsPosContainer
) {
10587 // NS_ASSERTION(aRelPos, "should have made area frame for this");
10588 aState
.PushAbsoluteContainingBlock(blockFrame
, absoluteSaveState
);
10591 // Process the child content
10592 nsFrameItems childItems
;
10593 rv
= ProcessChildren(aState
, aContent
, aStyleContext
, blockFrame
, PR_TRUE
,
10594 childItems
, PR_TRUE
, aPendingBinding
);
10596 // Set the frame's initial child list
10597 blockFrame
->SetInitialChildList(nsnull
, childItems
);
10603 nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState
& aState
,
10604 FrameConstructionItem
& aItem
,
10605 nsIFrame
* aParentFrame
,
10606 const nsStyleDisplay
* aDisplay
,
10607 nsFrameItems
& aFrameItems
,
10608 nsIFrame
** aNewFrame
)
10610 // If an inline frame has non-inline kids, then we chop up the child list
10611 // into runs of blocks and runs of inlines, create anonymous block frames to
10612 // contain the runs of blocks, inline frames with our style context for the
10613 // runs of inlines, and put all these frames, in order, into aFrameItems. We
10614 // put the first one into *aNewFrame. The whole setup is called an {ib}
10615 // split; in what follows "frames in the split" refers to the anonymous blocks
10616 // and inlines that contain our children.
10618 // {ib} splits maintain the following invariants:
10619 // 1) All frames in the split have the NS_FRAME_IS_SPECIAL bit set.
10620 // 2) Each frame in the split has the nsIFrame::IBSplitSpecialSibling
10621 // property pointing to the next frame in the split, except for the last
10622 // one, which does not have it set.
10623 // 3) Each frame in the split has the nsIFrame::IBSplitSpecialPrevSibling
10624 // property pointing to the previous frame in the split, except for the
10625 // first one, which does not have it set.
10626 // 4) The first and last frame in the split are always inlines.
10628 // An invariant that is NOT maintained is that the wrappers are actually
10629 // linked via GetNextSibling linkage. A simple example is an inline
10630 // containing an inline that contains a block. The three parts of the inner
10631 // inline end up with three different parents.
10633 // For example, this HTML:
10644 // Gives the following frame tree:
10646 // Inline (outer span)
10647 // Block (anonymous, outer span)
10650 // Inline (outer span)
10651 // Inline (inner span)
10653 // Block (anonymous, outer span)
10654 // Block (anonymous, inner span)
10657 // Inline (outer span)
10658 // Inline (inner span)
10660 // Block (anonymous, outer span)
10663 // Inline (outer span)
10666 nsIContent
* const content
= aItem
.mContent
;
10667 nsStyleContext
* const styleContext
= aItem
.mStyleContext
;
10669 nsIFrame
*newFrame
;
10671 PRBool positioned
=
10672 NS_STYLE_DISPLAY_INLINE
== aDisplay
->mDisplay
&&
10673 (NS_STYLE_POSITION_RELATIVE
== aDisplay
->mPosition
||
10674 aDisplay
->HasTransform());
10676 newFrame
= NS_NewPositionedInlineFrame(mPresShell
, styleContext
);
10678 newFrame
= NS_NewInlineFrame(mPresShell
, styleContext
);
10681 // Initialize the frame
10682 InitAndRestoreFrame(aState
, content
, aParentFrame
, nsnull
, newFrame
);
10684 nsFrameConstructorSaveState absoluteSaveState
; // definition cannot be inside next block
10685 // because the object's destructor is significant
10686 // this is part of the fix for bug 42372
10688 // Any inline frame might need a view (because of opacity, or fixed background)
10689 nsHTMLContainerFrame::CreateViewForFrame(newFrame
, PR_FALSE
);
10692 // Relatively positioned frames becomes a container for child
10693 // frames that are positioned
10694 aState
.PushAbsoluteContainingBlock(newFrame
, absoluteSaveState
);
10697 // Process the child content
10698 nsFrameItems childItems
;
10699 nsresult rv
= ConstructFramesFromItemList(aState
, aItem
.mChildItems
, newFrame
,
10701 if (NS_FAILED(rv
)) {
10706 nsFrameList::FrameLinkEnumerator
firstBlockEnumerator(childItems
);
10707 if (!aItem
.mIsAllInline
) {
10708 FindFirstBlock(firstBlockEnumerator
);
10711 if (aItem
.mIsAllInline
|| firstBlockEnumerator
.AtEnd()) {
10712 // This part is easy. We either already know we have no non-inline kids,
10713 // or haven't found any when constructing actual frames (the latter can
10714 // happen only if out-of-flows that we thought had no containing block
10715 // acquired one when ancestor inline frames and {ib} splits got
10716 // constructed). Just put all the kids into the single inline frame and
10718 newFrame
->SetInitialChildList(nsnull
, childItems
);
10719 if (NS_SUCCEEDED(rv
)) {
10720 aState
.AddChild(newFrame
, aFrameItems
, content
, styleContext
, aParentFrame
);
10721 *aNewFrame
= newFrame
;
10726 // This inline frame contains several types of children. Therefore this frame
10727 // has to be chopped into several pieces, as described above.
10729 // Grab the first inline's kids
10730 nsFrameList firstInlineKids
= childItems
.ExtractHead(firstBlockEnumerator
);
10731 newFrame
->SetInitialChildList(nsnull
, firstInlineKids
);
10733 aFrameItems
.AddChild(newFrame
);
10735 CreateIBSiblings(aState
, newFrame
, positioned
, childItems
, aFrameItems
);
10737 *aNewFrame
= newFrame
;
10742 nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState
& aState
,
10743 nsIFrame
* aInitialInline
,
10744 PRBool aIsPositioned
,
10745 nsFrameItems
& aChildItems
,
10746 nsFrameItems
& aSiblings
)
10748 nsIContent
* content
= aInitialInline
->GetContent();
10749 nsStyleContext
* styleContext
= aInitialInline
->GetStyleContext();
10750 nsIFrame
* parentFrame
= aInitialInline
->GetParent();
10752 // Resolve the right style context for our anonymous blocks.
10753 nsRefPtr
<nsStyleContext
> blockSC
=
10754 mPresShell
->StyleSet()->
10755 ResolveAnonymousBoxStyle(aIsPositioned
?
10756 nsCSSAnonBoxes::mozAnonymousPositionedBlock
:
10757 nsCSSAnonBoxes::mozAnonymousBlock
,
10760 nsIFrame
* lastNewInline
= aInitialInline
->GetFirstContinuation();
10762 // On entry to this loop aChildItems is not empty and the first frame in it
10764 NS_PRECONDITION(aChildItems
.NotEmpty(), "Should have child items");
10765 NS_PRECONDITION(!IsInlineOutside(aChildItems
.FirstChild()),
10766 "Must have list starting with block");
10768 // The initial run of blocks belongs to an anonymous block that we create
10769 // right now. The anonymous block will be the parent of these block
10770 // children of the inline.
10771 nsIFrame
* blockFrame
;
10772 blockFrame
= NS_NewBlockFrame(mPresShell
, blockSC
);
10774 InitAndRestoreFrame(aState
, content
, parentFrame
, nsnull
, blockFrame
,
10777 // Any frame could have a view
10778 nsHTMLContainerFrame::CreateViewForFrame(blockFrame
, PR_FALSE
);
10780 // Find the first non-block child which defines the end of our block kids
10781 // and the start of our next inline's kids
10782 nsFrameList::FrameLinkEnumerator firstNonBlock
=
10783 FindFirstNonBlock(aChildItems
);
10784 nsFrameList blockKids
= aChildItems
.ExtractHead(firstNonBlock
);
10786 MoveChildrenTo(aState
.mPresContext
, aInitialInline
, blockFrame
, blockKids
);
10788 SetFrameIsSpecial(lastNewInline
, blockFrame
);
10789 aSiblings
.AddChild(blockFrame
);
10791 // Now grab the initial inlines in aChildItems and put them into an inline
10793 nsIFrame
* inlineFrame
;
10794 if (aIsPositioned
) {
10795 inlineFrame
= NS_NewPositionedInlineFrame(mPresShell
, styleContext
);
10798 inlineFrame
= NS_NewInlineFrame(mPresShell
, styleContext
);
10801 InitAndRestoreFrame(aState
, content
, parentFrame
, nsnull
, inlineFrame
,
10804 // Any frame might need a view
10805 nsHTMLContainerFrame::CreateViewForFrame(inlineFrame
, PR_FALSE
);
10807 if (aChildItems
.NotEmpty()) {
10808 nsFrameList::FrameLinkEnumerator
firstBlock(aChildItems
);
10809 FindFirstBlock(firstBlock
);
10810 nsFrameList inlineKids
= aChildItems
.ExtractHead(firstBlock
);
10812 MoveChildrenTo(aState
.mPresContext
, aInitialInline
, inlineFrame
,
10816 SetFrameIsSpecial(blockFrame
, inlineFrame
);
10817 aSiblings
.AddChild(inlineFrame
);
10818 lastNewInline
= inlineFrame
;
10819 } while (aChildItems
.NotEmpty());
10821 SetFrameIsSpecial(lastNewInline
, nsnull
);
10825 nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState
& aState
,
10826 FrameConstructionItem
& aParentItem
)
10828 // XXXbz should we preallocate aParentItem.mChildItems to some sane
10829 // length? Maybe even to parentContent->GetChildCount()?
10830 nsFrameConstructorState::PendingBindingAutoPusher
10831 pusher(aState
, aParentItem
.mPendingBinding
);
10833 // Probe for generated content before
10834 nsStyleContext
* const parentStyleContext
= aParentItem
.mStyleContext
;
10835 nsIContent
* const parentContent
= aParentItem
.mContent
;
10836 CreateGeneratedContentItem(aState
, nsnull
, parentContent
, parentStyleContext
,
10837 nsCSSPseudoElements::ePseudo_before
,
10838 aParentItem
.mChildItems
);
10840 ChildIterator iter
, last
;
10841 for (ChildIterator::Init(parentContent
, &iter
, &last
);
10844 // Manually check for comments/PIs, since we do't have a frame to pass to
10845 // AddFrameConstructionItems. We know our parent is a non-replaced inline,
10846 // so there is no need to do the NeedFrameFor check.
10847 nsIContent
* content
= *iter
;
10848 content
->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME
);
10849 if (content
->IsNodeOfType(nsINode::eCOMMENT
) ||
10850 content
->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION
)) {
10853 if (content
->IsElement()) {
10854 // See comment explaining why we need to remove the "is possible
10855 // restyle root" flags in AddFrameConstructionItems. But note
10856 // that we can remove all restyle flags, just like in
10857 // ProcessChildren and for the same reason.
10858 content
->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS
);
10861 nsRefPtr
<nsStyleContext
> childContext
=
10862 ResolveStyleContext(parentStyleContext
, content
);
10864 AddFrameConstructionItemsInternal(aState
, content
, nsnull
, content
->Tag(),
10865 content
->GetNameSpaceID(),
10866 iter
.XBLInvolved(), childContext
,
10867 ITEM_ALLOW_XBL_BASE
| ITEM_ALLOW_PAGE_BREAK
,
10868 aParentItem
.mChildItems
);
10871 // Probe for generated content after
10872 CreateGeneratedContentItem(aState
, nsnull
, parentContent
, parentStyleContext
,
10873 nsCSSPseudoElements::ePseudo_after
,
10874 aParentItem
.mChildItems
);
10876 aParentItem
.mIsAllInline
= aParentItem
.mChildItems
.AreAllItemsInline();
10879 // return whether it's ok to append (in the AppendFrames sense) to
10880 // aParentFrame if our nextSibling is aNextSibling. aParentFrame must
10881 // be an {ib} special inline.
10883 IsSafeToAppendToSpecialInline(nsIFrame
* aParentFrame
, nsIFrame
* aNextSibling
)
10885 NS_PRECONDITION(IsInlineFrame(aParentFrame
),
10886 "Must have an inline parent here");
10888 NS_ASSERTION(IsFrameSpecial(aParentFrame
), "How is this not special?");
10889 if (aNextSibling
|| aParentFrame
->GetNextContinuation() ||
10890 GetSpecialSibling(aParentFrame
)) {
10894 aNextSibling
= aParentFrame
->GetNextSibling();
10895 aParentFrame
= aParentFrame
->GetParent();
10896 } while (IsInlineFrame(aParentFrame
));
10902 nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState
& aState
,
10903 nsIFrame
* aContainingBlock
,
10905 FrameConstructionItemList
& aItems
,
10907 nsIFrame
* aPrevSibling
)
10909 if (aItems
.IsEmpty()) {
10913 // Before we go and append the frames, we must check for several
10914 // special situations.
10916 // Situation #1 is a XUL frame that contains frames that are required
10917 // to be wrapped in blocks.
10918 if (aFrame
->IsBoxFrame() &&
10919 !(aFrame
->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK
) &&
10920 aItems
.AnyItemsNeedBlockParent()) {
10921 RecreateFramesForContent(aFrame
->GetContent(), PR_TRUE
);
10925 nsIFrame
* nextSibling
= ::GetInsertNextSibling(aFrame
, aPrevSibling
);
10927 // Situation #2 is a case when table pseudo-frames don't work out right
10928 ParentType parentType
= GetParentType(aFrame
);
10929 // If all the kids want a parent of the type that aFrame is, then we're all
10930 // set to go. Indeed, there won't be any table pseudo-frames created between
10931 // aFrame and the kids, so those won't need to be merged with any table
10932 // pseudo-frames that might already be kids of aFrame. If aFrame itself is a
10933 // table pseudo-frame, then all the kids in this list would have wanted a
10934 // frame of that type wrapping them anyway, so putting them inside it is ok.
10935 if (!aItems
.AllWantParentType(parentType
)) {
10936 // Don't give up yet. If parentType is not eTypeBlock and the parent is
10937 // not a generated content frame, then try filtering whitespace out of the
10939 if (parentType
!= eTypeBlock
&& !aFrame
->IsGeneratedContentFrame()) {
10940 // For leading whitespace followed by a kid that wants our parent type,
10941 // there are four cases:
10942 // 1) We have a previous sibling which is not a table pseudo. That means
10943 // that previous sibling wanted a (non-block) parent of the type we're
10944 // looking at. Then the whitespace comes between two table-internal
10945 // elements, so should be collapsed out.
10946 // 2) We have a previous sibling which is a table pseudo. It might have
10947 // kids who want this whitespace, so we need to reframe.
10948 // 3) We have no previous sibling and our parent frame is not a table
10949 // pseudo. That means that we'll be at the beginning of our actual
10950 // non-block-type parent, and the whitespace is OK to collapse out.
10951 // If something is ever inserted before us, it'll find our own parent
10952 // as its parent and if it's something that would care about the
10953 // whitespace it'll want a block parent, so it'll trigger a reframe at
10955 // 4) We have no previous sibling and our parent frame is a table pseudo.
10956 // Need to reframe.
10957 // All that is predicated on finding the correct previous sibling. We
10958 // might have to walk backwards along continuations from aFrame to do so.
10960 // It's always OK to drop whitespace between any two items that want a
10961 // parent of type parentType.
10963 // For trailing whitespace preceded by a kid that wants our parent type,
10964 // there are four cases:
10965 // 1) We have a next sibling which is not a table pseudo. That means
10966 // that next sibling wanted a (non-block) parent of the type we're
10967 // looking at. Then the whitespace comes between two table-internal
10968 // elements, so should be collapsed out.
10969 // 2) We have a next sibling which is a table pseudo. It might have
10970 // kids who want this whitespace, so we need to reframe.
10971 // 3) We have no next sibling and our parent frame is not a table
10972 // pseudo. That means that we'll be at the end of our actual
10973 // non-block-type parent, and the whitespace is OK to collapse out.
10974 // If something is ever inserted after us, it'll find our own parent
10975 // as its parent and if it's something that would care about the
10976 // whitespace it'll want a block parent, so it'll trigger a reframe at
10978 // 4) We have no next sibling and our parent frame is a table pseudo.
10979 // Need to reframe.
10980 // All that is predicated on finding the correct next sibling. We might
10981 // have to walk forward along continuations from aFrame to do so. That
10982 // said, in the case when nextSibling is null at this point and aIsAppend
10983 // is true, we know we're in case 3. Furthermore, in that case we don't
10984 // even have to worry about the table pseudo situation; we know our
10985 // parent is not a table pseudo there.
10986 FCItemIterator
iter(aItems
);
10987 FCItemIterator
start(iter
);
10989 if (iter
.SkipItemsWantingParentType(parentType
)) {
10993 // iter points to an item that wants a different parent. If it's not
10994 // whitespace, we're done; no more point scanning the list.
10995 if (!iter
.item().IsWhitespace(aState
)) {
10999 if (iter
== start
) {
11000 // Leading whitespace. How to handle this depends on our
11001 // previous sibling and aFrame. See the long comment above.
11002 nsIFrame
* prevSibling
= aPrevSibling
;
11003 if (!prevSibling
) {
11004 // Try to find one after all
11005 nsIFrame
* parentPrevCont
= aFrame
->GetPrevContinuation();
11006 while (parentPrevCont
) {
11007 prevSibling
= parentPrevCont
->GetLastChild(nsnull
);
11011 parentPrevCont
= parentPrevCont
->GetPrevContinuation();
11015 if (IsTablePseudo(prevSibling
)) {
11019 } else if (IsTablePseudo(aFrame
)) {
11025 FCItemIterator
spaceEndIter(iter
);
11026 // Advance spaceEndIter past any whitespace
11027 PRBool trailingSpaces
= spaceEndIter
.SkipWhitespace(aState
);
11030 if (trailingSpaces
) {
11031 // Trailing whitespace. How to handle this depeds on aIsAppend, our
11032 // next sibling and aFrame. See the long comment above.
11033 okToDrop
= aIsAppend
&& !nextSibling
;
11035 if (!nextSibling
) {
11036 // Try to find one after all
11037 nsIFrame
* parentNextCont
= aFrame
->GetNextContinuation();
11038 while (parentNextCont
) {
11039 nextSibling
= parentNextCont
->GetFirstChild(nsnull
);
11043 parentNextCont
= parentNextCont
->GetNextContinuation();
11047 okToDrop
= (nextSibling
&& !IsTablePseudo(nextSibling
)) ||
11048 (!nextSibling
&& !IsTablePseudo(aFrame
));
11052 NS_ASSERTION(!IsTablePseudo(aFrame
), "How did that happen?");
11056 okToDrop
= (spaceEndIter
.item().DesiredParentType() == parentType
);
11060 iter
.DeleteItemsTo(spaceEndIter
);
11062 // We're done: we don't want to drop the whitespace, and it has the
11063 // wrong parent type.
11067 // Now loop, since |iter| points to item right after the whitespace we
11069 } while (!iter
.IsDone());
11072 // We might be able to figure out some sort of optimizations here, but they
11073 // would have to depend on having a correct aPrevSibling and a correct next
11074 // sibling. For example, we can probably avoid reframing if none of
11075 // aFrame, aPrevSibling, and next sibling are table pseudo-frames. But it
11076 // doesn't seem worth it to worry about that for now, especially since we
11077 // in fact do not have a reliable aPrevSibling, nor any next sibling, in
11080 // aItems might have changed, so recheck the parent type thing. In fact,
11081 // it might be empty, so recheck that too.
11082 if (aItems
.IsEmpty()) {
11086 if (!aItems
.AllWantParentType(parentType
)) {
11087 // Reframing aFrame->GetContent() is good enough, since the content of
11088 // table pseudo-frames is the ancestor content.
11089 RecreateFramesForContent(aFrame
->GetContent(), PR_TRUE
);
11094 // Now we have several cases involving {ib} splits. Put them all in a
11095 // do/while with breaks to take us to the "go and reconstruct" code.
11097 if (IsInlineFrame(aFrame
)) {
11098 if (aItems
.AreAllItemsInline()) {
11099 // We can just put the kids in.
11103 if (!IsFrameSpecial(aFrame
)) {
11104 // Need to go ahead and reconstruct.
11108 // Now we're adding kids including some blocks to an inline part of an
11109 // {ib} split. If we plan to call AppendFrames, and don't have a next
11110 // sibling for the new frames, and our parent is the last continuation of
11111 // the last part of the {ib} split, and the same is true of all our
11112 // ancestor inlines (they have no following continuations and they're the
11113 // last part of their {ib} splits and we'd be adding to the end for all
11114 // of them), then AppendFrames will handle things for us. Bail out in
11116 if (aIsAppend
&& IsSafeToAppendToSpecialInline(aFrame
, nextSibling
)) {
11120 // Need to reconstruct.
11124 // Now we know we have a block parent. If it's not special, we're all set.
11125 if (!IsFrameSpecial(aFrame
)) {
11129 // We're adding some kids to a block part of an {ib} split. If all the
11130 // kids are blocks, we don't need to reconstruct.
11131 if (aItems
.AreAllItemsBlock()) {
11135 // We might have some inline kids for this block. Just reconstruct.
11139 // If we don't have a containing block, start with aFrame and look for one.
11140 if (!aContainingBlock
) {
11141 aContainingBlock
= aFrame
;
11144 // To find the right block to reframe, just walk up the tree until we find a
11146 // 1) Not part of an IB split (not special)
11147 // 2) Not a pseudo-frame
11148 // 3) Not an inline frame
11149 // We're guaranteed to find one, since nsStyleContext::ApplyStyleFixups
11150 // enforces that the root is display:none, display:table, or display:block.
11151 // Note that walking up "too far" is OK in terms of correctness, even if it
11152 // might be a little inefficient. This is why we walk out of all
11153 // pseudo-frames -- telling which ones are or are not OK to walk out of is
11154 // too hard (and I suspect that we do in fact need to walk out of all of
11156 while (IsFrameSpecial(aContainingBlock
) || IsInlineOutside(aContainingBlock
) ||
11157 aContainingBlock
->GetStyleContext()->GetPseudo()) {
11158 aContainingBlock
= aContainingBlock
->GetParent();
11159 NS_ASSERTION(aContainingBlock
,
11160 "Must have non-inline, non-special, non-pseudo frame as root "
11161 "(or child of root, for a table root)!");
11164 // Tell parent of the containing block to reformulate the
11165 // entire block. This is painful and definitely not optimal
11166 // but it will *always* get the right answer.
11168 nsIContent
*blockContent
= aContainingBlock
->GetContent();
11170 if (gNoisyContentUpdates
) {
11171 printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p\n",
11172 static_cast<void*>(blockContent
));
11175 RecreateFramesForContent(blockContent
, PR_TRUE
);
11180 nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame
* aFrame
)
11184 // ReframeContainingBlock is a NASTY routine, it causes terrible performance problems
11185 // so I want to see when it is happening! Unfortunately, it is happening way to often because
11186 // so much content on the web causes 'special' block-in-inline frame situations and we handle them
11188 if (gNoisyContentUpdates
) {
11189 printf("nsCSSFrameConstructor::ReframeContainingBlock frame=%p\n",
11190 static_cast<void*>(aFrame
));
11194 // XXXbz how exactly would we get here while isReflowing anyway? Should this
11195 // whole test be ifdef DEBUG?
11196 if (mPresShell
->IsReflowLocked()) {
11197 // don't ReframeContainingBlock, this will result in a crash
11198 // if we remove a tree that's in reflow - see bug 121368 for testcase
11199 NS_ERROR("Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a Reflow!!!");
11203 // Get the first "normal" ancestor of the target frame.
11204 nsIFrame
* containingBlock
= GetIBContainingBlockFor(aFrame
);
11205 if (containingBlock
) {
11206 // From here we look for the containing block in case the target
11207 // frame is already a block (which can happen when an inline frame
11208 // wraps some of its content in an anonymous block; see
11209 // ConstructInline)
11211 // NOTE: We used to get the FloatContainingBlock here, but it was often wrong.
11212 // GetIBContainingBlock works much better and provides the correct container in all cases
11213 // so GetFloatContainingBlock(aFrame) has been removed
11215 // And get the containingBlock's content
11216 nsCOMPtr
<nsIContent
> blockContent
= containingBlock
->GetContent();
11217 if (blockContent
) {
11219 if (gNoisyContentUpdates
) {
11220 printf(" ==> blockContent=%p\n", static_cast<void*>(blockContent
));
11223 return RecreateFramesForContent(blockContent
, PR_TRUE
);
11227 // If we get here, we're screwed!
11228 return RecreateFramesForContent(mPresShell
->GetDocument()->GetRootElement(),
11233 nsCSSFrameConstructor::RestyleForEmptyChange(Element
* aContainer
)
11235 // In some cases (:empty + E, :empty ~ E), a change if the content of
11236 // an element requires restyling its parent's siblings.
11237 nsRestyleHint hint
= eRestyle_Subtree
;
11238 nsIContent
* grandparent
= aContainer
->GetParent();
11240 (grandparent
->GetFlags() & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS
)) {
11241 hint
= nsRestyleHint(hint
| eRestyle_LaterSiblings
);
11243 PostRestyleEvent(aContainer
, hint
, NS_STYLE_HINT_NONE
);
11247 nsCSSFrameConstructor::RestyleForAppend(Element
* aContainer
,
11248 nsIContent
* aFirstNewContent
)
11250 NS_ASSERTION(aContainer
, "must have container for append");
11253 for (nsIContent
* cur
= aFirstNewContent
; cur
; cur
= cur
->GetNextSibling()) {
11254 NS_ASSERTION(!cur
->IsRootOfAnonymousSubtree(),
11255 "anonymous nodes should not be in child lists");
11259 PRUint32 selectorFlags
=
11260 aContainer
->GetFlags() & (NODE_ALL_SELECTOR_FLAGS
&
11261 ~NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS
);
11262 if (selectorFlags
== 0)
11265 if (selectorFlags
& NODE_HAS_EMPTY_SELECTOR
) {
11266 // see whether we need to restyle the container
11267 PRBool wasEmpty
= PR_TRUE
; // :empty or :-moz-only-whitespace
11268 for (nsIContent
* cur
= aContainer
->GetFirstChild();
11269 cur
!= aFirstNewContent
;
11270 cur
= cur
->GetNextSibling()) {
11271 // We don't know whether we're testing :empty or :-moz-only-whitespace,
11272 // so be conservative and assume :-moz-only-whitespace (i.e., make
11273 // IsSignificantChild less likely to be true, and thus make us more
11274 // likely to restyle).
11275 if (nsStyleUtil::IsSignificantChild(cur
, PR_TRUE
, PR_FALSE
)) {
11276 wasEmpty
= PR_FALSE
;
11281 RestyleForEmptyChange(aContainer
);
11286 if (selectorFlags
& NODE_HAS_SLOW_SELECTOR
) {
11287 PostRestyleEvent(aContainer
, eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
11288 // Restyling the container is the most we can do here, so we're done.
11292 if (selectorFlags
& NODE_HAS_EDGE_CHILD_SELECTOR
) {
11293 // restyle the last element child before this node
11294 for (nsIContent
* cur
= aFirstNewContent
->GetPreviousSibling();
11296 cur
= cur
->GetPreviousSibling()) {
11297 if (cur
->IsElement()) {
11298 PostRestyleEvent(cur
->AsElement(), eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
11305 // Needed since we can't use PostRestyleEvent on non-elements (with
11306 // eRestyle_LaterSiblings or nsRestyleHint(eRestyle_Subtree |
11307 // eRestyle_LaterSiblings) as appropriate).
11309 RestyleSiblingsStartingWith(nsCSSFrameConstructor
*aFrameConstructor
,
11310 nsIContent
*aStartingSibling
/* may be null */)
11312 for (nsIContent
*sibling
= aStartingSibling
; sibling
;
11313 sibling
= sibling
->GetNextSibling()) {
11314 if (sibling
->IsElement()) {
11315 aFrameConstructor
->
11316 PostRestyleEvent(sibling
->AsElement(),
11317 nsRestyleHint(eRestyle_Subtree
| eRestyle_LaterSiblings
),
11318 NS_STYLE_HINT_NONE
);
11324 // Restyling for a ContentInserted or CharacterDataChanged notification.
11325 // This could be used for ContentRemoved as well if we got the
11326 // notification before the removal happened (and sometimes
11327 // CharacterDataChanged is more like a removal than an addition).
11328 // The comments are written and variables are named in terms of it being
11329 // a ContentInserted notification.
11331 nsCSSFrameConstructor::RestyleForInsertOrChange(Element
* aContainer
,
11332 nsIContent
* aChild
)
11334 NS_ASSERTION(!aChild
->IsRootOfAnonymousSubtree(),
11335 "anonymous nodes should not be in child lists");
11336 PRUint32 selectorFlags
=
11337 aContainer
? (aContainer
->GetFlags() & NODE_ALL_SELECTOR_FLAGS
) : 0;
11338 if (selectorFlags
== 0)
11341 if (selectorFlags
& NODE_HAS_EMPTY_SELECTOR
) {
11342 // see whether we need to restyle the container
11343 PRBool wasEmpty
= PR_TRUE
; // :empty or :-moz-only-whitespace
11344 for (nsIContent
* child
= aContainer
->GetFirstChild();
11346 child
= child
->GetNextSibling()) {
11347 if (child
== aChild
)
11349 // We don't know whether we're testing :empty or :-moz-only-whitespace,
11350 // so be conservative and assume :-moz-only-whitespace (i.e., make
11351 // IsSignificantChild less likely to be true, and thus make us more
11352 // likely to restyle).
11353 if (nsStyleUtil::IsSignificantChild(child
, PR_TRUE
, PR_FALSE
)) {
11354 wasEmpty
= PR_FALSE
;
11359 RestyleForEmptyChange(aContainer
);
11364 if (selectorFlags
& NODE_HAS_SLOW_SELECTOR
) {
11365 PostRestyleEvent(aContainer
, eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
11366 // Restyling the container is the most we can do here, so we're done.
11370 if (selectorFlags
& NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS
) {
11371 // Restyle all later siblings.
11372 RestyleSiblingsStartingWith(this, aChild
->GetNextSibling());
11375 if (selectorFlags
& NODE_HAS_EDGE_CHILD_SELECTOR
) {
11376 // restyle the previously-first element child if it is after this node
11377 PRBool passedChild
= PR_FALSE
;
11378 for (nsIContent
* content
= aContainer
->GetFirstChild();
11380 content
= content
->GetNextSibling()) {
11381 if (content
== aChild
) {
11382 passedChild
= PR_TRUE
;
11385 if (content
->IsElement()) {
11387 PostRestyleEvent(content
->AsElement(), eRestyle_Subtree
,
11388 NS_STYLE_HINT_NONE
);
11393 // restyle the previously-last element child if it is before this node
11394 passedChild
= PR_FALSE
;
11395 for (nsIContent
* content
= aContainer
->GetLastChild();
11397 content
= content
->GetPreviousSibling()) {
11398 if (content
== aChild
) {
11399 passedChild
= PR_TRUE
;
11402 if (content
->IsElement()) {
11404 PostRestyleEvent(content
->AsElement(), eRestyle_Subtree
,
11405 NS_STYLE_HINT_NONE
);
11414 nsCSSFrameConstructor::RestyleForRemove(Element
* aContainer
,
11415 nsIContent
* aOldChild
,
11416 nsIContent
* aFollowingSibling
)
11418 NS_ASSERTION(!aOldChild
->IsRootOfAnonymousSubtree(),
11419 "anonymous nodes should not be in child lists");
11420 PRUint32 selectorFlags
=
11421 aContainer
? (aContainer
->GetFlags() & NODE_ALL_SELECTOR_FLAGS
) : 0;
11422 if (selectorFlags
== 0)
11425 if (selectorFlags
& NODE_HAS_EMPTY_SELECTOR
) {
11426 // see whether we need to restyle the container
11427 PRBool isEmpty
= PR_TRUE
; // :empty or :-moz-only-whitespace
11428 for (nsIContent
* child
= aContainer
->GetFirstChild();
11430 child
= child
->GetNextSibling()) {
11431 // We don't know whether we're testing :empty or :-moz-only-whitespace,
11432 // so be conservative and assume :-moz-only-whitespace (i.e., make
11433 // IsSignificantChild less likely to be true, and thus make us more
11434 // likely to restyle).
11435 if (nsStyleUtil::IsSignificantChild(child
, PR_TRUE
, PR_FALSE
)) {
11436 isEmpty
= PR_FALSE
;
11441 RestyleForEmptyChange(aContainer
);
11446 if (selectorFlags
& NODE_HAS_SLOW_SELECTOR
) {
11447 PostRestyleEvent(aContainer
, eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
11448 // Restyling the container is the most we can do here, so we're done.
11452 if (selectorFlags
& NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS
) {
11453 // Restyle all later siblings.
11454 RestyleSiblingsStartingWith(this, aFollowingSibling
);
11457 if (selectorFlags
& NODE_HAS_EDGE_CHILD_SELECTOR
) {
11458 // restyle the now-first element child if it was after aOldChild
11459 PRBool reachedFollowingSibling
= PR_FALSE
;
11460 for (nsIContent
* content
= aContainer
->GetFirstChild();
11462 content
= content
->GetNextSibling()) {
11463 if (content
== aFollowingSibling
) {
11464 reachedFollowingSibling
= PR_TRUE
;
11465 // do NOT continue here; we might want to restyle this node
11467 if (content
->IsElement()) {
11468 if (reachedFollowingSibling
) {
11469 PostRestyleEvent(content
->AsElement(), eRestyle_Subtree
,
11470 NS_STYLE_HINT_NONE
);
11475 // restyle the now-last element child if it was before aOldChild
11476 reachedFollowingSibling
= (aFollowingSibling
== nsnull
);
11477 for (nsIContent
* content
= aContainer
->GetLastChild();
11479 content
= content
->GetPreviousSibling()) {
11480 if (content
->IsElement()) {
11481 if (reachedFollowingSibling
) {
11482 PostRestyleEvent(content
->AsElement(), eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
11486 if (content
== aFollowingSibling
) {
11487 reachedFollowingSibling
= PR_TRUE
;
11495 nsCSSFrameConstructor::RebuildAllStyleData(nsChangeHint aExtraHint
)
11497 NS_ASSERTION(!(aExtraHint
& nsChangeHint_ReconstructFrame
),
11498 "Should not reconstruct the root of the frame tree. "
11499 "Use ReconstructDocElementHierarchy instead.");
11501 mRebuildAllStyleData
= PR_FALSE
;
11502 NS_UpdateHint(aExtraHint
, mRebuildAllExtraHint
);
11503 mRebuildAllExtraHint
= nsChangeHint(0);
11505 if (!mPresShell
|| !mPresShell
->GetRootFrame())
11508 // Make sure that the viewmanager will outlive the presshell
11509 nsIViewManager::UpdateViewBatch
batch(mPresShell
->GetViewManager());
11511 // Processing the style changes could cause a flush that propagates to
11512 // the parent frame and thus destroys the pres shell.
11513 nsCOMPtr
<nsIPresShell
> kungFuDeathGrip(mPresShell
);
11515 // We may reconstruct frames below and hence process anything that is in the
11516 // tree. We don't want to get notified to process those items again after.
11517 mPresShell
->GetDocument()->FlushPendingNotifications(Flush_ContentAndNotify
);
11519 nsAutoScriptBlocker scriptBlocker
;
11521 // Tell the style set to get the old rule tree out of the way
11522 // so we can recalculate while maintaining rule tree immutability
11523 nsresult rv
= mPresShell
->StyleSet()->BeginReconstruct();
11524 if (NS_FAILED(rv
)) {
11525 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
11529 // Recalculate all of the style contexts for the document
11530 // Note that we can ignore the return value of ComputeStyleChangeFor
11531 // because we never need to reframe the root frame
11532 // XXX This could be made faster by not rerunning rule matching
11533 // (but note that nsPresShell::SetPreferenceStyleRules currently depends
11534 // on us re-running rule matching here
11535 nsStyleChangeList changeList
;
11536 // XXX Does it matter that we're passing aExtraHint to the real root
11537 // frame and not the root node's primary frame?
11538 // Note: The restyle tracker we pass in here doesn't matter.
11539 mPresShell
->FrameManager()->ComputeStyleChangeFor(mPresShell
->GetRootFrame(),
11540 &changeList
, aExtraHint
,
11541 mPendingRestyles
, PR_TRUE
);
11542 // Process the required changes
11543 ProcessRestyledFrames(changeList
);
11544 // Tell the style set it's safe to destroy the old rule tree. We
11545 // must do this after the ProcessRestyledFrames call in case the
11546 // change list has frame reconstructs in it (since frames to be
11547 // reconstructed will still have their old style context pointers
11548 // until they are destroyed).
11549 mPresShell
->StyleSet()->EndReconstruct();
11550 batch
.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC
);
11554 nsCSSFrameConstructor::ProcessPendingRestyles()
11556 NS_PRECONDITION(mDocument
, "No document? Pshaw!");
11557 NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
11558 "Missing a script blocker!");
11560 // Process non-animation restyles...
11561 nsPresContext
*presContext
= mPresShell
->GetPresContext();
11562 NS_ABORT_IF_FALSE(!presContext
->IsProcessingRestyles(),
11563 "Nesting calls to ProcessPendingRestyles?");
11564 presContext
->SetProcessingRestyles(PR_TRUE
);
11566 mPendingRestyles
.ProcessRestyles();
11569 PRUint32 oldPendingRestyleCount
= mPendingRestyles
.Count();
11572 // ...and then process animation restyles. This needs to happen
11573 // second because we need to start animations that resulted from the
11574 // first set of restyles (e.g., CSS transitions with negative
11575 // transition-delay), and because we need to immediately
11576 // restyle-with-animation any just-restyled elements that are
11577 // mid-transition (since processing the non-animation restyle ignores
11578 // the running transition so it can check for a new change on the same
11579 // property, and then posts an immediate animation style change).
11580 presContext
->SetProcessingAnimationStyleChange(PR_TRUE
);
11581 mPendingAnimationRestyles
.ProcessRestyles();
11582 presContext
->SetProcessingAnimationStyleChange(PR_FALSE
);
11584 presContext
->SetProcessingRestyles(PR_FALSE
);
11585 NS_POSTCONDITION(mPendingRestyles
.Count() == oldPendingRestyleCount
,
11586 "We should not have posted new non-animation restyles while "
11587 "processing animation restyles");
11589 if (mRebuildAllStyleData
) {
11590 // We probably wasted a lot of work up above, but this seems safest
11591 // and it should be rarely used.
11592 // This might add us as a refresh observer again; that's ok.
11593 RebuildAllStyleData(nsChangeHint(0));
11598 nsCSSFrameConstructor::PostRestyleEventCommon(Element
* aElement
,
11599 nsRestyleHint aRestyleHint
,
11600 nsChangeHint aMinChangeHint
,
11601 PRBool aForAnimation
)
11603 if (NS_UNLIKELY(mPresShell
->IsDestroying())) {
11607 if (aRestyleHint
== 0 && !aMinChangeHint
) {
11608 // Nothing to do here
11612 RestyleTracker
& tracker
=
11613 aForAnimation
? mPendingAnimationRestyles
: mPendingRestyles
;
11614 tracker
.AddPendingRestyle(aElement
, aRestyleHint
, aMinChangeHint
);
11616 PostRestyleEventInternal(PR_FALSE
);
11620 nsCSSFrameConstructor::PostRestyleEventInternal(PRBool aForLazyConstruction
)
11622 // Make sure we're not in a style refresh; if we are, we still have
11623 // a call to ProcessPendingRestyles coming and there's no need to
11624 // add ourselves as a refresh observer until then.
11625 PRBool inRefresh
= !aForLazyConstruction
&& mInStyleRefresh
;
11626 if (!mObservingRefreshDriver
&& !inRefresh
) {
11627 mObservingRefreshDriver
= mPresShell
->GetPresContext()->RefreshDriver()->
11628 AddStyleFlushObserver(mPresShell
);
11633 nsCSSFrameConstructor::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint
)
11635 NS_ASSERTION(!(aExtraHint
& nsChangeHint_ReconstructFrame
),
11636 "Should not reconstruct the root of the frame tree. "
11637 "Use ReconstructDocElementHierarchy instead.");
11639 mRebuildAllStyleData
= PR_TRUE
;
11640 NS_UpdateHint(mRebuildAllExtraHint
, aExtraHint
);
11641 // Get a restyle event posted if necessary
11642 PostRestyleEventInternal(PR_FALSE
);
11646 nsCSSFrameConstructor::GenerateChildFrames(nsIFrame
* aFrame
)
11649 nsAutoScriptBlocker scriptBlocker
;
11652 nsFrameItems childItems
;
11653 nsFrameConstructorState
state(mPresShell
, nsnull
, nsnull
, nsnull
);
11654 // We don't have a parent frame with a pending binding constructor here,
11655 // so no need to worry about ordering of the kids' constructors with it.
11656 // Pass null for the PendingBinding.
11657 nsresult rv
= ProcessChildren(state
, aFrame
->GetContent(), aFrame
->GetStyleContext(),
11658 aFrame
, PR_FALSE
, childItems
, PR_FALSE
,
11660 if (NS_FAILED(rv
)) {
11665 aFrame
->SetInitialChildList(nsnull
, childItems
);
11670 // call XBL constructors after the frames are created
11671 mPresShell
->GetDocument()->BindingManager()->ProcessAttachedQueue();
11676 //////////////////////////////////////////////////////////
11677 // nsCSSFrameConstructor::FrameConstructionItem methods //
11678 //////////////////////////////////////////////////////////
11680 nsCSSFrameConstructor::
11681 FrameConstructionItem::IsWhitespace(nsFrameConstructorState
& aState
) const
11683 NS_PRECONDITION(!aState
.mSetPrimaryFrames
||
11684 !mContent
->GetPrimaryFrame(), "How did that happen?");
11688 mContent
->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE
|
11689 NS_REFRAME_IF_WHITESPACE
);
11690 return mContent
->TextIsOnlyWhitespace();
11693 //////////////////////////////////////////////////////////////
11694 // nsCSSFrameConstructor::FrameConstructionItemList methods //
11695 //////////////////////////////////////////////////////////////
11697 nsCSSFrameConstructor::FrameConstructionItemList::
11698 AdjustCountsForItem(FrameConstructionItem
* aItem
, PRInt32 aDelta
)
11700 NS_PRECONDITION(aDelta
== 1 || aDelta
== -1, "Unexpected delta");
11701 mItemCount
+= aDelta
;
11702 if (aItem
->mIsAllInline
) {
11703 mInlineCount
+= aDelta
;
11705 if (aItem
->mIsBlock
) {
11706 mBlockCount
+= aDelta
;
11708 if (aItem
->mIsLineParticipant
) {
11709 mLineParticipantCount
+= aDelta
;
11711 mDesiredParentCounts
[aItem
->DesiredParentType()] += aDelta
;
11714 ////////////////////////////////////////////////////////////////////////
11715 // nsCSSFrameConstructor::FrameConstructionItemList::Iterator methods //
11716 ////////////////////////////////////////////////////////////////////////
11718 nsCSSFrameConstructor::FrameConstructionItemList::
11719 Iterator::SkipItemsWantingParentType(ParentType aParentType
)
11721 NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
11722 while (item().DesiredParentType() == aParentType
) {
11732 nsCSSFrameConstructor::FrameConstructionItemList::
11733 Iterator::SkipWhitespace(nsFrameConstructorState
& aState
)
11735 NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
11736 NS_PRECONDITION(item().IsWhitespace(aState
), "Not pointing to whitespace?");
11742 } while (item().IsWhitespace(aState
));
11748 nsCSSFrameConstructor::FrameConstructionItemList::
11749 Iterator::AppendItemToList(FrameConstructionItemList
& aTargetList
)
11751 NS_ASSERTION(&aTargetList
!= &mList
, "Unexpected call");
11752 NS_PRECONDITION(!IsDone(), "should not be done");
11754 FrameConstructionItem
* item
= ToItem(mCurrent
);
11756 PR_REMOVE_LINK(item
);
11757 PR_APPEND_LINK(item
, &aTargetList
.mItems
);
11759 mList
.AdjustCountsForItem(item
, -1);
11760 aTargetList
.AdjustCountsForItem(item
, 1);
11764 nsCSSFrameConstructor::FrameConstructionItemList::
11765 Iterator::AppendItemsToList(const Iterator
& aEnd
,
11766 FrameConstructionItemList
& aTargetList
)
11768 NS_ASSERTION(&aTargetList
!= &mList
, "Unexpected call");
11769 NS_PRECONDITION(mEnd
== aEnd
.mEnd
, "end iterator for some other list?");
11771 if (!AtStart() || !aEnd
.IsDone() || !aTargetList
.IsEmpty()) {
11773 AppendItemToList(aTargetList
);
11774 } while (*this != aEnd
);
11778 // move over the list of items
11779 PR_INSERT_AFTER(&aTargetList
.mItems
, &mList
.mItems
);
11780 PR_REMOVE_LINK(&mList
.mItems
);
11782 // Copy over the various counters
11783 aTargetList
.mInlineCount
= mList
.mInlineCount
;
11784 aTargetList
.mBlockCount
= mList
.mBlockCount
;
11785 aTargetList
.mLineParticipantCount
= mList
.mLineParticipantCount
;
11786 aTargetList
.mItemCount
= mList
.mItemCount
;
11787 memcpy(aTargetList
.mDesiredParentCounts
, mList
.mDesiredParentCounts
,
11788 sizeof(aTargetList
.mDesiredParentCounts
));
11791 new (&mList
) FrameConstructionItemList();
11793 // Point ourselves to aEnd, as advertised
11794 mCurrent
= mEnd
= &mList
.mItems
;
11795 NS_POSTCONDITION(*this == aEnd
, "How did that happen?");
11799 nsCSSFrameConstructor::FrameConstructionItemList::
11800 Iterator::InsertItem(FrameConstructionItem
* aItem
)
11802 // Just insert the item before us. There's no magic here.
11803 PR_INSERT_BEFORE(aItem
, mCurrent
);
11804 mList
.AdjustCountsForItem(aItem
, 1);
11806 NS_POSTCONDITION(PR_NEXT_LINK(aItem
) == mCurrent
, "How did that happen?");
11810 nsCSSFrameConstructor::FrameConstructionItemList::
11811 Iterator::DeleteItemsTo(const Iterator
& aEnd
)
11813 NS_PRECONDITION(mEnd
== aEnd
.mEnd
, "end iterator for some other list?");
11814 NS_PRECONDITION(*this != aEnd
, "Shouldn't be at aEnd yet");
11817 NS_ASSERTION(!IsDone(), "Ran off end of list?");
11818 FrameConstructionItem
* item
= ToItem(mCurrent
);
11820 PR_REMOVE_LINK(item
);
11821 mList
.AdjustCountsForItem(item
, -1);
11823 } while (*this != aEnd
);