Bug 591198: Display element using normal layout rules if XBL binding fails for securi...
[mozilla-central.git] / layout / base / nsCSSFrameConstructor.cpp
blobd7fd0bb6e09e2dea69268a95b4db5534178b4ee8
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
14 * License.
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.
23 * Contributor(s):
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"
47 #include "nsCRT.h"
48 #include "nsIAtom.h"
49 #include "nsIURL.h"
50 #include "nsHashtable.h"
51 #include "nsIHTMLDocument.h"
52 #include "nsIStyleRule.h"
53 #include "nsIFrame.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"
96 #include "nsITheme.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"
119 #include "nsBox.h"
120 #include "nsTArray.h"
121 #include "nsGenericDOMDataNode.h"
122 #include "mozilla/dom/Element.h"
123 #include "FrameLayerBuilder.h"
125 #ifdef MOZ_XUL
126 #include "nsIRootBox.h"
127 #include "nsIDOMXULCommandDispatcher.h"
128 #include "nsIDOMXULDocument.h"
129 #include "nsIXULDocument.h"
130 #endif
131 #ifdef ACCESSIBILITY
132 #include "nsIAccessibilityService.h"
133 #include "nsIAccessibleEvent.h"
134 #endif
136 #include "nsInlineFrame.h"
137 #include "nsBlockFrame.h"
139 #include "nsIScrollableFrame.h"
141 #include "nsIXBLService.h"
143 #undef NOISY_FIRST_LETTER
145 #ifdef MOZ_MATHML
146 #include "nsMathMLParts.h"
147 #endif
148 #ifdef MOZ_SVG
149 #include "nsSVGFeatures.h"
150 #include "nsSVGEffects.h"
151 #include "nsSVGUtils.h"
152 #include "nsSVGOuterSVGFrame.h"
153 #endif
155 #include "nsRefreshDriver.h"
157 using namespace mozilla;
158 using namespace mozilla::dom;
160 nsIFrame*
161 NS_NewHTMLCanvasFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
163 #if defined(MOZ_MEDIA)
164 nsIFrame*
165 NS_NewHTMLVideoFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
166 #endif
168 #ifdef MOZ_SVG
169 #include "nsSVGTextContainerFrame.h"
171 PRBool
172 NS_SVGEnabled();
173 nsIFrame*
174 NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
175 nsIFrame*
176 NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
177 nsIFrame*
178 NS_NewSVGPathGeometryFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
179 nsIFrame*
180 NS_NewSVGGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
181 nsIFrame*
182 NS_NewSVGGenericContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
183 nsIFrame*
184 NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
185 nsIFrame*
186 NS_NewSVGAFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
187 nsIFrame*
188 NS_NewSVGGlyphFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
189 nsIFrame*
190 NS_NewSVGSwitchFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
191 nsIFrame*
192 NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
193 nsIFrame*
194 NS_NewSVGTSpanFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
195 nsIFrame*
196 NS_NewSVGContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
197 nsIFrame*
198 NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
199 extern nsIFrame*
200 NS_NewSVGLinearGradientFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
201 extern nsIFrame*
202 NS_NewSVGRadialGradientFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
203 extern nsIFrame*
204 NS_NewSVGStopFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
205 nsIFrame*
206 NS_NewSVGMarkerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
207 extern nsIFrame*
208 NS_NewSVGImageFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
209 nsIFrame*
210 NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
211 nsIFrame*
212 NS_NewSVGTextPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
213 nsIFrame*
214 NS_NewSVGFilterFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
215 nsIFrame*
216 NS_NewSVGPatternFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
217 nsIFrame*
218 NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
219 nsIFrame*
220 NS_NewSVGLeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
221 #endif
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"
230 #include "prenv.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;
239 #ifdef DEBUG
240 // Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or
241 // more of the following flags (comma separated) for handy debug
242 // output.
243 static PRBool gNoisyContentUpdates = PR_FALSE;
244 static PRBool gReallyNoisyContentUpdates = PR_FALSE;
245 static PRBool gNoisyInlineConstruction = PR_FALSE;
247 struct FrameCtorDebugFlags {
248 const char* name;
249 PRBool* on;
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]))
259 #endif
262 #ifdef MOZ_XUL
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 //------------------------------------------------------------------
275 nsIFrame*
276 NS_NewAutoRepeatBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
278 nsIFrame*
279 NS_NewRootBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
281 nsIFrame*
282 NS_NewDocElementBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
284 nsIFrame*
285 NS_NewThumbFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
287 nsIFrame*
288 NS_NewDeckFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
290 nsIFrame*
291 NS_NewLeafBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
293 nsIFrame*
294 NS_NewStackFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
296 nsIFrame*
297 NS_NewProgressMeterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
299 nsIFrame*
300 NS_NewImageBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
302 nsIFrame*
303 NS_NewTextBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
305 nsIFrame*
306 NS_NewGroupBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
308 nsIFrame*
309 NS_NewButtonBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
311 nsIFrame*
312 NS_NewSplitterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
314 nsIFrame*
315 NS_NewMenuPopupFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
317 nsIFrame*
318 NS_NewPopupSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
320 nsIFrame*
321 NS_NewMenuFrame (nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aFlags);
323 nsIFrame*
324 NS_NewMenuBarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
326 nsIFrame*
327 NS_NewTreeBodyFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
329 // grid
330 nsresult
331 NS_NewGridLayout2 ( nsIPresShell* aPresShell, nsIBoxLayout** aNewLayout );
332 nsIFrame*
333 NS_NewGridRowLeafFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
334 nsIFrame*
335 NS_NewGridRowGroupFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
337 // end grid
339 nsIFrame*
340 NS_NewTitleBarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
342 nsIFrame*
343 NS_NewResizerFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
346 #endif
348 nsIFrame*
349 NS_NewHTMLScrollFrame (nsIPresShell* aPresShell, nsStyleContext* aContext, PRBool aIsRoot);
351 nsIFrame*
352 NS_NewXULScrollFrame (nsIPresShell* aPresShell, nsStyleContext* aContext, PRBool aIsRoot);
354 nsIFrame*
355 NS_NewSliderFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
357 nsIFrame*
358 NS_NewScrollbarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
360 nsIFrame*
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;
370 #endif
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 //----------------------------------------------------------------------
385 static PRBool
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).
399 static PRBool
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.
409 static nsIContent*
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();
420 return nsnull;
423 // Reparent a frame into a wrapper frame that is a child of its old parent.
424 static void
425 ReparentFrame(nsFrameManager* aFrameManager,
426 nsIFrame* aNewParentFrame,
427 nsIFrame* aFrame)
429 aFrame->SetParent(aNewParentFrame);
430 aFrameManager->ReparentStyleContext(aFrame);
433 static void
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
447 // more easily.
449 static inline PRBool
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()));
477 static nsIFrame*
478 GetLastSpecialSibling(nsIFrame* aFrame, PRBool aReturnEmptyTrailingInline)
480 for (nsIFrame *frame = aFrame, *next; ; frame = next) {
481 next = GetSpecialSibling(frame);
482 if (!next ||
483 (!aReturnEmptyTrailingInline && !next->GetFirstChild(nsnull) &&
484 !GetSpecialSibling(next))) {
485 NS_ASSERTION(!next || !IsInlineOutside(frame),
486 "Should have a block here!");
487 return frame;
490 NS_NOTREACHED("unreachable code");
491 return nsnull;
494 static void
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 "
512 "special sibling");
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);
522 static nsIFrame*
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;
530 do {
531 parentFrame = aFrame->GetParent();
533 if (! parentFrame) {
534 NS_ERROR("no unsplit block frame in IB hierarchy");
535 return aFrame;
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())
543 break;
545 aFrame = parentFrame;
546 } while (1);
548 // post-conditions
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");
552 return parentFrame;
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.
568 static void
569 FindFirstBlock(nsFrameList::FrameLinkEnumerator& aLink)
571 for ( ; !aLink.AtEnd(); aLink.Next()) {
572 if (!IsInlineOutside(aLink.NextFrame())) {
573 return;
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())) {
587 break;
590 return link;
593 inline void
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);
610 void
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.
619 if (IsEmpty()) {
620 SetFrames(aChild);
622 else {
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);
639 #ifdef DEBUG
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...
643 ~nsAbsoluteItems() {
644 NS_ASSERTION(!FirstChild(),
645 "Dangling child list. Someone forgot to insert it?");
647 #endif
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
659 void
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 {
674 public:
675 nsFrameConstructorSaveState();
676 ~nsFrameConstructorSaveState();
678 private:
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
698 PendingBinding() {
699 MOZ_COUNT_CTOR(PendingBinding);
701 ~PendingBinding() {
702 MOZ_COUNT_DTOR(PendingBinding);
704 #endif
706 nsRefPtr<nsXBLBinding> mBinding;
709 // Structure used for maintaining state information during the
710 // frame construction process
711 class NS_STACK_CLASS nsFrameConstructorState {
712 public:
713 nsPresContext *mPresContext;
714 nsIPresShell *mPresShell;
715 nsFrameManager *mFrameManager;
717 #ifdef MOZ_XUL
718 // Frames destined for the nsGkAtoms::popupList.
719 nsAbsoluteItems mPopupItems;
720 #endif
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
729 // using this state.
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
736 // together.
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
749 // mode).
750 PRPackedBool mSetPrimaryFrames;
752 nsCOMArray<nsIContent> mGeneratedTextNodesWithInitializer;
754 // Constructor
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
796 * initialized.
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
803 * positioned
804 * @param aCanBeFloated pass false if the frame isn't allowed to be
805 * floated
806 * @param aIsOutOfFlowPopup pass true if the frame is an out-of-flow popup
807 * (XUL-only)
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 {
848 public:
849 PendingBindingAutoPusher(nsFrameConstructorState& aState,
850 PendingBinding* aPendingBinding) :
851 mState(aState),
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;
865 private:
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);
877 protected:
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()),
902 #ifdef MOZ_XUL
903 mPopupItems(nsnull),
904 #endif
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()->
913 HasTransform()),
914 mHavePendingPopupgroup(PR_FALSE),
915 mSetPrimaryFrames(PR_TRUE),
916 mCurrentPendingBindingInsertionPoint(&mPendingBindings)
918 #ifdef MOZ_XUL
919 nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell);
920 if (rootBox) {
921 mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
923 #endif
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()),
935 #ifdef MOZ_XUL
936 mPopupItems(nsnull),
937 #endif
938 mFixedItems(aFixedContainingBlock),
939 mAbsoluteItems(aAbsoluteContainingBlock),
940 mFloatedItems(aFloatContainingBlock),
941 // See PushAbsoluteContaningBlock below
942 mAdditionalStateBits(0),
943 mFixedPosIsAbsPos(aAbsoluteContainingBlock &&
944 aAbsoluteContainingBlock->GetStyleDisplay()->
945 HasTransform()),
946 mHavePendingPopupgroup(PR_FALSE),
947 mSetPrimaryFrames(PR_TRUE),
948 mCurrentPendingBindingInsertionPoint(&mPendingBindings)
950 #ifdef MOZ_XUL
951 nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell);
952 if (rootBox) {
953 mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
955 #endif
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);
975 #ifdef MOZ_XUL
976 ProcessFrameInsertions(mPopupItems, nsGkAtoms::popupList);
977 #endif
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();
984 do {
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));
994 static nsIFrame*
995 AdjustAbsoluteContainingBlock(nsIFrame* aContainingBlockIn)
997 if (!aContainingBlockIn) {
998 return nsnull;
1001 // Always use the container's first continuation. (Inline frames can have
1002 // non-fluid bidi continuations...)
1003 return aContainingBlockIn->GetFirstContinuation();
1006 void
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;
1019 mAbsoluteItems =
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());
1029 void
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);
1043 nsIFrame*
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;
1084 nsresult
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;
1106 #ifdef MOZ_XUL
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;
1115 else
1116 #endif // MOZ_XUL
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;
1148 nsresult rv =
1149 nsCSSFrameConstructor::CreatePlaceholderFrameFor(mPresShell,
1150 aContent,
1151 aNewFrame,
1152 aStyleContext,
1153 aParentFrame,
1154 nsnull,
1155 placeholderType,
1156 &placeholderFrame);
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();
1163 return rv;
1166 placeholderFrame->AddStateBits(mAdditionalStateBits);
1167 // Add the placeholder frame to the flow
1168 aFrameItems.AddChild(placeholderFrame);
1170 #ifdef DEBUG
1171 else {
1172 NS_ASSERTION(aNewFrame->GetParent() == aParentFrame,
1173 "In-flow frame has wrong parent");
1175 #endif
1177 if (aInsertAfter) {
1178 frameItems->InsertFrame(nsnull, aInsertAfterFrame, aNewFrame);
1179 } else {
1180 frameItems->AddChild(aNewFrame);
1183 return NS_OK;
1186 void
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)
1196 #ifdef MOZ_XUL
1197 NS_PRECONDITION(NS_NONXUL_LIST_TEST ||
1198 (&aFrameItems == &mPopupItems &&
1199 aChildListName == nsGkAtoms::popupList),
1200 "Unexpected aFrameItems/aChildListName combination");
1201 #else
1202 NS_PRECONDITION(NS_NONXUL_LIST_TEST,
1203 "Unexpected aFrameItems/aChildListName combination");
1204 #endif
1206 if (aFrameItems.IsEmpty()) {
1207 return;
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);
1223 } else {
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();
1237 if (!lastChild ||
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);
1241 } else {
1242 // try the other children
1243 nsIFrame* insertionPoint = nsnull;
1244 for (nsIFrame* f = childList.FirstChild(); f != lastChild;
1245 f = f->GetNextSibling()) {
1246 PRInt32 compare =
1247 nsLayoutUtils::CompareTreePosition(f, firstNewFrame, containingBlock);
1248 if (compare > 0) {
1249 // f comes after the new children, so stop here and insert after
1250 // the previous frame
1251 break;
1253 insertionPoint = f;
1255 rv = containingBlock->InsertFrames(aChildListName, insertionPoint,
1256 aFrameItems);
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()
1270 : mItems(nsnull),
1271 mFixedPosIsAbsPos(nsnull),
1272 mSavedItems(nsnull),
1273 mSavedFixedPosIsAbsPos(PR_FALSE),
1274 mChildListName(nsnull),
1275 mState(nsnull)
1279 nsFrameConstructorSaveState::~nsFrameConstructorSaveState()
1281 // Restore the state
1282 if (mItems) {
1283 NS_ASSERTION(mState, "Can't have mItems set without having a state!");
1284 mState->ProcessFrameInsertions(*mItems, mChildListName);
1285 *mItems = mSavedItems;
1286 #ifdef DEBUG
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();
1290 #endif
1292 if (mFixedPosIsAbsPos) {
1293 *mFixedPosIsAbsPos = mSavedFixedPosIsAbsPos;
1297 static
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");
1306 return PR_FALSE;
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'
1317 * style contexts.
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.
1325 static void
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);
1346 } else {
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)
1363 , mUpdateCount(0)
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()) {
1380 // now what?
1383 #ifdef DEBUG
1384 static PRBool gFirstTime = PR_TRUE;
1385 if (gFirstTime) {
1386 gFirstTime = PR_FALSE;
1387 char* flags = PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS");
1388 if (flags) {
1389 PRBool error = PR_FALSE;
1390 for (;;) {
1391 char* comma = PL_strchr(flags, ',');
1392 if (comma)
1393 *comma = '\0';
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);
1402 found = PR_TRUE;
1403 break;
1405 ++flag;
1408 if (! found)
1409 error = PR_TRUE;
1411 if (! comma)
1412 break;
1414 *comma = ',';
1415 flags = comma + 1;
1418 if (error) {
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);
1424 ++flag;
1426 printf("Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of flag\n");
1427 printf("names (no whitespace)\n");
1431 #endif
1434 nsIXBLService * nsCSSFrameConstructor::GetXBLService()
1436 if (!gXBLService) {
1437 nsresult rv = CallGetService("@mozilla.org/xbl;1", &gXBLService);
1438 if (NS_FAILED(rv))
1439 gXBLService = nsnull;
1442 return gXBLService;
1445 void
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))
1453 QuotesDirty();
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.
1460 CountersDirty();
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) {}
1474 static void
1475 DestroyGenConInitializer(void* aFrame,
1476 nsIAtom* aPropertyName,
1477 void* aPropertyValue,
1478 void* aDtorData)
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());
1491 if (!content) {
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");
1495 return nsnull;
1497 content->SetText(aString, PR_FALSE);
1498 if (aText) {
1499 *aText = do_QueryInterface(content);
1501 if (aInitializer) {
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
1523 // image object
1524 return nsnull;
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();
1540 switch (type) {
1541 case eStyleContentType_String:
1542 return CreateGenConTextNode(aState,
1543 nsDependentString(data.mContent.mString),
1544 nsnull, nsnull);
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);
1556 PRInt32 error;
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);
1566 else {
1567 if (mDocument->IsHTML() && aParentContent->IsHTML()) {
1568 ToLowerCase(contentString);
1570 attrName = do_GetAtom(contentString);
1573 if (!attrName) {
1574 return nsnull;
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()));
1589 if (!counterList)
1590 return nsnull;
1592 nsCounterUseNode* node =
1593 new nsCounterUseNode(counters, aContentIndex,
1594 type == eStyleContentType_Counters);
1595 if (!node)
1596 return nsnull;
1598 nsGenConInitializer* initializer =
1599 new nsGenConInitializer(node, counterList,
1600 &nsCSSFrameConstructor::CountersDirty);
1601 return CreateGenConTextNode(aState, EmptyString(), &node->mText,
1602 initializer);
1605 case eStyleContentType_Image:
1606 NS_NOTREACHED("handled by if above");
1607 return nsnull;
1609 case eStyleContentType_OpenQuote:
1610 case eStyleContentType_CloseQuote:
1611 case eStyleContentType_NoOpenQuote:
1612 case eStyleContentType_NoCloseQuote:
1614 nsQuoteNode* node =
1615 new nsQuoteNode(type, aContentIndex);
1616 if (!node)
1617 return nsnull;
1619 nsGenConInitializer* initializer =
1620 new nsGenConInitializer(node, &mQuoteList,
1621 &nsCSSFrameConstructor::QuotesDirty);
1622 return CreateGenConTextNode(aState, EmptyString(), &node->mText,
1623 initializer);
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();
1649 nsXPIDLString temp;
1650 nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
1651 "Submit", temp);
1652 return CreateGenConTextNode(aState, temp, nsnull, nsnull);
1655 break;
1657 } // switch
1659 return 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
1675 * ::after style.
1677 void
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");
1688 return;
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(),
1697 aPseudoElement,
1698 aStyleContext);
1699 if (!pseudoStyleContext)
1700 return;
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,
1707 kNameSpaceID_None);
1708 nsCOMPtr<nsIContent> container;
1709 nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
1710 if (NS_FAILED(rv))
1711 return;
1712 container->SetNativeAnonymous();
1714 rv = container->BindToTree(mDocument, aParentContent, aParentContent, PR_TRUE);
1715 if (NS_FAILED(rv)) {
1716 container->UnbindFromTree();
1717 return;
1720 PRUint32 contentCount = pseudoStyleContext->GetStyleContent()->ContentCount();
1721 for (PRUint32 contentIndex = 0; contentIndex < contentCount; contentIndex++) {
1722 nsCOMPtr<nsIContent> content =
1723 CreateGeneratedContent(aState, aParentContent, pseudoStyleContext,
1724 contentIndex);
1725 if (content) {
1726 container->AppendChildTo(content, PR_FALSE);
1730 AddFrameConstructionItemsInternal(aState, container, aParentFrame, elemName,
1731 kNameSpaceID_None, PR_TRUE,
1732 pseudoStyleContext,
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
1743 static PRBool
1744 IsTableRelated(nsIAtom* aParentType)
1746 return
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.
1764 static PRBool
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)));
1785 /* static */
1786 nsCSSFrameConstructor::ParentType
1787 nsCSSFrameConstructor::GetParentType(nsIAtom* aFrameType)
1789 if (aFrameType == nsGkAtoms::tableFrame) {
1790 return eTypeTable;
1792 if (aFrameType == nsGkAtoms::tableRowGroupFrame) {
1793 return eTypeRowGroup;
1795 if (aFrameType == nsGkAtoms::tableRowFrame) {
1796 return eTypeRow;
1798 if (aFrameType == nsGkAtoms::tableColGroupFrame) {
1799 return eTypeColGroup;
1802 return eTypeBlock;
1805 static nsIFrame*
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.
1820 static PRBool
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);
1832 return haveCaption;
1835 void
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
1852 static void
1853 PullOutCaptionFrames(nsFrameItems& aItems, nsFrameItems& aCaptions)
1855 nsIFrame *child = aItems.FirstChild();
1856 while (child) {
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.
1871 nsresult
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,
1881 "Unexpected call");
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
1895 nsIFrame* newFrame;
1896 #ifdef MOZ_MATHML
1897 if (kNameSpaceID_MathML == nameSpaceID)
1898 newFrame = NS_NewMathMLmtableOuterFrame(mPresShell, outerStyleContext);
1899 else
1900 #endif
1901 newFrame = NS_NewTableOuterFrame(mPresShell, outerStyleContext);
1903 nsIFrame* geometricParent =
1904 aState.GetGeometricParent(outerStyleContext->GetStyleDisplay(),
1905 aParentFrame);
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;
1914 #ifdef MOZ_MATHML
1915 if (kNameSpaceID_MathML == nameSpaceID)
1916 innerFrame = NS_NewMathMLmtableFrame(mPresShell, styleContext);
1917 else
1918 #endif
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,
1927 aParentFrame);
1928 if (NS_FAILED(rv)) {
1929 return 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);
1942 } else {
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;
1961 return rv;
1964 nsresult
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,
1973 "Unexpected call");
1974 nsIContent* const content = aItem.mContent;
1975 nsStyleContext* const styleContext = aItem.mStyleContext;
1976 const PRUint32 nameSpaceID = aItem.mNameSpaceID;
1978 nsIFrame* newFrame;
1979 #ifdef MOZ_MATHML
1980 if (kNameSpaceID_MathML == nameSpaceID)
1981 newFrame = NS_NewMathMLmtrFrame(mPresShell, styleContext);
1982 else
1983 #endif
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;
1993 nsresult rv;
1994 if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
1995 rv = ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
1996 childItems);
1997 } else {
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;
2007 return NS_OK;
2010 nsresult
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,
2041 PR_FALSE);
2042 aFrameItems.LastChild()->SetNextContinuation(newCol);
2043 newCol->SetPrevContinuation(aFrameItems.LastChild());
2044 aFrameItems.AddChild(newCol);
2045 newCol->SetColType(eColAnonymousCol);
2048 return NS_OK;
2051 nsresult
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,
2060 "Unexpected call");
2062 nsIContent* const content = aItem.mContent;
2063 nsStyleContext* const styleContext = aItem.mStyleContext;
2064 const PRUint32 nameSpaceID = aItem.mNameSpaceID;
2066 PRBool borderCollapse = IsBorderCollapse(aParentFrame);
2067 nsIFrame* newFrame;
2068 #ifdef MOZ_MATHML
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);
2078 else
2079 #endif
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
2099 PRBool isBlock;
2100 nsIFrame* cellInnerFrame;
2101 #ifdef MOZ_MATHML
2102 if (kNameSpaceID_MathML == nameSpaceID) {
2103 cellInnerFrame = NS_NewMathMLmtdInnerFrame(mPresShell, innerPseudoStyle);
2104 isBlock = PR_FALSE;
2106 else
2107 #endif
2109 cellInnerFrame = NS_NewBlockFormattingContext(mPresShell, innerPseudoStyle);
2110 isBlock = PR_TRUE;
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;
2121 nsresult rv;
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);
2130 } else {
2131 aState.PushFloatContainingBlock(cellInnerFrame, floatSaveState);
2134 rv = ConstructFramesFromItemList(aState, aItem.mChildItems, cellInnerFrame,
2135 childItems);
2136 } else {
2137 // Process the child content
2138 rv = ProcessChildren(aState, content, styleContext, cellInnerFrame,
2139 PR_TRUE, childItems, isBlock, aItem.mPendingBinding);
2142 if (NS_FAILED(rv)) {
2143 // Clean up
2144 // XXXbz kids of this stuff need to be cleaned up too!
2145 cellInnerFrame->Destroy();
2146 newFrame->Destroy();
2147 return rv;
2150 cellInnerFrame->SetInitialChildList(nsnull, childItems);
2151 SetInitialSingleChild(newFrame, cellInnerFrame);
2152 aFrameItems.AddChild(newFrame);
2153 *aNewFrame = newFrame;
2155 return NS_OK;
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
2175 // whitespace.
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
2182 // list.
2183 if (!aParentFrame->IsFrameOfType(nsIFrame::eExcludesIgnorableWhitespace) ||
2184 aParentFrame->IsGeneratedContentFrame() ||
2185 !aChildContent->IsNodeOfType(nsINode::eTEXT)) {
2186 return PR_TRUE;
2189 aChildContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
2190 NS_REFRAME_IF_WHITESPACE);
2191 return !aChildContent->TextIsOnlyWhitespace();
2194 /***********************************************
2195 * END TABLE SECTION
2196 ***********************************************/
2198 static PRBool CheckOverflow(nsPresContext* aPresContext,
2199 const nsStyleDisplay* aDisplay)
2201 if (aDisplay->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
2202 return PR_FALSE;
2204 if (aDisplay->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
2205 aPresContext->SetViewportOverflowOverride(NS_STYLE_OVERFLOW_HIDDEN,
2206 NS_STYLE_OVERFLOW_HIDDEN);
2207 else
2208 aPresContext->SetViewportOverflowOverride(aDisplay->mOverflowX,
2209 aDisplay->mOverflowY);
2210 return PR_TRUE;
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.
2221 nsIContent*
2222 nsCSSFrameConstructor::PropagateScrollToViewport()
2224 // Set default
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()) {
2232 return nsnull;
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);
2241 if (!rootStyle) {
2242 return nsnull;
2244 if (CheckOverflow(presContext, rootStyle->GetStyleDisplay())) {
2245 // tell caller we stole the overflow style from the root element
2246 return docElement;
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
2253 // of the viewport
2254 // XXX what about XHTML?
2255 nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
2256 if (!htmlDoc || !docElement->IsHTML()) {
2257 return nsnull;
2260 nsCOMPtr<nsIDOMHTMLElement> body;
2261 htmlDoc->GetBody(getter_AddRefs(body));
2262 nsCOMPtr<nsIContent> bodyElement = do_QueryInterface(body);
2264 if (!bodyElement ||
2265 !bodyElement->NodeInfo()->Equals(nsGkAtoms::body)) {
2266 // The body is not a <body> tag, it's a <frameset>.
2267 return nsnull;
2270 nsRefPtr<nsStyleContext> bodyStyle;
2271 bodyStyle = styleSet->ResolveStyleFor(bodyElement->AsElement(), rootStyle);
2272 if (!bodyStyle) {
2273 return nsnull;
2276 if (CheckOverflow(presContext, bodyStyle->GetStyleDisplay())) {
2277 // tell caller we stole the overflow style from the body element
2278 return bodyElement;
2281 return nsnull;
2284 nsresult
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
2300 // properly.
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
2319 // siblings.
2320 aDocElement->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS);
2322 // --------- CREATE AREA OR BOX FRAME -------
2323 nsRefPtr<nsStyleContext> styleContext;
2324 styleContext = mPresShell->StyleSet()->ResolveStyleFor(aDocElement,
2325 nsnull);
2327 const nsStyleDisplay* display = styleContext->GetStyleDisplay();
2329 // Ensure that our XBL bindings are installed.
2330 if (display->mBinding) {
2331 // Get the XBL loader.
2332 nsresult rv;
2333 PRBool resolveStyle;
2335 nsIXBLService * xblService = GetXBLService();
2336 if (!xblService)
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),
2343 &resolveStyle);
2344 if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED)
2345 return NS_OK; // Binding will load asynchronously.
2347 if (binding) {
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);
2354 if (resolveStyle) {
2355 styleContext = mPresShell->StyleSet()->ResolveStyleFor(aDocElement,
2356 nsnull);
2357 display = styleContext->GetStyleDisplay();
2361 // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2363 #ifdef DEBUG
2364 NS_ASSERTION(!display->IsScrollableOverflow() ||
2365 state.mPresContext->IsPaginated() ||
2366 propagatedScrollFrom == aDocElement,
2367 "Scrollbars should have been propagated to the viewport");
2368 #endif
2370 if (NS_UNLIKELY(display->mDisplay == NS_STYLE_DISPLAY_NONE)) {
2371 state.mFrameManager->SetUndisplayedContent(aDocElement, styleContext);
2372 return NS_OK;
2375 nsFrameConstructorSaveState absoluteSaveState;
2376 if (mHasRootAbsPosContainingBlock) {
2377 // Push the absolute containing block now so we can absolutely position
2378 // the root element
2379 state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
2380 absoluteSaveState);
2383 nsresult rv;
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
2394 // placeholder.
2395 nsIFrame* contentFrame;
2396 PRBool processChildren = PR_FALSE;
2398 // Check whether we need to build a XUL box or SVG root frame
2399 #ifdef MOZ_XUL
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,
2406 contentFrame);
2407 *aNewFrame = contentFrame;
2408 processChildren = PR_TRUE;
2410 else
2411 #endif
2412 #ifdef MOZ_SVG
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()) {
2430 return rv;
2432 *aNewFrame = frameItems.FirstChild();
2433 processChildren = PR_TRUE;
2435 // See if we need to create a view
2436 nsHTMLContainerFrame::CreateViewForFrame(contentFrame, PR_FALSE);
2437 } else {
2438 return NS_ERROR_FAILURE;
2441 else
2442 #endif
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);
2465 if (NS_FAILED(rv))
2466 return rv;
2467 if (!contentFrame || frameItems.IsEmpty())
2468 return NS_ERROR_FAILURE;
2469 *aNewFrame = frameItems.FirstChild();
2470 NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2471 } else {
2472 contentFrame = NS_NewBlockFrame(mPresShell, styleContext,
2473 NS_BLOCK_FLOAT_MGR|NS_BLOCK_MARGIN_ROOT);
2474 if (!contentFrame)
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(),
2483 nsnull);
2484 if (NS_FAILED(rv) || frameItems.IsEmpty())
2485 return rv;
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.
2502 PRBool isChild;
2503 contentFrame->GetParentStyleContextFrame(state.mPresContext,
2504 &mRootElementStyleFrame, &isChild);
2505 if (!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);
2525 return NS_OK;
2529 nsresult
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
2558 nsIView* rootView;
2559 mPresShell->GetViewManager()->GetRootView(rootView);
2560 viewportFrame->SetView(rootView);
2562 nsContainerFrame::SyncFrameViewProperties(mPresShell->GetPresContext(), viewportFrame,
2563 viewportPseudoStyle, rootView);
2564 nsContainerFrame::SyncWindowProperties(mPresShell->GetPresContext(), viewportFrame,
2565 rootView);
2567 // The viewport is the containing block for 'fixed' elements
2568 mFixedContainingBlock = viewportFrame;
2570 *aNewFrame = viewportFrame;
2571 return NS_OK;
2574 nsresult
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]
2589 nsHTMLScrollFrame
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]
2603 nsRootBoxFrame
2604 root element frame (nsDocElementBoxFrame)
2606 Print presentation, non-XUL
2608 ViewportFrame
2609 nsSimplePageSequenceFrame
2610 nsPageFrame [fixed-cb]
2611 nsPageContentFrame
2612 nsCanvasFrame [abs-cb]
2613 root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2614 nsTableOuterFrame, nsPlaceholderFrame)
2616 Print-preview presentation, non-XUL
2618 ViewportFrame
2619 nsHTMLScrollFrame
2620 nsSimplePageSequenceFrame
2621 nsPageFrame [fixed-cb]
2622 nsPageContentFrame
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
2633 the root element.
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
2645 // root frame.
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;
2660 if (!isPaginated) {
2661 #ifdef MOZ_XUL
2662 if (aDocElement->IsXUL())
2664 // pass a temporary stylecontext, the correct one will be set later
2665 rootFrame = NS_NewRootBoxFrame(mPresShell, viewportPseudoStyle);
2666 } else
2667 #endif
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;
2676 } else {
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
2693 // the viewport.
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;
2704 if (!isHTML) {
2705 isXUL = aDocElement->IsXUL();
2708 // Never create scrollbars for XUL documents
2709 PRBool isScrollable = !isXUL;
2711 // Never create scrollbars for frameset documents.
2712 if (isHTML) {
2713 nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
2714 if (htmlDoc && htmlDoc->GetIsFrameset())
2715 isScrollable = PR_FALSE;
2718 if (isPaginated) {
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
2724 // propagated
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);
2742 } else {
2743 if (rootPseudo == nsCSSAnonBoxes::canvas) {
2744 rootPseudo = nsCSSAnonBoxes::scrolledCanvas;
2745 } else {
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
2754 // created.
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.
2768 newFrame = nsnull;
2769 rootPseudoStyle = BeginBuildingScrollFrame( state,
2770 aDocElement,
2771 styleContext,
2772 viewportFrame,
2773 rootPseudo,
2774 PR_TRUE,
2775 newFrame);
2776 parentFrame = newFrame;
2777 mGfxScrollFrame = newFrame;
2780 rootFrame->SetStyleContextWithoutNotification(rootPseudoStyle);
2781 rootFrame->Init(aDocElement, parentFrame, nsnull);
2783 if (isScrollable) {
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);
2803 } else {
2804 nsFrameList newFrameList(newFrame, newFrame);
2805 viewportFrame->AppendFrames(nsnull, newFrameList);
2808 return NS_OK;
2811 nsresult
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,
2837 pagePseudoStyle);
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);
2870 return NS_OK;
2873 /* static */
2874 nsresult
2875 nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell* aPresShell,
2876 nsIContent* aContent,
2877 nsIFrame* aFrame,
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,
2890 aTypeBit);
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);
2905 return NS_OK;
2907 else {
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.
2918 static inline void
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);
2929 nsresult
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);
2945 else {
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();
2957 return rv;
2959 // See if we need to create a view
2960 nsHTMLContainerFrame::CreateViewForFrame(buttonFrame, PR_FALSE);
2962 nsRefPtr<nsStyleContext> innerBlockContext;
2963 innerBlockContext =
2964 mPresShell->StyleSet()->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::buttonContent,
2965 styleContext);
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();
2978 return rv;
2981 rv = aState.AddChild(buttonFrame, aFrameItems, content, styleContext,
2982 aParentFrame);
2983 if (NS_FAILED(rv)) {
2984 blockFrame->Destroy();
2985 buttonFrame->Destroy();
2986 return rv;
2989 PRBool isLeaf = buttonFrame->IsLeaf();
2990 #ifdef DEBUG
2991 // Make sure that we're an anonymous content creator exactly when we're a
2992 // leaf
2993 nsIAnonymousContentCreator* creator = do_QueryFrame(buttonFrame);
2994 NS_ASSERTION(!creator == !isLeaf,
2995 "Should be creator exactly when we're a leaf");
2996 #endif
2998 if (!isLeaf) {
2999 // Process children
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);
3009 #ifdef DEBUG
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!");
3013 #endif
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);
3026 if (isLeaf) {
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
3032 // ProcessChildren!
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;
3045 return NS_OK;
3048 nsresult
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));
3064 PRInt32 size = 1;
3065 if (sel) {
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,
3091 aParentFrame);
3092 if (NS_FAILED(rv)) {
3093 return 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);
3108 // Create a listbox
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,
3153 popupItems);
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);
3162 } else {
3163 ///////////////////////////////////////////////////////////////////
3164 // ListBox - Old Native Implementation
3165 ///////////////////////////////////////////////////////////////////
3166 nsIFrame* listFrame = NS_NewListControlFrame(mPresShell, styleContext);
3167 if (listFrame) {
3168 rv = NS_OK;
3170 else {
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;
3187 return rv;
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.
3196 nsresult
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();
3209 // Initialize it
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)) {
3223 return 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");
3232 if (view) {
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);
3250 // Process children
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);
3265 return NS_OK;
3268 nsresult
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;
3284 // Initialize it
3285 InitAndRestoreFrame(aState, content,
3286 aState.GetGeometricParent(aStyleDisplay, aParentFrame),
3287 nsnull, newFrame);
3289 // See if we need to create a view, e.g. the frame is absolutely
3290 // positioned
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,
3304 aParentFrame);
3305 if (NS_FAILED(rv)) {
3306 return rv;
3309 // Process children
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());
3329 if (legendFrame) {
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);
3338 break;
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;
3351 return NS_OK;
3354 static nsIFrame*
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)
3363 return f;
3365 return nsnull;
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 }
3372 /* static */
3373 const nsCSSFrameConstructor::FrameConstructionData*
3374 nsCSSFrameConstructor::FindTextData(nsIFrame* aParentFrame)
3376 #ifdef MOZ_SVG
3377 if (aParentFrame && aParentFrame->IsFrameOfType(nsIFrame::eSVG)) {
3378 nsIFrame *ancestorFrame =
3379 nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame);
3380 if (ancestorFrame) {
3381 nsSVGTextContainerFrame* metrics = do_QueryFrame(ancestorFrame);
3382 if (metrics) {
3383 static const FrameConstructionData sSVGGlyphData =
3384 SIMPLE_FCDATA(NS_NewSVGGlyphFrame);
3385 return &sSVGGlyphData;
3388 return nsnull;
3390 #endif
3392 static const FrameConstructionData sTextData =
3393 FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT, NS_NewTextFrame);
3394 return &sTextData;
3397 nsresult
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,
3413 nsnull, newFrame);
3415 if (NS_FAILED(rv)) {
3416 newFrame->Destroy();
3417 return rv;
3420 // We never need to create a view for a text frame.
3422 if (newFrame->IsGeneratedContentFrame()) {
3423 nsAutoPtr<nsGenConInitializer> initializer;
3424 initializer =
3425 static_cast<nsGenConInitializer*>(
3426 aContent->UnsetProperty(nsGkAtoms::genConInitializerProperty));
3427 if (initializer) {
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);
3442 return rv;
3445 /* static */
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;
3455 curData != endData;
3456 ++curData) {
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);
3463 return data;
3467 return nsnull;
3470 /* static */
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;
3480 curData != endData;
3481 ++curData) {
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);
3488 return data;
3492 return nsnull;
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) }
3509 /* static */
3510 const nsCSSFrameConstructor::FrameConstructionData*
3511 nsCSSFrameConstructor::FindHTMLData(nsIContent* aContent,
3512 nsIAtom* aTag,
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) {
3521 return nsnull;
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 &&
3530 (!aParentFrame ||
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.
3547 return nsnull;
3550 static const FrameConstructionDataByTag sHTMLData[] = {
3551 SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData),
3552 SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,
3553 nsCSSFrameConstructor::FindImgData),
3554 { &nsGkAtoms::br,
3555 FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_LINE_BREAK,
3556 NS_NewBRFrame) },
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),
3575 #endif
3576 SIMPLE_TAG_CREATE(isindex, NS_NewIsIndexFrame)
3579 return FindDataByTag(aTag, aContent, aStyleContext, sHTMLData,
3580 NS_ARRAY_LENGTH(sHTMLData));
3583 /* static */
3584 const nsCSSFrameConstructor::FrameConstructionData*
3585 nsCSSFrameConstructor::FindImgData(nsIContent* aContent,
3586 nsStyleContext* aStyleContext)
3588 if (!nsImageFrame::ShouldCreateImageFrameFor(aContent, aStyleContext)) {
3589 return nsnull;
3592 static const FrameConstructionData sImgData = SIMPLE_FCDATA(NS_NewImageFrame);
3593 return &sImgData;
3596 /* static */
3597 const nsCSSFrameConstructor::FrameConstructionData*
3598 nsCSSFrameConstructor::FindImgControlData(nsIContent* aContent,
3599 nsStyleContext* aStyleContext)
3601 if (!nsImageFrame::ShouldCreateImageFrameFor(aContent, aStyleContext)) {
3602 return nsnull;
3605 static const FrameConstructionData sImgControlData =
3606 SIMPLE_FCDATA(NS_NewImageControlFrame);
3607 return &sImgControlData;
3610 /* static */
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));
3644 /* static */
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
3652 PRUint32 type;
3653 if (aContent->IntrinsicState() &
3654 (NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_USERDISABLED |
3655 NS_EVENT_STATE_SUPPRESSED)) {
3656 type = nsIObjectLoadingContent::TYPE_NULL;
3657 } else {
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,
3668 NS_NewEmptyFrame),
3669 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_PLUGIN,
3670 NS_NewObjectFrame),
3671 SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE,
3672 NS_NewImageFrame),
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));
3682 nsresult
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);
3701 #ifdef MOZ_MATHML
3702 CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_WRAP_KIDS_IN_BLOCKS);
3703 #endif
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();
3717 nsIFrame* newFrame;
3718 nsIFrame* primaryFrame;
3719 if (bits & FCDATA_FUNC_IS_FULL_CTOR) {
3720 nsresult rv =
3721 (this->*(data->mFullConstructor))(aState, aItem, aParentFrame,
3722 display, aFrameItems, &newFrame);
3723 if (NS_FAILED(rv)) {
3724 return rv;
3727 primaryFrame = newFrame;
3728 } else {
3729 nsIContent* const content = aItem.mContent;
3731 newFrame =
3732 (*data->mFunc.mCreationFunc)(mPresShell, styleContext);
3733 if (!newFrame) {
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)
3748 : 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);
3758 } else {
3759 rv = InitAndRestoreFrame(aState, content, geometricParent, nsnull,
3760 newFrame);
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
3771 // primary frame).
3772 primaryFrame = frameToAddToList;
3774 rv = aState.AddChild(frameToAddToList, aFrameItems, content, styleContext,
3775 aParentFrame, allowOutOfFlow, allowOutOfFlow, isPopup);
3776 if (NS_FAILED(rv)) {
3777 return rv;
3780 #ifdef MOZ_XUL
3781 // Icky XUL stuff, sadly
3783 if (aItem.mIsRootPopupgroup) {
3784 NS_ASSERTION(nsIRootBox::GetRootBox(mPresShell) &&
3785 nsIRootBox::GetRootBox(mPresShell)->GetPopupSetFrame() ==
3786 newFrame,
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,
3805 childItems);
3806 } else {
3807 // Process the child frames.
3808 rv = ProcessChildren(aState, content, styleContext, newFrame,
3809 !(bits & FCDATA_DISALLOW_GENERATED_CONTENT),
3810 childItems,
3811 (bits & FCDATA_ALLOW_BLOCK_STYLES) != 0,
3812 aItem.mPendingBinding);
3815 #ifdef MOZ_XUL
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);
3822 if (rootBox) {
3823 rootBox->AddTooltipSupport(content);
3826 #endif
3828 #ifdef MOZ_MATHML
3829 if (NS_SUCCEEDED(rv) && (bits & FCDATA_WRAP_KIDS_IN_BLOCKS)) {
3830 nsFrameItems newItems;
3831 nsFrameItems currentBlock;
3832 nsIFrame* f;
3833 while ((f = childItems.FirstChild()) != nsnull) {
3834 PRBool wrapFrame = IsInlineFrame(f) || IsFrameSpecial(f);
3835 if (!wrapFrame) {
3836 rv = FlushAccumulatedBlock(aState, content, newFrame, &currentBlock, &newItems);
3837 if (NS_FAILED(rv))
3838 break;
3841 childItems.RemoveFrame(f);
3842 if (wrapFrame) {
3843 currentBlock.AddChild(f);
3844 } else {
3845 newItems.AddChild(f);
3848 rv = FlushAccumulatedBlock(aState, content, newFrame, &currentBlock, &newItems);
3850 if (childItems.NotEmpty()) {
3851 // an error must have occurred, delete unprocessed frames
3852 childItems.DestroyFrames();
3855 childItems = newItems;
3857 #endif
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);
3873 return NS_OK;
3876 // after the node has been constructed and initialized create any
3877 // anonymous content a node needs.
3878 nsresult
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();
3890 if (count == 0) {
3891 return NS_OK;
3894 nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
3895 aPendingBinding);
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);
3906 if (newFrame) {
3907 NS_ASSERTION(content->GetPrimaryFrame(),
3908 "Content must have a primary frame now");
3909 aChildItems.AddChild(newFrame);
3911 else {
3912 // create the frame and attach it to our frame
3913 ConstructFrame(aState, content, aParentFrame, aChildItems);
3917 return NS_OK;
3920 nsresult
3921 nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
3922 nsIFrame* aParentFrame,
3923 nsTArray<nsIContent*>& aContent)
3925 nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
3926 if (!creator)
3927 return NS_OK;
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?");
3938 #ifdef MOZ_SVG
3939 // least-surprise CSS binding until we do the SVG specified
3940 // cascading rules for <svg:use> - bug 265894
3941 if (aParent &&
3942 aParent->NodeInfo()->Equals(nsGkAtoms::use, kNameSpaceID_SVG)) {
3943 content->SetFlags(NODE_IS_ANONYMOUS);
3944 } else
3945 #endif
3947 content->SetNativeAnonymous();
3950 rv = content->BindToTree(mDocument, aParent, aParent, PR_TRUE);
3951 if (NS_FAILED(rv)) {
3952 content->UnbindFromTree();
3953 return rv;
3957 return NS_OK;
3960 static
3961 PRBool IsXULDisplayType(const nsStyleDisplay* aDisplay)
3963 return (aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_BOX ||
3964 #ifdef MOZ_XUL
3965 aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_GRID ||
3966 aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_STACK ||
3967 #endif
3968 aDisplay->mDisplay == NS_STYLE_DISPLAY_BOX
3969 #ifdef MOZ_XUL
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
3977 #endif
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, \
3985 _func)
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) }
3998 static
3999 nsIFrame* NS_NewGridBoxFrame(nsIPresShell* aPresShell,
4000 nsStyleContext* aStyleContext)
4002 nsCOMPtr<nsIBoxLayout> layout;
4003 NS_NewGridLayout2(aPresShell, getter_AddRefs(layout));
4004 if (!layout) {
4005 return nsnull;
4008 return NS_NewBoxFrame(aPresShell, aStyleContext, PR_FALSE, layout);
4011 /* static */
4012 const nsCSSFrameConstructor::FrameConstructionData*
4013 nsCSSFrameConstructor::FindXULTagData(nsIContent* aContent,
4014 nsIAtom* aTag,
4015 PRInt32 aNameSpaceID,
4016 nsStyleContext* aStyleContext)
4018 if (aNameSpaceID != kNameSpaceID_XUL) {
4019 return nsnull;
4022 static const FrameConstructionDataByTag sXULTagData[] = {
4023 #ifdef MOZ_XUL
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),
4041 #ifdef XP_MACOSX
4042 SIMPLE_TAG_CHAIN(menubar, nsCSSFrameConstructor::FindXULMenubarData),
4043 #else
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));
4065 #ifdef MOZ_XUL
4066 /* static */
4067 const nsCSSFrameConstructor::FrameConstructionData*
4068 nsCSSFrameConstructor::FindPopupGroupData(nsIContent* aContent,
4069 nsStyleContext* /* unused */)
4071 if (!aContent->IsRootOfNativeAnonymousSubtree()) {
4072 return nsnull;
4075 static const FrameConstructionData sPopupSetData =
4076 SIMPLE_XUL_FCDATA(NS_NewPopupSetFrame);
4077 return &sPopupSetData;
4080 /* static */
4081 const nsCSSFrameConstructor::FrameConstructionData
4082 nsCSSFrameConstructor::sXULTextBoxData = SIMPLE_XUL_FCDATA(NS_NewTextBoxFrame);
4084 /* static */
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);
4095 return &sLabelData;
4098 static nsIFrame*
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);
4107 /* static */
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;
4121 #ifdef XP_MACOSX
4122 /* static */
4123 const nsCSSFrameConstructor::FrameConstructionData*
4124 nsCSSFrameConstructor::FindXULMenubarData(nsIContent* aContent,
4125 nsStyleContext* aStyleContext)
4127 nsCOMPtr<nsISupports> container =
4128 aStyleContext->PresContext()->GetContainer();
4129 if (container) {
4130 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(container));
4131 if (treeItem) {
4132 PRInt32 type;
4133 treeItem->GetItemType(&type);
4134 if (nsIDocShellTreeItem::typeChrome == type) {
4135 nsCOMPtr<nsIDocShellTreeItem> parent;
4136 treeItem->GetParent(getter_AddRefs(parent));
4137 if (!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 */
4153 /* static */
4154 const nsCSSFrameConstructor::FrameConstructionData*
4155 nsCSSFrameConstructor::FindXULListBoxBodyData(nsIContent* aContent,
4156 nsStyleContext* aStyleContext)
4158 if (aStyleContext->GetStyleDisplay()->mDisplay !=
4159 NS_STYLE_DISPLAY_GRID_GROUP) {
4160 return nsnull;
4163 static const FrameConstructionData sListBoxBodyData =
4164 SCROLLABLE_XUL_FCDATA(NS_NewListBoxBodyFrame);
4165 return &sListBoxBodyData;
4168 /* static */
4169 const nsCSSFrameConstructor::FrameConstructionData*
4170 nsCSSFrameConstructor::FindXULListItemData(nsIContent* aContent,
4171 nsStyleContext* aStyleContext)
4173 if (aStyleContext->GetStyleDisplay()->mDisplay !=
4174 NS_STYLE_DISPLAY_GRID_LINE) {
4175 return nsnull;
4178 static const FrameConstructionData sListItemData =
4179 SCROLLABLE_XUL_FCDATA(NS_NewListItemFrame);
4180 return &sListItemData;
4183 #endif /* MOZ_XUL */
4185 /* static */
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),
4194 #ifdef MOZ_XUL
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,
4222 PRBool aIsRoot,
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
4233 // HTMLScrollFrame
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);
4238 } else {
4239 gfxScrollFrame = NS_NewHTMLScrollFrame(mPresShell, contentStyle, aIsRoot);
4242 InitAndRestoreFrame(aState, aContent, aParentFrame, nsnull, gfxScrollFrame);
4244 // Create a view
4245 nsHTMLContainerFrame::CreateViewForFrame(gfxScrollFrame, PR_FALSE);
4248 // if there are any anonymous children for the scroll frame, create
4249 // frames for them.
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,
4254 anonymousItems);
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;
4270 void
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 ------
4285 * ScrollFrame
4288 * Frame (scrolled frame you passed in)
4291 *-----------------------------------
4292 * LEGEND:
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
4300 * returned.
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)
4310 nsresult
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);
4327 return NS_OK;
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
4338 // block-level.
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));
4437 nsresult
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?
4468 return rv;
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,
4476 aParentFrame);
4477 return rv;
4480 nsresult
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);
4494 } else {
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);
4506 nsresult
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");
4520 if (!aNewFrame)
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)) {
4534 CountersDirty();
4537 return rv;
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);
4549 if (aParentFrame) {
4550 // Resolve the style context based on the content object and the parent
4551 // style context
4552 parentStyleContext = aParentFrame->GetStyleContext();
4553 } else {
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);
4581 // MathML Mod - RBS
4582 #ifdef MOZ_MATHML
4583 nsresult
4584 nsCSSFrameConstructor::FlushAccumulatedBlock(nsFrameConstructorState& aState,
4585 nsIContent* aContent,
4586 nsIFrame* aParentFrame,
4587 nsFrameItems* aBlockItems,
4588 nsFrameItems* aNewItems)
4590 if (aBlockItems->IsEmpty()) {
4591 // Nothing to do
4592 return NS_OK;
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,
4602 parentContext);
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);
4620 return NS_OK;
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) }
4631 /* static */
4632 const nsCSSFrameConstructor::FrameConstructionData*
4633 nsCSSFrameConstructor::FindMathMLData(nsIContent* aContent,
4634 nsIAtom* aTag,
4635 PRInt32 aNameSpaceID,
4636 nsStyleContext* aStyleContext)
4638 // Make sure that we remain confined in the MathML world
4639 if (aNameSpaceID != kNameSpaceID_MathML)
4640 return nsnull;
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
4699 #ifdef MOZ_SVG
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) }
4709 /* static */
4710 const nsCSSFrameConstructor::FrameConstructionData*
4711 nsCSSFrameConstructor::FindSVGData(nsIContent* aContent,
4712 nsIAtom* aTag,
4713 PRInt32 aNameSpaceID,
4714 nsIFrame* aParentFrame,
4715 nsStyleContext* aStyleContext)
4717 if (aNameSpaceID != kNameSpaceID_SVG || !NS_SVGEnabled()) {
4718 return nsnull;
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) {
4732 PRInt32 parentNSID;
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.
4775 // XXX FIXME XXX
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) {
4782 if (parentIsSVG) {
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
4804 if (metrics) {
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);
4815 if (!metrics) {
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));
4885 if (!data) {
4886 data = &sGenericContainerData;
4889 return data;
4892 nsresult
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)) {
4915 return 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;
4946 return rv;
4949 #endif // MOZ_SVG
4951 void
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.)
4961 pseudoStyle =
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);
4978 nsresult
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");
4992 nsresult rv =
4993 ConstructFramesFromItem(aState, iter, aParentFrame, aFrameItems);
4994 NS_ENSURE_SUCCESS(rv, rv);
4997 return NS_OK;
5000 void
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)) {
5021 return;
5024 // never create frames for comments or PIs
5025 if (aContent->IsNodeOfType(nsINode::eCOMMENT) ||
5026 aContent->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION))
5027 return;
5029 nsRefPtr<nsStyleContext> styleContext;
5030 styleContext = ResolveStyleContext(aParentFrame, aContent);
5032 AddFrameConstructionItemsInternal(aState, aContent, aParentFrame,
5033 aContent->Tag(), aContent->GetNameSpaceID(),
5034 aSuppressWhiteSpaceOptimizations,
5035 styleContext,
5036 ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK,
5037 aItems);
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.
5046 static void
5047 SetAsUndisplayedContent(nsFrameManager* aFrameManager, nsIContent* aContent,
5048 nsStyleContext* aStyleContext,
5049 PRBool aIsGeneratedContent)
5051 if (aStyleContext->GetPseudo()) {
5052 if (aIsGeneratedContent) {
5053 aContent->UnbindFromTree();
5055 return;
5058 NS_ASSERTION(!aIsGeneratedContent, "Should have had pseudo type");
5059 aFrameManager->SetUndisplayedContent(aContent, aStyleContext);
5062 void
5063 nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState& aState,
5064 nsIContent* aContent,
5065 nsIFrame* aParentFrame,
5066 nsIAtom* aTag,
5067 PRInt32 aNameSpaceID,
5068 PRBool aSuppressWhiteSpaceOptimizations,
5069 nsStyleContext* aStyleContext,
5070 PRUint32 aFlags,
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();
5084 if (!xblService)
5085 return;
5087 PRBool resolveStyle;
5089 nsAutoPtr<PendingBinding> newPendingBinding(new PendingBinding());
5090 if (!newPendingBinding) {
5091 return;
5093 nsresult rv = xblService->LoadBindings(aContent, display->mBinding->mURI,
5094 display->mBinding->mOriginPrincipal,
5095 PR_FALSE,
5096 getter_AddRefs(newPendingBinding->mBinding),
5097 &resolveStyle);
5098 if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED)
5099 return;
5101 if (newPendingBinding->mBinding) {
5102 pendingBinding = newPendingBinding;
5103 // aState takes over owning newPendingBinding
5104 aState.AddPendingBinding(newPendingBinding.forget());
5107 if (resolveStyle) {
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
5119 // any frame at all
5120 if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
5121 SetAsUndisplayedContent(aState.mFrameManager, aContent, styleContext,
5122 isGeneratedContent);
5123 return;
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;
5130 if (isText) {
5131 data = FindTextData(aParentFrame);
5132 #ifdef MOZ_SVG
5133 if (!data) {
5134 // Nothing to do here; suppressed text inside SVG
5135 return;
5137 #endif /* MOZ_SVG */
5138 } else {
5139 #ifdef MOZ_SVG
5140 // Don't create frames for non-SVG element children of SVG elements.
5141 if (aNameSpaceID != kNameSpaceID_SVG &&
5142 aParentFrame &&
5143 aParentFrame->IsFrameOfType(nsIFrame::eSVG) &&
5144 !aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)
5146 SetAsUndisplayedContent(aState.mFrameManager, aContent, styleContext,
5147 isGeneratedContent);
5148 return;
5150 #endif /* MOZ_SVG */
5152 data = FindHTMLData(aContent, aTag, aNameSpaceID, aParentFrame,
5153 styleContext);
5154 if (!data) {
5155 data = FindXULTagData(aContent, aTag, aNameSpaceID, styleContext);
5157 #ifdef MOZ_MATHML
5158 if (!data) {
5159 data = FindMathMLData(aContent, aTag, aNameSpaceID, styleContext);
5161 #endif
5162 #ifdef MOZ_SVG
5163 if (!data) {
5164 data = FindSVGData(aContent, aTag, aNameSpaceID, aParentFrame,
5165 styleContext);
5167 #endif /* MOZ_SVG */
5169 // Now check for XUL display types
5170 if (!data) {
5171 data = FindXULDisplayData(display, aContent, styleContext);
5174 // And general display types
5175 if (!data) {
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);
5184 return;
5187 #ifdef MOZ_XUL
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);
5195 return;
5198 isPopup = PR_TRUE;
5200 #endif /* MOZ_XUL */
5203 PRUint32 bits = data->mBits;
5205 // Inside colgroups, suppress everything except columns.
5206 if (aParentFrame &&
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);
5212 return;
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);
5229 if (!item) {
5230 if (isGeneratedContent) {
5231 aContent->UnbindFromTree();
5233 return;
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
5255 // right now.
5256 BuildInlineChildItems(aState, *item);
5257 item->mHasInlineEnds = PR_TRUE;
5258 item->mIsBlock = PR_FALSE;
5259 } else {
5260 // Compute a boolean isInline which is guaranteed to be false for blocks
5261 // (but may also be false for some inlines).
5262 PRBool isInline =
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
5265 // pseudos.
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.
5272 isPopup;
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
5286 // as.
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.
5300 item->mIsBlock =
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();
5322 static void
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()
5340 : AfterProperty();
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.
5351 PRBool
5352 nsCSSFrameConstructor::AtLineBoundary(FCItemIterator& aIter)
5354 if (aIter.item().mSuppressWhiteSpaceOptimizations) {
5355 return PR_FALSE;
5358 if (aIter.AtStart()) {
5359 if (aIter.List()->HasLineBoundaryAtStart() &&
5360 !aIter.item().mContent->GetPreviousSibling())
5361 return PR_TRUE;
5362 } else {
5363 FCItemIterator prev = aIter;
5364 prev.Prev();
5365 if (prev.item().IsLineBoundary() &&
5366 !prev.item().mSuppressWhiteSpaceOptimizations &&
5367 aIter.item().mContent->GetPreviousSibling() == prev.item().mContent)
5368 return PR_TRUE;
5371 FCItemIterator next = aIter;
5372 next.Next();
5373 if (next.IsDone()) {
5374 if (aIter.List()->HasLineBoundaryAtEnd() &&
5375 !aIter.item().mContent->GetNextSibling())
5376 return PR_TRUE;
5377 } else {
5378 if (next.item().IsLineBoundary() &&
5379 !next.item().mSuppressWhiteSpaceOptimizations &&
5380 aIter.item().mContent->GetNextSibling() == next.item().mContent)
5381 return PR_TRUE;
5384 return PR_FALSE;
5387 nsresult
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);
5398 if (item.mIsText) {
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))
5418 return NS_OK;
5420 return ConstructTextFrame(item.mFCData, aState, item.mContent,
5421 adjParentFrame, styleContext,
5422 aFrameItems);
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()),
5443 item.mContent);
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,
5452 aFrameItems);
5454 aState.mAdditionalStateBits = savedStateBits;
5456 return rv;
5460 inline PRBool
5461 IsRootBoxFrame(nsIFrame *aFrame)
5463 return (aFrame->GetType() == nsGkAtoms::rootFrame);
5466 nsresult
5467 nsCSSFrameConstructor::ReconstructDocElementHierarchy()
5469 return RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
5470 PR_FALSE);
5473 nsIFrame*
5474 nsCSSFrameConstructor::GetFrameFor(nsIContent* aContent)
5476 // Get the primary frame associated with the content
5477 nsIFrame* frame = aContent->GetPrimaryFrame();
5479 if (!frame)
5480 return nsnull;
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) {
5486 return nsnull;
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;
5497 nsIFrame*
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...
5511 return nsnull;
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 ||
5526 #ifdef MOZ_XUL
5527 nsGkAtoms::XULLabelFrame == frameType ||
5528 #endif
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);
5538 #ifdef DEBUG
5539 if (!containingBlock)
5540 NS_WARNING("Positioned frame that does not handle positioned kids; looking further up the parent chain");
5541 #endif
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;
5554 nsIFrame*
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
5572 return nsnull;
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.
5581 static nsIFrame*
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,
5592 aPresContext)) {
5593 nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(aParentFrame);
5594 if (afterFrame) {
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
5628 * null).
5630 static nsIFrame*
5631 FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aAfterFrame)
5633 if (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.
5645 static nsIFrame*
5646 GetInsertNextSibling(nsIFrame* aParentFrame, nsIFrame* aPrevSibling)
5648 if (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.
5660 nsresult
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) ||
5679 aIsRecursiveCall,
5680 "aParentFrame has later continuations with kids?");
5681 NS_ASSERTION(nextSibling ||
5682 !IsFrameSpecial(aParentFrame) ||
5683 (IsInlineFrame(aParentFrame) &&
5684 !GetSpecialSibling(aParentFrame) &&
5685 !aParentFrame->GetNextContinuation()) ||
5686 aIsRecursiveCall,
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
5691 // them.
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();
5730 PRBool positioned =
5731 parentDisplay->mPosition == NS_STYLE_POSITION_RELATIVE ||
5732 parentDisplay->HasTransform();
5733 nsFrameItems ibSiblings;
5734 CreateIBSiblings(aState, aParentFrame, positioned, aFrameList,
5735 ibSiblings);
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
5739 // changed.
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);
5749 return NS_OK;
5752 // Insert the frames after our aPrevSibling
5753 return aState.mFrameManager->InsertFrames(aParentFrame, nsnull, aPrevSibling,
5754 aFrameList);
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.
5764 PRBool
5765 nsCSSFrameConstructor::IsValidSibling(nsIFrame* aSibling,
5766 nsIContent* aContent,
5767 PRUint8& aDisplay)
5769 nsIFrame* parentFrame = aSibling->GetParent();
5770 nsIAtom* parentType = nsnull;
5771 nsIAtom* grandparentType = nsnull;
5772 if (parentFrame) {
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(),
5795 &styleParent,
5796 &providerIsChild)) ||
5797 !styleParent) {
5798 NS_NOTREACHED("Shouldn't happen");
5799 return PR_FALSE;
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) {
5807 return
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.
5826 return PR_FALSE;
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
5834 // siblings.
5835 return PR_FALSE;
5838 return PR_TRUE;
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)))
5849 return PR_FALSE;
5852 return PR_TRUE;
5855 nsIFrame*
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.
5865 return nsnull;
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?");
5879 if (aPrevSibling) {
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)) {
5893 sibling = nsnull;
5896 return sibling;
5899 nsIFrame*
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) {
5909 --aIter;
5910 nsIFrame* prevSibling =
5911 FindFrameForContentSibling(*aIter, child, aTargetContentDisplay, PR_TRUE);
5913 if (prevSibling) {
5914 // Found a previous sibling, we're done!
5915 return prevSibling;
5919 return nsnull;
5922 nsIFrame*
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.
5930 return nsnull;
5933 nsIContent* child = *aIter;
5935 while (++aIter != aLast) {
5936 nsIFrame* nextSibling =
5937 FindFrameForContentSibling(*aIter, child, aTargetContentDisplay, PR_FALSE);
5939 if (nextSibling) {
5940 // We found a next sibling, we're done!
5941 return nextSibling;
5945 return nsnull;
5948 // For fieldsets, returns the area frame, if the child is not a legend.
5949 static nsIFrame*
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;
5970 nsIFrame*
5971 nsCSSFrameConstructor::GetInsertionPrevSibling(nsIFrame*& aParentFrame,
5972 nsIContent* aContainer,
5973 nsIContent* aChild,
5974 PRBool* aIsAppend,
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);
5999 } else {
6000 iter.seek(aChild);
6003 #ifdef DEBUG
6004 else {
6005 NS_WARNING("Someone passed native anonymous content directly into frame "
6006 "construction. Stop doing that!");
6008 #endif
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.
6016 if (prevSibling) {
6017 aParentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
6019 else {
6020 // If there is no previous sibling, then find the frame that follows
6021 if (aEndSkipChild) {
6022 iter.seek(aEndSkipChild);
6023 iter--;
6025 nsIFrame* nextSibling = FindNextSibling(iter, last, childDisplay);
6027 if (nextSibling) {
6028 aParentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
6030 else {
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(),
6045 aChild);
6046 nsIFrame* appendAfterFrame;
6047 aParentFrame =
6048 ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
6049 container, aParentFrame,
6050 &appendAfterFrame);
6051 prevSibling = ::FindAppendPrevSibling(aParentFrame, appendAfterFrame);
6055 *aIsRangeInsertSafe = (childDisplay == UNSET_DISPLAY);
6056 return prevSibling;
6059 static PRBool
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);
6068 static void
6069 InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node);
6071 #ifdef MOZ_XUL
6073 static
6074 PRBool
6075 IsXULListBox(nsIContent* aContainer)
6077 return (aContainer->IsXUL() && aContainer->Tag() == nsGkAtoms::listbox);
6080 static
6081 nsListBoxBodyFrame*
6082 MaybeGetListBoxBodyFrame(nsIContent* aContainer, nsIContent* aChild)
6084 if (!aContainer)
6085 return nsnull;
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);
6098 return nsnull;
6100 #endif
6102 void
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)
6114 return;
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);
6122 void
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)
6131 return;
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.
6159 PRBool
6160 nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
6161 nsIContent* aContainer,
6162 nsIContent* aChild)
6164 if (mPresShell->GetPresContext()->IsChrome() || !aContainer ||
6165 aContainer->IsInNativeAnonymousSubtree() || aContainer->IsXUL()) {
6166 return PR_FALSE;
6169 if (aOperation == CONTENTINSERT) {
6170 if (aChild->IsRootOfAnonymousSubtree() ||
6171 aChild->IsXUL() || IsActuallyEditable(aContainer, aChild)) {
6172 return PR_FALSE;
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)) {
6181 return PR_FALSE;
6186 // We can construct lazily; just need to set suitable bits in the content
6187 // tree.
6189 // Walk up the tree setting the NODE_DESCENDANTS_NEED_FRAMES bit as we go.
6190 nsIContent* content = aContainer;
6191 #ifdef DEBUG
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;
6199 #endif
6200 while (content &&
6201 !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
6202 #ifdef DEBUG
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;
6212 #endif
6213 content->SetFlags(NODE_DESCENDANTS_NEED_FRAMES);
6214 content = content->GetFlattenedTreeParent();
6216 #ifdef DEBUG
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");
6225 #endif
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
6233 // fixed.
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
6242 // fixed.
6243 "setting NEEDS_FRAME on a node that already has a frame?");
6244 child->SetFlags(NODE_NEEDS_FRAME);
6248 PostRestyleEventInternal(PR_TRUE);
6249 return PR_TRUE;
6252 void
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
6269 // child lists).
6271 // Scan the children of aContent to see what operations (if any) we need to
6272 // perform.
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
6283 // fixed.
6284 "NEEDS_FRAME set on a node that already has a frame?");
6285 if (!inRun) {
6286 inRun = PR_TRUE;
6287 firstChildInRun = child;
6289 } else {
6290 if (inRun) {
6291 inRun = PR_FALSE;
6292 // generate a ContentRangeInserted for [startOfRun,i)
6293 ContentRangeInserted(aContent, firstChildInRun, child, nsnull,
6294 PR_FALSE);
6298 if (inRun) {
6299 ContentAppended(aContent, firstChildInRun, PR_FALSE);
6302 // Now descend.
6303 ChildIterator iter, last;
6304 for (ChildIterator::Init(aContent, &iter, &last);
6305 iter != last;
6306 ++iter) {
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)) {
6323 BeginUpdate();
6324 CreateNeededFrames(rootElement);
6325 EndUpdate();
6329 void
6330 nsCSSFrameConstructor::IssueSingleInsertNofications(nsIContent* aContainer,
6331 nsIContent* aStartChild,
6332 nsIContent* aEndChild,
6333 PRBool aAllowLazyConstruction)
6335 for (nsIContent* child = aStartChild;
6336 child != aEndChild;
6337 child = child->GetNextSibling()) {
6338 if ((child->GetPrimaryFrame() ||
6339 mPresShell->FrameManager()->GetUndisplayedContent(child))
6340 #ifdef MOZ_XUL
6341 // Except listboxes suck, so do NOT skip anything here if
6342 // we plan to notify a listbox.
6343 && !MaybeGetListBoxBodyFrame(aContainer, child)
6344 #endif
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.
6349 continue;
6351 // Call ContentInserted with this node.
6352 ContentInserted(aContainer, child, mTempFrameTreeState,
6353 aAllowLazyConstruction);
6357 nsIFrame*
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;
6374 if (!multiple) {
6375 // XXXbz XBL2/sXBL issue
6376 nsIDocument* document = aStartChild->GetDocument();
6377 // XXXbz how would |document| be null here?
6378 if (document &&
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;
6389 if (!multiple) {
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);
6412 return nsnull;
6416 return insertionPoint;
6419 PRBool
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;
6427 cur != aEndChild;
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);
6432 return PR_TRUE;
6436 return PR_FALSE;
6439 nsresult
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");
6448 #ifdef DEBUG
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);
6458 #endif
6460 #ifdef MOZ_XUL
6461 if (aContainer) {
6462 PRInt32 namespaceID;
6463 nsIAtom* tag =
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)
6470 return NS_OK;
6473 #endif // MOZ_XUL
6475 // Get the frame associated with the content
6476 nsIFrame* parentFrame = GetFrameFor(aContainer);
6477 if (! parentFrame)
6478 return NS_OK;
6480 if (aAllowLazyConstruction &&
6481 MaybeConstructLazily(CONTENTAPPEND, aContainer, aFirstNewContent)) {
6482 return NS_OK;
6485 LAYOUT_PHASE_TEMP_EXIT();
6486 parentFrame = GetRangeInsertionPoint(aContainer, parentFrame,
6487 aFirstNewContent, nsnull,
6488 aAllowLazyConstruction);
6489 LAYOUT_PHASE_TEMP_REENTER();
6490 if (!parentFrame) {
6491 return NS_OK;
6494 LAYOUT_PHASE_TEMP_EXIT();
6495 if (MaybeRecreateForFrameset(parentFrame, aFirstNewContent, nsnull)) {
6496 LAYOUT_PHASE_TEMP_REENTER();
6497 return NS_OK;
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);
6505 return NS_OK;
6508 #ifdef MOZ_MATHML
6509 if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) {
6510 LAYOUT_PHASE_TEMP_EXIT();
6511 nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), PR_FALSE);
6512 LAYOUT_PHASE_TEMP_REENTER();
6513 return rv;
6515 #endif
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) {
6522 #ifdef DEBUG
6523 if (gNoisyContentUpdates) {
6524 printf("nsCSSFrameConstructor::ContentAppended: parentFrame=");
6525 nsFrame::ListTag(stdout, parentFrame);
6526 printf(" is special\n");
6528 #endif
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;
6547 parentFrame =
6548 ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
6549 aContainer, parentFrame,
6550 &parentAfterFrame);
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;
6595 child;
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();
6610 return NS_OK;
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;
6635 child;
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();
6671 if (outerTable) {
6672 state.mFrameManager->AppendFrames(outerTable, nsGkAtoms::captionList,
6673 captionItems);
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);
6686 #ifdef DEBUG
6687 if (gReallyNoisyContentUpdates) {
6688 printf("nsCSSFrameConstructor::ContentAppended: resulting frame model:\n");
6689 parentFrame->List(stdout, 0);
6691 #endif
6693 return NS_OK;
6696 #ifdef MOZ_XUL
6698 enum content_operation
6700 CONTENT_INSERTED,
6701 CONTENT_REMOVED
6704 // Helper function to lookup the listbox body frame and send a notification
6705 // for insertion or removal of content
6706 static
6707 PRBool NotifyListBoxBody(nsPresContext* aPresContext,
6708 nsIContent* aContainer,
6709 nsIContent* aChild,
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);
6725 return PR_TRUE;
6727 } else {
6728 listBoxBodyFrame->OnContentInserted(aPresContext, aChild);
6729 return PR_TRUE;
6733 return PR_FALSE;
6735 #endif // MOZ_XUL
6737 nsresult
6738 nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
6739 nsIContent* aChild,
6740 nsILayoutHistoryState* aFrameState,
6741 PRBool aAllowLazyConstruction)
6743 return ContentRangeInserted(aContainer,
6744 aChild,
6745 aChild->GetNextSibling(),
6746 aFrameState,
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).
6768 nsresult
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?
6783 #ifdef DEBUG
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) {
6791 if (aContainer) {
6792 aContainer->List(stdout,0);
6793 } else {
6794 aStartChild->List(stdout, 0);
6798 #endif
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");
6808 #ifdef MOZ_XUL
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)) {
6816 return NS_OK;
6818 } else {
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();
6825 return NS_OK;
6828 #endif // MOZ_XUL
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,
6832 // say).
6833 if (! aContainer) {
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
6840 return NS_OK;
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);
6852 #ifdef DEBUG
6853 if (gReallyNoisyContentUpdates) {
6854 printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
6855 "model:\n");
6856 mFixedContainingBlock->List(stdout, 0);
6858 #endif
6861 return NS_OK;
6864 // Otherwise, we've got parent content. Find its frame.
6865 nsIFrame* parentFrame = GetFrameFor(aContainer);
6866 if (! parentFrame)
6867 return NS_OK;
6869 if (aAllowLazyConstruction &&
6870 MaybeConstructLazily(CONTENTINSERT, aContainer, aStartChild)) {
6871 return NS_OK;
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;
6884 } else {
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();
6892 if (!parentFrame) {
6893 return NS_OK;
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();
6909 return NS_OK;
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();
6918 return NS_OK;
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();
6937 return rv;
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);
6944 return NS_OK;
6947 #ifdef MOZ_MATHML
6948 if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) {
6949 LAYOUT_PHASE_TEMP_EXIT();
6950 nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), PR_FALSE);
6951 LAYOUT_PHASE_TEMP_REENTER();
6952 return rv;
6954 #endif
6956 nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
6957 GetAbsoluteContainingBlock(parentFrame),
6958 GetFloatContainingBlock(parentFrame),
6959 aFrameState);
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
6966 // logic.
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
6994 // new parent hint
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();
7003 } else {
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,
7015 // etc.
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();
7030 return NS_OK;
7033 container = parentFrame->GetContent();
7034 frameType = parentFrame->GetType();
7038 if (!prevSibling) {
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);
7043 if (firstChild &&
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(),
7066 items);
7069 if (isSingleInsert) {
7070 AddFrameConstructionItems(state, aStartChild,
7071 aStartChild->IsRootOfAnonymousSubtree(),
7072 parentFrame, items);
7073 } else {
7074 for (nsIContent* child = aStartChild;
7075 child != aEndChild;
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();
7098 return NS_OK;
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;
7111 child != aEndChild;
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
7125 // (bug 341858).
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
7138 // siblings
7139 if (prevSibling && frameItems.NotEmpty() &&
7140 frameItems.FirstChild()->GetParent() != prevSibling->GetParent()) {
7141 #ifdef DEBUG
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");
7154 #endif
7155 isAppend = PR_TRUE;
7156 nsIFrame* appendAfterFrame;
7157 parentFrame =
7158 ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
7159 container,
7160 frameItems.FirstChild()->GetParent(),
7161 &appendAfterFrame);
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...
7168 if (isAppend) {
7169 // Use append logic when appending
7170 AppendFirstLineFrames(state, containingBlock->GetContent(),
7171 containingBlock, frameItems);
7173 else {
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.
7197 PRBool ignored;
7198 if (isSingleInsert) {
7199 captionPrevSibling =
7200 GetInsertionPrevSibling(captionParent, aContainer, aStartChild,
7201 &captionIsAppend, &ignored);
7202 } else {
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
7206 // prevsibling.
7207 captionPrevSibling =
7208 GetInsertionPrevSibling(captionParent, aContainer, firstCaption,
7209 &captionIsAppend, &ignored,
7210 aStartChild, aEndChild);
7213 nsIFrame* outerTable = nsnull;
7214 if (GetCaptionAdjustedParent(captionParent, captionItems.FirstChild(),
7215 &outerTable)) {
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
7218 // will get lost
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,
7232 captionItems);
7233 } else {
7234 state.mFrameManager->InsertFrames(outerTable, nsGkAtoms::captionList,
7235 captionPrevSibling, captionItems);
7240 if (frameItems.NotEmpty()) {
7241 // Notify the parent frame
7242 if (isAppend) {
7243 AppendFrames(state, parentFrame, frameItems, prevSibling);
7244 } else {
7245 state.mFrameManager->InsertFrames(parentFrame, nsnull, prevSibling,
7246 frameItems);
7250 if (haveFirstLetterStyle) {
7251 // Recover the letter frames for the containing block when
7252 // it has first-letter style.
7253 RecoverLetterFrames(state.mFloatedItems.containingBlock);
7256 #ifdef DEBUG
7257 if (gReallyNoisyContentUpdates && parentFrame) {
7258 printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame model:\n");
7259 parentFrame->List(stdout, 0);
7261 #endif
7263 return NS_OK;
7266 nsresult
7267 nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
7268 nsIContent* aChild,
7269 nsIContent* aOldNextSibling,
7270 RemoveFlags aFlags,
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?
7282 #ifdef DEBUG
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);
7293 #endif
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);
7308 #ifdef MOZ_XUL
7309 if (NotifyListBoxBody(presContext, aContainer, aChild, aOldNextSibling,
7310 mDocument, childFrame, CONTENT_REMOVED))
7311 return NS_OK;
7313 #endif // MOZ_XUL
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;
7326 if (!aContainer) {
7327 nsIFrame* viewport = frameManager->GetRootFrame();
7328 if (viewport) {
7329 nsIFrame* firstChild = viewport->GetFirstChild(nsnull);
7330 if (firstChild && firstChild->GetContent() == aChild) {
7331 isRoot = PR_TRUE;
7332 childFrame = firstChild;
7333 NS_ASSERTION(!childFrame->GetNextSibling(), "How did that happen?");
7338 if (childFrame) {
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;
7346 return rv;
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();
7361 return rv;
7364 #ifdef MOZ_MATHML
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();
7375 return rv;
7377 #endif
7379 // Undo XUL wrapping if it's no longer needed.
7380 // (If we're in the XUL block-wrapping situation, parentFrame is the
7381 // wrapper frame.)
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();
7392 return rv;
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);
7405 if (haveFLS) {
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);
7415 printf("\n");
7416 #endif
7418 // First update the containing blocks structure by removing the
7419 // existing letter frames. This makes the subsequent logic
7420 // simpler.
7421 RemoveLetterFrames(presContext, mPresShell, frameManager,
7422 containingBlock);
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);
7430 return NS_OK;
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);
7440 printf("\n");
7441 #endif
7444 #ifdef DEBUG
7445 if (gReallyNoisyContentUpdates) {
7446 printf("nsCSSFrameConstructor::ContentRemoved: childFrame=");
7447 nsFrame::ListTag(stdout, childFrame);
7448 putchar('\n');
7449 parentFrame->List(stdout, 0);
7451 #endif
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),
7461 childFrame);
7462 //XXXfr NS_ENSURE_SUCCESS(rv, rv) ?
7464 if (isRoot) {
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
7489 // if necessary.
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();
7515 #ifdef DEBUG
7516 if (gReallyNoisyContentUpdates && parentFrame) {
7517 printf("nsCSSFrameConstructor::ContentRemoved: resulting frame model:\n");
7518 parentFrame->List(stdout, 0);
7520 #endif
7523 return rv;
7526 #ifdef DEBUG
7527 // To ensure that the functions below are only called within
7528 // |ApplyRenderingChangeToTree|.
7529 static PRBool gInApplyRenderingChangeToTree = PR_FALSE;
7530 #endif
7532 static void
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
7542 static void
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();
7551 if (view) {
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;
7562 do {
7563 nsIFrame* child = aFrame->GetFirstChild(childList);
7564 while (child) {
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);
7572 do {
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);
7594 static void
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
7607 // update there.
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)) {
7613 #ifdef MOZ_SVG
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);
7631 #endif
7632 } else {
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);
7650 static void
7651 ApplyRenderingChangeToTree(nsPresContext* aPresContext,
7652 nsIFrame* aFrame,
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);
7659 if (!aChange) {
7660 return;
7664 // If the frame's background is propagated to an ancestor, walk up to
7665 // that ancestor.
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);
7681 #ifdef DEBUG
7682 gInApplyRenderingChangeToTree = PR_TRUE;
7683 #endif
7684 DoApplyRenderingChangeToTree(aFrame, viewManager, shell->FrameManager(),
7685 aChange);
7686 #ifdef DEBUG
7687 gInApplyRenderingChangeToTree = PR_FALSE;
7688 #endif
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.
7701 static void
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();
7711 if (parent) {
7712 // Has a parent; might not be what we want
7713 nsIContent* grandParent = parent->GetParent();
7714 if (grandParent) {
7715 // Has a grandparent, so not what we want
7716 return;
7719 // Check whether it's an HTML body
7720 if (node->Tag() != nsGkAtoms::body ||
7721 !node->IsHTML()) {
7722 return;
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);
7740 nsresult
7741 nsCSSFrameConstructor::StyleChangeReflow(nsIFrame* aFrame,
7742 nsChangeHint aHint)
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)
7747 return NS_OK;
7749 #ifdef DEBUG
7750 if (gNoisyContentUpdates) {
7751 printf("nsCSSFrameConstructor::StyleChangeReflow: aFrame=");
7752 nsFrame::ListTag(stdout, aFrame);
7753 printf("\n");
7755 #endif
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;
7764 } else {
7765 dirtyType = nsIPresShell::eResize;
7768 nsFrameState dirtyBits;
7769 if (aHint & nsChangeHint_NeedDirtyReflow) {
7770 dirtyBits = NS_FRAME_IS_DIRTY;
7771 } else {
7772 dirtyBits = NS_FRAME_HAS_DIRTY_CHILDREN;
7775 do {
7776 mPresShell->FrameNeedsReflow(aFrame, dirtyType, dirtyBits);
7777 aFrame = nsLayoutUtils::GetNextContinuationOrSpecialSibling(aFrame);
7778 } while (aFrame);
7780 return NS_OK;
7783 nsresult
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())) {
7794 #ifdef DEBUG
7795 nsIFrame* frame = aContent->GetPrimaryFrame();
7796 NS_ASSERTION(!frame || !frame->IsGeneratedContentFrame(),
7797 "Bit should never be set on generated content");
7798 #endif
7799 LAYOUT_PHASE_TEMP_EXIT();
7800 nsresult rv = RecreateFramesForContent(aContent, PR_FALSE);
7801 LAYOUT_PHASE_TEMP_REENTER();
7802 return rv;
7805 // Find the child frame
7806 nsIFrame* frame = aContent->GetPrimaryFrame();
7808 // Notify the first frame that maps the content. It will generate a reflow
7809 // command
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) {
7814 #if 0
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));
7819 #endif
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;
7832 if (block) {
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);
7852 return rv;
7855 NS_DECLARE_FRAME_PROPERTY(ChangeListProperty, nsnull)
7857 nsresult
7858 nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
7860 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
7861 "Someone forgot a script blocker");
7862 PRInt32 count = aChangeList.Count();
7863 if (!count)
7864 return NS_OK;
7866 // Make sure to not rebuild quote or counter lists while we're
7867 // processing restyles
7868 BeginUpdate();
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));
7887 index = count;
7888 PRBool didInvalidate = PR_FALSE;
7889 PRBool didReflow = PR_FALSE;
7891 while (0 <= --index) {
7892 nsIFrame* frame;
7893 nsIContent* content;
7894 nsChangeHint hint;
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.
7904 frame = nsnull;
7905 if (!(hint & nsChangeHint_ReconstructFrame)) {
7906 continue;
7910 // skip any frame that has been destroyed due to a ripple effect
7911 if (frame) {
7912 if (!propTable->Get(frame, ChangeListProperty()))
7913 continue;
7916 if (hint & nsChangeHint_ReconstructFrame) {
7917 RecreateFramesForContent(content, PR_FALSE);
7918 } else {
7919 NS_ASSERTION(frame, "This shouldn't happen");
7920 #ifdef MOZ_SVG
7921 if (hint & nsChangeHint_UpdateEffects) {
7922 nsSVGEffects::UpdateEffects(frame);
7924 #endif
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);
7940 EndUpdate();
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();
7948 if (rootPC) {
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.
7956 index = count;
7957 while (0 <= --index) {
7958 const nsStyleChangeData* changeData;
7959 aChangeList.ChangeAt(index, &changeData);
7960 if (changeData->mFrame) {
7961 propTable->Delete(changeData->mFrame, ChangeListProperty());
7964 #ifdef DEBUG
7965 // reget frame from content since it may have been regenerated...
7966 if (changeData->mContent) {
7967 nsIFrame* frame = changeData->mContent->GetPrimaryFrame();
7968 if (frame) {
7969 mPresShell->FrameManager()->DebugVerifyStyleTree(frame);
7971 } else {
7972 NS_WARNING("Unable to test style tree integrity -- no content node");
7974 #endif
7977 aChangeList.Clear();
7978 return NS_OK;
7981 void
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);
8006 } else {
8007 // no frames, reconstruct for content
8008 MaybeRecreateFramesForElement(aElement);
8012 nsresult
8013 nsCSSFrameConstructor::ContentStatesChanged(nsIContent* aContent1,
8014 nsIContent* aContent2,
8015 PRInt32 aStateMask)
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);
8025 return NS_OK;
8028 void
8029 nsCSSFrameConstructor::DoContentStateChanged(Element* aElement,
8030 PRInt32 aStateMask)
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();
8044 if (primaryFrame) {
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;
8050 } else {
8051 PRUint8 app = primaryFrame->GetStyleDisplay()->mAppearance;
8052 if (app) {
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);
8058 if (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) {
8070 ++mHoverGeneration;
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);
8083 void
8084 nsCSSFrameConstructor::AttributeWillChange(Element* aElement,
8085 PRInt32 aNameSpaceID,
8086 nsIAtom* aAttribute,
8087 PRInt32 aModType)
8089 nsRestyleHint rshint =
8090 mPresShell->StyleSet()->HasAttributeDependentStyle(mPresShell->GetPresContext(),
8091 aElement,
8092 aAttribute,
8093 aModType,
8094 PR_FALSE);
8095 PostRestyleEvent(aElement, rshint, NS_STYLE_HINT_NONE);
8098 void
8099 nsCSSFrameConstructor::AttributeChanged(Element* aElement,
8100 PRInt32 aNameSpaceID,
8101 nsIAtom* aAttribute,
8102 PRInt32 aModType)
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();
8112 #if 0
8113 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
8114 ("HTMLStyleSheet::AttributeChanged: content=%p[%s] frame=%p",
8115 aContent, ContentTag(aElement, 0), frame));
8116 #endif
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;
8123 #ifdef MOZ_XUL
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;
8129 nsIAtom* tag =
8130 mDocument->BindingManager()->ResolveTag(aElement, &namespaceID);
8132 if (namespaceID == kNameSpaceID_XUL &&
8133 (tag == nsGkAtoms::listitem ||
8134 tag == nsGkAtoms::listcell))
8135 return;
8138 if (aAttribute == nsGkAtoms::tooltiptext ||
8139 aAttribute == nsGkAtoms::tooltip)
8141 nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
8142 if (rootBox) {
8143 if (aModType == nsIDOMMutationEvent::REMOVAL)
8144 rootBox->RemoveTooltipSupport(aElement);
8145 if (aModType == nsIDOMMutationEvent::ADDITION)
8146 rootBox->AddTooltipSupport(aElement);
8150 #endif // MOZ_XUL
8152 if (primaryFrame) {
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);
8161 if (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(),
8178 aElement,
8179 aAttribute,
8180 aModType,
8181 PR_TRUE);
8183 PostRestyleEvent(aElement, rshint, hint);
8186 void
8187 nsCSSFrameConstructor::BeginUpdate() {
8188 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
8189 "Someone forgot a script blocker");
8191 ++mUpdateCount;
8194 void
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");
8204 --mUpdateCount;
8207 void
8208 nsCSSFrameConstructor::RecalcQuotesAndCounters()
8210 if (mQuotesDirty) {
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");
8224 void
8225 nsCSSFrameConstructor::WillDestroyFrameTree()
8227 #if defined(DEBUG_dbaron_off)
8228 mCounterManager.Dump();
8229 #endif
8231 mIsDestroyingFrameTree = PR_TRUE;
8233 // Prevent frame tree destruction from being O(N^2)
8234 mQuoteList.Clear();
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);
8244 //STATIC
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);
8268 nsresult
8269 nsCSSFrameConstructor::CreateContinuingOuterTableFrame(nsIPresShell* aPresShell,
8270 nsPresContext* aPresContext,
8271 nsIFrame* aFrame,
8272 nsIFrame* aParentFrame,
8273 nsIContent* aContent,
8274 nsStyleContext* aStyleContext,
8275 nsIFrame** aContinuingFrame)
8277 nsIFrame* newFrame = NS_NewTableOuterFrame(aPresShell, aStyleContext);
8279 if (newFrame) {
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);
8288 if (childFrame) {
8289 nsIFrame* continuingTableFrame;
8290 nsresult rv = CreateContinuingFrame(aPresContext, childFrame, newFrame,
8291 &continuingTableFrame);
8292 if (NS_FAILED(rv)) {
8293 newFrame->Destroy();
8294 *aContinuingFrame = nsnull;
8295 return rv;
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;
8306 return NS_OK;
8308 else {
8309 *aContinuingFrame = nsnull;
8310 return NS_ERROR_OUT_OF_MEMORY;
8314 nsresult
8315 nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell* aPresShell,
8316 nsPresContext* aPresContext,
8317 nsIFrame* aFrame,
8318 nsIFrame* aParentFrame,
8319 nsIContent* aContent,
8320 nsStyleContext* aStyleContext,
8321 nsIFrame** aContinuingFrame)
8323 nsIFrame* newFrame = NS_NewTableFrame(aPresShell, aStyleContext);
8325 if (newFrame) {
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();
8338 if (rgNextInFlow) {
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),
8347 nsnull);
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,
8356 nsnull);
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;
8373 return NS_OK;
8375 else {
8376 *aContinuingFrame = nsnull;
8377 return NS_ERROR_OUT_OF_MEMORY;
8381 nsresult
8382 nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext,
8383 nsIFrame* aFrame,
8384 nsIFrame* aParentFrame,
8385 nsIFrame** aContinuingFrame,
8386 PRBool aIsFluid)
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);
8405 if (newFrame) {
8406 newFrame->Init(content, aParentFrame, aFrame);
8407 nsHTMLContainerFrame::CreateViewForFrame(newFrame, PR_FALSE);
8410 } else if (nsGkAtoms::inlineFrame == frameType) {
8411 newFrame = NS_NewInlineFrame(shell, styleContext);
8413 if (newFrame) {
8414 newFrame->Init(content, aParentFrame, aFrame);
8415 nsHTMLContainerFrame::CreateViewForFrame(newFrame, PR_FALSE);
8418 } else if (nsGkAtoms::blockFrame == frameType) {
8419 newFrame = NS_NewBlockFrame(shell, styleContext);
8421 if (newFrame) {
8422 newFrame->Init(content, aParentFrame, aFrame);
8423 nsHTMLContainerFrame::CreateViewForFrame(newFrame, PR_FALSE);
8426 #ifdef MOZ_XUL
8427 } else if (nsGkAtoms::XULLabelFrame == frameType) {
8428 newFrame = NS_NewXULLabelFrame(shell, styleContext);
8430 if (newFrame) {
8431 newFrame->Init(content, aParentFrame, aFrame);
8432 nsHTMLContainerFrame::CreateViewForFrame(newFrame, PR_FALSE);
8434 #endif
8435 } else if (nsGkAtoms::columnSetFrame == frameType) {
8436 newFrame = NS_NewColumnSetFrame(shell, styleContext, 0);
8438 if (newFrame) {
8439 newFrame->Init(content, aParentFrame, aFrame);
8440 nsHTMLContainerFrame::CreateViewForFrame(newFrame, PR_FALSE);
8443 } else if (nsGkAtoms::positionedInlineFrame == frameType) {
8444 newFrame = NS_NewPositionedInlineFrame(shell, styleContext);
8446 if (newFrame) {
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);
8466 if (newFrame) {
8467 newFrame->Init(content, aParentFrame, aFrame);
8468 nsHTMLContainerFrame::CreateViewForFrame(newFrame, PR_FALSE);
8471 } else if (nsGkAtoms::tableRowFrame == frameType) {
8472 newFrame = NS_NewTableRowFrame(shell, styleContext);
8474 if (newFrame) {
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);
8481 while (cellFrame) {
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));
8508 if (newFrame) {
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;
8520 return rv;
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);
8530 if (newFrame) {
8531 newFrame->Init(content, aParentFrame, aFrame);
8532 nsHTMLContainerFrame::CreateViewForFrame(newFrame, PR_FALSE);
8535 } else if (nsGkAtoms::letterFrame == frameType) {
8536 newFrame = NS_NewFirstLetterFrame(shell, styleContext);
8538 if (newFrame) {
8539 newFrame->Init(content, aParentFrame, aFrame);
8540 nsHTMLContainerFrame::CreateViewForFrame(newFrame, PR_FALSE);
8543 } else if (nsGkAtoms::imageFrame == frameType) {
8544 newFrame = NS_NewImageFrame(shell, styleContext);
8546 if (newFrame) {
8547 newFrame->Init(content, aParentFrame, aFrame);
8549 } else if (nsGkAtoms::imageControlFrame == frameType) {
8550 newFrame = NS_NewImageControlFrame(shell, styleContext);
8552 if (newFrame) {
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;
8562 return rv;
8564 // create a continuing placeholder frame
8565 rv = CreatePlaceholderFrameFor(shell, content, oofContFrame, styleContext,
8566 aParentFrame, aFrame,
8567 aFrame->GetStateBits() & PLACEHOLDER_TYPE_MASK,
8568 &newFrame);
8569 if (NS_FAILED(rv)) {
8570 oofContFrame->Destroy();
8571 *aContinuingFrame = nsnull;
8572 return rv;
8574 } else if (nsGkAtoms::fieldSetFrame == frameType) {
8575 newFrame = NS_NewFieldSetFrame(shell, styleContext);
8577 if (newFrame) {
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;
8591 return rv;
8593 // Set the fieldset's initial child list
8594 SetInitialSingleChild(newFrame, continuingBlockFrame);
8596 } else if (nsGkAtoms::legendFrame == frameType) {
8597 newFrame = NS_NewLegendFrame(shell, styleContext);
8599 if (newFrame) {
8600 newFrame->Init(content, aParentFrame, aFrame);
8601 nsHTMLContainerFrame::CreateViewForFrame(newFrame, PR_FALSE);
8603 } else {
8604 NS_NOTREACHED("unexpected frame type");
8605 *aContinuingFrame = nsnull;
8606 return NS_ERROR_UNEXPECTED;
8609 *aContinuingFrame = newFrame;
8611 if (!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.
8618 if (!aIsFluid) {
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);
8632 if (nextInFlow) {
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");
8641 return NS_OK;
8644 nsresult
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) {
8653 return NS_OK;
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);
8664 if (!firstFixed) {
8665 return NS_OK;
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
8671 // containers.
8672 nsFrameConstructorState state(mPresShell, aParentFrame,
8673 nsnull,
8674 mRootElementFrame);
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);
8697 return NS_OK;
8700 nsresult
8701 nsCSSFrameConstructor::GetInsertionPoint(nsIFrame* aParentFrame,
8702 nsIContent* aChildContent,
8703 nsIFrame** aInsertionPoint,
8704 PRBool* aMultiple)
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();
8711 if (!container)
8712 return NS_OK;
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
8719 // anonymous.
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.
8723 return NS_OK;
8726 PRUint32 index;
8727 insertionElement = bindingManager->GetInsertionPoint(container,
8728 aChildContent,
8729 &index);
8731 else {
8732 PRBool multiple;
8733 PRUint32 index;
8734 insertionElement = bindingManager->GetSingleInsertionPoint(container,
8735 &index,
8736 &multiple);
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);
8749 else {
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;
8765 return NS_OK;
8768 // Capture state for the frame tree rooted at the frame associated with the
8769 // content object, aContent
8770 nsresult
8771 nsCSSFrameConstructor::CaptureStateForFramesOf(nsIContent* aContent,
8772 nsILayoutHistoryState* aHistoryState)
8774 nsIFrame* frame = aContent->GetPrimaryFrame();
8775 if (frame == mRootElementFrame) {
8776 frame = mFixedContainingBlock;
8778 if (frame) {
8779 CaptureStateFor(frame, aHistoryState);
8781 return NS_OK;
8784 // Capture state for the frame tree rooted at aFrame.
8785 nsresult
8786 nsCSSFrameConstructor::CaptureStateFor(nsIFrame* aFrame,
8787 nsILayoutHistoryState* aHistoryState)
8789 if (aFrame && aHistoryState) {
8790 mPresShell->FrameManager()->CaptureFrameState(aFrame, aHistoryState);
8792 return NS_OK;
8795 nsresult
8796 nsCSSFrameConstructor::MaybeRecreateFramesForElement(Element* aElement)
8798 nsresult result = NS_OK;
8799 nsFrameManager *frameManager = mPresShell->FrameManager();
8801 nsStyleContext *oldContext = frameManager->GetUndisplayedContent(aElement);
8802 if (oldContext) {
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);
8812 return result;
8815 static nsIFrame*
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();
8823 return f;
8826 static nsIFrame*
8827 FindNextNonWhitespaceSibling(nsIFrame* aFrame)
8829 nsIFrame* f = aFrame;
8830 do {
8831 f = f->GetNextSibling();
8832 } while (f && f->GetType() == nsGkAtoms::textFrame &&
8833 f->GetContent()->TextIsOnlyWhitespace());
8834 return f;
8837 PRBool
8838 nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
8839 nsresult* aResult)
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.
8850 #ifdef DEBUG
8851 if (gNoisyContentUpdates) {
8852 printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8853 "frame=");
8854 nsFrame::ListTag(stdout, aFrame);
8855 printf(" is special\n");
8857 #endif
8859 *aResult = ReframeContainingBlock(aFrame);
8860 return PR_TRUE;
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);
8868 return PR_TRUE;
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);
8890 return 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)) {
8903 #ifdef DEBUG
8904 if (gNoisyContentUpdates) {
8905 printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8906 "frame=");
8907 nsFrame::ListTag(stdout, aFrame);
8908 printf(" has a table pseudo next sibling of different type\n");
8910 #endif
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);
8914 return PR_TRUE;
8917 #ifdef MOZ_XUL
8918 if (aFrame->GetType() == nsGkAtoms::popupSetFrame) {
8919 nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
8920 if (rootBox && rootBox->GetPopupSetFrame() == aFrame) {
8921 *aResult = ReconstructDocElementHierarchy();
8922 return PR_TRUE;
8925 #endif
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)) {
8931 return PR_FALSE;
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()) {
8938 return PR_FALSE;
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)) {
8947 return PR_FALSE;
8950 #ifdef DEBUG
8951 if (gNoisyContentUpdates) {
8952 printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8953 "frame=");
8954 nsFrame::ListTag(stdout, parent);
8955 printf(" is special\n");
8957 #endif
8959 *aResult = ReframeContainingBlock(parent);
8960 return PR_TRUE;
8963 nsresult
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
8971 // anyway).
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
8986 // (see bug 397518)
8987 while (PR_TRUE) {
8988 nsIContent* parentContent = aContent->GetParent();
8989 nsIFrame* parentContentFrame = parentContent->GetPrimaryFrame();
8990 if (!parentContentFrame || !parentContentFrame->IsFrameOfType(nsIFrame::eMathML))
8991 break;
8992 aContent = parentContent;
8993 frame = parentContentFrame;
8997 if (frame) {
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)) {
9017 return 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() ?
9035 nsnull :
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.
9043 if (aAsyncInsert) {
9044 PostRestyleEvent(aContent->AsElement(), nsRestyleHint(0),
9045 nsChangeHint_ReconstructFrame);
9046 } else {
9047 rv = ContentInserted(container, aContent, mTempFrameTreeState, PR_FALSE);
9052 #ifdef ACCESSIBILITY
9053 if (mPresShell->IsAccessibilityActive()) {
9054 PRUint32 changeType;
9055 if (frame) {
9056 nsIFrame *newFrame = aContent->GetPrimaryFrame();
9057 changeType = newFrame ? nsIAccessibilityService::FRAME_SIGNIFICANT_CHANGE :
9058 nsIAccessibilityService::FRAME_HIDE;
9060 else {
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");
9068 if (accService) {
9069 accService->InvalidateSubtreeFor(mPresShell, aContent, changeType);
9072 #endif
9074 return rv;
9077 //////////////////////////////////////////////////////////////////////
9079 // Block frame construction code
9081 already_AddRefed<nsStyleContext>
9082 nsCSSFrameConstructor::GetFirstLetterStyle(nsIContent* aContent,
9083 nsStyleContext* aStyleContext)
9085 if (aContent) {
9086 return mPresShell->StyleSet()->
9087 ResolvePseudoElementStyle(aContent->AsElement(),
9088 nsCSSPseudoElements::ePseudo_firstLetter,
9089 aStyleContext);
9091 return nsnull;
9094 already_AddRefed<nsStyleContext>
9095 nsCSSFrameConstructor::GetFirstLineStyle(nsIContent* aContent,
9096 nsStyleContext* aStyleContext)
9098 if (aContent) {
9099 return mPresShell->StyleSet()->
9100 ResolvePseudoElementStyle(aContent->AsElement(),
9101 nsCSSPseudoElements::ePseudo_firstLine,
9102 aStyleContext);
9104 return nsnull;
9107 // Predicate to see if a given content (block element) has
9108 // first-letter style applied to it.
9109 PRBool
9110 nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(nsIContent* aContent,
9111 nsStyleContext* aStyleContext)
9113 return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext,
9114 nsCSSPseudoElements::ePseudo_firstLetter,
9115 mPresShell->GetPresContext());
9118 PRBool
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;
9128 PRBool
9129 nsCSSFrameConstructor::ShouldHaveFirstLineStyle(nsIContent* aContent,
9130 nsStyleContext* aStyleContext)
9132 PRBool hasFirstLine =
9133 nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext,
9134 nsCSSPseudoElements::ePseudo_firstLine,
9135 mPresShell->GetPresContext());
9136 if (hasFirstLine) {
9137 // But disable for fieldsets
9138 PRInt32 namespaceID;
9139 nsIAtom* tag = mDocument->BindingManager()->ResolveTag(aContent,
9140 &namespaceID);
9141 // This check must match the one in FindHTMLData.
9142 hasFirstLine = tag != nsGkAtoms::fieldset ||
9143 namespaceID != kNameSpaceID_XHTML;
9146 return hasFirstLine;
9149 void
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);
9161 /* static */
9162 const nsCSSFrameConstructor::PseudoParentData
9163 nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
9164 { // Cell
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
9171 { // Row
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
9178 { // Row group
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
9186 { // Column group
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
9194 { // Table
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.
9212 nsresult
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
9220 return NS_OK;
9223 FCItemIterator iter(aItems);
9224 do {
9225 if (iter.SkipItemsWantingParentType(ourParentType)) {
9226 // Nothing else to do here; we're finished
9227 return NS_OK;
9230 // Now we're pointing to the first child that wants a different parent
9231 // type.
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
9250 // described above.
9251 endIter.SetToEnd();
9252 } else {
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;
9259 do {
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");
9274 if (updateStart) {
9275 iter = endIter;
9278 if (trailingSpaces) {
9279 break; /* Found group end */
9282 if (updateStart) {
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.
9298 break;
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.
9306 break;
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;
9315 endIter.Next();
9316 } while (!endIter.IsDone());
9319 if (iter == endIter) {
9320 // Nothing to wrap here; just skipped some whitespace
9321 continue;
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) {
9328 case eTypeBlock:
9329 wrapperType = eTypeTable;
9330 break;
9331 case eTypeRow:
9332 // The parent type for a cell is eTypeBlock, since that's what a cell
9333 // looks like to its kids.
9334 wrapperType = eTypeBlock;
9335 break;
9336 case eTypeRowGroup:
9337 wrapperType = eTypeRow;
9338 break;
9339 case eTypeTable:
9340 // Either colgroup or rowgroup, depending on what we're grouping.
9341 wrapperType = groupingParentType == eTypeColGroup ?
9342 eTypeColGroup : eTypeRowGroup;
9343 break;
9344 default:
9345 NS_NOTREACHED("Colgroups should be suppresing non-col child items");
9346 break;
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
9364 parentContent,
9365 // Lie about the tag; it doesn't matter anyway
9366 pseudoType,
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
9372 nsnull,
9373 wrapperStyle.forget(),
9374 PR_TRUE);
9376 if (!newItem) {
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
9384 // to, I guess.
9385 newItem->mIsAllInline = newItem->mHasInlineEnds =
9386 newItem->mStyleContext->GetStyleDisplay()->IsInlineOutside();
9388 // Table pseudo frames always induce line boundaries around their
9389 // contents.
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
9393 // in mChildItems
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
9405 // different.
9406 } while (!iter.IsDone());
9408 return NS_OK;
9411 inline nsresult
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);
9420 #ifdef DEBUG
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");
9425 #endif
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");
9435 return NS_OK;
9438 nsresult
9439 nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
9440 nsIContent* aContent,
9441 nsStyleContext* aStyleContext,
9442 nsIFrame* aFrame,
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,
9472 aPendingBinding);
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) {
9490 #ifdef DEBUG
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");
9496 #endif
9497 AddFrameConstructionItems(aState, anonymousItems[i], PR_TRUE, aFrame,
9498 itemsToConstruct);
9501 if (!aFrame->IsLeaf()) {
9502 // :before/:after content should have the same style context parent
9503 // as normal kids.
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) {
9510 styleContext =
9511 nsFrame::CorrectStyleParentFrame(aFrame, nsnull)->GetStyleContext();
9512 // Probe for generated content before
9513 CreateGeneratedContentItem(aState, aFrame, aContent, styleContext,
9514 nsCSSPseudoElements::ePseudo_before,
9515 itemsToConstruct);
9518 ChildIterator iter, last;
9519 for (ChildIterator::Init(aContent, &iter, &last);
9520 iter != last;
9521 ++iter) {
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,
9529 itemsToConstruct);
9531 itemsToConstruct.SetParentHasNoXBLChildren(!iter.XBLInvolved());
9533 if (aCanHaveGeneratedContent) {
9534 // Probe for generated content after
9535 CreateGeneratedContentItem(aState, aFrame, aContent, styleContext,
9536 nsCSSPseudoElements::ePseudo_after,
9537 itemsToConstruct);
9539 } else {
9540 ClearLazyBits(aContent->GetFirstChild(), nsnull);
9543 rv = ConstructFramesFromItemList(aState, itemsToConstruct, aFrame,
9544 aFrameItems);
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,
9555 aFrameItems);
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,
9581 message,
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,
9590 frameStyleContext);
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);
9610 return rv;
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
9626 // aState.
9627 nsresult
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())) {
9640 link.Next();
9643 nsFrameList firstLineChildren = aFrameItems.ExtractHead(link);
9645 if (firstLineChildren.IsEmpty()) {
9646 // Nothing is supposed to go into the first-line; nothing to do
9647 return NS_OK;
9650 if (!aLineFrame) {
9651 // Create line frame
9652 nsStyleContext* parentStyle =
9653 nsFrame::CorrectStyleParentFrame(aBlockFrame,
9654 nsCSSPseudoElements::firstLine)->
9655 GetStyleContext();
9656 nsRefPtr<nsStyleContext> firstLineStyle = GetFirstLineStyle(aBlockContent,
9657 parentStyle);
9659 aLineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle);
9661 if (aLineFrame) {
9662 // Initialize the line frame
9663 rv = InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, nsnull,
9664 aLineFrame);
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");
9676 if (aLineFrame) {
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);
9682 } else {
9683 aState.mFrameManager->AppendFrames(aLineFrame, nsnull, firstLineChildren);
9686 else {
9687 rv = NS_ERROR_OUT_OF_MEMORY;
9690 return rv;
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.
9696 nsresult
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.
9719 return NS_OK;
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.
9729 nsresult
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.
9743 #if 0
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;
9756 if (isInline) {
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,
9760 newFrame);
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;
9767 else {
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
9773 else {
9774 // We do not have a first-line frame
9775 if (isInline) {
9776 // We now need a first-line frame to contain the inline frame.
9777 nsIFrame* lineFrame = NS_NewFirstLineFrame(firstLineStyle);
9778 if (!lineFrame) {
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)->
9787 GetStyleContext();
9788 nsRefPtr<nsStyleContext> firstLineStyle =
9789 GetFirstLineStyle(aContent, parentStyle);
9791 // Initialize the line frame
9792 rv = InitAndRestoreFrame(aState, aContent, aBlockFrame,
9793 nsnull, lineFrame);
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>
9801 // reparenting them
9802 NS_ASSERTION(lineFrame->GetStyleContext() == firstLineStyle,
9803 "Bogus style context on line frame");
9804 ReparentFrame(aPresContext, lineFrame, newFrame);
9805 lineFrame->SetInitialChildList(nsnull, newFrame);
9808 else {
9809 // Easy case: the regular insertion logic can insert the new
9810 // frame because it's a block frame.
9814 else {
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.
9823 else {
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
9827 // letter-frame).
9828 if (isInline) {
9829 // Easy case: the insertion can go where the caller thinks it
9830 // should go (which is into prevSiblingParent).
9832 else {
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
9837 // of the block.
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).
9844 if (nextSibling) {
9845 nsLineFrame* lineFrame = (nsLineFrame*) prevSiblingParent;
9846 nsFrameList tail = lineFrame->StealFramesAfter(aPrevSibling);
9847 // XXX do something with 'tail'
9850 nsLineFrame* nextLineFrame = (nsLineFrame*) lineFrame;
9851 for (;;) {
9852 nextLineFrame = nextLineFrame->GetNextInFlow();
9853 if (!nextLineFrame) {
9854 break;
9856 nsIFrame* kids = nextLineFrame->GetFirstChild(nsnull);
9859 else {
9860 // We got lucky: aPrevSibling was the last inline frame in
9861 // the line-frame.
9862 ReparentFrame(aState.mFrameManager, aBlockFrame, newFrame);
9863 aState.mFrameManager->InsertFrames(aBlockFrame, nsnull,
9864 prevSiblingParent, newFrame);
9865 aFrameItems.childList = nsnull;
9866 aFrameItems.lastChild = nsnull;
9872 #endif
9873 return rv;
9876 //----------------------------------------------------------------------
9878 // First-letter support
9880 // Determine how many characters in the text fragment apply to the
9881 // first letter
9882 static PRInt32
9883 FirstLetterCount(const nsTextFragment* aFragment)
9885 PRInt32 count = 0;
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) {
9894 done = PR_TRUE;
9895 break;
9897 count++;
9898 continue;
9900 // XXX I18n
9901 if ((ch == '\'') || (ch == '\"')) {
9902 if (firstLetterLength) {
9903 done = PR_TRUE;
9904 break;
9906 // keep looping
9907 firstLetterLength = 1;
9909 else {
9910 count++;
9911 done = PR_TRUE;
9912 break;
9916 return count;
9919 static PRBool
9920 NeedFirstLetterContinuation(nsIContent* aContent)
9922 NS_PRECONDITION(aContent, "null ptr");
9924 PRBool result = PR_FALSE;
9925 if (aContent) {
9926 const nsTextFragment* frag = aContent->GetText();
9927 if (frag) {
9928 PRInt32 flc = FirstLetterCount(frag);
9929 PRInt32 tl = frag->GetLength();
9930 if (flc < tl) {
9931 result = PR_TRUE;
9935 return result;
9938 static PRBool IsFirstLetterContent(nsIContent* aContent)
9940 return aContent->TextLength() &&
9941 !aContent->TextIsOnlyWhitespace();
9945 * Create a letter frame, only make it a floating frame.
9947 void
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
9959 nsresult rv;
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
9966 // first-letter.
9967 nsIContent* letterContent = aTextContent->GetParent();
9968 nsIFrame* containingBlock = aState.GetGeometricParent(
9969 aStyleContext->GetStyleDisplay(), aParentFrame);
9970 InitAndRestoreFrame(aState, letterContent, containingBlock, nsnull,
9971 letterFrame);
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,
9992 &nextTextFrame);
9993 if (NS_FAILED(rv)) {
9994 letterFrame->Destroy();
9995 return;
9997 // Repair the continuations style context
9998 nsStyleContext* parentStyleContext = aStyleContext->GetParent();
9999 if (parentStyleContext) {
10000 nsRefPtr<nsStyleContext> newSC;
10001 newSC = styleSet->ResolveStyleForNonElement(parentStyleContext);
10002 if (newSC) {
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) {
10014 link.Next();
10017 rv = aState.AddChild(letterFrame, aResult, letterContent, aStyleContext,
10018 aParentFrame, PR_FALSE, PR_TRUE, PR_FALSE, PR_TRUE,
10019 link.PrevFrame());
10021 if (nextTextFrame) {
10022 if (NS_FAILED(rv)) {
10023 nextTextFrame->Destroy();
10024 } else {
10025 aResult.AddChild(nextTextFrame);
10031 * Create a new letter frame for aTextFrame. The letter frame will be
10032 * a child of aParentFrame.
10034 nsresult
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)->
10050 GetStyleContext();
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);
10059 if (sc) {
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
10067 // frame.
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);
10086 else {
10087 // Make an inflow first-letter frame
10088 nsIFrame* letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
10090 if (letterFrame) {
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,
10098 textFrame);
10100 SetInitialSingleChild(letterFrame, textFrame);
10101 aResult.Clear();
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);
10111 return NS_OK;
10114 nsresult
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)) {
10134 return rv;
10136 if (parentFrame) {
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);
10143 else {
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);
10152 return rv;
10155 nsresult
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;
10172 while (frame) {
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)) {
10184 return rv;
10187 // Provide adjustment information for parent
10188 *aModifiedParent = aParentFrame;
10189 *aTextFrame = frame;
10190 *aPrevFrame = prevFrame;
10191 *aStopLooking = PR_TRUE;
10192 return NS_OK;
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) {
10201 return NS_OK;
10204 else {
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;
10212 break;
10215 prevFrame = frame;
10216 frame = nextFrame;
10219 return rv;
10222 nsresult
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()) {
10235 break;
10237 floatFrame = floatFrame->GetNextSibling();
10239 if (!floatFrame) {
10240 // No such frame
10241 return NS_OK;
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);
10247 if (!textFrame) {
10248 return NS_OK;
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
10258 return NS_OK;
10260 parentFrame = placeholderFrame->GetParent();
10261 if (!parentFrame) {
10262 // Somethings really wrong
10263 return NS_OK;
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();
10270 if (!parentSC) {
10271 return NS_OK;
10273 nsIContent* textContent = textFrame->GetContent();
10274 if (!textContent) {
10275 return NS_OK;
10277 nsRefPtr<nsStyleContext> newSC;
10278 newSC = aPresShell->StyleSet()->ResolveStyleForNonElement(parentSC);
10279 if (!newSC) {
10280 return NS_OK;
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);
10303 #endif
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);
10316 return NS_OK;
10319 nsresult
10320 nsCSSFrameConstructor::RemoveFirstLetterFrames(nsPresContext* aPresContext,
10321 nsIPresShell* aPresShell,
10322 nsFrameManager* aFrameManager,
10323 nsIFrame* aFrame,
10324 nsIFrame* aBlockFrame,
10325 PRBool* aStopLooking)
10327 nsIFrame* prevSibling = nsnull;
10328 nsIFrame* kid = aFrame->GetFirstChild(nsnull);
10330 while (kid) {
10331 if (nsGkAtoms::letterFrame == kid->GetType()) {
10332 // Bingo. Found it. First steal away the text frame.
10333 nsIFrame* textFrame = kid->GetFirstChild(nsnull);
10334 if (!textFrame) {
10335 break;
10338 // Create a new textframe
10339 nsStyleContext* parentSC = aFrame->GetStyleContext();
10340 if (!parentSC) {
10341 break;
10343 nsIContent* textContent = textFrame->GetContent();
10344 if (!textContent) {
10345 break;
10347 nsRefPtr<nsStyleContext> newSC;
10348 newSC = aPresShell->StyleSet()->ResolveStyleForNonElement(parentSC);
10349 if (!newSC) {
10350 break;
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);
10370 break;
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) {
10377 break;
10380 prevSibling = kid;
10381 kid = kid->GetNextSibling();
10384 return NS_OK;
10387 nsresult
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;
10397 nsresult rv;
10398 do {
10399 rv = RemoveFloatingFirstLetterFrames(aPresContext, aPresShell,
10400 aFrameManager,
10401 continuation, &stopLooking);
10402 if (NS_SUCCEEDED(rv) && !stopLooking) {
10403 rv = RemoveFirstLetterFrames(aPresContext, aPresShell, aFrameManager,
10404 continuation, aBlockFrame, &stopLooking);
10406 if (stopLooking) {
10407 break;
10409 continuation = continuation->GetNextContinuation();
10410 } while (continuation);
10411 return rv;
10414 // Fixup the letter frame situation for the given block
10415 nsresult
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;
10426 nsresult rv;
10427 do {
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)) {
10435 return rv;
10437 if (stopLooking) {
10438 break;
10440 continuation = continuation->GetNextContinuation();
10441 } while (continuation);
10443 if (parentFrame) {
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);
10450 return rv;
10453 //----------------------------------------------------------------------
10455 // listbox Widget Routines
10457 nsresult
10458 nsCSSFrameConstructor::CreateListBoxContent(nsPresContext* aPresContext,
10459 nsIFrame* aParentFrame,
10460 nsIFrame* aPrevFrame,
10461 nsIContent* aChild,
10462 nsIFrame** aNewFrame,
10463 PRBool aIsAppend,
10464 PRBool aIsScrollbar,
10465 nsILayoutHistoryState* aFrameState)
10467 #ifdef MOZ_XUL
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;
10487 return NS_OK;
10490 BeginUpdate();
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
10504 if (aIsAppend)
10505 rv = ((nsListBoxBodyFrame*)aParentFrame)->ListBoxAppendFrames(frameItems);
10506 else
10507 rv = ((nsListBoxBodyFrame*)aParentFrame)->ListBoxInsertFrames(aPrevFrame, frameItems);
10510 EndUpdate();
10513 return rv;
10514 #else
10515 return NS_ERROR_FAILURE;
10516 #endif
10519 //----------------------------------------
10521 nsresult
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,
10562 aStyleContext,
10563 aContentParentFrame ? aContentParentFrame :
10564 aParentFrame);
10565 if (NS_FAILED(rv)) {
10566 return 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);
10599 return rv;
10602 nsresult
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:
10634 // <span>
10635 // <div>a</div>
10636 // <span>
10637 // b
10638 // <div>c</div>
10639 // </span>
10640 // d
10641 // <div>e</div>
10642 // f
10643 // </span>
10644 // Gives the following frame tree:
10646 // Inline (outer span)
10647 // Block (anonymous, outer span)
10648 // Block (div)
10649 // Text("a")
10650 // Inline (outer span)
10651 // Inline (inner span)
10652 // Text("b")
10653 // Block (anonymous, outer span)
10654 // Block (anonymous, inner span)
10655 // Block (div)
10656 // Text("c")
10657 // Inline (outer span)
10658 // Inline (inner span)
10659 // Text("d")
10660 // Block (anonymous, outer span)
10661 // Block (div)
10662 // Text("e")
10663 // Inline (outer span)
10664 // Text("f")
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());
10675 if (positioned) {
10676 newFrame = NS_NewPositionedInlineFrame(mPresShell, styleContext);
10677 } else {
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);
10691 if (positioned) {
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,
10700 childItems);
10701 if (NS_FAILED(rv)) {
10702 // Clean up?
10703 return 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
10717 // bail.
10718 newFrame->SetInitialChildList(nsnull, childItems);
10719 if (NS_SUCCEEDED(rv)) {
10720 aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame);
10721 *aNewFrame = newFrame;
10723 return rv;
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;
10738 return NS_OK;
10741 void
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,
10758 styleContext);
10760 nsIFrame* lastNewInline = aInitialInline->GetFirstContinuation();
10761 do {
10762 // On entry to this loop aChildItems is not empty and the first frame in it
10763 // is block-level.
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,
10775 PR_FALSE);
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
10792 // frame
10793 nsIFrame* inlineFrame;
10794 if (aIsPositioned) {
10795 inlineFrame = NS_NewPositionedInlineFrame(mPresShell, styleContext);
10797 else {
10798 inlineFrame = NS_NewInlineFrame(mPresShell, styleContext);
10801 InitAndRestoreFrame(aState, content, parentFrame, nsnull, inlineFrame,
10802 PR_FALSE);
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,
10813 inlineKids);
10816 SetFrameIsSpecial(blockFrame, inlineFrame);
10817 aSiblings.AddChild(inlineFrame);
10818 lastNewInline = inlineFrame;
10819 } while (aChildItems.NotEmpty());
10821 SetFrameIsSpecial(lastNewInline, nsnull);
10824 void
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);
10842 iter != last;
10843 ++iter) {
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)) {
10851 continue;
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.
10882 static PRBool
10883 IsSafeToAppendToSpecialInline(nsIFrame* aParentFrame, nsIFrame* aNextSibling)
10885 NS_PRECONDITION(IsInlineFrame(aParentFrame),
10886 "Must have an inline parent here");
10887 do {
10888 NS_ASSERTION(IsFrameSpecial(aParentFrame), "How is this not special?");
10889 if (aNextSibling || aParentFrame->GetNextContinuation() ||
10890 GetSpecialSibling(aParentFrame)) {
10891 return PR_FALSE;
10894 aNextSibling = aParentFrame->GetNextSibling();
10895 aParentFrame = aParentFrame->GetParent();
10896 } while (IsInlineFrame(aParentFrame));
10898 return PR_TRUE;
10901 PRBool
10902 nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
10903 nsIFrame* aContainingBlock,
10904 nsIFrame* aFrame,
10905 FrameConstructionItemList& aItems,
10906 PRBool aIsAppend,
10907 nsIFrame* aPrevSibling)
10909 if (aItems.IsEmpty()) {
10910 return PR_FALSE;
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);
10922 return 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
10938 // list.
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
10954 // that point.
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
10977 // that point.
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);
10988 do {
10989 if (iter.SkipItemsWantingParentType(parentType)) {
10990 break;
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)) {
10996 break;
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);
11008 if (prevSibling) {
11009 break;
11011 parentPrevCont = parentPrevCont->GetPrevContinuation();
11014 if (prevSibling) {
11015 if (IsTablePseudo(prevSibling)) {
11016 // need to reframe
11017 break;
11019 } else if (IsTablePseudo(aFrame)) {
11020 // need to reframe
11021 break;
11025 FCItemIterator spaceEndIter(iter);
11026 // Advance spaceEndIter past any whitespace
11027 PRBool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
11029 PRBool okToDrop;
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;
11034 if (!okToDrop) {
11035 if (!nextSibling) {
11036 // Try to find one after all
11037 nsIFrame* parentNextCont = aFrame->GetNextContinuation();
11038 while (parentNextCont) {
11039 nextSibling = parentNextCont->GetFirstChild(nsnull);
11040 if (nextSibling) {
11041 break;
11043 parentNextCont = parentNextCont->GetNextContinuation();
11047 okToDrop = (nextSibling && !IsTablePseudo(nextSibling)) ||
11048 (!nextSibling && !IsTablePseudo(aFrame));
11050 #ifdef DEBUG
11051 else {
11052 NS_ASSERTION(!IsTablePseudo(aFrame), "How did that happen?");
11054 #endif
11055 } else {
11056 okToDrop = (spaceEndIter.item().DesiredParentType() == parentType);
11059 if (okToDrop) {
11060 iter.DeleteItemsTo(spaceEndIter);
11061 } else {
11062 // We're done: we don't want to drop the whitespace, and it has the
11063 // wrong parent type.
11064 break;
11067 // Now loop, since |iter| points to item right after the whitespace we
11068 // removed.
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
11078 // this method.
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()) {
11083 return PR_FALSE;
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);
11090 return 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.
11096 do {
11097 if (IsInlineFrame(aFrame)) {
11098 if (aItems.AreAllItemsInline()) {
11099 // We can just put the kids in.
11100 return PR_FALSE;
11103 if (!IsFrameSpecial(aFrame)) {
11104 // Need to go ahead and reconstruct.
11105 break;
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
11115 // that case.
11116 if (aIsAppend && IsSafeToAppendToSpecialInline(aFrame, nextSibling)) {
11117 return PR_FALSE;
11120 // Need to reconstruct.
11121 break;
11124 // Now we know we have a block parent. If it's not special, we're all set.
11125 if (!IsFrameSpecial(aFrame)) {
11126 return PR_FALSE;
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()) {
11132 return PR_FALSE;
11135 // We might have some inline kids for this block. Just reconstruct.
11136 break;
11137 } while (0);
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
11145 // frame that is:
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
11155 // them).
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();
11169 #ifdef DEBUG
11170 if (gNoisyContentUpdates) {
11171 printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p\n",
11172 static_cast<void*>(blockContent));
11174 #endif
11175 RecreateFramesForContent(blockContent, PR_TRUE);
11176 return PR_TRUE;
11179 nsresult
11180 nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame)
11183 #ifdef DEBUG
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
11187 // very poorly
11188 if (gNoisyContentUpdates) {
11189 printf("nsCSSFrameConstructor::ReframeContainingBlock frame=%p\n",
11190 static_cast<void*>(aFrame));
11192 #endif
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!!!");
11200 return NS_OK;
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) {
11218 #ifdef DEBUG
11219 if (gNoisyContentUpdates) {
11220 printf(" ==> blockContent=%p\n", static_cast<void*>(blockContent));
11222 #endif
11223 return RecreateFramesForContent(blockContent, PR_TRUE);
11227 // If we get here, we're screwed!
11228 return RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
11229 PR_TRUE);
11232 void
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();
11239 if (grandparent &&
11240 (grandparent->GetFlags() & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS)) {
11241 hint = nsRestyleHint(hint | eRestyle_LaterSiblings);
11243 PostRestyleEvent(aContainer, hint, NS_STYLE_HINT_NONE);
11246 void
11247 nsCSSFrameConstructor::RestyleForAppend(Element* aContainer,
11248 nsIContent* aFirstNewContent)
11250 NS_ASSERTION(aContainer, "must have container for append");
11251 #ifdef DEBUG
11253 for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
11254 NS_ASSERTION(!cur->IsRootOfAnonymousSubtree(),
11255 "anonymous nodes should not be in child lists");
11258 #endif
11259 PRUint32 selectorFlags =
11260 aContainer->GetFlags() & (NODE_ALL_SELECTOR_FLAGS &
11261 ~NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
11262 if (selectorFlags == 0)
11263 return;
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;
11277 break;
11280 if (wasEmpty) {
11281 RestyleForEmptyChange(aContainer);
11282 return;
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.
11289 return;
11292 if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
11293 // restyle the last element child before this node
11294 for (nsIContent* cur = aFirstNewContent->GetPreviousSibling();
11295 cur;
11296 cur = cur->GetPreviousSibling()) {
11297 if (cur->IsElement()) {
11298 PostRestyleEvent(cur->AsElement(), eRestyle_Subtree, NS_STYLE_HINT_NONE);
11299 break;
11305 // Needed since we can't use PostRestyleEvent on non-elements (with
11306 // eRestyle_LaterSiblings or nsRestyleHint(eRestyle_Subtree |
11307 // eRestyle_LaterSiblings) as appropriate).
11308 static void
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);
11319 break;
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.
11330 void
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)
11339 return;
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();
11345 child;
11346 child = child->GetNextSibling()) {
11347 if (child == aChild)
11348 continue;
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;
11355 break;
11358 if (wasEmpty) {
11359 RestyleForEmptyChange(aContainer);
11360 return;
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.
11367 return;
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();
11379 content;
11380 content = content->GetNextSibling()) {
11381 if (content == aChild) {
11382 passedChild = PR_TRUE;
11383 continue;
11385 if (content->IsElement()) {
11386 if (passedChild) {
11387 PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
11388 NS_STYLE_HINT_NONE);
11390 break;
11393 // restyle the previously-last element child if it is before this node
11394 passedChild = PR_FALSE;
11395 for (nsIContent* content = aContainer->GetLastChild();
11396 content;
11397 content = content->GetPreviousSibling()) {
11398 if (content == aChild) {
11399 passedChild = PR_TRUE;
11400 continue;
11402 if (content->IsElement()) {
11403 if (passedChild) {
11404 PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
11405 NS_STYLE_HINT_NONE);
11407 break;
11413 void
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)
11423 return;
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();
11429 child;
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;
11437 break;
11440 if (isEmpty) {
11441 RestyleForEmptyChange(aContainer);
11442 return;
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.
11449 return;
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();
11461 content;
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);
11472 break;
11475 // restyle the now-last element child if it was before aOldChild
11476 reachedFollowingSibling = (aFollowingSibling == nsnull);
11477 for (nsIContent* content = aContainer->GetLastChild();
11478 content;
11479 content = content->GetPreviousSibling()) {
11480 if (content->IsElement()) {
11481 if (reachedFollowingSibling) {
11482 PostRestyleEvent(content->AsElement(), eRestyle_Subtree, NS_STYLE_HINT_NONE);
11484 break;
11486 if (content == aFollowingSibling) {
11487 reachedFollowingSibling = PR_TRUE;
11494 void
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())
11506 return;
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);
11526 return;
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);
11553 void
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();
11568 #ifdef DEBUG
11569 PRUint32 oldPendingRestyleCount = mPendingRestyles.Count();
11570 #endif
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));
11597 void
11598 nsCSSFrameConstructor::PostRestyleEventCommon(Element* aElement,
11599 nsRestyleHint aRestyleHint,
11600 nsChangeHint aMinChangeHint,
11601 PRBool aForAnimation)
11603 if (NS_UNLIKELY(mPresShell->IsDestroying())) {
11604 return;
11607 if (aRestyleHint == 0 && !aMinChangeHint) {
11608 // Nothing to do here
11609 return;
11612 RestyleTracker& tracker =
11613 aForAnimation ? mPendingAnimationRestyles : mPendingRestyles;
11614 tracker.AddPendingRestyle(aElement, aRestyleHint, aMinChangeHint);
11616 PostRestyleEventInternal(PR_FALSE);
11619 void
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);
11632 void
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);
11645 nsresult
11646 nsCSSFrameConstructor::GenerateChildFrames(nsIFrame* aFrame)
11649 nsAutoScriptBlocker scriptBlocker;
11650 BeginUpdate();
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,
11659 nsnull);
11660 if (NS_FAILED(rv)) {
11661 EndUpdate();
11662 return rv;
11665 aFrame->SetInitialChildList(nsnull, childItems);
11667 EndUpdate();
11670 // call XBL constructors after the frames are created
11671 mPresShell->GetDocument()->BindingManager()->ProcessAttachedQueue();
11673 return NS_OK;
11676 //////////////////////////////////////////////////////////
11677 // nsCSSFrameConstructor::FrameConstructionItem methods //
11678 //////////////////////////////////////////////////////////
11679 PRBool
11680 nsCSSFrameConstructor::
11681 FrameConstructionItem::IsWhitespace(nsFrameConstructorState& aState) const
11683 NS_PRECONDITION(!aState.mSetPrimaryFrames ||
11684 !mContent->GetPrimaryFrame(), "How did that happen?");
11685 if (!mIsText) {
11686 return PR_FALSE;
11688 mContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
11689 NS_REFRAME_IF_WHITESPACE);
11690 return mContent->TextIsOnlyWhitespace();
11693 //////////////////////////////////////////////////////////////
11694 // nsCSSFrameConstructor::FrameConstructionItemList methods //
11695 //////////////////////////////////////////////////////////////
11696 void
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 ////////////////////////////////////////////////////////////////////////
11717 inline PRBool
11718 nsCSSFrameConstructor::FrameConstructionItemList::
11719 Iterator::SkipItemsWantingParentType(ParentType aParentType)
11721 NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
11722 while (item().DesiredParentType() == aParentType) {
11723 Next();
11724 if (IsDone()) {
11725 return PR_TRUE;
11728 return PR_FALSE;
11731 inline PRBool
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?");
11737 do {
11738 Next();
11739 if (IsDone()) {
11740 return PR_TRUE;
11742 } while (item().IsWhitespace(aState));
11744 return PR_FALSE;
11747 void
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);
11755 Next();
11756 PR_REMOVE_LINK(item);
11757 PR_APPEND_LINK(item, &aTargetList.mItems);
11759 mList.AdjustCountsForItem(item, -1);
11760 aTargetList.AdjustCountsForItem(item, 1);
11763 void
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()) {
11772 do {
11773 AppendItemToList(aTargetList);
11774 } while (*this != aEnd);
11775 return;
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));
11790 // reset mList
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?");
11798 void
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?");
11809 void
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");
11816 do {
11817 NS_ASSERTION(!IsDone(), "Ran off end of list?");
11818 FrameConstructionItem* item = ToItem(mCurrent);
11819 Next();
11820 PR_REMOVE_LINK(item);
11821 mList.AdjustCountsForItem(item, -1);
11822 delete item;
11823 } while (*this != aEnd);