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
5 : *
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/
10 : *
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.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
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.
22 : *
23 : * Contributor(s):
24 : * Dan Rosen <dr@netscape.com>
25 : * Mats Palmgren <matspal@gmail.com>
26 : *
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.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : /*
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
44 : */
45 :
46 : #include "mozilla/Util.h"
47 :
48 : #include "nsCSSFrameConstructor.h"
49 : #include "nsCRT.h"
50 : #include "nsIAtom.h"
51 : #include "nsIURL.h"
52 : #include "nsHashtable.h"
53 : #include "nsIHTMLDocument.h"
54 : #include "nsIStyleRule.h"
55 : #include "nsIFrame.h"
56 : #include "nsGkAtoms.h"
57 : #include "nsPresContext.h"
58 : #include "nsILinkHandler.h"
59 : #include "nsIDocument.h"
60 : #include "nsTableFrame.h"
61 : #include "nsTableColGroupFrame.h"
62 : #include "nsTableColFrame.h"
63 : #include "nsIDOMHTMLDocument.h"
64 : #include "nsIDOMHTMLTableColElement.h"
65 : #include "nsIDOMHTMLTableCaptionElem.h"
66 : #include "nsHTMLParts.h"
67 : #include "nsIPresShell.h"
68 : #include "nsUnicharUtils.h"
69 : #include "nsStyleSet.h"
70 : #include "nsIViewManager.h"
71 : #include "nsEventStates.h"
72 : #include "nsStyleConsts.h"
73 : #include "nsTableOuterFrame.h"
74 : #include "nsIDOMXULElement.h"
75 : #include "nsContainerFrame.h"
76 : #include "nsINameSpaceManager.h"
77 : #include "nsIDOMHTMLSelectElement.h"
78 : #include "nsIDOMHTMLLegendElement.h"
79 : #include "nsIComboboxControlFrame.h"
80 : #include "nsIListControlFrame.h"
81 : #include "nsISelectControlFrame.h"
82 : #include "nsIDOMCharacterData.h"
83 : #include "nsIDOMHTMLImageElement.h"
84 : #include "nsPlaceholderFrame.h"
85 : #include "nsTableRowGroupFrame.h"
86 : #include "nsStyleChangeList.h"
87 : #include "nsIFormControl.h"
88 : #include "nsCSSAnonBoxes.h"
89 : #include "nsTextFragment.h"
90 : #include "nsIAnonymousContentCreator.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 "nsLayoutErrors.h"
108 : #include "nsLayoutUtils.h"
109 : #include "nsAutoPtr.h"
110 : #include "nsBoxFrame.h"
111 : #include "nsBoxLayout.h"
112 : #include "nsImageFrame.h"
113 : #include "nsIObjectLoadingContent.h"
114 : #include "nsContentErrors.h"
115 : #include "nsIPrincipal.h"
116 : #include "nsStyleUtil.h"
117 : #include "nsBox.h"
118 : #include "nsTArray.h"
119 : #include "nsGenericDOMDataNode.h"
120 : #include "mozilla/dom/Element.h"
121 : #include "FrameLayerBuilder.h"
122 : #include "nsAutoLayoutPhase.h"
123 :
124 : #ifdef MOZ_XUL
125 : #include "nsIRootBox.h"
126 : #include "nsIDOMXULCommandDispatcher.h"
127 : #include "nsIDOMXULDocument.h"
128 : #include "nsIXULDocument.h"
129 : #endif
130 : #ifdef ACCESSIBILITY
131 : #include "nsAccessibilityService.h"
132 : #endif
133 :
134 : #include "nsInlineFrame.h"
135 : #include "nsBlockFrame.h"
136 :
137 : #include "nsIScrollableFrame.h"
138 :
139 : #include "nsIXBLService.h"
140 :
141 : #undef NOISY_FIRST_LETTER
142 :
143 : #include "nsMathMLParts.h"
144 : #include "nsIDOMSVGFilters.h"
145 : #include "DOMSVGTests.h"
146 : #include "nsSVGEffects.h"
147 : #include "nsSVGUtils.h"
148 :
149 : #include "nsRefreshDriver.h"
150 : #include "nsRuleProcessorData.h"
151 :
152 : using namespace mozilla;
153 : using namespace mozilla::dom;
154 :
155 : // An alias for convenience.
156 : static const nsIFrame::ChildListID kPrincipalList = nsIFrame::kPrincipalList;
157 :
158 : nsIFrame*
159 : NS_NewHTMLCanvasFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
160 :
161 : #if defined(MOZ_MEDIA)
162 : nsIFrame*
163 : NS_NewHTMLVideoFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
164 : #endif
165 :
166 : #include "nsSVGTextContainerFrame.h"
167 :
168 : nsIFrame*
169 : NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
170 : nsIFrame*
171 : NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
172 : nsIFrame*
173 : NS_NewSVGPathGeometryFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
174 : nsIFrame*
175 : NS_NewSVGGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
176 : nsIFrame*
177 : NS_NewSVGGenericContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
178 : nsIFrame*
179 : NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
180 : nsIFrame*
181 : NS_NewSVGAFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
182 : nsIFrame*
183 : NS_NewSVGGlyphFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
184 : nsIFrame*
185 : NS_NewSVGSwitchFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
186 : nsIFrame*
187 : NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
188 : nsIFrame*
189 : NS_NewSVGTSpanFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
190 : nsIFrame*
191 : NS_NewSVGContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
192 : nsIFrame*
193 : NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
194 : extern nsIFrame*
195 : NS_NewSVGLinearGradientFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
196 : extern nsIFrame*
197 : NS_NewSVGRadialGradientFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
198 : extern nsIFrame*
199 : NS_NewSVGStopFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
200 : nsIFrame*
201 : NS_NewSVGMarkerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
202 : extern nsIFrame*
203 : NS_NewSVGImageFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
204 : nsIFrame*
205 : NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
206 : nsIFrame*
207 : NS_NewSVGTextPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
208 : nsIFrame*
209 : NS_NewSVGFilterFrame(nsIPresShell *aPresShell, nsStyleContext* aContext);
210 : nsIFrame*
211 : NS_NewSVGPatternFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
212 : nsIFrame*
213 : NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
214 : nsIFrame*
215 : NS_NewSVGFEContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
216 : nsIFrame*
217 : NS_NewSVGFELeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
218 : nsIFrame*
219 : NS_NewSVGFEImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
220 : nsIFrame*
221 : NS_NewSVGFEUnstyledLeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
222 :
223 : #include "nsIScrollable.h"
224 : #include "nsINodeInfo.h"
225 : #include "prenv.h"
226 : #include "nsWidgetsCID.h"
227 : #include "nsNodeInfoManager.h"
228 : #include "nsContentCreatorFunctions.h"
229 : #include "nsIServiceManager.h"
230 :
231 : // Global object maintenance
232 : nsIXBLService * nsCSSFrameConstructor::gXBLService = nsnull;
233 :
234 : #ifdef DEBUG
235 : // Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or
236 : // more of the following flags (comma separated) for handy debug
237 : // output.
238 : static bool gNoisyContentUpdates = false;
239 : static bool gReallyNoisyContentUpdates = false;
240 : static bool gNoisyInlineConstruction = false;
241 :
242 : struct FrameCtorDebugFlags {
243 : const char* name;
244 : bool* on;
245 : };
246 :
247 : static FrameCtorDebugFlags gFlags[] = {
248 : { "content-updates", &gNoisyContentUpdates },
249 : { "really-noisy-content-updates", &gReallyNoisyContentUpdates },
250 : { "noisy-inline", &gNoisyInlineConstruction }
251 : };
252 :
253 : #define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
254 : #endif
255 :
256 :
257 : #ifdef MOZ_XUL
258 : #include "nsMenuFrame.h"
259 : #include "nsMenuPopupFrame.h"
260 : #include "nsPopupSetFrame.h"
261 : #include "nsTreeColFrame.h"
262 : #include "nsIBoxObject.h"
263 : #include "nsPIListBoxObject.h"
264 : #include "nsListBoxBodyFrame.h"
265 : #include "nsListItemFrame.h"
266 : #include "nsXULLabelFrame.h"
267 :
268 : //------------------------------------------------------------------
269 :
270 : nsIFrame*
271 : NS_NewAutoRepeatBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
272 :
273 : nsIFrame*
274 : NS_NewRootBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
275 :
276 : nsIFrame*
277 : NS_NewDocElementBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
278 :
279 : nsIFrame*
280 : NS_NewThumbFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
281 :
282 : nsIFrame*
283 : NS_NewDeckFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
284 :
285 : nsIFrame*
286 : NS_NewLeafBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
287 :
288 : nsIFrame*
289 : NS_NewStackFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
290 :
291 : nsIFrame*
292 : NS_NewProgressMeterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
293 :
294 : nsIFrame*
295 : NS_NewImageBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
296 :
297 : nsIFrame*
298 : NS_NewTextBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
299 :
300 : nsIFrame*
301 : NS_NewGroupBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
302 :
303 : nsIFrame*
304 : NS_NewButtonBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
305 :
306 : nsIFrame*
307 : NS_NewSplitterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
308 :
309 : nsIFrame*
310 : NS_NewMenuPopupFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
311 :
312 : nsIFrame*
313 : NS_NewPopupSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
314 :
315 : nsIFrame*
316 : NS_NewMenuFrame (nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aFlags);
317 :
318 : nsIFrame*
319 : NS_NewMenuBarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
320 :
321 : nsIFrame*
322 : NS_NewTreeBodyFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
323 :
324 : // grid
325 : nsresult
326 : NS_NewGridLayout2 ( nsIPresShell* aPresShell, nsBoxLayout** aNewLayout );
327 : nsIFrame*
328 : NS_NewGridRowLeafFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
329 : nsIFrame*
330 : NS_NewGridRowGroupFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
331 :
332 : // end grid
333 :
334 : nsIFrame*
335 : NS_NewTitleBarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
336 :
337 : nsIFrame*
338 : NS_NewResizerFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
339 :
340 :
341 : #endif
342 :
343 : nsIFrame*
344 : NS_NewHTMLScrollFrame (nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot);
345 :
346 : nsIFrame*
347 : NS_NewXULScrollFrame (nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot);
348 :
349 : nsIFrame*
350 : NS_NewSliderFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
351 :
352 : nsIFrame*
353 : NS_NewScrollbarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
354 :
355 : nsIFrame*
356 : NS_NewScrollbarButtonFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
357 :
358 :
359 : #ifdef NOISY_FINDFRAME
360 : static PRInt32 FFWC_totalCount=0;
361 : static PRInt32 FFWC_doLoop=0;
362 : static PRInt32 FFWC_doSibling=0;
363 : static PRInt32 FFWC_recursions=0;
364 : static PRInt32 FFWC_nextInFlows=0;
365 : #endif
366 :
367 : static inline nsIFrame*
368 0 : GetFieldSetBlockFrame(nsIFrame* aFieldsetFrame)
369 : {
370 : // Depends on the fieldset child frame order - see ConstructFieldSetFrame() below.
371 0 : nsIFrame* firstChild = aFieldsetFrame->GetFirstPrincipalChild();
372 0 : return firstChild && firstChild->GetNextSibling() ? firstChild->GetNextSibling() : firstChild;
373 : }
374 :
375 : #define FCDATA_DECL(_flags, _func) \
376 : { _flags, { (FrameCreationFunc)_func }, nsnull, nsnull }
377 : #define FCDATA_WITH_WRAPPING_BLOCK(_flags, _func, _anon_box) \
378 : { _flags | FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS, \
379 : { (FrameCreationFunc)_func }, nsnull, &_anon_box }
380 :
381 : //----------------------------------------------------------------------
382 :
383 : static bool
384 0 : IsInlineOutside(nsIFrame* aFrame)
385 : {
386 0 : return aFrame->GetStyleDisplay()->IsInlineOutside();
387 : }
388 :
389 : /**
390 : * True if aFrame is an actual inline frame in the sense of non-replaced
391 : * display:inline CSS boxes. In other words, it can be affected by {ib}
392 : * splitting and can contain first-letter frames. Basically, this is either an
393 : * inline frame (positioned or otherwise) or an line frame (this last because
394 : * it can contain first-letter and because inserting blocks in the middle of it
395 : * needs to terminate it).
396 : */
397 : static bool
398 0 : IsInlineFrame(const nsIFrame* aFrame)
399 : {
400 0 : return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
401 : }
402 :
403 : /**
404 : * If any children require a block parent, return the first such child.
405 : * Otherwise return null.
406 : */
407 : static nsIContent*
408 0 : AnyKidsNeedBlockParent(nsIFrame *aFrameList)
409 : {
410 0 : for (nsIFrame *k = aFrameList; k; k = k->GetNextSibling()) {
411 : // Line participants, such as text and inline frames, can't be
412 : // directly inside a XUL box; they must be wrapped in an
413 : // intermediate block.
414 0 : if (k->IsFrameOfType(nsIFrame::eLineParticipant)) {
415 0 : return k->GetContent();
416 : }
417 : }
418 0 : return nsnull;
419 : }
420 :
421 : // Reparent a frame into a wrapper frame that is a child of its old parent.
422 : static void
423 0 : ReparentFrame(nsFrameManager* aFrameManager,
424 : nsIFrame* aNewParentFrame,
425 : nsIFrame* aFrame)
426 : {
427 0 : aFrame->SetParent(aNewParentFrame);
428 0 : aFrameManager->ReparentStyleContext(aFrame);
429 0 : }
430 :
431 : static void
432 0 : ReparentFrames(nsFrameManager* aFrameManager,
433 : nsIFrame* aNewParentFrame,
434 : const nsFrameList& aFrameList)
435 : {
436 0 : for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
437 0 : ReparentFrame(aFrameManager, aNewParentFrame, e.get());
438 : }
439 0 : }
440 :
441 : //----------------------------------------------------------------------
442 : //
443 : // When inline frames get weird and have block frames in them, we
444 : // annotate them to help us respond to incremental content changes
445 : // more easily.
446 :
447 : static inline bool
448 0 : IsFrameSpecial(nsIFrame* aFrame)
449 : {
450 0 : return (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) != 0;
451 : }
452 :
453 0 : static nsIFrame* GetSpecialSibling(nsIFrame* aFrame)
454 : {
455 0 : NS_PRECONDITION(IsFrameSpecial(aFrame), "Shouldn't call this");
456 :
457 : // We only store the "special sibling" annotation with the first
458 : // frame in the continuation chain. Walk back to find that frame now.
459 : return static_cast<nsIFrame*>
460 0 : (aFrame->GetFirstContinuation()->
461 0 : Properties().Get(nsIFrame::IBSplitSpecialSibling()));
462 : }
463 :
464 0 : static nsIFrame* GetSpecialPrevSibling(nsIFrame* aFrame)
465 : {
466 0 : NS_PRECONDITION(IsFrameSpecial(aFrame), "Shouldn't call this");
467 :
468 : // We only store the "special sibling" annotation with the first
469 : // frame in the continuation chain. Walk back to find that frame now.
470 : return static_cast<nsIFrame*>
471 0 : (aFrame->GetFirstContinuation()->
472 0 : Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
473 : }
474 :
475 : static nsIFrame*
476 0 : GetLastSpecialSibling(nsIFrame* aFrame, bool aReturnEmptyTrailingInline)
477 : {
478 0 : for (nsIFrame *frame = aFrame, *next; ; frame = next) {
479 0 : next = GetSpecialSibling(frame);
480 0 : if (!next ||
481 0 : (!aReturnEmptyTrailingInline && !next->GetFirstPrincipalChild() &&
482 0 : !GetSpecialSibling(next))) {
483 0 : NS_ASSERTION(!next || !IsInlineOutside(frame),
484 : "Should have a block here!");
485 0 : return frame;
486 : }
487 : }
488 : NS_NOTREACHED("unreachable code");
489 : return nsnull;
490 : }
491 :
492 : static void
493 0 : SetFrameIsSpecial(nsIFrame* aFrame, nsIFrame* aSpecialSibling)
494 : {
495 0 : NS_PRECONDITION(aFrame, "bad args!");
496 :
497 : // We should be the only continuation
498 0 : NS_ASSERTION(!aFrame->GetPrevContinuation(),
499 : "assigning special sibling to other than first continuation!");
500 0 : NS_ASSERTION(!aFrame->GetNextContinuation() ||
501 : IsFrameSpecial(aFrame->GetNextContinuation()),
502 : "should have no non-special continuations here");
503 :
504 : // Mark the frame as "special".
505 0 : aFrame->AddStateBits(NS_FRAME_IS_SPECIAL);
506 :
507 0 : if (aSpecialSibling) {
508 0 : NS_ASSERTION(!aSpecialSibling->GetPrevContinuation(),
509 : "assigning something other than the first continuation as the "
510 : "special sibling");
511 :
512 : // Store the "special sibling" (if we were given one) with the
513 : // first frame in the flow.
514 0 : FramePropertyTable* props = aFrame->PresContext()->PropertyTable();
515 0 : props->Set(aFrame, nsIFrame::IBSplitSpecialSibling(), aSpecialSibling);
516 0 : props->Set(aSpecialSibling, nsIFrame::IBSplitSpecialPrevSibling(), aFrame);
517 : }
518 0 : }
519 :
520 : static nsIFrame*
521 0 : GetIBContainingBlockFor(nsIFrame* aFrame)
522 : {
523 0 : NS_PRECONDITION(IsFrameSpecial(aFrame),
524 : "GetIBContainingBlockFor() should only be called on known IB frames");
525 :
526 : // Get the first "normal" ancestor of the target frame.
527 : nsIFrame* parentFrame;
528 0 : do {
529 0 : parentFrame = aFrame->GetParent();
530 :
531 0 : if (! parentFrame) {
532 0 : NS_ERROR("no unsplit block frame in IB hierarchy");
533 0 : return aFrame;
534 : }
535 :
536 : // Note that we ignore non-special frames which have a pseudo on their
537 : // style context -- they're not the frames we're looking for! In
538 : // particular, they may be hiding a real parent that _is_ special.
539 0 : if (!IsFrameSpecial(parentFrame) &&
540 0 : !parentFrame->GetStyleContext()->GetPseudo())
541 : break;
542 :
543 0 : aFrame = parentFrame;
544 : } while (1);
545 :
546 : // post-conditions
547 0 : NS_ASSERTION(parentFrame, "no normal ancestor found for special frame in GetIBContainingBlockFor");
548 0 : NS_ASSERTION(parentFrame != aFrame, "parentFrame is actually the child frame - bogus reslt");
549 :
550 0 : return parentFrame;
551 : }
552 :
553 : //----------------------------------------------------------------------
554 :
555 : // Block/inline frame construction logic. We maintain a few invariants here:
556 : //
557 : // 1. Block frames contain block and inline frames.
558 : //
559 : // 2. Inline frames only contain inline frames. If an inline parent has a block
560 : // child then the block child is migrated upward until it lands in a block
561 : // parent (the inline frames containing block is where it will end up).
562 :
563 : // After this function returns, aLink is pointing to the first link at or
564 : // after its starting position for which the next frame is a block. If there
565 : // is no such link, it points to the end of the list.
566 : static void
567 0 : FindFirstBlock(nsFrameList::FrameLinkEnumerator& aLink)
568 : {
569 0 : for ( ; !aLink.AtEnd(); aLink.Next()) {
570 0 : if (!IsInlineOutside(aLink.NextFrame())) {
571 0 : return;
572 : }
573 : }
574 : }
575 :
576 : // This function returns a frame link enumerator pointing to the first link in
577 : // the list for which the next frame is not block. If there is no such link,
578 : // it points to the end of the list.
579 : static nsFrameList::FrameLinkEnumerator
580 0 : FindFirstNonBlock(const nsFrameList& aList)
581 : {
582 0 : nsFrameList::FrameLinkEnumerator link(aList);
583 0 : for (; !link.AtEnd(); link.Next()) {
584 0 : if (IsInlineOutside(link.NextFrame())) {
585 0 : break;
586 : }
587 : }
588 : return link;
589 : }
590 :
591 : inline void
592 0 : SetInitialSingleChild(nsIFrame* aParent, nsIFrame* aFrame)
593 : {
594 0 : NS_PRECONDITION(!aFrame->GetNextSibling(), "Should be using a frame list");
595 0 : nsFrameList temp(aFrame, aFrame);
596 0 : aParent->SetInitialChildList(kPrincipalList, temp);
597 0 : }
598 :
599 : // -----------------------------------------------------------
600 :
601 : // Structure used when constructing formatting object trees.
602 : struct nsFrameItems : public nsFrameList
603 0 : {
604 : // Appends the frame to the end of the list
605 : void AddChild(nsIFrame* aChild);
606 : };
607 :
608 : void
609 0 : nsFrameItems::AddChild(nsIFrame* aChild)
610 : {
611 0 : NS_PRECONDITION(aChild, "nsFrameItems::AddChild");
612 :
613 : // It'd be really nice if we could just AppendFrames(kPrincipalList, aChild) here,
614 : // but some of our callers put frames that have different
615 : // parents (caption, I'm looking at you) on the same framelist, and
616 : // nsFrameList asserts if you try to do that.
617 0 : if (IsEmpty()) {
618 0 : SetFrames(aChild);
619 : }
620 : else {
621 0 : NS_ASSERTION(aChild != mLastChild,
622 : "Same frame being added to frame list twice?");
623 0 : mLastChild->SetNextSibling(aChild);
624 0 : mLastChild = nsLayoutUtils::GetLastSibling(aChild);
625 : }
626 0 : }
627 :
628 : // -----------------------------------------------------------
629 :
630 : // Structure used when constructing formatting object trees. Contains
631 : // state information needed for absolutely positioned elements
632 : struct nsAbsoluteItems : nsFrameItems {
633 : // containing block for absolutely positioned elements
634 : nsIFrame* containingBlock;
635 :
636 : nsAbsoluteItems(nsIFrame* aContainingBlock);
637 : #ifdef DEBUG
638 : // XXXbz Does this need a debug-only assignment operator that nulls out the
639 : // childList in the nsAbsoluteItems we're copying? Introducing a difference
640 : // between debug and non-debug behavior seems bad, so I guess not...
641 0 : ~nsAbsoluteItems() {
642 0 : NS_ASSERTION(!FirstChild(),
643 : "Dangling child list. Someone forgot to insert it?");
644 0 : }
645 : #endif
646 :
647 : // Appends the frame to the end of the list
648 : void AddChild(nsIFrame* aChild);
649 : };
650 :
651 0 : nsAbsoluteItems::nsAbsoluteItems(nsIFrame* aContainingBlock)
652 0 : : containingBlock(aContainingBlock)
653 : {
654 0 : }
655 :
656 : // Additional behavior is that it sets the frame's NS_FRAME_OUT_OF_FLOW flag
657 : void
658 0 : nsAbsoluteItems::AddChild(nsIFrame* aChild)
659 : {
660 0 : NS_ASSERTION(aChild->PresContext()->FrameManager()->
661 : GetPlaceholderFrameFor(aChild),
662 : "Child without placeholder being added to nsAbsoluteItems?");
663 0 : aChild->AddStateBits(NS_FRAME_OUT_OF_FLOW);
664 0 : nsFrameItems::AddChild(aChild);
665 0 : }
666 :
667 : // -----------------------------------------------------------
668 :
669 : // Structure for saving the existing state when pushing/poping containing
670 : // blocks. The destructor restores the state to its previous state
671 : class NS_STACK_CLASS nsFrameConstructorSaveState {
672 : public:
673 : typedef nsIFrame::ChildListID ChildListID;
674 : nsFrameConstructorSaveState();
675 : ~nsFrameConstructorSaveState();
676 :
677 : private:
678 : nsAbsoluteItems* mItems; // pointer to struct whose data we save/restore
679 : bool* mFixedPosIsAbsPos;
680 :
681 : nsAbsoluteItems mSavedItems; // copy of original data
682 : bool mSavedFixedPosIsAbsPos;
683 :
684 : // The name of the child list in which our frames would belong
685 : ChildListID mChildListID;
686 : nsFrameConstructorState* mState;
687 :
688 : friend class nsFrameConstructorState;
689 : };
690 :
691 : // Structure used to keep track of a list of bindings we need to call
692 : // AddToAttachedQueue on. These should be in post-order depth-first
693 : // flattened tree traversal order.
694 : struct PendingBinding : public PRCList
695 : {
696 : #ifdef NS_BUILD_REFCNT_LOGGING
697 0 : PendingBinding() {
698 0 : MOZ_COUNT_CTOR(PendingBinding);
699 0 : }
700 0 : ~PendingBinding() {
701 0 : MOZ_COUNT_DTOR(PendingBinding);
702 0 : }
703 : #endif
704 :
705 : nsRefPtr<nsXBLBinding> mBinding;
706 : };
707 :
708 : // Structure used for maintaining state information during the
709 : // frame construction process
710 : class NS_STACK_CLASS nsFrameConstructorState {
711 : public:
712 : typedef nsIFrame::ChildListID ChildListID;
713 :
714 : nsPresContext *mPresContext;
715 : nsIPresShell *mPresShell;
716 : nsFrameManager *mFrameManager;
717 :
718 : #ifdef MOZ_XUL
719 : // Frames destined for the kPopupList.
720 : nsAbsoluteItems mPopupItems;
721 : #endif
722 :
723 : // Containing block information for out-of-flow frames.
724 : nsAbsoluteItems mFixedItems;
725 : nsAbsoluteItems mAbsoluteItems;
726 : nsAbsoluteItems mFloatedItems;
727 :
728 : nsCOMPtr<nsILayoutHistoryState> mFrameState;
729 : // These bits will be added to the state bits of any frame we construct
730 : // using this state.
731 : nsFrameState mAdditionalStateBits;
732 :
733 : // When working with the -moz-transform property, we want to hook
734 : // the abs-pos and fixed-pos lists together, since transformed
735 : // elements are fixed-pos containing blocks. This flag determines
736 : // whether or not we want to wire the fixed-pos and abs-pos lists
737 : // together.
738 : bool mFixedPosIsAbsPos;
739 :
740 : // A boolean to indicate whether we have a "pending" popupgroup. That is, we
741 : // have already created the FrameConstructionItem for the root popupgroup but
742 : // we have not yet created the relevant frame.
743 : bool mHavePendingPopupgroup;
744 :
745 : // If false (which is the default) then call SetPrimaryFrame() as needed
746 : // during frame construction. If true, don't make any SetPrimaryFrame()
747 : // calls, except for generated content which doesn't have a primary frame
748 : // yet. The mCreatingExtraFrames == true mode is meant to be used for
749 : // construction of random "extra" frames for elements via normal frame
750 : // construction APIs (e.g. replication of things across pages in paginated
751 : // mode).
752 : bool mCreatingExtraFrames;
753 :
754 : nsCOMArray<nsIContent> mGeneratedTextNodesWithInitializer;
755 :
756 : TreeMatchContext mTreeMatchContext;
757 :
758 : // Constructor
759 : // Use the passed-in history state.
760 : nsFrameConstructorState(nsIPresShell* aPresShell,
761 : nsIFrame* aFixedContainingBlock,
762 : nsIFrame* aAbsoluteContainingBlock,
763 : nsIFrame* aFloatContainingBlock,
764 : nsILayoutHistoryState* aHistoryState);
765 : // Get the history state from the pres context's pres shell.
766 : nsFrameConstructorState(nsIPresShell* aPresShell,
767 : nsIFrame* aFixedContainingBlock,
768 : nsIFrame* aAbsoluteContainingBlock,
769 : nsIFrame* aFloatContainingBlock);
770 :
771 : ~nsFrameConstructorState();
772 :
773 : // Function to push the existing absolute containing block state and
774 : // create a new scope. Code that uses this function should get matching
775 : // logic in GetAbsoluteContainingBlock.
776 : void PushAbsoluteContainingBlock(nsIFrame* aNewAbsoluteContainingBlock,
777 : nsFrameConstructorSaveState& aSaveState);
778 :
779 : // Function to push the existing float containing block state and
780 : // create a new scope. Code that uses this function should get matching
781 : // logic in GetFloatContainingBlock.
782 : // Pushing a null float containing block forbids any frames from being
783 : // floated until a new float containing block is pushed.
784 : // XXX we should get rid of null float containing blocks and teach the
785 : // various frame classes to deal with floats instead.
786 : void PushFloatContainingBlock(nsIFrame* aNewFloatContainingBlock,
787 : nsFrameConstructorSaveState& aSaveState);
788 :
789 : // Function to return the proper geometric parent for a frame with display
790 : // struct given by aStyleDisplay and parent's frame given by
791 : // aContentParentFrame.
792 : nsIFrame* GetGeometricParent(const nsStyleDisplay* aStyleDisplay,
793 : nsIFrame* aContentParentFrame);
794 :
795 : /**
796 : * Function to add a new frame to the right frame list. This MUST be called
797 : * on frames before their children have been processed if the frames might
798 : * conceivably be out-of-flow; otherwise cleanup in error cases won't work
799 : * right. Also, this MUST be called on frames after they have been
800 : * initialized.
801 : * @param aNewFrame the frame to add
802 : * @param aFrameItems the list to add in-flow frames to
803 : * @param aContent the content pointer for aNewFrame
804 : * @param aStyleContext the style context resolved for aContent
805 : * @param aParentFrame the parent frame for the content if it were in-flow
806 : * @param aCanBePositioned pass false if the frame isn't allowed to be
807 : * positioned
808 : * @param aCanBeFloated pass false if the frame isn't allowed to be
809 : * floated
810 : * @param aIsOutOfFlowPopup pass true if the frame is an out-of-flow popup
811 : * (XUL-only)
812 : * @throws NS_ERROR_OUT_OF_MEMORY if it happens.
813 : * @note If this method throws, that means that aNewFrame was not inserted
814 : * into any frame lists. Furthermore, this method will handle cleanup
815 : * of aNewFrame (via calling Destroy() on it).
816 : */
817 : nsresult AddChild(nsIFrame* aNewFrame,
818 : nsFrameItems& aFrameItems,
819 : nsIContent* aContent,
820 : nsStyleContext* aStyleContext,
821 : nsIFrame* aParentFrame,
822 : bool aCanBePositioned = true,
823 : bool aCanBeFloated = true,
824 : bool aIsOutOfFlowPopup = false,
825 : bool aInsertAfter = false,
826 : nsIFrame* aInsertAfterFrame = nsnull);
827 :
828 : /**
829 : * Function to return the fixed-pos element list. Normally this will just hand back the
830 : * fixed-pos element list, but in case we're dealing with a transformed element that's
831 : * acting as an abs-pos and fixed-pos container, we'll hand back the abs-pos list. Callers should
832 : * use this function if they want to get the list acting as the fixed-pos item parent.
833 : */
834 0 : nsAbsoluteItems& GetFixedItems()
835 : {
836 0 : return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
837 : }
838 : const nsAbsoluteItems& GetFixedItems() const
839 : {
840 : return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
841 : }
842 :
843 :
844 : /**
845 : * class to automatically push and pop a pending binding in the frame
846 : * constructor state. See nsCSSFrameConstructor::FrameConstructionItem
847 : * mPendingBinding documentation.
848 : */
849 : class PendingBindingAutoPusher;
850 : friend class PendingBindingAutoPusher;
851 : class NS_STACK_CLASS PendingBindingAutoPusher {
852 : public:
853 0 : PendingBindingAutoPusher(nsFrameConstructorState& aState,
854 : PendingBinding* aPendingBinding) :
855 : mState(aState),
856 0 : mPendingBinding(aState.mCurrentPendingBindingInsertionPoint)
857 : {
858 0 : NS_PRECONDITION(mPendingBinding, "how did that happen?");
859 0 : if (aPendingBinding) {
860 0 : aState.mCurrentPendingBindingInsertionPoint = aPendingBinding;
861 : }
862 0 : }
863 :
864 0 : ~PendingBindingAutoPusher()
865 : {
866 0 : mState.mCurrentPendingBindingInsertionPoint = mPendingBinding;
867 0 : }
868 :
869 : private:
870 : nsFrameConstructorState& mState;
871 : PRCList* mPendingBinding;
872 : };
873 :
874 : /**
875 : * Add a new pending binding to the list
876 : */
877 0 : void AddPendingBinding(PendingBinding* aPendingBinding) {
878 0 : PR_INSERT_BEFORE(aPendingBinding, mCurrentPendingBindingInsertionPoint);
879 0 : }
880 :
881 : protected:
882 : friend class nsFrameConstructorSaveState;
883 :
884 : /**
885 : * ProcessFrameInsertions takes the frames in aFrameItems and adds them as
886 : * kids to the aChildListID child list of |aFrameItems.containingBlock|.
887 : */
888 : void ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
889 : ChildListID aChildListID);
890 :
891 : // Our list of all pending bindings. When we're done, we need to call
892 : // AddToAttachedQueue on all of them, in order.
893 : PRCList mPendingBindings;
894 :
895 : PRCList* mCurrentPendingBindingInsertionPoint;
896 : };
897 :
898 0 : nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
899 : nsIFrame* aFixedContainingBlock,
900 : nsIFrame* aAbsoluteContainingBlock,
901 : nsIFrame* aFloatContainingBlock,
902 : nsILayoutHistoryState* aHistoryState)
903 0 : : mPresContext(aPresShell->GetPresContext()),
904 : mPresShell(aPresShell),
905 0 : mFrameManager(aPresShell->FrameManager()),
906 : #ifdef MOZ_XUL
907 : mPopupItems(nsnull),
908 : #endif
909 : mFixedItems(aFixedContainingBlock),
910 : mAbsoluteItems(aAbsoluteContainingBlock),
911 : mFloatedItems(aFloatContainingBlock),
912 : // See PushAbsoluteContaningBlock below
913 : mFrameState(aHistoryState),
914 : mAdditionalStateBits(0),
915 : mFixedPosIsAbsPos(aAbsoluteContainingBlock &&
916 : aAbsoluteContainingBlock->GetStyleDisplay()->
917 0 : HasTransform()),
918 : mHavePendingPopupgroup(false),
919 : mCreatingExtraFrames(false),
920 : mTreeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited,
921 : aPresShell->GetDocument()),
922 0 : mCurrentPendingBindingInsertionPoint(&mPendingBindings)
923 : {
924 : #ifdef MOZ_XUL
925 0 : nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell);
926 0 : if (rootBox) {
927 0 : mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
928 : }
929 : #endif
930 0 : MOZ_COUNT_CTOR(nsFrameConstructorState);
931 0 : PR_INIT_CLIST(&mPendingBindings);
932 0 : }
933 :
934 0 : nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
935 : nsIFrame* aFixedContainingBlock,
936 : nsIFrame* aAbsoluteContainingBlock,
937 : nsIFrame* aFloatContainingBlock)
938 0 : : mPresContext(aPresShell->GetPresContext()),
939 : mPresShell(aPresShell),
940 0 : mFrameManager(aPresShell->FrameManager()),
941 : #ifdef MOZ_XUL
942 : mPopupItems(nsnull),
943 : #endif
944 : mFixedItems(aFixedContainingBlock),
945 : mAbsoluteItems(aAbsoluteContainingBlock),
946 : mFloatedItems(aFloatContainingBlock),
947 : // See PushAbsoluteContaningBlock below
948 : mAdditionalStateBits(0),
949 : mFixedPosIsAbsPos(aAbsoluteContainingBlock &&
950 : aAbsoluteContainingBlock->GetStyleDisplay()->
951 0 : HasTransform()),
952 : mHavePendingPopupgroup(false),
953 : mCreatingExtraFrames(false),
954 : mTreeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited,
955 : aPresShell->GetDocument()),
956 0 : mCurrentPendingBindingInsertionPoint(&mPendingBindings)
957 : {
958 : #ifdef MOZ_XUL
959 0 : nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell);
960 0 : if (rootBox) {
961 0 : mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
962 : }
963 : #endif
964 0 : MOZ_COUNT_CTOR(nsFrameConstructorState);
965 0 : mFrameState = aPresShell->GetDocument()->GetLayoutHistoryState();
966 0 : PR_INIT_CLIST(&mPendingBindings);
967 0 : }
968 :
969 0 : nsFrameConstructorState::~nsFrameConstructorState()
970 : {
971 : // Frame order comparison functions only work properly when the placeholders
972 : // have been inserted into the frame tree. So for example if we have a new float
973 : // containing the placeholder for a new abs-pos frame, and we process the abs-pos
974 : // insertion first, then we won't be able to find the right place to insert in
975 : // in the abs-pos list. So put floats in first, because they can contain placeholders
976 : // for abs-pos and fixed-pos items whose containing blocks are outside the floats.
977 : // Then put abs-pos frames in, because they can contain placeholders for fixed-pos
978 : // items whose containing block is outside the abs-pos frames.
979 0 : MOZ_COUNT_DTOR(nsFrameConstructorState);
980 0 : ProcessFrameInsertions(mFloatedItems, nsIFrame::kFloatList);
981 0 : ProcessFrameInsertions(mAbsoluteItems, nsIFrame::kAbsoluteList);
982 0 : ProcessFrameInsertions(mFixedItems, nsIFrame::kFixedList);
983 : #ifdef MOZ_XUL
984 0 : ProcessFrameInsertions(mPopupItems, nsIFrame::kPopupList);
985 : #endif
986 0 : for (PRInt32 i = mGeneratedTextNodesWithInitializer.Count() - 1; i >= 0; --i) {
987 0 : mGeneratedTextNodesWithInitializer[i]->
988 0 : DeleteProperty(nsGkAtoms::genConInitializerProperty);
989 : }
990 0 : if (!PR_CLIST_IS_EMPTY(&mPendingBindings)) {
991 0 : nsBindingManager* bindingManager = mPresShell->GetDocument()->BindingManager();
992 0 : do {
993 : PendingBinding* pendingBinding =
994 0 : static_cast<PendingBinding*>(PR_NEXT_LINK(&mPendingBindings));
995 0 : PR_REMOVE_LINK(pendingBinding);
996 0 : bindingManager->AddToAttachedQueue(pendingBinding->mBinding);
997 0 : delete pendingBinding;
998 0 : } while (!PR_CLIST_IS_EMPTY(&mPendingBindings));
999 : }
1000 0 : }
1001 :
1002 : static nsIFrame*
1003 0 : AdjustAbsoluteContainingBlock(nsIFrame* aContainingBlockIn)
1004 : {
1005 0 : if (!aContainingBlockIn) {
1006 0 : return nsnull;
1007 : }
1008 :
1009 : // Always use the container's first continuation. (Inline frames can have
1010 : // non-fluid bidi continuations...)
1011 0 : return aContainingBlockIn->GetFirstContinuation();
1012 : }
1013 :
1014 : void
1015 0 : nsFrameConstructorState::PushAbsoluteContainingBlock(nsIFrame* aNewAbsoluteContainingBlock,
1016 : nsFrameConstructorSaveState& aSaveState)
1017 : {
1018 0 : aSaveState.mItems = &mAbsoluteItems;
1019 0 : aSaveState.mSavedItems = mAbsoluteItems;
1020 0 : aSaveState.mChildListID = nsIFrame::kAbsoluteList;
1021 0 : aSaveState.mState = this;
1022 :
1023 : /* Store whether we're wiring the abs-pos and fixed-pos lists together. */
1024 0 : aSaveState.mFixedPosIsAbsPos = &mFixedPosIsAbsPos;
1025 0 : aSaveState.mSavedFixedPosIsAbsPos = mFixedPosIsAbsPos;
1026 :
1027 : mAbsoluteItems =
1028 0 : nsAbsoluteItems(AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock));
1029 :
1030 : /* See if we're wiring the fixed-pos and abs-pos lists together. This happens iff
1031 : * we're a transformed element.
1032 : */
1033 : mFixedPosIsAbsPos = (aNewAbsoluteContainingBlock &&
1034 0 : aNewAbsoluteContainingBlock->GetStyleDisplay()->HasTransform());
1035 :
1036 0 : if (aNewAbsoluteContainingBlock) {
1037 0 : aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
1038 : }
1039 0 : }
1040 :
1041 : void
1042 0 : nsFrameConstructorState::PushFloatContainingBlock(nsIFrame* aNewFloatContainingBlock,
1043 : nsFrameConstructorSaveState& aSaveState)
1044 : {
1045 0 : NS_PRECONDITION(!aNewFloatContainingBlock ||
1046 : aNewFloatContainingBlock->IsFloatContainingBlock(),
1047 : "Please push a real float containing block!");
1048 0 : aSaveState.mItems = &mFloatedItems;
1049 0 : aSaveState.mSavedItems = mFloatedItems;
1050 0 : aSaveState.mChildListID = nsIFrame::kFloatList;
1051 0 : aSaveState.mState = this;
1052 0 : mFloatedItems = nsAbsoluteItems(aNewFloatContainingBlock);
1053 0 : }
1054 :
1055 : nsIFrame*
1056 0 : nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay* aStyleDisplay,
1057 : nsIFrame* aContentParentFrame)
1058 : {
1059 0 : NS_PRECONDITION(aStyleDisplay, "Must have display struct!");
1060 :
1061 : // If there is no container for a fixed, absolute, or floating root
1062 : // frame, we will ignore the positioning. This hack is originally
1063 : // brought to you by the letter T: tables, since other roots don't
1064 : // even call into this code. See bug 178855.
1065 : //
1066 : // XXX Disabling positioning in this case is a hack. If one was so inclined,
1067 : // one could support this either by (1) inserting a dummy block between the
1068 : // table and the canvas or (2) teaching the canvas how to reflow positioned
1069 : // elements. (1) has the usual problems when multiple frames share the same
1070 : // content (notice all the special cases in this file dealing with inner
1071 : // tables and outer tables which share the same content). (2) requires some
1072 : // work and possible factoring.
1073 : //
1074 : // XXXbz couldn't we just force position to "static" on roots and
1075 : // float to "none"? That's OK per CSS 2.1, as far as I can tell.
1076 :
1077 0 : if (aStyleDisplay->IsFloating() && mFloatedItems.containingBlock) {
1078 0 : NS_ASSERTION(!aStyleDisplay->IsAbsolutelyPositioned(),
1079 : "Absolutely positioned _and_ floating?");
1080 0 : return mFloatedItems.containingBlock;
1081 : }
1082 :
1083 0 : if (aStyleDisplay->mPosition == NS_STYLE_POSITION_ABSOLUTE &&
1084 : mAbsoluteItems.containingBlock) {
1085 0 : return mAbsoluteItems.containingBlock;
1086 : }
1087 :
1088 0 : if (aStyleDisplay->mPosition == NS_STYLE_POSITION_FIXED &&
1089 0 : GetFixedItems().containingBlock) {
1090 0 : return GetFixedItems().containingBlock;
1091 : }
1092 :
1093 0 : return aContentParentFrame;
1094 : }
1095 :
1096 : nsresult
1097 0 : nsFrameConstructorState::AddChild(nsIFrame* aNewFrame,
1098 : nsFrameItems& aFrameItems,
1099 : nsIContent* aContent,
1100 : nsStyleContext* aStyleContext,
1101 : nsIFrame* aParentFrame,
1102 : bool aCanBePositioned,
1103 : bool aCanBeFloated,
1104 : bool aIsOutOfFlowPopup,
1105 : bool aInsertAfter,
1106 : nsIFrame* aInsertAfterFrame)
1107 : {
1108 0 : NS_PRECONDITION(!aNewFrame->GetNextSibling(), "Shouldn't happen");
1109 :
1110 0 : const nsStyleDisplay* disp = aNewFrame->GetStyleDisplay();
1111 :
1112 : // The comments in GetGeometricParent regarding root table frames
1113 : // all apply here, unfortunately.
1114 :
1115 0 : bool needPlaceholder = false;
1116 : nsFrameState placeholderType;
1117 0 : nsFrameItems* frameItems = &aFrameItems;
1118 : #ifdef MOZ_XUL
1119 0 : if (NS_UNLIKELY(aIsOutOfFlowPopup)) {
1120 0 : NS_ASSERTION(aNewFrame->GetParent() == mPopupItems.containingBlock,
1121 : "Popup whose parent is not the popup containing block?");
1122 0 : NS_ASSERTION(mPopupItems.containingBlock, "Must have a popup set frame!");
1123 0 : needPlaceholder = true;
1124 0 : frameItems = &mPopupItems;
1125 0 : placeholderType = PLACEHOLDER_FOR_POPUP;
1126 : }
1127 : else
1128 : #endif // MOZ_XUL
1129 0 : if (aCanBeFloated && disp->IsFloating() &&
1130 : mFloatedItems.containingBlock) {
1131 0 : NS_ASSERTION(aNewFrame->GetParent() == mFloatedItems.containingBlock,
1132 : "Float whose parent is not the float containing block?");
1133 0 : needPlaceholder = true;
1134 0 : frameItems = &mFloatedItems;
1135 0 : placeholderType = PLACEHOLDER_FOR_FLOAT;
1136 : }
1137 0 : else if (aCanBePositioned) {
1138 0 : if (disp->mPosition == NS_STYLE_POSITION_ABSOLUTE &&
1139 : mAbsoluteItems.containingBlock) {
1140 0 : NS_ASSERTION(aNewFrame->GetParent() == mAbsoluteItems.containingBlock,
1141 : "Abs pos whose parent is not the abs pos containing block?");
1142 0 : needPlaceholder = true;
1143 0 : frameItems = &mAbsoluteItems;
1144 0 : placeholderType = PLACEHOLDER_FOR_ABSPOS;
1145 : }
1146 0 : if (disp->mPosition == NS_STYLE_POSITION_FIXED &&
1147 0 : GetFixedItems().containingBlock) {
1148 0 : NS_ASSERTION(aNewFrame->GetParent() == GetFixedItems().containingBlock,
1149 : "Fixed pos whose parent is not the fixed pos containing block?");
1150 0 : needPlaceholder = true;
1151 0 : frameItems = &GetFixedItems();
1152 0 : placeholderType = PLACEHOLDER_FOR_FIXEDPOS;
1153 : }
1154 : }
1155 :
1156 0 : if (needPlaceholder) {
1157 0 : NS_ASSERTION(frameItems != &aFrameItems,
1158 : "Putting frame in-flow _and_ want a placeholder?");
1159 : nsIFrame* placeholderFrame;
1160 : nsresult rv =
1161 : nsCSSFrameConstructor::CreatePlaceholderFrameFor(mPresShell,
1162 : aContent,
1163 : aNewFrame,
1164 : aStyleContext,
1165 : aParentFrame,
1166 : nsnull,
1167 : placeholderType,
1168 0 : &placeholderFrame);
1169 0 : if (NS_FAILED(rv)) {
1170 : // Note that aNewFrame could be the top frame for a scrollframe setup,
1171 : // hence already set as the primary frame. So we have to clean up here.
1172 : // But it shouldn't have any out-of-flow kids.
1173 : // XXXbz Maybe add a utility function to assert that?
1174 0 : aNewFrame->Destroy();
1175 0 : return rv;
1176 : }
1177 :
1178 0 : placeholderFrame->AddStateBits(mAdditionalStateBits);
1179 : // Add the placeholder frame to the flow
1180 0 : aFrameItems.AddChild(placeholderFrame);
1181 : }
1182 : #ifdef DEBUG
1183 : else {
1184 0 : NS_ASSERTION(aNewFrame->GetParent() == aParentFrame,
1185 : "In-flow frame has wrong parent");
1186 : }
1187 : #endif
1188 :
1189 0 : if (aInsertAfter) {
1190 0 : frameItems->InsertFrame(nsnull, aInsertAfterFrame, aNewFrame);
1191 : } else {
1192 0 : frameItems->AddChild(aNewFrame);
1193 : }
1194 :
1195 0 : return NS_OK;
1196 : }
1197 :
1198 : void
1199 0 : nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
1200 : ChildListID aChildListID)
1201 : {
1202 : #define NS_NONXUL_LIST_TEST (&aFrameItems == &mFloatedItems && \
1203 : aChildListID == nsIFrame::kFloatList) || \
1204 : (&aFrameItems == &mAbsoluteItems && \
1205 : aChildListID == nsIFrame::kAbsoluteList) || \
1206 : (&aFrameItems == &mFixedItems && \
1207 : aChildListID == nsIFrame::kFixedList)
1208 : #ifdef MOZ_XUL
1209 0 : NS_PRECONDITION(NS_NONXUL_LIST_TEST ||
1210 : (&aFrameItems == &mPopupItems &&
1211 : aChildListID == nsIFrame::kPopupList),
1212 : "Unexpected aFrameItems/aChildListID combination");
1213 : #else
1214 : NS_PRECONDITION(NS_NONXUL_LIST_TEST,
1215 : "Unexpected aFrameItems/aChildListID combination");
1216 : #endif
1217 :
1218 0 : if (aFrameItems.IsEmpty()) {
1219 0 : return;
1220 : }
1221 :
1222 0 : nsIFrame* containingBlock = aFrameItems.containingBlock;
1223 :
1224 0 : NS_ASSERTION(containingBlock,
1225 : "Child list without containing block?");
1226 :
1227 : // Insert the frames hanging out in aItems. We can use SetInitialChildList()
1228 : // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
1229 : // is set) and doesn't have any frames in the aChildListID child list yet.
1230 0 : const nsFrameList& childList = containingBlock->GetChildList(aChildListID);
1231 0 : nsresult rv = NS_OK;
1232 0 : if (childList.IsEmpty() &&
1233 0 : (containingBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1234 : // If we're injecting absolutely positioned frames, inject them on the
1235 : // absolute containing block
1236 0 : if (aChildListID == containingBlock->GetAbsoluteListID()) {
1237 : rv = containingBlock->GetAbsoluteContainingBlock()->
1238 0 : SetInitialChildList(containingBlock, aChildListID, aFrameItems);
1239 : } else {
1240 0 : rv = containingBlock->SetInitialChildList(aChildListID, aFrameItems);
1241 : }
1242 : } else {
1243 : // Note that whether the frame construction context is doing an append or
1244 : // not is not helpful here, since it could be appending to some frame in
1245 : // the middle of the document, which means we're not necessarily
1246 : // appending to the children of the containing block.
1247 : //
1248 : // We need to make sure the 'append to the end of document' case is fast.
1249 : // So first test the last child of the containing block
1250 0 : nsIFrame* lastChild = childList.LastChild();
1251 :
1252 : // CompareTreePosition uses placeholder hierarchy for out of flow frames,
1253 : // so this will make out-of-flows respect the ordering of placeholders,
1254 : // which is great because it takes care of anonymous content.
1255 0 : nsIFrame* firstNewFrame = aFrameItems.FirstChild();
1256 0 : if (!lastChild ||
1257 0 : nsLayoutUtils::CompareTreePosition(lastChild, firstNewFrame, containingBlock) < 0) {
1258 : // no lastChild, or lastChild comes before the new children, so just append
1259 0 : rv = mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
1260 : } else {
1261 : // try the other children
1262 0 : nsIFrame* insertionPoint = nsnull;
1263 0 : for (nsIFrame* f = childList.FirstChild(); f != lastChild;
1264 : f = f->GetNextSibling()) {
1265 : PRInt32 compare =
1266 0 : nsLayoutUtils::CompareTreePosition(f, firstNewFrame, containingBlock);
1267 0 : if (compare > 0) {
1268 : // f comes after the new children, so stop here and insert after
1269 : // the previous frame
1270 0 : break;
1271 : }
1272 0 : insertionPoint = f;
1273 : }
1274 : rv = mFrameManager->InsertFrames(containingBlock, aChildListID,
1275 0 : insertionPoint, aFrameItems);
1276 : }
1277 : }
1278 :
1279 0 : NS_POSTCONDITION(aFrameItems.IsEmpty(), "How did that happen?");
1280 :
1281 : // XXXbz And if NS_FAILED(rv), what? I guess we need to clean up the list
1282 : // and deal with all the placeholders... but what if the placeholders aren't
1283 : // in the document yet? Could that happen?
1284 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "Frames getting lost!");
1285 : }
1286 :
1287 :
1288 0 : nsFrameConstructorSaveState::nsFrameConstructorSaveState()
1289 : : mItems(nsnull),
1290 : mFixedPosIsAbsPos(nsnull),
1291 : mSavedItems(nsnull),
1292 : mSavedFixedPosIsAbsPos(false),
1293 : mChildListID(kPrincipalList),
1294 0 : mState(nsnull)
1295 : {
1296 0 : }
1297 :
1298 0 : nsFrameConstructorSaveState::~nsFrameConstructorSaveState()
1299 : {
1300 : // Restore the state
1301 0 : if (mItems) {
1302 0 : NS_ASSERTION(mState, "Can't have mItems set without having a state!");
1303 0 : mState->ProcessFrameInsertions(*mItems, mChildListID);
1304 0 : *mItems = mSavedItems;
1305 : #ifdef DEBUG
1306 : // We've transferred the child list, so drop the pointer we held to it.
1307 : // Note that this only matters for the assert in ~nsAbsoluteItems.
1308 0 : mSavedItems.Clear();
1309 : #endif
1310 : }
1311 0 : if (mFixedPosIsAbsPos) {
1312 0 : *mFixedPosIsAbsPos = mSavedFixedPosIsAbsPos;
1313 : }
1314 0 : }
1315 :
1316 : static
1317 0 : bool IsBorderCollapse(nsIFrame* aFrame)
1318 : {
1319 0 : for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
1320 0 : if (nsGkAtoms::tableFrame == frame->GetType()) {
1321 0 : return ((nsTableFrame*)frame)->IsBorderCollapse();
1322 : }
1323 : }
1324 0 : NS_ASSERTION(false, "program error");
1325 0 : return false;
1326 : }
1327 :
1328 : /**
1329 : * Moves aFrameList from aOldParent to aNewParent. This updates the parent
1330 : * pointer of the frames in the list, and reparents their views as needed.
1331 : * nsFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its
1332 : * ancestors as needed. Then it sets the list as the initial child list
1333 : * on aNewParent, unless aNewParent either already has kids or has been
1334 : * reflowed; in that case it appends the new frames. Note that this
1335 : * method differs from ReparentFrames in that it doesn't change the kids'
1336 : * style contexts.
1337 : */
1338 : // XXXbz Since this is only used for {ib} splits, could we just copy the view
1339 : // bits from aOldParent to aNewParent and then use the
1340 : // nsFrameList::ApplySetParent? That would still leave us doing two passes
1341 : // over the list, of course; if we really wanted to we could factor out the
1342 : // relevant part of ReparentFrameViewList, I suppose... Or just get rid of
1343 : // views, which would make most of this function go away.
1344 : static void
1345 0 : MoveChildrenTo(nsPresContext* aPresContext,
1346 : nsIFrame* aOldParent,
1347 : nsIFrame* aNewParent,
1348 : nsFrameList& aFrameList)
1349 : {
1350 0 : bool sameGrandParent = aOldParent->GetParent() == aNewParent->GetParent();
1351 :
1352 0 : if (aNewParent->HasView() || aOldParent->HasView() || !sameGrandParent) {
1353 : // Move the frames into the new view
1354 : nsContainerFrame::ReparentFrameViewList(aPresContext, aFrameList,
1355 0 : aOldParent, aNewParent);
1356 : }
1357 :
1358 0 : for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
1359 0 : e.get()->SetParent(aNewParent);
1360 : }
1361 :
1362 0 : if (aNewParent->PrincipalChildList().IsEmpty() &&
1363 0 : (aNewParent->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1364 0 : aNewParent->SetInitialChildList(kPrincipalList, aFrameList);
1365 : } else {
1366 0 : aNewParent->AppendFrames(kPrincipalList, aFrameList);
1367 : }
1368 0 : }
1369 :
1370 : //----------------------------------------------------------------------
1371 :
1372 0 : nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument *aDocument,
1373 : nsIPresShell *aPresShell)
1374 : : nsFrameManager(aPresShell)
1375 : , mDocument(aDocument)
1376 : , mRootElementFrame(nsnull)
1377 : , mRootElementStyleFrame(nsnull)
1378 : , mFixedContainingBlock(nsnull)
1379 : , mDocElementContainingBlock(nsnull)
1380 : , mGfxScrollFrame(nsnull)
1381 : , mPageSequenceFrame(nsnull)
1382 : , mUpdateCount(0)
1383 : , mQuotesDirty(false)
1384 : , mCountersDirty(false)
1385 : , mIsDestroyingFrameTree(false)
1386 : , mRebuildAllStyleData(false)
1387 : , mHasRootAbsPosContainingBlock(false)
1388 : , mObservingRefreshDriver(false)
1389 : , mInStyleRefresh(false)
1390 : , mHoverGeneration(0)
1391 : , mRebuildAllExtraHint(nsChangeHint(0))
1392 : , mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE |
1393 : ELEMENT_IS_POTENTIAL_RESTYLE_ROOT, this)
1394 : , mPendingAnimationRestyles(ELEMENT_HAS_PENDING_ANIMATION_RESTYLE |
1395 0 : ELEMENT_IS_POTENTIAL_ANIMATION_RESTYLE_ROOT, this)
1396 : {
1397 : // XXXbz this should be in Init() or something!
1398 0 : if (!mPendingRestyles.Init() || !mPendingAnimationRestyles.Init()) {
1399 : // now what?
1400 : }
1401 :
1402 : #ifdef DEBUG
1403 : static bool gFirstTime = true;
1404 0 : if (gFirstTime) {
1405 0 : gFirstTime = false;
1406 0 : char* flags = PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS");
1407 0 : if (flags) {
1408 0 : bool error = false;
1409 0 : for (;;) {
1410 0 : char* comma = PL_strchr(flags, ',');
1411 0 : if (comma)
1412 0 : *comma = '\0';
1413 :
1414 0 : bool found = false;
1415 0 : FrameCtorDebugFlags* flag = gFlags;
1416 0 : FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS;
1417 0 : while (flag < limit) {
1418 0 : if (PL_strcasecmp(flag->name, flags) == 0) {
1419 0 : *(flag->on) = true;
1420 0 : printf("nsCSSFrameConstructor: setting %s debug flag on\n", flag->name);
1421 0 : found = true;
1422 0 : break;
1423 : }
1424 0 : ++flag;
1425 : }
1426 :
1427 0 : if (! found)
1428 0 : error = true;
1429 :
1430 0 : if (! comma)
1431 : break;
1432 :
1433 0 : *comma = ',';
1434 0 : flags = comma + 1;
1435 : }
1436 :
1437 0 : if (error) {
1438 0 : printf("Here are the available GECKO_FRAMECTOR_DEBUG_FLAGS:\n");
1439 0 : FrameCtorDebugFlags* flag = gFlags;
1440 0 : FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS;
1441 0 : while (flag < limit) {
1442 0 : printf(" %s\n", flag->name);
1443 0 : ++flag;
1444 : }
1445 0 : printf("Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of flag\n");
1446 0 : printf("names (no whitespace)\n");
1447 : }
1448 : }
1449 : }
1450 : #endif
1451 0 : }
1452 :
1453 0 : nsIXBLService * nsCSSFrameConstructor::GetXBLService()
1454 : {
1455 0 : if (!gXBLService) {
1456 0 : nsresult rv = CallGetService("@mozilla.org/xbl;1", &gXBLService);
1457 0 : if (NS_FAILED(rv))
1458 0 : gXBLService = nsnull;
1459 : }
1460 :
1461 0 : return gXBLService;
1462 : }
1463 :
1464 : void
1465 0 : nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame)
1466 : {
1467 0 : NS_PRECONDITION(mUpdateCount != 0,
1468 : "Should be in an update while destroying frames");
1469 :
1470 0 : if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
1471 0 : if (mQuoteList.DestroyNodesFor(aFrame))
1472 0 : QuotesDirty();
1473 : }
1474 :
1475 0 : if (mCounterManager.DestroyNodesFor(aFrame)) {
1476 : // Technically we don't need to update anything if we destroyed only
1477 : // USE nodes. However, this is unlikely to happen in the real world
1478 : // since USE nodes generally go along with INCREMENT nodes.
1479 0 : CountersDirty();
1480 : }
1481 :
1482 0 : nsFrameManager::NotifyDestroyingFrame(aFrame);
1483 0 : }
1484 :
1485 0 : struct nsGenConInitializer {
1486 : nsAutoPtr<nsGenConNode> mNode;
1487 : nsGenConList* mList;
1488 : void (nsCSSFrameConstructor::*mDirtyAll)();
1489 :
1490 0 : nsGenConInitializer(nsGenConNode* aNode, nsGenConList* aList,
1491 : void (nsCSSFrameConstructor::*aDirtyAll)())
1492 0 : : mNode(aNode), mList(aList), mDirtyAll(aDirtyAll) {}
1493 : };
1494 :
1495 : static void
1496 0 : DestroyGenConInitializer(void* aFrame,
1497 : nsIAtom* aPropertyName,
1498 : void* aPropertyValue,
1499 : void* aDtorData)
1500 : {
1501 0 : delete static_cast<nsGenConInitializer*>(aPropertyValue);
1502 0 : }
1503 :
1504 : already_AddRefed<nsIContent>
1505 0 : nsCSSFrameConstructor::CreateGenConTextNode(nsFrameConstructorState& aState,
1506 : const nsString& aString,
1507 : nsCOMPtr<nsIDOMCharacterData>* aText,
1508 : nsGenConInitializer* aInitializer)
1509 : {
1510 0 : nsCOMPtr<nsIContent> content;
1511 0 : NS_NewTextNode(getter_AddRefs(content), mDocument->NodeInfoManager());
1512 0 : if (!content) {
1513 : // XXX The quotes/counters code doesn't like the text pointer
1514 : // being null in case of dynamic changes!
1515 0 : NS_ASSERTION(!aText, "this OOM case isn't handled very well");
1516 0 : return nsnull;
1517 : }
1518 0 : content->SetText(aString, false);
1519 0 : if (aText) {
1520 0 : *aText = do_QueryInterface(content);
1521 : }
1522 0 : if (aInitializer) {
1523 0 : content->SetProperty(nsGkAtoms::genConInitializerProperty, aInitializer,
1524 0 : DestroyGenConInitializer);
1525 0 : aState.mGeneratedTextNodesWithInitializer.AppendObject(content);
1526 : }
1527 0 : return content.forget();
1528 : }
1529 :
1530 : already_AddRefed<nsIContent>
1531 0 : nsCSSFrameConstructor::CreateGeneratedContent(nsFrameConstructorState& aState,
1532 : nsIContent* aParentContent,
1533 : nsStyleContext* aStyleContext,
1534 : PRUint32 aContentIndex)
1535 : {
1536 : // Get the content value
1537 : const nsStyleContentData &data =
1538 0 : aStyleContext->GetStyleContent()->ContentAt(aContentIndex);
1539 0 : nsStyleContentType type = data.mType;
1540 :
1541 0 : if (eStyleContentType_Image == type) {
1542 0 : if (!data.mContent.mImage) {
1543 : // CSS had something specified that couldn't be converted to an
1544 : // image object
1545 0 : return nsnull;
1546 : }
1547 :
1548 : // Create an image content object and pass it the image request.
1549 : // XXX Check if it's an image type we can handle...
1550 :
1551 0 : nsCOMPtr<nsINodeInfo> nodeInfo;
1552 : nodeInfo = mDocument->NodeInfoManager()->
1553 : GetNodeInfo(nsGkAtoms::mozgeneratedcontentimage, nsnull,
1554 0 : kNameSpaceID_XHTML, nsIDOMNode::ELEMENT_NODE);
1555 :
1556 0 : nsCOMPtr<nsIContent> content;
1557 0 : NS_NewGenConImageContent(getter_AddRefs(content), nodeInfo.forget(),
1558 0 : data.mContent.mImage);
1559 0 : return content.forget();
1560 : }
1561 :
1562 0 : switch (type) {
1563 : case eStyleContentType_String:
1564 : return CreateGenConTextNode(aState,
1565 0 : nsDependentString(data.mContent.mString),
1566 0 : nsnull, nsnull);
1567 :
1568 : case eStyleContentType_Attr:
1569 : {
1570 0 : nsCOMPtr<nsIAtom> attrName;
1571 0 : PRInt32 attrNameSpace = kNameSpaceID_None;
1572 0 : nsAutoString contentString(data.mContent.mString);
1573 :
1574 0 : PRInt32 barIndex = contentString.FindChar('|'); // CSS namespace delimiter
1575 0 : if (-1 != barIndex) {
1576 0 : nsAutoString nameSpaceVal;
1577 0 : contentString.Left(nameSpaceVal, barIndex);
1578 : PRInt32 error;
1579 0 : attrNameSpace = nameSpaceVal.ToInteger(&error, 10);
1580 0 : contentString.Cut(0, barIndex + 1);
1581 0 : if (contentString.Length()) {
1582 0 : if (mDocument->IsHTML() && aParentContent->IsHTML()) {
1583 0 : ToLowerCase(contentString);
1584 : }
1585 0 : attrName = do_GetAtom(contentString);
1586 : }
1587 : }
1588 : else {
1589 0 : if (mDocument->IsHTML() && aParentContent->IsHTML()) {
1590 0 : ToLowerCase(contentString);
1591 : }
1592 0 : attrName = do_GetAtom(contentString);
1593 : }
1594 :
1595 0 : if (!attrName) {
1596 0 : return nsnull;
1597 : }
1598 :
1599 0 : nsCOMPtr<nsIContent> content;
1600 : NS_NewAttributeContent(mDocument->NodeInfoManager(),
1601 0 : attrNameSpace, attrName, getter_AddRefs(content));
1602 0 : return content.forget();
1603 : }
1604 :
1605 : case eStyleContentType_Counter:
1606 : case eStyleContentType_Counters:
1607 : {
1608 0 : nsCSSValue::Array* counters = data.mContent.mCounters;
1609 : nsCounterList* counterList = mCounterManager.CounterListFor(
1610 0 : nsDependentString(counters->Item(0).GetStringBufferValue()));
1611 0 : if (!counterList)
1612 0 : return nsnull;
1613 :
1614 : nsCounterUseNode* node =
1615 : new nsCounterUseNode(counters, aContentIndex,
1616 0 : type == eStyleContentType_Counters);
1617 :
1618 : nsGenConInitializer* initializer =
1619 : new nsGenConInitializer(node, counterList,
1620 0 : &nsCSSFrameConstructor::CountersDirty);
1621 0 : return CreateGenConTextNode(aState, EmptyString(), &node->mText,
1622 0 : initializer);
1623 : }
1624 :
1625 : case eStyleContentType_Image:
1626 0 : NS_NOTREACHED("handled by if above");
1627 0 : return nsnull;
1628 :
1629 : case eStyleContentType_OpenQuote:
1630 : case eStyleContentType_CloseQuote:
1631 : case eStyleContentType_NoOpenQuote:
1632 : case eStyleContentType_NoCloseQuote:
1633 : {
1634 : nsQuoteNode* node =
1635 0 : new nsQuoteNode(type, aContentIndex);
1636 :
1637 : nsGenConInitializer* initializer =
1638 : new nsGenConInitializer(node, &mQuoteList,
1639 0 : &nsCSSFrameConstructor::QuotesDirty);
1640 0 : return CreateGenConTextNode(aState, EmptyString(), &node->mText,
1641 0 : initializer);
1642 : }
1643 :
1644 : case eStyleContentType_AltContent:
1645 : {
1646 : // Use the "alt" attribute; if that fails and the node is an HTML
1647 : // <input>, try the value attribute and then fall back to some default
1648 : // localized text we have.
1649 : // XXX what if the 'alt' attribute is added later, how will we
1650 : // detect that and do the right thing here?
1651 0 : if (aParentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::alt)) {
1652 0 : nsCOMPtr<nsIContent> content;
1653 : NS_NewAttributeContent(mDocument->NodeInfoManager(),
1654 0 : kNameSpaceID_None, nsGkAtoms::alt, getter_AddRefs(content));
1655 0 : return content.forget();
1656 : }
1657 :
1658 0 : if (aParentContent->IsHTML() &&
1659 0 : aParentContent->NodeInfo()->Equals(nsGkAtoms::input)) {
1660 0 : if (aParentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
1661 0 : nsCOMPtr<nsIContent> content;
1662 : NS_NewAttributeContent(mDocument->NodeInfoManager(),
1663 0 : kNameSpaceID_None, nsGkAtoms::value, getter_AddRefs(content));
1664 0 : return content.forget();
1665 : }
1666 :
1667 0 : nsXPIDLString temp;
1668 : nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
1669 0 : "Submit", temp);
1670 0 : return CreateGenConTextNode(aState, temp, nsnull, nsnull);
1671 : }
1672 :
1673 0 : break;
1674 : }
1675 : } // switch
1676 :
1677 0 : return nsnull;
1678 : }
1679 :
1680 : /*
1681 : * aParentFrame - the frame that should be the parent of the generated
1682 : * content. This is the frame for the corresponding content node,
1683 : * which must not be a leaf frame.
1684 : *
1685 : * Any items created are added to aItems.
1686 : *
1687 : * We create an XML element (tag _moz_generated_content_before or
1688 : * _moz_generated_content_after) representing the pseudoelement. We
1689 : * create a DOM node for each 'content' item and make those nodes the
1690 : * children of the XML element. Then we create a frame subtree for
1691 : * the XML element as if it were a regular child of
1692 : * aParentFrame/aParentContent, giving the XML element the ::before or
1693 : * ::after style.
1694 : */
1695 : void
1696 0 : nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aState,
1697 : nsIFrame* aParentFrame,
1698 : nsIContent* aParentContent,
1699 : nsStyleContext* aStyleContext,
1700 : nsCSSPseudoElements::Type aPseudoElement,
1701 : FrameConstructionItemList& aItems)
1702 : {
1703 : // XXXbz is this ever true?
1704 0 : if (!aParentContent->IsElement()) {
1705 0 : NS_ERROR("Bogus generated content parent");
1706 0 : return;
1707 : }
1708 :
1709 0 : nsStyleSet *styleSet = mPresShell->StyleSet();
1710 :
1711 : // Probe for the existence of the pseudo-element
1712 0 : nsRefPtr<nsStyleContext> pseudoStyleContext;
1713 : pseudoStyleContext =
1714 : styleSet->ProbePseudoElementStyle(aParentContent->AsElement(),
1715 : aPseudoElement,
1716 : aStyleContext,
1717 0 : aState.mTreeMatchContext);
1718 0 : if (!pseudoStyleContext)
1719 : return;
1720 : // |ProbePseudoStyleFor| checked the 'display' property and the
1721 : // |ContentCount()| of the 'content' property for us.
1722 0 : nsCOMPtr<nsINodeInfo> nodeInfo;
1723 : nsIAtom* elemName = aPseudoElement == nsCSSPseudoElements::ePseudo_before ?
1724 0 : nsGkAtoms::mozgeneratedcontentbefore : nsGkAtoms::mozgeneratedcontentafter;
1725 : nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(elemName, nsnull,
1726 : kNameSpaceID_None,
1727 0 : nsIDOMNode::ELEMENT_NODE);
1728 0 : nsCOMPtr<nsIContent> container;
1729 0 : nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
1730 0 : if (NS_FAILED(rv))
1731 : return;
1732 0 : container->SetNativeAnonymous();
1733 :
1734 0 : rv = container->BindToTree(mDocument, aParentContent, aParentContent, true);
1735 0 : if (NS_FAILED(rv)) {
1736 0 : container->UnbindFromTree();
1737 : return;
1738 : }
1739 :
1740 0 : PRUint32 contentCount = pseudoStyleContext->GetStyleContent()->ContentCount();
1741 0 : for (PRUint32 contentIndex = 0; contentIndex < contentCount; contentIndex++) {
1742 : nsCOMPtr<nsIContent> content =
1743 : CreateGeneratedContent(aState, aParentContent, pseudoStyleContext,
1744 0 : contentIndex);
1745 0 : if (content) {
1746 0 : container->AppendChildTo(content, false);
1747 : }
1748 : }
1749 :
1750 : AddFrameConstructionItemsInternal(aState, container, aParentFrame, elemName,
1751 : kNameSpaceID_None, true,
1752 : pseudoStyleContext,
1753 0 : ITEM_IS_GENERATED_CONTENT, aItems);
1754 : }
1755 :
1756 : /****************************************************
1757 : ** BEGIN TABLE SECTION
1758 : ****************************************************/
1759 :
1760 : // The term pseudo frame is being used instead of anonymous frame, since anonymous
1761 : // frame has been used elsewhere to refer to frames that have generated content
1762 :
1763 : // Return whether the given frame is a table pseudo-frame. Note that
1764 : // cell-content and table-outer frames have pseudo-types, but are always
1765 : // created, even for non-anonymous cells and tables respectively. So for those
1766 : // we have to examine the cell or table frame to see whether it's a pseudo
1767 : // frame. In particular, a lone table caption will have an outer table as its
1768 : // parent, but will also trigger construction of an empty inner table, which
1769 : // will be the one we can examine to see whether the outer was a pseudo-frame.
1770 : static bool
1771 0 : IsTablePseudo(nsIFrame* aFrame)
1772 : {
1773 0 : nsIAtom* pseudoType = aFrame->GetStyleContext()->GetPseudo();
1774 : return pseudoType &&
1775 : (pseudoType == nsCSSAnonBoxes::table ||
1776 : pseudoType == nsCSSAnonBoxes::inlineTable ||
1777 : pseudoType == nsCSSAnonBoxes::tableColGroup ||
1778 : pseudoType == nsCSSAnonBoxes::tableRowGroup ||
1779 : pseudoType == nsCSSAnonBoxes::tableRow ||
1780 : pseudoType == nsCSSAnonBoxes::tableCell ||
1781 : (pseudoType == nsCSSAnonBoxes::cellContent &&
1782 0 : aFrame->GetParent()->GetStyleContext()->GetPseudo() ==
1783 : nsCSSAnonBoxes::tableCell) ||
1784 : (pseudoType == nsCSSAnonBoxes::tableOuter &&
1785 0 : (aFrame->GetFirstPrincipalChild()->GetStyleContext()->GetPseudo() ==
1786 : nsCSSAnonBoxes::table ||
1787 0 : aFrame->GetFirstPrincipalChild()->GetStyleContext()->GetPseudo() ==
1788 0 : nsCSSAnonBoxes::inlineTable)));
1789 : }
1790 :
1791 : /* static */
1792 : nsCSSFrameConstructor::ParentType
1793 0 : nsCSSFrameConstructor::GetParentType(nsIAtom* aFrameType)
1794 : {
1795 0 : if (aFrameType == nsGkAtoms::tableFrame) {
1796 0 : return eTypeTable;
1797 : }
1798 0 : if (aFrameType == nsGkAtoms::tableRowGroupFrame) {
1799 0 : return eTypeRowGroup;
1800 : }
1801 0 : if (aFrameType == nsGkAtoms::tableRowFrame) {
1802 0 : return eTypeRow;
1803 : }
1804 0 : if (aFrameType == nsGkAtoms::tableColGroupFrame) {
1805 0 : return eTypeColGroup;
1806 : }
1807 :
1808 0 : return eTypeBlock;
1809 : }
1810 :
1811 : static nsIFrame*
1812 0 : AdjustCaptionParentFrame(nsIFrame* aParentFrame)
1813 : {
1814 0 : if (nsGkAtoms::tableFrame == aParentFrame->GetType()) {
1815 0 : return aParentFrame->GetParent();;
1816 : }
1817 0 : return aParentFrame;
1818 : }
1819 :
1820 : /**
1821 : * If the parent frame is a |tableFrame| and the child is a
1822 : * |captionFrame|, then we want to insert the frames beneath the
1823 : * |tableFrame|'s parent frame. Returns |true| if the parent frame
1824 : * needed to be fixed up.
1825 : */
1826 : static bool
1827 0 : GetCaptionAdjustedParent(nsIFrame* aParentFrame,
1828 : const nsIFrame* aChildFrame,
1829 : nsIFrame** aAdjParentFrame)
1830 : {
1831 0 : *aAdjParentFrame = aParentFrame;
1832 0 : bool haveCaption = false;
1833 :
1834 0 : if (nsGkAtoms::tableCaptionFrame == aChildFrame->GetType()) {
1835 0 : haveCaption = true;
1836 0 : *aAdjParentFrame = AdjustCaptionParentFrame(aParentFrame);
1837 : }
1838 0 : return haveCaption;
1839 : }
1840 :
1841 : void
1842 0 : nsCSSFrameConstructor::AdjustParentFrame(nsIFrame* & aParentFrame,
1843 : const FrameConstructionData* aFCData,
1844 : nsStyleContext* aStyleContext)
1845 : {
1846 0 : NS_PRECONDITION(aStyleContext, "Must have child's style context");
1847 0 : NS_PRECONDITION(aFCData, "Must have frame construction data");
1848 :
1849 0 : bool tablePart = ((aFCData->mBits & FCDATA_IS_TABLE_PART) != 0);
1850 :
1851 0 : if (tablePart && aStyleContext->GetStyleDisplay()->mDisplay ==
1852 : NS_STYLE_DISPLAY_TABLE_CAPTION) {
1853 0 : aParentFrame = AdjustCaptionParentFrame(aParentFrame);
1854 : }
1855 0 : }
1856 :
1857 : // Pull all the captions present in aItems out into aCaptions
1858 : static void
1859 0 : PullOutCaptionFrames(nsFrameItems& aItems, nsFrameItems& aCaptions)
1860 : {
1861 0 : nsIFrame *child = aItems.FirstChild();
1862 0 : while (child) {
1863 0 : nsIFrame *nextSibling = child->GetNextSibling();
1864 0 : if (nsGkAtoms::tableCaptionFrame == child->GetType()) {
1865 0 : aItems.RemoveFrame(child);
1866 0 : aCaptions.AddChild(child);
1867 : }
1868 0 : child = nextSibling;
1869 : }
1870 0 : }
1871 :
1872 :
1873 : // Construct the outer, inner table frames and the children frames for the table.
1874 : // XXX Page break frames for pseudo table frames are not constructed to avoid the risk
1875 : // associated with revising the pseudo frame mechanism. The long term solution
1876 : // of having frames handle page-break-before/after will solve the problem.
1877 : nsresult
1878 0 : nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState,
1879 : FrameConstructionItem& aItem,
1880 : nsIFrame* aParentFrame,
1881 : const nsStyleDisplay* aDisplay,
1882 : nsFrameItems& aFrameItems,
1883 : nsIFrame** aNewFrame)
1884 : {
1885 0 : NS_PRECONDITION(aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE ||
1886 : aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_TABLE,
1887 : "Unexpected call");
1888 :
1889 0 : nsIContent* const content = aItem.mContent;
1890 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
1891 0 : const PRUint32 nameSpaceID = aItem.mNameSpaceID;
1892 :
1893 0 : nsresult rv = NS_OK;
1894 :
1895 : // create the pseudo SC for the outer table as a child of the inner SC
1896 0 : nsRefPtr<nsStyleContext> outerStyleContext;
1897 : outerStyleContext = mPresShell->StyleSet()->
1898 0 : ResolveAnonymousBoxStyle(nsCSSAnonBoxes::tableOuter, styleContext);
1899 :
1900 : // Create the outer table frame which holds the caption and inner table frame
1901 : nsIFrame* newFrame;
1902 0 : if (kNameSpaceID_MathML == nameSpaceID)
1903 0 : newFrame = NS_NewMathMLmtableOuterFrame(mPresShell, outerStyleContext);
1904 : else
1905 0 : newFrame = NS_NewTableOuterFrame(mPresShell, outerStyleContext);
1906 :
1907 : nsIFrame* geometricParent =
1908 : aState.GetGeometricParent(outerStyleContext->GetStyleDisplay(),
1909 0 : aParentFrame);
1910 :
1911 : // Init the table outer frame
1912 0 : InitAndRestoreFrame(aState, content, geometricParent, nsnull, newFrame);
1913 :
1914 : // Create the inner table frame
1915 : nsIFrame* innerFrame;
1916 0 : if (kNameSpaceID_MathML == nameSpaceID)
1917 0 : innerFrame = NS_NewMathMLmtableFrame(mPresShell, styleContext);
1918 : else
1919 0 : innerFrame = NS_NewTableFrame(mPresShell, styleContext);
1920 :
1921 0 : if (!innerFrame) {
1922 0 : newFrame->Destroy();
1923 0 : return NS_ERROR_OUT_OF_MEMORY;
1924 : }
1925 :
1926 0 : InitAndRestoreFrame(aState, content, newFrame, nsnull, innerFrame);
1927 :
1928 : // Put the newly created frames into the right child list
1929 0 : SetInitialSingleChild(newFrame, innerFrame);
1930 :
1931 : rv = aState.AddChild(newFrame, aFrameItems, content, styleContext,
1932 0 : aParentFrame);
1933 0 : if (NS_FAILED(rv)) {
1934 0 : return rv;
1935 : }
1936 :
1937 0 : if (!mRootElementFrame) {
1938 : // The frame we're constructing will be the root element frame.
1939 : // Set mRootElementFrame before processing children.
1940 0 : mRootElementFrame = newFrame;
1941 : }
1942 :
1943 0 : nsFrameItems childItems;
1944 :
1945 : // Process children
1946 0 : nsFrameConstructorSaveState absoluteSaveState;
1947 0 : const nsStyleDisplay* display = outerStyleContext->GetStyleDisplay();
1948 :
1949 : // Mark the table frame as an absolute container if needed
1950 0 : if (display->IsPositioned()) {
1951 0 : aState.PushAbsoluteContainingBlock(newFrame, absoluteSaveState);
1952 : }
1953 0 : if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
1954 : rv = ConstructFramesFromItemList(aState, aItem.mChildItems,
1955 0 : innerFrame, childItems);
1956 : } else {
1957 : rv = ProcessChildren(aState, content, styleContext, innerFrame,
1958 0 : true, childItems, false, aItem.mPendingBinding);
1959 : }
1960 : // XXXbz what about cleaning up?
1961 0 : if (NS_FAILED(rv)) return rv;
1962 :
1963 0 : nsFrameItems captionItems;
1964 0 : PullOutCaptionFrames(childItems, captionItems);
1965 :
1966 : // Set the inner table frame's initial primary list
1967 0 : innerFrame->SetInitialChildList(kPrincipalList, childItems);
1968 :
1969 : // Set the outer table frame's secondary childlist lists
1970 0 : if (captionItems.NotEmpty()) {
1971 0 : newFrame->SetInitialChildList(nsIFrame::kCaptionList, captionItems);
1972 : }
1973 :
1974 0 : *aNewFrame = newFrame;
1975 0 : return rv;
1976 : }
1977 :
1978 : nsresult
1979 0 : nsCSSFrameConstructor::ConstructTableRow(nsFrameConstructorState& aState,
1980 : FrameConstructionItem& aItem,
1981 : nsIFrame* aParentFrame,
1982 : const nsStyleDisplay* aDisplay,
1983 : nsFrameItems& aFrameItems,
1984 : nsIFrame** aNewFrame)
1985 : {
1986 0 : NS_PRECONDITION(aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_ROW,
1987 : "Unexpected call");
1988 0 : nsIContent* const content = aItem.mContent;
1989 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
1990 0 : const PRUint32 nameSpaceID = aItem.mNameSpaceID;
1991 :
1992 : nsIFrame* newFrame;
1993 0 : if (kNameSpaceID_MathML == nameSpaceID)
1994 0 : newFrame = NS_NewMathMLmtrFrame(mPresShell, styleContext);
1995 : else
1996 0 : newFrame = NS_NewTableRowFrame(mPresShell, styleContext);
1997 :
1998 0 : if (NS_UNLIKELY(!newFrame)) {
1999 0 : return NS_ERROR_OUT_OF_MEMORY;
2000 : }
2001 0 : InitAndRestoreFrame(aState, content, aParentFrame, nsnull, newFrame);
2002 :
2003 0 : nsFrameItems childItems;
2004 : nsresult rv;
2005 0 : if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2006 : rv = ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
2007 0 : childItems);
2008 : } else {
2009 : rv = ProcessChildren(aState, content, styleContext, newFrame,
2010 0 : true, childItems, false, aItem.mPendingBinding);
2011 : }
2012 0 : if (NS_FAILED(rv)) return rv;
2013 :
2014 0 : newFrame->SetInitialChildList(kPrincipalList, childItems);
2015 0 : aFrameItems.AddChild(newFrame);
2016 0 : *aNewFrame = newFrame;
2017 :
2018 0 : return NS_OK;
2019 : }
2020 :
2021 : nsresult
2022 0 : nsCSSFrameConstructor::ConstructTableCol(nsFrameConstructorState& aState,
2023 : FrameConstructionItem& aItem,
2024 : nsIFrame* aParentFrame,
2025 : const nsStyleDisplay* aStyleDisplay,
2026 : nsFrameItems& aFrameItems,
2027 : nsIFrame** aNewFrame)
2028 : {
2029 0 : nsIContent* const content = aItem.mContent;
2030 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
2031 :
2032 0 : nsTableColFrame* colFrame = NS_NewTableColFrame(mPresShell, styleContext);
2033 0 : if (NS_UNLIKELY(!colFrame)) {
2034 0 : return NS_ERROR_OUT_OF_MEMORY;
2035 : }
2036 0 : InitAndRestoreFrame(aState, content, aParentFrame, nsnull, colFrame);
2037 :
2038 0 : NS_ASSERTION(colFrame->GetStyleContext() == styleContext,
2039 : "Unexpected style context");
2040 :
2041 0 : aFrameItems.AddChild(colFrame);
2042 0 : *aNewFrame = colFrame;
2043 :
2044 : // construct additional col frames if the col frame has a span > 1
2045 0 : PRInt32 span = colFrame->GetSpan();
2046 0 : for (PRInt32 spanX = 1; spanX < span; spanX++) {
2047 0 : nsTableColFrame* newCol = NS_NewTableColFrame(mPresShell, styleContext);
2048 0 : if (NS_UNLIKELY(!newCol)) {
2049 0 : return NS_ERROR_OUT_OF_MEMORY;
2050 : }
2051 : InitAndRestoreFrame(aState, content, aParentFrame, nsnull, newCol,
2052 0 : false);
2053 0 : aFrameItems.LastChild()->SetNextContinuation(newCol);
2054 0 : newCol->SetPrevContinuation(aFrameItems.LastChild());
2055 0 : aFrameItems.AddChild(newCol);
2056 0 : newCol->SetColType(eColAnonymousCol);
2057 : }
2058 :
2059 0 : return NS_OK;
2060 : }
2061 :
2062 : nsresult
2063 0 : nsCSSFrameConstructor::ConstructTableCell(nsFrameConstructorState& aState,
2064 : FrameConstructionItem& aItem,
2065 : nsIFrame* aParentFrame,
2066 : const nsStyleDisplay* aDisplay,
2067 : nsFrameItems& aFrameItems,
2068 : nsIFrame** aNewFrame)
2069 : {
2070 0 : NS_PRECONDITION(aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL,
2071 : "Unexpected call");
2072 :
2073 0 : nsIContent* const content = aItem.mContent;
2074 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
2075 0 : const PRUint32 nameSpaceID = aItem.mNameSpaceID;
2076 :
2077 0 : bool borderCollapse = IsBorderCollapse(aParentFrame);
2078 : nsIFrame* newFrame;
2079 : // <mtable> is border separate in mathml.css and the MathML code doesn't implement
2080 : // border collapse. For those users who style <mtable> with border collapse,
2081 : // give them the default non-MathML table frames that understand border collapse.
2082 : // This won't break us because MathML table frames are all subclasses of the default
2083 : // table code, and so we can freely mix <mtable> with <mtr> or <tr>, <mtd> or <td>.
2084 : // What will happen is just that non-MathML frames won't understand MathML attributes
2085 : // and will therefore miss the special handling that the MathML code does.
2086 0 : if (kNameSpaceID_MathML == nameSpaceID && !borderCollapse)
2087 0 : newFrame = NS_NewMathMLmtdFrame(mPresShell, styleContext);
2088 : else
2089 : // Warning: If you change this and add a wrapper frame around table cell
2090 : // frames, make sure Bug 368554 doesn't regress!
2091 : // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
2092 0 : newFrame = NS_NewTableCellFrame(mPresShell, styleContext, borderCollapse);
2093 :
2094 0 : if (NS_UNLIKELY(!newFrame)) {
2095 0 : return NS_ERROR_OUT_OF_MEMORY;
2096 : }
2097 :
2098 : // Initialize the table cell frame
2099 0 : InitAndRestoreFrame(aState, content, aParentFrame, nsnull, newFrame);
2100 :
2101 : // Resolve pseudo style and initialize the body cell frame
2102 0 : nsRefPtr<nsStyleContext> innerPseudoStyle;
2103 : innerPseudoStyle = mPresShell->StyleSet()->
2104 0 : ResolveAnonymousBoxStyle(nsCSSAnonBoxes::cellContent, styleContext);
2105 :
2106 : // Create a block frame that will format the cell's content
2107 : bool isBlock;
2108 : nsIFrame* cellInnerFrame;
2109 0 : if (kNameSpaceID_MathML == nameSpaceID) {
2110 0 : cellInnerFrame = NS_NewMathMLmtdInnerFrame(mPresShell, innerPseudoStyle);
2111 0 : isBlock = false;
2112 : } else {
2113 0 : cellInnerFrame = NS_NewBlockFormattingContext(mPresShell, innerPseudoStyle);
2114 0 : isBlock = true;
2115 : }
2116 :
2117 0 : if (NS_UNLIKELY(!cellInnerFrame)) {
2118 0 : newFrame->Destroy();
2119 0 : return NS_ERROR_OUT_OF_MEMORY;
2120 : }
2121 :
2122 0 : InitAndRestoreFrame(aState, content, newFrame, nsnull, cellInnerFrame);
2123 :
2124 0 : nsFrameItems childItems;
2125 : nsresult rv;
2126 0 : if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
2127 : // Need to push ourselves as a float containing block.
2128 : // XXXbz it might be nice to work on getting the parent
2129 : // FrameConstructionItem down into ProcessChildren and just making use of
2130 : // the push there, but that's a bit of work.
2131 0 : nsFrameConstructorSaveState floatSaveState;
2132 0 : if (!isBlock) { /* MathML case */
2133 0 : aState.PushFloatContainingBlock(nsnull, floatSaveState);
2134 : } else {
2135 0 : aState.PushFloatContainingBlock(cellInnerFrame, floatSaveState);
2136 : }
2137 :
2138 : rv = ConstructFramesFromItemList(aState, aItem.mChildItems, cellInnerFrame,
2139 0 : childItems);
2140 : } else {
2141 : // Process the child content
2142 : rv = ProcessChildren(aState, content, styleContext, cellInnerFrame,
2143 0 : true, childItems, isBlock, aItem.mPendingBinding);
2144 : }
2145 :
2146 0 : if (NS_FAILED(rv)) {
2147 : // Clean up
2148 : // XXXbz kids of this stuff need to be cleaned up too!
2149 0 : cellInnerFrame->Destroy();
2150 0 : newFrame->Destroy();
2151 0 : return rv;
2152 : }
2153 :
2154 0 : cellInnerFrame->SetInitialChildList(kPrincipalList, childItems);
2155 0 : SetInitialSingleChild(newFrame, cellInnerFrame);
2156 0 : aFrameItems.AddChild(newFrame);
2157 0 : *aNewFrame = newFrame;
2158 :
2159 0 : return NS_OK;
2160 : }
2161 :
2162 : static inline bool
2163 0 : NeedFrameFor(const nsFrameConstructorState& aState,
2164 : nsIFrame* aParentFrame,
2165 : nsIContent* aChildContent)
2166 : {
2167 : // XXX the GetContent() != aChildContent check is needed due to bug 135040.
2168 : // Remove it once that's fixed.
2169 0 : NS_PRECONDITION(!aChildContent->GetPrimaryFrame() ||
2170 : aState.mCreatingExtraFrames ||
2171 : aChildContent->GetPrimaryFrame()->GetContent() != aChildContent,
2172 : "Why did we get called?");
2173 :
2174 : // don't create a whitespace frame if aParentFrame doesn't want it.
2175 : // always create frames for children in generated content. counter(),
2176 : // quotes, and attr() content can easily change dynamically and we don't
2177 : // want to be reconstructing frames. It's not even clear that these
2178 : // should be considered ignorable just because they evaluate to
2179 : // whitespace.
2180 :
2181 : // We could handle all this in CreateNeededTablePseudos or some other place
2182 : // after we build our frame construction items, but that would involve
2183 : // creating frame construction items for whitespace kids of
2184 : // eExcludesIgnorableWhitespace frames, where we know we'll be dropping them
2185 : // all anyway, and involve an extra walk down the frame construction item
2186 : // list.
2187 0 : if (!aParentFrame->IsFrameOfType(nsIFrame::eExcludesIgnorableWhitespace) ||
2188 0 : aParentFrame->IsGeneratedContentFrame() ||
2189 0 : !aChildContent->IsNodeOfType(nsINode::eTEXT)) {
2190 0 : return true;
2191 : }
2192 :
2193 : aChildContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
2194 0 : NS_REFRAME_IF_WHITESPACE);
2195 0 : return !aChildContent->TextIsOnlyWhitespace();
2196 : }
2197 :
2198 : /***********************************************
2199 : * END TABLE SECTION
2200 : ***********************************************/
2201 :
2202 0 : static bool CheckOverflow(nsPresContext* aPresContext,
2203 : const nsStyleDisplay* aDisplay)
2204 : {
2205 0 : if (aDisplay->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
2206 0 : return false;
2207 :
2208 0 : if (aDisplay->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
2209 : aPresContext->SetViewportOverflowOverride(NS_STYLE_OVERFLOW_HIDDEN,
2210 0 : NS_STYLE_OVERFLOW_HIDDEN);
2211 : else
2212 : aPresContext->SetViewportOverflowOverride(aDisplay->mOverflowX,
2213 0 : aDisplay->mOverflowY);
2214 0 : return true;
2215 : }
2216 :
2217 : /**
2218 : * This checks the root element and the HTML BODY, if any, for an "overflow" property
2219 : * that should be applied to the viewport. If one is found then we return the
2220 : * element that we took the overflow from (which should then be treated as
2221 : * "overflow:visible"), and we store the overflow style in the prescontext.
2222 : * @return if scroll was propagated from some content node, the content node it
2223 : * was propagated from.
2224 : */
2225 : nsIContent*
2226 0 : nsCSSFrameConstructor::PropagateScrollToViewport()
2227 : {
2228 : // Set default
2229 0 : nsPresContext* presContext = mPresShell->GetPresContext();
2230 : presContext->SetViewportOverflowOverride(NS_STYLE_OVERFLOW_AUTO,
2231 0 : NS_STYLE_OVERFLOW_AUTO);
2232 :
2233 : // We never mess with the viewport scroll state
2234 : // when printing or in print preview
2235 0 : if (presContext->IsPaginated()) {
2236 0 : return nsnull;
2237 : }
2238 :
2239 0 : Element* docElement = mDocument->GetRootElement();
2240 :
2241 : // Check the style on the document root element
2242 0 : nsStyleSet *styleSet = mPresShell->StyleSet();
2243 0 : nsRefPtr<nsStyleContext> rootStyle;
2244 0 : rootStyle = styleSet->ResolveStyleFor(docElement, nsnull);
2245 0 : if (!rootStyle) {
2246 0 : return nsnull;
2247 : }
2248 0 : if (CheckOverflow(presContext, rootStyle->GetStyleDisplay())) {
2249 : // tell caller we stole the overflow style from the root element
2250 0 : return docElement;
2251 : }
2252 :
2253 : // Don't look in the BODY for non-HTML documents or HTML documents
2254 : // with non-HTML roots
2255 : // XXX this should be earlier; we shouldn't even look at the document root
2256 : // for non-HTML documents. Fix this once we support explicit CSS styling
2257 : // of the viewport
2258 : // XXX what about XHTML?
2259 0 : nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
2260 0 : if (!htmlDoc || !docElement->IsHTML()) {
2261 0 : return nsnull;
2262 : }
2263 :
2264 0 : nsCOMPtr<nsIDOMHTMLElement> body;
2265 0 : htmlDoc->GetBody(getter_AddRefs(body));
2266 0 : nsCOMPtr<nsIContent> bodyElement = do_QueryInterface(body);
2267 :
2268 0 : if (!bodyElement ||
2269 0 : !bodyElement->NodeInfo()->Equals(nsGkAtoms::body)) {
2270 : // The body is not a <body> tag, it's a <frameset>.
2271 0 : return nsnull;
2272 : }
2273 :
2274 0 : nsRefPtr<nsStyleContext> bodyStyle;
2275 0 : bodyStyle = styleSet->ResolveStyleFor(bodyElement->AsElement(), rootStyle);
2276 0 : if (!bodyStyle) {
2277 0 : return nsnull;
2278 : }
2279 :
2280 0 : if (CheckOverflow(presContext, bodyStyle->GetStyleDisplay())) {
2281 : // tell caller we stole the overflow style from the body element
2282 0 : return bodyElement;
2283 : }
2284 :
2285 0 : return nsnull;
2286 : }
2287 :
2288 : nsresult
2289 0 : nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocElement,
2290 : nsILayoutHistoryState* aFrameState,
2291 : nsIFrame** aNewFrame)
2292 : {
2293 0 : NS_PRECONDITION(mFixedContainingBlock,
2294 : "No viewport? Someone forgot to call ConstructRootFrame!");
2295 0 : NS_PRECONDITION(mFixedContainingBlock == GetRootFrame(),
2296 : "Unexpected mFixedContainingBlock");
2297 0 : NS_PRECONDITION(!mDocElementContainingBlock,
2298 : "Shouldn't have a doc element containing block here");
2299 :
2300 0 : *aNewFrame = nsnull;
2301 :
2302 : // Make sure to call PropagateScrollToViewport before
2303 : // SetUpDocElementContainingBlock, since it sets up our scrollbar state
2304 : // properly.
2305 : #ifdef DEBUG
2306 : nsIContent* propagatedScrollFrom =
2307 : #endif
2308 0 : PropagateScrollToViewport();
2309 :
2310 0 : SetUpDocElementContainingBlock(aDocElement);
2311 :
2312 0 : NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now");
2313 :
2314 : nsFrameConstructorState state(mPresShell, mFixedContainingBlock, nsnull,
2315 0 : nsnull, aFrameState);
2316 : // Initialize the ancestor filter with null for now; we'll push
2317 : // aDocElement once we finish resolving style for it.
2318 0 : state.mTreeMatchContext.mAncestorFilter.Init(nsnull);
2319 :
2320 : // XXXbz why, exactly?
2321 0 : if (!mTempFrameTreeState)
2322 0 : state.mPresShell->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState));
2323 :
2324 : // Make sure that we'll handle restyles for this document element in
2325 : // the future. We need this, because the document element might
2326 : // have stale restyle bits from a previous frame constructor for
2327 : // this document. Unlike in AddFrameConstructionItems, it's safe to
2328 : // unset all element restyle flags, since we don't have any
2329 : // siblings.
2330 0 : aDocElement->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS);
2331 :
2332 : // --------- CREATE AREA OR BOX FRAME -------
2333 0 : nsRefPtr<nsStyleContext> styleContext;
2334 : styleContext = mPresShell->StyleSet()->ResolveStyleFor(aDocElement,
2335 0 : nsnull);
2336 :
2337 0 : const nsStyleDisplay* display = styleContext->GetStyleDisplay();
2338 :
2339 : // Ensure that our XBL bindings are installed.
2340 0 : if (display->mBinding) {
2341 : // Get the XBL loader.
2342 : nsresult rv;
2343 : bool resolveStyle;
2344 :
2345 0 : nsIXBLService * xblService = GetXBLService();
2346 0 : if (!xblService)
2347 0 : return NS_ERROR_FAILURE;
2348 :
2349 0 : nsRefPtr<nsXBLBinding> binding;
2350 : rv = xblService->LoadBindings(aDocElement, display->mBinding->GetURI(),
2351 0 : display->mBinding->mOriginPrincipal,
2352 : false, getter_AddRefs(binding),
2353 0 : &resolveStyle);
2354 0 : if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED)
2355 0 : return NS_OK; // Binding will load asynchronously.
2356 :
2357 0 : if (binding) {
2358 : // For backwards compat, keep firing the root's constructor
2359 : // after all of its kids' constructors. So tell the binding
2360 : // manager about it right now.
2361 0 : mDocument->BindingManager()->AddToAttachedQueue(binding);
2362 : }
2363 :
2364 0 : if (resolveStyle) {
2365 : styleContext = mPresShell->StyleSet()->ResolveStyleFor(aDocElement,
2366 0 : nsnull);
2367 0 : display = styleContext->GetStyleDisplay();
2368 : }
2369 : }
2370 :
2371 : // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2372 :
2373 : #ifdef DEBUG
2374 0 : NS_ASSERTION(!display->IsScrollableOverflow() ||
2375 : state.mPresContext->IsPaginated() ||
2376 : propagatedScrollFrom == aDocElement,
2377 : "Scrollbars should have been propagated to the viewport");
2378 : #endif
2379 :
2380 0 : if (NS_UNLIKELY(display->mDisplay == NS_STYLE_DISPLAY_NONE)) {
2381 0 : SetUndisplayedContent(aDocElement, styleContext);
2382 0 : return NS_OK;
2383 : }
2384 :
2385 : AncestorFilter::AutoAncestorPusher
2386 0 : ancestorPusher(true, state.mTreeMatchContext.mAncestorFilter, aDocElement);
2387 :
2388 : // Make sure to start any background image loads for the root element now.
2389 0 : styleContext->StartBackgroundImageLoads();
2390 :
2391 0 : nsFrameConstructorSaveState absoluteSaveState;
2392 0 : if (mHasRootAbsPosContainingBlock) {
2393 : // Push the absolute containing block now so we can absolutely position
2394 : // the root element
2395 : state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
2396 0 : absoluteSaveState);
2397 : }
2398 :
2399 : nsresult rv;
2400 :
2401 : // The rules from CSS 2.1, section 9.2.4, have already been applied
2402 : // by the style system, so we can assume that display->mDisplay is
2403 : // either NONE, BLOCK, or TABLE.
2404 :
2405 : // contentFrame is the primary frame for the root element. *aNewFrame
2406 : // is the frame that will be the child of the initial containing block.
2407 : // These are usually the same frame but they can be different, in
2408 : // particular if the root frame is positioned, in which case
2409 : // contentFrame is the out-of-flow frame and *aNewFrame is the
2410 : // placeholder.
2411 : nsIFrame* contentFrame;
2412 0 : bool processChildren = false;
2413 :
2414 : // Check whether we need to build a XUL box or SVG root frame
2415 : #ifdef MOZ_XUL
2416 0 : if (aDocElement->IsXUL()) {
2417 0 : contentFrame = NS_NewDocElementBoxFrame(mPresShell, styleContext);
2418 0 : if (NS_UNLIKELY(!contentFrame)) {
2419 0 : return NS_ERROR_OUT_OF_MEMORY;
2420 : }
2421 : InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock, nsnull,
2422 0 : contentFrame);
2423 0 : *aNewFrame = contentFrame;
2424 0 : processChildren = true;
2425 : }
2426 : else
2427 : #endif
2428 0 : if (aDocElement->IsSVG()) {
2429 0 : if (aDocElement->Tag() == nsGkAtoms::svg) {
2430 0 : contentFrame = NS_NewSVGOuterSVGFrame(mPresShell, styleContext);
2431 0 : if (NS_UNLIKELY(!contentFrame)) {
2432 0 : return NS_ERROR_OUT_OF_MEMORY;
2433 : }
2434 : InitAndRestoreFrame(state, aDocElement,
2435 : state.GetGeometricParent(display,
2436 : mDocElementContainingBlock),
2437 0 : nsnull, contentFrame);
2438 :
2439 : // AddChild takes care of transforming the frame tree for fixed-pos
2440 : // or abs-pos situations
2441 0 : nsFrameItems frameItems;
2442 : rv = state.AddChild(contentFrame, frameItems, aDocElement,
2443 0 : styleContext, mDocElementContainingBlock);
2444 0 : if (NS_FAILED(rv) || frameItems.IsEmpty()) {
2445 0 : return rv;
2446 : }
2447 0 : *aNewFrame = frameItems.FirstChild();
2448 0 : processChildren = true;
2449 : } else {
2450 0 : return NS_ERROR_FAILURE;
2451 : }
2452 : } else {
2453 0 : bool docElemIsTable = (display->mDisplay == NS_STYLE_DISPLAY_TABLE);
2454 0 : if (docElemIsTable) {
2455 : // We're going to call the right function ourselves, so no need to give a
2456 : // function to this FrameConstructionData.
2457 :
2458 : // XXXbz on the other hand, if we converted this whole function to
2459 : // FrameConstructionData/Item, then we'd need the right function
2460 : // here... but would probably be able to get away with less code in this
2461 : // function in general.
2462 : // Use a null PendingBinding, since our binding is not in fact pending.
2463 : static const FrameConstructionData rootTableData = FCDATA_DECL(0, nsnull);
2464 0 : nsRefPtr<nsStyleContext> extraRef(styleContext);
2465 : FrameConstructionItem item(&rootTableData, aDocElement,
2466 : aDocElement->Tag(), kNameSpaceID_None,
2467 0 : nsnull, extraRef.forget(), true);
2468 :
2469 0 : nsFrameItems frameItems;
2470 : // if the document is a table then just populate it.
2471 : rv = ConstructTable(state, item, mDocElementContainingBlock,
2472 : styleContext->GetStyleDisplay(),
2473 0 : frameItems, &contentFrame);
2474 0 : if (NS_FAILED(rv))
2475 0 : return rv;
2476 0 : if (!contentFrame || frameItems.IsEmpty())
2477 0 : return NS_ERROR_FAILURE;
2478 0 : *aNewFrame = frameItems.FirstChild();
2479 0 : NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2480 : } else {
2481 0 : contentFrame = NS_NewBlockFormattingContext(mPresShell, styleContext);
2482 0 : if (!contentFrame)
2483 0 : return NS_ERROR_OUT_OF_MEMORY;
2484 0 : nsFrameItems frameItems;
2485 : // Use a null PendingBinding, since our binding is not in fact pending.
2486 : rv = ConstructBlock(state, display, aDocElement,
2487 : state.GetGeometricParent(display,
2488 : mDocElementContainingBlock),
2489 : mDocElementContainingBlock, styleContext,
2490 0 : &contentFrame, frameItems, display->IsPositioned(),
2491 0 : nsnull);
2492 0 : if (NS_FAILED(rv) || frameItems.IsEmpty())
2493 0 : return rv;
2494 0 : *aNewFrame = frameItems.FirstChild();
2495 0 : NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
2496 : }
2497 : }
2498 :
2499 : // set the primary frame
2500 0 : aDocElement->SetPrimaryFrame(contentFrame);
2501 :
2502 0 : NS_ASSERTION(processChildren ? !mRootElementFrame :
2503 : mRootElementFrame == contentFrame,
2504 : "unexpected mRootElementFrame");
2505 0 : mRootElementFrame = contentFrame;
2506 :
2507 : // Figure out which frame has the main style for the document element,
2508 : // assigning it to mRootElementStyleFrame.
2509 : // Backgrounds should be propagated from that frame to the viewport.
2510 0 : mRootElementStyleFrame = contentFrame->GetParentStyleContextFrame();
2511 : bool isChild = mRootElementStyleFrame &&
2512 0 : mRootElementStyleFrame->GetParent() == contentFrame;
2513 0 : if (!isChild) {
2514 0 : mRootElementStyleFrame = mRootElementFrame;
2515 : }
2516 :
2517 0 : if (processChildren) {
2518 : // Still need to process the child content
2519 0 : nsFrameItems childItems;
2520 :
2521 0 : NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame),
2522 : "Only XUL and SVG frames should reach here");
2523 : // Use a null PendingBinding, since our binding is not in fact pending.
2524 : ProcessChildren(state, aDocElement, styleContext, contentFrame, true,
2525 0 : childItems, false, nsnull);
2526 :
2527 : // Set the initial child lists
2528 0 : contentFrame->SetInitialChildList(kPrincipalList, childItems);
2529 : }
2530 :
2531 0 : SetInitialSingleChild(mDocElementContainingBlock, *aNewFrame);
2532 :
2533 0 : return NS_OK;
2534 : }
2535 :
2536 :
2537 : nsresult
2538 0 : nsCSSFrameConstructor::ConstructRootFrame(nsIFrame** aNewFrame)
2539 : {
2540 0 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
2541 0 : NS_PRECONDITION(aNewFrame, "null out param");
2542 :
2543 0 : nsStyleSet *styleSet = mPresShell->StyleSet();
2544 :
2545 : // Set up our style rule observer.
2546 : // XXXbz wouldn't this make more sense as part of presshell init?
2547 : {
2548 0 : styleSet->SetBindingManager(mDocument->BindingManager());
2549 : }
2550 :
2551 : // --------- BUILD VIEWPORT -----------
2552 0 : nsIFrame* viewportFrame = nsnull;
2553 0 : nsRefPtr<nsStyleContext> viewportPseudoStyle;
2554 :
2555 : viewportPseudoStyle =
2556 0 : styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::viewport, nsnull);
2557 :
2558 0 : viewportFrame = NS_NewViewportFrame(mPresShell, viewportPseudoStyle);
2559 :
2560 : // XXXbz do we _have_ to pass a null content pointer to that frame?
2561 : // Would it really kill us to pass in the root element or something?
2562 : // What would that break?
2563 0 : viewportFrame->Init(nsnull, nsnull, nsnull);
2564 :
2565 : // Bind the viewport frame to the root view
2566 0 : nsIView* rootView = mPresShell->GetViewManager()->GetRootView();
2567 0 : viewportFrame->SetView(rootView);
2568 :
2569 : nsContainerFrame::SyncFrameViewProperties(mPresShell->GetPresContext(), viewportFrame,
2570 0 : viewportPseudoStyle, rootView);
2571 : nsContainerFrame::SyncWindowProperties(mPresShell->GetPresContext(), viewportFrame,
2572 0 : rootView);
2573 :
2574 : // The viewport is the containing block for 'fixed' elements
2575 0 : mFixedContainingBlock = viewportFrame;
2576 : // Make it an absolute container for fixed-pos elements
2577 0 : mFixedContainingBlock->MarkAsAbsoluteContainingBlock();
2578 :
2579 0 : *aNewFrame = viewportFrame;
2580 0 : return NS_OK;
2581 : }
2582 :
2583 : nsresult
2584 0 : nsCSSFrameConstructor::SetUpDocElementContainingBlock(nsIContent* aDocElement)
2585 : {
2586 0 : NS_PRECONDITION(aDocElement, "No element?");
2587 0 : NS_PRECONDITION(!aDocElement->GetParent(), "Not root content?");
2588 0 : NS_PRECONDITION(aDocElement->GetCurrentDoc(), "Not in a document?");
2589 0 : NS_PRECONDITION(aDocElement->GetCurrentDoc()->GetRootElement() ==
2590 : aDocElement, "Not the root of the document?");
2591 :
2592 : /*
2593 : how the root frame hierarchy should look
2594 :
2595 : Galley presentation, non-XUL, with scrolling (i.e. not a frameset):
2596 :
2597 : ViewportFrame [fixed-cb]
2598 : nsHTMLScrollFrame
2599 : nsCanvasFrame [abs-cb]
2600 : root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2601 : nsTableOuterFrame, nsPlaceholderFrame)
2602 :
2603 : Galley presentation, non-XUL, without scrolling (i.e. a frameset):
2604 :
2605 : ViewportFrame [fixed-cb]
2606 : nsCanvasFrame [abs-cb]
2607 : root element frame (nsBlockFrame)
2608 :
2609 : Galley presentation, XUL
2610 :
2611 : ViewportFrame [fixed-cb]
2612 : nsRootBoxFrame
2613 : root element frame (nsDocElementBoxFrame)
2614 :
2615 : Print presentation, non-XUL
2616 :
2617 : ViewportFrame
2618 : nsSimplePageSequenceFrame
2619 : nsPageFrame [fixed-cb]
2620 : nsPageContentFrame
2621 : nsCanvasFrame [abs-cb]
2622 : root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2623 : nsTableOuterFrame, nsPlaceholderFrame)
2624 :
2625 : Print-preview presentation, non-XUL
2626 :
2627 : ViewportFrame
2628 : nsHTMLScrollFrame
2629 : nsSimplePageSequenceFrame
2630 : nsPageFrame [fixed-cb]
2631 : nsPageContentFrame
2632 : nsCanvasFrame [abs-cb]
2633 : root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
2634 : nsTableOuterFrame, nsPlaceholderFrame)
2635 :
2636 : Print/print preview of XUL is not supported.
2637 : [fixed-cb]: the default containing block for fixed-pos content
2638 : [abs-cb]: the default containing block for abs-pos content
2639 :
2640 : Meaning of nsCSSFrameConstructor fields:
2641 : mRootElementFrame is "root element frame". This is the primary frame for
2642 : the root element.
2643 : mDocElementContainingBlock is the parent of mRootElementFrame
2644 : (i.e. nsCanvasFrame or nsRootBoxFrame)
2645 : mFixedContainingBlock is the [fixed-cb]
2646 : mGfxScrollFrame is the nsHTMLScrollFrame mentioned above, or null if there isn't one
2647 : mPageSequenceFrame is the nsSimplePageSequenceFrame, or null if there isn't one
2648 : */
2649 :
2650 : // --------- CREATE ROOT FRAME -------
2651 :
2652 :
2653 : // Create the root frame. The document element's frame is a child of the
2654 : // root frame.
2655 : //
2656 : // The root frame serves two purposes:
2657 : // - reserves space for any margins needed for the document element's frame
2658 : // - renders the document element's background. This ensures the background covers
2659 : // the entire canvas as specified by the CSS2 spec
2660 :
2661 0 : nsPresContext* presContext = mPresShell->GetPresContext();
2662 0 : bool isPaginated = presContext->IsRootPaginatedDocument();
2663 0 : nsIFrame* viewportFrame = mFixedContainingBlock;
2664 0 : nsStyleContext* viewportPseudoStyle = viewportFrame->GetStyleContext();
2665 :
2666 0 : nsIFrame* rootFrame = nsnull;
2667 : nsIAtom* rootPseudo;
2668 :
2669 0 : if (!isPaginated) {
2670 : #ifdef MOZ_XUL
2671 0 : if (aDocElement->IsXUL())
2672 : {
2673 : // pass a temporary stylecontext, the correct one will be set later
2674 0 : rootFrame = NS_NewRootBoxFrame(mPresShell, viewportPseudoStyle);
2675 : } else
2676 : #endif
2677 : {
2678 : // pass a temporary stylecontext, the correct one will be set later
2679 0 : rootFrame = NS_NewCanvasFrame(mPresShell, viewportPseudoStyle);
2680 0 : mHasRootAbsPosContainingBlock = true;
2681 : }
2682 :
2683 0 : rootPseudo = nsCSSAnonBoxes::canvas;
2684 0 : mDocElementContainingBlock = rootFrame;
2685 : } else {
2686 : // Create a page sequence frame
2687 0 : rootFrame = NS_NewSimplePageSequenceFrame(mPresShell, viewportPseudoStyle);
2688 0 : mPageSequenceFrame = rootFrame;
2689 0 : rootPseudo = nsCSSAnonBoxes::pageSequence;
2690 : }
2691 :
2692 :
2693 : // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
2694 :
2695 : // If the device supports scrolling (e.g., in galley mode on the screen and
2696 : // for print-preview, but not when printing), then create a scroll frame that
2697 : // will act as the scrolling mechanism for the viewport.
2698 : // XXX Do we even need a viewport when printing to a printer?
2699 :
2700 : // As long as the docshell doesn't prohibit it, and the device supports
2701 : // it, create a scroll frame that will act as the scolling mechanism for
2702 : // the viewport.
2703 : //
2704 : // Threre are three possible values stored in the docshell:
2705 : // 1) nsIScrollable::Scrollbar_Never = no scrollbars
2706 : // 2) nsIScrollable::Scrollbar_Auto = scrollbars appear if needed
2707 : // 3) nsIScrollable::Scrollbar_Always = scrollbars always
2708 : // Only need to create a scroll frame/view for cases 2 and 3.
2709 :
2710 0 : bool isHTML = aDocElement->IsHTML();
2711 0 : bool isXUL = false;
2712 :
2713 0 : if (!isHTML) {
2714 0 : isXUL = aDocElement->IsXUL();
2715 : }
2716 :
2717 : // Never create scrollbars for XUL documents
2718 0 : bool isScrollable = !isXUL;
2719 :
2720 : // Never create scrollbars for frameset documents.
2721 0 : if (isHTML) {
2722 0 : nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
2723 0 : if (htmlDoc && htmlDoc->GetIsFrameset())
2724 0 : isScrollable = false;
2725 : }
2726 :
2727 0 : if (isPaginated) {
2728 0 : isScrollable = presContext->HasPaginatedScrolling();
2729 : }
2730 :
2731 : // We no longer need to do overflow propagation here. It's taken care of
2732 : // when we construct frames for the element whose overflow might be
2733 : // propagated
2734 0 : NS_ASSERTION(!isScrollable || !isXUL,
2735 : "XUL documents should never be scrollable - see above");
2736 :
2737 0 : nsIFrame* newFrame = rootFrame;
2738 0 : nsRefPtr<nsStyleContext> rootPseudoStyle;
2739 : // we must create a state because if the scrollbars are GFX it needs the
2740 : // state to build the scrollbar frames.
2741 0 : nsFrameConstructorState state(mPresShell, nsnull, nsnull, nsnull);
2742 :
2743 : // Start off with the viewport as parent; we'll adjust it as needed.
2744 0 : nsIFrame* parentFrame = viewportFrame;
2745 :
2746 0 : nsStyleSet* styleSet = mPresShell->StyleSet();
2747 : // If paginated, make sure we don't put scrollbars in
2748 0 : if (!isScrollable) {
2749 : rootPseudoStyle = styleSet->ResolveAnonymousBoxStyle(rootPseudo,
2750 0 : viewportPseudoStyle);
2751 : } else {
2752 0 : if (rootPseudo == nsCSSAnonBoxes::canvas) {
2753 0 : rootPseudo = nsCSSAnonBoxes::scrolledCanvas;
2754 : } else {
2755 0 : NS_ASSERTION(rootPseudo == nsCSSAnonBoxes::pageSequence,
2756 : "Unknown root pseudo");
2757 0 : rootPseudo = nsCSSAnonBoxes::scrolledPageSequence;
2758 : }
2759 :
2760 : // Build the frame. We give it the content we are wrapping which is the
2761 : // document element, the root frame, the parent view port frame, and we
2762 : // should get back the new frame and the scrollable view if one was
2763 : // created.
2764 :
2765 : // resolve a context for the scrollframe
2766 0 : nsRefPtr<nsStyleContext> styleContext;
2767 : styleContext = styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::viewportScroll,
2768 0 : viewportPseudoStyle);
2769 :
2770 : // Note that the viewport scrollframe is always built with
2771 : // overflow:auto style. This forces the scroll frame to create
2772 : // anonymous content for both scrollbars. This is necessary even
2773 : // if the HTML or BODY elements are overriding the viewport
2774 : // scroll style to 'hidden' --- dynamic style changes might put
2775 : // scrollbars back on the viewport and we don't want to have to
2776 : // reframe the viewport to create the scrollbar content.
2777 0 : newFrame = nsnull;
2778 : rootPseudoStyle = BeginBuildingScrollFrame( state,
2779 : aDocElement,
2780 : styleContext,
2781 : viewportFrame,
2782 : rootPseudo,
2783 : true,
2784 0 : newFrame);
2785 0 : parentFrame = newFrame;
2786 0 : mGfxScrollFrame = newFrame;
2787 : }
2788 :
2789 0 : rootFrame->SetStyleContextWithoutNotification(rootPseudoStyle);
2790 0 : rootFrame->Init(aDocElement, parentFrame, nsnull);
2791 :
2792 0 : if (isScrollable) {
2793 0 : FinishBuildingScrollFrame(parentFrame, rootFrame);
2794 : }
2795 :
2796 0 : if (isPaginated) { // paginated
2797 : // Create the first page
2798 : // Set the initial child lists
2799 : nsIFrame *pageFrame, *canvasFrame;
2800 : ConstructPageFrame(mPresShell, presContext, rootFrame, nsnull,
2801 0 : pageFrame, canvasFrame);
2802 0 : SetInitialSingleChild(rootFrame, pageFrame);
2803 :
2804 : // The eventual parent of the document element frame.
2805 : // XXX should this be set for every new page (in ConstructPageFrame)?
2806 0 : mDocElementContainingBlock = canvasFrame;
2807 0 : mHasRootAbsPosContainingBlock = true;
2808 : }
2809 :
2810 0 : if (viewportFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
2811 0 : SetInitialSingleChild(viewportFrame, newFrame);
2812 : } else {
2813 0 : nsFrameList newFrameList(newFrame, newFrame);
2814 0 : viewportFrame->AppendFrames(kPrincipalList, newFrameList);
2815 : }
2816 :
2817 0 : return NS_OK;
2818 : }
2819 :
2820 : nsresult
2821 0 : nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell* aPresShell,
2822 : nsPresContext* aPresContext,
2823 : nsIFrame* aParentFrame,
2824 : nsIFrame* aPrevPageFrame,
2825 : nsIFrame*& aPageFrame,
2826 : nsIFrame*& aCanvasFrame)
2827 : {
2828 0 : nsStyleContext* parentStyleContext = aParentFrame->GetStyleContext();
2829 0 : nsStyleSet *styleSet = aPresShell->StyleSet();
2830 :
2831 0 : nsRefPtr<nsStyleContext> pagePseudoStyle;
2832 : pagePseudoStyle = styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::page,
2833 0 : parentStyleContext);
2834 :
2835 0 : aPageFrame = NS_NewPageFrame(aPresShell, pagePseudoStyle);
2836 0 : if (NS_UNLIKELY(!aPageFrame))
2837 0 : return NS_ERROR_OUT_OF_MEMORY;
2838 :
2839 : // Initialize the page frame and force it to have a view. This makes printing of
2840 : // the pages easier and faster.
2841 0 : aPageFrame->Init(nsnull, aParentFrame, aPrevPageFrame);
2842 :
2843 0 : nsRefPtr<nsStyleContext> pageContentPseudoStyle;
2844 : pageContentPseudoStyle =
2845 : styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::pageContent,
2846 0 : pagePseudoStyle);
2847 :
2848 0 : nsIFrame* pageContentFrame = NS_NewPageContentFrame(aPresShell, pageContentPseudoStyle);
2849 0 : if (NS_UNLIKELY(!pageContentFrame))
2850 0 : return NS_ERROR_OUT_OF_MEMORY;
2851 :
2852 : // Initialize the page content frame and force it to have a view. Also make it the
2853 : // containing block for fixed elements which are repeated on every page.
2854 0 : nsIFrame* prevPageContentFrame = nsnull;
2855 0 : if (aPrevPageFrame) {
2856 0 : prevPageContentFrame = aPrevPageFrame->GetFirstPrincipalChild();
2857 0 : NS_ASSERTION(prevPageContentFrame, "missing page content frame");
2858 : }
2859 0 : pageContentFrame->Init(nsnull, aPageFrame, prevPageContentFrame);
2860 0 : SetInitialSingleChild(aPageFrame, pageContentFrame);
2861 0 : mFixedContainingBlock = pageContentFrame;
2862 : // Make it an absolute container for fixed-pos elements
2863 0 : mFixedContainingBlock->MarkAsAbsoluteContainingBlock();
2864 :
2865 0 : nsRefPtr<nsStyleContext> canvasPseudoStyle;
2866 : canvasPseudoStyle = styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::canvas,
2867 0 : pageContentPseudoStyle);
2868 :
2869 0 : aCanvasFrame = NS_NewCanvasFrame(aPresShell, canvasPseudoStyle);
2870 0 : if (NS_UNLIKELY(!aCanvasFrame))
2871 0 : return NS_ERROR_OUT_OF_MEMORY;
2872 :
2873 0 : nsIFrame* prevCanvasFrame = nsnull;
2874 0 : if (prevPageContentFrame) {
2875 0 : prevCanvasFrame = prevPageContentFrame->GetFirstPrincipalChild();
2876 0 : NS_ASSERTION(prevCanvasFrame, "missing canvas frame");
2877 : }
2878 0 : aCanvasFrame->Init(nsnull, pageContentFrame, prevCanvasFrame);
2879 0 : SetInitialSingleChild(pageContentFrame, aCanvasFrame);
2880 :
2881 0 : return NS_OK;
2882 : }
2883 :
2884 : /* static */
2885 : nsresult
2886 0 : nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell* aPresShell,
2887 : nsIContent* aContent,
2888 : nsIFrame* aFrame,
2889 : nsStyleContext* aStyleContext,
2890 : nsIFrame* aParentFrame,
2891 : nsIFrame* aPrevInFlow,
2892 : nsFrameState aTypeBit,
2893 : nsIFrame** aPlaceholderFrame)
2894 : {
2895 : nsRefPtr<nsStyleContext> placeholderStyle = aPresShell->StyleSet()->
2896 0 : ResolveStyleForNonElement(aStyleContext->GetParent());
2897 :
2898 : // The placeholder frame gets a pseudo style context
2899 : nsPlaceholderFrame* placeholderFrame =
2900 : (nsPlaceholderFrame*)NS_NewPlaceholderFrame(aPresShell, placeholderStyle,
2901 0 : aTypeBit);
2902 :
2903 0 : if (placeholderFrame) {
2904 0 : placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow);
2905 :
2906 : // The placeholder frame has a pointer back to the out-of-flow frame
2907 0 : placeholderFrame->SetOutOfFlowFrame(aFrame);
2908 :
2909 0 : aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
2910 :
2911 : // Add mapping from absolutely positioned frame to its placeholder frame
2912 0 : aPresShell->FrameManager()->RegisterPlaceholderFrame(placeholderFrame);
2913 :
2914 0 : *aPlaceholderFrame = static_cast<nsIFrame*>(placeholderFrame);
2915 :
2916 0 : return NS_OK;
2917 : }
2918 : else {
2919 0 : return NS_ERROR_OUT_OF_MEMORY;
2920 : }
2921 : }
2922 :
2923 : // Clears any lazy bits set in the range [aStartContent, aEndContent). If
2924 : // aEndContent is null, that means to clear bits in all siblings starting with
2925 : // aStartContent. aStartContent must not be null unless aEndContent is also
2926 : // null. We do this so that when new children are inserted under elements whose
2927 : // frame is a leaf the new children don't cause us to try to construct frames
2928 : // for the existing children again.
2929 : static inline void
2930 0 : ClearLazyBits(nsIContent* aStartContent, nsIContent* aEndContent)
2931 : {
2932 0 : NS_PRECONDITION(aStartContent || !aEndContent,
2933 : "Must have start child if we have an end child");
2934 0 : for (nsIContent* cur = aStartContent; cur != aEndContent;
2935 0 : cur = cur->GetNextSibling()) {
2936 0 : cur->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
2937 : }
2938 0 : }
2939 :
2940 : nsresult
2941 0 : nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState,
2942 : FrameConstructionItem& aItem,
2943 : nsIFrame* aParentFrame,
2944 : const nsStyleDisplay* aStyleDisplay,
2945 : nsFrameItems& aFrameItems,
2946 : nsIFrame** aNewFrame)
2947 : {
2948 0 : nsresult rv = NS_OK;
2949 0 : const PRInt32 kNoSizeSpecified = -1;
2950 :
2951 0 : nsIContent* const content = aItem.mContent;
2952 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
2953 :
2954 : // Construct a frame-based listbox or combobox
2955 0 : nsCOMPtr<nsIDOMHTMLSelectElement> sel(do_QueryInterface(content));
2956 0 : PRInt32 size = 1;
2957 0 : if (sel) {
2958 0 : sel->GetSize(&size);
2959 0 : bool multipleSelect = false;
2960 0 : sel->GetMultiple(&multipleSelect);
2961 : // Construct a combobox if size=1 or no size is specified and its multiple select
2962 0 : if (((1 == size || 0 == size) || (kNoSizeSpecified == size)) && (false == multipleSelect)) {
2963 : // Construct a frame-based combo box.
2964 : // The frame-based combo box is built out of three parts. A display area, a button and
2965 : // a dropdown list. The display area and button are created through anonymous content.
2966 : // The drop-down list's frame is created explicitly. The combobox frame shares its content
2967 : // with the drop-down list.
2968 0 : PRUint32 flags = NS_BLOCK_FLOAT_MGR;
2969 0 : nsIFrame* comboboxFrame = NS_NewComboboxControlFrame(mPresShell, styleContext, flags);
2970 :
2971 : // Save the history state so we don't restore during construction
2972 : // since the complete tree is required before we restore.
2973 0 : nsILayoutHistoryState *historyState = aState.mFrameState;
2974 0 : aState.mFrameState = nsnull;
2975 : // Initialize the combobox frame
2976 : InitAndRestoreFrame(aState, content,
2977 : aState.GetGeometricParent(aStyleDisplay, aParentFrame),
2978 0 : nsnull, comboboxFrame);
2979 :
2980 : rv = aState.AddChild(comboboxFrame, aFrameItems, content, styleContext,
2981 0 : aParentFrame);
2982 0 : if (NS_FAILED(rv)) {
2983 0 : return rv;
2984 : }
2985 :
2986 0 : nsIComboboxControlFrame* comboBox = do_QueryFrame(comboboxFrame);
2987 0 : NS_ASSERTION(comboBox, "NS_NewComboboxControlFrame returned frame that "
2988 : "doesn't implement nsIComboboxControlFrame");
2989 :
2990 : // Resolve pseudo element style for the dropdown list
2991 0 : nsRefPtr<nsStyleContext> listStyle;
2992 : listStyle = mPresShell->StyleSet()->
2993 0 : ResolveAnonymousBoxStyle(nsCSSAnonBoxes::dropDownList, styleContext);
2994 :
2995 : // Create a listbox
2996 0 : nsIFrame* listFrame = NS_NewListControlFrame(mPresShell, listStyle);
2997 :
2998 : // Notify the listbox that it is being used as a dropdown list.
2999 0 : nsIListControlFrame * listControlFrame = do_QueryFrame(listFrame);
3000 0 : if (listControlFrame) {
3001 0 : listControlFrame->SetComboboxFrame(comboboxFrame);
3002 : }
3003 : // Notify combobox that it should use the listbox as it's popup
3004 0 : comboBox->SetDropDown(listFrame);
3005 :
3006 0 : NS_ASSERTION(!listStyle->GetStyleDisplay()->IsPositioned(),
3007 : "Ended up with positioned dropdown list somehow.");
3008 0 : NS_ASSERTION(!listStyle->GetStyleDisplay()->IsFloating(),
3009 : "Ended up with floating dropdown list somehow.");
3010 :
3011 : // Initialize the scroll frame positioned. Note that it is NOT
3012 : // initialized as absolutely positioned.
3013 0 : nsIFrame* scrolledFrame = NS_NewSelectsAreaFrame(mPresShell, styleContext, flags);
3014 :
3015 : InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
3016 : comboboxFrame, listStyle, true,
3017 0 : aItem.mPendingBinding, aFrameItems);
3018 :
3019 0 : NS_ASSERTION(listFrame->GetView(), "ListFrame's view is nsnull");
3020 :
3021 : // Create display and button frames from the combobox's anonymous content.
3022 : // The anonymous content is appended to existing anonymous content for this
3023 : // element (the scrollbars).
3024 :
3025 0 : nsFrameItems childItems;
3026 : CreateAnonymousFrames(aState, content, comboboxFrame,
3027 0 : aItem.mPendingBinding, childItems);
3028 :
3029 0 : comboboxFrame->SetInitialChildList(kPrincipalList, childItems);
3030 :
3031 : // Initialize the additional popup child list which contains the
3032 : // dropdown list frame.
3033 0 : nsFrameItems popupItems;
3034 0 : popupItems.AddChild(listFrame);
3035 : comboboxFrame->SetInitialChildList(nsIFrame::kSelectPopupList,
3036 0 : popupItems);
3037 :
3038 0 : *aNewFrame = comboboxFrame;
3039 0 : aState.mFrameState = historyState;
3040 0 : if (aState.mFrameState) {
3041 : // Restore frame state for the entire subtree of |comboboxFrame|.
3042 0 : RestoreFrameState(comboboxFrame, aState.mFrameState);
3043 0 : }
3044 : } else {
3045 0 : nsIFrame* listFrame = NS_NewListControlFrame(mPresShell, styleContext);
3046 0 : if (listFrame) {
3047 0 : rv = NS_OK;
3048 : }
3049 : else {
3050 0 : rv = NS_ERROR_OUT_OF_MEMORY;
3051 : }
3052 :
3053 : nsIFrame* scrolledFrame = NS_NewSelectsAreaFrame(
3054 0 : mPresShell, styleContext, NS_BLOCK_FLOAT_MGR);
3055 :
3056 : // ******* this code stolen from Initialze ScrollFrame ********
3057 : // please adjust this code to use BuildScrollFrame.
3058 :
3059 : InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
3060 : aParentFrame, styleContext, false,
3061 0 : aItem.mPendingBinding, aFrameItems);
3062 :
3063 0 : *aNewFrame = listFrame;
3064 : }
3065 : }
3066 0 : return rv;
3067 :
3068 : }
3069 :
3070 : /**
3071 : * Used to be InitializeScrollFrame but now it's only used for the select tag
3072 : * But the select tag should really be fixed to use GFX scrollbars that can
3073 : * be create with BuildScrollFrame.
3074 : */
3075 : nsresult
3076 0 : nsCSSFrameConstructor::InitializeSelectFrame(nsFrameConstructorState& aState,
3077 : nsIFrame* scrollFrame,
3078 : nsIFrame* scrolledFrame,
3079 : nsIContent* aContent,
3080 : nsIFrame* aParentFrame,
3081 : nsStyleContext* aStyleContext,
3082 : bool aBuildCombobox,
3083 : PendingBinding* aPendingBinding,
3084 : nsFrameItems& aFrameItems)
3085 : {
3086 0 : const nsStyleDisplay* display = aStyleContext->GetStyleDisplay();
3087 :
3088 : // Initialize it
3089 0 : nsIFrame* geometricParent = aState.GetGeometricParent(display, aParentFrame);
3090 :
3091 : // We don't call InitAndRestoreFrame for scrollFrame because we can only
3092 : // restore the frame state after its parts have been created (in particular,
3093 : // the scrollable view). So we have to split Init and Restore.
3094 :
3095 : // Initialize the frame
3096 0 : scrollFrame->Init(aContent, geometricParent, nsnull);
3097 :
3098 0 : if (!aBuildCombobox) {
3099 : nsresult rv = aState.AddChild(scrollFrame, aFrameItems, aContent,
3100 0 : aStyleContext, aParentFrame);
3101 0 : if (NS_FAILED(rv)) {
3102 0 : return rv;
3103 : }
3104 : }
3105 :
3106 0 : if (aBuildCombobox) {
3107 0 : nsContainerFrame::CreateViewForFrame(scrollFrame, true);
3108 : }
3109 :
3110 : BuildScrollFrame(aState, aContent, aStyleContext, scrolledFrame,
3111 0 : geometricParent, scrollFrame);
3112 :
3113 0 : if (aState.mFrameState) {
3114 : // Restore frame state for the scroll frame
3115 0 : RestoreFrameStateFor(scrollFrame, aState.mFrameState);
3116 : }
3117 :
3118 : // Process children
3119 0 : nsFrameItems childItems;
3120 :
3121 : ProcessChildren(aState, aContent, aStyleContext, scrolledFrame, false,
3122 0 : childItems, false, aPendingBinding);
3123 :
3124 : // Set the scrolled frame's initial child lists
3125 0 : scrolledFrame->SetInitialChildList(kPrincipalList, childItems);
3126 0 : return NS_OK;
3127 : }
3128 :
3129 : nsresult
3130 0 : nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState& aState,
3131 : FrameConstructionItem& aItem,
3132 : nsIFrame* aParentFrame,
3133 : const nsStyleDisplay* aStyleDisplay,
3134 : nsFrameItems& aFrameItems,
3135 : nsIFrame** aNewFrame)
3136 : {
3137 0 : nsIContent* const content = aItem.mContent;
3138 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
3139 :
3140 0 : nsIFrame* newFrame = NS_NewFieldSetFrame(mPresShell, styleContext);
3141 0 : if (NS_UNLIKELY(!newFrame)) {
3142 0 : return NS_ERROR_OUT_OF_MEMORY;
3143 : }
3144 :
3145 : // Initialize it
3146 : InitAndRestoreFrame(aState, content,
3147 : aState.GetGeometricParent(aStyleDisplay, aParentFrame),
3148 0 : nsnull, newFrame);
3149 :
3150 : // Resolve style and initialize the frame
3151 0 : nsRefPtr<nsStyleContext> fieldsetContentStyle;
3152 : fieldsetContentStyle = mPresShell->StyleSet()->
3153 0 : ResolveAnonymousBoxStyle(nsCSSAnonBoxes::fieldsetContent, styleContext);
3154 :
3155 : nsIFrame* blockFrame = NS_NewBlockFrame(mPresShell, fieldsetContentStyle,
3156 : NS_BLOCK_FLOAT_MGR |
3157 0 : NS_BLOCK_MARGIN_ROOT);
3158 0 : InitAndRestoreFrame(aState, content, newFrame, nsnull, blockFrame);
3159 :
3160 : nsresult rv = aState.AddChild(newFrame, aFrameItems, content, styleContext,
3161 0 : aParentFrame);
3162 0 : if (NS_FAILED(rv)) {
3163 0 : return rv;
3164 : }
3165 :
3166 : // Process children
3167 0 : nsFrameConstructorSaveState absoluteSaveState;
3168 0 : nsFrameItems childItems;
3169 :
3170 0 : if (aStyleDisplay->IsPositioned()) {
3171 0 : aState.PushAbsoluteContainingBlock(newFrame, absoluteSaveState);
3172 : }
3173 :
3174 : ProcessChildren(aState, content, styleContext, blockFrame, true,
3175 0 : childItems, true, aItem.mPendingBinding);
3176 :
3177 0 : nsFrameItems fieldsetKids;
3178 0 : fieldsetKids.AddChild(blockFrame);
3179 :
3180 0 : for (nsFrameList::Enumerator e(childItems); !e.AtEnd(); e.Next()) {
3181 0 : nsLegendFrame* legendFrame = do_QueryFrame(e.get());
3182 0 : if (legendFrame) {
3183 : // We want the legend to be the first frame in the fieldset child list.
3184 : // That way the EventStateManager will do the right thing when tabbing
3185 : // from a selection point within the legend (bug 236071), which is
3186 : // used for implementing legend access keys (bug 81481).
3187 : // GetAdjustedParentFrame() below depends on this frame order.
3188 0 : childItems.RemoveFrame(legendFrame);
3189 : // Make sure to reparent the legend so it has the fieldset as the parent.
3190 0 : fieldsetKids.InsertFrame(newFrame, nsnull, legendFrame);
3191 0 : break;
3192 : }
3193 : }
3194 :
3195 : // Set the inner frame's initial child lists
3196 0 : blockFrame->SetInitialChildList(kPrincipalList, childItems);
3197 :
3198 : // Set the outer frame's initial child list
3199 0 : newFrame->SetInitialChildList(kPrincipalList, fieldsetKids);
3200 :
3201 : // our new frame returned is the top frame which is the list frame.
3202 0 : *aNewFrame = newFrame;
3203 :
3204 0 : return NS_OK;
3205 : }
3206 :
3207 : static nsIFrame*
3208 0 : FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame)
3209 : {
3210 0 : for (nsIFrame* f = aFrame->GetParent(); f; f = f->GetParent()) {
3211 0 : NS_ASSERTION(f->IsGeneratedContentFrame(),
3212 : "should not have exited generated content");
3213 0 : nsIAtom* pseudo = f->GetStyleContext()->GetPseudo();
3214 0 : if (pseudo == nsCSSPseudoElements::before ||
3215 : pseudo == nsCSSPseudoElements::after)
3216 0 : return f;
3217 : }
3218 0 : return nsnull;
3219 : }
3220 :
3221 : #define SIMPLE_FCDATA(_func) FCDATA_DECL(0, _func)
3222 : #define FULL_CTOR_FCDATA(_flags, _func) \
3223 : { _flags | FCDATA_FUNC_IS_FULL_CTOR, { nsnull }, _func, nsnull }
3224 :
3225 : /* static */
3226 : const nsCSSFrameConstructor::FrameConstructionData*
3227 0 : nsCSSFrameConstructor::FindTextData(nsIFrame* aParentFrame)
3228 : {
3229 0 : if (aParentFrame && aParentFrame->IsFrameOfType(nsIFrame::eSVG)) {
3230 : nsIFrame *ancestorFrame =
3231 0 : nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame);
3232 0 : if (ancestorFrame) {
3233 0 : nsSVGTextContainerFrame* metrics = do_QueryFrame(ancestorFrame);
3234 0 : if (metrics) {
3235 : static const FrameConstructionData sSVGGlyphData =
3236 : SIMPLE_FCDATA(NS_NewSVGGlyphFrame);
3237 0 : return &sSVGGlyphData;
3238 : }
3239 : }
3240 0 : return nsnull;
3241 : }
3242 :
3243 : static const FrameConstructionData sTextData =
3244 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT, NS_NewTextFrame);
3245 0 : return &sTextData;
3246 : }
3247 :
3248 : nsresult
3249 0 : nsCSSFrameConstructor::ConstructTextFrame(const FrameConstructionData* aData,
3250 : nsFrameConstructorState& aState,
3251 : nsIContent* aContent,
3252 : nsIFrame* aParentFrame,
3253 : nsStyleContext* aStyleContext,
3254 : nsFrameItems& aFrameItems)
3255 : {
3256 0 : NS_PRECONDITION(aData, "Must have frame construction data");
3257 :
3258 0 : nsIFrame* newFrame = (*aData->mFunc.mCreationFunc)(mPresShell, aStyleContext);
3259 :
3260 0 : if (NS_UNLIKELY(!newFrame))
3261 0 : return NS_ERROR_OUT_OF_MEMORY;
3262 :
3263 : nsresult rv = InitAndRestoreFrame(aState, aContent, aParentFrame,
3264 0 : nsnull, newFrame);
3265 :
3266 0 : if (NS_FAILED(rv)) {
3267 0 : newFrame->Destroy();
3268 0 : return rv;
3269 : }
3270 :
3271 : // We never need to create a view for a text frame.
3272 :
3273 0 : if (newFrame->IsGeneratedContentFrame()) {
3274 0 : nsAutoPtr<nsGenConInitializer> initializer;
3275 : initializer =
3276 : static_cast<nsGenConInitializer*>(
3277 0 : aContent->UnsetProperty(nsGkAtoms::genConInitializerProperty));
3278 0 : if (initializer) {
3279 0 : if (initializer->mNode->InitTextFrame(initializer->mList,
3280 0 : FindAncestorWithGeneratedContentPseudo(newFrame), newFrame)) {
3281 0 : (this->*(initializer->mDirtyAll))();
3282 : }
3283 0 : initializer->mNode.forget();
3284 : }
3285 : }
3286 :
3287 : // Add the newly constructed frame to the flow
3288 0 : aFrameItems.AddChild(newFrame);
3289 :
3290 0 : if (!aState.mCreatingExtraFrames)
3291 0 : aContent->SetPrimaryFrame(newFrame);
3292 :
3293 0 : return rv;
3294 : }
3295 :
3296 : /* static */
3297 : const nsCSSFrameConstructor::FrameConstructionData*
3298 0 : nsCSSFrameConstructor::FindDataByInt(PRInt32 aInt,
3299 : Element* aElement,
3300 : nsStyleContext* aStyleContext,
3301 : const FrameConstructionDataByInt* aDataPtr,
3302 : PRUint32 aDataLength)
3303 : {
3304 0 : for (const FrameConstructionDataByInt *curData = aDataPtr,
3305 0 : *endData = aDataPtr + aDataLength;
3306 : curData != endData;
3307 : ++curData) {
3308 0 : if (curData->mInt == aInt) {
3309 0 : const FrameConstructionData* data = &curData->mData;
3310 0 : if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
3311 0 : return data->mFunc.mDataGetter(aElement, aStyleContext);
3312 : }
3313 :
3314 0 : return data;
3315 : }
3316 : }
3317 :
3318 0 : return nsnull;
3319 : }
3320 :
3321 : /* static */
3322 : const nsCSSFrameConstructor::FrameConstructionData*
3323 0 : nsCSSFrameConstructor::FindDataByTag(nsIAtom* aTag,
3324 : Element* aElement,
3325 : nsStyleContext* aStyleContext,
3326 : const FrameConstructionDataByTag* aDataPtr,
3327 : PRUint32 aDataLength)
3328 : {
3329 0 : for (const FrameConstructionDataByTag *curData = aDataPtr,
3330 0 : *endData = aDataPtr + aDataLength;
3331 : curData != endData;
3332 : ++curData) {
3333 0 : if (*curData->mTag == aTag) {
3334 0 : const FrameConstructionData* data = &curData->mData;
3335 0 : if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
3336 0 : return data->mFunc.mDataGetter(aElement, aStyleContext);
3337 : }
3338 :
3339 0 : return data;
3340 : }
3341 : }
3342 :
3343 0 : return nsnull;
3344 : }
3345 :
3346 : #define SUPPRESS_FCDATA() FCDATA_DECL(FCDATA_SUPPRESS_FRAME, nsnull)
3347 : #define SIMPLE_INT_CREATE(_int, _func) { _int, SIMPLE_FCDATA(_func) }
3348 : #define SIMPLE_INT_CHAIN(_int, _func) \
3349 : { _int, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
3350 : #define COMPLEX_INT_CREATE(_int, _func) \
3351 : { _int, FULL_CTOR_FCDATA(0, _func) }
3352 :
3353 : #define SIMPLE_TAG_CREATE(_tag, _func) \
3354 : { &nsGkAtoms::_tag, SIMPLE_FCDATA(_func) }
3355 : #define SIMPLE_TAG_CHAIN(_tag, _func) \
3356 : { &nsGkAtoms::_tag, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
3357 : #define COMPLEX_TAG_CREATE(_tag, _func) \
3358 : { &nsGkAtoms::_tag, FULL_CTOR_FCDATA(0, _func) }
3359 :
3360 : /* static */
3361 : const nsCSSFrameConstructor::FrameConstructionData*
3362 0 : nsCSSFrameConstructor::FindHTMLData(Element* aElement,
3363 : nsIAtom* aTag,
3364 : PRInt32 aNameSpaceID,
3365 : nsIFrame* aParentFrame,
3366 : nsStyleContext* aStyleContext)
3367 : {
3368 : // Ignore the tag if it's not HTML content and if it doesn't extend (via XBL)
3369 : // a valid HTML namespace. This check must match the one in
3370 : // ShouldHaveFirstLineStyle.
3371 0 : if (aNameSpaceID != kNameSpaceID_XHTML) {
3372 0 : return nsnull;
3373 : }
3374 :
3375 0 : NS_ASSERTION(!aParentFrame ||
3376 : aParentFrame->GetStyleContext()->GetPseudo() !=
3377 : nsCSSAnonBoxes::fieldsetContent ||
3378 : aParentFrame->GetParent()->GetType() == nsGkAtoms::fieldSetFrame,
3379 : "Unexpected parent for fieldset content anon box");
3380 0 : if (aTag == nsGkAtoms::legend &&
3381 : (!aParentFrame ||
3382 0 : (aParentFrame->GetType() != nsGkAtoms::fieldSetFrame &&
3383 0 : aParentFrame->GetStyleContext()->GetPseudo() !=
3384 : nsCSSAnonBoxes::fieldsetContent) ||
3385 0 : !aElement->GetParent() ||
3386 0 : !aElement->GetParent()->IsHTML(nsGkAtoms::fieldset) ||
3387 0 : aStyleContext->GetStyleDisplay()->IsFloating() ||
3388 0 : aStyleContext->GetStyleDisplay()->IsAbsolutelyPositioned())) {
3389 : // <legend> is only special inside fieldset, check both the frame tree
3390 : // parent and content tree parent due to XBL issues. For floated or
3391 : // absolutely positioned legends we want to construct by display type and
3392 : // not do special legend stuff.
3393 : // XXXbz it would be nice if we could just decide this based on the parent
3394 : // tag, and hence just use a SIMPLE_TAG_CHAIN for legend below, but the
3395 : // fact that with XBL we could end up with this legend element in some
3396 : // totally weird insertion point makes that chancy, I think.
3397 0 : return nsnull;
3398 : }
3399 :
3400 : static const FrameConstructionDataByTag sHTMLData[] = {
3401 : SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData),
3402 : SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,
3403 : nsCSSFrameConstructor::FindImgData),
3404 : { &nsGkAtoms::br,
3405 : FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_LINE_BREAK,
3406 : NS_NewBRFrame) },
3407 : SIMPLE_TAG_CREATE(wbr, NS_NewWBRFrame),
3408 : SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData),
3409 : SIMPLE_TAG_CREATE(textarea, NS_NewTextControlFrame),
3410 : COMPLEX_TAG_CREATE(select, &nsCSSFrameConstructor::ConstructSelectFrame),
3411 : SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData),
3412 : SIMPLE_TAG_CHAIN(applet, nsCSSFrameConstructor::FindObjectData),
3413 : SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData),
3414 : COMPLEX_TAG_CREATE(fieldset,
3415 : &nsCSSFrameConstructor::ConstructFieldSetFrame),
3416 : { &nsGkAtoms::legend,
3417 : FCDATA_DECL(FCDATA_ALLOW_BLOCK_STYLES, NS_NewLegendFrame) },
3418 : SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame),
3419 : SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame),
3420 : { &nsGkAtoms::button,
3421 : FCDATA_WITH_WRAPPING_BLOCK(FCDATA_ALLOW_BLOCK_STYLES,
3422 : NS_NewHTMLButtonControlFrame,
3423 : nsCSSAnonBoxes::buttonContent) },
3424 : SIMPLE_TAG_CHAIN(canvas, nsCSSFrameConstructor::FindCanvasData),
3425 : #if defined(MOZ_MEDIA)
3426 : SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame),
3427 : SIMPLE_TAG_CREATE(audio, NS_NewHTMLVideoFrame),
3428 : #endif
3429 : SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame)
3430 : };
3431 :
3432 : return FindDataByTag(aTag, aElement, aStyleContext, sHTMLData,
3433 0 : ArrayLength(sHTMLData));
3434 : }
3435 :
3436 : /* static */
3437 : const nsCSSFrameConstructor::FrameConstructionData*
3438 0 : nsCSSFrameConstructor::FindImgData(Element* aElement,
3439 : nsStyleContext* aStyleContext)
3440 : {
3441 0 : if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyleContext)) {
3442 0 : return nsnull;
3443 : }
3444 :
3445 : static const FrameConstructionData sImgData = SIMPLE_FCDATA(NS_NewImageFrame);
3446 0 : return &sImgData;
3447 : }
3448 :
3449 : /* static */
3450 : const nsCSSFrameConstructor::FrameConstructionData*
3451 0 : nsCSSFrameConstructor::FindImgControlData(Element* aElement,
3452 : nsStyleContext* aStyleContext)
3453 : {
3454 0 : if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyleContext)) {
3455 0 : return nsnull;
3456 : }
3457 :
3458 : static const FrameConstructionData sImgControlData =
3459 : SIMPLE_FCDATA(NS_NewImageControlFrame);
3460 0 : return &sImgControlData;
3461 : }
3462 :
3463 : /* static */
3464 : const nsCSSFrameConstructor::FrameConstructionData*
3465 0 : nsCSSFrameConstructor::FindInputData(Element* aElement,
3466 : nsStyleContext* aStyleContext)
3467 : {
3468 : static const FrameConstructionDataByInt sInputData[] = {
3469 : SIMPLE_INT_CREATE(NS_FORM_INPUT_CHECKBOX, NS_NewGfxCheckboxControlFrame),
3470 : SIMPLE_INT_CREATE(NS_FORM_INPUT_RADIO, NS_NewGfxRadioControlFrame),
3471 : SIMPLE_INT_CREATE(NS_FORM_INPUT_FILE, NS_NewFileControlFrame),
3472 : SIMPLE_INT_CHAIN(NS_FORM_INPUT_IMAGE,
3473 : nsCSSFrameConstructor::FindImgControlData),
3474 : SIMPLE_INT_CREATE(NS_FORM_INPUT_EMAIL, NS_NewTextControlFrame),
3475 : SIMPLE_INT_CREATE(NS_FORM_INPUT_SEARCH, NS_NewTextControlFrame),
3476 : SIMPLE_INT_CREATE(NS_FORM_INPUT_TEXT, NS_NewTextControlFrame),
3477 : SIMPLE_INT_CREATE(NS_FORM_INPUT_TEL, NS_NewTextControlFrame),
3478 : SIMPLE_INT_CREATE(NS_FORM_INPUT_URL, NS_NewTextControlFrame),
3479 : SIMPLE_INT_CREATE(NS_FORM_INPUT_PASSWORD, NS_NewTextControlFrame),
3480 : { NS_FORM_INPUT_SUBMIT,
3481 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3482 : nsCSSAnonBoxes::buttonContent) },
3483 : { NS_FORM_INPUT_RESET,
3484 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3485 : nsCSSAnonBoxes::buttonContent) },
3486 : { NS_FORM_INPUT_BUTTON,
3487 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
3488 : nsCSSAnonBoxes::buttonContent) }
3489 : // Keeping hidden inputs out of here on purpose for so they get frames by
3490 : // display (in practice, none).
3491 : };
3492 :
3493 0 : nsCOMPtr<nsIFormControl> control = do_QueryInterface(aElement);
3494 0 : NS_ASSERTION(control, "input doesn't implement nsIFormControl?");
3495 :
3496 0 : return FindDataByInt(control->GetType(), aElement, aStyleContext,
3497 0 : sInputData, ArrayLength(sInputData));
3498 : }
3499 :
3500 : /* static */
3501 : const nsCSSFrameConstructor::FrameConstructionData*
3502 0 : nsCSSFrameConstructor::FindObjectData(Element* aElement,
3503 : nsStyleContext* aStyleContext)
3504 : {
3505 : // GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for
3506 : // cases when the object is broken/suppressed/etc (e.g. a broken image), but
3507 : // we want to treat those cases as TYPE_NULL
3508 : PRUint32 type;
3509 0 : if (aElement->State().HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN |
3510 : NS_EVENT_STATE_USERDISABLED |
3511 0 : NS_EVENT_STATE_SUPPRESSED)) {
3512 0 : type = nsIObjectLoadingContent::TYPE_NULL;
3513 : } else {
3514 0 : nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(aElement));
3515 0 : NS_ASSERTION(objContent,
3516 : "applet, embed and object must implement "
3517 : "nsIObjectLoadingContent!");
3518 :
3519 0 : objContent->GetDisplayedType(&type);
3520 : }
3521 :
3522 : static const FrameConstructionDataByInt sObjectData[] = {
3523 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING,
3524 : NS_NewEmptyFrame),
3525 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_PLUGIN,
3526 : NS_NewObjectFrame),
3527 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE,
3528 : NS_NewImageFrame),
3529 : SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT,
3530 : NS_NewSubDocumentFrame)
3531 : // Nothing for TYPE_NULL so we'll construct frames by display there
3532 : };
3533 :
3534 : return FindDataByInt((PRInt32)type, aElement, aStyleContext,
3535 0 : sObjectData, ArrayLength(sObjectData));
3536 : }
3537 :
3538 : /* static */
3539 : const nsCSSFrameConstructor::FrameConstructionData*
3540 0 : nsCSSFrameConstructor::FindCanvasData(Element* aElement,
3541 : nsStyleContext* aStyleContext)
3542 : {
3543 : // We want to check whether script is enabled on the document that
3544 : // could be painting to the canvas. That's the owner document of
3545 : // the canvas, except when the owner document is a static document,
3546 : // in which case it's the original document it was cloned from.
3547 0 : nsIDocument* doc = aElement->OwnerDoc();
3548 0 : if (doc->IsStaticDocument()) {
3549 0 : doc = doc->GetOriginalDocument();
3550 : }
3551 0 : if (!doc->IsScriptEnabled()) {
3552 0 : return nsnull;
3553 : }
3554 :
3555 : static const FrameConstructionData sCanvasData =
3556 : FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewHTMLCanvasFrame,
3557 : nsCSSAnonBoxes::htmlCanvasContent);
3558 0 : return &sCanvasData;
3559 : }
3560 :
3561 : nsresult
3562 0 : nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aItem,
3563 : nsFrameConstructorState& aState,
3564 : nsIFrame* aParentFrame,
3565 : nsFrameItems& aFrameItems)
3566 : {
3567 0 : const FrameConstructionData* data = aItem.mFCData;
3568 0 : NS_ASSERTION(data, "Must have frame construction data");
3569 :
3570 0 : PRUint32 bits = data->mBits;
3571 :
3572 0 : NS_ASSERTION(!(bits & FCDATA_FUNC_IS_DATA_GETTER),
3573 : "Should have dealt with this inside the data finder");
3574 :
3575 : // Some sets of bits are not compatible with each other
3576 : #define CHECK_ONLY_ONE_BIT(_bit1, _bit2) \
3577 : NS_ASSERTION(!(bits & _bit1) || !(bits & _bit2), \
3578 : "Only one of these bits should be set")
3579 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_FORCE_NULL_ABSPOS_CONTAINER);
3580 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_WRAP_KIDS_IN_BLOCKS);
3581 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_MAY_NEED_SCROLLFRAME);
3582 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_IS_POPUP);
3583 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_SKIP_ABSPOS_PUSH);
3584 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
3585 : FCDATA_DISALLOW_GENERATED_CONTENT);
3586 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_ALLOW_BLOCK_STYLES);
3587 0 : CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR,
3588 : FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
3589 0 : CHECK_ONLY_ONE_BIT(FCDATA_WRAP_KIDS_IN_BLOCKS,
3590 : FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
3591 : #undef CHECK_ONLY_ONE_BIT
3592 0 : NS_ASSERTION(!(bits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) ||
3593 : ((bits & FCDATA_FUNC_IS_FULL_CTOR) &&
3594 : data->mFullConstructor ==
3595 : &nsCSSFrameConstructor::ConstructNonScrollableBlock),
3596 : "Unexpected FCDATA_FORCED_NON_SCROLLABLE_BLOCK flag");
3597 :
3598 : // Don't create a subdocument frame for iframes if we're creating extra frames
3599 0 : if (aState.mCreatingExtraFrames && aItem.mContent->IsHTML() &&
3600 0 : aItem.mContent->Tag() == nsGkAtoms::iframe)
3601 : {
3602 0 : return NS_OK;
3603 : }
3604 :
3605 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
3606 0 : const nsStyleDisplay* display = styleContext->GetStyleDisplay();
3607 0 : nsIContent* const content = aItem.mContent;
3608 :
3609 : // Push the content as a style ancestor now, so we don't have to do
3610 : // it in our various full-constructor functions. In particular,
3611 : // since a number of full-constructor functions don't actually call
3612 : // ProcessChildren in some cases (e.g. for CSS anonymous table boxes
3613 : // or for situations where only anonymouse children are having
3614 : // frames constructed), this is the best place to bottleneck the
3615 : // pushing of the content instead of having to do it in multiple
3616 : // places.
3617 : AncestorFilter::AutoAncestorPusher
3618 0 : ancestorPusher(aState.mTreeMatchContext.mAncestorFilter.HasFilter(),
3619 : aState.mTreeMatchContext.mAncestorFilter,
3620 0 : content->IsElement() ? content->AsElement() : nsnull);
3621 :
3622 : nsIFrame* newFrame;
3623 : nsIFrame* primaryFrame;
3624 0 : if (bits & FCDATA_FUNC_IS_FULL_CTOR) {
3625 : nsresult rv =
3626 : (this->*(data->mFullConstructor))(aState, aItem, aParentFrame,
3627 0 : display, aFrameItems, &newFrame);
3628 0 : if (NS_FAILED(rv)) {
3629 0 : return rv;
3630 : }
3631 :
3632 0 : primaryFrame = newFrame;
3633 : } else {
3634 : newFrame =
3635 0 : (*data->mFunc.mCreationFunc)(mPresShell, styleContext);
3636 0 : if (!newFrame) {
3637 0 : return NS_ERROR_OUT_OF_MEMORY;
3638 : }
3639 :
3640 0 : bool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW);
3641 0 : bool isPopup = aItem.mIsPopup;
3642 0 : NS_ASSERTION(!isPopup ||
3643 : (aState.mPopupItems.containingBlock &&
3644 : aState.mPopupItems.containingBlock->GetType() ==
3645 : nsGkAtoms::popupSetFrame),
3646 : "Should have a containing block here!");
3647 :
3648 : nsIFrame* geometricParent =
3649 : isPopup ? aState.mPopupItems.containingBlock :
3650 : (allowOutOfFlow ? aState.GetGeometricParent(display, aParentFrame)
3651 0 : : aParentFrame);
3652 :
3653 0 : nsresult rv = NS_OK;
3654 :
3655 : // Must init frameToAddToList to null, since it's inout
3656 0 : nsIFrame* frameToAddToList = nsnull;
3657 0 : if ((bits & FCDATA_MAY_NEED_SCROLLFRAME) &&
3658 0 : display->IsScrollableOverflow()) {
3659 : BuildScrollFrame(aState, content, styleContext, newFrame,
3660 0 : geometricParent, frameToAddToList);
3661 : } else {
3662 : rv = InitAndRestoreFrame(aState, content, geometricParent, nsnull,
3663 0 : newFrame);
3664 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "InitAndRestoreFrame failed");
3665 : // See whether we need to create a view
3666 0 : nsContainerFrame::CreateViewForFrame(newFrame, false);
3667 0 : frameToAddToList = newFrame;
3668 : }
3669 :
3670 : // Use frameToAddToList as the primary frame. In the non-scrollframe case
3671 : // they're equal, but in the scrollframe case newFrame is the scrolled
3672 : // frame, while frameToAddToList is the scrollframe (and should be the
3673 : // primary frame).
3674 0 : primaryFrame = frameToAddToList;
3675 :
3676 : // If we need to create a block formatting context to wrap our
3677 : // kids, do it now.
3678 0 : const nsStyleDisplay* maybeAbsoluteContainingBlockDisplay = display;
3679 0 : nsIFrame* maybeAbsoluteContainingBlock = newFrame;
3680 0 : nsIFrame* possiblyLeafFrame = newFrame;
3681 0 : if (bits & FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS) {
3682 0 : nsRefPtr<nsStyleContext> blockContext;
3683 : blockContext =
3684 : mPresShell->StyleSet()->ResolveAnonymousBoxStyle(*data->mAnonBoxPseudo,
3685 0 : styleContext);
3686 : nsIFrame* blockFrame =
3687 0 : NS_NewBlockFormattingContext(mPresShell, blockContext);
3688 0 : if (NS_UNLIKELY(!blockFrame)) {
3689 0 : primaryFrame->Destroy();
3690 0 : return NS_ERROR_OUT_OF_MEMORY;
3691 : }
3692 :
3693 0 : rv = InitAndRestoreFrame(aState, content, newFrame, nsnull, blockFrame);
3694 0 : if (NS_FAILED(rv)) {
3695 0 : blockFrame->Destroy();
3696 0 : primaryFrame->Destroy();
3697 0 : return rv;
3698 : }
3699 :
3700 0 : SetInitialSingleChild(newFrame, blockFrame);
3701 :
3702 : // Now figure out whether newFrame or blockFrame should be the
3703 : // absolute container. It should be the latter if it's
3704 : // positioned, otherwise the former.
3705 0 : const nsStyleDisplay* blockDisplay = blockContext->GetStyleDisplay();
3706 0 : if (blockDisplay->IsPositioned()) {
3707 0 : maybeAbsoluteContainingBlockDisplay = blockDisplay;
3708 0 : maybeAbsoluteContainingBlock = blockFrame;
3709 : }
3710 :
3711 : // Our kids should go into the blockFrame
3712 0 : newFrame = blockFrame;
3713 : }
3714 :
3715 : rv = aState.AddChild(frameToAddToList, aFrameItems, content, styleContext,
3716 0 : aParentFrame, allowOutOfFlow, allowOutOfFlow, isPopup);
3717 0 : if (NS_FAILED(rv)) {
3718 0 : return rv;
3719 : }
3720 :
3721 : #ifdef MOZ_XUL
3722 : // Icky XUL stuff, sadly
3723 :
3724 0 : if (aItem.mIsRootPopupgroup) {
3725 0 : NS_ASSERTION(nsIRootBox::GetRootBox(mPresShell) &&
3726 : nsIRootBox::GetRootBox(mPresShell)->GetPopupSetFrame() ==
3727 : newFrame,
3728 : "Unexpected PopupSetFrame");
3729 0 : aState.mPopupItems.containingBlock = newFrame;
3730 0 : aState.mHavePendingPopupgroup = false;
3731 : }
3732 : #endif /* MOZ_XUL */
3733 :
3734 : // Process the child content if requested
3735 0 : nsFrameItems childItems;
3736 0 : nsFrameConstructorSaveState absoluteSaveState;
3737 :
3738 0 : if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER) {
3739 0 : aState.PushAbsoluteContainingBlock(nsnull, absoluteSaveState);
3740 0 : } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH) &&
3741 0 : maybeAbsoluteContainingBlockDisplay->IsPositioned()) {
3742 : aState.PushAbsoluteContainingBlock(maybeAbsoluteContainingBlock,
3743 0 : absoluteSaveState);
3744 : }
3745 :
3746 0 : if (bits & FCDATA_USE_CHILD_ITEMS) {
3747 : rv = ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
3748 0 : childItems);
3749 : } else {
3750 : // Process the child frames.
3751 : rv = ProcessChildren(aState, content, styleContext, newFrame,
3752 : !(bits & FCDATA_DISALLOW_GENERATED_CONTENT),
3753 : childItems,
3754 : (bits & FCDATA_ALLOW_BLOCK_STYLES) != 0,
3755 0 : aItem.mPendingBinding, possiblyLeafFrame);
3756 : }
3757 :
3758 : #ifdef MOZ_XUL
3759 : // More icky XUL stuff
3760 0 : if (aItem.mNameSpaceID == kNameSpaceID_XUL &&
3761 : (aItem.mTag == nsGkAtoms::treechildren || // trees always need titletips
3762 0 : content->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext) ||
3763 0 : content->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltip))) {
3764 0 : nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
3765 0 : if (rootBox) {
3766 0 : rootBox->AddTooltipSupport(content);
3767 : }
3768 : }
3769 : #endif
3770 :
3771 0 : if (NS_SUCCEEDED(rv) && (bits & FCDATA_WRAP_KIDS_IN_BLOCKS)) {
3772 0 : nsFrameItems newItems;
3773 0 : nsFrameItems currentBlock;
3774 : nsIFrame* f;
3775 0 : while ((f = childItems.FirstChild()) != nsnull) {
3776 0 : bool wrapFrame = IsInlineFrame(f) || IsFrameSpecial(f);
3777 0 : if (!wrapFrame) {
3778 0 : rv = FlushAccumulatedBlock(aState, content, newFrame, ¤tBlock, &newItems);
3779 0 : if (NS_FAILED(rv))
3780 0 : break;
3781 : }
3782 :
3783 0 : childItems.RemoveFrame(f);
3784 0 : if (wrapFrame) {
3785 0 : currentBlock.AddChild(f);
3786 : } else {
3787 0 : newItems.AddChild(f);
3788 : }
3789 : }
3790 0 : rv = FlushAccumulatedBlock(aState, content, newFrame, ¤tBlock, &newItems);
3791 :
3792 0 : if (childItems.NotEmpty()) {
3793 : // an error must have occurred, delete unprocessed frames
3794 0 : childItems.DestroyFrames();
3795 : }
3796 :
3797 0 : childItems = newItems;
3798 : }
3799 :
3800 : // Set the frame's initial child list
3801 : // Note that MathML depends on this being called even if
3802 : // childItems is empty!
3803 0 : newFrame->SetInitialChildList(kPrincipalList, childItems);
3804 : }
3805 :
3806 0 : NS_ASSERTION(newFrame->IsFrameOfType(nsIFrame::eLineParticipant) ==
3807 : ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0),
3808 : "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits");
3809 :
3810 : // Even if mCreatingExtraFrames is set, we may need to SetPrimaryFrame for
3811 : // generated content that doesn't have one yet. Note that we have to examine
3812 : // the frame bit, because by this point mIsGeneratedContent has been cleared
3813 : // on aItem.
3814 0 : if ((!aState.mCreatingExtraFrames ||
3815 0 : ((primaryFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) &&
3816 0 : !aItem.mContent->GetPrimaryFrame())) &&
3817 0 : !(bits & FCDATA_SKIP_FRAMESET)) {
3818 0 : aItem.mContent->SetPrimaryFrame(primaryFrame);
3819 : }
3820 :
3821 0 : return NS_OK;
3822 : }
3823 :
3824 : // after the node has been constructed and initialized create any
3825 : // anonymous content a node needs.
3826 : nsresult
3827 0 : nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState,
3828 : nsIContent* aParent,
3829 : nsIFrame* aParentFrame,
3830 : PendingBinding* aPendingBinding,
3831 : nsFrameItems& aChildItems)
3832 : {
3833 0 : nsAutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> newAnonymousItems;
3834 0 : nsresult rv = GetAnonymousContent(aParent, aParentFrame, newAnonymousItems);
3835 0 : NS_ENSURE_SUCCESS(rv, rv);
3836 :
3837 0 : PRUint32 count = newAnonymousItems.Length();
3838 0 : if (count == 0) {
3839 0 : return NS_OK;
3840 : }
3841 :
3842 : nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
3843 0 : aPendingBinding);
3844 : AncestorFilter::AutoAncestorPusher
3845 0 : ancestorPusher(aState.mTreeMatchContext.mAncestorFilter.HasFilter(),
3846 : aState.mTreeMatchContext.mAncestorFilter,
3847 0 : aParent->AsElement());
3848 :
3849 0 : nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
3850 0 : NS_ASSERTION(creator,
3851 : "How can that happen if we have nodes to construct frames for?");
3852 :
3853 0 : for (PRUint32 i=0; i < count; i++) {
3854 0 : nsIContent* content = newAnonymousItems[i].mContent;
3855 0 : NS_ASSERTION(content, "null anonymous content?");
3856 0 : NS_ASSERTION(!newAnonymousItems[i].mStyleContext, "Unexpected style context");
3857 :
3858 0 : nsIFrame* newFrame = creator->CreateFrameFor(content);
3859 0 : if (newFrame) {
3860 0 : NS_ASSERTION(content->GetPrimaryFrame(),
3861 : "Content must have a primary frame now");
3862 0 : aChildItems.AddChild(newFrame);
3863 : }
3864 : else {
3865 : // create the frame and attach it to our frame
3866 0 : ConstructFrame(aState, content, aParentFrame, aChildItems);
3867 : }
3868 : }
3869 :
3870 0 : return NS_OK;
3871 : }
3872 :
3873 : nsresult
3874 0 : nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
3875 : nsIFrame* aParentFrame,
3876 : nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent)
3877 : {
3878 0 : nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
3879 0 : if (!creator)
3880 0 : return NS_OK;
3881 :
3882 0 : nsresult rv = creator->CreateAnonymousContent(aContent);
3883 0 : NS_ENSURE_SUCCESS(rv, rv);
3884 :
3885 0 : PRUint32 count = aContent.Length();
3886 0 : for (PRUint32 i=0; i < count; i++) {
3887 : // get our child's content and set its parent to our content
3888 0 : nsIContent* content = aContent[i].mContent;
3889 0 : NS_ASSERTION(content, "null anonymous content?");
3890 :
3891 : // least-surprise CSS binding until we do the SVG specified
3892 : // cascading rules for <svg:use> - bug 265894
3893 0 : if (aParent &&
3894 0 : aParent->NodeInfo()->Equals(nsGkAtoms::use, kNameSpaceID_SVG)) {
3895 0 : content->SetFlags(NODE_IS_ANONYMOUS);
3896 : } else {
3897 0 : content->SetNativeAnonymous();
3898 : }
3899 :
3900 0 : rv = content->BindToTree(mDocument, aParent, aParent, true);
3901 0 : if (NS_FAILED(rv)) {
3902 0 : content->UnbindFromTree();
3903 0 : return rv;
3904 : }
3905 : }
3906 :
3907 0 : return NS_OK;
3908 : }
3909 :
3910 : static
3911 0 : bool IsXULDisplayType(const nsStyleDisplay* aDisplay)
3912 : {
3913 : return (aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_BOX ||
3914 : #ifdef MOZ_XUL
3915 : aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_GRID ||
3916 : aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_STACK ||
3917 : #endif
3918 : aDisplay->mDisplay == NS_STYLE_DISPLAY_BOX
3919 : #ifdef MOZ_XUL
3920 : || aDisplay->mDisplay == NS_STYLE_DISPLAY_GRID ||
3921 : aDisplay->mDisplay == NS_STYLE_DISPLAY_STACK ||
3922 : aDisplay->mDisplay == NS_STYLE_DISPLAY_GRID_GROUP ||
3923 : aDisplay->mDisplay == NS_STYLE_DISPLAY_GRID_LINE ||
3924 : aDisplay->mDisplay == NS_STYLE_DISPLAY_DECK ||
3925 : aDisplay->mDisplay == NS_STYLE_DISPLAY_POPUP ||
3926 : aDisplay->mDisplay == NS_STYLE_DISPLAY_GROUPBOX
3927 : #endif
3928 0 : );
3929 : }
3930 :
3931 :
3932 : // XUL frames are not allowed to be out of flow.
3933 : #define SIMPLE_XUL_FCDATA(_func) \
3934 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH, \
3935 : _func)
3936 : #define SCROLLABLE_XUL_FCDATA(_func) \
3937 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH | \
3938 : FCDATA_MAY_NEED_SCROLLFRAME, _func)
3939 : // .. but we allow some XUL frames to be _containers_ for out-of-flow content
3940 : // (This is the same as SCROLLABLE_XUL_FCDATA, but w/o FCDATA_SKIP_ABSPOS_PUSH)
3941 : #define SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func) \
3942 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \
3943 : FCDATA_MAY_NEED_SCROLLFRAME, _func)
3944 :
3945 : #define SIMPLE_XUL_CREATE(_tag, _func) \
3946 : { &nsGkAtoms::_tag, SIMPLE_XUL_FCDATA(_func) }
3947 : #define SCROLLABLE_XUL_CREATE(_tag, _func) \
3948 : { &nsGkAtoms::_tag, SCROLLABLE_XUL_FCDATA(_func) }
3949 : #define SIMPLE_XUL_INT_CREATE(_int, _func) \
3950 : { _int, SIMPLE_XUL_FCDATA(_func) }
3951 : #define SCROLLABLE_XUL_INT_CREATE(_int, _func) \
3952 : { _int, SCROLLABLE_XUL_FCDATA(_func) }
3953 : #define SCROLLABLE_ABSPOS_CONTAINER_XUL_INT_CREATE(_int, _func) \
3954 : { _int, SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func) }
3955 :
3956 : static
3957 0 : nsIFrame* NS_NewGridBoxFrame(nsIPresShell* aPresShell,
3958 : nsStyleContext* aStyleContext)
3959 : {
3960 0 : nsCOMPtr<nsBoxLayout> layout;
3961 0 : NS_NewGridLayout2(aPresShell, getter_AddRefs(layout));
3962 0 : if (!layout) {
3963 0 : return nsnull;
3964 : }
3965 :
3966 0 : return NS_NewBoxFrame(aPresShell, aStyleContext, false, layout);
3967 : }
3968 :
3969 : /* static */
3970 : const nsCSSFrameConstructor::FrameConstructionData*
3971 0 : nsCSSFrameConstructor::FindXULTagData(Element* aElement,
3972 : nsIAtom* aTag,
3973 : PRInt32 aNameSpaceID,
3974 : nsStyleContext* aStyleContext)
3975 : {
3976 0 : if (aNameSpaceID != kNameSpaceID_XUL) {
3977 0 : return nsnull;
3978 : }
3979 :
3980 : static const FrameConstructionDataByTag sXULTagData[] = {
3981 : #ifdef MOZ_XUL
3982 : SCROLLABLE_XUL_CREATE(button, NS_NewButtonBoxFrame),
3983 : SCROLLABLE_XUL_CREATE(checkbox, NS_NewButtonBoxFrame),
3984 : SCROLLABLE_XUL_CREATE(radio, NS_NewButtonBoxFrame),
3985 : SCROLLABLE_XUL_CREATE(autorepeatbutton, NS_NewAutoRepeatBoxFrame),
3986 : SCROLLABLE_XUL_CREATE(titlebar, NS_NewTitleBarFrame),
3987 : SCROLLABLE_XUL_CREATE(resizer, NS_NewResizerFrame),
3988 : SIMPLE_XUL_CREATE(image, NS_NewImageBoxFrame),
3989 : SIMPLE_XUL_CREATE(spring, NS_NewLeafBoxFrame),
3990 : SIMPLE_XUL_CREATE(spacer, NS_NewLeafBoxFrame),
3991 : SIMPLE_XUL_CREATE(treechildren, NS_NewTreeBodyFrame),
3992 : SIMPLE_XUL_CREATE(treecol, NS_NewTreeColFrame),
3993 : SIMPLE_XUL_CREATE(text, NS_NewTextBoxFrame),
3994 : SIMPLE_TAG_CHAIN(label, nsCSSFrameConstructor::FindXULLabelData),
3995 : SIMPLE_TAG_CHAIN(description, nsCSSFrameConstructor::FindXULDescriptionData),
3996 : SIMPLE_XUL_CREATE(menu, NS_NewMenuFrame),
3997 : SIMPLE_XUL_CREATE(menubutton, NS_NewMenuFrame),
3998 : SIMPLE_XUL_CREATE(menuitem, NS_NewMenuItemFrame),
3999 : #ifdef XP_MACOSX
4000 : SIMPLE_TAG_CHAIN(menubar, nsCSSFrameConstructor::FindXULMenubarData),
4001 : #else
4002 : SIMPLE_XUL_CREATE(menubar, NS_NewMenuBarFrame),
4003 : #endif /* XP_MACOSX */
4004 : SIMPLE_TAG_CHAIN(popupgroup, nsCSSFrameConstructor::FindPopupGroupData),
4005 : SIMPLE_XUL_CREATE(iframe, NS_NewSubDocumentFrame),
4006 : SIMPLE_XUL_CREATE(editor, NS_NewSubDocumentFrame),
4007 : SIMPLE_XUL_CREATE(browser, NS_NewSubDocumentFrame),
4008 : SIMPLE_XUL_CREATE(progressmeter, NS_NewProgressMeterFrame),
4009 : SIMPLE_XUL_CREATE(splitter, NS_NewSplitterFrame),
4010 : SIMPLE_TAG_CHAIN(listboxbody,
4011 : nsCSSFrameConstructor::FindXULListBoxBodyData),
4012 : SIMPLE_TAG_CHAIN(listitem, nsCSSFrameConstructor::FindXULListItemData),
4013 : #endif /* MOZ_XUL */
4014 : SIMPLE_XUL_CREATE(slider, NS_NewSliderFrame),
4015 : SIMPLE_XUL_CREATE(scrollbar, NS_NewScrollbarFrame),
4016 : SIMPLE_XUL_CREATE(scrollbarbutton, NS_NewScrollbarButtonFrame)
4017 : };
4018 :
4019 : return FindDataByTag(aTag, aElement, aStyleContext, sXULTagData,
4020 0 : ArrayLength(sXULTagData));
4021 : }
4022 :
4023 : #ifdef MOZ_XUL
4024 : /* static */
4025 : const nsCSSFrameConstructor::FrameConstructionData*
4026 0 : nsCSSFrameConstructor::FindPopupGroupData(Element* aElement,
4027 : nsStyleContext* /* unused */)
4028 : {
4029 0 : if (!aElement->IsRootOfNativeAnonymousSubtree()) {
4030 0 : return nsnull;
4031 : }
4032 :
4033 : static const FrameConstructionData sPopupSetData =
4034 : SIMPLE_XUL_FCDATA(NS_NewPopupSetFrame);
4035 0 : return &sPopupSetData;
4036 : }
4037 :
4038 : /* static */
4039 : const nsCSSFrameConstructor::FrameConstructionData
4040 : nsCSSFrameConstructor::sXULTextBoxData = SIMPLE_XUL_FCDATA(NS_NewTextBoxFrame);
4041 :
4042 : /* static */
4043 : const nsCSSFrameConstructor::FrameConstructionData*
4044 0 : nsCSSFrameConstructor::FindXULLabelData(Element* aElement,
4045 : nsStyleContext* /* unused */)
4046 : {
4047 0 : if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
4048 0 : return &sXULTextBoxData;
4049 : }
4050 :
4051 : static const FrameConstructionData sLabelData =
4052 : SIMPLE_XUL_FCDATA(NS_NewXULLabelFrame);
4053 0 : return &sLabelData;
4054 : }
4055 :
4056 : static nsIFrame*
4057 0 : NS_NewXULDescriptionFrame(nsIPresShell* aPresShell, nsStyleContext *aContext)
4058 : {
4059 : // XXXbz do we really need to set those flags? If the parent is not
4060 : // a block we'll get them anyway, and if it is, do we want them?
4061 : return NS_NewBlockFrame(aPresShell, aContext,
4062 0 : NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT);
4063 : }
4064 :
4065 : /* static */
4066 : const nsCSSFrameConstructor::FrameConstructionData*
4067 0 : nsCSSFrameConstructor::FindXULDescriptionData(Element* aElement,
4068 : nsStyleContext* /* unused */)
4069 : {
4070 0 : if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
4071 0 : return &sXULTextBoxData;
4072 : }
4073 :
4074 : static const FrameConstructionData sDescriptionData =
4075 : SIMPLE_XUL_FCDATA(NS_NewXULDescriptionFrame);
4076 0 : return &sDescriptionData;
4077 : }
4078 :
4079 : #ifdef XP_MACOSX
4080 : /* static */
4081 : const nsCSSFrameConstructor::FrameConstructionData*
4082 : nsCSSFrameConstructor::FindXULMenubarData(Element* aElement,
4083 : nsStyleContext* aStyleContext)
4084 : {
4085 : nsCOMPtr<nsISupports> container =
4086 : aStyleContext->PresContext()->GetContainer();
4087 : if (container) {
4088 : nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(container));
4089 : if (treeItem) {
4090 : PRInt32 type;
4091 : treeItem->GetItemType(&type);
4092 : if (nsIDocShellTreeItem::typeChrome == type) {
4093 : nsCOMPtr<nsIDocShellTreeItem> parent;
4094 : treeItem->GetParent(getter_AddRefs(parent));
4095 : if (!parent) {
4096 : // This is the root. Suppress the menubar, since on Mac
4097 : // window menus are not attached to the window.
4098 : static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
4099 : return &sSuppressData;
4100 : }
4101 : }
4102 : }
4103 : }
4104 :
4105 : static const FrameConstructionData sMenubarData =
4106 : SIMPLE_XUL_FCDATA(NS_NewMenuBarFrame);
4107 : return &sMenubarData;
4108 : }
4109 : #endif /* XP_MACOSX */
4110 :
4111 : /* static */
4112 : const nsCSSFrameConstructor::FrameConstructionData*
4113 0 : nsCSSFrameConstructor::FindXULListBoxBodyData(Element* aElement,
4114 : nsStyleContext* aStyleContext)
4115 : {
4116 0 : if (aStyleContext->GetStyleDisplay()->mDisplay !=
4117 : NS_STYLE_DISPLAY_GRID_GROUP) {
4118 0 : return nsnull;
4119 : }
4120 :
4121 : static const FrameConstructionData sListBoxBodyData =
4122 : SCROLLABLE_XUL_FCDATA(NS_NewListBoxBodyFrame);
4123 0 : return &sListBoxBodyData;
4124 : }
4125 :
4126 : /* static */
4127 : const nsCSSFrameConstructor::FrameConstructionData*
4128 0 : nsCSSFrameConstructor::FindXULListItemData(Element* aElement,
4129 : nsStyleContext* aStyleContext)
4130 : {
4131 0 : if (aStyleContext->GetStyleDisplay()->mDisplay !=
4132 : NS_STYLE_DISPLAY_GRID_LINE) {
4133 0 : return nsnull;
4134 : }
4135 :
4136 : static const FrameConstructionData sListItemData =
4137 : SCROLLABLE_XUL_FCDATA(NS_NewListItemFrame);
4138 0 : return &sListItemData;
4139 : }
4140 :
4141 : #endif /* MOZ_XUL */
4142 :
4143 : /* static */
4144 : const nsCSSFrameConstructor::FrameConstructionData*
4145 0 : nsCSSFrameConstructor::FindXULDisplayData(const nsStyleDisplay* aDisplay,
4146 : Element* aElement,
4147 : nsStyleContext* aStyleContext)
4148 : {
4149 : static const FrameConstructionDataByInt sXULDisplayData[] = {
4150 : SCROLLABLE_ABSPOS_CONTAINER_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_BOX,
4151 : NS_NewBoxFrame),
4152 : SCROLLABLE_ABSPOS_CONTAINER_XUL_INT_CREATE(NS_STYLE_DISPLAY_BOX,
4153 : NS_NewBoxFrame),
4154 : #ifdef MOZ_XUL
4155 : SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_GRID, NS_NewGridBoxFrame),
4156 : SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GRID, NS_NewGridBoxFrame),
4157 : SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GRID_GROUP,
4158 : NS_NewGridRowGroupFrame),
4159 : SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GRID_LINE,
4160 : NS_NewGridRowLeafFrame),
4161 : SIMPLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_DECK, NS_NewDeckFrame),
4162 : SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GROUPBOX, NS_NewGroupBoxFrame),
4163 : SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_STACK, NS_NewStackFrame),
4164 : SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_STACK, NS_NewStackFrame),
4165 : { NS_STYLE_DISPLAY_POPUP,
4166 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_IS_POPUP |
4167 : FCDATA_SKIP_ABSPOS_PUSH, NS_NewMenuPopupFrame) }
4168 : #endif /* MOZ_XUL */
4169 : };
4170 :
4171 : // Processing by display here:
4172 : return FindDataByInt(aDisplay->mDisplay, aElement, aStyleContext,
4173 0 : sXULDisplayData, ArrayLength(sXULDisplayData));
4174 : }
4175 :
4176 : already_AddRefed<nsStyleContext>
4177 0 : nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState& aState,
4178 : nsIContent* aContent,
4179 : nsStyleContext* aContentStyle,
4180 : nsIFrame* aParentFrame,
4181 : nsIAtom* aScrolledPseudo,
4182 : bool aIsRoot,
4183 : nsIFrame*& aNewFrame)
4184 : {
4185 0 : nsIFrame* gfxScrollFrame = aNewFrame;
4186 :
4187 0 : nsFrameItems anonymousItems;
4188 :
4189 0 : nsRefPtr<nsStyleContext> contentStyle = aContentStyle;
4190 :
4191 0 : if (!gfxScrollFrame) {
4192 : // Build a XULScrollFrame when the child is a box, otherwise an
4193 : // HTMLScrollFrame
4194 : // XXXbz this is the lone remaining consumer of IsXULDisplayType.
4195 : // I wonder whether we can eliminate that somehow.
4196 0 : if (IsXULDisplayType(aContentStyle->GetStyleDisplay())) {
4197 0 : gfxScrollFrame = NS_NewXULScrollFrame(mPresShell, contentStyle, aIsRoot);
4198 : } else {
4199 0 : gfxScrollFrame = NS_NewHTMLScrollFrame(mPresShell, contentStyle, aIsRoot);
4200 : }
4201 :
4202 0 : InitAndRestoreFrame(aState, aContent, aParentFrame, nsnull, gfxScrollFrame);
4203 : }
4204 :
4205 : // if there are any anonymous children for the scroll frame, create
4206 : // frames for them.
4207 : // Pass a null pending binding: we don't care how constructors for any of
4208 : // this anonymous content order with anything else. It's never been
4209 : // consistent anyway.
4210 : CreateAnonymousFrames(aState, aContent, gfxScrollFrame, nsnull,
4211 0 : anonymousItems);
4212 :
4213 0 : aNewFrame = gfxScrollFrame;
4214 :
4215 : // we used the style that was passed in. So resolve another one.
4216 0 : nsStyleSet *styleSet = mPresShell->StyleSet();
4217 : nsStyleContext* aScrolledChildStyle =
4218 0 : styleSet->ResolveAnonymousBoxStyle(aScrolledPseudo, contentStyle).get();
4219 :
4220 0 : if (gfxScrollFrame) {
4221 0 : gfxScrollFrame->SetInitialChildList(kPrincipalList, anonymousItems);
4222 : }
4223 :
4224 0 : return aScrolledChildStyle;
4225 : }
4226 :
4227 : void
4228 0 : nsCSSFrameConstructor::FinishBuildingScrollFrame(nsIFrame* aScrollFrame,
4229 : nsIFrame* aScrolledFrame)
4230 : {
4231 0 : nsFrameList scrolled(aScrolledFrame, aScrolledFrame);
4232 0 : aScrollFrame->AppendFrames(kPrincipalList, scrolled);
4233 0 : }
4234 :
4235 :
4236 : /**
4237 : * Called to wrap a gfx scrollframe around a frame. The hierarchy will look like this
4238 : *
4239 : * ------- for gfx scrollbars ------
4240 : *
4241 : *
4242 : * ScrollFrame
4243 : * ^
4244 : * |
4245 : * Frame (scrolled frame you passed in)
4246 : *
4247 : *
4248 : *-----------------------------------
4249 : * LEGEND:
4250 : *
4251 : * ScrollFrame: This is a frame that manages gfx cross platform frame based scrollbars.
4252 : *
4253 : * @param aContent the content node of the child to wrap.
4254 : * @param aScrolledFrame The frame of the content to wrap. This should not be
4255 : * Initialized. This method will initialize it with a scrolled pseudo
4256 : * and no nsIContent. The content will be attached to the scrollframe
4257 : * returned.
4258 : * @param aContentStyle the style context that has already been resolved for the content being passed in.
4259 : *
4260 : * @param aParentFrame The parent to attach the scroll frame to
4261 : *
4262 : * @param aNewFrame The new scrollframe or gfx scrollframe that we create. It will contain the
4263 : * scrolled frame you passed in. (returned)
4264 : * If this is not null, we'll just use it
4265 : * @param aScrolledContentStyle the style that was resolved for the scrolled frame. (returned)
4266 : */
4267 : nsresult
4268 0 : nsCSSFrameConstructor::BuildScrollFrame(nsFrameConstructorState& aState,
4269 : nsIContent* aContent,
4270 : nsStyleContext* aContentStyle,
4271 : nsIFrame* aScrolledFrame,
4272 : nsIFrame* aParentFrame,
4273 : nsIFrame*& aNewFrame)
4274 : {
4275 : nsRefPtr<nsStyleContext> scrolledContentStyle =
4276 : BeginBuildingScrollFrame(aState, aContent, aContentStyle, aParentFrame,
4277 : nsCSSAnonBoxes::scrolledContent,
4278 0 : false, aNewFrame);
4279 :
4280 0 : aScrolledFrame->SetStyleContextWithoutNotification(scrolledContentStyle);
4281 0 : InitAndRestoreFrame(aState, aContent, aNewFrame, nsnull, aScrolledFrame);
4282 :
4283 0 : FinishBuildingScrollFrame(aNewFrame, aScrolledFrame);
4284 0 : return NS_OK;
4285 : }
4286 :
4287 : const nsCSSFrameConstructor::FrameConstructionData*
4288 0 : nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
4289 : Element* aElement,
4290 : nsStyleContext* aStyleContext)
4291 : {
4292 : PR_STATIC_ASSERT(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET)));
4293 :
4294 : // The style system ensures that floated and positioned frames are
4295 : // block-level.
4296 0 : NS_ASSERTION(!(aDisplay->IsFloating() ||
4297 : aDisplay->IsAbsolutelyPositioned()) ||
4298 : aDisplay->IsBlockOutside(),
4299 : "Style system did not apply CSS2.1 section 9.7 fixups");
4300 :
4301 : // If this is "body", try propagating its scroll style to the viewport
4302 : // Note that we need to do this even if the body is NOT scrollable;
4303 : // it might have dynamically changed from scrollable to not scrollable,
4304 : // and that might need to be propagated.
4305 : // XXXbz is this the right place to do this? If this code moves,
4306 : // make this function static.
4307 0 : bool propagatedScrollToViewport = false;
4308 0 : if (aElement->IsHTML(nsGkAtoms::body)) {
4309 : propagatedScrollToViewport =
4310 0 : PropagateScrollToViewport() == aElement;
4311 : }
4312 :
4313 0 : NS_ASSERTION(!propagatedScrollToViewport ||
4314 : !mPresShell->GetPresContext()->IsPaginated(),
4315 : "Shouldn't propagate scroll in paginated contexts");
4316 :
4317 : // If the frame is a block-level frame and is scrollable, then wrap it in a
4318 : // scroll frame.
4319 : // XXX Ignore tables for the time being
4320 : // XXXbz it would be nice to combine this with the other block
4321 : // case... Think about how do do this?
4322 0 : if (aDisplay->IsBlockInside() &&
4323 0 : aDisplay->IsScrollableOverflow() &&
4324 0 : !propagatedScrollToViewport) {
4325 : // Except we don't want to do that for paginated contexts for
4326 : // frames that are block-outside and aren't frames for native
4327 : // anonymous stuff.
4328 0 : if (mPresShell->GetPresContext()->IsPaginated() &&
4329 0 : aDisplay->IsBlockOutside() &&
4330 0 : !aElement->IsInNativeAnonymousSubtree()) {
4331 : static const FrameConstructionData sForcedNonScrollableBlockData =
4332 : FULL_CTOR_FCDATA(FCDATA_FORCED_NON_SCROLLABLE_BLOCK,
4333 : &nsCSSFrameConstructor::ConstructNonScrollableBlock);
4334 0 : return &sForcedNonScrollableBlockData;
4335 : }
4336 :
4337 : static const FrameConstructionData sScrollableBlockData =
4338 : FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructScrollableBlock);
4339 0 : return &sScrollableBlockData;
4340 : }
4341 :
4342 : // Handle various non-scrollable blocks
4343 0 : if (aDisplay->IsBlockInside()) {
4344 : static const FrameConstructionData sNonScrollableBlockData =
4345 : FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructNonScrollableBlock);
4346 0 : return &sNonScrollableBlockData;
4347 : }
4348 :
4349 : static const FrameConstructionDataByInt sDisplayData[] = {
4350 : // To keep the hash table small don't add inline frames (they're
4351 : // typically things like FONT and B), because we can quickly
4352 : // find them if we need to.
4353 : // XXXbz the "quickly" part is a bald-faced lie!
4354 : { NS_STYLE_DISPLAY_INLINE,
4355 : FULL_CTOR_FCDATA(FCDATA_IS_INLINE | FCDATA_IS_LINE_PARTICIPANT,
4356 : &nsCSSFrameConstructor::ConstructInline) },
4357 : { NS_STYLE_DISPLAY_TABLE,
4358 : FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable) },
4359 : { NS_STYLE_DISPLAY_INLINE_TABLE,
4360 : FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable) },
4361 : { NS_STYLE_DISPLAY_TABLE_CAPTION,
4362 : FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_ALLOW_BLOCK_STYLES |
4363 : FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH |
4364 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4365 : NS_NewTableCaptionFrame) },
4366 : { NS_STYLE_DISPLAY_TABLE_ROW_GROUP,
4367 : FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW |
4368 : FCDATA_SKIP_ABSPOS_PUSH |
4369 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4370 : NS_NewTableRowGroupFrame) },
4371 : { NS_STYLE_DISPLAY_TABLE_HEADER_GROUP,
4372 : FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW |
4373 : FCDATA_SKIP_ABSPOS_PUSH |
4374 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4375 : NS_NewTableRowGroupFrame) },
4376 : { NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP,
4377 : FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW |
4378 : FCDATA_SKIP_ABSPOS_PUSH |
4379 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4380 : NS_NewTableRowGroupFrame) },
4381 : { NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP,
4382 : FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW |
4383 : FCDATA_SKIP_ABSPOS_PUSH |
4384 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
4385 : NS_NewTableColGroupFrame) },
4386 : { NS_STYLE_DISPLAY_TABLE_COLUMN,
4387 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4388 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeColGroup),
4389 : &nsCSSFrameConstructor::ConstructTableCol) },
4390 : { NS_STYLE_DISPLAY_TABLE_ROW,
4391 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4392 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup),
4393 : &nsCSSFrameConstructor::ConstructTableRow) },
4394 : { NS_STYLE_DISPLAY_TABLE_CELL,
4395 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
4396 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow),
4397 : &nsCSSFrameConstructor::ConstructTableCell) }
4398 : };
4399 :
4400 : return FindDataByInt(aDisplay->mDisplay, aElement, aStyleContext,
4401 0 : sDisplayData, ArrayLength(sDisplayData));
4402 : }
4403 :
4404 : nsresult
4405 0 : nsCSSFrameConstructor::ConstructScrollableBlock(nsFrameConstructorState& aState,
4406 : FrameConstructionItem& aItem,
4407 : nsIFrame* aParentFrame,
4408 : const nsStyleDisplay* aDisplay,
4409 : nsFrameItems& aFrameItems,
4410 : nsIFrame** aNewFrame)
4411 : {
4412 0 : nsIContent* const content = aItem.mContent;
4413 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
4414 :
4415 0 : *aNewFrame = nsnull;
4416 : nsRefPtr<nsStyleContext> scrolledContentStyle
4417 : = BeginBuildingScrollFrame(aState, content, styleContext,
4418 : aState.GetGeometricParent(aDisplay, aParentFrame),
4419 : nsCSSAnonBoxes::scrolledContent,
4420 0 : false, *aNewFrame);
4421 :
4422 : // Create our block frame
4423 : // pass a temporary stylecontext, the correct one will be set later
4424 : nsIFrame* scrolledFrame =
4425 0 : NS_NewBlockFormattingContext(mPresShell, styleContext);
4426 :
4427 0 : nsFrameItems blockItem;
4428 : nsresult rv = ConstructBlock(aState,
4429 : scrolledContentStyle->GetStyleDisplay(), content,
4430 : *aNewFrame, *aNewFrame, scrolledContentStyle,
4431 0 : &scrolledFrame, blockItem, aDisplay->IsPositioned(),
4432 0 : aItem.mPendingBinding);
4433 0 : if (NS_UNLIKELY(NS_FAILED(rv))) {
4434 : // XXXbz any cleanup needed here?
4435 0 : return rv;
4436 : }
4437 :
4438 0 : NS_ASSERTION(blockItem.FirstChild() == scrolledFrame,
4439 : "Scrollframe's frameItems should be exactly the scrolled frame");
4440 0 : FinishBuildingScrollFrame(*aNewFrame, scrolledFrame);
4441 :
4442 : rv = aState.AddChild(*aNewFrame, aFrameItems, content, styleContext,
4443 0 : aParentFrame);
4444 0 : return rv;
4445 : }
4446 :
4447 : nsresult
4448 0 : nsCSSFrameConstructor::ConstructNonScrollableBlock(nsFrameConstructorState& aState,
4449 : FrameConstructionItem& aItem,
4450 : nsIFrame* aParentFrame,
4451 : const nsStyleDisplay* aDisplay,
4452 : nsFrameItems& aFrameItems,
4453 : nsIFrame** aNewFrame)
4454 : {
4455 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
4456 :
4457 : // We want a block formatting context root in paginated contexts for
4458 : // every block that would be scrollable in a non-paginated context.
4459 : // We mark our blocks with a bit here if this condition is true, so
4460 : // we can check it later in nsFrame::ApplyPaginatedOverflowClipping.
4461 : bool clipPaginatedOverflow =
4462 0 : (aItem.mFCData->mBits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) != 0;
4463 0 : if (aDisplay->IsAbsolutelyPositioned() ||
4464 0 : aDisplay->IsFloating() ||
4465 : NS_STYLE_DISPLAY_INLINE_BLOCK == aDisplay->mDisplay ||
4466 : clipPaginatedOverflow) {
4467 0 : *aNewFrame = NS_NewBlockFormattingContext(mPresShell, styleContext);
4468 0 : if (clipPaginatedOverflow) {
4469 0 : (*aNewFrame)->AddStateBits(NS_BLOCK_CLIP_PAGINATED_OVERFLOW);
4470 : }
4471 : } else {
4472 0 : *aNewFrame = NS_NewBlockFrame(mPresShell, styleContext);
4473 : }
4474 :
4475 : return ConstructBlock(aState, aDisplay, aItem.mContent,
4476 : aState.GetGeometricParent(aDisplay, aParentFrame),
4477 : aParentFrame, styleContext, aNewFrame,
4478 0 : aFrameItems, aDisplay->IsPositioned(),
4479 0 : aItem.mPendingBinding);
4480 : }
4481 :
4482 :
4483 : nsresult
4484 0 : nsCSSFrameConstructor::InitAndRestoreFrame(const nsFrameConstructorState& aState,
4485 : nsIContent* aContent,
4486 : nsIFrame* aParentFrame,
4487 : nsIFrame* aPrevInFlow,
4488 : nsIFrame* aNewFrame,
4489 : bool aAllowCounters)
4490 : {
4491 0 : NS_PRECONDITION(mUpdateCount != 0,
4492 : "Should be in an update while creating frames");
4493 :
4494 0 : nsresult rv = NS_OK;
4495 :
4496 0 : NS_ASSERTION(aNewFrame, "Null frame cannot be initialized");
4497 0 : if (!aNewFrame)
4498 0 : return NS_ERROR_NULL_POINTER;
4499 :
4500 : // Initialize the frame
4501 0 : rv = aNewFrame->Init(aContent, aParentFrame, aPrevInFlow);
4502 0 : aNewFrame->AddStateBits(aState.mAdditionalStateBits);
4503 :
4504 0 : if (aState.mFrameState) {
4505 : // Restore frame state for just the newly created frame.
4506 0 : RestoreFrameStateFor(aNewFrame, aState.mFrameState);
4507 : }
4508 :
4509 0 : if (aAllowCounters && !aPrevInFlow &&
4510 0 : mCounterManager.AddCounterResetsAndIncrements(aNewFrame)) {
4511 0 : CountersDirty();
4512 : }
4513 :
4514 0 : return rv;
4515 : }
4516 :
4517 : already_AddRefed<nsStyleContext>
4518 0 : nsCSSFrameConstructor::ResolveStyleContext(nsIFrame* aParentFrame,
4519 : nsIContent* aContent,
4520 : nsFrameConstructorState* aState)
4521 : {
4522 0 : nsStyleContext* parentStyleContext = nsnull;
4523 0 : NS_ASSERTION(aContent->GetParent(), "Must have parent here");
4524 :
4525 0 : aParentFrame = nsFrame::CorrectStyleParentFrame(aParentFrame, nsnull);
4526 :
4527 0 : if (aParentFrame) {
4528 : // Resolve the style context based on the content object and the parent
4529 : // style context
4530 0 : parentStyleContext = aParentFrame->GetStyleContext();
4531 : } else {
4532 : // Perhaps aParentFrame is a canvasFrame and we're replicating
4533 : // fixed-pos frames.
4534 : // XXX should we create a way to tell ConstructFrame which style
4535 : // context to use, and pass it the style context for the
4536 : // previous page's fixed-pos frame?
4537 : }
4538 :
4539 0 : return ResolveStyleContext(parentStyleContext, aContent, aState);
4540 : }
4541 :
4542 : already_AddRefed<nsStyleContext>
4543 0 : nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext* aParentStyleContext,
4544 : nsIContent* aContent,
4545 : nsFrameConstructorState* aState)
4546 : {
4547 0 : nsStyleSet *styleSet = mPresShell->StyleSet();
4548 0 : aContent->OwnerDoc()->FlushPendingLinkUpdates();
4549 :
4550 0 : if (aContent->IsElement()) {
4551 0 : if (aState) {
4552 : return styleSet->ResolveStyleFor(aContent->AsElement(),
4553 : aParentStyleContext,
4554 0 : aState->mTreeMatchContext);
4555 : }
4556 0 : return styleSet->ResolveStyleFor(aContent->AsElement(), aParentStyleContext);
4557 :
4558 : }
4559 :
4560 0 : NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
4561 : "shouldn't waste time creating style contexts for "
4562 : "comments and processing instructions");
4563 :
4564 0 : return styleSet->ResolveStyleForNonElement(aParentStyleContext);
4565 : }
4566 :
4567 : // MathML Mod - RBS
4568 : nsresult
4569 0 : nsCSSFrameConstructor::FlushAccumulatedBlock(nsFrameConstructorState& aState,
4570 : nsIContent* aContent,
4571 : nsIFrame* aParentFrame,
4572 : nsFrameItems* aBlockItems,
4573 : nsFrameItems* aNewItems)
4574 : {
4575 0 : if (aBlockItems->IsEmpty()) {
4576 : // Nothing to do
4577 0 : return NS_OK;
4578 : }
4579 :
4580 : nsStyleContext* parentContext =
4581 : nsFrame::CorrectStyleParentFrame(aParentFrame,
4582 0 : nsCSSAnonBoxes::mozMathMLAnonymousBlock)->GetStyleContext();
4583 0 : nsStyleSet *styleSet = mPresShell->StyleSet();
4584 0 : nsRefPtr<nsStyleContext> blockContext;
4585 : blockContext = styleSet->
4586 : ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozMathMLAnonymousBlock,
4587 0 : parentContext);
4588 :
4589 : // then, create a block frame that will wrap the child frames. Make it a
4590 : // MathML frame so that Get(Absolute/Float)ContainingBlockFor know that this
4591 : // is not a suitable block.
4592 : nsIFrame* blockFrame = NS_NewMathMLmathBlockFrame(mPresShell, blockContext,
4593 0 : NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT);
4594 0 : if (NS_UNLIKELY(!blockFrame))
4595 0 : return NS_ERROR_OUT_OF_MEMORY;
4596 :
4597 0 : InitAndRestoreFrame(aState, aContent, aParentFrame, nsnull, blockFrame);
4598 0 : ReparentFrames(this, blockFrame, *aBlockItems);
4599 : // abs-pos and floats are disabled in MathML children so we don't have to
4600 : // worry about messing up those.
4601 0 : blockFrame->SetInitialChildList(kPrincipalList, *aBlockItems);
4602 0 : NS_ASSERTION(aBlockItems->IsEmpty(), "What happened?");
4603 0 : aBlockItems->Clear();
4604 0 : aNewItems->AddChild(blockFrame);
4605 0 : return NS_OK;
4606 : }
4607 :
4608 : // Only <math> elements can be floated or positioned. All other MathML
4609 : // should be in-flow.
4610 : #define SIMPLE_MATHML_CREATE(_tag, _func) \
4611 : { &nsGkAtoms::_tag, \
4612 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \
4613 : FCDATA_FORCE_NULL_ABSPOS_CONTAINER | \
4614 : FCDATA_WRAP_KIDS_IN_BLOCKS, _func) }
4615 :
4616 : /* static */
4617 : const nsCSSFrameConstructor::FrameConstructionData*
4618 0 : nsCSSFrameConstructor::FindMathMLData(Element* aElement,
4619 : nsIAtom* aTag,
4620 : PRInt32 aNameSpaceID,
4621 : nsStyleContext* aStyleContext)
4622 : {
4623 : // Make sure that we remain confined in the MathML world
4624 0 : if (aNameSpaceID != kNameSpaceID_MathML)
4625 0 : return nsnull;
4626 :
4627 : // Handle <math> specially, because it sometimes produces inlines
4628 0 : if (aTag == nsGkAtoms::math) {
4629 : // This needs to match the test in EnsureBlockDisplay in
4630 : // nsRuleNode.cpp. Though the behavior here for the display:table
4631 : // case is pretty weird...
4632 0 : if (aStyleContext->GetStyleDisplay()->IsBlockOutside()) {
4633 : static const FrameConstructionData sBlockMathData =
4634 : FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER |
4635 : FCDATA_WRAP_KIDS_IN_BLOCKS,
4636 : NS_CreateNewMathMLmathBlockFrame);
4637 0 : return &sBlockMathData;
4638 : }
4639 :
4640 : static const FrameConstructionData sInlineMathData =
4641 : FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER |
4642 : FCDATA_IS_LINE_PARTICIPANT |
4643 : FCDATA_WRAP_KIDS_IN_BLOCKS,
4644 : NS_NewMathMLmathInlineFrame);
4645 0 : return &sInlineMathData;
4646 : }
4647 :
4648 :
4649 : static const FrameConstructionDataByTag sMathMLData[] = {
4650 : SIMPLE_MATHML_CREATE(mi_, NS_NewMathMLTokenFrame),
4651 : SIMPLE_MATHML_CREATE(mn_, NS_NewMathMLTokenFrame),
4652 : SIMPLE_MATHML_CREATE(ms_, NS_NewMathMLTokenFrame),
4653 : SIMPLE_MATHML_CREATE(mtext_, NS_NewMathMLTokenFrame),
4654 : SIMPLE_MATHML_CREATE(mo_, NS_NewMathMLmoFrame),
4655 : SIMPLE_MATHML_CREATE(mfrac_, NS_NewMathMLmfracFrame),
4656 : SIMPLE_MATHML_CREATE(msup_, NS_NewMathMLmsupFrame),
4657 : SIMPLE_MATHML_CREATE(msub_, NS_NewMathMLmsubFrame),
4658 : SIMPLE_MATHML_CREATE(msubsup_, NS_NewMathMLmsubsupFrame),
4659 : SIMPLE_MATHML_CREATE(munder_, NS_NewMathMLmunderoverFrame),
4660 : SIMPLE_MATHML_CREATE(mover_, NS_NewMathMLmunderoverFrame),
4661 : SIMPLE_MATHML_CREATE(munderover_, NS_NewMathMLmunderoverFrame),
4662 : SIMPLE_MATHML_CREATE(mphantom_, NS_NewMathMLmphantomFrame),
4663 : SIMPLE_MATHML_CREATE(mpadded_, NS_NewMathMLmpaddedFrame),
4664 : SIMPLE_MATHML_CREATE(mspace_, NS_NewMathMLmspaceFrame),
4665 : SIMPLE_MATHML_CREATE(none, NS_NewMathMLmspaceFrame),
4666 : SIMPLE_MATHML_CREATE(mprescripts_, NS_NewMathMLmspaceFrame),
4667 : SIMPLE_MATHML_CREATE(mfenced_, NS_NewMathMLmfencedFrame),
4668 : SIMPLE_MATHML_CREATE(mmultiscripts_, NS_NewMathMLmmultiscriptsFrame),
4669 : SIMPLE_MATHML_CREATE(mstyle_, NS_NewMathMLmstyleFrame),
4670 : SIMPLE_MATHML_CREATE(msqrt_, NS_NewMathMLmsqrtFrame),
4671 : SIMPLE_MATHML_CREATE(mroot_, NS_NewMathMLmrootFrame),
4672 : SIMPLE_MATHML_CREATE(maction_, NS_NewMathMLmactionFrame),
4673 : SIMPLE_MATHML_CREATE(mrow_, NS_NewMathMLmrowFrame),
4674 : SIMPLE_MATHML_CREATE(merror_, NS_NewMathMLmrowFrame),
4675 : SIMPLE_MATHML_CREATE(menclose_, NS_NewMathMLmencloseFrame),
4676 : SIMPLE_MATHML_CREATE(semantics_, NS_NewMathMLsemanticsFrame)
4677 : };
4678 :
4679 : return FindDataByTag(aTag, aElement, aStyleContext, sMathMLData,
4680 0 : ArrayLength(sMathMLData));
4681 : }
4682 :
4683 : // Only outer <svg> elements can be floated or positioned. All other SVG
4684 : // should be in-flow.
4685 : #define SIMPLE_SVG_FCDATA(_func) \
4686 : FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \
4687 : FCDATA_SKIP_ABSPOS_PUSH | \
4688 : FCDATA_DISALLOW_GENERATED_CONTENT, _func)
4689 : #define SIMPLE_SVG_CREATE(_tag, _func) \
4690 : { &nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func) }
4691 :
4692 : static bool
4693 0 : IsFilterPrimitiveChildTag(const nsIAtom* aTag)
4694 : {
4695 : return aTag == nsGkAtoms::feDistantLight ||
4696 : aTag == nsGkAtoms::fePointLight ||
4697 : aTag == nsGkAtoms::feSpotLight ||
4698 : aTag == nsGkAtoms::feFuncR ||
4699 : aTag == nsGkAtoms::feFuncG ||
4700 : aTag == nsGkAtoms::feFuncB ||
4701 : aTag == nsGkAtoms::feFuncA ||
4702 0 : aTag == nsGkAtoms::feMergeNode;
4703 : }
4704 :
4705 : /* static */
4706 : const nsCSSFrameConstructor::FrameConstructionData*
4707 0 : nsCSSFrameConstructor::FindSVGData(Element* aElement,
4708 : nsIAtom* aTag,
4709 : PRInt32 aNameSpaceID,
4710 : nsIFrame* aParentFrame,
4711 : nsStyleContext* aStyleContext)
4712 : {
4713 0 : if (aNameSpaceID != kNameSpaceID_SVG) {
4714 0 : return nsnull;
4715 : }
4716 :
4717 : static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
4718 : static const FrameConstructionData sContainerData =
4719 : SIMPLE_SVG_FCDATA(NS_NewSVGContainerFrame);
4720 :
4721 0 : bool parentIsSVG = false;
4722 : nsIContent* parentContent =
4723 0 : aParentFrame ? aParentFrame->GetContent() : nsnull;
4724 : // XXXbz should this really be based on the XBL-resolved tag of the parent
4725 : // frame's content? Should it not be based on the type of the parent frame
4726 : // (e.g. whether it's an SVG frame)?
4727 0 : if (parentContent) {
4728 : PRInt32 parentNSID;
4729 : nsIAtom* parentTag =
4730 : parentContent->OwnerDoc()->BindingManager()->
4731 0 : ResolveTag(parentContent, &parentNSID);
4732 :
4733 : // It's not clear whether the SVG spec intends to allow any SVG
4734 : // content within svg:foreignObject at all (SVG 1.1, section
4735 : // 23.2), but if it does, it better be svg:svg. So given that
4736 : // we're allowing it, treat it as a non-SVG parent.
4737 : parentIsSVG = parentNSID == kNameSpaceID_SVG &&
4738 0 : parentTag != nsGkAtoms::foreignObject;
4739 : }
4740 :
4741 0 : if ((aTag != nsGkAtoms::svg && !parentIsSVG) ||
4742 : (aTag == nsGkAtoms::desc || aTag == nsGkAtoms::title)) {
4743 : // Sections 5.1 and G.4 of SVG 1.1 say that SVG elements other than
4744 : // svg:svg not contained within svg:svg are incorrect, although they
4745 : // don't seem to specify error handling. Ignore them, since many of
4746 : // our frame classes can't deal. It *may* be that the document
4747 : // should at that point be considered in error according to F.2, but
4748 : // it's hard to tell.
4749 : //
4750 : // Style mutation can't change this situation, so don't bother
4751 : // adding to the undisplayed content map.
4752 : //
4753 : // We don't currently handle any UI for desc/title
4754 0 : return &sSuppressData;
4755 : }
4756 :
4757 : // We don't need frames for animation elements
4758 0 : if (aElement->IsNodeOfType(nsINode::eANIMATION)) {
4759 0 : return &sSuppressData;
4760 : }
4761 :
4762 0 : if (aTag == nsGkAtoms::svg && !parentIsSVG) {
4763 : // We need outer <svg> elements to have an nsSVGOuterSVGFrame regardless
4764 : // of whether they fail conditional processing attributes, since various
4765 : // SVG frames assume that one exists. We handle the non-rendering
4766 : // of failing outer <svg> element contents like <switch> statements,
4767 : // and do the PassesConditionalProcessingTests call in
4768 : // nsSVGOuterSVGFrame::Init.
4769 : static const FrameConstructionData sOuterSVGData =
4770 : FCDATA_DECL(FCDATA_SKIP_ABSPOS_PUSH | FCDATA_DISALLOW_GENERATED_CONTENT,
4771 : NS_NewSVGOuterSVGFrame);
4772 0 : return &sOuterSVGData;
4773 : }
4774 :
4775 0 : nsCOMPtr<DOMSVGTests> tests(do_QueryInterface(aElement));
4776 0 : if (tests && !tests->PassesConditionalProcessingTests()) {
4777 : // Elements with failing conditional processing attributes never get
4778 : // rendered. Note that this is not where we select which frame in a
4779 : // <switch> to render! That happens in nsSVGSwitchFrame::PaintSVG.
4780 0 : return &sContainerData;
4781 : }
4782 :
4783 : // Prevent bad frame types being children of filters or parents of filter
4784 : // primitives:
4785 0 : bool parentIsFilter = aParentFrame->GetType() == nsGkAtoms::svgFilterFrame;
4786 : nsCOMPtr<nsIDOMSVGFilterPrimitiveStandardAttributes> filterPrimitive =
4787 0 : do_QueryInterface(aElement);
4788 0 : if ((parentIsFilter && !filterPrimitive) ||
4789 0 : (!parentIsFilter && filterPrimitive)) {
4790 0 : return &sSuppressData;
4791 : }
4792 :
4793 : // Prevent bad frame types being children of filter primitives or parents of
4794 : // filter primitive children:
4795 : bool parentIsFEContainerFrame =
4796 0 : aParentFrame->GetType() == nsGkAtoms::svgFEContainerFrame;
4797 0 : if ((parentIsFEContainerFrame && !IsFilterPrimitiveChildTag(aTag)) ||
4798 0 : (!parentIsFEContainerFrame && IsFilterPrimitiveChildTag(aTag))) {
4799 0 : return &sSuppressData;
4800 : }
4801 :
4802 : // Special cases for text/tspan/textPath, because the kind of frame
4803 : // they get depends on the parent frame. We ignore 'a' elements when
4804 : // determining the parent, however.
4805 : nsIFrame *ancestorFrame =
4806 0 : nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame);
4807 0 : if (ancestorFrame) {
4808 0 : if (aTag == nsGkAtoms::tspan || aTag == nsGkAtoms::altGlyph) {
4809 : // tspan and altGlyph must be children of another text content element.
4810 0 : nsSVGTextContainerFrame* metrics = do_QueryFrame(ancestorFrame);
4811 0 : if (!metrics) {
4812 0 : return &sSuppressData;
4813 0 : }
4814 0 : } else if (aTag == nsGkAtoms::textPath) {
4815 : // textPath must be a child of text.
4816 0 : nsIAtom* ancestorFrameType = ancestorFrame->GetType();
4817 0 : if (ancestorFrameType != nsGkAtoms::svgTextFrame) {
4818 0 : return &sSuppressData;
4819 : }
4820 0 : } else if (aTag != nsGkAtoms::a) {
4821 : // Every other element except 'a' must not be a child of a text content
4822 : // element.
4823 0 : nsSVGTextContainerFrame* metrics = do_QueryFrame(ancestorFrame);
4824 0 : if (metrics) {
4825 0 : return &sSuppressData;
4826 : }
4827 : }
4828 : }
4829 :
4830 : static const FrameConstructionDataByTag sSVGData[] = {
4831 : SIMPLE_SVG_CREATE(svg, NS_NewSVGInnerSVGFrame),
4832 : SIMPLE_SVG_CREATE(g, NS_NewSVGGFrame),
4833 : SIMPLE_SVG_CREATE(svgSwitch, NS_NewSVGSwitchFrame),
4834 : SIMPLE_SVG_CREATE(polygon, NS_NewSVGPathGeometryFrame),
4835 : SIMPLE_SVG_CREATE(polyline, NS_NewSVGPathGeometryFrame),
4836 : SIMPLE_SVG_CREATE(circle, NS_NewSVGPathGeometryFrame),
4837 : SIMPLE_SVG_CREATE(ellipse, NS_NewSVGPathGeometryFrame),
4838 : SIMPLE_SVG_CREATE(line, NS_NewSVGPathGeometryFrame),
4839 : SIMPLE_SVG_CREATE(rect, NS_NewSVGPathGeometryFrame),
4840 : SIMPLE_SVG_CREATE(path, NS_NewSVGPathGeometryFrame),
4841 : SIMPLE_SVG_CREATE(defs, NS_NewSVGContainerFrame),
4842 : SIMPLE_SVG_CREATE(generic, NS_NewSVGGenericContainerFrame),
4843 : { &nsGkAtoms::foreignObject,
4844 : FCDATA_WITH_WRAPPING_BLOCK(FCDATA_DISALLOW_OUT_OF_FLOW,
4845 : NS_NewSVGForeignObjectFrame,
4846 : nsCSSAnonBoxes::mozSVGForeignContent) },
4847 : SIMPLE_SVG_CREATE(a, NS_NewSVGAFrame),
4848 : SIMPLE_SVG_CREATE(altGlyph, NS_NewSVGTSpanFrame),
4849 : SIMPLE_SVG_CREATE(text, NS_NewSVGTextFrame),
4850 : SIMPLE_SVG_CREATE(tspan, NS_NewSVGTSpanFrame),
4851 : SIMPLE_SVG_CREATE(linearGradient, NS_NewSVGLinearGradientFrame),
4852 : SIMPLE_SVG_CREATE(radialGradient, NS_NewSVGRadialGradientFrame),
4853 : SIMPLE_SVG_CREATE(stop, NS_NewSVGStopFrame),
4854 : SIMPLE_SVG_CREATE(use, NS_NewSVGUseFrame),
4855 : SIMPLE_SVG_CREATE(marker, NS_NewSVGMarkerFrame),
4856 : SIMPLE_SVG_CREATE(image, NS_NewSVGImageFrame),
4857 : SIMPLE_SVG_CREATE(clipPath, NS_NewSVGClipPathFrame),
4858 : SIMPLE_SVG_CREATE(textPath, NS_NewSVGTextPathFrame),
4859 : SIMPLE_SVG_CREATE(filter, NS_NewSVGFilterFrame),
4860 : SIMPLE_SVG_CREATE(pattern, NS_NewSVGPatternFrame),
4861 : SIMPLE_SVG_CREATE(mask, NS_NewSVGMaskFrame),
4862 : SIMPLE_SVG_CREATE(feDistantLight, NS_NewSVGFEUnstyledLeafFrame),
4863 : SIMPLE_SVG_CREATE(fePointLight, NS_NewSVGFEUnstyledLeafFrame),
4864 : SIMPLE_SVG_CREATE(feSpotLight, NS_NewSVGFEUnstyledLeafFrame),
4865 : SIMPLE_SVG_CREATE(feBlend, NS_NewSVGFELeafFrame),
4866 : SIMPLE_SVG_CREATE(feColorMatrix, NS_NewSVGFELeafFrame),
4867 : SIMPLE_SVG_CREATE(feFuncR, NS_NewSVGFEUnstyledLeafFrame),
4868 : SIMPLE_SVG_CREATE(feFuncG, NS_NewSVGFEUnstyledLeafFrame),
4869 : SIMPLE_SVG_CREATE(feFuncB, NS_NewSVGFEUnstyledLeafFrame),
4870 : SIMPLE_SVG_CREATE(feFuncA, NS_NewSVGFEUnstyledLeafFrame),
4871 : SIMPLE_SVG_CREATE(feComposite, NS_NewSVGFELeafFrame),
4872 : SIMPLE_SVG_CREATE(feComponentTransfer, NS_NewSVGFEContainerFrame),
4873 : SIMPLE_SVG_CREATE(feConvolveMatrix, NS_NewSVGFELeafFrame),
4874 : SIMPLE_SVG_CREATE(feDiffuseLighting, NS_NewSVGFEContainerFrame),
4875 : SIMPLE_SVG_CREATE(feDisplacementMap, NS_NewSVGFELeafFrame),
4876 : SIMPLE_SVG_CREATE(feFlood, NS_NewSVGFELeafFrame),
4877 : SIMPLE_SVG_CREATE(feGaussianBlur, NS_NewSVGFELeafFrame),
4878 : SIMPLE_SVG_CREATE(feImage, NS_NewSVGFEImageFrame),
4879 : SIMPLE_SVG_CREATE(feMerge, NS_NewSVGFEContainerFrame),
4880 : SIMPLE_SVG_CREATE(feMergeNode, NS_NewSVGFEUnstyledLeafFrame),
4881 : SIMPLE_SVG_CREATE(feMorphology, NS_NewSVGFELeafFrame),
4882 : SIMPLE_SVG_CREATE(feOffset, NS_NewSVGFELeafFrame),
4883 : SIMPLE_SVG_CREATE(feSpecularLighting, NS_NewSVGFEContainerFrame),
4884 : SIMPLE_SVG_CREATE(feTile, NS_NewSVGFELeafFrame),
4885 : SIMPLE_SVG_CREATE(feTurbulence, NS_NewSVGFELeafFrame)
4886 : };
4887 :
4888 : const FrameConstructionData* data =
4889 : FindDataByTag(aTag, aElement, aStyleContext, sSVGData,
4890 0 : ArrayLength(sSVGData));
4891 :
4892 0 : if (!data) {
4893 0 : data = &sContainerData;
4894 : }
4895 :
4896 0 : return data;
4897 : }
4898 :
4899 : void
4900 0 : nsCSSFrameConstructor::AddPageBreakItem(nsIContent* aContent,
4901 : nsStyleContext* aMainStyleContext,
4902 : FrameConstructionItemList& aItems)
4903 : {
4904 0 : nsRefPtr<nsStyleContext> pseudoStyle;
4905 : // Use the same parent style context that |aMainStyleContext| has, since
4906 : // that's easier to re-resolve and it doesn't matter in practice.
4907 : // (Getting different parents can result in framechange hints, e.g.,
4908 : // for user-modify.)
4909 : pseudoStyle =
4910 : mPresShell->StyleSet()->
4911 : ResolveAnonymousBoxStyle(nsCSSAnonBoxes::pageBreak,
4912 0 : aMainStyleContext->GetParent());
4913 :
4914 0 : NS_ASSERTION(pseudoStyle->GetStyleDisplay()->mDisplay ==
4915 : NS_STYLE_DISPLAY_BLOCK, "Unexpected display");
4916 :
4917 : static const FrameConstructionData sPageBreakData =
4918 : FCDATA_DECL(FCDATA_SKIP_FRAMESET, NS_NewPageBreakFrame);
4919 :
4920 : // Lie about the tag and namespace so we don't trigger anything
4921 : // interesting during frame construction.
4922 : aItems.AppendItem(&sPageBreakData, aContent, nsCSSAnonBoxes::pageBreak,
4923 0 : kNameSpaceID_None, nsnull, pseudoStyle.forget(), true);
4924 0 : }
4925 :
4926 : nsresult
4927 0 : nsCSSFrameConstructor::ConstructFrame(nsFrameConstructorState& aState,
4928 : nsIContent* aContent,
4929 : nsIFrame* aParentFrame,
4930 : nsFrameItems& aFrameItems)
4931 :
4932 : {
4933 0 : NS_PRECONDITION(nsnull != aParentFrame, "no parent frame");
4934 0 : FrameConstructionItemList items;
4935 0 : AddFrameConstructionItems(aState, aContent, true, aParentFrame, items);
4936 :
4937 0 : for (FCItemIterator iter(items); !iter.IsDone(); iter.Next()) {
4938 0 : NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame),
4939 : "This is not going to work");
4940 : nsresult rv =
4941 0 : ConstructFramesFromItem(aState, iter, aParentFrame, aFrameItems);
4942 0 : NS_ENSURE_SUCCESS(rv, rv);
4943 : }
4944 :
4945 0 : return NS_OK;
4946 : }
4947 :
4948 : void
4949 0 : nsCSSFrameConstructor::AddFrameConstructionItems(nsFrameConstructorState& aState,
4950 : nsIContent* aContent,
4951 : bool aSuppressWhiteSpaceOptimizations,
4952 : nsIFrame* aParentFrame,
4953 : FrameConstructionItemList& aItems)
4954 : {
4955 0 : aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
4956 0 : if (aContent->IsElement()) {
4957 : // We can't just remove our pending restyle flags, since we may
4958 : // have restyle-later-siblings set on us. But we _can_ remove the
4959 : // "is possible restyle root" flags, and need to. Otherwise we can
4960 : // end up with stale such flags (e.g. if we used to have a
4961 : // display:none parent when our last restyle was posted and
4962 : // processed and now no longer do).
4963 : aContent->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS &
4964 0 : ~ELEMENT_PENDING_RESTYLE_FLAGS);
4965 : }
4966 :
4967 : // XXX the GetContent() != aContent check is needed due to bug 135040.
4968 : // Remove it once that's fixed.
4969 0 : if (aContent->GetPrimaryFrame() &&
4970 0 : aContent->GetPrimaryFrame()->GetContent() == aContent &&
4971 0 : !aState.mCreatingExtraFrames) {
4972 : NS_ERROR("asked to create frame construction item for a node that already "
4973 0 : "has a frame");
4974 0 : return;
4975 : }
4976 :
4977 : // don't create a whitespace frame if aParent doesn't want it
4978 0 : if (!NeedFrameFor(aState, aParentFrame, aContent)) {
4979 0 : return;
4980 : }
4981 :
4982 : // never create frames for comments or PIs
4983 0 : if (aContent->IsNodeOfType(nsINode::eCOMMENT) ||
4984 0 : aContent->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION))
4985 0 : return;
4986 :
4987 0 : nsRefPtr<nsStyleContext> styleContext;
4988 0 : styleContext = ResolveStyleContext(aParentFrame, aContent, &aState);
4989 :
4990 : AddFrameConstructionItemsInternal(aState, aContent, aParentFrame,
4991 : aContent->Tag(), aContent->GetNameSpaceID(),
4992 : aSuppressWhiteSpaceOptimizations,
4993 : styleContext,
4994 : ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK,
4995 0 : aItems);
4996 : }
4997 :
4998 : /**
4999 : * Set aContent as undisplayed content with style context aStyleContext. This
5000 : * method enforces the invariant that all style contexts in the undisplayed
5001 : * content map must be non-pseudo contexts and also handles unbinding
5002 : * undisplayed generated content as needed.
5003 : */
5004 : static void
5005 0 : SetAsUndisplayedContent(nsFrameManager* aFrameManager, nsIContent* aContent,
5006 : nsStyleContext* aStyleContext,
5007 : bool aIsGeneratedContent)
5008 : {
5009 0 : if (aStyleContext->GetPseudo()) {
5010 0 : if (aIsGeneratedContent) {
5011 0 : aContent->UnbindFromTree();
5012 : }
5013 0 : return;
5014 : }
5015 :
5016 0 : NS_ASSERTION(!aIsGeneratedContent, "Should have had pseudo type");
5017 0 : aFrameManager->SetUndisplayedContent(aContent, aStyleContext);
5018 : }
5019 :
5020 : void
5021 0 : nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState& aState,
5022 : nsIContent* aContent,
5023 : nsIFrame* aParentFrame,
5024 : nsIAtom* aTag,
5025 : PRInt32 aNameSpaceID,
5026 : bool aSuppressWhiteSpaceOptimizations,
5027 : nsStyleContext* aStyleContext,
5028 : PRUint32 aFlags,
5029 : FrameConstructionItemList& aItems)
5030 : {
5031 0 : NS_PRECONDITION(aContent->IsNodeOfType(nsINode::eTEXT) ||
5032 : aContent->IsElement(),
5033 : "Shouldn't get anything else here!");
5034 :
5035 : // The following code allows the user to specify the base tag
5036 : // of an element using XBL. XUL and HTML objects (like boxes, menus, etc.)
5037 : // can then be extended arbitrarily.
5038 0 : const nsStyleDisplay* display = aStyleContext->GetStyleDisplay();
5039 0 : nsRefPtr<nsStyleContext> styleContext(aStyleContext);
5040 0 : PendingBinding* pendingBinding = nsnull;
5041 0 : if ((aFlags & ITEM_ALLOW_XBL_BASE) && display->mBinding)
5042 : {
5043 : // Ensure that our XBL bindings are installed.
5044 :
5045 0 : nsIXBLService * xblService = GetXBLService();
5046 0 : if (!xblService)
5047 : return;
5048 :
5049 : bool resolveStyle;
5050 :
5051 0 : nsAutoPtr<PendingBinding> newPendingBinding(new PendingBinding());
5052 :
5053 : nsresult rv = xblService->LoadBindings(aContent, display->mBinding->GetURI(),
5054 0 : display->mBinding->mOriginPrincipal,
5055 : false,
5056 0 : getter_AddRefs(newPendingBinding->mBinding),
5057 0 : &resolveStyle);
5058 0 : if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED)
5059 : return;
5060 :
5061 0 : if (newPendingBinding->mBinding) {
5062 0 : pendingBinding = newPendingBinding;
5063 : // aState takes over owning newPendingBinding
5064 0 : aState.AddPendingBinding(newPendingBinding.forget());
5065 : }
5066 :
5067 0 : if (resolveStyle) {
5068 : styleContext =
5069 0 : ResolveStyleContext(styleContext->GetParent(), aContent, &aState);
5070 0 : display = styleContext->GetStyleDisplay();
5071 0 : aStyleContext = styleContext;
5072 : }
5073 :
5074 0 : aTag = mDocument->BindingManager()->ResolveTag(aContent, &aNameSpaceID);
5075 : }
5076 :
5077 0 : bool isGeneratedContent = ((aFlags & ITEM_IS_GENERATED_CONTENT) != 0);
5078 :
5079 : // Pre-check for display "none" - if we find that, don't create
5080 : // any frame at all
5081 0 : if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
5082 0 : SetAsUndisplayedContent(this, aContent, styleContext, isGeneratedContent);
5083 : return;
5084 : }
5085 :
5086 0 : bool isText = !aContent->IsElement();
5087 :
5088 : // never create frames for non-option/optgroup kids of <select> and
5089 : // non-option kids of <optgroup> inside a <select>.
5090 : // XXXbz it's not clear how this should best work with XBL.
5091 0 : nsIContent *parent = aContent->GetParent();
5092 0 : if (parent) {
5093 : // Check tag first, since that check will usually fail
5094 0 : nsIAtom* parentTag = parent->Tag();
5095 0 : if ((parentTag == nsGkAtoms::select || parentTag == nsGkAtoms::optgroup) &&
5096 0 : parent->IsHTML() &&
5097 : // <option> is ok no matter what
5098 0 : !aContent->IsHTML(nsGkAtoms::option) &&
5099 : // <optgroup> is OK in <select> but not in <optgroup>
5100 0 : (!aContent->IsHTML(nsGkAtoms::optgroup) ||
5101 : parentTag != nsGkAtoms::select) &&
5102 : // Allow native anonymous content no matter what
5103 0 : !aContent->IsRootOfNativeAnonymousSubtree()) {
5104 : // No frame for aContent
5105 0 : if (!isText) {
5106 0 : SetAsUndisplayedContent(this, aContent, styleContext, isGeneratedContent);
5107 : }
5108 : return;
5109 : }
5110 : }
5111 :
5112 0 : bool isPopup = false;
5113 : // Try to find frame construction data for this content
5114 : const FrameConstructionData* data;
5115 0 : if (isText) {
5116 0 : data = FindTextData(aParentFrame);
5117 0 : if (!data) {
5118 : // Nothing to do here; suppressed text inside SVG
5119 : return;
5120 : }
5121 : } else {
5122 0 : Element* element = aContent->AsElement();
5123 :
5124 : // Don't create frames for non-SVG element children of SVG elements.
5125 0 : if (aNameSpaceID != kNameSpaceID_SVG &&
5126 : aParentFrame &&
5127 0 : aParentFrame->IsFrameOfType(nsIFrame::eSVG) &&
5128 0 : !aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)
5129 : ) {
5130 : SetAsUndisplayedContent(this, element, styleContext,
5131 0 : isGeneratedContent);
5132 : return;
5133 : }
5134 :
5135 : data = FindHTMLData(element, aTag, aNameSpaceID, aParentFrame,
5136 0 : styleContext);
5137 0 : if (!data) {
5138 0 : data = FindXULTagData(element, aTag, aNameSpaceID, styleContext);
5139 : }
5140 0 : if (!data) {
5141 0 : data = FindMathMLData(element, aTag, aNameSpaceID, styleContext);
5142 : }
5143 0 : if (!data) {
5144 : data = FindSVGData(element, aTag, aNameSpaceID, aParentFrame,
5145 0 : styleContext);
5146 : }
5147 :
5148 : // Now check for XUL display types
5149 0 : if (!data) {
5150 0 : data = FindXULDisplayData(display, element, styleContext);
5151 : }
5152 :
5153 : // And general display types
5154 0 : if (!data) {
5155 0 : data = FindDisplayData(display, element, styleContext);
5156 : }
5157 :
5158 0 : NS_ASSERTION(data, "Should have frame construction data now");
5159 :
5160 0 : if (data->mBits & FCDATA_SUPPRESS_FRAME) {
5161 0 : SetAsUndisplayedContent(this, element, styleContext, isGeneratedContent);
5162 : return;
5163 : }
5164 :
5165 : #ifdef MOZ_XUL
5166 0 : if ((data->mBits & FCDATA_IS_POPUP) &&
5167 : (!aParentFrame || // Parent is inline
5168 0 : aParentFrame->GetType() != nsGkAtoms::menuFrame)) {
5169 0 : if (!aState.mPopupItems.containingBlock &&
5170 0 : !aState.mHavePendingPopupgroup) {
5171 : SetAsUndisplayedContent(this, element, styleContext,
5172 0 : isGeneratedContent);
5173 : return;
5174 : }
5175 :
5176 0 : isPopup = true;
5177 : }
5178 : #endif /* MOZ_XUL */
5179 : }
5180 :
5181 0 : PRUint32 bits = data->mBits;
5182 :
5183 : // Inside colgroups, suppress everything except columns.
5184 0 : if (aParentFrame &&
5185 0 : aParentFrame->GetType() == nsGkAtoms::tableColGroupFrame &&
5186 0 : (!(bits & FCDATA_IS_TABLE_PART) ||
5187 : display->mDisplay != NS_STYLE_DISPLAY_TABLE_COLUMN)) {
5188 0 : SetAsUndisplayedContent(this, aContent, styleContext, isGeneratedContent);
5189 : return;
5190 : }
5191 :
5192 : bool canHavePageBreak =
5193 : (aFlags & ITEM_ALLOW_PAGE_BREAK) &&
5194 0 : aState.mPresContext->IsPaginated() &&
5195 0 : !display->IsAbsolutelyPositioned() &&
5196 0 : !(bits & FCDATA_IS_TABLE_PART);
5197 :
5198 0 : if (canHavePageBreak && display->mBreakBefore) {
5199 0 : AddPageBreakItem(aContent, aStyleContext, aItems);
5200 : }
5201 :
5202 : FrameConstructionItem* item =
5203 : aItems.AppendItem(data, aContent, aTag, aNameSpaceID,
5204 : pendingBinding, styleContext.forget(),
5205 0 : aSuppressWhiteSpaceOptimizations);
5206 0 : if (!item) {
5207 0 : if (isGeneratedContent) {
5208 0 : aContent->UnbindFromTree();
5209 : }
5210 : return;
5211 : }
5212 :
5213 0 : item->mIsText = isText;
5214 0 : item->mIsGeneratedContent = isGeneratedContent;
5215 0 : if (isGeneratedContent) {
5216 0 : NS_ADDREF(item->mContent);
5217 : }
5218 : item->mIsRootPopupgroup =
5219 : aNameSpaceID == kNameSpaceID_XUL && aTag == nsGkAtoms::popupgroup &&
5220 0 : aContent->IsRootOfNativeAnonymousSubtree();
5221 0 : if (item->mIsRootPopupgroup) {
5222 0 : aState.mHavePendingPopupgroup = true;
5223 : }
5224 0 : item->mIsPopup = isPopup;
5225 :
5226 0 : if (canHavePageBreak && display->mBreakAfter) {
5227 0 : AddPageBreakItem(aContent, aStyleContext, aItems);
5228 : }
5229 :
5230 0 : if (bits & FCDATA_IS_INLINE) {
5231 : // To correctly set item->mIsAllInline we need to build up our child items
5232 : // right now.
5233 0 : BuildInlineChildItems(aState, *item);
5234 0 : item->mHasInlineEnds = true;
5235 0 : item->mIsBlock = false;
5236 : } else {
5237 : // Compute a boolean isInline which is guaranteed to be false for blocks
5238 : // (but may also be false for some inlines).
5239 : bool isInline =
5240 : // Table-internal things are inline-outside if and only if they're kids of
5241 : // inlines, since they'll trigger construction of inline-table
5242 : // pseudos.
5243 : ((bits & FCDATA_IS_TABLE_PART) &&
5244 : (!aParentFrame || // No aParentFrame means inline
5245 0 : aParentFrame->GetStyleDisplay()->mDisplay == NS_STYLE_DISPLAY_INLINE)) ||
5246 : // Things that are inline-outside but aren't inline frames are inline
5247 0 : display->IsInlineOutside() ||
5248 : // Popups that are certainly out of flow.
5249 0 : isPopup;
5250 :
5251 : // Set mIsAllInline conservatively. It just might be that even an inline
5252 : // that has mIsAllInline false doesn't need an {ib} split. So this is just
5253 : // an optimization to keep from doing too much work in cases when we can
5254 : // show that mIsAllInline is true..
5255 : item->mIsAllInline = item->mHasInlineEnds = isInline ||
5256 : // Figure out whether we're guaranteed this item will be out of flow.
5257 : // This is not a precise test, since one of our ancestor inlines might add
5258 : // an absolute containing block (if it's relatively positioned) when there
5259 : // wasn't such a containing block before. But it's conservative in the
5260 : // sense that anything that will really end up as an in-flow non-inline
5261 : // will test false here. In other words, if this test is true we're
5262 : // guaranteed to be inline; if it's false we don't know what we'll end up
5263 : // as.
5264 : //
5265 : // If we make this test precise, we can remove some of the code dealing
5266 : // with the imprecision in ConstructInline and adjust the comments on
5267 : // mIsAllInline and mIsBlock in the header. And probably remove mIsBlock
5268 : // altogether, since then it will always be equal to !mHasInlineEnds.
5269 0 : (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
5270 0 : aState.GetGeometricParent(display, nsnull));
5271 :
5272 : // Set mIsBlock conservatively. It's OK to set it false for some real
5273 : // blocks, but not OK to set it true for things that aren't blocks. Since
5274 : // isOutOfFlow might be false even in cases when the frame will end up
5275 : // out-of-flow, we can't use it here. But we _can_ say that the frame will
5276 : // for sure end up in-flow if it's not floated or absolutely positioned.
5277 : item->mIsBlock =
5278 0 : !isInline && !display->IsAbsolutelyPositioned() && !display->IsFloating();
5279 : }
5280 :
5281 0 : if (item->mIsAllInline) {
5282 0 : aItems.InlineItemAdded();
5283 0 : } else if (item->mIsBlock) {
5284 0 : aItems.BlockItemAdded();
5285 : }
5286 :
5287 : // Our item should be treated as a line participant if we have the relevant
5288 : // bit and are going to be in-flow. Note that this really only matters if
5289 : // our ancestor is a box or some such, so the fact that we might have an
5290 : // inline ancestor that might become a containing block is not relevant here.
5291 0 : if ((bits & FCDATA_IS_LINE_PARTICIPANT) &&
5292 : ((bits & FCDATA_DISALLOW_OUT_OF_FLOW) ||
5293 0 : !aState.GetGeometricParent(display, nsnull))) {
5294 0 : item->mIsLineParticipant = true;
5295 0 : aItems.LineParticipantItemAdded();
5296 : }
5297 : }
5298 :
5299 : static void
5300 0 : DestroyContent(void* aPropertyValue)
5301 : {
5302 0 : nsIContent* content = static_cast<nsIContent*>(aPropertyValue);
5303 0 : content->UnbindFromTree();
5304 0 : NS_RELEASE(content);
5305 0 : }
5306 :
5307 0 : NS_DECLARE_FRAME_PROPERTY(BeforeProperty, DestroyContent)
5308 0 : NS_DECLARE_FRAME_PROPERTY(AfterProperty, DestroyContent)
5309 :
5310 : static const FramePropertyDescriptor*
5311 0 : GenConPseudoToProperty(nsIAtom* aPseudo)
5312 : {
5313 0 : NS_ASSERTION(aPseudo == nsCSSPseudoElements::before ||
5314 : aPseudo == nsCSSPseudoElements::after,
5315 : "Bad gen-con pseudo");
5316 : return aPseudo == nsCSSPseudoElements::before ? BeforeProperty()
5317 0 : : AfterProperty();
5318 : }
5319 :
5320 : /**
5321 : * Return true if the frame construction item pointed to by aIter will
5322 : * create a frame adjacent to a line boundary in the frame tree, and that
5323 : * line boundary is induced by a content node adjacent to the frame's
5324 : * content node in the content tree. The latter condition is necessary so
5325 : * that ContentAppended/ContentInserted/ContentRemoved can easily find any
5326 : * text nodes that were suppressed here.
5327 : */
5328 : bool
5329 0 : nsCSSFrameConstructor::AtLineBoundary(FCItemIterator& aIter)
5330 : {
5331 0 : if (aIter.item().mSuppressWhiteSpaceOptimizations) {
5332 0 : return false;
5333 : }
5334 :
5335 0 : if (aIter.AtStart()) {
5336 0 : if (aIter.List()->HasLineBoundaryAtStart() &&
5337 0 : !aIter.item().mContent->GetPreviousSibling())
5338 0 : return true;
5339 : } else {
5340 0 : FCItemIterator prev = aIter;
5341 0 : prev.Prev();
5342 0 : if (prev.item().IsLineBoundary() &&
5343 0 : !prev.item().mSuppressWhiteSpaceOptimizations &&
5344 0 : aIter.item().mContent->GetPreviousSibling() == prev.item().mContent)
5345 0 : return true;
5346 : }
5347 :
5348 0 : FCItemIterator next = aIter;
5349 0 : next.Next();
5350 0 : if (next.IsDone()) {
5351 0 : if (aIter.List()->HasLineBoundaryAtEnd() &&
5352 0 : !aIter.item().mContent->GetNextSibling())
5353 0 : return true;
5354 : } else {
5355 0 : if (next.item().IsLineBoundary() &&
5356 0 : !next.item().mSuppressWhiteSpaceOptimizations &&
5357 0 : aIter.item().mContent->GetNextSibling() == next.item().mContent)
5358 0 : return true;
5359 : }
5360 :
5361 0 : return false;
5362 : }
5363 :
5364 : nsresult
5365 0 : nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState& aState,
5366 : FCItemIterator& aIter,
5367 : nsIFrame* aParentFrame,
5368 : nsFrameItems& aFrameItems)
5369 : {
5370 0 : nsIFrame* adjParentFrame = aParentFrame;
5371 0 : FrameConstructionItem& item = aIter.item();
5372 0 : nsStyleContext* styleContext = item.mStyleContext;
5373 0 : AdjustParentFrame(adjParentFrame, item.mFCData, styleContext);
5374 :
5375 0 : if (item.mIsText) {
5376 : // If this is collapsible whitespace next to a line boundary,
5377 : // don't create a frame. item.IsWhitespace() also sets the
5378 : // NS_CREATE_FRAME_IF_NON_WHITESPACE flag in the text node. (If we
5379 : // end up creating a frame, nsTextFrame::Init will clear the flag.)
5380 : // We don't do this for generated content, because some generated
5381 : // text content is empty text nodes that are about to be initialized.
5382 : // (We check mAdditionalStateBits because only the generated content
5383 : // container's frame construction item is marked with
5384 : // mIsGeneratedContent, and we might not have an aParentFrame.)
5385 : // We don't do it for content that may have XBL anonymous siblings,
5386 : // because they make it difficult to correctly create the frame
5387 : // due to dynamic changes.
5388 : // We don't do it for text that's not a line participant (i.e. SVG text).
5389 0 : if (AtLineBoundary(aIter) &&
5390 0 : !styleContext->GetStyleText()->NewlineIsSignificant() &&
5391 0 : aIter.List()->ParentHasNoXBLChildren() &&
5392 0 : !(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) &&
5393 : (item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) &&
5394 0 : item.IsWhitespace(aState))
5395 0 : return NS_OK;
5396 :
5397 : return ConstructTextFrame(item.mFCData, aState, item.mContent,
5398 : adjParentFrame, styleContext,
5399 0 : aFrameItems);
5400 : }
5401 :
5402 : // Start background loads during frame construction so that we're
5403 : // guaranteed that they will be started before onload fires.
5404 0 : styleContext->StartBackgroundImageLoads();
5405 :
5406 0 : nsFrameState savedStateBits = aState.mAdditionalStateBits;
5407 0 : if (item.mIsGeneratedContent) {
5408 : // Ensure that frames created here are all tagged with
5409 : // NS_FRAME_GENERATED_CONTENT.
5410 0 : aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
5411 :
5412 : // Note that we're not necessarily setting this property on the primary
5413 : // frame for the content for which this is generated content. We might be
5414 : // setting it on a table pseudo-frame inserted under that instead. That's
5415 : // OK, though; we just need to do the property set so that the content will
5416 : // get cleaned up when the frame is destroyed.
5417 : aParentFrame->Properties().Set(GenConPseudoToProperty(styleContext->GetPseudo()),
5418 0 : item.mContent);
5419 :
5420 : // Now that we've passed ownership of item.mContent to the frame, unset
5421 : // our generated content flag so we don't release or unbind it ourselves.
5422 0 : item.mIsGeneratedContent = false;
5423 : }
5424 :
5425 : // XXXbz maybe just inline ConstructFrameFromItemInternal here or something?
5426 : nsresult rv = ConstructFrameFromItemInternal(item, aState, adjParentFrame,
5427 0 : aFrameItems);
5428 :
5429 0 : aState.mAdditionalStateBits = savedStateBits;
5430 :
5431 0 : return rv;
5432 : }
5433 :
5434 :
5435 : inline bool
5436 : IsRootBoxFrame(nsIFrame *aFrame)
5437 : {
5438 : return (aFrame->GetType() == nsGkAtoms::rootFrame);
5439 : }
5440 :
5441 : nsresult
5442 0 : nsCSSFrameConstructor::ReconstructDocElementHierarchy()
5443 : {
5444 0 : Element* rootElement = mDocument->GetRootElement();
5445 0 : if (!rootElement) {
5446 : /* nothing to do */
5447 0 : return NS_OK;
5448 : }
5449 0 : return RecreateFramesForContent(rootElement, false);
5450 : }
5451 :
5452 : nsIFrame*
5453 0 : nsCSSFrameConstructor::GetFrameFor(nsIContent* aContent)
5454 : {
5455 : // Get the primary frame associated with the content
5456 0 : nsIFrame* frame = aContent->GetPrimaryFrame();
5457 :
5458 0 : if (!frame)
5459 0 : return nsnull;
5460 :
5461 : // If the content of the frame is not the desired content then this is not
5462 : // really a frame for the desired content.
5463 : // XXX This check is needed due to bug 135040. Remove it once that's fixed.
5464 0 : if (frame->GetContent() != aContent) {
5465 0 : return nsnull;
5466 : }
5467 :
5468 0 : nsIFrame* insertionFrame = frame->GetContentInsertionFrame();
5469 :
5470 0 : NS_ASSERTION(insertionFrame == frame || !frame->IsLeaf(),
5471 : "The insertion frame is the primary frame or the primary frame isn't a leaf");
5472 :
5473 0 : return insertionFrame;
5474 : }
5475 :
5476 : nsIFrame*
5477 0 : nsCSSFrameConstructor::GetAbsoluteContainingBlock(nsIFrame* aFrame)
5478 : {
5479 0 : NS_PRECONDITION(nsnull != mRootElementFrame, "no root element frame");
5480 :
5481 : // Starting with aFrame, look for a frame that is absolutely positioned or
5482 : // relatively positioned
5483 0 : for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
5484 0 : if (frame->IsFrameOfType(nsIFrame::eMathML)) {
5485 : // If it's mathml, bail out -- no absolute positioning out from inside
5486 : // mathml frames. Note that we don't make this part of the loop
5487 : // condition because of the stuff at the end of this method...
5488 0 : return nsnull;
5489 : }
5490 :
5491 : // If the frame is positioned, we will probably return it as the containing
5492 : // block (see the exceptions below). Otherwise, we'll start looking at the
5493 : // parent frame, unless we're dealing with a scrollframe.
5494 : // Scrollframes are special since they're not positioned, but their
5495 : // scrolledframe might be. So, we need to check this special case to return
5496 : // the correct containing block (the scrolledframe) in that case.
5497 0 : const nsStyleDisplay* disp = frame->GetStyleDisplay();
5498 0 : if (!disp->IsPositioned()) {
5499 0 : continue;
5500 : }
5501 0 : nsIFrame* absPosCBCandidate = nsnull;
5502 0 : if (frame->GetType() == nsGkAtoms::scrollFrame) {
5503 0 : nsIScrollableFrame* scrollFrame = do_QueryFrame(frame);
5504 0 : absPosCBCandidate = scrollFrame->GetScrolledFrame();
5505 : } else {
5506 : // Only first continuations can be containing blocks.
5507 0 : absPosCBCandidate = frame->GetFirstContinuation();
5508 : }
5509 : // Is the frame really an absolute container?
5510 0 : if (!absPosCBCandidate || !absPosCBCandidate->IsAbsoluteContainer()) {
5511 0 : continue;
5512 : }
5513 :
5514 : // For tables, return the outer table frame.
5515 0 : if (absPosCBCandidate->GetType() == nsGkAtoms::tableFrame) {
5516 0 : return absPosCBCandidate->GetParent();
5517 : }
5518 : // For outer table frames, we can just return absPosCBCandidate.
5519 0 : return absPosCBCandidate;
5520 : }
5521 :
5522 : // It is possible for the search for the containing block to fail, because
5523 : // no absolute container can be found in the parent chain. In those cases,
5524 : // we fall back to the document element's containing block.
5525 0 : return mHasRootAbsPosContainingBlock ? mDocElementContainingBlock : nsnull;
5526 : }
5527 :
5528 : nsIFrame*
5529 0 : nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame)
5530 : {
5531 : // Starting with aFrame, look for a frame that is a float containing block.
5532 : // IF we hit a mathml frame, bail out; we don't allow floating out of mathml
5533 : // frames, because they don't seem to be able to deal.
5534 : // The logic here needs to match the logic in ProcessChildren()
5535 0 : for (nsIFrame* containingBlock = aFrame;
5536 0 : containingBlock && !containingBlock->IsFrameOfType(nsIFrame::eMathML) &&
5537 0 : !containingBlock->IsBoxFrame();
5538 : containingBlock = containingBlock->GetParent()) {
5539 0 : if (containingBlock->IsFloatContainingBlock()) {
5540 0 : return containingBlock;
5541 : }
5542 : }
5543 :
5544 : // If we didn't find a containing block, then there just isn't
5545 : // one.... return null
5546 0 : return nsnull;
5547 : }
5548 :
5549 : /**
5550 : * This function will check whether aContainer has :after generated content.
5551 : * If so, appending to it should actually insert. The return value is the
5552 : * parent to use for newly-appended content. *aAfterFrame points to the :after
5553 : * frame before which appended content should go, if there is one.
5554 : */
5555 : static nsIFrame*
5556 0 : AdjustAppendParentForAfterContent(nsPresContext* aPresContext,
5557 : nsIContent* aContainer,
5558 : nsIFrame* aParentFrame,
5559 : nsIFrame** aAfterFrame)
5560 : {
5561 : // See if the parent has an :after pseudo-element. Check for the presence
5562 : // of style first, since nsLayoutUtils::GetAfterFrame is sorta expensive.
5563 0 : nsStyleContext* parentStyle = aParentFrame->GetStyleContext();
5564 0 : if (nsLayoutUtils::HasPseudoStyle(aContainer, parentStyle,
5565 : nsCSSPseudoElements::ePseudo_after,
5566 : aPresContext)) {
5567 0 : nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(aParentFrame);
5568 0 : if (afterFrame) {
5569 0 : *aAfterFrame = afterFrame;
5570 0 : return afterFrame->GetParent();
5571 : }
5572 : }
5573 :
5574 0 : *aAfterFrame = nsnull;
5575 :
5576 0 : if (IsFrameSpecial(aParentFrame)) {
5577 : // We might be in a situation where the last part of the {ib} split was
5578 : // empty. Since we have no ::after pseudo-element, we do in fact want to be
5579 : // appending to that last part, so advance to it if needed. Note that here
5580 : // aParentFrame is the result of a GetLastSpecialSibling call, so must be
5581 : // either the last or next to last special sibling.
5582 0 : nsIFrame* trailingInline = GetSpecialSibling(aParentFrame);
5583 0 : if (trailingInline) {
5584 0 : aParentFrame = trailingInline;
5585 : }
5586 :
5587 : // Always make sure to look at the last continuation of the frame
5588 : // for the {ib} case, even if that continuation is empty. We
5589 : // don't do this for the non-special-frame case, since in the
5590 : // other cases appending to the last nonempty continuation is fine
5591 : // and in fact not doing that can confuse code that doesn't know
5592 : // to pull kids from continuations other than its next one.
5593 0 : aParentFrame = aParentFrame->GetLastContinuation();
5594 : }
5595 :
5596 0 : return aParentFrame;
5597 : }
5598 :
5599 : /**
5600 : * This function will get the previous sibling to use for an append operation.
5601 : * it takes a parent frame (must not be null) and its :after frame (may be
5602 : * null).
5603 : */
5604 : static nsIFrame*
5605 0 : FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aAfterFrame)
5606 : {
5607 0 : if (aAfterFrame) {
5608 0 : NS_ASSERTION(aAfterFrame->GetParent() == aParentFrame, "Wrong parent");
5609 0 : return aAfterFrame->GetPrevSibling();
5610 : }
5611 :
5612 0 : return aParentFrame->GetLastChild(kPrincipalList);
5613 : }
5614 :
5615 : /**
5616 : * This function will get the next sibling for a frame insert operation given
5617 : * the parent and previous sibling. aPrevSibling may be null.
5618 : */
5619 : static nsIFrame*
5620 0 : GetInsertNextSibling(nsIFrame* aParentFrame, nsIFrame* aPrevSibling)
5621 : {
5622 0 : if (aPrevSibling) {
5623 0 : return aPrevSibling->GetNextSibling();
5624 : }
5625 :
5626 0 : return aParentFrame->GetFirstPrincipalChild();
5627 : }
5628 :
5629 : /**
5630 : * This function is called by ContentAppended() and ContentInserted() when
5631 : * appending flowed frames to a parent's principal child list. It handles the
5632 : * case where the parent is the trailing inline of an {ib} split.
5633 : */
5634 : nsresult
5635 0 : nsCSSFrameConstructor::AppendFramesToParent(nsFrameConstructorState& aState,
5636 : nsIFrame* aParentFrame,
5637 : nsFrameItems& aFrameList,
5638 : nsIFrame* aPrevSibling,
5639 : bool aIsRecursiveCall)
5640 : {
5641 0 : NS_PRECONDITION(!IsFrameSpecial(aParentFrame) ||
5642 : !GetSpecialSibling(aParentFrame) ||
5643 : !GetSpecialSibling(aParentFrame)->GetFirstPrincipalChild(),
5644 : "aParentFrame has a special sibling with kids?");
5645 0 : NS_PRECONDITION(!aPrevSibling || aPrevSibling->GetParent() == aParentFrame,
5646 : "Parent and prevsibling don't match");
5647 :
5648 0 : nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling);
5649 :
5650 0 : NS_ASSERTION(nextSibling ||
5651 : !aParentFrame->GetNextContinuation() ||
5652 : !aParentFrame->GetNextContinuation()->GetFirstPrincipalChild() ||
5653 : aIsRecursiveCall,
5654 : "aParentFrame has later continuations with kids?");
5655 0 : NS_ASSERTION(nextSibling ||
5656 : !IsFrameSpecial(aParentFrame) ||
5657 : (IsInlineFrame(aParentFrame) &&
5658 : !GetSpecialSibling(aParentFrame) &&
5659 : !aParentFrame->GetNextContinuation()) ||
5660 : aIsRecursiveCall,
5661 : "aParentFrame is not last?");
5662 :
5663 : // If we're inserting a list of frames at the end of the trailing inline
5664 : // of an {ib} split, we may need to create additional {ib} siblings to parent
5665 : // them.
5666 0 : if (!nextSibling && IsFrameSpecial(aParentFrame)) {
5667 : // When we get here, our frame list might start with a block. If it does
5668 : // so, and aParentFrame is an inline, and it and all its previous
5669 : // continuations have no siblings, then put the initial blocks from the
5670 : // frame list into the previous block of the {ib} split. Note that we
5671 : // didn't want to stop at the block part of the split when figuring out
5672 : // initial parent, because that could screw up float parenting; it's easier
5673 : // to do this little fixup here instead.
5674 0 : if (aFrameList.NotEmpty() && !IsInlineOutside(aFrameList.FirstChild())) {
5675 : // See whether our trailing inline is empty
5676 0 : nsIFrame* firstContinuation = aParentFrame->GetFirstContinuation();
5677 0 : if (firstContinuation->PrincipalChildList().IsEmpty()) {
5678 : // Our trailing inline is empty. Collect our starting blocks from
5679 : // aFrameList, get the right parent frame for them, and put them in.
5680 : nsFrameList::FrameLinkEnumerator firstNonBlockEnumerator =
5681 0 : FindFirstNonBlock(aFrameList);
5682 0 : nsFrameList blockKids = aFrameList.ExtractHead(firstNonBlockEnumerator);
5683 0 : NS_ASSERTION(blockKids.NotEmpty(), "No blocks?");
5684 :
5685 : nsIFrame* prevBlock =
5686 0 : GetSpecialPrevSibling(firstContinuation)->GetLastContinuation();
5687 0 : NS_ASSERTION(prevBlock, "Should have previous block here");
5688 :
5689 0 : MoveChildrenTo(aState.mPresContext, aParentFrame, prevBlock, blockKids);
5690 : }
5691 : }
5692 :
5693 : // We want to put some of the frames into this inline frame.
5694 0 : nsFrameList::FrameLinkEnumerator firstBlockEnumerator(aFrameList);
5695 0 : FindFirstBlock(firstBlockEnumerator);
5696 :
5697 0 : nsFrameList inlineKids = aFrameList.ExtractHead(firstBlockEnumerator);
5698 0 : if (!inlineKids.IsEmpty()) {
5699 0 : AppendFrames(aParentFrame, kPrincipalList, inlineKids);
5700 : }
5701 :
5702 0 : if (!aFrameList.IsEmpty()) {
5703 0 : const nsStyleDisplay* parentDisplay = aParentFrame->GetStyleDisplay();
5704 : bool positioned =
5705 : parentDisplay->mPosition == NS_STYLE_POSITION_RELATIVE ||
5706 0 : parentDisplay->HasTransform();
5707 0 : nsFrameItems ibSiblings;
5708 : CreateIBSiblings(aState, aParentFrame, positioned, aFrameList,
5709 0 : ibSiblings);
5710 :
5711 : // Make sure to trigger reflow of the inline that used to be our
5712 : // last one and now isn't anymore, since its GetSkipSides() has
5713 : // changed.
5714 : mPresShell->FrameNeedsReflow(aParentFrame,
5715 : nsIPresShell::eTreeChange,
5716 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
5717 :
5718 : // Recurse so we create new ib siblings as needed for aParentFrame's parent
5719 : return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings,
5720 0 : aParentFrame, true);
5721 : }
5722 :
5723 0 : return NS_OK;
5724 : }
5725 :
5726 : // Insert the frames after our aPrevSibling
5727 0 : return InsertFrames(aParentFrame, kPrincipalList, aPrevSibling, aFrameList);
5728 : }
5729 :
5730 : #define UNSET_DISPLAY 255
5731 :
5732 : // This gets called to see if the frames corresponding to aSibling and aContent
5733 : // should be siblings in the frame tree. Although (1) rows and cols, (2) row
5734 : // groups and col groups, (3) row groups and captions, (4) legends and content
5735 : // inside fieldsets, (5) popups and other kids of the menu are siblings from a
5736 : // content perspective, they are not considered siblings in the frame tree.
5737 : bool
5738 0 : nsCSSFrameConstructor::IsValidSibling(nsIFrame* aSibling,
5739 : nsIContent* aContent,
5740 : PRUint8& aDisplay)
5741 : {
5742 0 : nsIFrame* parentFrame = aSibling->GetParent();
5743 0 : nsIAtom* parentType = nsnull;
5744 0 : nsIAtom* grandparentType = nsnull;
5745 0 : if (parentFrame) {
5746 0 : parentType = parentFrame->GetType();
5747 0 : nsIFrame* grandparentFrame = parentFrame->GetParent();
5748 0 : if (grandparentFrame) {
5749 0 : grandparentType = grandparentFrame->GetType();
5750 : }
5751 : }
5752 :
5753 0 : PRUint8 siblingDisplay = aSibling->GetStyleDisplay()->mDisplay;
5754 0 : if ((NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == siblingDisplay) ||
5755 : (NS_STYLE_DISPLAY_TABLE_COLUMN == siblingDisplay) ||
5756 : (NS_STYLE_DISPLAY_TABLE_CAPTION == siblingDisplay) ||
5757 : (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == siblingDisplay) ||
5758 : (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == siblingDisplay) ||
5759 : (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == siblingDisplay) ||
5760 : nsGkAtoms::menuFrame == parentType) {
5761 : // if we haven't already, construct a style context to find the display type of aContent
5762 0 : if (UNSET_DISPLAY == aDisplay) {
5763 0 : nsRefPtr<nsStyleContext> styleContext;
5764 0 : nsIFrame* styleParent = aSibling->GetParentStyleContextFrame();
5765 0 : if (!styleParent) {
5766 0 : NS_NOTREACHED("Shouldn't happen");
5767 0 : return false;
5768 : }
5769 : // XXXbz when this code is killed, the state argument to
5770 : // ResolveStyleContext can be made non-optional.
5771 0 : styleContext = ResolveStyleContext(styleParent, aContent, nsnull);
5772 0 : if (!styleContext) return false;
5773 0 : const nsStyleDisplay* display = styleContext->GetStyleDisplay();
5774 0 : aDisplay = display->mDisplay;
5775 : }
5776 0 : if (nsGkAtoms::menuFrame == parentType) {
5777 : return
5778 : (NS_STYLE_DISPLAY_POPUP == aDisplay) ==
5779 0 : (NS_STYLE_DISPLAY_POPUP == siblingDisplay);
5780 : }
5781 : // To have decent performance we want to return false in cases in which
5782 : // reordering the two siblings has no effect on display. To ensure
5783 : // correctness, we MUST return false in cases where the two siblings have
5784 : // the same desired parent type and live on different display lists.
5785 : // Specificaly, columns and column groups should only consider columns and
5786 : // column groups as valid siblings. Captions should only consider other
5787 : // captions. All other things should consider each other as valid
5788 : // siblings. The restriction in the |if| above on siblingDisplay is ok,
5789 : // because for correctness the only part that really needs to happen is to
5790 : // not consider captions, column groups, and row/header/footer groups
5791 : // siblings of each other. Treating a column or colgroup as a valid
5792 : // sibling of a non-table-related frame will just mean we end up reframing.
5793 0 : if ((siblingDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION) !=
5794 : (aDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION)) {
5795 : // One's a caption and the other is not. Not valid siblings.
5796 0 : return false;
5797 : }
5798 :
5799 0 : if ((siblingDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP ||
5800 : siblingDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN) !=
5801 : (aDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP ||
5802 : aDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN)) {
5803 : // One's a column or column group and the other is not. Not valid
5804 : // siblings.
5805 0 : return false;
5806 : }
5807 :
5808 0 : return true;
5809 : }
5810 0 : else if (nsGkAtoms::fieldSetFrame == parentType ||
5811 : (nsGkAtoms::fieldSetFrame == grandparentType &&
5812 : nsGkAtoms::blockFrame == parentType)) {
5813 : // Legends can be sibling of legends but not of other content in the fieldset
5814 0 : nsIAtom* sibType = aSibling->GetType();
5815 0 : nsCOMPtr<nsIDOMHTMLLegendElement> legendContent(do_QueryInterface(aContent));
5816 :
5817 0 : if ((legendContent && (nsGkAtoms::legendFrame != sibType)) ||
5818 0 : (!legendContent && (nsGkAtoms::legendFrame == sibType)))
5819 0 : return false;
5820 : }
5821 :
5822 0 : return true;
5823 : }
5824 :
5825 : nsIFrame*
5826 0 : nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent* aContent,
5827 : nsIContent* aTargetContent,
5828 : PRUint8& aTargetContentDisplay,
5829 : bool aPrevSibling)
5830 : {
5831 0 : nsIFrame* sibling = aContent->GetPrimaryFrame();
5832 0 : if (!sibling || sibling->GetContent() != aContent) {
5833 : // XXX the GetContent() != aContent check is needed due to bug 135040.
5834 : // Remove it once that's fixed.
5835 0 : return nsnull;
5836 : }
5837 :
5838 : // If the frame is out-of-flow, GetPrimaryFrame() will have returned the
5839 : // out-of-flow frame; we want the placeholder.
5840 0 : if (sibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
5841 0 : nsIFrame* placeholderFrame = GetPlaceholderFrameFor(sibling);
5842 0 : NS_ASSERTION(placeholderFrame, "no placeholder for out-of-flow frame");
5843 0 : sibling = placeholderFrame;
5844 : }
5845 :
5846 : // The frame we have now should never be a continuation
5847 0 : NS_ASSERTION(!sibling->GetPrevContinuation(), "How did that happen?");
5848 :
5849 0 : if (aPrevSibling) {
5850 : // The frame may be a special frame (a split inline frame that
5851 : // contains a block). Get the last part of that split.
5852 0 : if (IsFrameSpecial(sibling)) {
5853 0 : sibling = GetLastSpecialSibling(sibling, true);
5854 : }
5855 :
5856 : // The frame may have a continuation. If so, we want the last
5857 : // non-overflow-container continuation as our previous sibling.
5858 0 : sibling = sibling->GetTailContinuation();
5859 : }
5860 :
5861 0 : if (aTargetContent &&
5862 0 : !IsValidSibling(sibling, aTargetContent, aTargetContentDisplay)) {
5863 0 : sibling = nsnull;
5864 : }
5865 :
5866 0 : return sibling;
5867 : }
5868 :
5869 : nsIFrame*
5870 0 : nsCSSFrameConstructor::FindPreviousSibling(const ChildIterator& aFirst,
5871 : ChildIterator aIter,
5872 : PRUint8& aTargetContentDisplay)
5873 : {
5874 0 : nsIContent* child = *aIter;
5875 :
5876 : // Note: not all content objects are associated with a frame (e.g., if it's
5877 : // `display: none') so keep looking until we find a previous frame
5878 0 : while (aIter != aFirst) {
5879 0 : --aIter;
5880 : nsIFrame* prevSibling =
5881 0 : FindFrameForContentSibling(*aIter, child, aTargetContentDisplay, true);
5882 :
5883 0 : if (prevSibling) {
5884 : // Found a previous sibling, we're done!
5885 0 : return prevSibling;
5886 : }
5887 : }
5888 :
5889 0 : return nsnull;
5890 : }
5891 :
5892 : nsIFrame*
5893 0 : nsCSSFrameConstructor::FindNextSibling(ChildIterator aIter,
5894 : const ChildIterator& aLast,
5895 : PRUint8& aTargetContentDisplay)
5896 : {
5897 0 : if (aIter == aLast) {
5898 : // XXXbz Can happen when XBL lies to us about insertion points. This check
5899 : // might be able to go away once bug 474324 is fixed.
5900 0 : return nsnull;
5901 : }
5902 :
5903 0 : nsIContent* child = *aIter;
5904 :
5905 0 : while (++aIter != aLast) {
5906 : nsIFrame* nextSibling =
5907 0 : FindFrameForContentSibling(*aIter, child, aTargetContentDisplay, false);
5908 :
5909 0 : if (nextSibling) {
5910 : // We found a next sibling, we're done!
5911 0 : return nextSibling;
5912 : }
5913 : }
5914 :
5915 0 : return nsnull;
5916 : }
5917 :
5918 : // For fieldsets, returns the area frame, if the child is not a legend.
5919 : static nsIFrame*
5920 0 : GetAdjustedParentFrame(nsIFrame* aParentFrame,
5921 : nsIAtom* aParentFrameType,
5922 : nsIContent* aChildContent)
5923 : {
5924 0 : NS_PRECONDITION(nsGkAtoms::tableOuterFrame != aParentFrameType,
5925 : "Shouldn't be happening!");
5926 :
5927 0 : nsIFrame* newParent = nsnull;
5928 :
5929 0 : if (nsGkAtoms::fieldSetFrame == aParentFrameType) {
5930 : // If the parent is a fieldSet, use the fieldSet's area frame as the
5931 : // parent unless the new content is a legend.
5932 0 : nsCOMPtr<nsIDOMHTMLLegendElement> legendContent(do_QueryInterface(aChildContent));
5933 0 : if (!legendContent) {
5934 0 : newParent = GetFieldSetBlockFrame(aParentFrame);
5935 : }
5936 : }
5937 0 : return (newParent) ? newParent : aParentFrame;
5938 : }
5939 :
5940 : nsIFrame*
5941 0 : nsCSSFrameConstructor::GetInsertionPrevSibling(nsIFrame*& aParentFrame,
5942 : nsIContent* aContainer,
5943 : nsIContent* aChild,
5944 : bool* aIsAppend,
5945 : bool* aIsRangeInsertSafe,
5946 : nsIContent* aStartSkipChild,
5947 : nsIContent* aEndSkipChild)
5948 : {
5949 0 : *aIsAppend = false;
5950 :
5951 : // Find the frame that precedes the insertion point. Walk backwards
5952 : // from the parent frame to get the parent content, because if an
5953 : // XBL insertion point is involved, we'll need to use _that_ to find
5954 : // the preceding frame.
5955 :
5956 0 : NS_PRECONDITION(aParentFrame, "Must have parent frame to start with");
5957 0 : nsIContent* container = aParentFrame->GetContent();
5958 :
5959 0 : ChildIterator first, last;
5960 0 : ChildIterator::Init(container, &first, &last);
5961 0 : ChildIterator iter(first);
5962 0 : bool xblCase = iter.XBLInvolved() || container != aContainer;
5963 0 : if (xblCase || !aChild->IsRootOfAnonymousSubtree()) {
5964 : // The check for IsRootOfAnonymousSubtree() is because editor is
5965 : // severely broken and calls us directly for native anonymous
5966 : // nodes that it creates.
5967 0 : if (aStartSkipChild) {
5968 0 : iter.seek(aStartSkipChild);
5969 : } else {
5970 0 : iter.seek(aChild);
5971 : }
5972 : }
5973 : #ifdef DEBUG
5974 : else {
5975 : NS_WARNING("Someone passed native anonymous content directly into frame "
5976 0 : "construction. Stop doing that!");
5977 : }
5978 : #endif
5979 :
5980 0 : PRUint8 childDisplay = UNSET_DISPLAY;
5981 0 : nsIFrame* prevSibling = FindPreviousSibling(first, iter, childDisplay);
5982 :
5983 : // Now, find the geometric parent so that we can handle
5984 : // continuations properly. Use the prev sibling if we have it;
5985 : // otherwise use the next sibling.
5986 0 : if (prevSibling) {
5987 0 : aParentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
5988 : }
5989 : else {
5990 : // If there is no previous sibling, then find the frame that follows
5991 0 : if (aEndSkipChild) {
5992 0 : iter.seek(aEndSkipChild);
5993 0 : iter--;
5994 : }
5995 0 : nsIFrame* nextSibling = FindNextSibling(iter, last, childDisplay);
5996 :
5997 0 : if (nextSibling) {
5998 0 : aParentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
5999 : }
6000 : else {
6001 : // No previous or next sibling, so treat this like an appended frame.
6002 0 : *aIsAppend = true;
6003 0 : if (IsFrameSpecial(aParentFrame)) {
6004 : // Since we're appending, we'll walk to the last anonymous frame
6005 : // that was created for the broken inline frame. But don't walk
6006 : // to the trailing inline if it's empty; stop at the block.
6007 0 : aParentFrame = GetLastSpecialSibling(aParentFrame, false);
6008 : }
6009 : // Get continuation that parents the last child. This MUST be done
6010 : // before the AdjustAppendParentForAfterContent call.
6011 0 : aParentFrame = nsLayoutUtils::GetLastContinuationWithChild(aParentFrame);
6012 : // Deal with fieldsets
6013 : aParentFrame = ::GetAdjustedParentFrame(aParentFrame,
6014 0 : aParentFrame->GetType(),
6015 0 : aChild);
6016 : nsIFrame* appendAfterFrame;
6017 : aParentFrame =
6018 : ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
6019 : container, aParentFrame,
6020 0 : &appendAfterFrame);
6021 0 : prevSibling = ::FindAppendPrevSibling(aParentFrame, appendAfterFrame);
6022 : }
6023 : }
6024 :
6025 0 : *aIsRangeInsertSafe = (childDisplay == UNSET_DISPLAY);
6026 0 : return prevSibling;
6027 : }
6028 :
6029 : static bool
6030 0 : IsSpecialFramesetChild(nsIContent* aContent)
6031 : {
6032 : // IMPORTANT: This must match the conditions in nsHTMLFramesetFrame::Init.
6033 0 : return aContent->IsHTML() &&
6034 0 : (aContent->Tag() == nsGkAtoms::frameset ||
6035 0 : aContent->Tag() == nsGkAtoms::frame);
6036 : }
6037 :
6038 : static void
6039 : InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node);
6040 :
6041 : #ifdef MOZ_XUL
6042 :
6043 : static
6044 : bool
6045 0 : IsXULListBox(nsIContent* aContainer)
6046 : {
6047 0 : return (aContainer->IsXUL() && aContainer->Tag() == nsGkAtoms::listbox);
6048 : }
6049 :
6050 : static
6051 : nsListBoxBodyFrame*
6052 0 : MaybeGetListBoxBodyFrame(nsIContent* aContainer, nsIContent* aChild)
6053 : {
6054 0 : if (!aContainer)
6055 0 : return nsnull;
6056 :
6057 0 : if (IsXULListBox(aContainer) &&
6058 0 : aChild->IsXUL() && aChild->Tag() == nsGkAtoms::listitem) {
6059 0 : nsCOMPtr<nsIDOMXULElement> xulElement = do_QueryInterface(aContainer);
6060 0 : nsCOMPtr<nsIBoxObject> boxObject;
6061 0 : xulElement->GetBoxObject(getter_AddRefs(boxObject));
6062 0 : nsCOMPtr<nsPIListBoxObject> listBoxObject = do_QueryInterface(boxObject);
6063 0 : if (listBoxObject) {
6064 0 : return listBoxObject->GetListBoxBody(false);
6065 : }
6066 : }
6067 :
6068 0 : return nsnull;
6069 : }
6070 : #endif
6071 :
6072 : void
6073 0 : nsCSSFrameConstructor::AddTextItemIfNeeded(nsFrameConstructorState& aState,
6074 : nsIFrame* aParentFrame,
6075 : nsIContent* aPossibleTextContent,
6076 : FrameConstructionItemList& aItems)
6077 : {
6078 0 : NS_PRECONDITION(aPossibleTextContent, "Must have node");
6079 0 : if (!aPossibleTextContent->IsNodeOfType(nsINode::eTEXT) ||
6080 0 : !aPossibleTextContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) {
6081 : // Not text, or not suppressed due to being all-whitespace (if it
6082 : // were being suppressed, it would have the
6083 : // NS_CREATE_FRAME_IF_NON_WHITESPACE flag)
6084 0 : return;
6085 : }
6086 0 : NS_ASSERTION(!aPossibleTextContent->GetPrimaryFrame(),
6087 : "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
6088 : AddFrameConstructionItems(aState, aPossibleTextContent, false,
6089 0 : aParentFrame, aItems);
6090 : }
6091 :
6092 : void
6093 0 : nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aParentContent,
6094 : nsIContent* aContent)
6095 : {
6096 0 : if (!aContent->IsNodeOfType(nsINode::eTEXT) ||
6097 0 : !aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) {
6098 : // Not text, or not suppressed due to being all-whitespace (if it
6099 : // were being suppressed, it would have the
6100 : // NS_CREATE_FRAME_IF_NON_WHITESPACE flag)
6101 0 : return;
6102 : }
6103 0 : NS_ASSERTION(!aContent->GetPrimaryFrame(),
6104 : "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
6105 0 : ContentInserted(aParentContent, aContent, nsnull, false);
6106 : }
6107 :
6108 : // We want to disable lazy frame construction for nodes that are under an
6109 : // editor. We use nsINode::IsEditable, but that includes inputs with type text
6110 : // and password and textareas, which are common and aren't really editable (the
6111 : // native anonymous content under them is what is actually editable) so we want
6112 : // to construct frames for those lazily.
6113 : // The logic for this check is based on
6114 : // nsGenericHTMLFormElement::UpdateEditableFormControlState and so must be kept
6115 : // in sync with that. MayHaveContentEditableAttr() being true only indicates
6116 : // a contenteditable attribute, it doesn't indicate whether it is true or false,
6117 : // so we force eager construction in some cases when the node is not editable,
6118 : // but that should be rare.
6119 : static inline bool
6120 0 : IsActuallyEditable(nsIContent* aContainer, nsIContent* aChild)
6121 : {
6122 0 : return (aChild->IsEditable() &&
6123 0 : (aContainer->IsEditable() ||
6124 0 : aChild->MayHaveContentEditableAttr()));
6125 : }
6126 :
6127 : // For inserts aChild should be valid, for appends it should be null.
6128 : // Returns true if this operation can be lazy, false if not.
6129 : bool
6130 0 : nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
6131 : nsIContent* aContainer,
6132 : nsIContent* aChild)
6133 : {
6134 0 : if (mPresShell->GetPresContext()->IsChrome() || !aContainer ||
6135 0 : aContainer->IsInNativeAnonymousSubtree() || aContainer->IsXUL()) {
6136 0 : return false;
6137 : }
6138 :
6139 0 : if (aOperation == CONTENTINSERT) {
6140 0 : if (aChild->IsRootOfAnonymousSubtree() ||
6141 0 : aChild->IsXUL() || IsActuallyEditable(aContainer, aChild)) {
6142 0 : return false;
6143 : }
6144 : } else { // CONTENTAPPEND
6145 0 : NS_ASSERTION(aOperation == CONTENTAPPEND,
6146 : "operation should be either insert or append");
6147 0 : for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
6148 0 : NS_ASSERTION(!child->IsRootOfAnonymousSubtree(),
6149 : "Should be coming through the CONTENTAPPEND case");
6150 0 : if (child->IsXUL() || IsActuallyEditable(aContainer, child)) {
6151 0 : return false;
6152 : }
6153 : }
6154 : }
6155 :
6156 : // We can construct lazily; just need to set suitable bits in the content
6157 : // tree.
6158 :
6159 : // Walk up the tree setting the NODE_DESCENDANTS_NEED_FRAMES bit as we go.
6160 0 : nsIContent* content = aContainer;
6161 : #ifdef DEBUG
6162 : // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
6163 : // we want to assert, but leaf frames that process their own children and may
6164 : // ignore anonymous children (eg framesets) make this complicated. So we set
6165 : // these two booleans if we encounter these situations and unset them if we
6166 : // hit a node with a leaf frame.
6167 0 : bool noPrimaryFrame = false;
6168 0 : bool needsFrameBitSet = false;
6169 : #endif
6170 0 : while (content &&
6171 0 : !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
6172 : #ifdef DEBUG
6173 0 : if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) {
6174 0 : noPrimaryFrame = needsFrameBitSet = false;
6175 : }
6176 0 : if (!noPrimaryFrame && !content->GetPrimaryFrame()) {
6177 0 : noPrimaryFrame = true;
6178 : }
6179 0 : if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
6180 0 : needsFrameBitSet = true;
6181 : }
6182 : #endif
6183 0 : content->SetFlags(NODE_DESCENDANTS_NEED_FRAMES);
6184 0 : content = content->GetFlattenedTreeParent();
6185 : }
6186 : #ifdef DEBUG
6187 0 : if (content && content->GetPrimaryFrame() &&
6188 0 : content->GetPrimaryFrame()->IsLeaf()) {
6189 0 : noPrimaryFrame = needsFrameBitSet = false;
6190 : }
6191 0 : NS_ASSERTION(!noPrimaryFrame, "Ancestors of nodes with frames to be "
6192 : "constructed lazily should have frames");
6193 0 : NS_ASSERTION(!needsFrameBitSet, "Ancestors of nodes with frames to be "
6194 : "constructed lazily should not have NEEDS_FRAME bit set");
6195 : #endif
6196 :
6197 : // Set NODE_NEEDS_FRAME on the new nodes.
6198 0 : if (aOperation == CONTENTINSERT) {
6199 0 : NS_ASSERTION(!aChild->GetPrimaryFrame() ||
6200 : aChild->GetPrimaryFrame()->GetContent() != aChild,
6201 : //XXX the aChild->GetPrimaryFrame()->GetContent() != aChild
6202 : // check is needed due to bug 135040. Remove it once that's
6203 : // fixed.
6204 : "setting NEEDS_FRAME on a node that already has a frame?");
6205 0 : aChild->SetFlags(NODE_NEEDS_FRAME);
6206 : } else { // CONTENTAPPEND
6207 0 : for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
6208 0 : NS_ASSERTION(!child->GetPrimaryFrame() ||
6209 : child->GetPrimaryFrame()->GetContent() != child,
6210 : //XXX the child->GetPrimaryFrame()->GetContent() != child
6211 : // check is needed due to bug 135040. Remove it once that's
6212 : // fixed.
6213 : "setting NEEDS_FRAME on a node that already has a frame?");
6214 0 : child->SetFlags(NODE_NEEDS_FRAME);
6215 : }
6216 : }
6217 :
6218 0 : PostRestyleEventInternal(true);
6219 0 : return true;
6220 : }
6221 :
6222 : void
6223 0 : nsCSSFrameConstructor::CreateNeededFrames(nsIContent* aContent)
6224 : {
6225 0 : NS_ASSERTION(!aContent->HasFlag(NODE_NEEDS_FRAME),
6226 : "shouldn't get here with a content node that has needs frame bit set");
6227 0 : NS_ASSERTION(aContent->HasFlag(NODE_DESCENDANTS_NEED_FRAMES),
6228 : "should only get here with a content node that has descendants needing frames");
6229 :
6230 0 : aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
6231 :
6232 : // We could either descend first (on nodes that don't have NODE_NEEDS_FRAME
6233 : // set) or issue content notifications for our kids first. In absence of
6234 : // anything definitive either way we'll go with the latter.
6235 :
6236 : // It might be better to use GetChildArray and scan it completely first and
6237 : // then issue all notifications. (We have to scan it completely first because
6238 : // constructing frames can set attributes, which can change the storage of
6239 : // child lists).
6240 :
6241 : // Scan the children of aContent to see what operations (if any) we need to
6242 : // perform.
6243 0 : PRUint32 childCount = aContent->GetChildCount();
6244 0 : bool inRun = false;
6245 0 : nsIContent* firstChildInRun = nsnull;
6246 0 : for (PRUint32 i = 0; i < childCount; i++) {
6247 0 : nsIContent* child = aContent->GetChildAt(i);
6248 0 : if (child->HasFlag(NODE_NEEDS_FRAME)) {
6249 0 : NS_ASSERTION(!child->GetPrimaryFrame() ||
6250 : child->GetPrimaryFrame()->GetContent() != child,
6251 : //XXX the child->GetPrimaryFrame()->GetContent() != child
6252 : // check is needed due to bug 135040. Remove it once that's
6253 : // fixed.
6254 : "NEEDS_FRAME set on a node that already has a frame?");
6255 0 : if (!inRun) {
6256 0 : inRun = true;
6257 0 : firstChildInRun = child;
6258 : }
6259 : } else {
6260 0 : if (inRun) {
6261 0 : inRun = false;
6262 : // generate a ContentRangeInserted for [startOfRun,i)
6263 : ContentRangeInserted(aContent, firstChildInRun, child, nsnull,
6264 0 : false);
6265 : }
6266 : }
6267 : }
6268 0 : if (inRun) {
6269 0 : ContentAppended(aContent, firstChildInRun, false);
6270 : }
6271 :
6272 : // Now descend.
6273 0 : ChildIterator iter, last;
6274 0 : for (ChildIterator::Init(aContent, &iter, &last);
6275 : iter != last;
6276 : ++iter) {
6277 0 : nsIContent* child = *iter;
6278 0 : if (child->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
6279 0 : CreateNeededFrames(child);
6280 : }
6281 : }
6282 0 : }
6283 :
6284 0 : void nsCSSFrameConstructor::CreateNeededFrames()
6285 : {
6286 0 : NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
6287 : "Someone forgot a script blocker");
6288 :
6289 0 : Element* rootElement = mDocument->GetRootElement();
6290 0 : NS_ASSERTION(!rootElement || !rootElement->HasFlag(NODE_NEEDS_FRAME),
6291 : "root element should not have frame created lazily");
6292 0 : if (rootElement && rootElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
6293 0 : BeginUpdate();
6294 0 : CreateNeededFrames(rootElement);
6295 0 : EndUpdate();
6296 : }
6297 0 : }
6298 :
6299 : void
6300 0 : nsCSSFrameConstructor::IssueSingleInsertNofications(nsIContent* aContainer,
6301 : nsIContent* aStartChild,
6302 : nsIContent* aEndChild,
6303 : bool aAllowLazyConstruction)
6304 : {
6305 0 : for (nsIContent* child = aStartChild;
6306 : child != aEndChild;
6307 0 : child = child->GetNextSibling()) {
6308 0 : if ((child->GetPrimaryFrame() ||
6309 0 : GetUndisplayedContent(child))
6310 : #ifdef MOZ_XUL
6311 : // Except listboxes suck, so do NOT skip anything here if
6312 : // we plan to notify a listbox.
6313 0 : && !MaybeGetListBoxBodyFrame(aContainer, child)
6314 : #endif
6315 : ) {
6316 : // Already have a frame or undisplayed entry for this content; a
6317 : // previous ContentInserted in this loop must have reconstructed
6318 : // its insertion parent. Skip it.
6319 0 : continue;
6320 : }
6321 : // Call ContentInserted with this node.
6322 : ContentInserted(aContainer, child, mTempFrameTreeState,
6323 0 : aAllowLazyConstruction);
6324 : }
6325 0 : }
6326 :
6327 : nsIFrame*
6328 0 : nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent* aContainer,
6329 : nsIFrame* aParentFrame,
6330 : nsIContent* aStartChild,
6331 : nsIContent* aEndChild,
6332 : bool aAllowLazyConstruction)
6333 : {
6334 : // See if we have an XBL insertion point. If so, then that's our
6335 : // real parent frame; if not, then the frame hasn't been built yet
6336 : // and we just bail.
6337 : nsIFrame* insertionPoint;
6338 0 : bool multiple = false;
6339 0 : GetInsertionPoint(aParentFrame, nsnull, &insertionPoint, &multiple);
6340 0 : if (! insertionPoint)
6341 0 : return nsnull; // Don't build the frames.
6342 :
6343 0 : bool hasInsertion = false;
6344 0 : if (!multiple) {
6345 : // XXXbz XBL2/sXBL issue
6346 0 : nsIDocument* document = aStartChild->GetDocument();
6347 : // XXXbz how would |document| be null here?
6348 0 : if (document &&
6349 0 : document->BindingManager()->GetInsertionParent(aStartChild)) {
6350 0 : hasInsertion = true;
6351 : }
6352 : }
6353 :
6354 0 : if (multiple || hasInsertion) {
6355 : // We have an insertion point. There are some additional tests we need to do
6356 : // in order to ensure that an append is a safe operation.
6357 0 : PRUint32 childCount = 0;
6358 :
6359 0 : if (!multiple) {
6360 : // We may need to make multiple ContentInserted calls instead. A
6361 : // reasonable heuristic to employ (in order to maintain good performance)
6362 : // is to find out if the insertion point's content node contains any
6363 : // explicit children. If it does not, then it is highly likely that
6364 : // an append is occurring. (Note it is not definite, and there are insane
6365 : // cases we will not deal with by employing this heuristic, but it beats
6366 : // always falling back to multiple ContentInserted calls).
6367 : //
6368 : // In the multiple insertion point case, we know we're going to need to do
6369 : // multiple ContentInserted calls anyway.
6370 0 : childCount = insertionPoint->GetContent()->GetChildCount();
6371 : }
6372 :
6373 : // If we have multiple insertion points or if we have an insertion point
6374 : // and the operation is not a true append or if the insertion point already
6375 : // has explicit children, then we must fall back.
6376 0 : if (multiple || aEndChild != nsnull || childCount > 0) {
6377 : // Now comes the fun part. For each inserted child, make a
6378 : // ContentInserted call as if it had just gotten inserted and
6379 : // let ContentInserted handle the mess.
6380 : IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
6381 0 : aAllowLazyConstruction);
6382 0 : return nsnull;
6383 : }
6384 : }
6385 :
6386 0 : return insertionPoint;
6387 : }
6388 :
6389 : bool
6390 0 : nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
6391 : nsIContent* aStartChild,
6392 : nsIContent* aEndChild)
6393 : {
6394 0 : if (aParentFrame->GetType() == nsGkAtoms::frameSetFrame) {
6395 : // Check whether we have any kids we care about.
6396 0 : for (nsIContent* cur = aStartChild;
6397 : cur != aEndChild;
6398 0 : cur = cur->GetNextSibling()) {
6399 0 : if (IsSpecialFramesetChild(cur)) {
6400 : // Just reframe the parent, since framesets are weird like that.
6401 0 : RecreateFramesForContent(aParentFrame->GetContent(), false);
6402 0 : return true;
6403 : }
6404 : }
6405 : }
6406 0 : return false;
6407 : }
6408 :
6409 : nsresult
6410 0 : nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
6411 : nsIContent* aFirstNewContent,
6412 : bool aAllowLazyConstruction)
6413 : {
6414 0 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
6415 0 : NS_PRECONDITION(mUpdateCount != 0,
6416 : "Should be in an update while creating frames");
6417 :
6418 : #ifdef DEBUG
6419 0 : if (gNoisyContentUpdates) {
6420 : printf("nsCSSFrameConstructor::ContentAppended container=%p "
6421 : "first-child=%p lazy=%d\n",
6422 : static_cast<void*>(aContainer), aFirstNewContent,
6423 0 : aAllowLazyConstruction);
6424 0 : if (gReallyNoisyContentUpdates && aContainer) {
6425 0 : aContainer->List(stdout, 0);
6426 : }
6427 : }
6428 : #endif
6429 :
6430 : #ifdef DEBUG
6431 0 : for (nsIContent* child = aFirstNewContent;
6432 : child;
6433 0 : child = child->GetNextSibling()) {
6434 : // XXX the GetContent() != child check is needed due to bug 135040.
6435 : // Remove it once that's fixed.
6436 0 : NS_ASSERTION(!child->GetPrimaryFrame() ||
6437 : child->GetPrimaryFrame()->GetContent() != child,
6438 : "asked to construct a frame for a node that already has a frame");
6439 : }
6440 : #endif
6441 :
6442 : #ifdef MOZ_XUL
6443 0 : if (aContainer) {
6444 : PRInt32 namespaceID;
6445 : nsIAtom* tag =
6446 0 : mDocument->BindingManager()->ResolveTag(aContainer, &namespaceID);
6447 :
6448 : // Just ignore tree tags, anyway we don't create any frames for them.
6449 0 : if (tag == nsGkAtoms::treechildren ||
6450 : tag == nsGkAtoms::treeitem ||
6451 : tag == nsGkAtoms::treerow)
6452 0 : return NS_OK;
6453 :
6454 : }
6455 : #endif // MOZ_XUL
6456 :
6457 : // Get the frame associated with the content
6458 0 : nsIFrame* parentFrame = GetFrameFor(aContainer);
6459 0 : if (! parentFrame)
6460 0 : return NS_OK;
6461 :
6462 0 : if (aAllowLazyConstruction &&
6463 0 : MaybeConstructLazily(CONTENTAPPEND, aContainer, aFirstNewContent)) {
6464 0 : return NS_OK;
6465 : }
6466 :
6467 0 : LAYOUT_PHASE_TEMP_EXIT();
6468 : parentFrame = GetRangeInsertionPoint(aContainer, parentFrame,
6469 : aFirstNewContent, nsnull,
6470 0 : aAllowLazyConstruction);
6471 0 : LAYOUT_PHASE_TEMP_REENTER();
6472 0 : if (!parentFrame) {
6473 0 : return NS_OK;
6474 : }
6475 :
6476 0 : LAYOUT_PHASE_TEMP_EXIT();
6477 0 : if (MaybeRecreateForFrameset(parentFrame, aFirstNewContent, nsnull)) {
6478 0 : LAYOUT_PHASE_TEMP_REENTER();
6479 0 : return NS_OK;
6480 : }
6481 0 : LAYOUT_PHASE_TEMP_REENTER();
6482 :
6483 0 : if (parentFrame->IsLeaf()) {
6484 : // Nothing to do here; we shouldn't be constructing kids of leaves
6485 : // Clear lazy bits so we don't try to construct again.
6486 0 : ClearLazyBits(aFirstNewContent, nsnull);
6487 0 : return NS_OK;
6488 : }
6489 :
6490 0 : if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) {
6491 0 : LAYOUT_PHASE_TEMP_EXIT();
6492 0 : nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false);
6493 0 : LAYOUT_PHASE_TEMP_REENTER();
6494 0 : return rv;
6495 : }
6496 :
6497 : // If the frame we are manipulating is a ``special'' frame (that is, one
6498 : // that's been created as a result of a block-in-inline situation) then we
6499 : // need to append to the last special sibling, not to the frame itself.
6500 0 : bool parentSpecial = IsFrameSpecial(parentFrame);
6501 0 : if (parentSpecial) {
6502 : #ifdef DEBUG
6503 0 : if (gNoisyContentUpdates) {
6504 0 : printf("nsCSSFrameConstructor::ContentAppended: parentFrame=");
6505 0 : nsFrame::ListTag(stdout, parentFrame);
6506 0 : printf(" is special\n");
6507 : }
6508 : #endif
6509 :
6510 : // Since we're appending, we'll walk to the last anonymous frame
6511 : // that was created for the broken inline frame. But don't walk
6512 : // to the trailing inline if it's empty; stop at the block.
6513 0 : parentFrame = GetLastSpecialSibling(parentFrame, false);
6514 : }
6515 :
6516 : // Get continuation that parents the last child. This MUST be done
6517 : // before the AdjustAppendParentForAfterContent call.
6518 0 : parentFrame = nsLayoutUtils::GetLastContinuationWithChild(parentFrame);
6519 :
6520 : // We should never get here with fieldsets, since they have multiple
6521 : // insertion points.
6522 0 : NS_ASSERTION(parentFrame->GetType() != nsGkAtoms::fieldSetFrame,
6523 : "Unexpected parent");
6524 :
6525 : // Deal with possible :after generated content on the parent
6526 : nsIFrame* parentAfterFrame;
6527 : parentFrame =
6528 : ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
6529 : aContainer, parentFrame,
6530 0 : &parentAfterFrame);
6531 :
6532 : // Create some new frames
6533 : nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
6534 : GetAbsoluteContainingBlock(parentFrame),
6535 0 : GetFloatContainingBlock(parentFrame));
6536 0 : state.mTreeMatchContext.mAncestorFilter.Init(aContainer->AsElement());
6537 :
6538 : // See if the containing block has :first-letter style applied.
6539 0 : bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
6540 0 : nsIFrame* containingBlock = state.mFloatedItems.containingBlock;
6541 0 : if (containingBlock) {
6542 0 : haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
6543 : haveFirstLineStyle =
6544 : ShouldHaveFirstLineStyle(containingBlock->GetContent(),
6545 0 : containingBlock->GetStyleContext());
6546 : }
6547 :
6548 0 : if (haveFirstLetterStyle) {
6549 : // Before we get going, remove the current letter frames
6550 : RemoveLetterFrames(state.mPresContext, state.mPresShell,
6551 0 : containingBlock);
6552 : }
6553 :
6554 0 : nsIAtom* frameType = parentFrame->GetType();
6555 : bool haveNoXBLChildren =
6556 0 : mDocument->BindingManager()->GetXBLChildNodesFor(aContainer) == nsnull;
6557 0 : FrameConstructionItemList items;
6558 0 : if (aFirstNewContent->GetPreviousSibling() &&
6559 0 : GetParentType(frameType) == eTypeBlock &&
6560 : haveNoXBLChildren) {
6561 : // If there's a text node in the normal content list just before the new
6562 : // items, and it has no frame, make a frame construction item for it. If it
6563 : // doesn't need a frame, ConstructFramesFromItemList below won't give it
6564 : // one. No need to do all this if our parent type is not block, though,
6565 : // since WipeContainingBlock already handles that situation.
6566 : //
6567 : // Because we're appending, we don't need to worry about any text
6568 : // after the appended content; there can only be XBL anonymous content
6569 : // (text in an XBL binding is not suppressed) or generated content
6570 : // (and bare text nodes are not generated). Native anonymous content
6571 : // generated by frames never participates in inline layout.
6572 : AddTextItemIfNeeded(state, parentFrame,
6573 0 : aFirstNewContent->GetPreviousSibling(), items);
6574 : }
6575 0 : for (nsIContent* child = aFirstNewContent;
6576 : child;
6577 0 : child = child->GetNextSibling()) {
6578 0 : AddFrameConstructionItems(state, child, false, parentFrame, items);
6579 : }
6580 :
6581 0 : nsIFrame* prevSibling = ::FindAppendPrevSibling(parentFrame, parentAfterFrame);
6582 :
6583 : // Perform special check for diddling around with the frames in
6584 : // a special inline frame.
6585 : // If we're appending before :after content, then we're not really
6586 : // appending, so let WipeContainingBlock know that.
6587 0 : LAYOUT_PHASE_TEMP_EXIT();
6588 0 : if (WipeContainingBlock(state, containingBlock, parentFrame, items,
6589 : true, prevSibling)) {
6590 0 : LAYOUT_PHASE_TEMP_REENTER();
6591 0 : return NS_OK;
6592 : }
6593 0 : LAYOUT_PHASE_TEMP_REENTER();
6594 :
6595 : // If the parent is a block frame, and we're not in a special case
6596 : // where frames can be moved around, determine if the list is for the
6597 : // start or end of the block.
6598 0 : if (nsLayoutUtils::GetAsBlock(parentFrame) && !haveFirstLetterStyle &&
6599 0 : !haveFirstLineStyle && !parentSpecial) {
6600 : items.SetLineBoundaryAtStart(!prevSibling ||
6601 0 : !prevSibling->GetStyleDisplay()->IsInlineOutside() ||
6602 0 : prevSibling->GetType() == nsGkAtoms::brFrame);
6603 : // :after content can't be <br> so no need to check it
6604 0 : items.SetLineBoundaryAtEnd(!parentAfterFrame ||
6605 0 : !parentAfterFrame->GetStyleDisplay()->IsInlineOutside());
6606 : }
6607 : // To suppress whitespace-only text frames, we have to verify that
6608 : // our container's DOM child list matches its flattened tree child list.
6609 : // This is guaranteed to be true if GetXBLChildNodesFor() returns null.
6610 0 : items.SetParentHasNoXBLChildren(haveNoXBLChildren);
6611 :
6612 0 : nsFrameItems frameItems;
6613 0 : ConstructFramesFromItemList(state, items, parentFrame, frameItems);
6614 :
6615 0 : for (nsIContent* child = aFirstNewContent;
6616 : child;
6617 0 : child = child->GetNextSibling()) {
6618 : // Invalidate now instead of before the WipeContainingBlock call, just in
6619 : // case we do wipe; in that case we don't need to do this walk at all.
6620 : // XXXbz does that matter? Would it make more sense to save some virtual
6621 : // GetChildAt calls instead and do this during construction of our
6622 : // FrameConstructionItemList?
6623 0 : InvalidateCanvasIfNeeded(mPresShell, child);
6624 : }
6625 :
6626 : // if the container is a table and a caption was appended, it needs to be put
6627 : // in the outer table frame's additional child list.
6628 0 : nsFrameItems captionItems;
6629 0 : if (nsGkAtoms::tableFrame == frameType) {
6630 : // Pull out the captions. Note that we don't want to do that as we go,
6631 : // because processing a single caption can add a whole bunch of things to
6632 : // the frame items due to pseudoframe processing. So we'd have to pull
6633 : // captions from a list anyway; might as well do that here.
6634 : // XXXbz this is no longer true; we could pull captions directly out of the
6635 : // FrameConstructionItemList now.
6636 0 : PullOutCaptionFrames(frameItems, captionItems);
6637 : }
6638 :
6639 0 : if (haveFirstLineStyle && parentFrame == containingBlock) {
6640 : // It's possible that some of the new frames go into a
6641 : // first-line frame. Look at them and see...
6642 : AppendFirstLineFrames(state, containingBlock->GetContent(),
6643 0 : containingBlock, frameItems);
6644 : }
6645 :
6646 : // Notify the parent frame passing it the list of new frames
6647 : // Append the flowed frames to the principal child list; captions
6648 : // need special treatment
6649 0 : if (captionItems.NotEmpty()) { // append the caption to the outer table
6650 0 : NS_ASSERTION(nsGkAtoms::tableFrame == frameType, "how did that happen?");
6651 0 : nsIFrame* outerTable = parentFrame->GetParent();
6652 0 : AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems);
6653 : }
6654 :
6655 0 : if (frameItems.NotEmpty()) { // append the in-flow kids
6656 0 : AppendFramesToParent(state, parentFrame, frameItems, prevSibling);
6657 : }
6658 :
6659 : // Recover first-letter frames
6660 0 : if (haveFirstLetterStyle) {
6661 0 : RecoverLetterFrames(containingBlock);
6662 : }
6663 :
6664 : #ifdef DEBUG
6665 0 : if (gReallyNoisyContentUpdates) {
6666 0 : printf("nsCSSFrameConstructor::ContentAppended: resulting frame model:\n");
6667 0 : parentFrame->List(stdout, 0);
6668 : }
6669 : #endif
6670 :
6671 : #ifdef ACCESSIBILITY
6672 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
6673 0 : if (accService) {
6674 : accService->ContentRangeInserted(mPresShell, aContainer,
6675 0 : aFirstNewContent, nsnull);
6676 : }
6677 : #endif
6678 :
6679 0 : return NS_OK;
6680 : }
6681 :
6682 : #ifdef MOZ_XUL
6683 :
6684 : enum content_operation
6685 : {
6686 : CONTENT_INSERTED,
6687 : CONTENT_REMOVED
6688 : };
6689 :
6690 : // Helper function to lookup the listbox body frame and send a notification
6691 : // for insertion or removal of content
6692 : static
6693 0 : bool NotifyListBoxBody(nsPresContext* aPresContext,
6694 : nsIContent* aContainer,
6695 : nsIContent* aChild,
6696 : // Only used for the removed notification
6697 : nsIContent* aOldNextSibling,
6698 : nsIDocument* aDocument,
6699 : nsIFrame* aChildFrame,
6700 : content_operation aOperation)
6701 : {
6702 : nsListBoxBodyFrame* listBoxBodyFrame =
6703 0 : MaybeGetListBoxBodyFrame(aContainer, aChild);
6704 0 : if (listBoxBodyFrame) {
6705 0 : if (aOperation == CONTENT_REMOVED) {
6706 : // Except if we have an aChildFrame and its parent is not the right
6707 : // thing, then we don't do this. Pseudo frames are so much fun....
6708 0 : if (!aChildFrame || aChildFrame->GetParent() == listBoxBodyFrame) {
6709 : listBoxBodyFrame->OnContentRemoved(aPresContext, aContainer,
6710 0 : aChildFrame, aOldNextSibling);
6711 0 : return true;
6712 : }
6713 : } else {
6714 0 : listBoxBodyFrame->OnContentInserted(aPresContext, aChild);
6715 0 : return true;
6716 : }
6717 : }
6718 :
6719 0 : return false;
6720 : }
6721 : #endif // MOZ_XUL
6722 :
6723 : nsresult
6724 0 : nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
6725 : nsIContent* aChild,
6726 : nsILayoutHistoryState* aFrameState,
6727 : bool aAllowLazyConstruction)
6728 : {
6729 : return ContentRangeInserted(aContainer,
6730 : aChild,
6731 : aChild->GetNextSibling(),
6732 : aFrameState,
6733 0 : aAllowLazyConstruction);
6734 : }
6735 :
6736 : // ContentRangeInserted handles creating frames for a range of nodes that
6737 : // aren't at the end of their childlist. ContentRangeInserted isn't a real
6738 : // content notification, but rather it handles regular ContentInserted calls
6739 : // for a single node as well as the lazy construction of frames for a range of
6740 : // nodes when called from CreateNeededFrames. For a range of nodes to be
6741 : // suitable to have its frames constructed all at once they must meet the same
6742 : // conditions that ContentAppended imposes (GetRangeInsertionPoint checks
6743 : // these), plus more. Namely when finding the insertion prevsibling we must not
6744 : // need to consult something specific to any one node in the range, so that the
6745 : // insertion prevsibling would be the same for each node in the range. So we
6746 : // pass the first node in the range to GetInsertionPrevSibling, and if
6747 : // IsValidSibling (the only place GetInsertionPrevSibling might look at the
6748 : // passed in node itself) needs to resolve style on the node we record this and
6749 : // return that this range needs to be split up and inserted separately. Table
6750 : // captions need extra attention as we need to determine where to insert them
6751 : // in the caption list, while skipping any nodes in the range being inserted
6752 : // (because when we treat the caption frames the other nodes have had their
6753 : // frames constructed but not yet inserted into the frame tree).
6754 : nsresult
6755 0 : nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
6756 : nsIContent* aStartChild,
6757 : nsIContent* aEndChild,
6758 : nsILayoutHistoryState* aFrameState,
6759 : bool aAllowLazyConstruction)
6760 : {
6761 0 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
6762 0 : NS_PRECONDITION(mUpdateCount != 0,
6763 : "Should be in an update while creating frames");
6764 :
6765 0 : NS_PRECONDITION(aStartChild, "must always pass a child");
6766 :
6767 : // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
6768 : // the :empty pseudo-class?
6769 : #ifdef DEBUG
6770 0 : if (gNoisyContentUpdates) {
6771 : printf("nsCSSFrameConstructor::ContentRangeInserted container=%p "
6772 : "start-child=%p end-child=%p lazy=%d\n",
6773 : static_cast<void*>(aContainer),
6774 : static_cast<void*>(aStartChild), static_cast<void*>(aEndChild),
6775 0 : aAllowLazyConstruction);
6776 0 : if (gReallyNoisyContentUpdates) {
6777 0 : if (aContainer) {
6778 0 : aContainer->List(stdout,0);
6779 : } else {
6780 0 : aStartChild->List(stdout, 0);
6781 : }
6782 : }
6783 : }
6784 : #endif
6785 :
6786 : #ifdef DEBUG
6787 0 : for (nsIContent* child = aStartChild;
6788 : child != aEndChild;
6789 0 : child = child->GetNextSibling()) {
6790 : // XXX the GetContent() != child check is needed due to bug 135040.
6791 : // Remove it once that's fixed.
6792 0 : NS_ASSERTION(!child->GetPrimaryFrame() ||
6793 : child->GetPrimaryFrame()->GetContent() != child,
6794 : "asked to construct a frame for a node that already has a frame");
6795 : }
6796 : #endif
6797 :
6798 0 : nsresult rv = NS_OK;
6799 :
6800 0 : bool isSingleInsert = (aStartChild->GetNextSibling() == aEndChild);
6801 0 : NS_ASSERTION(isSingleInsert || !aAllowLazyConstruction,
6802 : "range insert shouldn't be lazy");
6803 0 : NS_ASSERTION(isSingleInsert || aEndChild,
6804 : "range should not include all nodes after aStartChild");
6805 :
6806 : #ifdef MOZ_XUL
6807 0 : if (aContainer && IsXULListBox(aContainer)) {
6808 0 : if (isSingleInsert) {
6809 0 : if (NotifyListBoxBody(mPresShell->GetPresContext(), aContainer,
6810 : // The insert case in NotifyListBoxBody
6811 : // doesn't use "old next sibling".
6812 : aStartChild, nsnull,
6813 0 : mDocument, nsnull, CONTENT_INSERTED)) {
6814 0 : return NS_OK;
6815 : }
6816 : } else {
6817 : // We don't handle a range insert to a listbox parent, issue single
6818 : // ContertInserted calls for each node inserted.
6819 0 : LAYOUT_PHASE_TEMP_EXIT();
6820 : IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
6821 0 : aAllowLazyConstruction);
6822 0 : LAYOUT_PHASE_TEMP_REENTER();
6823 0 : return NS_OK;
6824 : }
6825 : }
6826 : #endif // MOZ_XUL
6827 :
6828 : // If we have a null parent, then this must be the document element being
6829 : // inserted, or some other child of the document in the DOM (might be a PI,
6830 : // say).
6831 0 : if (! aContainer) {
6832 0 : NS_ASSERTION(isSingleInsert,
6833 : "root node insertion should be a single insertion");
6834 0 : Element *docElement = mDocument->GetRootElement();
6835 :
6836 0 : if (aStartChild != docElement) {
6837 : // Not the root element; just bail out
6838 0 : return NS_OK;
6839 : }
6840 :
6841 0 : NS_PRECONDITION(nsnull == mRootElementFrame,
6842 : "root element frame already created");
6843 :
6844 : // Create frames for the document element and its child elements
6845 : nsIFrame* docElementFrame;
6846 0 : rv = ConstructDocElementFrame(docElement, aFrameState, &docElementFrame);
6847 :
6848 0 : if (NS_SUCCEEDED(rv) && docElementFrame) {
6849 0 : InvalidateCanvasIfNeeded(mPresShell, aStartChild);
6850 : #ifdef DEBUG
6851 0 : if (gReallyNoisyContentUpdates) {
6852 : printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
6853 0 : "model:\n");
6854 0 : mFixedContainingBlock->List(stdout, 0);
6855 : }
6856 : #endif
6857 : }
6858 :
6859 : #ifdef ACCESSIBILITY
6860 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
6861 0 : if (accService) {
6862 : accService->ContentRangeInserted(mPresShell, aContainer,
6863 0 : aStartChild, aEndChild);
6864 : }
6865 : #endif
6866 :
6867 0 : return NS_OK;
6868 : }
6869 :
6870 : // Otherwise, we've got parent content. Find its frame.
6871 0 : nsIFrame* parentFrame = GetFrameFor(aContainer);
6872 0 : if (! parentFrame)
6873 0 : return NS_OK;
6874 :
6875 0 : if (aAllowLazyConstruction &&
6876 0 : MaybeConstructLazily(CONTENTINSERT, aContainer, aStartChild)) {
6877 0 : return NS_OK;
6878 : }
6879 :
6880 0 : if (isSingleInsert) {
6881 : // See if we have an XBL insertion point. If so, then that's our
6882 : // real parent frame; if not, then the frame hasn't been built yet
6883 : // and we just bail.
6884 : nsIFrame* insertionPoint;
6885 0 : GetInsertionPoint(parentFrame, aStartChild, &insertionPoint);
6886 0 : if (! insertionPoint)
6887 0 : return NS_OK; // Don't build the frames.
6888 :
6889 0 : parentFrame = insertionPoint;
6890 : } else {
6891 : // Get our insertion point. If we need to issue single ContentInserted's
6892 : // GetRangeInsertionPoint will take care of that for us.
6893 0 : LAYOUT_PHASE_TEMP_EXIT();
6894 : parentFrame = GetRangeInsertionPoint(aContainer, parentFrame,
6895 : aStartChild, aEndChild,
6896 0 : aAllowLazyConstruction);
6897 0 : LAYOUT_PHASE_TEMP_REENTER();
6898 0 : if (!parentFrame) {
6899 0 : return NS_OK;
6900 : }
6901 : }
6902 :
6903 : bool isAppend, isRangeInsertSafe;
6904 : nsIFrame* prevSibling =
6905 : GetInsertionPrevSibling(parentFrame, aContainer, aStartChild,
6906 0 : &isAppend, &isRangeInsertSafe);
6907 :
6908 : // check if range insert is safe
6909 0 : if (!isSingleInsert && !isRangeInsertSafe) {
6910 : // must fall back to a single ContertInserted for each child in the range
6911 0 : LAYOUT_PHASE_TEMP_EXIT();
6912 : IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
6913 0 : aAllowLazyConstruction);
6914 0 : LAYOUT_PHASE_TEMP_REENTER();
6915 0 : return NS_OK;
6916 : }
6917 :
6918 0 : nsIContent* container = parentFrame->GetContent();
6919 :
6920 0 : nsIAtom* frameType = parentFrame->GetType();
6921 0 : LAYOUT_PHASE_TEMP_EXIT();
6922 0 : if (MaybeRecreateForFrameset(parentFrame, aStartChild, aEndChild)) {
6923 0 : LAYOUT_PHASE_TEMP_REENTER();
6924 0 : return NS_OK;
6925 : }
6926 0 : LAYOUT_PHASE_TEMP_REENTER();
6927 :
6928 : // We should only get here with fieldsets when doing a single insert, because
6929 : // fieldsets have multiple insertion points.
6930 0 : NS_ASSERTION(isSingleInsert || frameType != nsGkAtoms::fieldSetFrame,
6931 : "Unexpected parent");
6932 0 : if (frameType == nsGkAtoms::fieldSetFrame &&
6933 0 : aStartChild->Tag() == nsGkAtoms::legend) {
6934 : // Just reframe the parent, since figuring out whether this
6935 : // should be the new legend and then handling it is too complex.
6936 : // We could do a little better here --- check if the fieldset already
6937 : // has a legend which occurs earlier in its child list than this node,
6938 : // and if so, proceed. But we'd have to extend nsFieldSetFrame
6939 : // to locate this legend in the inserted frames and extract it.
6940 0 : LAYOUT_PHASE_TEMP_EXIT();
6941 0 : nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false);
6942 0 : LAYOUT_PHASE_TEMP_REENTER();
6943 0 : return rv;
6944 : }
6945 :
6946 : // Don't construct kids of leaves
6947 0 : if (parentFrame->IsLeaf()) {
6948 : // Clear lazy bits so we don't try to construct again.
6949 0 : ClearLazyBits(aStartChild, aEndChild);
6950 0 : return NS_OK;
6951 : }
6952 :
6953 0 : if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) {
6954 0 : LAYOUT_PHASE_TEMP_EXIT();
6955 0 : nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false);
6956 0 : LAYOUT_PHASE_TEMP_REENTER();
6957 0 : return rv;
6958 : }
6959 :
6960 : nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
6961 : GetAbsoluteContainingBlock(parentFrame),
6962 : GetFloatContainingBlock(parentFrame),
6963 0 : aFrameState);
6964 : state.mTreeMatchContext.mAncestorFilter.Init(aContainer ?
6965 0 : aContainer->AsElement() :
6966 0 : nsnull);
6967 :
6968 : // Recover state for the containing block - we need to know if
6969 : // it has :first-letter or :first-line style applied to it. The
6970 : // reason we care is that the internal structure in these cases
6971 : // is not the normal structure and requires custom updating
6972 : // logic.
6973 0 : nsIFrame* containingBlock = state.mFloatedItems.containingBlock;
6974 0 : bool haveFirstLetterStyle = false;
6975 0 : bool haveFirstLineStyle = false;
6976 :
6977 : // In order to shave off some cycles, we only dig up the
6978 : // containing block haveFirst* flags if the parent frame where
6979 : // the insertion/append is occurring is an inline or block
6980 : // container. For other types of containers this isn't relevant.
6981 0 : const nsStyleDisplay* parentDisplay = parentFrame->GetStyleDisplay();
6982 :
6983 : // Examine the parentFrame where the insertion is taking
6984 : // place. If it's a certain kind of container then some special
6985 : // processing is done.
6986 0 : if ((NS_STYLE_DISPLAY_BLOCK == parentDisplay->mDisplay) ||
6987 : (NS_STYLE_DISPLAY_LIST_ITEM == parentDisplay->mDisplay) ||
6988 : (NS_STYLE_DISPLAY_INLINE == parentDisplay->mDisplay) ||
6989 : (NS_STYLE_DISPLAY_INLINE_BLOCK == parentDisplay->mDisplay)) {
6990 : // Recover the special style flags for the containing block
6991 0 : if (containingBlock) {
6992 0 : haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
6993 : haveFirstLineStyle =
6994 : ShouldHaveFirstLineStyle(containingBlock->GetContent(),
6995 0 : containingBlock->GetStyleContext());
6996 : }
6997 :
6998 0 : if (haveFirstLetterStyle) {
6999 : // If our current parentFrame is a Letter frame, use its parent as our
7000 : // new parent hint
7001 0 : if (parentFrame->GetType() == nsGkAtoms::letterFrame) {
7002 : // If parentFrame is out of flow, then we actually want the parent of
7003 : // the placeholder frame.
7004 0 : if (parentFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
7005 : nsPlaceholderFrame* placeholderFrame =
7006 0 : GetPlaceholderFrameFor(parentFrame);
7007 0 : NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?");
7008 0 : parentFrame = placeholderFrame->GetParent();
7009 : } else {
7010 0 : parentFrame = parentFrame->GetParent();
7011 : }
7012 : }
7013 :
7014 : // Remove the old letter frames before doing the insertion
7015 : RemoveLetterFrames(state.mPresContext, mPresShell,
7016 0 : state.mFloatedItems.containingBlock);
7017 :
7018 : // Removing the letterframes messes around with the frame tree, removing
7019 : // and creating frames. We need to reget our prevsibling, parent frame,
7020 : // etc.
7021 : prevSibling = GetInsertionPrevSibling(parentFrame, aContainer,
7022 : aStartChild, &isAppend,
7023 0 : &isRangeInsertSafe);
7024 :
7025 : // Need check whether a range insert is still safe.
7026 0 : if (!isSingleInsert && !isRangeInsertSafe) {
7027 : // Need to recover the letter frames first.
7028 0 : RecoverLetterFrames(state.mFloatedItems.containingBlock);
7029 :
7030 : // must fall back to a single ContertInserted for each child in the range
7031 0 : LAYOUT_PHASE_TEMP_EXIT();
7032 : IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
7033 0 : aAllowLazyConstruction);
7034 0 : LAYOUT_PHASE_TEMP_REENTER();
7035 0 : return NS_OK;
7036 : }
7037 :
7038 0 : container = parentFrame->GetContent();
7039 0 : frameType = parentFrame->GetType();
7040 : }
7041 : }
7042 :
7043 0 : if (!prevSibling) {
7044 : // We're inserting the new frames as the first child. See if the
7045 : // parent has a :before pseudo-element
7046 0 : nsIFrame* firstChild = parentFrame->GetFirstPrincipalChild();
7047 :
7048 0 : if (firstChild &&
7049 : nsLayoutUtils::IsGeneratedContentFor(container, firstChild,
7050 0 : nsCSSPseudoElements::before)) {
7051 : // Insert the new frames after the last continuation of the :before
7052 0 : prevSibling = firstChild->GetTailContinuation();
7053 0 : parentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
7054 : // Don't change isAppend here; we'll can call AppendFrames as needed, and
7055 : // the change to our prevSibling doesn't affect that.
7056 : }
7057 : }
7058 :
7059 0 : FrameConstructionItemList items;
7060 0 : ParentType parentType = GetParentType(frameType);
7061 : bool haveNoXBLChildren =
7062 0 : mDocument->BindingManager()->GetXBLChildNodesFor(aContainer) == nsnull;
7063 0 : if (aStartChild->GetPreviousSibling() &&
7064 : parentType == eTypeBlock && haveNoXBLChildren) {
7065 : // If there's a text node in the normal content list just before the
7066 : // new nodes, and it has no frame, make a frame construction item for
7067 : // it, because it might need a frame now. No need to do this if our
7068 : // parent type is not block, though, since WipeContainingBlock
7069 : // already handles that sitation.
7070 : AddTextItemIfNeeded(state, parentFrame, aStartChild->GetPreviousSibling(),
7071 0 : items);
7072 : }
7073 :
7074 0 : if (isSingleInsert) {
7075 : AddFrameConstructionItems(state, aStartChild,
7076 0 : aStartChild->IsRootOfAnonymousSubtree(),
7077 0 : parentFrame, items);
7078 : } else {
7079 0 : for (nsIContent* child = aStartChild;
7080 : child != aEndChild;
7081 0 : child = child->GetNextSibling()){
7082 0 : AddFrameConstructionItems(state, child, false, parentFrame, items);
7083 : }
7084 : }
7085 :
7086 0 : if (aEndChild && parentType == eTypeBlock && haveNoXBLChildren) {
7087 : // If there's a text node in the normal content list just after the
7088 : // new nodes, and it has no frame, make a frame construction item for
7089 : // it, because it might need a frame now. No need to do this if our
7090 : // parent type is not block, though, since WipeContainingBlock
7091 : // already handles that sitation.
7092 0 : AddTextItemIfNeeded(state, parentFrame, aEndChild, items);
7093 : }
7094 :
7095 : // Perform special check for diddling around with the frames in
7096 : // a special inline frame.
7097 : // If we're appending before :after content, then we're not really
7098 : // appending, so let WipeContainingBlock know that.
7099 0 : LAYOUT_PHASE_TEMP_EXIT();
7100 0 : if (WipeContainingBlock(state, containingBlock, parentFrame, items,
7101 0 : isAppend, prevSibling)) {
7102 0 : LAYOUT_PHASE_TEMP_REENTER();
7103 0 : return NS_OK;
7104 : }
7105 0 : LAYOUT_PHASE_TEMP_REENTER();
7106 :
7107 : // If the container is a table and a caption will be appended, it needs to be
7108 : // put in the outer table frame's additional child list.
7109 : // We make no attempt here to set flags to indicate whether the list
7110 : // will be at the start or end of a block. It doesn't seem worthwhile.
7111 0 : nsFrameItems frameItems, captionItems;
7112 0 : ConstructFramesFromItemList(state, items, parentFrame, frameItems);
7113 :
7114 0 : if (frameItems.NotEmpty()) {
7115 0 : for (nsIContent* child = aStartChild;
7116 : child != aEndChild;
7117 0 : child = child->GetNextSibling()){
7118 0 : InvalidateCanvasIfNeeded(mPresShell, child);
7119 : }
7120 :
7121 0 : if (nsGkAtoms::tableFrame == frameType ||
7122 : nsGkAtoms::tableOuterFrame == frameType) {
7123 0 : PullOutCaptionFrames(frameItems, captionItems);
7124 : }
7125 : }
7126 :
7127 : // If the parent of our current prevSibling is different from the frame we'll
7128 : // actually use as the parent, then the calculated insertion point is now
7129 : // invalid and as it is unknown where to insert correctly we append instead
7130 : // (bug 341858).
7131 : // This can affect our prevSibling and isAppend, but should not have any
7132 : // effect on the WipeContainingBlock above, since this should only happen
7133 : // when neither parent is a special frame and should not affect whitespace
7134 : // handling inside table-related frames (and in fact, can only happen when
7135 : // one of the parents is an outer table and one is an inner table or when the
7136 : // parent is a fieldset or fieldset content frame). So it won't affect the
7137 : // {ib} or XUL box cases in WipeContainingBlock(), and the table pseudo
7138 : // handling will only be affected by us maybe thinking we're not inserting
7139 : // at the beginning, whereas we really are. That would have made us reframe
7140 : // unnecessarily, but that's ok.
7141 : // XXXbz we should push our frame construction item code up higher, so we
7142 : // know what our items are by the time we start figuring out previous
7143 : // siblings
7144 0 : if (prevSibling && frameItems.NotEmpty() &&
7145 0 : frameItems.FirstChild()->GetParent() != prevSibling->GetParent()) {
7146 : #ifdef DEBUG
7147 0 : nsIFrame* frame1 = frameItems.FirstChild()->GetParent();
7148 0 : nsIFrame* frame2 = prevSibling->GetParent();
7149 0 : NS_ASSERTION(!IsFrameSpecial(frame1) && !IsFrameSpecial(frame2),
7150 : "Neither should be special");
7151 0 : NS_ASSERTION((frame1->GetType() == nsGkAtoms::tableFrame &&
7152 : frame2->GetType() == nsGkAtoms::tableOuterFrame) ||
7153 : (frame1->GetType() == nsGkAtoms::tableOuterFrame &&
7154 : frame2->GetType() == nsGkAtoms::tableFrame) ||
7155 : frame1->GetType() == nsGkAtoms::fieldSetFrame ||
7156 : (frame1->GetParent() &&
7157 : frame1->GetParent()->GetType() == nsGkAtoms::fieldSetFrame),
7158 : "Unexpected frame types");
7159 : #endif
7160 0 : isAppend = true;
7161 : nsIFrame* appendAfterFrame;
7162 : parentFrame =
7163 : ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
7164 : container,
7165 : frameItems.FirstChild()->GetParent(),
7166 0 : &appendAfterFrame);
7167 0 : prevSibling = ::FindAppendPrevSibling(parentFrame, appendAfterFrame);
7168 : }
7169 :
7170 0 : if (haveFirstLineStyle && parentFrame == containingBlock) {
7171 : // It's possible that the new frame goes into a first-line
7172 : // frame. Look at it and see...
7173 0 : if (isAppend) {
7174 : // Use append logic when appending
7175 : AppendFirstLineFrames(state, containingBlock->GetContent(),
7176 0 : containingBlock, frameItems);
7177 : }
7178 : else {
7179 : // Use more complicated insert logic when inserting
7180 : // XXXbz this method is a no-op, so it's easy for the args being passed
7181 : // here to make no sense without anyone noticing... If it ever stops
7182 : // being a no-op, vet them carefully!
7183 : InsertFirstLineFrames(state, container, containingBlock, &parentFrame,
7184 0 : prevSibling, frameItems);
7185 : }
7186 : }
7187 :
7188 : // We might have captions; put them into the caption list of the
7189 : // outer table frame.
7190 0 : if (captionItems.NotEmpty()) {
7191 0 : NS_ASSERTION(nsGkAtoms::tableFrame == frameType ||
7192 : nsGkAtoms::tableOuterFrame == frameType,
7193 : "parent for caption is not table?");
7194 : // We need to determine where to put the caption items; start with the
7195 : // the parent frame that has already been determined and get the insertion
7196 : // prevsibling of the first caption item.
7197 0 : nsIFrame* captionParent = parentFrame;
7198 : bool captionIsAppend;
7199 0 : nsIFrame* captionPrevSibling = nsnull;
7200 :
7201 : // aIsRangeInsertSafe is ignored on purpose because it is irrelevant here.
7202 : bool ignored;
7203 0 : if (isSingleInsert) {
7204 : captionPrevSibling =
7205 : GetInsertionPrevSibling(captionParent, aContainer, aStartChild,
7206 0 : &captionIsAppend, &ignored);
7207 : } else {
7208 0 : nsIContent* firstCaption = captionItems.FirstChild()->GetContent();
7209 : // It is very important here that we skip the children in
7210 : // [aStartChild,aEndChild) when looking for a
7211 : // prevsibling.
7212 : captionPrevSibling =
7213 : GetInsertionPrevSibling(captionParent, aContainer, firstCaption,
7214 : &captionIsAppend, &ignored,
7215 0 : aStartChild, aEndChild);
7216 : }
7217 :
7218 0 : nsIFrame* outerTable = nsnull;
7219 0 : if (GetCaptionAdjustedParent(captionParent, captionItems.FirstChild(),
7220 0 : &outerTable)) {
7221 : // If the parent is not an outer table frame we will try to add frames
7222 : // to a named child list that the parent does not honour and the frames
7223 : // will get lost
7224 0 : NS_ASSERTION(nsGkAtoms::tableOuterFrame == outerTable->GetType(),
7225 : "Pseudo frame construction failure; "
7226 : "a caption can be only a child of an outer table frame");
7227 :
7228 : // If the parent of our current prevSibling is different from the frame
7229 : // we'll actually use as the parent, then the calculated insertion
7230 : // point is now invalid (bug 341382).
7231 0 : if (captionPrevSibling &&
7232 0 : captionPrevSibling->GetParent() != outerTable) {
7233 0 : captionPrevSibling = nsnull;
7234 : }
7235 0 : if (captionIsAppend) {
7236 0 : AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems);
7237 : } else {
7238 : InsertFrames(outerTable, nsIFrame::kCaptionList,
7239 0 : captionPrevSibling, captionItems);
7240 : }
7241 : }
7242 : }
7243 :
7244 0 : if (frameItems.NotEmpty()) {
7245 : // Notify the parent frame
7246 0 : if (isAppend) {
7247 0 : AppendFramesToParent(state, parentFrame, frameItems, prevSibling);
7248 : } else {
7249 0 : InsertFrames(parentFrame, kPrincipalList, prevSibling, frameItems);
7250 : }
7251 : }
7252 :
7253 0 : if (haveFirstLetterStyle) {
7254 : // Recover the letter frames for the containing block when
7255 : // it has first-letter style.
7256 0 : RecoverLetterFrames(state.mFloatedItems.containingBlock);
7257 : }
7258 :
7259 : #ifdef DEBUG
7260 0 : if (gReallyNoisyContentUpdates && parentFrame) {
7261 0 : printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame model:\n");
7262 0 : parentFrame->List(stdout, 0);
7263 : }
7264 : #endif
7265 :
7266 : #ifdef ACCESSIBILITY
7267 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
7268 0 : if (accService) {
7269 : accService->ContentRangeInserted(mPresShell, aContainer,
7270 0 : aStartChild, aEndChild);
7271 : }
7272 : #endif
7273 :
7274 0 : return NS_OK;
7275 : }
7276 :
7277 : nsresult
7278 0 : nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
7279 : nsIContent* aChild,
7280 : nsIContent* aOldNextSibling,
7281 : RemoveFlags aFlags,
7282 : bool* aDidReconstruct)
7283 : {
7284 0 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
7285 0 : NS_PRECONDITION(mUpdateCount != 0,
7286 : "Should be in an update while destroying frames");
7287 :
7288 0 : *aDidReconstruct = false;
7289 :
7290 : // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
7291 : // the :empty pseudo-class?
7292 :
7293 : #ifdef DEBUG
7294 0 : if (gNoisyContentUpdates) {
7295 : printf("nsCSSFrameConstructor::ContentRemoved container=%p child=%p "
7296 : "old-next-sibling=%p\n",
7297 : static_cast<void*>(aContainer),
7298 : static_cast<void*>(aChild),
7299 0 : static_cast<void*>(aOldNextSibling));
7300 0 : if (gReallyNoisyContentUpdates) {
7301 0 : aContainer->List(stdout, 0);
7302 : }
7303 : }
7304 : #endif
7305 :
7306 0 : nsPresContext *presContext = mPresShell->GetPresContext();
7307 0 : nsresult rv = NS_OK;
7308 :
7309 : // Find the child frame that maps the content
7310 0 : nsIFrame* childFrame = aChild->GetPrimaryFrame();
7311 :
7312 0 : if (!childFrame || childFrame->GetContent() != aChild) {
7313 : // XXXbz the GetContent() != aChild check is needed due to bug 135040.
7314 : // Remove it once that's fixed.
7315 0 : ClearUndisplayedContentIn(aChild, aContainer);
7316 : }
7317 :
7318 : #ifdef MOZ_XUL
7319 0 : if (NotifyListBoxBody(presContext, aContainer, aChild, aOldNextSibling,
7320 0 : mDocument, childFrame, CONTENT_REMOVED))
7321 0 : return NS_OK;
7322 :
7323 : #endif // MOZ_XUL
7324 :
7325 : // If we're removing the root, then make sure to remove things starting at
7326 : // the viewport's child instead of the primary frame (which might even be
7327 : // null if the root had an XBL binding or display:none, even though the
7328 : // frames above it got created). We do the adjustment after the childFrame
7329 : // check above, because we do want to clear any undisplayed content we might
7330 : // have for the root. Detecting removal of a root is a little exciting; in
7331 : // particular, having a null aContainer is necessary but NOT sufficient. Due
7332 : // to how we process reframes, the content node might not even be in our
7333 : // document by now. So explicitly check whether the viewport's first kid's
7334 : // content node is aChild.
7335 0 : bool isRoot = false;
7336 0 : if (!aContainer) {
7337 0 : nsIFrame* viewport = GetRootFrame();
7338 0 : if (viewport) {
7339 0 : nsIFrame* firstChild = viewport->GetFirstPrincipalChild();
7340 0 : if (firstChild && firstChild->GetContent() == aChild) {
7341 0 : isRoot = true;
7342 0 : childFrame = firstChild;
7343 0 : NS_ASSERTION(!childFrame->GetNextSibling(), "How did that happen?");
7344 : }
7345 : }
7346 : }
7347 :
7348 0 : if (childFrame) {
7349 0 : InvalidateCanvasIfNeeded(mPresShell, aChild);
7350 :
7351 : // See whether we need to remove more than just childFrame
7352 0 : LAYOUT_PHASE_TEMP_EXIT();
7353 0 : if (MaybeRecreateContainerForFrameRemoval(childFrame, &rv)) {
7354 0 : LAYOUT_PHASE_TEMP_REENTER();
7355 0 : *aDidReconstruct = true;
7356 0 : return rv;
7357 : }
7358 0 : LAYOUT_PHASE_TEMP_REENTER();
7359 :
7360 : // Get the childFrame's parent frame
7361 0 : nsIFrame* parentFrame = childFrame->GetParent();
7362 0 : nsIAtom* parentType = parentFrame->GetType();
7363 :
7364 0 : if (parentType == nsGkAtoms::frameSetFrame &&
7365 0 : IsSpecialFramesetChild(aChild)) {
7366 : // Just reframe the parent, since framesets are weird like that.
7367 0 : *aDidReconstruct = true;
7368 0 : LAYOUT_PHASE_TEMP_EXIT();
7369 0 : nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false);
7370 0 : LAYOUT_PHASE_TEMP_REENTER();
7371 0 : return rv;
7372 : }
7373 :
7374 : // If we're a child of MathML, then we should reframe the MathML content.
7375 : // If we're non-MathML, then we would be wrapped in a block so we need to
7376 : // check our grandparent in that case.
7377 : nsIFrame* possibleMathMLAncestor = parentType == nsGkAtoms::blockFrame ?
7378 0 : parentFrame->GetParent() : parentFrame;
7379 0 : if (possibleMathMLAncestor->IsFrameOfType(nsIFrame::eMathML)) {
7380 0 : *aDidReconstruct = true;
7381 0 : LAYOUT_PHASE_TEMP_EXIT();
7382 0 : nsresult rv = RecreateFramesForContent(possibleMathMLAncestor->GetContent(), false);
7383 0 : LAYOUT_PHASE_TEMP_REENTER();
7384 0 : return rv;
7385 : }
7386 :
7387 : // Undo XUL wrapping if it's no longer needed.
7388 : // (If we're in the XUL block-wrapping situation, parentFrame is the
7389 : // wrapper frame.)
7390 0 : nsIFrame* grandparentFrame = parentFrame->GetParent();
7391 0 : if (grandparentFrame && grandparentFrame->IsBoxFrame() &&
7392 0 : (grandparentFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
7393 : // check if this frame is the only one needing wrapping
7394 0 : aChild == AnyKidsNeedBlockParent(parentFrame->GetFirstPrincipalChild()) &&
7395 0 : !AnyKidsNeedBlockParent(childFrame->GetNextSibling())) {
7396 0 : *aDidReconstruct = true;
7397 0 : LAYOUT_PHASE_TEMP_EXIT();
7398 0 : nsresult rv = RecreateFramesForContent(grandparentFrame->GetContent(), true);
7399 0 : LAYOUT_PHASE_TEMP_REENTER();
7400 0 : return rv;
7401 : }
7402 :
7403 : #ifdef ACCESSIBILITY
7404 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
7405 0 : if (accService) {
7406 0 : accService->ContentRemoved(mPresShell, aContainer, aChild);
7407 : }
7408 : #endif
7409 :
7410 : // Examine the containing-block for the removed content and see if
7411 : // :first-letter style applies.
7412 0 : nsIFrame* inflowChild = childFrame;
7413 0 : if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
7414 0 : inflowChild = GetPlaceholderFrameFor(childFrame);
7415 0 : NS_ASSERTION(inflowChild, "No placeholder for out-of-flow?");
7416 : }
7417 : nsIFrame* containingBlock =
7418 0 : GetFloatContainingBlock(inflowChild->GetParent());
7419 0 : bool haveFLS = containingBlock && HasFirstLetterStyle(containingBlock);
7420 0 : if (haveFLS) {
7421 : // Trap out to special routine that handles adjusting a blocks
7422 : // frame tree when first-letter style is present.
7423 : #ifdef NOISY_FIRST_LETTER
7424 : printf("ContentRemoved: containingBlock=");
7425 : nsFrame::ListTag(stdout, containingBlock);
7426 : printf(" parentFrame=");
7427 : nsFrame::ListTag(stdout, parentFrame);
7428 : printf(" childFrame=");
7429 : nsFrame::ListTag(stdout, childFrame);
7430 : printf("\n");
7431 : #endif
7432 :
7433 : // First update the containing blocks structure by removing the
7434 : // existing letter frames. This makes the subsequent logic
7435 : // simpler.
7436 0 : RemoveLetterFrames(presContext, mPresShell, containingBlock);
7437 :
7438 : // Recover childFrame and parentFrame
7439 0 : childFrame = aChild->GetPrimaryFrame();
7440 0 : if (!childFrame || childFrame->GetContent() != aChild) {
7441 : // XXXbz the GetContent() != aChild check is needed due to bug 135040.
7442 : // Remove it once that's fixed.
7443 0 : ClearUndisplayedContentIn(aChild, aContainer);
7444 0 : return NS_OK;
7445 : }
7446 0 : parentFrame = childFrame->GetParent();
7447 0 : parentType = parentFrame->GetType();
7448 :
7449 : #ifdef NOISY_FIRST_LETTER
7450 : printf(" ==> revised parentFrame=");
7451 : nsFrame::ListTag(stdout, parentFrame);
7452 : printf(" childFrame=");
7453 : nsFrame::ListTag(stdout, childFrame);
7454 : printf("\n");
7455 : #endif
7456 : }
7457 :
7458 : #ifdef DEBUG
7459 0 : if (gReallyNoisyContentUpdates) {
7460 0 : printf("nsCSSFrameConstructor::ContentRemoved: childFrame=");
7461 0 : nsFrame::ListTag(stdout, childFrame);
7462 0 : putchar('\n');
7463 0 : parentFrame->List(stdout, 0);
7464 : }
7465 : #endif
7466 :
7467 :
7468 : // Notify the parent frame that it should delete the frame
7469 0 : if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
7470 0 : childFrame = GetPlaceholderFrameFor(childFrame);
7471 0 : NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow.");
7472 0 : parentFrame = childFrame->GetParent();
7473 : }
7474 : rv = RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame),
7475 0 : childFrame);
7476 : //XXXfr NS_ENSURE_SUCCESS(rv, rv) ?
7477 :
7478 0 : if (isRoot) {
7479 0 : mRootElementFrame = nsnull;
7480 0 : mRootElementStyleFrame = nsnull;
7481 0 : mDocElementContainingBlock = nsnull;
7482 0 : mPageSequenceFrame = nsnull;
7483 0 : mGfxScrollFrame = nsnull;
7484 0 : mHasRootAbsPosContainingBlock = false;
7485 0 : mFixedContainingBlock = GetRootFrame();
7486 : }
7487 :
7488 0 : if (haveFLS && mRootElementFrame) {
7489 0 : RecoverLetterFrames(containingBlock);
7490 : }
7491 :
7492 : // If we're just reconstructing frames for the element, then the
7493 : // following ContentInserted notification on the element will
7494 : // take care of fixing up any adjacent text nodes. We don't need
7495 : // to do this if the table parent type of our parent type is not
7496 : // eTypeBlock, though, because in that case the whitespace isn't
7497 : // being suppressed due to us anyway.
7498 0 : if (aContainer && !aChild->IsRootOfAnonymousSubtree() &&
7499 : aFlags != REMOVE_FOR_RECONSTRUCTION &&
7500 0 : GetParentType(parentType) == eTypeBlock) {
7501 : // Adjacent whitespace-only text nodes might have been suppressed if
7502 : // this node does not have inline ends. Create frames for them now
7503 : // if necessary.
7504 : // Reframe any text node just before the node being removed, if there is
7505 : // one, and if it's not the last child or the first child. If a whitespace
7506 : // textframe was being suppressed and it's now the last child or first
7507 : // child then it can stay suppressed since the parent must be a block
7508 : // and hence it's adjacent to a block end.
7509 : // If aOldNextSibling is null, then the text node before the node being
7510 : // removed is the last node, and we don't need to worry about it.
7511 0 : if (aOldNextSibling) {
7512 0 : nsIContent* prevSibling = aOldNextSibling->GetPreviousSibling();
7513 0 : if (prevSibling && prevSibling->GetPreviousSibling()) {
7514 0 : LAYOUT_PHASE_TEMP_EXIT();
7515 0 : ReframeTextIfNeeded(aContainer, prevSibling);
7516 0 : LAYOUT_PHASE_TEMP_REENTER();
7517 : }
7518 : }
7519 : // Reframe any text node just after the node being removed, if there is
7520 : // one, and if it's not the last child or the first child.
7521 0 : if (aOldNextSibling && aOldNextSibling->GetNextSibling() &&
7522 0 : aOldNextSibling->GetPreviousSibling()) {
7523 0 : LAYOUT_PHASE_TEMP_EXIT();
7524 0 : ReframeTextIfNeeded(aContainer, aOldNextSibling);
7525 0 : LAYOUT_PHASE_TEMP_REENTER();
7526 : }
7527 : }
7528 :
7529 : #ifdef DEBUG
7530 0 : if (gReallyNoisyContentUpdates && parentFrame) {
7531 0 : printf("nsCSSFrameConstructor::ContentRemoved: resulting frame model:\n");
7532 0 : parentFrame->List(stdout, 0);
7533 : }
7534 : #endif
7535 : }
7536 :
7537 0 : return rv;
7538 : }
7539 :
7540 : #ifdef DEBUG
7541 : // To ensure that the functions below are only called within
7542 : // |ApplyRenderingChangeToTree|.
7543 : static bool gInApplyRenderingChangeToTree = false;
7544 : #endif
7545 :
7546 : static void
7547 : DoApplyRenderingChangeToTree(nsIFrame* aFrame,
7548 : nsFrameManager* aFrameManager,
7549 : nsChangeHint aChange);
7550 :
7551 : /**
7552 : * This rect is relative to aFrame's parent
7553 : */
7554 : static void
7555 0 : UpdateViewsForTree(nsIFrame* aFrame,
7556 : nsFrameManager* aFrameManager,
7557 : nsChangeHint aChange)
7558 : {
7559 0 : NS_PRECONDITION(gInApplyRenderingChangeToTree,
7560 : "should only be called within ApplyRenderingChangeToTree");
7561 :
7562 0 : nsIView* view = aFrame->GetView();
7563 0 : if (view) {
7564 0 : if (aChange & nsChangeHint_SyncFrameView) {
7565 : nsContainerFrame::SyncFrameViewProperties(aFrame->PresContext(),
7566 0 : aFrame, nsnull, view);
7567 : }
7568 : }
7569 :
7570 0 : nsIFrame::ChildListIterator lists(aFrame);
7571 0 : for (; !lists.IsDone(); lists.Next()) {
7572 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
7573 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
7574 0 : nsIFrame* child = childFrames.get();
7575 0 : if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
7576 : // only do frames that don't have placeholders
7577 0 : if (nsGkAtoms::placeholderFrame == child->GetType()) {
7578 : // do the out-of-flow frame and its continuations
7579 : nsIFrame* outOfFlowFrame =
7580 0 : nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
7581 0 : do {
7582 : DoApplyRenderingChangeToTree(outOfFlowFrame, aFrameManager,
7583 0 : aChange);
7584 0 : } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
7585 0 : } else if (lists.CurrentID() == nsIFrame::kPopupList) {
7586 : DoApplyRenderingChangeToTree(child, aFrameManager,
7587 0 : aChange);
7588 : } else { // regular frame
7589 0 : if ((child->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) &&
7590 : (aChange & nsChangeHint_RepaintFrame)) {
7591 : FrameLayerBuilder::InvalidateThebesLayerContents(child,
7592 0 : child->GetVisualOverflowRectRelativeToSelf());
7593 : }
7594 0 : UpdateViewsForTree(child, aFrameManager, aChange);
7595 : }
7596 : }
7597 : }
7598 : }
7599 0 : }
7600 :
7601 : static void
7602 0 : DoApplyRenderingChangeToTree(nsIFrame* aFrame,
7603 : nsFrameManager* aFrameManager,
7604 : nsChangeHint aChange)
7605 : {
7606 0 : NS_PRECONDITION(gInApplyRenderingChangeToTree,
7607 : "should only be called within ApplyRenderingChangeToTree");
7608 :
7609 0 : for ( ; aFrame; aFrame = nsLayoutUtils::GetNextContinuationOrSpecialSibling(aFrame)) {
7610 : // Get view if this frame has one and trigger an update. If the
7611 : // frame doesn't have a view, find the nearest containing view
7612 : // (adjusting r's coordinate system to reflect the nesting) and
7613 : // update there.
7614 : // We don't need to update transforms in UpdateViewsForTree, because
7615 : // there can't be any out-of-flows or popups that need to be transformed;
7616 : // all out-of-flow descendants of the transformed element must also be
7617 : // descendants of the transformed frame.
7618 : UpdateViewsForTree(aFrame, aFrameManager,
7619 : nsChangeHint(aChange & (nsChangeHint_RepaintFrame |
7620 : nsChangeHint_SyncFrameView |
7621 0 : nsChangeHint_UpdateOpacityLayer)));
7622 :
7623 : // if frame has view, will already be invalidated
7624 0 : if (aChange & nsChangeHint_RepaintFrame) {
7625 0 : if (aFrame->IsFrameOfType(nsIFrame::eSVG)) {
7626 0 : if (aChange & nsChangeHint_UpdateEffects) {
7627 : // Invalidate the frame's old bounds, update its bounds, invalidate its new
7628 : // bounds, and then inform anyone observing _us_ that we've changed:
7629 0 : nsSVGUtils::UpdateGraphic(aFrame);
7630 : } else {
7631 : // Just invalidate our area:
7632 0 : nsSVGUtils::InvalidateCoveredRegion(aFrame);
7633 : }
7634 : } else {
7635 0 : aFrame->InvalidateOverflowRect();
7636 : }
7637 : }
7638 0 : if (aChange & nsChangeHint_UpdateOpacityLayer) {
7639 0 : aFrame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer);
7640 0 : aFrame->InvalidateLayer(aFrame->GetVisualOverflowRectRelativeToSelf(),
7641 0 : nsDisplayItem::TYPE_OPACITY);
7642 : }
7643 :
7644 0 : if (aChange & nsChangeHint_UpdateTransformLayer) {
7645 0 : aFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
7646 : // Invalidate the old transformed area. The new transformed area
7647 : // will be invalidated by nsFrame::FinishAndStoreOverflowArea.
7648 0 : aFrame->InvalidateTransformLayer();
7649 : }
7650 : }
7651 0 : }
7652 :
7653 : static void
7654 0 : ApplyRenderingChangeToTree(nsPresContext* aPresContext,
7655 : nsIFrame* aFrame,
7656 : nsChangeHint aChange)
7657 : {
7658 0 : NS_ASSERTION(!(aChange & nsChangeHint_UpdateTransformLayer) ||
7659 : aFrame->GetStyleDisplay()->HasTransform(),
7660 : "Only transform style should give a UpdateTransformLayer hint");
7661 :
7662 0 : nsIPresShell *shell = aPresContext->PresShell();
7663 0 : if (shell->IsPaintingSuppressed()) {
7664 : // Don't allow synchronous rendering changes when painting is turned off.
7665 0 : aChange = NS_SubtractHint(aChange, nsChangeHint_RepaintFrame);
7666 0 : if (!aChange) {
7667 0 : return;
7668 : }
7669 : }
7670 :
7671 : // If the frame's background is propagated to an ancestor, walk up to
7672 : // that ancestor.
7673 : nsStyleContext *bgSC;
7674 0 : while (!nsCSSRendering::FindBackground(aPresContext, aFrame, &bgSC)) {
7675 0 : aFrame = aFrame->GetParent();
7676 0 : NS_ASSERTION(aFrame, "root frame must paint");
7677 : }
7678 :
7679 : // Trigger rendering updates by damaging this frame and any
7680 : // continuations of this frame.
7681 :
7682 : // XXX this needs to detect the need for a view due to an opacity change and deal with it...
7683 :
7684 : #ifdef DEBUG
7685 0 : gInApplyRenderingChangeToTree = true;
7686 : #endif
7687 0 : DoApplyRenderingChangeToTree(aFrame, shell->FrameManager(), aChange);
7688 : #ifdef DEBUG
7689 0 : gInApplyRenderingChangeToTree = false;
7690 : #endif
7691 : }
7692 :
7693 : /**
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.
7697 : *
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.
7700 : */
7701 : static void
7702 0 : InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node)
7703 : {
7704 0 : NS_PRECONDITION(presShell->GetRootFrame(), "What happened here?");
7705 0 : NS_PRECONDITION(presShell->GetPresContext(), "Say what?");
7706 :
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.
7709 :
7710 0 : nsIContent* parent = node->GetParent();
7711 0 : if (parent) {
7712 : // Has a parent; might not be what we want
7713 0 : nsIContent* grandParent = parent->GetParent();
7714 0 : if (grandParent) {
7715 : // Has a grandparent, so not what we want
7716 0 : return;
7717 : }
7718 :
7719 : // Check whether it's an HTML body
7720 0 : if (node->Tag() != nsGkAtoms::body ||
7721 0 : !node->IsHTML()) {
7722 0 : return;
7723 : }
7724 : }
7725 :
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.
7730 :
7731 0 : nsIFrame* rootFrame = presShell->GetRootFrame();
7732 0 : rootFrame->InvalidateFrameSubtree();
7733 : }
7734 :
7735 : nsresult
7736 0 : nsCSSFrameConstructor::StyleChangeReflow(nsIFrame* aFrame,
7737 : nsChangeHint aHint)
7738 : {
7739 : // If the frame hasn't even received an initial reflow, then don't
7740 : // send it a style-change reflow!
7741 0 : if (aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)
7742 0 : return NS_OK;
7743 :
7744 : #ifdef DEBUG
7745 0 : if (gNoisyContentUpdates) {
7746 0 : printf("nsCSSFrameConstructor::StyleChangeReflow: aFrame=");
7747 0 : nsFrame::ListTag(stdout, aFrame);
7748 0 : printf("\n");
7749 : }
7750 : #endif
7751 :
7752 : nsIPresShell::IntrinsicDirty dirtyType;
7753 0 : if (aHint & nsChangeHint_ClearDescendantIntrinsics) {
7754 0 : NS_ASSERTION(aHint & nsChangeHint_ClearAncestorIntrinsics,
7755 : "Please read the comments in nsChangeHint.h");
7756 0 : dirtyType = nsIPresShell::eStyleChange;
7757 0 : } else if (aHint & nsChangeHint_ClearAncestorIntrinsics) {
7758 0 : dirtyType = nsIPresShell::eTreeChange;
7759 : } else {
7760 0 : dirtyType = nsIPresShell::eResize;
7761 : }
7762 :
7763 : nsFrameState dirtyBits;
7764 0 : if (aHint & nsChangeHint_NeedDirtyReflow) {
7765 0 : dirtyBits = NS_FRAME_IS_DIRTY;
7766 : } else {
7767 0 : dirtyBits = NS_FRAME_HAS_DIRTY_CHILDREN;
7768 : }
7769 :
7770 0 : do {
7771 0 : mPresShell->FrameNeedsReflow(aFrame, dirtyType, dirtyBits);
7772 0 : aFrame = nsLayoutUtils::GetNextContinuationOrSpecialSibling(aFrame);
7773 : } while (aFrame);
7774 :
7775 0 : return NS_OK;
7776 : }
7777 :
7778 : nsresult
7779 0 : nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent,
7780 : CharacterDataChangeInfo* aInfo)
7781 : {
7782 0 : AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
7783 0 : nsresult rv = NS_OK;
7784 :
7785 0 : if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
7786 0 : !aContent->TextIsOnlyWhitespace()) ||
7787 0 : (aContent->HasFlag(NS_REFRAME_IF_WHITESPACE) &&
7788 0 : aContent->TextIsOnlyWhitespace())) {
7789 : #ifdef DEBUG
7790 0 : nsIFrame* frame = aContent->GetPrimaryFrame();
7791 0 : NS_ASSERTION(!frame || !frame->IsGeneratedContentFrame(),
7792 : "Bit should never be set on generated content");
7793 : #endif
7794 0 : LAYOUT_PHASE_TEMP_EXIT();
7795 0 : nsresult rv = RecreateFramesForContent(aContent, false);
7796 0 : LAYOUT_PHASE_TEMP_REENTER();
7797 0 : return rv;
7798 : }
7799 :
7800 : // Find the child frame
7801 0 : nsIFrame* frame = aContent->GetPrimaryFrame();
7802 :
7803 : // Notify the first frame that maps the content. It will generate a reflow
7804 : // command
7805 :
7806 : // It's possible the frame whose content changed isn't inserted into the
7807 : // frame hierarchy yet, or that there is no frame that maps the content
7808 0 : if (nsnull != frame) {
7809 : #if 0
7810 : NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
7811 : ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p",
7812 : aContent, ContentTag(aContent, 0),
7813 : aSubContent, frame));
7814 : #endif
7815 :
7816 : // Special check for text content that is a child of a letter frame. If
7817 : // this happens, we should remove the letter frame, do whatever we're
7818 : // planning to do with this notification, then put the letter frame back.
7819 : // Note that this is basically what RecreateFramesForContent ends up doing;
7820 : // the reason we dont' want to call that here is that our text content
7821 : // could be native anonymous, in which case RecreateFramesForContent would
7822 : // completely barf on it. And recreating the non-anonymous ancestor would
7823 : // just lead us to come back into this notification (e.g. if quotes or
7824 : // counters are involved), leading to a loop.
7825 0 : nsIFrame* block = GetFloatContainingBlock(frame);
7826 0 : bool haveFirstLetterStyle = false;
7827 0 : if (block) {
7828 : // See if the block has first-letter style applied to it.
7829 0 : haveFirstLetterStyle = HasFirstLetterStyle(block);
7830 0 : if (haveFirstLetterStyle) {
7831 : RemoveLetterFrames(mPresShell->GetPresContext(), mPresShell,
7832 0 : block);
7833 : // Reget |frame|, since we might have killed it.
7834 : // Do we really need to call CharacterDataChanged in this case, though?
7835 0 : frame = aContent->GetPrimaryFrame();
7836 0 : NS_ASSERTION(frame, "Should have frame here!");
7837 : }
7838 : }
7839 :
7840 0 : frame->CharacterDataChanged(aInfo);
7841 :
7842 0 : if (haveFirstLetterStyle) {
7843 0 : RecoverLetterFrames(block);
7844 : }
7845 : }
7846 :
7847 0 : return rv;
7848 : }
7849 :
7850 0 : NS_DECLARE_FRAME_PROPERTY(ChangeListProperty, nsnull)
7851 :
7852 : nsresult
7853 0 : nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
7854 : {
7855 0 : NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
7856 : "Someone forgot a script blocker");
7857 0 : PRInt32 count = aChangeList.Count();
7858 0 : if (!count)
7859 0 : return NS_OK;
7860 :
7861 : // Make sure to not rebuild quote or counter lists while we're
7862 : // processing restyles
7863 0 : BeginUpdate();
7864 :
7865 0 : nsPresContext* presContext = mPresShell->GetPresContext();
7866 0 : FramePropertyTable* propTable = presContext->PropertyTable();
7867 :
7868 : // Mark frames so that we skip frames that die along the way, bug 123049.
7869 : // A frame can be in the list multiple times with different hints. Further
7870 : // optmization is possible if nsStyleChangeList::AppendChange could coalesce
7871 0 : PRInt32 index = count;
7872 :
7873 0 : while (0 <= --index) {
7874 : const nsStyleChangeData* changeData;
7875 0 : aChangeList.ChangeAt(index, &changeData);
7876 0 : if (changeData->mFrame) {
7877 : propTable->Set(changeData->mFrame, ChangeListProperty(),
7878 0 : NS_INT32_TO_PTR(1));
7879 : }
7880 : }
7881 :
7882 0 : index = count;
7883 0 : bool didInvalidate = false;
7884 0 : bool didReflow = false;
7885 :
7886 0 : while (0 <= --index) {
7887 : nsIFrame* frame;
7888 : nsIContent* content;
7889 : nsChangeHint hint;
7890 0 : aChangeList.ChangeAt(index, frame, content, hint);
7891 :
7892 0 : NS_ASSERTION(!(hint & nsChangeHint_ReflowFrame) ||
7893 : (hint & nsChangeHint_NeedReflow),
7894 : "Reflow hint bits set without actually asking for a reflow");
7895 :
7896 0 : if (frame && frame->GetContent() != content) {
7897 : // XXXbz this is due to image maps messing with the primary frame of
7898 : // <area>s. See bug 135040. Remove this block once that's fixed.
7899 0 : frame = nsnull;
7900 0 : if (!(hint & nsChangeHint_ReconstructFrame)) {
7901 0 : continue;
7902 : }
7903 : }
7904 :
7905 : // skip any frame that has been destroyed due to a ripple effect
7906 0 : if (frame) {
7907 0 : if (!propTable->Get(frame, ChangeListProperty()))
7908 0 : continue;
7909 : }
7910 :
7911 0 : if (hint & nsChangeHint_ReconstructFrame) {
7912 : // If we ever start passing true here, be careful of restyles
7913 : // that involve a reframe and animations. In particular, if the
7914 : // restyle we're processing here is an animation restyle, but
7915 : // the style resolution we will do for the frame construction
7916 : // happens async when we're not in an animation restyle already,
7917 : // problems could arise.
7918 0 : RecreateFramesForContent(content, false);
7919 : } else {
7920 0 : NS_ASSERTION(frame, "This shouldn't happen");
7921 0 : if (hint & nsChangeHint_UpdateEffects) {
7922 0 : nsSVGEffects::UpdateEffects(frame);
7923 : }
7924 0 : if (hint & nsChangeHint_NeedReflow) {
7925 0 : StyleChangeReflow(frame, hint);
7926 0 : didReflow = true;
7927 : }
7928 0 : if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView |
7929 : nsChangeHint_UpdateOpacityLayer | nsChangeHint_UpdateTransformLayer)) {
7930 0 : ApplyRenderingChangeToTree(presContext, frame, hint);
7931 0 : didInvalidate = true;
7932 : }
7933 0 : if ((hint & nsChangeHint_UpdateOverflow) && !didReflow) {
7934 0 : while (frame) {
7935 : nsOverflowAreas* pre = static_cast<nsOverflowAreas*>
7936 0 : (frame->Properties().Get(frame->PreTransformOverflowAreasProperty()));
7937 0 : if (pre) {
7938 : // FinishAndStoreOverflow will change the overflow areas passed in,
7939 : // so make a copy.
7940 0 : nsOverflowAreas overflowAreas = *pre;
7941 0 : frame->FinishAndStoreOverflow(overflowAreas, frame->GetSize());
7942 : } else {
7943 0 : frame->UpdateOverflow();
7944 : }
7945 :
7946 : nsIFrame* next =
7947 0 : nsLayoutUtils::GetNextContinuationOrSpecialSibling(frame);
7948 : // Update the ancestors' overflow after we have updated the overflow
7949 : // for all the continuations with the same parent.
7950 0 : if (!next || frame->GetParent() != next->GetParent()) {
7951 0 : for (nsIFrame* ancestor = frame->GetParent(); ancestor;
7952 : ancestor = ancestor->GetParent()) {
7953 0 : if (!ancestor->UpdateOverflow()) {
7954 0 : break;
7955 : }
7956 : }
7957 : }
7958 0 : frame = next;
7959 : }
7960 : }
7961 0 : if (hint & nsChangeHint_UpdateCursor) {
7962 0 : mPresShell->SynthesizeMouseMove(false);
7963 : }
7964 : }
7965 : }
7966 :
7967 0 : EndUpdate();
7968 :
7969 0 : if (didInvalidate && !didReflow) {
7970 : // RepaintFrame changes can indicate changes in opacity etc which
7971 : // can require plugin clipping to change. If we requested a reflow,
7972 : // we don't need to do this since the reflow will do it for us.
7973 0 : nsIFrame* rootFrame = GetRootFrame();
7974 0 : nsRootPresContext* rootPC = presContext->GetRootPresContext();
7975 0 : if (rootPC) {
7976 0 : rootPC->RequestUpdatePluginGeometry(rootFrame);
7977 : }
7978 : }
7979 :
7980 : // cleanup references and verify the style tree. Note that the latter needs
7981 : // to happen once we've processed the whole list, since until then the tree
7982 : // is not in fact in a consistent state.
7983 0 : index = count;
7984 0 : while (0 <= --index) {
7985 : const nsStyleChangeData* changeData;
7986 0 : aChangeList.ChangeAt(index, &changeData);
7987 0 : if (changeData->mFrame) {
7988 0 : propTable->Delete(changeData->mFrame, ChangeListProperty());
7989 : }
7990 :
7991 : #ifdef DEBUG
7992 : // reget frame from content since it may have been regenerated...
7993 0 : if (changeData->mContent) {
7994 0 : nsIFrame* frame = changeData->mContent->GetPrimaryFrame();
7995 0 : if (frame) {
7996 0 : DebugVerifyStyleTree(frame);
7997 : }
7998 : } else {
7999 0 : NS_WARNING("Unable to test style tree integrity -- no content node");
8000 : }
8001 : #endif
8002 : }
8003 :
8004 0 : aChangeList.Clear();
8005 0 : return NS_OK;
8006 : }
8007 :
8008 : void
8009 0 : nsCSSFrameConstructor::RestyleElement(Element *aElement,
8010 : nsIFrame *aPrimaryFrame,
8011 : nsChangeHint aMinHint,
8012 : RestyleTracker& aRestyleTracker,
8013 : bool aRestyleDescendants)
8014 : {
8015 0 : NS_ASSERTION(aPrimaryFrame == aElement->GetPrimaryFrame(),
8016 : "frame/content mismatch");
8017 0 : if (aPrimaryFrame && aPrimaryFrame->GetContent() != aElement) {
8018 : // XXXbz this is due to image maps messing with the primary frame pointer
8019 : // of <area>s. See bug 135040. We can remove this block once that's fixed.
8020 0 : aPrimaryFrame = nsnull;
8021 : }
8022 0 : NS_ASSERTION(!aPrimaryFrame || aPrimaryFrame->GetContent() == aElement,
8023 : "frame/content mismatch");
8024 :
8025 0 : if (aMinHint & nsChangeHint_ReconstructFrame) {
8026 0 : RecreateFramesForContent(aElement, false);
8027 0 : } else if (aPrimaryFrame) {
8028 0 : nsStyleChangeList changeList;
8029 : ComputeStyleChangeFor(aPrimaryFrame, &changeList, aMinHint,
8030 0 : aRestyleTracker, aRestyleDescendants);
8031 0 : ProcessRestyledFrames(changeList);
8032 : } else {
8033 : // no frames, reconstruct for content
8034 0 : MaybeRecreateFramesForElement(aElement);
8035 : }
8036 0 : }
8037 :
8038 : nsresult
8039 0 : nsCSSFrameConstructor::ContentStateChanged(nsIContent* aContent,
8040 : nsEventStates aStateMask)
8041 : {
8042 : // XXXbz it would be good if this function only took Elements, but
8043 : // we'd have to make ESM guarantee that usefully.
8044 0 : if (!aContent->IsElement()) {
8045 0 : return NS_OK;
8046 : }
8047 :
8048 0 : Element* aElement = aContent->AsElement();
8049 :
8050 0 : nsStyleSet *styleSet = mPresShell->StyleSet();
8051 0 : nsPresContext *presContext = mPresShell->GetPresContext();
8052 0 : NS_ASSERTION(styleSet, "couldn't get style set");
8053 :
8054 0 : nsChangeHint hint = NS_STYLE_HINT_NONE;
8055 : // Any change to a content state that affects which frames we construct
8056 : // must lead to a frame reconstruct here if we already have a frame.
8057 : // Note that we never decide through non-CSS means to not create frames
8058 : // based on content states, so if we already don't have a frame we don't
8059 : // need to force a reframe -- if it's needed, the HasStateDependentStyle
8060 : // call will handle things.
8061 0 : nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
8062 0 : if (primaryFrame) {
8063 : // If it's generated content, ignore LOADING/etc state changes on it.
8064 0 : if (!primaryFrame->IsGeneratedContentFrame() &&
8065 : aStateMask.HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN |
8066 : NS_EVENT_STATE_USERDISABLED |
8067 : NS_EVENT_STATE_SUPPRESSED |
8068 0 : NS_EVENT_STATE_LOADING)) {
8069 0 : hint = nsChangeHint_ReconstructFrame;
8070 : } else {
8071 0 : PRUint8 app = primaryFrame->GetStyleDisplay()->mAppearance;
8072 0 : if (app) {
8073 0 : nsITheme *theme = presContext->GetTheme();
8074 0 : if (theme && theme->ThemeSupportsWidget(presContext,
8075 0 : primaryFrame, app)) {
8076 0 : bool repaint = false;
8077 0 : theme->WidgetStateChanged(primaryFrame, app, nsnull, &repaint);
8078 0 : if (repaint) {
8079 0 : NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
8080 : }
8081 : }
8082 : }
8083 : }
8084 :
8085 0 : primaryFrame->ContentStatesChanged(aStateMask);
8086 : }
8087 :
8088 0 : if (aStateMask.HasState(NS_EVENT_STATE_HOVER) &&
8089 0 : !aElement->HasFlag(NODE_HAS_RELEVANT_HOVER_RULES)) {
8090 0 : aStateMask &= ~NS_EVENT_STATE_HOVER;
8091 : }
8092 :
8093 0 : nsRestyleHint rshint = aStateMask.IsEmpty() ?
8094 : nsRestyleHint(0) :
8095 0 : styleSet->HasStateDependentStyle(presContext, aElement, aStateMask);
8096 :
8097 0 : if (aStateMask.HasState(NS_EVENT_STATE_HOVER) && rshint != 0) {
8098 0 : ++mHoverGeneration;
8099 : }
8100 :
8101 0 : if (aStateMask.HasState(NS_EVENT_STATE_VISITED)) {
8102 : // Exposing information to the page about whether the link is
8103 : // visited or not isn't really something we can worry about here.
8104 : // FIXME: We could probably do this a bit better.
8105 0 : NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
8106 : }
8107 :
8108 0 : PostRestyleEvent(aElement, rshint, hint);
8109 0 : return NS_OK;
8110 : }
8111 :
8112 : void
8113 0 : nsCSSFrameConstructor::AttributeWillChange(Element* aElement,
8114 : PRInt32 aNameSpaceID,
8115 : nsIAtom* aAttribute,
8116 : PRInt32 aModType)
8117 : {
8118 : nsRestyleHint rshint =
8119 : mPresShell->StyleSet()->HasAttributeDependentStyle(mPresShell->GetPresContext(),
8120 : aElement,
8121 : aAttribute,
8122 : aModType,
8123 0 : false);
8124 0 : PostRestyleEvent(aElement, rshint, NS_STYLE_HINT_NONE);
8125 0 : }
8126 :
8127 : void
8128 0 : nsCSSFrameConstructor::AttributeChanged(Element* aElement,
8129 : PRInt32 aNameSpaceID,
8130 : nsIAtom* aAttribute,
8131 : PRInt32 aModType)
8132 : {
8133 : // Hold onto the PresShell to prevent ourselves from being destroyed.
8134 : // XXXbz how, exactly, would this attribute change cause us to be
8135 : // destroyed from inside this function?
8136 0 : nsCOMPtr<nsIPresShell> shell = mPresShell;
8137 :
8138 : // Get the frame associated with the content which is the highest in the frame tree
8139 0 : nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
8140 :
8141 : #if 0
8142 : NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
8143 : ("HTMLStyleSheet::AttributeChanged: content=%p[%s] frame=%p",
8144 : aContent, ContentTag(aElement, 0), frame));
8145 : #endif
8146 :
8147 : // the style tag has its own interpretation based on aHint
8148 0 : nsChangeHint hint = aElement->GetAttributeChangeHint(aAttribute, aModType);
8149 :
8150 0 : bool reframe = (hint & nsChangeHint_ReconstructFrame) != 0;
8151 :
8152 : #ifdef MOZ_XUL
8153 : // The following listbox widget trap prevents offscreen listbox widget
8154 : // content from being removed and re-inserted (which is what would
8155 : // happen otherwise).
8156 0 : if (!primaryFrame && !reframe) {
8157 : PRInt32 namespaceID;
8158 : nsIAtom* tag =
8159 0 : mDocument->BindingManager()->ResolveTag(aElement, &namespaceID);
8160 :
8161 0 : if (namespaceID == kNameSpaceID_XUL &&
8162 : (tag == nsGkAtoms::listitem ||
8163 : tag == nsGkAtoms::listcell))
8164 : return;
8165 : }
8166 :
8167 0 : if (aAttribute == nsGkAtoms::tooltiptext ||
8168 : aAttribute == nsGkAtoms::tooltip)
8169 : {
8170 0 : nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
8171 0 : if (rootBox) {
8172 0 : if (aModType == nsIDOMMutationEvent::REMOVAL)
8173 0 : rootBox->RemoveTooltipSupport(aElement);
8174 0 : if (aModType == nsIDOMMutationEvent::ADDITION)
8175 0 : rootBox->AddTooltipSupport(aElement);
8176 : }
8177 : }
8178 :
8179 : #endif // MOZ_XUL
8180 :
8181 0 : if (primaryFrame) {
8182 : // See if we have appearance information for a theme.
8183 0 : const nsStyleDisplay* disp = primaryFrame->GetStyleDisplay();
8184 0 : if (disp->mAppearance) {
8185 0 : nsPresContext* presContext = mPresShell->GetPresContext();
8186 0 : nsITheme *theme = presContext->GetTheme();
8187 0 : if (theme && theme->ThemeSupportsWidget(presContext, primaryFrame, disp->mAppearance)) {
8188 0 : bool repaint = false;
8189 0 : theme->WidgetStateChanged(primaryFrame, disp->mAppearance, aAttribute, &repaint);
8190 0 : if (repaint)
8191 0 : NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
8192 : }
8193 : }
8194 :
8195 : // let the frame deal with it now, so we don't have to deal later
8196 0 : primaryFrame->AttributeChanged(aNameSpaceID, aAttribute, aModType);
8197 : // XXXwaterson should probably check for special IB siblings
8198 : // here, and propagate the AttributeChanged notification to
8199 : // them, as well. Currently, inline frames don't do anything on
8200 : // this notification, so it's not that big a deal.
8201 : }
8202 :
8203 : // See if we can optimize away the style re-resolution -- must be called after
8204 : // the frame's AttributeChanged() in case it does something that affects the style
8205 : nsRestyleHint rshint =
8206 : mPresShell->StyleSet()->HasAttributeDependentStyle(mPresShell->GetPresContext(),
8207 : aElement,
8208 : aAttribute,
8209 : aModType,
8210 0 : true);
8211 :
8212 0 : PostRestyleEvent(aElement, rshint, hint);
8213 : }
8214 :
8215 : void
8216 0 : nsCSSFrameConstructor::BeginUpdate() {
8217 0 : NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
8218 : "Someone forgot a script blocker");
8219 :
8220 : nsRootPresContext* rootPresContext =
8221 0 : mPresShell->GetPresContext()->GetRootPresContext();
8222 0 : if (rootPresContext) {
8223 0 : rootPresContext->IncrementDOMGeneration();
8224 : }
8225 :
8226 0 : ++mUpdateCount;
8227 0 : }
8228 :
8229 : void
8230 0 : nsCSSFrameConstructor::EndUpdate()
8231 : {
8232 0 : if (mUpdateCount == 1) {
8233 : // This is the end of our last update. Before we decrement
8234 : // mUpdateCount, recalc quotes and counters as needed.
8235 :
8236 0 : RecalcQuotesAndCounters();
8237 0 : NS_ASSERTION(mUpdateCount == 1, "Odd update count");
8238 : }
8239 0 : NS_ASSERTION(mUpdateCount, "Negative mUpdateCount!");
8240 0 : --mUpdateCount;
8241 0 : }
8242 :
8243 : void
8244 0 : nsCSSFrameConstructor::RecalcQuotesAndCounters()
8245 : {
8246 0 : if (mQuotesDirty) {
8247 0 : mQuotesDirty = false;
8248 0 : mQuoteList.RecalcAll();
8249 : }
8250 :
8251 0 : if (mCountersDirty) {
8252 0 : mCountersDirty = false;
8253 0 : mCounterManager.RecalcAll();
8254 : }
8255 :
8256 0 : NS_ASSERTION(!mQuotesDirty, "Quotes updates will be lost");
8257 0 : NS_ASSERTION(!mCountersDirty, "Counter updates will be lost");
8258 0 : }
8259 :
8260 : void
8261 0 : nsCSSFrameConstructor::WillDestroyFrameTree()
8262 : {
8263 : #if defined(DEBUG_dbaron_off)
8264 : mCounterManager.Dump();
8265 : #endif
8266 :
8267 0 : mIsDestroyingFrameTree = true;
8268 :
8269 : // Prevent frame tree destruction from being O(N^2)
8270 0 : mQuoteList.Clear();
8271 0 : mCounterManager.Clear();
8272 :
8273 : // Remove our presshell as a style flush observer. But leave
8274 : // mObservingRefreshDriver true so we don't readd to it even if someone tries
8275 : // to post restyle events on us from this point on for some reason.
8276 : mPresShell->GetPresContext()->RefreshDriver()->
8277 0 : RemoveStyleFlushObserver(mPresShell);
8278 :
8279 0 : nsFrameManager::Destroy();
8280 0 : }
8281 :
8282 : //STATIC
8283 :
8284 : // XXXbz I'd really like this method to go away. Once we have inline-block and
8285 : // I can just use that for sized broken images, that can happen, maybe.
8286 0 : void nsCSSFrameConstructor::GetAlternateTextFor(nsIContent* aContent,
8287 : nsIAtom* aTag, // content object's tag
8288 : nsXPIDLString& aAltText)
8289 : {
8290 : // The "alt" attribute specifies alternate text that is rendered
8291 : // when the image can not be displayed
8292 :
8293 : // If there's no "alt" attribute, and aContent is an input
8294 : // element, then use the value of the "value" attribute
8295 0 : if (!aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aAltText) &&
8296 : nsGkAtoms::input == aTag) {
8297 : // If there's no "value" attribute either, then use the localized string
8298 : // for "Submit" as the alternate text.
8299 0 : if (!aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aAltText)) {
8300 : nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
8301 0 : "Submit", aAltText);
8302 : }
8303 : }
8304 0 : }
8305 :
8306 : nsresult
8307 0 : nsCSSFrameConstructor::CreateContinuingOuterTableFrame(nsIPresShell* aPresShell,
8308 : nsPresContext* aPresContext,
8309 : nsIFrame* aFrame,
8310 : nsIFrame* aParentFrame,
8311 : nsIContent* aContent,
8312 : nsStyleContext* aStyleContext,
8313 : nsIFrame** aContinuingFrame)
8314 : {
8315 0 : nsIFrame* newFrame = NS_NewTableOuterFrame(aPresShell, aStyleContext);
8316 :
8317 0 : if (newFrame) {
8318 0 : newFrame->Init(aContent, aParentFrame, aFrame);
8319 :
8320 : // Create a continuing inner table frame, and if there's a caption then
8321 : // replicate the caption
8322 0 : nsFrameItems newChildFrames;
8323 :
8324 0 : nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
8325 0 : if (childFrame) {
8326 : nsIFrame* continuingTableFrame;
8327 : nsresult rv = CreateContinuingFrame(aPresContext, childFrame, newFrame,
8328 0 : &continuingTableFrame);
8329 0 : if (NS_FAILED(rv)) {
8330 0 : newFrame->Destroy();
8331 0 : *aContinuingFrame = nsnull;
8332 0 : return rv;
8333 : }
8334 0 : newChildFrames.AddChild(continuingTableFrame);
8335 :
8336 0 : NS_ASSERTION(!childFrame->GetNextSibling(),"there can be only one inner table frame");
8337 : }
8338 :
8339 : // Set the outer table's initial child list
8340 0 : newFrame->SetInitialChildList(kPrincipalList, newChildFrames);
8341 :
8342 0 : *aContinuingFrame = newFrame;
8343 0 : return NS_OK;
8344 : }
8345 : else {
8346 0 : *aContinuingFrame = nsnull;
8347 0 : return NS_ERROR_OUT_OF_MEMORY;
8348 : }
8349 : }
8350 :
8351 : nsresult
8352 0 : nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell* aPresShell,
8353 : nsPresContext* aPresContext,
8354 : nsIFrame* aFrame,
8355 : nsIFrame* aParentFrame,
8356 : nsIContent* aContent,
8357 : nsStyleContext* aStyleContext,
8358 : nsIFrame** aContinuingFrame)
8359 : {
8360 0 : nsIFrame* newFrame = NS_NewTableFrame(aPresShell, aStyleContext);
8361 :
8362 0 : if (newFrame) {
8363 0 : newFrame->Init(aContent, aParentFrame, aFrame);
8364 :
8365 : // Replicate any header/footer frames
8366 0 : nsFrameItems childFrames;
8367 0 : nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
8368 0 : for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
8369 : // See if it's a header/footer, possibly wrapped in a scroll frame.
8370 : nsTableRowGroupFrame* rowGroupFrame =
8371 0 : static_cast<nsTableRowGroupFrame*>(childFrame);
8372 : // If the row group was continued, then don't replicate it.
8373 0 : nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow();
8374 0 : if (rgNextInFlow) {
8375 0 : rowGroupFrame->SetRepeatable(false);
8376 : }
8377 0 : else if (rowGroupFrame->IsRepeatable()) {
8378 : // Replicate the header/footer frame.
8379 : nsTableRowGroupFrame* headerFooterFrame;
8380 0 : nsFrameItems childItems;
8381 : nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
8382 : GetAbsoluteContainingBlock(newFrame),
8383 0 : nsnull);
8384 0 : state.mCreatingExtraFrames = true;
8385 :
8386 : headerFooterFrame = static_cast<nsTableRowGroupFrame*>
8387 0 : (NS_NewTableRowGroupFrame(aPresShell, rowGroupFrame->GetStyleContext()));
8388 0 : nsIContent* headerFooter = rowGroupFrame->GetContent();
8389 0 : headerFooterFrame->Init(headerFooter, newFrame, nsnull);
8390 : ProcessChildren(state, headerFooter, rowGroupFrame->GetStyleContext(),
8391 : headerFooterFrame, true, childItems, false,
8392 0 : nsnull);
8393 0 : NS_ASSERTION(state.mFloatedItems.IsEmpty(), "unexpected floated element");
8394 0 : headerFooterFrame->SetInitialChildList(kPrincipalList, childItems);
8395 0 : headerFooterFrame->SetRepeatable(true);
8396 :
8397 : // Table specific initialization
8398 0 : headerFooterFrame->InitRepeatedFrame(aPresContext, rowGroupFrame);
8399 :
8400 : // XXX Deal with absolute and fixed frames...
8401 0 : childFrames.AddChild(headerFooterFrame);
8402 : }
8403 : }
8404 :
8405 : // Set the table frame's initial child list
8406 0 : newFrame->SetInitialChildList(kPrincipalList, childFrames);
8407 :
8408 0 : *aContinuingFrame = newFrame;
8409 0 : return NS_OK;
8410 : }
8411 : else {
8412 0 : *aContinuingFrame = nsnull;
8413 0 : return NS_ERROR_OUT_OF_MEMORY;
8414 : }
8415 : }
8416 :
8417 : nsresult
8418 0 : nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext,
8419 : nsIFrame* aFrame,
8420 : nsIFrame* aParentFrame,
8421 : nsIFrame** aContinuingFrame,
8422 : bool aIsFluid)
8423 : {
8424 0 : nsIPresShell* shell = aPresContext->PresShell();
8425 0 : nsStyleContext* styleContext = aFrame->GetStyleContext();
8426 0 : nsIFrame* newFrame = nsnull;
8427 0 : nsresult rv = NS_OK;
8428 0 : nsIFrame* nextContinuation = aFrame->GetNextContinuation();
8429 0 : nsIFrame* nextInFlow = aFrame->GetNextInFlow();
8430 :
8431 : // Use the frame type to determine what type of frame to create
8432 0 : nsIAtom* frameType = aFrame->GetType();
8433 0 : nsIContent* content = aFrame->GetContent();
8434 :
8435 0 : NS_ASSERTION(aFrame->GetSplittableType() != NS_FRAME_NOT_SPLITTABLE,
8436 : "why CreateContinuingFrame for a non-splittable frame?");
8437 :
8438 0 : if (nsGkAtoms::textFrame == frameType) {
8439 0 : newFrame = NS_NewContinuingTextFrame(shell, styleContext);
8440 :
8441 0 : if (newFrame) {
8442 0 : newFrame->Init(content, aParentFrame, aFrame);
8443 : }
8444 :
8445 0 : } else if (nsGkAtoms::inlineFrame == frameType) {
8446 0 : newFrame = NS_NewInlineFrame(shell, styleContext);
8447 :
8448 0 : if (newFrame) {
8449 0 : newFrame->Init(content, aParentFrame, aFrame);
8450 : }
8451 :
8452 0 : } else if (nsGkAtoms::blockFrame == frameType) {
8453 0 : newFrame = NS_NewBlockFrame(shell, styleContext);
8454 :
8455 0 : if (newFrame) {
8456 0 : newFrame->Init(content, aParentFrame, aFrame);
8457 : }
8458 :
8459 : #ifdef MOZ_XUL
8460 0 : } else if (nsGkAtoms::XULLabelFrame == frameType) {
8461 0 : newFrame = NS_NewXULLabelFrame(shell, styleContext);
8462 :
8463 0 : if (newFrame) {
8464 0 : newFrame->Init(content, aParentFrame, aFrame);
8465 : }
8466 : #endif
8467 0 : } else if (nsGkAtoms::columnSetFrame == frameType) {
8468 0 : newFrame = NS_NewColumnSetFrame(shell, styleContext, 0);
8469 :
8470 0 : if (newFrame) {
8471 0 : newFrame->Init(content, aParentFrame, aFrame);
8472 : }
8473 :
8474 0 : } else if (nsGkAtoms::pageFrame == frameType) {
8475 : nsIFrame* canvasFrame;
8476 : rv = ConstructPageFrame(shell, aPresContext, aParentFrame, aFrame,
8477 0 : newFrame, canvasFrame);
8478 0 : } else if (nsGkAtoms::tableOuterFrame == frameType) {
8479 : rv = CreateContinuingOuterTableFrame(shell, aPresContext, aFrame, aParentFrame,
8480 0 : content, styleContext, &newFrame);
8481 :
8482 0 : } else if (nsGkAtoms::tableFrame == frameType) {
8483 : rv = CreateContinuingTableFrame(shell, aPresContext, aFrame, aParentFrame,
8484 0 : content, styleContext, &newFrame);
8485 :
8486 0 : } else if (nsGkAtoms::tableRowGroupFrame == frameType) {
8487 0 : newFrame = NS_NewTableRowGroupFrame(shell, styleContext);
8488 :
8489 0 : if (newFrame) {
8490 0 : newFrame->Init(content, aParentFrame, aFrame);
8491 : }
8492 :
8493 0 : } else if (nsGkAtoms::tableRowFrame == frameType) {
8494 0 : newFrame = NS_NewTableRowFrame(shell, styleContext);
8495 :
8496 0 : if (newFrame) {
8497 0 : newFrame->Init(content, aParentFrame, aFrame);
8498 :
8499 : // Create a continuing frame for each table cell frame
8500 0 : nsFrameItems newChildList;
8501 0 : nsIFrame* cellFrame = aFrame->GetFirstPrincipalChild();
8502 0 : while (cellFrame) {
8503 : // See if it's a table cell frame
8504 0 : if (IS_TABLE_CELL(cellFrame->GetType())) {
8505 : nsIFrame* continuingCellFrame;
8506 : rv = CreateContinuingFrame(aPresContext, cellFrame, newFrame,
8507 0 : &continuingCellFrame);
8508 0 : if (NS_FAILED(rv)) {
8509 0 : newChildList.DestroyFrames();
8510 0 : newFrame->Destroy();
8511 0 : *aContinuingFrame = nsnull;
8512 0 : return NS_ERROR_OUT_OF_MEMORY;
8513 : }
8514 0 : newChildList.AddChild(continuingCellFrame);
8515 : }
8516 0 : cellFrame = cellFrame->GetNextSibling();
8517 : }
8518 :
8519 : // Set the table cell's initial child list
8520 0 : newFrame->SetInitialChildList(kPrincipalList, newChildList);
8521 : }
8522 :
8523 0 : } else if (IS_TABLE_CELL(frameType)) {
8524 : // Warning: If you change this and add a wrapper frame around table cell
8525 : // frames, make sure Bug 368554 doesn't regress!
8526 : // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
8527 0 : newFrame = NS_NewTableCellFrame(shell, styleContext, IsBorderCollapse(aParentFrame));
8528 :
8529 0 : if (newFrame) {
8530 0 : newFrame->Init(content, aParentFrame, aFrame);
8531 :
8532 : // Create a continuing area frame
8533 : nsIFrame* continuingBlockFrame;
8534 0 : nsIFrame* blockFrame = aFrame->GetFirstPrincipalChild();
8535 : rv = CreateContinuingFrame(aPresContext, blockFrame, newFrame,
8536 0 : &continuingBlockFrame);
8537 0 : if (NS_FAILED(rv)) {
8538 0 : newFrame->Destroy();
8539 0 : *aContinuingFrame = nsnull;
8540 0 : return rv;
8541 : }
8542 :
8543 : // Set the table cell's initial child list
8544 0 : SetInitialSingleChild(newFrame, continuingBlockFrame);
8545 : }
8546 :
8547 0 : } else if (nsGkAtoms::lineFrame == frameType) {
8548 0 : newFrame = NS_NewFirstLineFrame(shell, styleContext);
8549 :
8550 0 : if (newFrame) {
8551 0 : newFrame->Init(content, aParentFrame, aFrame);
8552 : }
8553 :
8554 0 : } else if (nsGkAtoms::letterFrame == frameType) {
8555 0 : newFrame = NS_NewFirstLetterFrame(shell, styleContext);
8556 :
8557 0 : if (newFrame) {
8558 0 : newFrame->Init(content, aParentFrame, aFrame);
8559 : }
8560 :
8561 0 : } else if (nsGkAtoms::imageFrame == frameType) {
8562 0 : newFrame = NS_NewImageFrame(shell, styleContext);
8563 :
8564 0 : if (newFrame) {
8565 0 : newFrame->Init(content, aParentFrame, aFrame);
8566 : }
8567 0 : } else if (nsGkAtoms::imageControlFrame == frameType) {
8568 0 : newFrame = NS_NewImageControlFrame(shell, styleContext);
8569 :
8570 0 : if (newFrame) {
8571 0 : newFrame->Init(content, aParentFrame, aFrame);
8572 : }
8573 0 : } else if (nsGkAtoms::placeholderFrame == frameType) {
8574 : // create a continuing out of flow frame
8575 0 : nsIFrame* oofFrame = nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
8576 : nsIFrame* oofContFrame;
8577 0 : rv = CreateContinuingFrame(aPresContext, oofFrame, aParentFrame, &oofContFrame);
8578 0 : if (NS_FAILED(rv)) {
8579 0 : *aContinuingFrame = nsnull;
8580 0 : return rv;
8581 : }
8582 : // create a continuing placeholder frame
8583 : rv = CreatePlaceholderFrameFor(shell, content, oofContFrame, styleContext,
8584 : aParentFrame, aFrame,
8585 0 : aFrame->GetStateBits() & PLACEHOLDER_TYPE_MASK,
8586 0 : &newFrame);
8587 0 : if (NS_FAILED(rv)) {
8588 0 : oofContFrame->Destroy();
8589 0 : *aContinuingFrame = nsnull;
8590 0 : return rv;
8591 : }
8592 0 : } else if (nsGkAtoms::fieldSetFrame == frameType) {
8593 0 : newFrame = NS_NewFieldSetFrame(shell, styleContext);
8594 :
8595 0 : if (newFrame) {
8596 0 : newFrame->Init(content, aParentFrame, aFrame);
8597 :
8598 : // Create a continuing area frame
8599 : // XXXbz we really shouldn't have to do this by hand!
8600 : nsIFrame* continuingBlockFrame;
8601 0 : nsIFrame* blockFrame = GetFieldSetBlockFrame(aFrame);
8602 : rv = CreateContinuingFrame(aPresContext, blockFrame, newFrame,
8603 0 : &continuingBlockFrame);
8604 0 : if (NS_FAILED(rv)) {
8605 0 : newFrame->Destroy();
8606 0 : *aContinuingFrame = nsnull;
8607 0 : return rv;
8608 : }
8609 : // Set the fieldset's initial child list
8610 0 : SetInitialSingleChild(newFrame, continuingBlockFrame);
8611 : }
8612 0 : } else if (nsGkAtoms::legendFrame == frameType) {
8613 0 : newFrame = NS_NewLegendFrame(shell, styleContext);
8614 :
8615 0 : if (newFrame) {
8616 0 : newFrame->Init(content, aParentFrame, aFrame);
8617 : }
8618 : } else {
8619 0 : NS_NOTREACHED("unexpected frame type");
8620 0 : *aContinuingFrame = nsnull;
8621 0 : return NS_ERROR_UNEXPECTED;
8622 : }
8623 :
8624 0 : *aContinuingFrame = newFrame;
8625 :
8626 0 : if (!newFrame) {
8627 0 : return NS_ERROR_OUT_OF_MEMORY;
8628 : }
8629 :
8630 : // Init() set newFrame to be a fluid continuation of aFrame.
8631 : // If we want a non-fluid continuation, we need to call SetPrevContinuation()
8632 : // to reset NS_FRAME_IS_FLUID_CONTINUATION.
8633 0 : if (!aIsFluid) {
8634 0 : newFrame->SetPrevContinuation(aFrame);
8635 : }
8636 :
8637 : // A continuation of generated content is also generated content
8638 0 : if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
8639 0 : newFrame->AddStateBits(NS_FRAME_GENERATED_CONTENT);
8640 : }
8641 :
8642 : // A continuation of an out-of-flow is also an out-of-flow
8643 0 : if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
8644 0 : newFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
8645 : }
8646 :
8647 0 : if (nextInFlow) {
8648 0 : nextInFlow->SetPrevInFlow(newFrame);
8649 0 : newFrame->SetNextInFlow(nextInFlow);
8650 0 : } else if (nextContinuation) {
8651 0 : nextContinuation->SetPrevContinuation(newFrame);
8652 0 : newFrame->SetNextContinuation(nextContinuation);
8653 : }
8654 :
8655 0 : NS_POSTCONDITION(!newFrame->GetNextSibling(), "unexpected sibling");
8656 0 : return NS_OK;
8657 : }
8658 :
8659 : nsresult
8660 0 : nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame)
8661 : {
8662 : // Now deal with fixed-pos things.... They should appear on all pages,
8663 : // so we want to move over the placeholders when processing the child
8664 : // of the pageContentFrame.
8665 :
8666 0 : nsIFrame* prevPageContentFrame = aParentFrame->GetPrevInFlow();
8667 0 : if (!prevPageContentFrame) {
8668 0 : return NS_OK;
8669 : }
8670 0 : nsIFrame* canvasFrame = aParentFrame->GetFirstPrincipalChild();
8671 0 : nsIFrame* prevCanvasFrame = prevPageContentFrame->GetFirstPrincipalChild();
8672 0 : if (!canvasFrame || !prevCanvasFrame) {
8673 : // document's root element frame missing
8674 0 : return NS_ERROR_UNEXPECTED;
8675 : }
8676 :
8677 0 : nsFrameItems fixedPlaceholders;
8678 0 : nsIFrame* firstFixed = prevPageContentFrame->GetFirstChild(nsIFrame::kFixedList);
8679 0 : if (!firstFixed) {
8680 0 : return NS_OK;
8681 : }
8682 :
8683 : // Don't allow abs-pos descendants of the fixed content to escape the content.
8684 : // This should not normally be possible (because fixed-pos elements should
8685 : // be absolute containers) but fixed-pos tables currently aren't abs-pos
8686 : // containers.
8687 : nsFrameConstructorState state(mPresShell, aParentFrame,
8688 : nsnull,
8689 0 : mRootElementFrame);
8690 0 : state.mCreatingExtraFrames = true;
8691 :
8692 : // We can't use an ancestor filter here, because we're not going to
8693 : // be usefully recurring down the tree. This means that other
8694 : // places in frame construction can't assume a filter is
8695 : // initialized!
8696 :
8697 : // Iterate across fixed frames and replicate each whose placeholder is a
8698 : // descendant of aFrame. (We don't want to explicitly copy placeholders that
8699 : // are within fixed frames, because that would cause duplicates on the new
8700 : // page - bug 389619)
8701 0 : for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
8702 0 : nsIFrame* prevPlaceholder = GetPlaceholderFrameFor(fixed);
8703 0 : if (prevPlaceholder &&
8704 0 : nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) {
8705 : // We want to use the same style as the primary style frame for
8706 : // our content
8707 0 : nsIContent* content = fixed->GetContent();
8708 : nsStyleContext* styleContext =
8709 : nsLayoutUtils::GetStyleFrame(content->GetPrimaryFrame())->
8710 0 : GetStyleContext();
8711 0 : FrameConstructionItemList items;
8712 : AddFrameConstructionItemsInternal(state, content, canvasFrame,
8713 : content->Tag(),
8714 : content->GetNameSpaceID(),
8715 : true,
8716 : styleContext,
8717 : ITEM_ALLOW_XBL_BASE |
8718 : ITEM_ALLOW_PAGE_BREAK,
8719 0 : items);
8720 0 : for (FCItemIterator iter(items); !iter.IsDone(); iter.Next()) {
8721 0 : NS_ASSERTION(iter.item().DesiredParentType() ==
8722 : GetParentType(canvasFrame),
8723 : "This is not going to work");
8724 : nsresult rv =
8725 0 : ConstructFramesFromItem(state, iter, canvasFrame, fixedPlaceholders);
8726 0 : NS_ENSURE_SUCCESS(rv, rv);
8727 : }
8728 : }
8729 : }
8730 :
8731 : // Add the placeholders to our primary child list.
8732 : // XXXbz this is a little screwed up, since the fixed frames will have
8733 : // broken auto-positioning. Oh, well.
8734 0 : NS_ASSERTION(!canvasFrame->GetFirstPrincipalChild(),
8735 : "leaking frames; doc root continuation must be empty");
8736 0 : canvasFrame->SetInitialChildList(kPrincipalList, fixedPlaceholders);
8737 0 : return NS_OK;
8738 : }
8739 :
8740 : nsresult
8741 0 : nsCSSFrameConstructor::GetInsertionPoint(nsIFrame* aParentFrame,
8742 : nsIContent* aChildContent,
8743 : nsIFrame** aInsertionPoint,
8744 : bool* aMultiple)
8745 : {
8746 : // Make the insertion point be the parent frame by default, in case
8747 : // we have to bail early.
8748 0 : *aInsertionPoint = aParentFrame;
8749 :
8750 0 : nsIContent* container = aParentFrame->GetContent();
8751 0 : if (!container)
8752 0 : return NS_OK;
8753 :
8754 0 : nsBindingManager *bindingManager = mDocument->BindingManager();
8755 :
8756 : nsIContent* insertionElement;
8757 0 : if (aChildContent) {
8758 : // We've got an explicit insertion child. Check to see if it's
8759 : // anonymous.
8760 0 : if (aChildContent->GetBindingParent() == container) {
8761 : // This child content is anonymous. Don't use the insertion
8762 : // point, since that's only for the explicit kids.
8763 0 : return NS_OK;
8764 : }
8765 :
8766 : PRUint32 index;
8767 : insertionElement = bindingManager->GetInsertionPoint(container,
8768 : aChildContent,
8769 0 : &index);
8770 : }
8771 : else {
8772 : bool multiple;
8773 : PRUint32 index;
8774 : insertionElement = bindingManager->GetSingleInsertionPoint(container,
8775 : &index,
8776 0 : &multiple);
8777 0 : if (multiple && aMultiple)
8778 0 : *aMultiple = multiple; // Record the fact that filters are in use.
8779 : }
8780 :
8781 0 : if (insertionElement) {
8782 0 : nsIFrame* insertionPoint = insertionElement->GetPrimaryFrame();
8783 0 : if (insertionPoint) {
8784 : // Use the content insertion frame of the insertion point.
8785 0 : insertionPoint = insertionPoint->GetContentInsertionFrame();
8786 0 : if (insertionPoint && insertionPoint != aParentFrame)
8787 0 : GetInsertionPoint(insertionPoint, aChildContent, aInsertionPoint, aMultiple);
8788 : }
8789 : else {
8790 : // There was no frame created yet for the insertion point.
8791 0 : *aInsertionPoint = nsnull;
8792 : }
8793 : }
8794 :
8795 : // fieldsets have multiple insertion points. Note that we might
8796 : // have to look at insertionElement here...
8797 0 : if (aMultiple && !*aMultiple) {
8798 0 : nsIContent* content = insertionElement ? insertionElement : container;
8799 0 : if (content->IsHTML(nsGkAtoms::fieldset)) {
8800 0 : *aMultiple = true;
8801 : }
8802 : }
8803 :
8804 0 : return NS_OK;
8805 : }
8806 :
8807 : // Capture state for the frame tree rooted at the frame associated with the
8808 : // content object, aContent
8809 : nsresult
8810 0 : nsCSSFrameConstructor::CaptureStateForFramesOf(nsIContent* aContent,
8811 : nsILayoutHistoryState* aHistoryState)
8812 : {
8813 0 : nsIFrame* frame = aContent->GetPrimaryFrame();
8814 0 : if (frame == mRootElementFrame) {
8815 0 : frame = mFixedContainingBlock;
8816 : }
8817 0 : if (frame) {
8818 0 : CaptureStateFor(frame, aHistoryState);
8819 : }
8820 0 : return NS_OK;
8821 : }
8822 :
8823 : // Capture state for the frame tree rooted at aFrame.
8824 : nsresult
8825 0 : nsCSSFrameConstructor::CaptureStateFor(nsIFrame* aFrame,
8826 : nsILayoutHistoryState* aHistoryState)
8827 : {
8828 0 : if (aFrame && aHistoryState) {
8829 0 : CaptureFrameState(aFrame, aHistoryState);
8830 : }
8831 0 : return NS_OK;
8832 : }
8833 :
8834 : nsresult
8835 0 : nsCSSFrameConstructor::MaybeRecreateFramesForElement(Element* aElement)
8836 : {
8837 0 : nsresult result = NS_OK;
8838 :
8839 0 : nsStyleContext *oldContext = GetUndisplayedContent(aElement);
8840 0 : if (oldContext) {
8841 : // The parent has a frame, so try resolving a new context.
8842 : nsRefPtr<nsStyleContext> newContext = mPresShell->StyleSet()->
8843 0 : ResolveStyleFor(aElement, oldContext->GetParent());
8844 :
8845 0 : ChangeUndisplayedContent(aElement, newContext);
8846 0 : if (newContext->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_NONE) {
8847 0 : result = RecreateFramesForContent(aElement, false);
8848 : }
8849 : }
8850 0 : return result;
8851 : }
8852 :
8853 : static nsIFrame*
8854 0 : FindFirstNonWhitespaceChild(nsIFrame* aParentFrame)
8855 : {
8856 0 : nsIFrame* f = aParentFrame->GetFirstPrincipalChild();
8857 0 : while (f && f->GetType() == nsGkAtoms::textFrame &&
8858 0 : f->GetContent()->TextIsOnlyWhitespace()) {
8859 0 : f = f->GetNextSibling();
8860 : }
8861 0 : return f;
8862 : }
8863 :
8864 : static nsIFrame*
8865 0 : FindNextNonWhitespaceSibling(nsIFrame* aFrame)
8866 : {
8867 0 : nsIFrame* f = aFrame;
8868 0 : do {
8869 0 : f = f->GetNextSibling();
8870 0 : } while (f && f->GetType() == nsGkAtoms::textFrame &&
8871 0 : f->GetContent()->TextIsOnlyWhitespace());
8872 0 : return f;
8873 : }
8874 :
8875 : bool
8876 0 : nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
8877 : nsresult* aResult)
8878 : {
8879 0 : NS_PRECONDITION(aFrame, "Must have a frame");
8880 0 : NS_PRECONDITION(aFrame->GetParent(), "Frame shouldn't be root");
8881 0 : NS_PRECONDITION(aResult, "Null out param?");
8882 0 : NS_PRECONDITION(aFrame == aFrame->GetFirstContinuation(),
8883 : "aFrame not the result of GetPrimaryFrame()?");
8884 :
8885 0 : if (IsFrameSpecial(aFrame)) {
8886 : // The removal functions can't handle removal of an {ib} split directly; we
8887 : // need to rebuild the containing block.
8888 : #ifdef DEBUG
8889 0 : if (gNoisyContentUpdates) {
8890 : printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8891 0 : "frame=");
8892 0 : nsFrame::ListTag(stdout, aFrame);
8893 0 : printf(" is special\n");
8894 : }
8895 : #endif
8896 :
8897 0 : *aResult = ReframeContainingBlock(aFrame);
8898 0 : return true;
8899 : }
8900 :
8901 0 : if (aFrame->GetType() == nsGkAtoms::legendFrame &&
8902 0 : aFrame->GetParent()->GetType() == nsGkAtoms::fieldSetFrame) {
8903 : // When we remove the legend for a fieldset, we should reframe
8904 : // the fieldset to ensure another legend is used, if there is one
8905 0 : *aResult = RecreateFramesForContent(aFrame->GetParent()->GetContent(), false);
8906 0 : return true;
8907 : }
8908 :
8909 : // Now check for possibly needing to reconstruct due to a pseudo parent
8910 : nsIFrame* inFlowFrame =
8911 0 : (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ?
8912 0 : GetPlaceholderFrameFor(aFrame) : aFrame;
8913 0 : NS_ASSERTION(inFlowFrame, "How did that happen?");
8914 0 : nsIFrame* parent = inFlowFrame->GetParent();
8915 0 : if (IsTablePseudo(parent)) {
8916 0 : if (FindFirstNonWhitespaceChild(parent) == inFlowFrame ||
8917 0 : !FindNextNonWhitespaceSibling(inFlowFrame->GetLastContinuation()) ||
8918 : // If we're a table-column-group, then the GetFirstChild check above is
8919 : // not going to catch cases when we're the first child.
8920 0 : (inFlowFrame->GetType() == nsGkAtoms::tableColGroupFrame &&
8921 0 : parent->GetFirstChild(nsIFrame::kColGroupList) == inFlowFrame) ||
8922 : // Similar if we're a table-caption.
8923 0 : (inFlowFrame->GetType() == nsGkAtoms::tableCaptionFrame &&
8924 0 : parent->GetFirstChild(nsIFrame::kCaptionList) == inFlowFrame)) {
8925 : // We're the first or last frame in the pseudo. Need to reframe.
8926 : // Good enough to recreate frames for |parent|'s content
8927 0 : *aResult = RecreateFramesForContent(parent->GetContent(), true);
8928 0 : return true;
8929 : }
8930 : }
8931 :
8932 : // Might need to reconstruct things if this frame's nextSibling is a table
8933 : // pseudo, since removal of this frame might mean that this pseudo needs to
8934 : // get merged with the frame's prevSibling.
8935 : // XXXbz it would be really nice if we had the prevSibling here too, to check
8936 : // whether this is in fact the case...
8937 : nsIFrame* nextSibling =
8938 0 : FindNextNonWhitespaceSibling(inFlowFrame->GetLastContinuation());
8939 0 : NS_ASSERTION(!IsTablePseudo(inFlowFrame), "Shouldn't happen here");
8940 0 : if (nextSibling && IsTablePseudo(nextSibling)) {
8941 : #ifdef DEBUG
8942 0 : if (gNoisyContentUpdates) {
8943 : printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
8944 0 : "frame=");
8945 0 : nsFrame::ListTag(stdout, aFrame);
8946 0 : printf(" has a table pseudo next sibling of different type\n");
8947 : }
8948 : #endif
8949 : // Good enough to recreate frames for aFrame's parent's content; even if
8950 : // aFrame's parent is a table pseudo, that'll be the right content node.
8951 0 : *aResult = RecreateFramesForContent(parent->GetContent(), true);
8952 0 : return true;
8953 : }
8954 :
8955 : #ifdef MOZ_XUL
8956 0 : if (aFrame->GetType() == nsGkAtoms::popupSetFrame) {
8957 0 : nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
8958 0 : if (rootBox && rootBox->GetPopupSetFrame() == aFrame) {
8959 0 : *aResult = ReconstructDocElementHierarchy();
8960 0 : return true;
8961 : }
8962 : }
8963 : #endif
8964 :
8965 : // Reconstruct if inflowFrame is parent's only child, and parent is, or has,
8966 : // a non-fluid continuation, i.e. it was split by bidi resolution
8967 0 : if (!inFlowFrame->GetPrevSibling() &&
8968 0 : !inFlowFrame->GetNextSibling() &&
8969 0 : (parent->GetPrevContinuation() && !parent->GetPrevInFlow() ||
8970 0 : parent->GetNextContinuation() && !parent->GetNextInFlow())) {
8971 0 : *aResult = RecreateFramesForContent(parent->GetContent(), true);
8972 0 : return true;
8973 : }
8974 :
8975 : // We might still need to reconstruct things if the parent of inFlowFrame is
8976 : // special, since in that case the removal of aFrame might affect the
8977 : // splitting of its parent.
8978 0 : if (!IsFrameSpecial(parent)) {
8979 0 : return false;
8980 : }
8981 :
8982 : // If inFlowFrame is not the only in-flow child of |parent|, then removing
8983 : // it will change nothing about the {ib} split.
8984 0 : if (inFlowFrame != parent->GetFirstPrincipalChild() ||
8985 0 : inFlowFrame->GetLastContinuation()->GetNextSibling()) {
8986 0 : return false;
8987 : }
8988 :
8989 : // If the parent is the first or last part of the {ib} split, then
8990 : // removing one of its kids will have no effect on the splitting.
8991 : // Get the first continuation up front so we don't have to do it twice.
8992 0 : nsIFrame* parentFirstContinuation = parent->GetFirstContinuation();
8993 0 : if (!GetSpecialSibling(parentFirstContinuation) ||
8994 0 : !GetSpecialPrevSibling(parentFirstContinuation)) {
8995 0 : return false;
8996 : }
8997 :
8998 : #ifdef DEBUG
8999 0 : if (gNoisyContentUpdates) {
9000 : printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
9001 0 : "frame=");
9002 0 : nsFrame::ListTag(stdout, parent);
9003 0 : printf(" is special\n");
9004 : }
9005 : #endif
9006 :
9007 0 : *aResult = ReframeContainingBlock(parent);
9008 0 : return true;
9009 : }
9010 :
9011 : nsresult
9012 0 : nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
9013 : bool aAsyncInsert)
9014 : {
9015 0 : NS_PRECONDITION(!aAsyncInsert || aContent->IsElement(),
9016 : "Can only insert elements async");
9017 : // If there is no document, we don't want to recreate frames for it. (You
9018 : // shouldn't generally be giving this method content without a document
9019 : // anyway).
9020 : // Rebuilding the frame tree can have bad effects, especially if it's the
9021 : // frame tree for chrome (see bug 157322).
9022 0 : NS_ENSURE_TRUE(aContent->GetDocument(), NS_ERROR_FAILURE);
9023 :
9024 : // Is the frame `special'? If so, we need to reframe the containing
9025 : // block *here*, rather than trying to remove and re-insert the
9026 : // content (which would otherwise result in *two* nested reframe
9027 : // containing block from ContentRemoved() and ContentInserted(),
9028 : // below!). We'd really like to optimize away one of those
9029 : // containing block reframes, hence the code here.
9030 :
9031 0 : nsIFrame* frame = aContent->GetPrimaryFrame();
9032 0 : if (frame && frame->IsFrameOfType(nsIFrame::eMathML)) {
9033 : // Reframe the topmost MathML element to prevent exponential blowup
9034 : // (see bug 397518)
9035 0 : while (true) {
9036 0 : nsIContent* parentContent = aContent->GetParent();
9037 0 : nsIFrame* parentContentFrame = parentContent->GetPrimaryFrame();
9038 0 : if (!parentContentFrame || !parentContentFrame->IsFrameOfType(nsIFrame::eMathML))
9039 : break;
9040 0 : aContent = parentContent;
9041 0 : frame = parentContentFrame;
9042 : }
9043 : }
9044 :
9045 0 : if (frame) {
9046 0 : nsIFrame* nonGeneratedAncestor = nsLayoutUtils::GetNonGeneratedAncestor(frame);
9047 0 : if (nonGeneratedAncestor->GetContent() != aContent) {
9048 0 : return RecreateFramesForContent(nonGeneratedAncestor->GetContent(), aAsyncInsert);
9049 : }
9050 :
9051 0 : nsIFrame* parent = frame->GetParent();
9052 0 : nsIContent* parentContent = parent ? parent->GetContent() : nsnull;
9053 : // If the parent frame is a leaf then the subsequent insert will fail to
9054 : // create a frame, so we need to recreate the parent content. This happens
9055 : // with native anonymous content from the editor.
9056 0 : if (parent && parent->IsLeaf() && parentContent &&
9057 : parentContent != aContent) {
9058 0 : return RecreateFramesForContent(parentContent, aAsyncInsert);
9059 : }
9060 : }
9061 :
9062 0 : nsresult rv = NS_OK;
9063 :
9064 0 : if (frame && MaybeRecreateContainerForFrameRemoval(frame, &rv)) {
9065 0 : return rv;
9066 : }
9067 :
9068 0 : nsINode* containerNode = aContent->GetNodeParent();
9069 : // XXXbz how can containerNode be null here?
9070 0 : if (containerNode) {
9071 : // Before removing the frames associated with the content object,
9072 : // ask them to save their state onto a temporary state object.
9073 0 : CaptureStateForFramesOf(aContent, mTempFrameTreeState);
9074 :
9075 : // Need the nsIContent parent, which might be null here, since we need to
9076 : // pass it to ContentInserted and ContentRemoved.
9077 0 : nsCOMPtr<nsIContent> container = aContent->GetParent();
9078 :
9079 : // Remove the frames associated with the content object.
9080 : bool didReconstruct;
9081 : rv = ContentRemoved(container, aContent,
9082 0 : aContent->IsRootOfAnonymousSubtree() ?
9083 : nsnull :
9084 0 : aContent->GetNextSibling(),
9085 0 : REMOVE_FOR_RECONSTRUCTION, &didReconstruct);
9086 :
9087 0 : if (NS_SUCCEEDED(rv) && !didReconstruct) {
9088 : // Now, recreate the frames associated with this content object. If
9089 : // ContentRemoved triggered reconstruction, then we don't need to do this
9090 : // because the frames will already have been built.
9091 0 : if (aAsyncInsert) {
9092 : PostRestyleEvent(aContent->AsElement(), nsRestyleHint(0),
9093 0 : nsChangeHint_ReconstructFrame);
9094 : } else {
9095 0 : rv = ContentInserted(container, aContent, mTempFrameTreeState, false);
9096 : }
9097 : }
9098 : }
9099 :
9100 0 : return rv;
9101 : }
9102 :
9103 : //////////////////////////////////////////////////////////////////////
9104 :
9105 : // Block frame construction code
9106 :
9107 : already_AddRefed<nsStyleContext>
9108 0 : nsCSSFrameConstructor::GetFirstLetterStyle(nsIContent* aContent,
9109 : nsStyleContext* aStyleContext)
9110 : {
9111 0 : if (aContent) {
9112 : return mPresShell->StyleSet()->
9113 : ResolvePseudoElementStyle(aContent->AsElement(),
9114 : nsCSSPseudoElements::ePseudo_firstLetter,
9115 0 : aStyleContext);
9116 : }
9117 0 : return nsnull;
9118 : }
9119 :
9120 : already_AddRefed<nsStyleContext>
9121 0 : nsCSSFrameConstructor::GetFirstLineStyle(nsIContent* aContent,
9122 : nsStyleContext* aStyleContext)
9123 : {
9124 0 : if (aContent) {
9125 : return mPresShell->StyleSet()->
9126 : ResolvePseudoElementStyle(aContent->AsElement(),
9127 : nsCSSPseudoElements::ePseudo_firstLine,
9128 0 : aStyleContext);
9129 : }
9130 0 : return nsnull;
9131 : }
9132 :
9133 : // Predicate to see if a given content (block element) has
9134 : // first-letter style applied to it.
9135 : bool
9136 0 : nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(nsIContent* aContent,
9137 : nsStyleContext* aStyleContext)
9138 : {
9139 : return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext,
9140 : nsCSSPseudoElements::ePseudo_firstLetter,
9141 0 : mPresShell->GetPresContext());
9142 : }
9143 :
9144 : bool
9145 0 : nsCSSFrameConstructor::HasFirstLetterStyle(nsIFrame* aBlockFrame)
9146 : {
9147 0 : NS_PRECONDITION(aBlockFrame, "Need a frame");
9148 0 : NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame),
9149 : "Not a block frame?");
9150 :
9151 0 : return (aBlockFrame->GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE) != 0;
9152 : }
9153 :
9154 : bool
9155 0 : nsCSSFrameConstructor::ShouldHaveFirstLineStyle(nsIContent* aContent,
9156 : nsStyleContext* aStyleContext)
9157 : {
9158 : bool hasFirstLine =
9159 : nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext,
9160 : nsCSSPseudoElements::ePseudo_firstLine,
9161 0 : mPresShell->GetPresContext());
9162 0 : if (hasFirstLine) {
9163 : // But disable for fieldsets
9164 : PRInt32 namespaceID;
9165 : nsIAtom* tag = mDocument->BindingManager()->ResolveTag(aContent,
9166 0 : &namespaceID);
9167 : // This check must match the one in FindHTMLData.
9168 : hasFirstLine = tag != nsGkAtoms::fieldset ||
9169 0 : namespaceID != kNameSpaceID_XHTML;
9170 : }
9171 :
9172 0 : return hasFirstLine;
9173 : }
9174 :
9175 : void
9176 0 : nsCSSFrameConstructor::ShouldHaveSpecialBlockStyle(nsIContent* aContent,
9177 : nsStyleContext* aStyleContext,
9178 : bool* aHaveFirstLetterStyle,
9179 : bool* aHaveFirstLineStyle)
9180 : {
9181 : *aHaveFirstLetterStyle =
9182 0 : ShouldHaveFirstLetterStyle(aContent, aStyleContext);
9183 : *aHaveFirstLineStyle =
9184 0 : ShouldHaveFirstLineStyle(aContent, aStyleContext);
9185 0 : }
9186 :
9187 : /* static */
9188 : const nsCSSFrameConstructor::PseudoParentData
9189 : nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
9190 : { // Cell
9191 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9192 : FCDATA_USE_CHILD_ITEMS |
9193 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow),
9194 : &nsCSSFrameConstructor::ConstructTableCell),
9195 : &nsCSSAnonBoxes::tableCell
9196 : },
9197 : { // Row
9198 : FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9199 : FCDATA_USE_CHILD_ITEMS |
9200 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup),
9201 : &nsCSSFrameConstructor::ConstructTableRow),
9202 : &nsCSSAnonBoxes::tableRow
9203 : },
9204 : { // Row group
9205 : FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9206 : FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_USE_CHILD_ITEMS |
9207 : FCDATA_SKIP_ABSPOS_PUSH |
9208 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
9209 : NS_NewTableRowGroupFrame),
9210 : &nsCSSAnonBoxes::tableRowGroup
9211 : },
9212 : { // Column group
9213 : FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET |
9214 : FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_USE_CHILD_ITEMS |
9215 : FCDATA_SKIP_ABSPOS_PUSH |
9216 : FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
9217 : NS_NewTableColGroupFrame),
9218 : &nsCSSAnonBoxes::tableColGroup
9219 : },
9220 : { // Table
9221 : FULL_CTOR_FCDATA(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS,
9222 : &nsCSSFrameConstructor::ConstructTable),
9223 : &nsCSSAnonBoxes::table
9224 : }
9225 : };
9226 :
9227 : /*
9228 : * This function works as follows: we walk through the child list (aItems) and
9229 : * find items that cannot have aParentFrame as their parent. We wrap
9230 : * continuous runs of such items into a FrameConstructionItem for a frame that
9231 : * gets them closer to their desired parents. For example, a run of non-row
9232 : * children of a row-group will get wrapped in a row. When we later construct
9233 : * the frame for this wrapper (in this case for the row), it'll be the correct
9234 : * parent for the cells in the set of items we wrapped or we'll wrap cells
9235 : * around everything else. At the end of this method, aItems is guaranteed to
9236 : * contain only items for frames that can be direct kids of aParentFrame.
9237 : */
9238 : nsresult
9239 0 : nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState& aState,
9240 : FrameConstructionItemList& aItems,
9241 : nsIFrame* aParentFrame)
9242 : {
9243 0 : ParentType ourParentType = GetParentType(aParentFrame);
9244 0 : if (aItems.AllWantParentType(ourParentType)) {
9245 : // Nothing to do here
9246 0 : return NS_OK;
9247 : }
9248 :
9249 0 : FCItemIterator iter(aItems);
9250 0 : do {
9251 0 : if (iter.SkipItemsWantingParentType(ourParentType)) {
9252 : // Nothing else to do here; we're finished
9253 0 : return NS_OK;
9254 : }
9255 :
9256 : // Now we're pointing to the first child that wants a different parent
9257 : // type.
9258 :
9259 : // Now try to figure out what kids we can group together. We can generally
9260 : // group everything that has a different desired parent type from us. Two
9261 : // exceptions to this:
9262 : // 1) If our parent type is table, we can't group columns with anything
9263 : // else other than whitespace.
9264 : // 2) Whitespace that lies between two things we can group which both want
9265 : // a non-block parent should be dropped, even if we can't group them
9266 : // with each other and even if the whitespace wants a parent of
9267 : // ourParentType. Ends of the list count as things that don't want a
9268 : // block parent (so that for example we'll drop a whitespace-only list).
9269 :
9270 0 : FCItemIterator endIter(iter); /* iterator to find the end of the group */
9271 0 : ParentType groupingParentType = endIter.item().DesiredParentType();
9272 0 : if (aItems.AllWantParentType(groupingParentType) &&
9273 : groupingParentType != eTypeBlock) {
9274 : // Just group them all and be done with it. We need the check for
9275 : // eTypeBlock here to catch the "all the items are whitespace" case
9276 : // described above.
9277 0 : endIter.SetToEnd();
9278 : } else {
9279 : // Locate the end of the group.
9280 :
9281 : // Keep track of the type the previous item wanted, in case we have to
9282 : // deal with whitespace. Start it off with ourParentType, since that's
9283 : // the last thing |iter| would have skipped over.
9284 0 : ParentType prevParentType = ourParentType;
9285 0 : do {
9286 : /* Walk an iterator past any whitespace that we might be able to drop from the list */
9287 0 : FCItemIterator spaceEndIter(endIter);
9288 0 : if (prevParentType != eTypeBlock &&
9289 0 : !aParentFrame->IsGeneratedContentFrame() &&
9290 0 : spaceEndIter.item().IsWhitespace(aState)) {
9291 0 : bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
9292 :
9293 : // We drop the whitespace if these are not trailing spaces and the next item
9294 : // does not want a block parent (see case 2 above)
9295 : // if these are trailing spaces and aParentFrame is a tabular container
9296 : // according to rule 1.3 of CSS 2.1 Sec 17.2.1. (Being a tabular container
9297 : // pretty much means ourParentType != eTypeBlock besides the eTypeColGroup case,
9298 : // which won't reach here.)
9299 0 : if ((trailingSpaces && ourParentType != eTypeBlock) ||
9300 0 : (!trailingSpaces && spaceEndIter.item().DesiredParentType() !=
9301 : eTypeBlock)) {
9302 0 : bool updateStart = (iter == endIter);
9303 0 : endIter.DeleteItemsTo(spaceEndIter);
9304 0 : NS_ASSERTION(trailingSpaces == endIter.IsDone(), "These should match");
9305 :
9306 0 : if (updateStart) {
9307 0 : iter = endIter;
9308 : }
9309 :
9310 0 : if (trailingSpaces) {
9311 0 : break; /* Found group end */
9312 : }
9313 :
9314 0 : if (updateStart) {
9315 : // Update groupingParentType, since it might have been eTypeBlock
9316 : // just because of the whitespace.
9317 0 : groupingParentType = iter.item().DesiredParentType();
9318 : }
9319 : }
9320 : }
9321 :
9322 : // Now endIter points to a non-whitespace item or a non-droppable
9323 : // whitespace item. In the latter case, if this is the end of the group
9324 : // we'll traverse this whitespace again. But it'll all just be quick
9325 : // DesiredParentType() checks which will match ourParentType (that's
9326 : // what it means that this is the group end), so it's OK.
9327 0 : prevParentType = endIter.item().DesiredParentType();
9328 0 : if (prevParentType == ourParentType) {
9329 : // End the group at endIter.
9330 0 : break;
9331 : }
9332 :
9333 0 : if (ourParentType == eTypeTable &&
9334 : (prevParentType == eTypeColGroup) !=
9335 : (groupingParentType == eTypeColGroup)) {
9336 : // Either we started with columns and now found something else, or vice
9337 : // versa. In any case, end the grouping.
9338 0 : break;
9339 : }
9340 :
9341 : // Include the whitespace we didn't drop (if any) in the group, since
9342 : // this is not the end of the group. Note that this doesn't change
9343 : // prevParentType, since if we didn't drop the whitespace then we ended
9344 : // at something that wants a block parent.
9345 0 : endIter = spaceEndIter;
9346 :
9347 0 : endIter.Next();
9348 0 : } while (!endIter.IsDone());
9349 : }
9350 :
9351 0 : if (iter == endIter) {
9352 : // Nothing to wrap here; just skipped some whitespace
9353 0 : continue;
9354 : }
9355 :
9356 : // Now group together all the items between iter and endIter. The right
9357 : // parent type to use depends on ourParentType.
9358 : ParentType wrapperType;
9359 0 : switch (ourParentType) {
9360 : case eTypeBlock:
9361 0 : wrapperType = eTypeTable;
9362 0 : break;
9363 : case eTypeRow:
9364 : // The parent type for a cell is eTypeBlock, since that's what a cell
9365 : // looks like to its kids.
9366 0 : wrapperType = eTypeBlock;
9367 0 : break;
9368 : case eTypeRowGroup:
9369 0 : wrapperType = eTypeRow;
9370 0 : break;
9371 : case eTypeTable:
9372 : // Either colgroup or rowgroup, depending on what we're grouping.
9373 : wrapperType = groupingParentType == eTypeColGroup ?
9374 0 : eTypeColGroup : eTypeRowGroup;
9375 0 : break;
9376 : default:
9377 0 : NS_NOTREACHED("Colgroups should be suppresing non-col child items");
9378 0 : break;
9379 : }
9380 :
9381 0 : const PseudoParentData& pseudoData = sPseudoParentData[wrapperType];
9382 0 : nsIAtom* pseudoType = *pseudoData.mPseudoType;
9383 0 : nsStyleContext* parentStyle = aParentFrame->GetStyleContext();
9384 0 : nsIContent* parentContent = aParentFrame->GetContent();
9385 :
9386 0 : if (pseudoType == nsCSSAnonBoxes::table &&
9387 0 : parentStyle->GetStyleDisplay()->mDisplay == NS_STYLE_DISPLAY_INLINE) {
9388 0 : pseudoType = nsCSSAnonBoxes::inlineTable;
9389 : }
9390 :
9391 : nsRefPtr<nsStyleContext> wrapperStyle =
9392 0 : mPresShell->StyleSet()->ResolveAnonymousBoxStyle(pseudoType, parentStyle);
9393 : FrameConstructionItem* newItem =
9394 : new FrameConstructionItem(&pseudoData.mFCData,
9395 : // Use the content of our parent frame
9396 : parentContent,
9397 : // Lie about the tag; it doesn't matter anyway
9398 : pseudoType,
9399 : // The namespace does matter, however; it needs
9400 : // to match that of our first child item to
9401 : // match the old behavior
9402 0 : iter.item().mNameSpaceID,
9403 : // no pending binding
9404 : nsnull,
9405 : wrapperStyle.forget(),
9406 0 : true);
9407 :
9408 : // Here we're cheating a tad... technically, table-internal items should be
9409 : // inline if aParentFrame is inline, but they'll get wrapped in an
9410 : // inline-table in the end, so it'll all work out. In any case, arguably
9411 : // we don't need to maintain this state at this point... but it's better
9412 : // to, I guess.
9413 : newItem->mIsAllInline = newItem->mHasInlineEnds =
9414 0 : newItem->mStyleContext->GetStyleDisplay()->IsInlineOutside();
9415 :
9416 : // Table pseudo frames always induce line boundaries around their
9417 : // contents.
9418 0 : newItem->mChildItems.SetLineBoundaryAtStart(true);
9419 0 : newItem->mChildItems.SetLineBoundaryAtEnd(true);
9420 : // The parent of the items in aItems is also the parent of the items
9421 : // in mChildItems
9422 : newItem->mChildItems.SetParentHasNoXBLChildren(
9423 0 : aItems.ParentHasNoXBLChildren());
9424 :
9425 : // Eat up all items between |iter| and |endIter| and put them in our wrapper
9426 : // Advances |iter| to point to |endIter|.
9427 0 : iter.AppendItemsToList(endIter, newItem->mChildItems);
9428 :
9429 0 : iter.InsertItem(newItem);
9430 :
9431 : // Now |iter| points to the item that was the first one we didn't wrap;
9432 : // loop and see whether we need to skip it or wrap it in something
9433 : // different.
9434 0 : } while (!iter.IsDone());
9435 :
9436 0 : return NS_OK;
9437 : }
9438 :
9439 : inline nsresult
9440 0 : nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aState,
9441 : FrameConstructionItemList& aItems,
9442 : nsIFrame* aParentFrame,
9443 : nsFrameItems& aFrameItems)
9444 : {
9445 0 : nsresult rv = CreateNeededTablePseudos(aState, aItems, aParentFrame);
9446 0 : NS_ENSURE_SUCCESS(rv, rv);
9447 :
9448 : #ifdef DEBUG
9449 0 : for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
9450 0 : NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame),
9451 : "Needed pseudos didn't get created; expect bad things");
9452 : }
9453 : #endif
9454 :
9455 0 : for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
9456 0 : rv = ConstructFramesFromItem(aState, iter, aParentFrame, aFrameItems);
9457 0 : NS_ENSURE_SUCCESS(rv, rv);
9458 : }
9459 :
9460 0 : NS_ASSERTION(!aState.mHavePendingPopupgroup,
9461 : "Should have proccessed it by now");
9462 :
9463 0 : return NS_OK;
9464 : }
9465 :
9466 : nsresult
9467 0 : nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
9468 : nsIContent* aContent,
9469 : nsStyleContext* aStyleContext,
9470 : nsIFrame* aFrame,
9471 : const bool aCanHaveGeneratedContent,
9472 : nsFrameItems& aFrameItems,
9473 : const bool aAllowBlockStyles,
9474 : PendingBinding* aPendingBinding,
9475 : nsIFrame* aPossiblyLeafFrame)
9476 : {
9477 0 : NS_PRECONDITION(aFrame, "Must have parent frame here");
9478 0 : NS_PRECONDITION(aFrame->GetContentInsertionFrame() == aFrame,
9479 : "Parent frame in ProcessChildren should be its own "
9480 : "content insertion frame");
9481 :
9482 0 : if (!aPossiblyLeafFrame) {
9483 0 : aPossiblyLeafFrame = aFrame;
9484 : }
9485 :
9486 : // XXXbz ideally, this would do all the pushing of various
9487 : // containing blocks as needed, so callers don't have to do it...
9488 :
9489 0 : bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
9490 0 : if (aAllowBlockStyles) {
9491 : ShouldHaveSpecialBlockStyle(aContent, aStyleContext, &haveFirstLetterStyle,
9492 0 : &haveFirstLineStyle);
9493 : }
9494 :
9495 : // The logic here needs to match the logic in GetFloatContainingBlock()
9496 0 : nsFrameConstructorSaveState floatSaveState;
9497 0 : if (aFrame->IsFrameOfType(nsIFrame::eMathML) ||
9498 0 : aFrame->IsBoxFrame()) {
9499 0 : aState.PushFloatContainingBlock(nsnull, floatSaveState);
9500 0 : } else if (aFrame->IsFloatContainingBlock()) {
9501 0 : aState.PushFloatContainingBlock(aFrame, floatSaveState);
9502 : }
9503 :
9504 : nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
9505 0 : aPendingBinding);
9506 :
9507 0 : FrameConstructionItemList itemsToConstruct;
9508 0 : nsresult rv = NS_OK;
9509 :
9510 : // If we have first-letter or first-line style then frames can get
9511 : // moved around so don't set these flags.
9512 0 : if (aAllowBlockStyles && !haveFirstLetterStyle && !haveFirstLineStyle) {
9513 0 : itemsToConstruct.SetLineBoundaryAtStart(true);
9514 0 : itemsToConstruct.SetLineBoundaryAtEnd(true);
9515 : }
9516 :
9517 : // Create any anonymous frames we need here. This must happen before the
9518 : // non-anonymous children are processed to ensure that popups are never
9519 : // constructed before the popupset.
9520 0 : nsAutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
9521 0 : GetAnonymousContent(aContent, aPossiblyLeafFrame, anonymousItems);
9522 0 : for (PRUint32 i = 0; i < anonymousItems.Length(); ++i) {
9523 0 : nsIContent* content = anonymousItems[i].mContent;
9524 : #ifdef DEBUG
9525 0 : nsIAnonymousContentCreator* creator = do_QueryFrame(aFrame);
9526 0 : NS_ASSERTION(!creator || !creator->CreateFrameFor(content),
9527 : "If you need to use CreateFrameFor, you need to call "
9528 : "CreateAnonymousFrames manually and not follow the standard "
9529 : "ProcessChildren() codepath for this frame");
9530 : #endif
9531 : // Assert some things about this content
9532 0 : NS_ABORT_IF_FALSE(!(content->GetFlags() &
9533 : (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME)),
9534 : "Should not be marked as needing frames");
9535 0 : NS_ABORT_IF_FALSE(!content->IsElement() ||
9536 : !(content->GetFlags() & ELEMENT_ALL_RESTYLE_FLAGS),
9537 : "Should have no pending restyle flags");
9538 0 : NS_ABORT_IF_FALSE(!content->GetPrimaryFrame(),
9539 : "Should have no existing frame");
9540 0 : NS_ABORT_IF_FALSE(!content->IsNodeOfType(nsINode::eCOMMENT) &&
9541 : !content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION),
9542 : "Why is someone creating garbage anonymous content");
9543 :
9544 0 : nsRefPtr<nsStyleContext> styleContext;
9545 0 : if (anonymousItems[i].mStyleContext) {
9546 0 : styleContext = anonymousItems[i].mStyleContext.forget();
9547 : } else {
9548 0 : styleContext = ResolveStyleContext(aFrame, content, &aState);
9549 : }
9550 :
9551 : AddFrameConstructionItemsInternal(aState, content, aFrame,
9552 : content->Tag(), content->GetNameSpaceID(),
9553 : true, styleContext,
9554 : ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK,
9555 0 : itemsToConstruct);
9556 : }
9557 :
9558 0 : if (!aPossiblyLeafFrame->IsLeaf()) {
9559 : // :before/:after content should have the same style context parent
9560 : // as normal kids.
9561 : // Note that we don't use this style context for looking up things like
9562 : // special block styles because in some cases involving table pseudo-frames
9563 : // it has nothing to do with the parent frame's desired behavior.
9564 : nsStyleContext* styleContext;
9565 :
9566 0 : if (aCanHaveGeneratedContent) {
9567 : styleContext =
9568 0 : nsFrame::CorrectStyleParentFrame(aFrame, nsnull)->GetStyleContext();
9569 : // Probe for generated content before
9570 : CreateGeneratedContentItem(aState, aFrame, aContent, styleContext,
9571 : nsCSSPseudoElements::ePseudo_before,
9572 0 : itemsToConstruct);
9573 : }
9574 :
9575 0 : ChildIterator iter, last;
9576 0 : for (ChildIterator::Init(aContent, &iter, &last);
9577 : iter != last;
9578 : ++iter) {
9579 0 : nsIContent* child = *iter;
9580 : // Frame construction item construction should not post
9581 : // restyles, so removing restyle flags here is safe.
9582 0 : if (child->IsElement()) {
9583 0 : child->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS);
9584 : }
9585 0 : AddFrameConstructionItems(aState, child, iter.XBLInvolved(), aFrame,
9586 0 : itemsToConstruct);
9587 : }
9588 0 : itemsToConstruct.SetParentHasNoXBLChildren(!iter.XBLInvolved());
9589 :
9590 0 : if (aCanHaveGeneratedContent) {
9591 : // Probe for generated content after
9592 : CreateGeneratedContentItem(aState, aFrame, aContent, styleContext,
9593 : nsCSSPseudoElements::ePseudo_after,
9594 0 : itemsToConstruct);
9595 : }
9596 : } else {
9597 0 : ClearLazyBits(aContent->GetFirstChild(), nsnull);
9598 : }
9599 :
9600 : rv = ConstructFramesFromItemList(aState, itemsToConstruct, aFrame,
9601 0 : aFrameItems);
9602 0 : NS_ENSURE_SUCCESS(rv, rv);
9603 :
9604 0 : NS_ASSERTION(!aAllowBlockStyles || !aFrame->IsBoxFrame(),
9605 : "can't be both block and box");
9606 :
9607 0 : if (haveFirstLetterStyle) {
9608 0 : rv = WrapFramesInFirstLetterFrame(aContent, aFrame, aFrameItems);
9609 : }
9610 0 : if (haveFirstLineStyle) {
9611 : rv = WrapFramesInFirstLineFrame(aState, aContent, aFrame, nsnull,
9612 0 : aFrameItems);
9613 : }
9614 :
9615 : // We might end up with first-line frames that change
9616 : // AnyKidsNeedBlockParent() without changing itemsToConstruct, but that
9617 : // should never happen for cases whan aFrame->IsBoxFrame().
9618 0 : NS_ASSERTION(!haveFirstLineStyle || !aFrame->IsBoxFrame(),
9619 : "Shouldn't have first-line style if we're a box");
9620 0 : NS_ASSERTION(!aFrame->IsBoxFrame() ||
9621 : itemsToConstruct.AnyItemsNeedBlockParent() ==
9622 : (AnyKidsNeedBlockParent(aFrameItems.FirstChild()) != nsnull),
9623 : "Something went awry in our block parent calculations");
9624 :
9625 0 : if (aFrame->IsBoxFrame() && itemsToConstruct.AnyItemsNeedBlockParent()) {
9626 : // XXXbz we could do this on the FrameConstructionItemList level,
9627 : // no? And if we cared we could look through the item list
9628 : // instead of groveling through the framelist here..
9629 0 : nsIContent *badKid = AnyKidsNeedBlockParent(aFrameItems.FirstChild());
9630 0 : nsDependentAtomString parentTag(aContent->Tag()), kidTag(badKid->Tag());
9631 0 : const PRUnichar* params[] = { parentTag.get(), kidTag.get() };
9632 0 : nsStyleContext *frameStyleContext = aFrame->GetStyleContext();
9633 0 : const nsStyleDisplay *display = frameStyleContext->GetStyleDisplay();
9634 : const char *message =
9635 : (display->mDisplay == NS_STYLE_DISPLAY_INLINE_BOX)
9636 0 : ? "NeededToWrapXULInlineBox" : "NeededToWrapXUL";
9637 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
9638 : "FrameConstructor", mDocument,
9639 : nsContentUtils::eXUL_PROPERTIES,
9640 : message,
9641 0 : params, ArrayLength(params));
9642 :
9643 : nsRefPtr<nsStyleContext> blockSC = mPresShell->StyleSet()->
9644 : ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozXULAnonymousBlock,
9645 0 : frameStyleContext);
9646 0 : nsIFrame *blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
9647 : // We might, in theory, want to set NS_BLOCK_FLOAT_MGR and
9648 : // NS_BLOCK_MARGIN_ROOT, but I think it's a bad idea given that
9649 : // a real block placed here wouldn't get those set on it.
9650 :
9651 : InitAndRestoreFrame(aState, aContent, aFrame, nsnull,
9652 0 : blockFrame, false);
9653 :
9654 0 : NS_ASSERTION(!blockFrame->HasView(), "need to do view reparenting");
9655 0 : ReparentFrames(this, blockFrame, aFrameItems);
9656 :
9657 0 : blockFrame->SetInitialChildList(kPrincipalList, aFrameItems);
9658 0 : NS_ASSERTION(aFrameItems.IsEmpty(), "How did that happen?");
9659 0 : aFrameItems.Clear();
9660 0 : aFrameItems.AddChild(blockFrame);
9661 :
9662 0 : aFrame->AddStateBits(NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK);
9663 : }
9664 :
9665 0 : return rv;
9666 : }
9667 :
9668 : //----------------------------------------------------------------------
9669 :
9670 : // Support for :first-line style
9671 :
9672 : // Special routine to handle placing a list of frames into a block
9673 : // frame that has first-line style. The routine ensures that the first
9674 : // collection of inline frames end up in a first-line frame.
9675 : // NOTE: aState may have containing block information related to a
9676 : // different part of the frame tree than where the first line occurs.
9677 : // In particular aState may be set up for where ContentInserted or
9678 : // ContentAppended is inserting content, which may be some
9679 : // non-first-in-flow continuation of the block to which the first-line
9680 : // belongs. So this function needs to be careful about how it uses
9681 : // aState.
9682 : nsresult
9683 0 : nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
9684 : nsFrameConstructorState& aState,
9685 : nsIContent* aBlockContent,
9686 : nsIFrame* aBlockFrame,
9687 : nsIFrame* aLineFrame,
9688 : nsFrameItems& aFrameItems)
9689 : {
9690 0 : nsresult rv = NS_OK;
9691 :
9692 : // Find the part of aFrameItems that we want to put in the first-line
9693 0 : nsFrameList::FrameLinkEnumerator link(aFrameItems);
9694 0 : while (!link.AtEnd() && IsInlineOutside(link.NextFrame())) {
9695 0 : link.Next();
9696 : }
9697 :
9698 0 : nsFrameList firstLineChildren = aFrameItems.ExtractHead(link);
9699 :
9700 0 : if (firstLineChildren.IsEmpty()) {
9701 : // Nothing is supposed to go into the first-line; nothing to do
9702 0 : return NS_OK;
9703 : }
9704 :
9705 0 : if (!aLineFrame) {
9706 : // Create line frame
9707 : nsStyleContext* parentStyle =
9708 : nsFrame::CorrectStyleParentFrame(aBlockFrame,
9709 : nsCSSPseudoElements::firstLine)->
9710 0 : GetStyleContext();
9711 : nsRefPtr<nsStyleContext> firstLineStyle = GetFirstLineStyle(aBlockContent,
9712 0 : parentStyle);
9713 :
9714 0 : aLineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle);
9715 :
9716 0 : if (aLineFrame) {
9717 : // Initialize the line frame
9718 : rv = InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, nsnull,
9719 0 : aLineFrame);
9720 :
9721 : // The lineFrame will be the block's first child; the rest of the
9722 : // frame list (after lastInlineFrame) will be the second and
9723 : // subsequent children; insert lineFrame into aFrameItems.
9724 0 : aFrameItems.InsertFrame(nsnull, nsnull, aLineFrame);
9725 :
9726 0 : NS_ASSERTION(aLineFrame->GetStyleContext() == firstLineStyle,
9727 : "Bogus style context on line frame");
9728 : }
9729 : }
9730 :
9731 0 : if (aLineFrame) {
9732 : // Give the inline frames to the lineFrame <b>after</b> reparenting them
9733 0 : ReparentFrames(this, aLineFrame, firstLineChildren);
9734 0 : if (aLineFrame->PrincipalChildList().IsEmpty() &&
9735 0 : (aLineFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
9736 0 : aLineFrame->SetInitialChildList(kPrincipalList, firstLineChildren);
9737 : } else {
9738 0 : AppendFrames(aLineFrame, kPrincipalList, firstLineChildren);
9739 : }
9740 : }
9741 : else {
9742 0 : rv = NS_ERROR_OUT_OF_MEMORY;
9743 : }
9744 :
9745 0 : return rv;
9746 : }
9747 :
9748 : // Special routine to handle appending a new frame to a block frame's
9749 : // child list. Takes care of placing the new frame into the right
9750 : // place when first-line style is present.
9751 : nsresult
9752 0 : nsCSSFrameConstructor::AppendFirstLineFrames(
9753 : nsFrameConstructorState& aState,
9754 : nsIContent* aBlockContent,
9755 : nsIFrame* aBlockFrame,
9756 : nsFrameItems& aFrameItems)
9757 : {
9758 : // It's possible that aBlockFrame needs to have a first-line frame
9759 : // created because it doesn't currently have any children.
9760 0 : const nsFrameList& blockKids = aBlockFrame->PrincipalChildList();
9761 0 : if (blockKids.IsEmpty()) {
9762 : return WrapFramesInFirstLineFrame(aState, aBlockContent,
9763 0 : aBlockFrame, nsnull, aFrameItems);
9764 : }
9765 :
9766 : // Examine the last block child - if it's a first-line frame then
9767 : // appended frames need special treatment.
9768 0 : nsIFrame* lastBlockKid = blockKids.LastChild();
9769 0 : if (lastBlockKid->GetType() != nsGkAtoms::lineFrame) {
9770 : // No first-line frame at the end of the list, therefore there is
9771 : // an intervening block between any first-line frame the frames
9772 : // we are appending. Therefore, we don't need any special
9773 : // treatment of the appended frames.
9774 0 : return NS_OK;
9775 : }
9776 :
9777 : return WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame,
9778 0 : lastBlockKid, aFrameItems);
9779 : }
9780 :
9781 : // Special routine to handle inserting a new frame into a block
9782 : // frame's child list. Takes care of placing the new frame into the
9783 : // right place when first-line style is present.
9784 : nsresult
9785 0 : nsCSSFrameConstructor::InsertFirstLineFrames(
9786 : nsFrameConstructorState& aState,
9787 : nsIContent* aContent,
9788 : nsIFrame* aBlockFrame,
9789 : nsIFrame** aParentFrame,
9790 : nsIFrame* aPrevSibling,
9791 : nsFrameItems& aFrameItems)
9792 : {
9793 0 : nsresult rv = NS_OK;
9794 : // XXXbz If you make this method actually do something, check to
9795 : // make sure that the caller is passing what you expect. In
9796 : // particular, which content is aContent? And audit the rest of
9797 : // this code too; it makes bogus assumptions and may not build.
9798 : #if 0
9799 : nsIFrame* parentFrame = *aParentFrame;
9800 : nsIFrame* newFrame = aFrameItems.childList;
9801 : bool isInline = IsInlineOutside(newFrame);
9802 :
9803 : if (!aPrevSibling) {
9804 : // Insertion will become the first frame. Two cases: we either
9805 : // already have a first-line frame or we don't.
9806 : nsIFrame* firstBlockKid = aBlockFrame->GetFirstPrincipalChild();
9807 : if (firstBlockKid->GetType() == nsGkAtoms::lineFrame) {
9808 : // We already have a first-line frame
9809 : nsIFrame* lineFrame = firstBlockKid;
9810 :
9811 : if (isInline) {
9812 : // Easy case: the new inline frame will go into the lineFrame.
9813 : ReparentFrame(this, lineFrame, newFrame);
9814 : InsertFrames(lineFrame, kPrincipalList, nsnull, newFrame);
9815 :
9816 : // Since the frame is going into the lineFrame, don't let it
9817 : // go into the block too.
9818 : aFrameItems.childList = nsnull;
9819 : aFrameItems.lastChild = nsnull;
9820 : }
9821 : else {
9822 : // Harder case: We are about to insert a block level element
9823 : // before the first-line frame.
9824 : // XXX need a method to steal away frames from the line-frame
9825 : }
9826 : }
9827 : else {
9828 : // We do not have a first-line frame
9829 : if (isInline) {
9830 : // We now need a first-line frame to contain the inline frame.
9831 : nsIFrame* lineFrame = NS_NewFirstLineFrame(firstLineStyle);
9832 : if (!lineFrame) {
9833 : rv = NS_ERROR_OUT_OF_MEMORY;
9834 : }
9835 :
9836 : if (NS_SUCCEEDED(rv)) {
9837 : // Lookup first-line style context
9838 : nsStyleContext* parentStyle =
9839 : nsFrame::CorrectStyleParentFrame(aBlockFrame,
9840 : nsCSSPseudoElements::firstLine)->
9841 : GetStyleContext();
9842 : nsRefPtr<nsStyleContext> firstLineStyle =
9843 : GetFirstLineStyle(aContent, parentStyle);
9844 :
9845 : // Initialize the line frame
9846 : rv = InitAndRestoreFrame(aState, aContent, aBlockFrame,
9847 : nsnull, lineFrame);
9848 :
9849 : // Make sure the caller inserts the lineFrame into the
9850 : // blocks list of children.
9851 : aFrameItems.childList = lineFrame;
9852 : aFrameItems.lastChild = lineFrame;
9853 :
9854 : // Give the inline frames to the lineFrame <b>after</b>
9855 : // reparenting them
9856 : NS_ASSERTION(lineFrame->GetStyleContext() == firstLineStyle,
9857 : "Bogus style context on line frame");
9858 : ReparentFrame(aPresContext, lineFrame, newFrame);
9859 : lineFrame->SetInitialChildList(kPrincipalList, newFrame);
9860 : }
9861 : }
9862 : else {
9863 : // Easy case: the regular insertion logic can insert the new
9864 : // frame because it's a block frame.
9865 : }
9866 : }
9867 : }
9868 : else {
9869 : // Insertion will not be the first frame.
9870 : nsIFrame* prevSiblingParent = aPrevSibling->GetParent();
9871 : if (prevSiblingParent == aBlockFrame) {
9872 : // Easy case: The prev-siblings parent is the block
9873 : // frame. Therefore the prev-sibling is not currently in a
9874 : // line-frame. Therefore the new frame which is going after it,
9875 : // regardless of type, is not going into a line-frame.
9876 : }
9877 : else {
9878 : // If the prevSiblingParent is not the block-frame then it must
9879 : // be a line-frame (if it were a letter-frame, that logic would
9880 : // already have adjusted the prev-sibling to be the
9881 : // letter-frame).
9882 : if (isInline) {
9883 : // Easy case: the insertion can go where the caller thinks it
9884 : // should go (which is into prevSiblingParent).
9885 : }
9886 : else {
9887 : // Block elements don't end up in line-frames, therefore
9888 : // change the insertion point to aBlockFrame. However, there
9889 : // might be more inline elements following aPrevSibling that
9890 : // need to be pulled out of the line-frame and become children
9891 : // of the block.
9892 : nsIFrame* nextSibling = aPrevSibling->GetNextSibling();
9893 : nsIFrame* nextLineFrame = prevSiblingParent->GetNextInFlow();
9894 : if (nextSibling || nextLineFrame) {
9895 : // Oy. We have work to do. Create a list of the new frames
9896 : // that are going into the block by stripping them away from
9897 : // the line-frame(s).
9898 : if (nextSibling) {
9899 : nsLineFrame* lineFrame = (nsLineFrame*) prevSiblingParent;
9900 : nsFrameList tail = lineFrame->StealFramesAfter(aPrevSibling);
9901 : // XXX do something with 'tail'
9902 : }
9903 :
9904 : nsLineFrame* nextLineFrame = (nsLineFrame*) lineFrame;
9905 : for (;;) {
9906 : nextLineFrame = nextLineFrame->GetNextInFlow();
9907 : if (!nextLineFrame) {
9908 : break;
9909 : }
9910 : nsIFrame* kids = nextLineFrame->GetFirstPrincipalChild();
9911 : }
9912 : }
9913 : else {
9914 : // We got lucky: aPrevSibling was the last inline frame in
9915 : // the line-frame.
9916 : ReparentFrame(this, aBlockFrame, newFrame);
9917 : InsertFrames(aBlockFrame, kPrincipalList,
9918 : prevSiblingParent, newFrame);
9919 : aFrameItems.childList = nsnull;
9920 : aFrameItems.lastChild = nsnull;
9921 : }
9922 : }
9923 : }
9924 : }
9925 :
9926 : #endif
9927 0 : return rv;
9928 : }
9929 :
9930 : //----------------------------------------------------------------------
9931 :
9932 : // First-letter support
9933 :
9934 : // Determine how many characters in the text fragment apply to the
9935 : // first letter
9936 : static PRInt32
9937 0 : FirstLetterCount(const nsTextFragment* aFragment)
9938 : {
9939 0 : PRInt32 count = 0;
9940 0 : PRInt32 firstLetterLength = 0;
9941 :
9942 0 : PRInt32 i, n = aFragment->GetLength();
9943 0 : for (i = 0; i < n; i++) {
9944 0 : PRUnichar ch = aFragment->CharAt(i);
9945 0 : if (XP_IS_SPACE(ch)) {
9946 0 : if (firstLetterLength) {
9947 0 : break;
9948 : }
9949 0 : count++;
9950 0 : continue;
9951 : }
9952 : // XXX I18n
9953 0 : if ((ch == '\'') || (ch == '\"')) {
9954 0 : if (firstLetterLength) {
9955 0 : break;
9956 : }
9957 : // keep looping
9958 0 : firstLetterLength = 1;
9959 : }
9960 : else {
9961 0 : count++;
9962 0 : break;
9963 : }
9964 : }
9965 :
9966 0 : return count;
9967 : }
9968 :
9969 : static bool
9970 0 : NeedFirstLetterContinuation(nsIContent* aContent)
9971 : {
9972 0 : NS_PRECONDITION(aContent, "null ptr");
9973 :
9974 0 : bool result = false;
9975 0 : if (aContent) {
9976 0 : const nsTextFragment* frag = aContent->GetText();
9977 0 : if (frag) {
9978 0 : PRInt32 flc = FirstLetterCount(frag);
9979 0 : PRInt32 tl = frag->GetLength();
9980 0 : if (flc < tl) {
9981 0 : result = true;
9982 : }
9983 : }
9984 : }
9985 0 : return result;
9986 : }
9987 :
9988 0 : static bool IsFirstLetterContent(nsIContent* aContent)
9989 : {
9990 0 : return aContent->TextLength() &&
9991 0 : !aContent->TextIsOnlyWhitespace();
9992 : }
9993 :
9994 : /**
9995 : * Create a letter frame, only make it a floating frame.
9996 : */
9997 : void
9998 0 : nsCSSFrameConstructor::CreateFloatingLetterFrame(
9999 : nsFrameConstructorState& aState,
10000 : nsIFrame* aBlockFrame,
10001 : nsIContent* aTextContent,
10002 : nsIFrame* aTextFrame,
10003 : nsIContent* aBlockContent,
10004 : nsIFrame* aParentFrame,
10005 : nsStyleContext* aStyleContext,
10006 : nsFrameItems& aResult)
10007 : {
10008 : // Create the first-letter-frame
10009 : nsresult rv;
10010 : nsIFrame* letterFrame;
10011 0 : nsStyleSet *styleSet = mPresShell->StyleSet();
10012 :
10013 0 : letterFrame = NS_NewFirstLetterFrame(mPresShell, aStyleContext);
10014 : // We don't want to use a text content for a non-text frame (because we want
10015 : // its primary frame to be a text frame). So use its parent for the
10016 : // first-letter.
10017 0 : nsIContent* letterContent = aTextContent->GetParent();
10018 : nsIFrame* containingBlock = aState.GetGeometricParent(
10019 0 : aStyleContext->GetStyleDisplay(), aParentFrame);
10020 : InitAndRestoreFrame(aState, letterContent, containingBlock, nsnull,
10021 0 : letterFrame);
10022 :
10023 : // Init the text frame to refer to the letter frame. Make sure we
10024 : // get a proper style context for it (the one passed in is for the
10025 : // letter frame and will have the float property set on it; the text
10026 : // frame shouldn't have that set).
10027 0 : nsRefPtr<nsStyleContext> textSC;
10028 0 : textSC = styleSet->ResolveStyleForNonElement(aStyleContext);
10029 0 : aTextFrame->SetStyleContextWithoutNotification(textSC);
10030 0 : InitAndRestoreFrame(aState, aTextContent, letterFrame, nsnull, aTextFrame);
10031 :
10032 : // And then give the text frame to the letter frame
10033 0 : SetInitialSingleChild(letterFrame, aTextFrame);
10034 :
10035 : // See if we will need to continue the text frame (does it contain
10036 : // more than just the first-letter text or not?) If it does, then we
10037 : // create (in advance) a continuation frame for it.
10038 0 : nsIFrame* nextTextFrame = nsnull;
10039 0 : if (NeedFirstLetterContinuation(aTextContent)) {
10040 : // Create continuation
10041 : rv = CreateContinuingFrame(aState.mPresContext, aTextFrame, aParentFrame,
10042 0 : &nextTextFrame);
10043 0 : if (NS_FAILED(rv)) {
10044 0 : letterFrame->Destroy();
10045 : return;
10046 : }
10047 : // Repair the continuations style context
10048 0 : nsStyleContext* parentStyleContext = aStyleContext->GetParent();
10049 0 : if (parentStyleContext) {
10050 0 : nsRefPtr<nsStyleContext> newSC;
10051 0 : newSC = styleSet->ResolveStyleForNonElement(parentStyleContext);
10052 0 : if (newSC) {
10053 0 : nextTextFrame->SetStyleContext(newSC);
10054 : }
10055 : }
10056 : }
10057 :
10058 0 : NS_ASSERTION(aResult.IsEmpty(), "aResult should be an empty nsFrameItems!");
10059 : // Put the new float before any of the floats in the block we're doing
10060 : // first-letter for, that is, before any floats whose parent is
10061 : // containingBlock.
10062 0 : nsFrameList::FrameLinkEnumerator link(aState.mFloatedItems);
10063 0 : while (!link.AtEnd() && link.NextFrame()->GetParent() != containingBlock) {
10064 0 : link.Next();
10065 : }
10066 :
10067 : rv = aState.AddChild(letterFrame, aResult, letterContent, aStyleContext,
10068 : aParentFrame, false, true, false, true,
10069 0 : link.PrevFrame());
10070 :
10071 0 : if (nextTextFrame) {
10072 0 : if (NS_FAILED(rv)) {
10073 0 : nextTextFrame->Destroy();
10074 : } else {
10075 0 : aResult.AddChild(nextTextFrame);
10076 : }
10077 : }
10078 : }
10079 :
10080 : /**
10081 : * Create a new letter frame for aTextFrame. The letter frame will be
10082 : * a child of aParentFrame.
10083 : */
10084 : nsresult
10085 0 : nsCSSFrameConstructor::CreateLetterFrame(nsIFrame* aBlockFrame,
10086 : nsIFrame* aBlockContinuation,
10087 : nsIContent* aTextContent,
10088 : nsIFrame* aParentFrame,
10089 : nsFrameItems& aResult)
10090 : {
10091 0 : NS_PRECONDITION(aTextContent->IsNodeOfType(nsINode::eTEXT),
10092 : "aTextContent isn't text");
10093 0 : NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame),
10094 : "Not a block frame?");
10095 :
10096 : // Get style context for the first-letter-frame
10097 : nsStyleContext* parentStyleContext =
10098 : nsFrame::CorrectStyleParentFrame(aParentFrame,
10099 : nsCSSPseudoElements::firstLetter)->
10100 0 : GetStyleContext();
10101 :
10102 : // Use content from containing block so that we can actually
10103 : // find a matching style rule.
10104 0 : nsIContent* blockContent = aBlockFrame->GetContent();
10105 :
10106 : // Create first-letter style rule
10107 : nsRefPtr<nsStyleContext> sc = GetFirstLetterStyle(blockContent,
10108 0 : parentStyleContext);
10109 0 : if (sc) {
10110 0 : nsRefPtr<nsStyleContext> textSC;
10111 0 : textSC = mPresShell->StyleSet()->ResolveStyleForNonElement(sc);
10112 :
10113 : // Create a new text frame (the original one will be discarded)
10114 : // pass a temporary stylecontext, the correct one will be set
10115 : // later. Start off by unsetting the primary frame for
10116 : // aTextContent, so it's no longer pointing to the to-be-destroyed
10117 : // frame.
10118 : // XXXbz it would be really nice to destroy the old frame _first_,
10119 : // then create the new one, so we could avoid this hack.
10120 0 : aTextContent->SetPrimaryFrame(nsnull);
10121 0 : nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC);
10122 :
10123 0 : NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame),
10124 : "Containing block is confused");
10125 : nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
10126 : GetAbsoluteContainingBlock(aParentFrame),
10127 0 : aBlockContinuation);
10128 :
10129 : // Create the right type of first-letter frame
10130 0 : const nsStyleDisplay* display = sc->GetStyleDisplay();
10131 0 : if (display->IsFloating()) {
10132 : // Make a floating first-letter frame
10133 : CreateFloatingLetterFrame(state, aBlockFrame, aTextContent, textFrame,
10134 0 : blockContent, aParentFrame, sc, aResult);
10135 : }
10136 : else {
10137 : // Make an inflow first-letter frame
10138 0 : nsIFrame* letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
10139 :
10140 0 : if (letterFrame) {
10141 : // Initialize the first-letter-frame. We don't want to use a text
10142 : // content for a non-text frame (because we want its primary frame to
10143 : // be a text frame). So use its parent for the first-letter.
10144 0 : nsIContent* letterContent = aTextContent->GetParent();
10145 0 : letterFrame->Init(letterContent, aParentFrame, nsnull);
10146 :
10147 : InitAndRestoreFrame(state, aTextContent, letterFrame, nsnull,
10148 0 : textFrame);
10149 :
10150 0 : SetInitialSingleChild(letterFrame, textFrame);
10151 0 : aResult.Clear();
10152 0 : aResult.AddChild(letterFrame);
10153 0 : NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
10154 : "should have the first continuation here");
10155 0 : aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
10156 : }
10157 : }
10158 0 : aTextContent->SetPrimaryFrame(textFrame);
10159 : }
10160 :
10161 0 : return NS_OK;
10162 : }
10163 :
10164 : nsresult
10165 0 : nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
10166 : nsIContent* aBlockContent,
10167 : nsIFrame* aBlockFrame,
10168 : nsFrameItems& aBlockFrames)
10169 : {
10170 0 : nsresult rv = NS_OK;
10171 :
10172 0 : aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
10173 :
10174 0 : nsIFrame* parentFrame = nsnull;
10175 0 : nsIFrame* textFrame = nsnull;
10176 0 : nsIFrame* prevFrame = nsnull;
10177 0 : nsFrameItems letterFrames;
10178 0 : bool stopLooking = false;
10179 : rv = WrapFramesInFirstLetterFrame(aBlockFrame, aBlockFrame, aBlockFrame,
10180 : aBlockFrames.FirstChild(),
10181 : &parentFrame, &textFrame, &prevFrame,
10182 0 : letterFrames, &stopLooking);
10183 0 : if (NS_FAILED(rv)) {
10184 0 : return rv;
10185 : }
10186 0 : if (parentFrame) {
10187 0 : if (parentFrame == aBlockFrame) {
10188 : // Take textFrame out of the block's frame list and substitute the
10189 : // letter frame(s) instead.
10190 0 : aBlockFrames.DestroyFrame(textFrame);
10191 0 : aBlockFrames.InsertFrames(nsnull, prevFrame, letterFrames);
10192 : }
10193 : else {
10194 : // Take the old textFrame out of the inline parent's child list
10195 0 : RemoveFrame(kPrincipalList, textFrame);
10196 :
10197 : // Insert in the letter frame(s)
10198 0 : parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames);
10199 : }
10200 : }
10201 :
10202 0 : return rv;
10203 : }
10204 :
10205 : nsresult
10206 0 : nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
10207 : nsIFrame* aBlockFrame,
10208 : nsIFrame* aBlockContinuation,
10209 : nsIFrame* aParentFrame,
10210 : nsIFrame* aParentFrameList,
10211 : nsIFrame** aModifiedParent,
10212 : nsIFrame** aTextFrame,
10213 : nsIFrame** aPrevFrame,
10214 : nsFrameItems& aLetterFrames,
10215 : bool* aStopLooking)
10216 : {
10217 0 : nsresult rv = NS_OK;
10218 :
10219 0 : nsIFrame* prevFrame = nsnull;
10220 0 : nsIFrame* frame = aParentFrameList;
10221 :
10222 0 : while (frame) {
10223 0 : nsIFrame* nextFrame = frame->GetNextSibling();
10224 :
10225 0 : nsIAtom* frameType = frame->GetType();
10226 0 : if (nsGkAtoms::textFrame == frameType) {
10227 : // Wrap up first-letter content in a letter frame
10228 0 : nsIContent* textContent = frame->GetContent();
10229 0 : if (IsFirstLetterContent(textContent)) {
10230 : // Create letter frame to wrap up the text
10231 : rv = CreateLetterFrame(aBlockFrame, aBlockContinuation, textContent,
10232 0 : aParentFrame, aLetterFrames);
10233 0 : if (NS_FAILED(rv)) {
10234 0 : return rv;
10235 : }
10236 :
10237 : // Provide adjustment information for parent
10238 0 : *aModifiedParent = aParentFrame;
10239 0 : *aTextFrame = frame;
10240 0 : *aPrevFrame = prevFrame;
10241 0 : *aStopLooking = true;
10242 0 : return NS_OK;
10243 : }
10244 : }
10245 0 : else if (IsInlineFrame(frame) && frameType != nsGkAtoms::brFrame) {
10246 0 : nsIFrame* kids = frame->GetFirstPrincipalChild();
10247 : WrapFramesInFirstLetterFrame(aBlockFrame, aBlockContinuation, frame,
10248 : kids, aModifiedParent, aTextFrame,
10249 0 : aPrevFrame, aLetterFrames, aStopLooking);
10250 0 : if (*aStopLooking) {
10251 0 : return NS_OK;
10252 : }
10253 : }
10254 : else {
10255 : // This will stop us looking to create more letter frames. For
10256 : // example, maybe the frame-type is "letterFrame" or
10257 : // "placeholderFrame". This keeps us from creating extra letter
10258 : // frames, and also prevents us from creating letter frames when
10259 : // the first real content child of a block is not text (e.g. an
10260 : // image, hr, etc.)
10261 0 : *aStopLooking = true;
10262 0 : break;
10263 : }
10264 :
10265 0 : prevFrame = frame;
10266 0 : frame = nextFrame;
10267 : }
10268 :
10269 0 : return rv;
10270 : }
10271 :
10272 : nsresult
10273 0 : nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
10274 : nsPresContext* aPresContext,
10275 : nsIPresShell* aPresShell,
10276 : nsIFrame* aBlockFrame,
10277 : bool* aStopLooking)
10278 : {
10279 : // First look for the float frame that is a letter frame
10280 0 : nsIFrame* floatFrame = aBlockFrame->GetFirstChild(nsIFrame::kFloatList);
10281 0 : while (floatFrame) {
10282 : // See if we found a floating letter frame
10283 0 : if (nsGkAtoms::letterFrame == floatFrame->GetType()) {
10284 0 : break;
10285 : }
10286 0 : floatFrame = floatFrame->GetNextSibling();
10287 : }
10288 0 : if (!floatFrame) {
10289 : // No such frame
10290 0 : return NS_OK;
10291 : }
10292 :
10293 : // Take the text frame away from the letter frame (so it isn't
10294 : // destroyed when we destroy the letter frame).
10295 0 : nsIFrame* textFrame = floatFrame->GetFirstPrincipalChild();
10296 0 : if (!textFrame) {
10297 0 : return NS_OK;
10298 : }
10299 :
10300 : // Discover the placeholder frame for the letter frame
10301 : nsIFrame* parentFrame;
10302 0 : nsPlaceholderFrame* placeholderFrame = GetPlaceholderFrameFor(floatFrame);
10303 :
10304 0 : if (!placeholderFrame) {
10305 : // Somethings really wrong
10306 0 : return NS_OK;
10307 : }
10308 0 : parentFrame = placeholderFrame->GetParent();
10309 0 : if (!parentFrame) {
10310 : // Somethings really wrong
10311 0 : return NS_OK;
10312 : }
10313 :
10314 : // Create a new text frame with the right style context that maps
10315 : // all of the content that was previously part of the letter frame
10316 : // (and probably continued elsewhere).
10317 0 : nsStyleContext* parentSC = parentFrame->GetStyleContext();
10318 0 : if (!parentSC) {
10319 0 : return NS_OK;
10320 : }
10321 0 : nsIContent* textContent = textFrame->GetContent();
10322 0 : if (!textContent) {
10323 0 : return NS_OK;
10324 : }
10325 0 : nsRefPtr<nsStyleContext> newSC;
10326 0 : newSC = aPresShell->StyleSet()->ResolveStyleForNonElement(parentSC);
10327 0 : if (!newSC) {
10328 0 : return NS_OK;
10329 : }
10330 0 : nsIFrame* newTextFrame = NS_NewTextFrame(aPresShell, newSC);
10331 0 : if (NS_UNLIKELY(!newTextFrame)) {
10332 0 : return NS_ERROR_OUT_OF_MEMORY;;
10333 : }
10334 0 : newTextFrame->Init(textContent, parentFrame, nsnull);
10335 :
10336 : // Destroy the old text frame's continuations (the old text frame
10337 : // will be destroyed when its letter frame is destroyed).
10338 0 : nsIFrame* frameToDelete = textFrame->GetLastContinuation();
10339 0 : while (frameToDelete != textFrame) {
10340 0 : nsIFrame* nextFrameToDelete = frameToDelete->GetPrevContinuation();
10341 0 : RemoveFrame(kPrincipalList, frameToDelete);
10342 0 : frameToDelete = nextFrameToDelete;
10343 : }
10344 :
10345 0 : nsIFrame* prevSibling = placeholderFrame->GetPrevSibling();
10346 :
10347 : // Now that everything is set...
10348 : #ifdef NOISY_FIRST_LETTER
10349 : printf("RemoveFloatingFirstLetterFrames: textContent=%p oldTextFrame=%p newTextFrame=%p\n",
10350 : textContent.get(), textFrame, newTextFrame);
10351 : #endif
10352 :
10353 : // Remove placeholder frame and the float
10354 0 : RemoveFrame(kPrincipalList, placeholderFrame);
10355 :
10356 : // Now that the old frames are gone, we can start pointing to our
10357 : // new primary frame.
10358 0 : textContent->SetPrimaryFrame(newTextFrame);
10359 :
10360 : // Insert text frame in its place
10361 0 : nsFrameList textList(newTextFrame, newTextFrame);
10362 0 : InsertFrames(parentFrame, kPrincipalList, prevSibling, textList);
10363 :
10364 0 : return NS_OK;
10365 : }
10366 :
10367 : nsresult
10368 0 : nsCSSFrameConstructor::RemoveFirstLetterFrames(nsPresContext* aPresContext,
10369 : nsIPresShell* aPresShell,
10370 : nsIFrame* aFrame,
10371 : nsIFrame* aBlockFrame,
10372 : bool* aStopLooking)
10373 : {
10374 0 : nsIFrame* prevSibling = nsnull;
10375 0 : nsIFrame* kid = aFrame->GetFirstPrincipalChild();
10376 :
10377 0 : while (kid) {
10378 0 : if (nsGkAtoms::letterFrame == kid->GetType()) {
10379 : // Bingo. Found it. First steal away the text frame.
10380 0 : nsIFrame* textFrame = kid->GetFirstPrincipalChild();
10381 0 : if (!textFrame) {
10382 0 : break;
10383 : }
10384 :
10385 : // Create a new textframe
10386 0 : nsStyleContext* parentSC = aFrame->GetStyleContext();
10387 0 : if (!parentSC) {
10388 0 : break;
10389 : }
10390 0 : nsIContent* textContent = textFrame->GetContent();
10391 0 : if (!textContent) {
10392 0 : break;
10393 : }
10394 0 : nsRefPtr<nsStyleContext> newSC;
10395 0 : newSC = aPresShell->StyleSet()->ResolveStyleForNonElement(parentSC);
10396 0 : if (!newSC) {
10397 : break;
10398 : }
10399 0 : textFrame = NS_NewTextFrame(aPresShell, newSC);
10400 0 : textFrame->Init(textContent, aFrame, nsnull);
10401 :
10402 : // Next rip out the kid and replace it with the text frame
10403 0 : RemoveFrame(kPrincipalList, kid);
10404 :
10405 : // Now that the old frames are gone, we can start pointing to our
10406 : // new primary frame.
10407 0 : textContent->SetPrimaryFrame(textFrame);
10408 :
10409 : // Insert text frame in its place
10410 0 : nsFrameList textList(textFrame, textFrame);
10411 0 : InsertFrames(aFrame, kPrincipalList, prevSibling, textList);
10412 :
10413 0 : *aStopLooking = true;
10414 0 : NS_ASSERTION(!aBlockFrame->GetPrevContinuation(),
10415 : "should have the first continuation here");
10416 0 : aBlockFrame->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD);
10417 : break;
10418 : }
10419 0 : else if (IsInlineFrame(kid)) {
10420 : // Look inside child inline frame for the letter frame
10421 : RemoveFirstLetterFrames(aPresContext, aPresShell,
10422 0 : kid, aBlockFrame, aStopLooking);
10423 0 : if (*aStopLooking) {
10424 0 : break;
10425 : }
10426 : }
10427 0 : prevSibling = kid;
10428 0 : kid = kid->GetNextSibling();
10429 : }
10430 :
10431 0 : return NS_OK;
10432 : }
10433 :
10434 : nsresult
10435 0 : nsCSSFrameConstructor::RemoveLetterFrames(nsPresContext* aPresContext,
10436 : nsIPresShell* aPresShell,
10437 : nsIFrame* aBlockFrame)
10438 : {
10439 0 : aBlockFrame = aBlockFrame->GetFirstContinuation();
10440 0 : nsIFrame* continuation = aBlockFrame;
10441 :
10442 0 : bool stopLooking = false;
10443 : nsresult rv;
10444 0 : do {
10445 : rv = RemoveFloatingFirstLetterFrames(aPresContext, aPresShell,
10446 0 : continuation, &stopLooking);
10447 0 : if (NS_SUCCEEDED(rv) && !stopLooking) {
10448 : rv = RemoveFirstLetterFrames(aPresContext, aPresShell,
10449 0 : continuation, aBlockFrame, &stopLooking);
10450 : }
10451 0 : if (stopLooking) {
10452 0 : break;
10453 : }
10454 0 : continuation = continuation->GetNextContinuation();
10455 : } while (continuation);
10456 0 : return rv;
10457 : }
10458 :
10459 : // Fixup the letter frame situation for the given block
10460 : nsresult
10461 0 : nsCSSFrameConstructor::RecoverLetterFrames(nsIFrame* aBlockFrame)
10462 : {
10463 0 : aBlockFrame = aBlockFrame->GetFirstContinuation();
10464 0 : nsIFrame* continuation = aBlockFrame;
10465 :
10466 0 : nsIFrame* parentFrame = nsnull;
10467 0 : nsIFrame* textFrame = nsnull;
10468 0 : nsIFrame* prevFrame = nsnull;
10469 0 : nsFrameItems letterFrames;
10470 0 : bool stopLooking = false;
10471 : nsresult rv;
10472 0 : do {
10473 : // XXX shouldn't this bit be set already (bug 408493), assert instead?
10474 0 : continuation->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE);
10475 : rv = WrapFramesInFirstLetterFrame(aBlockFrame, continuation, continuation,
10476 : continuation->GetFirstPrincipalChild(),
10477 : &parentFrame, &textFrame, &prevFrame,
10478 0 : letterFrames, &stopLooking);
10479 0 : if (NS_FAILED(rv)) {
10480 0 : return rv;
10481 : }
10482 0 : if (stopLooking) {
10483 0 : break;
10484 : }
10485 0 : continuation = continuation->GetNextContinuation();
10486 : } while (continuation);
10487 :
10488 0 : if (parentFrame) {
10489 : // Take the old textFrame out of the parents child list
10490 0 : RemoveFrame(kPrincipalList, textFrame);
10491 :
10492 : // Insert in the letter frame(s)
10493 0 : parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames);
10494 : }
10495 0 : return rv;
10496 : }
10497 :
10498 : //----------------------------------------------------------------------
10499 :
10500 : // listbox Widget Routines
10501 :
10502 : nsresult
10503 0 : nsCSSFrameConstructor::CreateListBoxContent(nsPresContext* aPresContext,
10504 : nsIFrame* aParentFrame,
10505 : nsIFrame* aPrevFrame,
10506 : nsIContent* aChild,
10507 : nsIFrame** aNewFrame,
10508 : bool aIsAppend,
10509 : bool aIsScrollbar,
10510 : nsILayoutHistoryState* aFrameState)
10511 : {
10512 : #ifdef MOZ_XUL
10513 0 : nsresult rv = NS_OK;
10514 :
10515 : // Construct a new frame
10516 0 : if (nsnull != aParentFrame) {
10517 0 : nsFrameItems frameItems;
10518 : nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
10519 : GetAbsoluteContainingBlock(aParentFrame),
10520 : GetFloatContainingBlock(aParentFrame),
10521 0 : mTempFrameTreeState);
10522 :
10523 : // If we ever initialize the ancestor filter on |state|, make sure
10524 : // to push the right parent!
10525 :
10526 0 : nsRefPtr<nsStyleContext> styleContext;
10527 0 : styleContext = ResolveStyleContext(aParentFrame, aChild, &state);
10528 :
10529 : // Pre-check for display "none" - only if we find that, do we create
10530 : // any frame at all
10531 0 : const nsStyleDisplay* display = styleContext->GetStyleDisplay();
10532 :
10533 0 : if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
10534 0 : *aNewFrame = nsnull;
10535 0 : return NS_OK;
10536 : }
10537 :
10538 0 : BeginUpdate();
10539 :
10540 0 : FrameConstructionItemList items;
10541 : AddFrameConstructionItemsInternal(state, aChild, aParentFrame,
10542 : aChild->Tag(), aChild->GetNameSpaceID(),
10543 : true, styleContext,
10544 0 : ITEM_ALLOW_XBL_BASE, items);
10545 0 : ConstructFramesFromItemList(state, items, aParentFrame, frameItems);
10546 :
10547 0 : nsIFrame* newFrame = frameItems.FirstChild();
10548 0 : *aNewFrame = newFrame;
10549 :
10550 0 : if (newFrame) {
10551 : // Notify the parent frame
10552 0 : if (aIsAppend)
10553 0 : rv = ((nsListBoxBodyFrame*)aParentFrame)->ListBoxAppendFrames(frameItems);
10554 : else
10555 0 : rv = ((nsListBoxBodyFrame*)aParentFrame)->ListBoxInsertFrames(aPrevFrame, frameItems);
10556 : }
10557 :
10558 0 : EndUpdate();
10559 :
10560 : #ifdef ACCESSIBILITY
10561 0 : if (newFrame) {
10562 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
10563 0 : if (accService) {
10564 : accService->ContentRangeInserted(mPresShell, aChild->GetParent(),
10565 0 : aChild, aChild->GetNextSibling());
10566 : }
10567 : }
10568 : #endif
10569 : }
10570 :
10571 0 : return rv;
10572 : #else
10573 : return NS_ERROR_FAILURE;
10574 : #endif
10575 : }
10576 :
10577 : //----------------------------------------
10578 :
10579 : nsresult
10580 0 : nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState& aState,
10581 : const nsStyleDisplay* aDisplay,
10582 : nsIContent* aContent,
10583 : nsIFrame* aParentFrame,
10584 : nsIFrame* aContentParentFrame,
10585 : nsStyleContext* aStyleContext,
10586 : nsIFrame** aNewFrame,
10587 : nsFrameItems& aFrameItems,
10588 : bool aAbsPosContainer,
10589 : PendingBinding* aPendingBinding)
10590 : {
10591 : // Create column wrapper if necessary
10592 0 : nsIFrame* blockFrame = *aNewFrame;
10593 0 : NS_ASSERTION(blockFrame->GetType() == nsGkAtoms::blockFrame, "not a block frame?");
10594 0 : nsIFrame* parent = aParentFrame;
10595 0 : nsRefPtr<nsStyleContext> blockStyle = aStyleContext;
10596 0 : const nsStyleColumn* columns = aStyleContext->GetStyleColumn();
10597 :
10598 0 : if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO
10599 0 : || columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) {
10600 0 : nsIFrame* columnSetFrame = nsnull;
10601 0 : columnSetFrame = NS_NewColumnSetFrame(mPresShell, aStyleContext, 0);
10602 0 : if (!columnSetFrame) {
10603 0 : return NS_ERROR_OUT_OF_MEMORY;
10604 : }
10605 :
10606 0 : InitAndRestoreFrame(aState, aContent, aParentFrame, nsnull, columnSetFrame);
10607 : blockStyle = mPresShell->StyleSet()->
10608 0 : ResolveAnonymousBoxStyle(nsCSSAnonBoxes::columnContent, aStyleContext);
10609 0 : parent = columnSetFrame;
10610 0 : *aNewFrame = columnSetFrame;
10611 :
10612 0 : SetInitialSingleChild(columnSetFrame, blockFrame);
10613 : }
10614 :
10615 0 : blockFrame->SetStyleContextWithoutNotification(blockStyle);
10616 0 : InitAndRestoreFrame(aState, aContent, parent, nsnull, blockFrame);
10617 :
10618 : nsresult rv = aState.AddChild(*aNewFrame, aFrameItems, aContent,
10619 : aStyleContext,
10620 : aContentParentFrame ? aContentParentFrame :
10621 0 : aParentFrame);
10622 0 : if (NS_FAILED(rv)) {
10623 0 : return rv;
10624 : }
10625 :
10626 0 : if (!mRootElementFrame) {
10627 : // The frame we're constructing will be the root element frame.
10628 : // Set mRootElementFrame before processing children.
10629 0 : mRootElementFrame = *aNewFrame;
10630 : }
10631 :
10632 : // We should make the outer frame be the absolute containing block,
10633 : // if one is required. We have to do this because absolute
10634 : // positioning must be computed with respect to the CSS dimensions
10635 : // of the element, which are the dimensions of the outer block. But
10636 : // we can't really do that because only blocks can have absolute
10637 : // children. So use the block and try to compensate with hacks
10638 : // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
10639 0 : nsFrameConstructorSaveState absoluteSaveState;
10640 0 : if (aAbsPosContainer) {
10641 : // NS_ASSERTION(aRelPos, "should have made area frame for this");
10642 0 : aState.PushAbsoluteContainingBlock(*aNewFrame, absoluteSaveState);
10643 : }
10644 :
10645 : // Process the child content
10646 0 : nsFrameItems childItems;
10647 : rv = ProcessChildren(aState, aContent, aStyleContext, blockFrame, true,
10648 0 : childItems, true, aPendingBinding);
10649 :
10650 : // Set the frame's initial child list
10651 0 : blockFrame->SetInitialChildList(kPrincipalList, childItems);
10652 :
10653 0 : return rv;
10654 : }
10655 :
10656 : nsresult
10657 0 : nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState,
10658 : FrameConstructionItem& aItem,
10659 : nsIFrame* aParentFrame,
10660 : const nsStyleDisplay* aDisplay,
10661 : nsFrameItems& aFrameItems,
10662 : nsIFrame** aNewFrame)
10663 : {
10664 : // If an inline frame has non-inline kids, then we chop up the child list
10665 : // into runs of blocks and runs of inlines, create anonymous block frames to
10666 : // contain the runs of blocks, inline frames with our style context for the
10667 : // runs of inlines, and put all these frames, in order, into aFrameItems. We
10668 : // put the first one into *aNewFrame. The whole setup is called an {ib}
10669 : // split; in what follows "frames in the split" refers to the anonymous blocks
10670 : // and inlines that contain our children.
10671 : //
10672 : // {ib} splits maintain the following invariants:
10673 : // 1) All frames in the split have the NS_FRAME_IS_SPECIAL bit set.
10674 : // 2) Each frame in the split has the nsIFrame::IBSplitSpecialSibling
10675 : // property pointing to the next frame in the split, except for the last
10676 : // one, which does not have it set.
10677 : // 3) Each frame in the split has the nsIFrame::IBSplitSpecialPrevSibling
10678 : // property pointing to the previous frame in the split, except for the
10679 : // first one, which does not have it set.
10680 : // 4) The first and last frame in the split are always inlines.
10681 : //
10682 : // An invariant that is NOT maintained is that the wrappers are actually
10683 : // linked via GetNextSibling linkage. A simple example is an inline
10684 : // containing an inline that contains a block. The three parts of the inner
10685 : // inline end up with three different parents.
10686 : //
10687 : // For example, this HTML:
10688 : // <span>
10689 : // <div>a</div>
10690 : // <span>
10691 : // b
10692 : // <div>c</div>
10693 : // </span>
10694 : // d
10695 : // <div>e</div>
10696 : // f
10697 : // </span>
10698 : // Gives the following frame tree:
10699 : //
10700 : // Inline (outer span)
10701 : // Block (anonymous, outer span)
10702 : // Block (div)
10703 : // Text("a")
10704 : // Inline (outer span)
10705 : // Inline (inner span)
10706 : // Text("b")
10707 : // Block (anonymous, outer span)
10708 : // Block (anonymous, inner span)
10709 : // Block (div)
10710 : // Text("c")
10711 : // Inline (outer span)
10712 : // Inline (inner span)
10713 : // Text("d")
10714 : // Block (anonymous, outer span)
10715 : // Block (div)
10716 : // Text("e")
10717 : // Inline (outer span)
10718 : // Text("f")
10719 :
10720 0 : nsIContent* const content = aItem.mContent;
10721 0 : nsStyleContext* const styleContext = aItem.mStyleContext;
10722 :
10723 : nsIFrame *newFrame;
10724 :
10725 : bool positioned =
10726 : NS_STYLE_DISPLAY_INLINE == aDisplay->mDisplay &&
10727 : (NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition ||
10728 0 : aDisplay->HasTransform());
10729 0 : newFrame = NS_NewInlineFrame(mPresShell, styleContext);
10730 :
10731 : // Initialize the frame
10732 0 : InitAndRestoreFrame(aState, content, aParentFrame, nsnull, newFrame);
10733 :
10734 0 : nsFrameConstructorSaveState absoluteSaveState; // definition cannot be inside next block
10735 : // because the object's destructor is significant
10736 : // this is part of the fix for bug 42372
10737 :
10738 0 : if (positioned) {
10739 : // Relatively positioned frames becomes a container for child
10740 : // frames that are positioned
10741 0 : aState.PushAbsoluteContainingBlock(newFrame, absoluteSaveState);
10742 : }
10743 :
10744 : // Process the child content
10745 0 : nsFrameItems childItems;
10746 : nsresult rv = ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
10747 0 : childItems);
10748 0 : if (NS_FAILED(rv)) {
10749 : // Clean up?
10750 0 : return rv;
10751 : }
10752 :
10753 0 : nsFrameList::FrameLinkEnumerator firstBlockEnumerator(childItems);
10754 0 : if (!aItem.mIsAllInline) {
10755 0 : FindFirstBlock(firstBlockEnumerator);
10756 : }
10757 :
10758 0 : if (aItem.mIsAllInline || firstBlockEnumerator.AtEnd()) {
10759 : // This part is easy. We either already know we have no non-inline kids,
10760 : // or haven't found any when constructing actual frames (the latter can
10761 : // happen only if out-of-flows that we thought had no containing block
10762 : // acquired one when ancestor inline frames and {ib} splits got
10763 : // constructed). Just put all the kids into the single inline frame and
10764 : // bail.
10765 0 : newFrame->SetInitialChildList(kPrincipalList, childItems);
10766 0 : if (NS_SUCCEEDED(rv)) {
10767 0 : aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame);
10768 0 : *aNewFrame = newFrame;
10769 : }
10770 0 : return rv;
10771 : }
10772 :
10773 : // This inline frame contains several types of children. Therefore this frame
10774 : // has to be chopped into several pieces, as described above.
10775 :
10776 : // Grab the first inline's kids
10777 0 : nsFrameList firstInlineKids = childItems.ExtractHead(firstBlockEnumerator);
10778 0 : newFrame->SetInitialChildList(kPrincipalList, firstInlineKids);
10779 :
10780 0 : aFrameItems.AddChild(newFrame);
10781 :
10782 0 : CreateIBSiblings(aState, newFrame, positioned, childItems, aFrameItems);
10783 :
10784 0 : *aNewFrame = newFrame;
10785 0 : return NS_OK;
10786 : }
10787 :
10788 : void
10789 0 : nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState,
10790 : nsIFrame* aInitialInline,
10791 : bool aIsPositioned,
10792 : nsFrameItems& aChildItems,
10793 : nsFrameItems& aSiblings)
10794 : {
10795 0 : nsIContent* content = aInitialInline->GetContent();
10796 0 : nsStyleContext* styleContext = aInitialInline->GetStyleContext();
10797 0 : nsIFrame* parentFrame = aInitialInline->GetParent();
10798 :
10799 : // Resolve the right style context for our anonymous blocks.
10800 : // The distinction in styles is needed because of CSS 2.1, section
10801 : // 9.2.1.1, which says:
10802 : // When such an inline box is affected by relative positioning, any
10803 : // resulting translation also affects the block-level box contained
10804 : // in the inline box.
10805 : nsRefPtr<nsStyleContext> blockSC =
10806 : mPresShell->StyleSet()->
10807 : ResolveAnonymousBoxStyle(aIsPositioned ?
10808 : nsCSSAnonBoxes::mozAnonymousPositionedBlock :
10809 : nsCSSAnonBoxes::mozAnonymousBlock,
10810 0 : styleContext);
10811 :
10812 0 : nsIFrame* lastNewInline = aInitialInline->GetFirstContinuation();
10813 0 : do {
10814 : // On entry to this loop aChildItems is not empty and the first frame in it
10815 : // is block-level.
10816 0 : NS_PRECONDITION(aChildItems.NotEmpty(), "Should have child items");
10817 0 : NS_PRECONDITION(!IsInlineOutside(aChildItems.FirstChild()),
10818 : "Must have list starting with block");
10819 :
10820 : // The initial run of blocks belongs to an anonymous block that we create
10821 : // right now. The anonymous block will be the parent of these block
10822 : // children of the inline.
10823 : nsIFrame* blockFrame;
10824 0 : blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
10825 :
10826 : InitAndRestoreFrame(aState, content, parentFrame, nsnull, blockFrame,
10827 0 : false);
10828 :
10829 : // Find the first non-block child which defines the end of our block kids
10830 : // and the start of our next inline's kids
10831 : nsFrameList::FrameLinkEnumerator firstNonBlock =
10832 0 : FindFirstNonBlock(aChildItems);
10833 0 : nsFrameList blockKids = aChildItems.ExtractHead(firstNonBlock);
10834 :
10835 0 : MoveChildrenTo(aState.mPresContext, aInitialInline, blockFrame, blockKids);
10836 :
10837 0 : SetFrameIsSpecial(lastNewInline, blockFrame);
10838 0 : aSiblings.AddChild(blockFrame);
10839 :
10840 : // Now grab the initial inlines in aChildItems and put them into an inline
10841 : // frame
10842 0 : nsIFrame* inlineFrame = NS_NewInlineFrame(mPresShell, styleContext);
10843 :
10844 : InitAndRestoreFrame(aState, content, parentFrame, nsnull, inlineFrame,
10845 0 : false);
10846 :
10847 0 : if (aIsPositioned) {
10848 0 : inlineFrame->MarkAsAbsoluteContainingBlock();
10849 : }
10850 :
10851 0 : if (aChildItems.NotEmpty()) {
10852 0 : nsFrameList::FrameLinkEnumerator firstBlock(aChildItems);
10853 0 : FindFirstBlock(firstBlock);
10854 0 : nsFrameList inlineKids = aChildItems.ExtractHead(firstBlock);
10855 :
10856 : MoveChildrenTo(aState.mPresContext, aInitialInline, inlineFrame,
10857 0 : inlineKids);
10858 : }
10859 :
10860 0 : SetFrameIsSpecial(blockFrame, inlineFrame);
10861 0 : aSiblings.AddChild(inlineFrame);
10862 0 : lastNewInline = inlineFrame;
10863 0 : } while (aChildItems.NotEmpty());
10864 :
10865 0 : SetFrameIsSpecial(lastNewInline, nsnull);
10866 0 : }
10867 :
10868 : void
10869 0 : nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState,
10870 : FrameConstructionItem& aParentItem)
10871 : {
10872 : // XXXbz should we preallocate aParentItem.mChildItems to some sane
10873 : // length? Maybe even to parentContent->GetChildCount()?
10874 : nsFrameConstructorState::PendingBindingAutoPusher
10875 0 : pusher(aState, aParentItem.mPendingBinding);
10876 :
10877 : // Probe for generated content before
10878 0 : nsStyleContext* const parentStyleContext = aParentItem.mStyleContext;
10879 0 : nsIContent* const parentContent = aParentItem.mContent;
10880 :
10881 : AncestorFilter::AutoAncestorPusher
10882 0 : ancestorPusher(aState.mTreeMatchContext.mAncestorFilter.HasFilter(),
10883 : aState.mTreeMatchContext.mAncestorFilter,
10884 0 : parentContent->AsElement());
10885 :
10886 : CreateGeneratedContentItem(aState, nsnull, parentContent, parentStyleContext,
10887 : nsCSSPseudoElements::ePseudo_before,
10888 0 : aParentItem.mChildItems);
10889 :
10890 0 : ChildIterator iter, last;
10891 0 : for (ChildIterator::Init(parentContent, &iter, &last);
10892 : iter != last;
10893 : ++iter) {
10894 : // Manually check for comments/PIs, since we don't have a frame to pass to
10895 : // AddFrameConstructionItems. We know our parent is a non-replaced inline,
10896 : // so there is no need to do the NeedFrameFor check.
10897 0 : nsIContent* content = *iter;
10898 0 : content->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
10899 0 : if (content->IsNodeOfType(nsINode::eCOMMENT) ||
10900 0 : content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
10901 0 : continue;
10902 : }
10903 0 : if (content->IsElement()) {
10904 : // See comment explaining why we need to remove the "is possible
10905 : // restyle root" flags in AddFrameConstructionItems. But note
10906 : // that we can remove all restyle flags, just like in
10907 : // ProcessChildren and for the same reason.
10908 0 : content->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS);
10909 : }
10910 :
10911 : nsRefPtr<nsStyleContext> childContext =
10912 0 : ResolveStyleContext(parentStyleContext, content, &aState);
10913 :
10914 : AddFrameConstructionItemsInternal(aState, content, nsnull, content->Tag(),
10915 : content->GetNameSpaceID(),
10916 0 : iter.XBLInvolved(), childContext,
10917 : ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK,
10918 0 : aParentItem.mChildItems);
10919 : }
10920 :
10921 : // Probe for generated content after
10922 : CreateGeneratedContentItem(aState, nsnull, parentContent, parentStyleContext,
10923 : nsCSSPseudoElements::ePseudo_after,
10924 0 : aParentItem.mChildItems);
10925 :
10926 0 : aParentItem.mIsAllInline = aParentItem.mChildItems.AreAllItemsInline();
10927 0 : }
10928 :
10929 : // return whether it's ok to append (in the AppendFrames sense) to
10930 : // aParentFrame if our nextSibling is aNextSibling. aParentFrame must
10931 : // be an {ib} special inline.
10932 : static bool
10933 0 : IsSafeToAppendToSpecialInline(nsIFrame* aParentFrame, nsIFrame* aNextSibling)
10934 : {
10935 0 : NS_PRECONDITION(IsInlineFrame(aParentFrame),
10936 : "Must have an inline parent here");
10937 0 : do {
10938 0 : NS_ASSERTION(IsFrameSpecial(aParentFrame), "How is this not special?");
10939 0 : if (aNextSibling || aParentFrame->GetNextContinuation() ||
10940 0 : GetSpecialSibling(aParentFrame)) {
10941 0 : return false;
10942 : }
10943 :
10944 0 : aNextSibling = aParentFrame->GetNextSibling();
10945 0 : aParentFrame = aParentFrame->GetParent();
10946 : } while (IsInlineFrame(aParentFrame));
10947 :
10948 0 : return true;
10949 : }
10950 :
10951 : bool
10952 0 : nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
10953 : nsIFrame* aContainingBlock,
10954 : nsIFrame* aFrame,
10955 : FrameConstructionItemList& aItems,
10956 : bool aIsAppend,
10957 : nsIFrame* aPrevSibling)
10958 : {
10959 0 : if (aItems.IsEmpty()) {
10960 0 : return false;
10961 : }
10962 :
10963 : // Before we go and append the frames, we must check for several
10964 : // special situations.
10965 :
10966 : // Situation #1 is a XUL frame that contains frames that are required
10967 : // to be wrapped in blocks.
10968 0 : if (aFrame->IsBoxFrame() &&
10969 0 : !(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
10970 0 : aItems.AnyItemsNeedBlockParent()) {
10971 0 : RecreateFramesForContent(aFrame->GetContent(), true);
10972 0 : return true;
10973 : }
10974 :
10975 0 : nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
10976 :
10977 : // Situation #2 is a case when table pseudo-frames don't work out right
10978 0 : ParentType parentType = GetParentType(aFrame);
10979 : // If all the kids want a parent of the type that aFrame is, then we're all
10980 : // set to go. Indeed, there won't be any table pseudo-frames created between
10981 : // aFrame and the kids, so those won't need to be merged with any table
10982 : // pseudo-frames that might already be kids of aFrame. If aFrame itself is a
10983 : // table pseudo-frame, then all the kids in this list would have wanted a
10984 : // frame of that type wrapping them anyway, so putting them inside it is ok.
10985 0 : if (!aItems.AllWantParentType(parentType)) {
10986 : // Don't give up yet. If parentType is not eTypeBlock and the parent is
10987 : // not a generated content frame, then try filtering whitespace out of the
10988 : // list.
10989 0 : if (parentType != eTypeBlock && !aFrame->IsGeneratedContentFrame()) {
10990 : // For leading whitespace followed by a kid that wants our parent type,
10991 : // there are four cases:
10992 : // 1) We have a previous sibling which is not a table pseudo. That means
10993 : // that previous sibling wanted a (non-block) parent of the type we're
10994 : // looking at. Then the whitespace comes between two table-internal
10995 : // elements, so should be collapsed out.
10996 : // 2) We have a previous sibling which is a table pseudo. It might have
10997 : // kids who want this whitespace, so we need to reframe.
10998 : // 3) We have no previous sibling and our parent frame is not a table
10999 : // pseudo. That means that we'll be at the beginning of our actual
11000 : // non-block-type parent, and the whitespace is OK to collapse out.
11001 : // If something is ever inserted before us, it'll find our own parent
11002 : // as its parent and if it's something that would care about the
11003 : // whitespace it'll want a block parent, so it'll trigger a reframe at
11004 : // that point.
11005 : // 4) We have no previous sibling and our parent frame is a table pseudo.
11006 : // Need to reframe.
11007 : // All that is predicated on finding the correct previous sibling. We
11008 : // might have to walk backwards along continuations from aFrame to do so.
11009 : //
11010 : // It's always OK to drop whitespace between any two items that want a
11011 : // parent of type parentType.
11012 : //
11013 : // For trailing whitespace preceded by a kid that wants our parent type,
11014 : // there are four cases:
11015 : // 1) We have a next sibling which is not a table pseudo. That means
11016 : // that next sibling wanted a (non-block) parent of the type we're
11017 : // looking at. Then the whitespace comes between two table-internal
11018 : // elements, so should be collapsed out.
11019 : // 2) We have a next sibling which is a table pseudo. It might have
11020 : // kids who want this whitespace, so we need to reframe.
11021 : // 3) We have no next sibling and our parent frame is not a table
11022 : // pseudo. That means that we'll be at the end of our actual
11023 : // non-block-type parent, and the whitespace is OK to collapse out.
11024 : // If something is ever inserted after us, it'll find our own parent
11025 : // as its parent and if it's something that would care about the
11026 : // whitespace it'll want a block parent, so it'll trigger a reframe at
11027 : // that point.
11028 : // 4) We have no next sibling and our parent frame is a table pseudo.
11029 : // Need to reframe.
11030 : // All that is predicated on finding the correct next sibling. We might
11031 : // have to walk forward along continuations from aFrame to do so. That
11032 : // said, in the case when nextSibling is null at this point and aIsAppend
11033 : // is true, we know we're in case 3. Furthermore, in that case we don't
11034 : // even have to worry about the table pseudo situation; we know our
11035 : // parent is not a table pseudo there.
11036 0 : FCItemIterator iter(aItems);
11037 0 : FCItemIterator start(iter);
11038 0 : do {
11039 0 : if (iter.SkipItemsWantingParentType(parentType)) {
11040 0 : break;
11041 : }
11042 :
11043 : // iter points to an item that wants a different parent. If it's not
11044 : // whitespace, we're done; no more point scanning the list.
11045 0 : if (!iter.item().IsWhitespace(aState)) {
11046 0 : break;
11047 : }
11048 :
11049 0 : if (iter == start) {
11050 : // Leading whitespace. How to handle this depends on our
11051 : // previous sibling and aFrame. See the long comment above.
11052 0 : nsIFrame* prevSibling = aPrevSibling;
11053 0 : if (!prevSibling) {
11054 : // Try to find one after all
11055 0 : nsIFrame* parentPrevCont = aFrame->GetPrevContinuation();
11056 0 : while (parentPrevCont) {
11057 0 : prevSibling = parentPrevCont->GetLastChild(kPrincipalList);
11058 0 : if (prevSibling) {
11059 0 : break;
11060 : }
11061 0 : parentPrevCont = parentPrevCont->GetPrevContinuation();
11062 : }
11063 : };
11064 0 : if (prevSibling) {
11065 0 : if (IsTablePseudo(prevSibling)) {
11066 : // need to reframe
11067 0 : break;
11068 : }
11069 0 : } else if (IsTablePseudo(aFrame)) {
11070 : // need to reframe
11071 0 : break;
11072 : }
11073 : }
11074 :
11075 0 : FCItemIterator spaceEndIter(iter);
11076 : // Advance spaceEndIter past any whitespace
11077 0 : bool trailingSpaces = spaceEndIter.SkipWhitespace(aState);
11078 :
11079 : bool okToDrop;
11080 0 : if (trailingSpaces) {
11081 : // Trailing whitespace. How to handle this depeds on aIsAppend, our
11082 : // next sibling and aFrame. See the long comment above.
11083 0 : okToDrop = aIsAppend && !nextSibling;
11084 0 : if (!okToDrop) {
11085 0 : if (!nextSibling) {
11086 : // Try to find one after all
11087 0 : nsIFrame* parentNextCont = aFrame->GetNextContinuation();
11088 0 : while (parentNextCont) {
11089 0 : nextSibling = parentNextCont->GetFirstPrincipalChild();
11090 0 : if (nextSibling) {
11091 0 : break;
11092 : }
11093 0 : parentNextCont = parentNextCont->GetNextContinuation();
11094 : }
11095 : }
11096 :
11097 0 : okToDrop = (nextSibling && !IsTablePseudo(nextSibling)) ||
11098 0 : (!nextSibling && !IsTablePseudo(aFrame));
11099 : }
11100 : #ifdef DEBUG
11101 : else {
11102 0 : NS_ASSERTION(!IsTablePseudo(aFrame), "How did that happen?");
11103 : }
11104 : #endif
11105 : } else {
11106 0 : okToDrop = (spaceEndIter.item().DesiredParentType() == parentType);
11107 : }
11108 :
11109 0 : if (okToDrop) {
11110 0 : iter.DeleteItemsTo(spaceEndIter);
11111 : } else {
11112 : // We're done: we don't want to drop the whitespace, and it has the
11113 : // wrong parent type.
11114 0 : break;
11115 : }
11116 :
11117 : // Now loop, since |iter| points to item right after the whitespace we
11118 : // removed.
11119 0 : } while (!iter.IsDone());
11120 : }
11121 :
11122 : // We might be able to figure out some sort of optimizations here, but they
11123 : // would have to depend on having a correct aPrevSibling and a correct next
11124 : // sibling. For example, we can probably avoid reframing if none of
11125 : // aFrame, aPrevSibling, and next sibling are table pseudo-frames. But it
11126 : // doesn't seem worth it to worry about that for now, especially since we
11127 : // in fact do not have a reliable aPrevSibling, nor any next sibling, in
11128 : // this method.
11129 :
11130 : // aItems might have changed, so recheck the parent type thing. In fact,
11131 : // it might be empty, so recheck that too.
11132 0 : if (aItems.IsEmpty()) {
11133 0 : return false;
11134 : }
11135 :
11136 0 : if (!aItems.AllWantParentType(parentType)) {
11137 : // Reframing aFrame->GetContent() is good enough, since the content of
11138 : // table pseudo-frames is the ancestor content.
11139 0 : RecreateFramesForContent(aFrame->GetContent(), true);
11140 0 : return true;
11141 : }
11142 : }
11143 :
11144 : // Now we have several cases involving {ib} splits. Put them all in a
11145 : // do/while with breaks to take us to the "go and reconstruct" code.
11146 : do {
11147 0 : if (IsInlineFrame(aFrame)) {
11148 0 : if (aItems.AreAllItemsInline()) {
11149 : // We can just put the kids in.
11150 0 : return false;
11151 : }
11152 :
11153 0 : if (!IsFrameSpecial(aFrame)) {
11154 : // Need to go ahead and reconstruct.
11155 0 : break;
11156 : }
11157 :
11158 : // Now we're adding kids including some blocks to an inline part of an
11159 : // {ib} split. If we plan to call AppendFrames, and don't have a next
11160 : // sibling for the new frames, and our parent is the last continuation of
11161 : // the last part of the {ib} split, and the same is true of all our
11162 : // ancestor inlines (they have no following continuations and they're the
11163 : // last part of their {ib} splits and we'd be adding to the end for all
11164 : // of them), then AppendFrames will handle things for us. Bail out in
11165 : // that case.
11166 0 : if (aIsAppend && IsSafeToAppendToSpecialInline(aFrame, nextSibling)) {
11167 0 : return false;
11168 : }
11169 :
11170 : // Need to reconstruct.
11171 0 : break;
11172 : }
11173 :
11174 : // Now we know we have a block parent. If it's not special, we're all set.
11175 0 : if (!IsFrameSpecial(aFrame)) {
11176 0 : return false;
11177 : }
11178 :
11179 : // We're adding some kids to a block part of an {ib} split. If all the
11180 : // kids are blocks, we don't need to reconstruct.
11181 0 : if (aItems.AreAllItemsBlock()) {
11182 0 : return false;
11183 : }
11184 :
11185 : // We might have some inline kids for this block. Just reconstruct.
11186 0 : break;
11187 : } while (0);
11188 :
11189 : // If we don't have a containing block, start with aFrame and look for one.
11190 0 : if (!aContainingBlock) {
11191 0 : aContainingBlock = aFrame;
11192 : }
11193 :
11194 : // To find the right block to reframe, just walk up the tree until we find a
11195 : // frame that is:
11196 : // 1) Not part of an IB split (not special)
11197 : // 2) Not a pseudo-frame
11198 : // 3) Not an inline frame
11199 : // We're guaranteed to find one, since nsStyleContext::ApplyStyleFixups
11200 : // enforces that the root is display:none, display:table, or display:block.
11201 : // Note that walking up "too far" is OK in terms of correctness, even if it
11202 : // might be a little inefficient. This is why we walk out of all
11203 : // pseudo-frames -- telling which ones are or are not OK to walk out of is
11204 : // too hard (and I suspect that we do in fact need to walk out of all of
11205 : // them).
11206 0 : while (IsFrameSpecial(aContainingBlock) || IsInlineOutside(aContainingBlock) ||
11207 0 : aContainingBlock->GetStyleContext()->GetPseudo()) {
11208 0 : aContainingBlock = aContainingBlock->GetParent();
11209 0 : NS_ASSERTION(aContainingBlock,
11210 : "Must have non-inline, non-special, non-pseudo frame as root "
11211 : "(or child of root, for a table root)!");
11212 : }
11213 :
11214 : // Tell parent of the containing block to reformulate the
11215 : // entire block. This is painful and definitely not optimal
11216 : // but it will *always* get the right answer.
11217 :
11218 0 : nsIContent *blockContent = aContainingBlock->GetContent();
11219 : #ifdef DEBUG
11220 0 : if (gNoisyContentUpdates) {
11221 : printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p\n",
11222 0 : static_cast<void*>(blockContent));
11223 : }
11224 : #endif
11225 0 : RecreateFramesForContent(blockContent, true);
11226 0 : return true;
11227 : }
11228 :
11229 : nsresult
11230 0 : nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame)
11231 : {
11232 :
11233 : #ifdef DEBUG
11234 : // ReframeContainingBlock is a NASTY routine, it causes terrible performance problems
11235 : // so I want to see when it is happening! Unfortunately, it is happening way to often because
11236 : // so much content on the web causes 'special' block-in-inline frame situations and we handle them
11237 : // very poorly
11238 0 : if (gNoisyContentUpdates) {
11239 : printf("nsCSSFrameConstructor::ReframeContainingBlock frame=%p\n",
11240 0 : static_cast<void*>(aFrame));
11241 : }
11242 : #endif
11243 :
11244 : // XXXbz how exactly would we get here while isReflowing anyway? Should this
11245 : // whole test be ifdef DEBUG?
11246 0 : if (mPresShell->IsReflowLocked()) {
11247 : // don't ReframeContainingBlock, this will result in a crash
11248 : // if we remove a tree that's in reflow - see bug 121368 for testcase
11249 0 : NS_ERROR("Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a Reflow!!!");
11250 0 : return NS_OK;
11251 : }
11252 :
11253 : // Get the first "normal" ancestor of the target frame.
11254 0 : nsIFrame* containingBlock = GetIBContainingBlockFor(aFrame);
11255 0 : if (containingBlock) {
11256 : // From here we look for the containing block in case the target
11257 : // frame is already a block (which can happen when an inline frame
11258 : // wraps some of its content in an anonymous block; see
11259 : // ConstructInline)
11260 :
11261 : // NOTE: We used to get the FloatContainingBlock here, but it was often wrong.
11262 : // GetIBContainingBlock works much better and provides the correct container in all cases
11263 : // so GetFloatContainingBlock(aFrame) has been removed
11264 :
11265 : // And get the containingBlock's content
11266 0 : nsCOMPtr<nsIContent> blockContent = containingBlock->GetContent();
11267 0 : if (blockContent) {
11268 : #ifdef DEBUG
11269 0 : if (gNoisyContentUpdates) {
11270 0 : printf(" ==> blockContent=%p\n", static_cast<void*>(blockContent));
11271 : }
11272 : #endif
11273 0 : return RecreateFramesForContent(blockContent, true);
11274 : }
11275 : }
11276 :
11277 : // If we get here, we're screwed!
11278 0 : return RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
11279 0 : true);
11280 : }
11281 :
11282 : void
11283 0 : nsCSSFrameConstructor::RestyleForEmptyChange(Element* aContainer)
11284 : {
11285 : // In some cases (:empty + E, :empty ~ E), a change if the content of
11286 : // an element requires restyling its parent's siblings.
11287 0 : nsRestyleHint hint = eRestyle_Subtree;
11288 0 : nsIContent* grandparent = aContainer->GetParent();
11289 0 : if (grandparent &&
11290 0 : (grandparent->GetFlags() & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS)) {
11291 0 : hint = nsRestyleHint(hint | eRestyle_LaterSiblings);
11292 : }
11293 0 : PostRestyleEvent(aContainer, hint, NS_STYLE_HINT_NONE);
11294 0 : }
11295 :
11296 : void
11297 0 : nsCSSFrameConstructor::RestyleForAppend(Element* aContainer,
11298 : nsIContent* aFirstNewContent)
11299 : {
11300 0 : NS_ASSERTION(aContainer, "must have container for append");
11301 : #ifdef DEBUG
11302 : {
11303 0 : for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
11304 0 : NS_ASSERTION(!cur->IsRootOfAnonymousSubtree(),
11305 : "anonymous nodes should not be in child lists");
11306 : }
11307 : }
11308 : #endif
11309 : PRUint32 selectorFlags =
11310 0 : aContainer->GetFlags() & (NODE_ALL_SELECTOR_FLAGS &
11311 0 : ~NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
11312 0 : if (selectorFlags == 0)
11313 0 : return;
11314 :
11315 0 : if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
11316 : // see whether we need to restyle the container
11317 0 : bool wasEmpty = true; // :empty or :-moz-only-whitespace
11318 0 : for (nsIContent* cur = aContainer->GetFirstChild();
11319 : cur != aFirstNewContent;
11320 0 : cur = cur->GetNextSibling()) {
11321 : // We don't know whether we're testing :empty or :-moz-only-whitespace,
11322 : // so be conservative and assume :-moz-only-whitespace (i.e., make
11323 : // IsSignificantChild less likely to be true, and thus make us more
11324 : // likely to restyle).
11325 0 : if (nsStyleUtil::IsSignificantChild(cur, true, false)) {
11326 0 : wasEmpty = false;
11327 0 : break;
11328 : }
11329 : }
11330 0 : if (wasEmpty) {
11331 0 : RestyleForEmptyChange(aContainer);
11332 0 : return;
11333 : }
11334 : }
11335 :
11336 0 : if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
11337 0 : PostRestyleEvent(aContainer, eRestyle_Subtree, NS_STYLE_HINT_NONE);
11338 : // Restyling the container is the most we can do here, so we're done.
11339 0 : return;
11340 : }
11341 :
11342 0 : if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
11343 : // restyle the last element child before this node
11344 0 : for (nsIContent* cur = aFirstNewContent->GetPreviousSibling();
11345 : cur;
11346 0 : cur = cur->GetPreviousSibling()) {
11347 0 : if (cur->IsElement()) {
11348 0 : PostRestyleEvent(cur->AsElement(), eRestyle_Subtree, NS_STYLE_HINT_NONE);
11349 0 : break;
11350 : }
11351 : }
11352 : }
11353 : }
11354 :
11355 : // Needed since we can't use PostRestyleEvent on non-elements (with
11356 : // eRestyle_LaterSiblings or nsRestyleHint(eRestyle_Subtree |
11357 : // eRestyle_LaterSiblings) as appropriate).
11358 : static void
11359 0 : RestyleSiblingsStartingWith(nsCSSFrameConstructor *aFrameConstructor,
11360 : nsIContent *aStartingSibling /* may be null */)
11361 : {
11362 0 : for (nsIContent *sibling = aStartingSibling; sibling;
11363 0 : sibling = sibling->GetNextSibling()) {
11364 0 : if (sibling->IsElement()) {
11365 : aFrameConstructor->
11366 : PostRestyleEvent(sibling->AsElement(),
11367 : nsRestyleHint(eRestyle_Subtree | eRestyle_LaterSiblings),
11368 0 : NS_STYLE_HINT_NONE);
11369 0 : break;
11370 : }
11371 : }
11372 0 : }
11373 :
11374 : // Restyling for a ContentInserted or CharacterDataChanged notification.
11375 : // This could be used for ContentRemoved as well if we got the
11376 : // notification before the removal happened (and sometimes
11377 : // CharacterDataChanged is more like a removal than an addition).
11378 : // The comments are written and variables are named in terms of it being
11379 : // a ContentInserted notification.
11380 : void
11381 0 : nsCSSFrameConstructor::RestyleForInsertOrChange(Element* aContainer,
11382 : nsIContent* aChild)
11383 : {
11384 0 : NS_ASSERTION(!aChild->IsRootOfAnonymousSubtree(),
11385 : "anonymous nodes should not be in child lists");
11386 : PRUint32 selectorFlags =
11387 0 : aContainer ? (aContainer->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
11388 0 : if (selectorFlags == 0)
11389 0 : return;
11390 :
11391 0 : if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
11392 : // see whether we need to restyle the container
11393 0 : bool wasEmpty = true; // :empty or :-moz-only-whitespace
11394 0 : for (nsIContent* child = aContainer->GetFirstChild();
11395 : child;
11396 0 : child = child->GetNextSibling()) {
11397 0 : if (child == aChild)
11398 0 : continue;
11399 : // We don't know whether we're testing :empty or :-moz-only-whitespace,
11400 : // so be conservative and assume :-moz-only-whitespace (i.e., make
11401 : // IsSignificantChild less likely to be true, and thus make us more
11402 : // likely to restyle).
11403 0 : if (nsStyleUtil::IsSignificantChild(child, true, false)) {
11404 0 : wasEmpty = false;
11405 0 : break;
11406 : }
11407 : }
11408 0 : if (wasEmpty) {
11409 0 : RestyleForEmptyChange(aContainer);
11410 0 : return;
11411 : }
11412 : }
11413 :
11414 0 : if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
11415 0 : PostRestyleEvent(aContainer, eRestyle_Subtree, NS_STYLE_HINT_NONE);
11416 : // Restyling the container is the most we can do here, so we're done.
11417 0 : return;
11418 : }
11419 :
11420 0 : if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
11421 : // Restyle all later siblings.
11422 0 : RestyleSiblingsStartingWith(this, aChild->GetNextSibling());
11423 : }
11424 :
11425 0 : if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
11426 : // restyle the previously-first element child if it is after this node
11427 0 : bool passedChild = false;
11428 0 : for (nsIContent* content = aContainer->GetFirstChild();
11429 : content;
11430 0 : content = content->GetNextSibling()) {
11431 0 : if (content == aChild) {
11432 0 : passedChild = true;
11433 0 : continue;
11434 : }
11435 0 : if (content->IsElement()) {
11436 0 : if (passedChild) {
11437 : PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
11438 0 : NS_STYLE_HINT_NONE);
11439 : }
11440 0 : break;
11441 : }
11442 : }
11443 : // restyle the previously-last element child if it is before this node
11444 0 : passedChild = false;
11445 0 : for (nsIContent* content = aContainer->GetLastChild();
11446 : content;
11447 0 : content = content->GetPreviousSibling()) {
11448 0 : if (content == aChild) {
11449 0 : passedChild = true;
11450 0 : continue;
11451 : }
11452 0 : if (content->IsElement()) {
11453 0 : if (passedChild) {
11454 : PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
11455 0 : NS_STYLE_HINT_NONE);
11456 : }
11457 0 : break;
11458 : }
11459 : }
11460 : }
11461 : }
11462 :
11463 : void
11464 0 : nsCSSFrameConstructor::RestyleForRemove(Element* aContainer,
11465 : nsIContent* aOldChild,
11466 : nsIContent* aFollowingSibling)
11467 : {
11468 0 : NS_ASSERTION(!aOldChild->IsRootOfAnonymousSubtree(),
11469 : "anonymous nodes should not be in child lists");
11470 : PRUint32 selectorFlags =
11471 0 : aContainer ? (aContainer->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
11472 0 : if (selectorFlags == 0)
11473 0 : return;
11474 :
11475 0 : if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
11476 : // see whether we need to restyle the container
11477 0 : bool isEmpty = true; // :empty or :-moz-only-whitespace
11478 0 : for (nsIContent* child = aContainer->GetFirstChild();
11479 : child;
11480 0 : child = child->GetNextSibling()) {
11481 : // We don't know whether we're testing :empty or :-moz-only-whitespace,
11482 : // so be conservative and assume :-moz-only-whitespace (i.e., make
11483 : // IsSignificantChild less likely to be true, and thus make us more
11484 : // likely to restyle).
11485 0 : if (nsStyleUtil::IsSignificantChild(child, true, false)) {
11486 0 : isEmpty = false;
11487 0 : break;
11488 : }
11489 : }
11490 0 : if (isEmpty) {
11491 0 : RestyleForEmptyChange(aContainer);
11492 0 : return;
11493 : }
11494 : }
11495 :
11496 0 : if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
11497 0 : PostRestyleEvent(aContainer, eRestyle_Subtree, NS_STYLE_HINT_NONE);
11498 : // Restyling the container is the most we can do here, so we're done.
11499 0 : return;
11500 : }
11501 :
11502 0 : if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
11503 : // Restyle all later siblings.
11504 0 : RestyleSiblingsStartingWith(this, aFollowingSibling);
11505 : }
11506 :
11507 0 : if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
11508 : // restyle the now-first element child if it was after aOldChild
11509 0 : bool reachedFollowingSibling = false;
11510 0 : for (nsIContent* content = aContainer->GetFirstChild();
11511 : content;
11512 0 : content = content->GetNextSibling()) {
11513 0 : if (content == aFollowingSibling) {
11514 0 : reachedFollowingSibling = true;
11515 : // do NOT continue here; we might want to restyle this node
11516 : }
11517 0 : if (content->IsElement()) {
11518 0 : if (reachedFollowingSibling) {
11519 : PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
11520 0 : NS_STYLE_HINT_NONE);
11521 : }
11522 0 : break;
11523 : }
11524 : }
11525 : // restyle the now-last element child if it was before aOldChild
11526 0 : reachedFollowingSibling = (aFollowingSibling == nsnull);
11527 0 : for (nsIContent* content = aContainer->GetLastChild();
11528 : content;
11529 0 : content = content->GetPreviousSibling()) {
11530 0 : if (content->IsElement()) {
11531 0 : if (reachedFollowingSibling) {
11532 0 : PostRestyleEvent(content->AsElement(), eRestyle_Subtree, NS_STYLE_HINT_NONE);
11533 : }
11534 0 : break;
11535 : }
11536 0 : if (content == aFollowingSibling) {
11537 0 : reachedFollowingSibling = true;
11538 : }
11539 : }
11540 : }
11541 : }
11542 :
11543 :
11544 : void
11545 0 : nsCSSFrameConstructor::RebuildAllStyleData(nsChangeHint aExtraHint)
11546 : {
11547 0 : NS_ASSERTION(!(aExtraHint & nsChangeHint_ReconstructFrame),
11548 : "Should not reconstruct the root of the frame tree. "
11549 : "Use ReconstructDocElementHierarchy instead.");
11550 :
11551 0 : mRebuildAllStyleData = false;
11552 0 : NS_UpdateHint(aExtraHint, mRebuildAllExtraHint);
11553 0 : mRebuildAllExtraHint = nsChangeHint(0);
11554 :
11555 0 : if (!mPresShell || !mPresShell->GetRootFrame())
11556 0 : return;
11557 :
11558 : // Make sure that the viewmanager will outlive the presshell
11559 0 : nsCOMPtr<nsIViewManager> vm = mPresShell->GetViewManager();
11560 :
11561 : // Processing the style changes could cause a flush that propagates to
11562 : // the parent frame and thus destroys the pres shell.
11563 0 : nsCOMPtr<nsIPresShell> kungFuDeathGrip(mPresShell);
11564 :
11565 : // We may reconstruct frames below and hence process anything that is in the
11566 : // tree. We don't want to get notified to process those items again after.
11567 0 : mPresShell->GetDocument()->FlushPendingNotifications(Flush_ContentAndNotify);
11568 :
11569 0 : nsAutoScriptBlocker scriptBlocker;
11570 :
11571 : // Tell the style set to get the old rule tree out of the way
11572 : // so we can recalculate while maintaining rule tree immutability
11573 0 : nsresult rv = mPresShell->StyleSet()->BeginReconstruct();
11574 0 : if (NS_FAILED(rv)) {
11575 : return;
11576 : }
11577 :
11578 0 : nsPresContext *presContext = mPresShell->GetPresContext();
11579 0 : presContext->SetProcessingRestyles(true);
11580 : // Recalculate all of the style contexts for the document
11581 : // Note that we can ignore the return value of ComputeStyleChangeFor
11582 : // because we never need to reframe the root frame
11583 : // XXX This could be made faster by not rerunning rule matching
11584 : // (but note that nsPresShell::SetPreferenceStyleRules currently depends
11585 : // on us re-running rule matching here
11586 0 : nsStyleChangeList changeList;
11587 : // XXX Does it matter that we're passing aExtraHint to the real root
11588 : // frame and not the root node's primary frame?
11589 : // Note: The restyle tracker we pass in here doesn't matter.
11590 : ComputeStyleChangeFor(mPresShell->GetRootFrame(),
11591 : &changeList, aExtraHint,
11592 0 : mPendingRestyles, true);
11593 : // Process the required changes
11594 0 : ProcessRestyledFrames(changeList);
11595 0 : presContext->SetProcessingRestyles(false);
11596 :
11597 : // Make sure that we process any pending animation restyles from the
11598 : // above style change. Note that we can *almost* implement the above
11599 : // by just posting a style change -- except we really need to restyle
11600 : // the root frame rather than the root element's primary frame.
11601 0 : ProcessPendingRestyles();
11602 :
11603 : // Tell the style set it's safe to destroy the old rule tree. We
11604 : // must do this after the ProcessRestyledFrames call in case the
11605 : // change list has frame reconstructs in it (since frames to be
11606 : // reconstructed will still have their old style context pointers
11607 : // until they are destroyed).
11608 0 : mPresShell->StyleSet()->EndReconstruct();
11609 : }
11610 :
11611 : void
11612 0 : nsCSSFrameConstructor::ProcessPendingRestyles()
11613 : {
11614 0 : NS_PRECONDITION(mDocument, "No document? Pshaw!");
11615 0 : NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
11616 : "Missing a script blocker!");
11617 :
11618 : // Process non-animation restyles...
11619 0 : nsPresContext *presContext = mPresShell->GetPresContext();
11620 0 : NS_ABORT_IF_FALSE(!presContext->IsProcessingRestyles(),
11621 : "Nesting calls to ProcessPendingRestyles?");
11622 0 : presContext->SetProcessingRestyles(true);
11623 :
11624 0 : mPendingRestyles.ProcessRestyles();
11625 :
11626 : #ifdef DEBUG
11627 0 : PRUint32 oldPendingRestyleCount = mPendingRestyles.Count();
11628 : #endif
11629 :
11630 : // ...and then process animation restyles. This needs to happen
11631 : // second because we need to start animations that resulted from the
11632 : // first set of restyles (e.g., CSS transitions with negative
11633 : // transition-delay), and because we need to immediately
11634 : // restyle-with-animation any just-restyled elements that are
11635 : // mid-transition (since processing the non-animation restyle ignores
11636 : // the running transition so it can check for a new change on the same
11637 : // property, and then posts an immediate animation style change).
11638 0 : presContext->SetProcessingAnimationStyleChange(true);
11639 0 : mPendingAnimationRestyles.ProcessRestyles();
11640 0 : presContext->SetProcessingAnimationStyleChange(false);
11641 :
11642 0 : presContext->SetProcessingRestyles(false);
11643 0 : NS_POSTCONDITION(mPendingRestyles.Count() == oldPendingRestyleCount,
11644 : "We should not have posted new non-animation restyles while "
11645 : "processing animation restyles");
11646 :
11647 0 : if (mRebuildAllStyleData) {
11648 : // We probably wasted a lot of work up above, but this seems safest
11649 : // and it should be rarely used.
11650 : // This might add us as a refresh observer again; that's ok.
11651 0 : RebuildAllStyleData(nsChangeHint(0));
11652 : }
11653 0 : }
11654 :
11655 : void
11656 0 : nsCSSFrameConstructor::PostRestyleEventCommon(Element* aElement,
11657 : nsRestyleHint aRestyleHint,
11658 : nsChangeHint aMinChangeHint,
11659 : bool aForAnimation)
11660 : {
11661 0 : if (NS_UNLIKELY(mPresShell->IsDestroying())) {
11662 0 : return;
11663 : }
11664 :
11665 0 : if (aRestyleHint == 0 && !aMinChangeHint) {
11666 : // Nothing to do here
11667 0 : return;
11668 : }
11669 :
11670 : RestyleTracker& tracker =
11671 0 : aForAnimation ? mPendingAnimationRestyles : mPendingRestyles;
11672 0 : tracker.AddPendingRestyle(aElement, aRestyleHint, aMinChangeHint);
11673 :
11674 0 : PostRestyleEventInternal(false);
11675 : }
11676 :
11677 : void
11678 0 : nsCSSFrameConstructor::PostRestyleEventInternal(bool aForLazyConstruction)
11679 : {
11680 : // Make sure we're not in a style refresh; if we are, we still have
11681 : // a call to ProcessPendingRestyles coming and there's no need to
11682 : // add ourselves as a refresh observer until then.
11683 0 : bool inRefresh = !aForLazyConstruction && mInStyleRefresh;
11684 0 : if (!mObservingRefreshDriver && !inRefresh) {
11685 : mObservingRefreshDriver = mPresShell->GetPresContext()->RefreshDriver()->
11686 0 : AddStyleFlushObserver(mPresShell);
11687 : }
11688 :
11689 : // Unconditionally flag our document as needing a flush. The other
11690 : // option here would be a dedicated boolean to track whether we need
11691 : // to do so (set here and unset in ProcessPendingRestyles).
11692 0 : mPresShell->GetDocument()->SetNeedStyleFlush();
11693 0 : }
11694 :
11695 : void
11696 0 : nsCSSFrameConstructor::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint)
11697 : {
11698 0 : NS_ASSERTION(!(aExtraHint & nsChangeHint_ReconstructFrame),
11699 : "Should not reconstruct the root of the frame tree. "
11700 : "Use ReconstructDocElementHierarchy instead.");
11701 :
11702 0 : mRebuildAllStyleData = true;
11703 0 : NS_UpdateHint(mRebuildAllExtraHint, aExtraHint);
11704 : // Get a restyle event posted if necessary
11705 0 : PostRestyleEventInternal(false);
11706 0 : }
11707 :
11708 : nsresult
11709 0 : nsCSSFrameConstructor::GenerateChildFrames(nsIFrame* aFrame)
11710 : {
11711 : {
11712 0 : nsAutoScriptBlocker scriptBlocker;
11713 0 : BeginUpdate();
11714 :
11715 0 : nsFrameItems childItems;
11716 0 : nsFrameConstructorState state(mPresShell, nsnull, nsnull, nsnull);
11717 : // We don't have a parent frame with a pending binding constructor here,
11718 : // so no need to worry about ordering of the kids' constructors with it.
11719 : // Pass null for the PendingBinding.
11720 : nsresult rv = ProcessChildren(state, aFrame->GetContent(), aFrame->GetStyleContext(),
11721 : aFrame, false, childItems, false,
11722 0 : nsnull);
11723 0 : if (NS_FAILED(rv)) {
11724 0 : EndUpdate();
11725 0 : return rv;
11726 : }
11727 :
11728 0 : aFrame->SetInitialChildList(kPrincipalList, childItems);
11729 :
11730 0 : EndUpdate();
11731 : }
11732 :
11733 : #ifdef ACCESSIBILITY
11734 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
11735 0 : if (accService) {
11736 0 : nsIContent* container = aFrame->GetContent();
11737 0 : nsIContent* child = container->GetFirstChild();
11738 0 : if (child) {
11739 0 : accService->ContentRangeInserted(mPresShell, container, child, nsnull);
11740 : }
11741 : }
11742 : #endif
11743 :
11744 : // call XBL constructors after the frames are created
11745 0 : mPresShell->GetDocument()->BindingManager()->ProcessAttachedQueue();
11746 :
11747 0 : return NS_OK;
11748 : }
11749 :
11750 : //////////////////////////////////////////////////////////
11751 : // nsCSSFrameConstructor::FrameConstructionItem methods //
11752 : //////////////////////////////////////////////////////////
11753 : bool
11754 0 : nsCSSFrameConstructor::
11755 : FrameConstructionItem::IsWhitespace(nsFrameConstructorState& aState) const
11756 : {
11757 0 : NS_PRECONDITION(aState.mCreatingExtraFrames ||
11758 : !mContent->GetPrimaryFrame(), "How did that happen?");
11759 0 : if (!mIsText) {
11760 0 : return false;
11761 : }
11762 : mContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
11763 0 : NS_REFRAME_IF_WHITESPACE);
11764 0 : return mContent->TextIsOnlyWhitespace();
11765 : }
11766 :
11767 : //////////////////////////////////////////////////////////////
11768 : // nsCSSFrameConstructor::FrameConstructionItemList methods //
11769 : //////////////////////////////////////////////////////////////
11770 : void
11771 0 : nsCSSFrameConstructor::FrameConstructionItemList::
11772 : AdjustCountsForItem(FrameConstructionItem* aItem, PRInt32 aDelta)
11773 : {
11774 0 : NS_PRECONDITION(aDelta == 1 || aDelta == -1, "Unexpected delta");
11775 0 : mItemCount += aDelta;
11776 0 : if (aItem->mIsAllInline) {
11777 0 : mInlineCount += aDelta;
11778 : }
11779 0 : if (aItem->mIsBlock) {
11780 0 : mBlockCount += aDelta;
11781 : }
11782 0 : if (aItem->mIsLineParticipant) {
11783 0 : mLineParticipantCount += aDelta;
11784 : }
11785 0 : mDesiredParentCounts[aItem->DesiredParentType()] += aDelta;
11786 0 : }
11787 :
11788 : ////////////////////////////////////////////////////////////////////////
11789 : // nsCSSFrameConstructor::FrameConstructionItemList::Iterator methods //
11790 : ////////////////////////////////////////////////////////////////////////
11791 : inline bool
11792 0 : nsCSSFrameConstructor::FrameConstructionItemList::
11793 : Iterator::SkipItemsWantingParentType(ParentType aParentType)
11794 : {
11795 0 : NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
11796 0 : while (item().DesiredParentType() == aParentType) {
11797 0 : Next();
11798 0 : if (IsDone()) {
11799 0 : return true;
11800 : }
11801 : }
11802 0 : return false;
11803 : }
11804 :
11805 : inline bool
11806 0 : nsCSSFrameConstructor::FrameConstructionItemList::
11807 : Iterator::SkipWhitespace(nsFrameConstructorState& aState)
11808 : {
11809 0 : NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
11810 0 : NS_PRECONDITION(item().IsWhitespace(aState), "Not pointing to whitespace?");
11811 0 : do {
11812 0 : Next();
11813 0 : if (IsDone()) {
11814 0 : return true;
11815 : }
11816 0 : } while (item().IsWhitespace(aState));
11817 :
11818 0 : return false;
11819 : }
11820 :
11821 : void
11822 0 : nsCSSFrameConstructor::FrameConstructionItemList::
11823 : Iterator::AppendItemToList(FrameConstructionItemList& aTargetList)
11824 : {
11825 0 : NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
11826 0 : NS_PRECONDITION(!IsDone(), "should not be done");
11827 :
11828 0 : FrameConstructionItem* item = ToItem(mCurrent);
11829 0 : Next();
11830 0 : PR_REMOVE_LINK(item);
11831 0 : PR_APPEND_LINK(item, &aTargetList.mItems);
11832 :
11833 0 : mList.AdjustCountsForItem(item, -1);
11834 0 : aTargetList.AdjustCountsForItem(item, 1);
11835 0 : }
11836 :
11837 : void
11838 0 : nsCSSFrameConstructor::FrameConstructionItemList::
11839 : Iterator::AppendItemsToList(const Iterator& aEnd,
11840 : FrameConstructionItemList& aTargetList)
11841 : {
11842 0 : NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
11843 0 : NS_PRECONDITION(mEnd == aEnd.mEnd, "end iterator for some other list?");
11844 :
11845 0 : if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty()) {
11846 0 : do {
11847 0 : AppendItemToList(aTargetList);
11848 : } while (*this != aEnd);
11849 0 : return;
11850 : }
11851 :
11852 : // move over the list of items
11853 0 : PR_INSERT_AFTER(&aTargetList.mItems, &mList.mItems);
11854 0 : PR_REMOVE_LINK(&mList.mItems);
11855 :
11856 : // Copy over the various counters
11857 0 : aTargetList.mInlineCount = mList.mInlineCount;
11858 0 : aTargetList.mBlockCount = mList.mBlockCount;
11859 0 : aTargetList.mLineParticipantCount = mList.mLineParticipantCount;
11860 0 : aTargetList.mItemCount = mList.mItemCount;
11861 : memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
11862 0 : sizeof(aTargetList.mDesiredParentCounts));
11863 :
11864 : // reset mList
11865 0 : new (&mList) FrameConstructionItemList();
11866 :
11867 : // Point ourselves to aEnd, as advertised
11868 0 : mCurrent = mEnd = &mList.mItems;
11869 0 : NS_POSTCONDITION(*this == aEnd, "How did that happen?");
11870 : }
11871 :
11872 : void
11873 0 : nsCSSFrameConstructor::FrameConstructionItemList::
11874 : Iterator::InsertItem(FrameConstructionItem* aItem)
11875 : {
11876 : // Just insert the item before us. There's no magic here.
11877 0 : PR_INSERT_BEFORE(aItem, mCurrent);
11878 0 : mList.AdjustCountsForItem(aItem, 1);
11879 :
11880 0 : NS_POSTCONDITION(PR_NEXT_LINK(aItem) == mCurrent, "How did that happen?");
11881 0 : }
11882 :
11883 : void
11884 0 : nsCSSFrameConstructor::FrameConstructionItemList::
11885 : Iterator::DeleteItemsTo(const Iterator& aEnd)
11886 : {
11887 0 : NS_PRECONDITION(mEnd == aEnd.mEnd, "end iterator for some other list?");
11888 0 : NS_PRECONDITION(*this != aEnd, "Shouldn't be at aEnd yet");
11889 :
11890 0 : do {
11891 0 : NS_ASSERTION(!IsDone(), "Ran off end of list?");
11892 0 : FrameConstructionItem* item = ToItem(mCurrent);
11893 0 : Next();
11894 0 : PR_REMOVE_LINK(item);
11895 0 : mList.AdjustCountsForItem(item, -1);
11896 0 : delete item;
11897 : } while (*this != aEnd);
11898 0 : }
|