1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/base/nsCSSFrameConstructor.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,11393 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +// vim:cindent:ts=2:et:sw=2: 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * construction of a frame tree that is nearly isomorphic to the content 1.12 + * tree and updating of that tree in response to dynamic changes 1.13 + */ 1.14 + 1.15 +#include "nsCSSFrameConstructor.h" 1.16 + 1.17 +#include "mozilla/AutoRestore.h" 1.18 +#include "mozilla/DebugOnly.h" 1.19 +#include "mozilla/dom/HTMLSelectElement.h" 1.20 +#include "mozilla/EventStates.h" 1.21 +#include "mozilla/Likely.h" 1.22 +#include "mozilla/LinkedList.h" 1.23 +#include "nsAbsoluteContainingBlock.h" 1.24 +#include "nsIAtom.h" 1.25 +#include "nsIFrameInlines.h" 1.26 +#include "nsGkAtoms.h" 1.27 +#include "nsPresContext.h" 1.28 +#include "nsIDocument.h" 1.29 +#include "nsTableFrame.h" 1.30 +#include "nsTableColFrame.h" 1.31 +#include "nsIDOMHTMLDocument.h" 1.32 +#include "nsHTMLParts.h" 1.33 +#include "nsIPresShell.h" 1.34 +#include "nsUnicharUtils.h" 1.35 +#include "nsStyleSet.h" 1.36 +#include "nsViewManager.h" 1.37 +#include "nsStyleConsts.h" 1.38 +#include "nsIDOMXULElement.h" 1.39 +#include "nsContainerFrame.h" 1.40 +#include "nsNameSpaceManager.h" 1.41 +#include "nsIComboboxControlFrame.h" 1.42 +#include "nsIListControlFrame.h" 1.43 +#include "nsIDOMCharacterData.h" 1.44 +#include "nsPlaceholderFrame.h" 1.45 +#include "nsTableRowGroupFrame.h" 1.46 +#include "nsIFormControl.h" 1.47 +#include "nsCSSAnonBoxes.h" 1.48 +#include "nsTextFragment.h" 1.49 +#include "nsIAnonymousContentCreator.h" 1.50 +#include "nsBindingManager.h" 1.51 +#include "nsXBLBinding.h" 1.52 +#include "nsContentUtils.h" 1.53 +#include "nsIScriptError.h" 1.54 +#ifdef XP_MACOSX 1.55 +#include "nsIDocShell.h" 1.56 +#endif 1.57 +#include "ChildIterator.h" 1.58 +#include "nsError.h" 1.59 +#include "nsLayoutUtils.h" 1.60 +#include "nsAutoPtr.h" 1.61 +#include "nsBoxFrame.h" 1.62 +#include "nsBoxLayout.h" 1.63 +#include "nsFlexContainerFrame.h" 1.64 +#include "nsGridContainerFrame.h" 1.65 +#include "nsImageFrame.h" 1.66 +#include "nsIObjectLoadingContent.h" 1.67 +#include "nsTArray.h" 1.68 +#include "nsGenericDOMDataNode.h" 1.69 +#include "mozilla/dom/Element.h" 1.70 +#include "nsAutoLayoutPhase.h" 1.71 +#include "nsStyleStructInlines.h" 1.72 +#include "nsPageContentFrame.h" 1.73 +#include "RestyleManager.h" 1.74 +#include "StickyScrollContainer.h" 1.75 +#include "nsFieldSetFrame.h" 1.76 + 1.77 +#ifdef MOZ_XUL 1.78 +#include "nsIRootBox.h" 1.79 +#endif 1.80 +#ifdef ACCESSIBILITY 1.81 +#include "nsAccessibilityService.h" 1.82 +#endif 1.83 + 1.84 +#include "nsBlockFrame.h" 1.85 + 1.86 +#include "nsIScrollableFrame.h" 1.87 + 1.88 +#include "nsXBLService.h" 1.89 + 1.90 +#undef NOISY_FIRST_LETTER 1.91 + 1.92 +#include "nsMathMLParts.h" 1.93 +#include "mozilla/dom/SVGTests.h" 1.94 +#include "nsSVGUtils.h" 1.95 + 1.96 +#include "nsRefreshDriver.h" 1.97 +#include "nsRuleProcessorData.h" 1.98 +#include "nsTextNode.h" 1.99 + 1.100 +using namespace mozilla; 1.101 +using namespace mozilla::dom; 1.102 + 1.103 +// An alias for convenience. 1.104 +static const nsIFrame::ChildListID kPrincipalList = nsIFrame::kPrincipalList; 1.105 + 1.106 +nsIFrame* 1.107 +NS_NewHTMLCanvasFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.108 + 1.109 +nsIFrame* 1.110 +NS_NewHTMLVideoFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.111 + 1.112 +nsIFrame* 1.113 +NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.114 +nsIFrame* 1.115 +NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.116 +nsIFrame* 1.117 +NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.118 +nsIFrame* 1.119 +NS_NewSVGPathGeometryFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.120 +nsIFrame* 1.121 +NS_NewSVGGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.122 +nsIFrame* 1.123 +NS_NewSVGGenericContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.124 +nsIFrame* 1.125 +NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.126 +nsIFrame* 1.127 +NS_NewSVGAFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.128 +nsIFrame* 1.129 +NS_NewSVGSwitchFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.130 +nsIFrame* 1.131 +NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.132 +nsIFrame* 1.133 +NS_NewSVGContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.134 +nsIFrame* 1.135 +NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.136 +nsIFrame* 1.137 +NS_NewSVGViewFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.138 +extern nsIFrame* 1.139 +NS_NewSVGLinearGradientFrame(nsIPresShell *aPresShell, nsStyleContext* aContext); 1.140 +extern nsIFrame* 1.141 +NS_NewSVGRadialGradientFrame(nsIPresShell *aPresShell, nsStyleContext* aContext); 1.142 +extern nsIFrame* 1.143 +NS_NewSVGStopFrame(nsIPresShell *aPresShell, nsStyleContext* aContext); 1.144 +nsIFrame* 1.145 +NS_NewSVGMarkerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.146 +nsIFrame* 1.147 +NS_NewSVGMarkerAnonChildFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.148 +extern nsIFrame* 1.149 +NS_NewSVGImageFrame(nsIPresShell *aPresShell, nsStyleContext* aContext); 1.150 +nsIFrame* 1.151 +NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.152 +nsIFrame* 1.153 +NS_NewSVGFilterFrame(nsIPresShell *aPresShell, nsStyleContext* aContext); 1.154 +nsIFrame* 1.155 +NS_NewSVGPatternFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.156 +nsIFrame* 1.157 +NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.158 +nsIFrame* 1.159 +NS_NewSVGFEContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.160 +nsIFrame* 1.161 +NS_NewSVGFELeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.162 +nsIFrame* 1.163 +NS_NewSVGFEImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.164 +nsIFrame* 1.165 +NS_NewSVGFEUnstyledLeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.166 + 1.167 +#include "nsINodeInfo.h" 1.168 +#include "prenv.h" 1.169 +#include "nsNodeInfoManager.h" 1.170 +#include "nsContentCreatorFunctions.h" 1.171 + 1.172 +#ifdef DEBUG 1.173 +// Set the environment variable GECKO_FRAMECTOR_DEBUG_FLAGS to one or 1.174 +// more of the following flags (comma separated) for handy debug 1.175 +// output. 1.176 +static bool gNoisyContentUpdates = false; 1.177 +static bool gReallyNoisyContentUpdates = false; 1.178 +static bool gNoisyInlineConstruction = false; 1.179 + 1.180 +struct FrameCtorDebugFlags { 1.181 + const char* name; 1.182 + bool* on; 1.183 +}; 1.184 + 1.185 +static FrameCtorDebugFlags gFlags[] = { 1.186 + { "content-updates", &gNoisyContentUpdates }, 1.187 + { "really-noisy-content-updates", &gReallyNoisyContentUpdates }, 1.188 + { "noisy-inline", &gNoisyInlineConstruction } 1.189 +}; 1.190 + 1.191 +#define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0])) 1.192 +#endif 1.193 + 1.194 + 1.195 +#ifdef MOZ_XUL 1.196 +#include "nsMenuFrame.h" 1.197 +#include "nsPopupSetFrame.h" 1.198 +#include "nsTreeColFrame.h" 1.199 +#include "nsIBoxObject.h" 1.200 +#include "nsPIListBoxObject.h" 1.201 +#include "nsListBoxBodyFrame.h" 1.202 +#include "nsListItemFrame.h" 1.203 +#include "nsXULLabelFrame.h" 1.204 + 1.205 +//------------------------------------------------------------------ 1.206 + 1.207 +nsIFrame* 1.208 +NS_NewAutoRepeatBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.209 + 1.210 +nsIFrame* 1.211 +NS_NewRootBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.212 + 1.213 +nsIFrame* 1.214 +NS_NewDocElementBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.215 + 1.216 +nsIFrame* 1.217 +NS_NewThumbFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.218 + 1.219 +nsIFrame* 1.220 +NS_NewDeckFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.221 + 1.222 +nsIFrame* 1.223 +NS_NewLeafBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.224 + 1.225 +nsIFrame* 1.226 +NS_NewStackFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.227 + 1.228 +nsIFrame* 1.229 +NS_NewProgressMeterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.230 + 1.231 +nsIFrame* 1.232 +NS_NewRangeFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.233 + 1.234 +nsIFrame* 1.235 +NS_NewImageBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.236 + 1.237 +nsIFrame* 1.238 +NS_NewTextBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.239 + 1.240 +nsIFrame* 1.241 +NS_NewGroupBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.242 + 1.243 +nsIFrame* 1.244 +NS_NewButtonBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.245 + 1.246 +nsIFrame* 1.247 +NS_NewSplitterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.248 + 1.249 +nsIFrame* 1.250 +NS_NewMenuPopupFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.251 + 1.252 +nsIFrame* 1.253 +NS_NewPopupSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.254 + 1.255 +nsIFrame* 1.256 +NS_NewMenuFrame (nsIPresShell* aPresShell, nsStyleContext* aContext, uint32_t aFlags); 1.257 + 1.258 +nsIFrame* 1.259 +NS_NewMenuBarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.260 + 1.261 +nsIFrame* 1.262 +NS_NewTreeBodyFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.263 + 1.264 +// grid 1.265 +nsresult 1.266 +NS_NewGridLayout2 ( nsIPresShell* aPresShell, nsBoxLayout** aNewLayout ); 1.267 +nsIFrame* 1.268 +NS_NewGridRowLeafFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.269 +nsIFrame* 1.270 +NS_NewGridRowGroupFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.271 + 1.272 +// end grid 1.273 + 1.274 +nsIFrame* 1.275 +NS_NewTitleBarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.276 + 1.277 +nsIFrame* 1.278 +NS_NewResizerFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.279 + 1.280 + 1.281 +#endif 1.282 + 1.283 +nsIFrame* 1.284 +NS_NewHTMLScrollFrame (nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot); 1.285 + 1.286 +nsIFrame* 1.287 +NS_NewXULScrollFrame (nsIPresShell* aPresShell, nsStyleContext* aContext, 1.288 + bool aIsRoot, bool aClipAllDescendants); 1.289 + 1.290 +nsIFrame* 1.291 +NS_NewSliderFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.292 + 1.293 +nsIFrame* 1.294 +NS_NewScrollbarFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.295 + 1.296 +nsIFrame* 1.297 +NS_NewScrollbarButtonFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); 1.298 + 1.299 + 1.300 +#ifdef NOISY_FINDFRAME 1.301 +static int32_t FFWC_totalCount=0; 1.302 +static int32_t FFWC_doLoop=0; 1.303 +static int32_t FFWC_doSibling=0; 1.304 +static int32_t FFWC_recursions=0; 1.305 +static int32_t FFWC_nextInFlows=0; 1.306 +#endif 1.307 + 1.308 +// Returns true if aFrame is an anonymous flex item 1.309 +static inline bool 1.310 +IsAnonymousFlexItem(const nsIFrame* aFrame) 1.311 +{ 1.312 + const nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo(); 1.313 + return pseudoType == nsCSSAnonBoxes::anonymousFlexItem; 1.314 +} 1.315 + 1.316 +static inline nsIFrame* 1.317 +GetFieldSetBlockFrame(nsIFrame* aFieldsetFrame) 1.318 +{ 1.319 + // Depends on the fieldset child frame order - see ConstructFieldSetFrame() below. 1.320 + nsIFrame* firstChild = aFieldsetFrame->GetFirstPrincipalChild(); 1.321 + nsIFrame* inner = firstChild && firstChild->GetNextSibling() ? firstChild->GetNextSibling() : firstChild; 1.322 + return inner ? inner->GetContentInsertionFrame() : nullptr; 1.323 +} 1.324 + 1.325 +#define FCDATA_DECL(_flags, _func) \ 1.326 + { _flags, { (FrameCreationFunc)_func }, nullptr, nullptr } 1.327 +#define FCDATA_WITH_WRAPPING_BLOCK(_flags, _func, _anon_box) \ 1.328 + { _flags | FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS, \ 1.329 + { (FrameCreationFunc)_func }, nullptr, &_anon_box } 1.330 + 1.331 +//---------------------------------------------------------------------- 1.332 + 1.333 +/** 1.334 + * True if aFrame is an actual inline frame in the sense of non-replaced 1.335 + * display:inline CSS boxes. In other words, it can be affected by {ib} 1.336 + * splitting and can contain first-letter frames. Basically, this is either an 1.337 + * inline frame (positioned or otherwise) or an line frame (this last because 1.338 + * it can contain first-letter and because inserting blocks in the middle of it 1.339 + * needs to terminate it). 1.340 + */ 1.341 +static bool 1.342 +IsInlineFrame(const nsIFrame* aFrame) 1.343 +{ 1.344 + return aFrame->IsFrameOfType(nsIFrame::eLineParticipant); 1.345 +} 1.346 + 1.347 +/** 1.348 + * True if aFrame is an instance of an SVG frame class or is an inline/block 1.349 + * frame being used for SVG text. 1.350 + */ 1.351 +static bool 1.352 +IsFrameForSVG(const nsIFrame* aFrame) 1.353 +{ 1.354 + return aFrame->IsFrameOfType(nsIFrame::eSVG) || 1.355 + aFrame->IsSVGText(); 1.356 +} 1.357 + 1.358 +/** 1.359 + * Returns true iff aFrame explicitly prevents its descendants from floating 1.360 + * (at least, down to the level of descendants which themselves are 1.361 + * float-containing blocks -- those will manage the floating status of any 1.362 + * lower-level descendents inside them, of course). 1.363 + */ 1.364 +static bool 1.365 +ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame) 1.366 +{ 1.367 + return aFrame->IsFrameOfType(nsIFrame::eMathML) || 1.368 + aFrame->IsBoxFrame() || 1.369 + aFrame->GetType() == nsGkAtoms::flexContainerFrame || 1.370 + aFrame->GetType() == nsGkAtoms::gridContainerFrame; 1.371 +} 1.372 + 1.373 +/** 1.374 + * If any children require a block parent, return the first such child. 1.375 + * Otherwise return null. 1.376 + */ 1.377 +static nsIContent* 1.378 +AnyKidsNeedBlockParent(nsIFrame *aFrameList) 1.379 +{ 1.380 + for (nsIFrame *k = aFrameList; k; k = k->GetNextSibling()) { 1.381 + // Line participants, such as text and inline frames, can't be 1.382 + // directly inside a XUL box; they must be wrapped in an 1.383 + // intermediate block. 1.384 + if (k->IsFrameOfType(nsIFrame::eLineParticipant)) { 1.385 + return k->GetContent(); 1.386 + } 1.387 + } 1.388 + return nullptr; 1.389 +} 1.390 + 1.391 +// Reparent a frame into a wrapper frame that is a child of its old parent. 1.392 +static void 1.393 +ReparentFrame(RestyleManager* aRestyleManager, 1.394 + nsIFrame* aNewParentFrame, 1.395 + nsIFrame* aFrame) 1.396 +{ 1.397 + aFrame->SetParent(aNewParentFrame); 1.398 + aRestyleManager->ReparentStyleContext(aFrame); 1.399 +} 1.400 + 1.401 +static void 1.402 +ReparentFrames(nsCSSFrameConstructor* aFrameConstructor, 1.403 + nsIFrame* aNewParentFrame, 1.404 + const nsFrameList& aFrameList) 1.405 +{ 1.406 + RestyleManager* restyleManager = aFrameConstructor->RestyleManager(); 1.407 + for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) { 1.408 + ReparentFrame(restyleManager, aNewParentFrame, e.get()); 1.409 + } 1.410 +} 1.411 + 1.412 +//---------------------------------------------------------------------- 1.413 +// 1.414 +// When inline frames get weird and have block frames in them, we 1.415 +// annotate them to help us respond to incremental content changes 1.416 +// more easily. 1.417 + 1.418 +static inline bool 1.419 +IsFramePartOfIBSplit(nsIFrame* aFrame) 1.420 +{ 1.421 + return (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) != 0; 1.422 +} 1.423 + 1.424 +static nsIFrame* GetIBSplitSibling(nsIFrame* aFrame) 1.425 +{ 1.426 + NS_PRECONDITION(IsFramePartOfIBSplit(aFrame), "Shouldn't call this"); 1.427 + 1.428 + // We only store the "ib-split sibling" annotation with the first 1.429 + // frame in the continuation chain. Walk back to find that frame now. 1.430 + return static_cast<nsIFrame*> 1.431 + (aFrame->FirstContinuation()-> 1.432 + Properties().Get(nsIFrame::IBSplitSibling())); 1.433 +} 1.434 + 1.435 +static nsIFrame* GetIBSplitPrevSibling(nsIFrame* aFrame) 1.436 +{ 1.437 + NS_PRECONDITION(IsFramePartOfIBSplit(aFrame), "Shouldn't call this"); 1.438 + 1.439 + // We only store the ib-split sibling annotation with the first 1.440 + // frame in the continuation chain. Walk back to find that frame now. 1.441 + return static_cast<nsIFrame*> 1.442 + (aFrame->FirstContinuation()-> 1.443 + Properties().Get(nsIFrame::IBSplitPrevSibling())); 1.444 +} 1.445 + 1.446 +static nsIFrame* 1.447 +GetLastIBSplitSibling(nsIFrame* aFrame, bool aReturnEmptyTrailingInline) 1.448 +{ 1.449 + for (nsIFrame *frame = aFrame, *next; ; frame = next) { 1.450 + next = GetIBSplitSibling(frame); 1.451 + if (!next || 1.452 + (!aReturnEmptyTrailingInline && !next->GetFirstPrincipalChild() && 1.453 + !GetIBSplitSibling(next))) { 1.454 + NS_ASSERTION(!next || !frame->IsInlineOutside(), 1.455 + "Should have a block here!"); 1.456 + return frame; 1.457 + } 1.458 + } 1.459 + NS_NOTREACHED("unreachable code"); 1.460 + return nullptr; 1.461 +} 1.462 + 1.463 +static void 1.464 +SetFrameIsIBSplit(nsIFrame* aFrame, nsIFrame* aIBSplitSibling) 1.465 +{ 1.466 + NS_PRECONDITION(aFrame, "bad args!"); 1.467 + 1.468 + // We should be the only continuation 1.469 + NS_ASSERTION(!aFrame->GetPrevContinuation(), 1.470 + "assigning ib-split sibling to other than first continuation!"); 1.471 + NS_ASSERTION(!aFrame->GetNextContinuation() || 1.472 + IsFramePartOfIBSplit(aFrame->GetNextContinuation()), 1.473 + "should have no non-ib-split continuations here"); 1.474 + 1.475 + // Mark the frame as ib-split. 1.476 + aFrame->AddStateBits(NS_FRAME_PART_OF_IBSPLIT); 1.477 + 1.478 + if (aIBSplitSibling) { 1.479 + NS_ASSERTION(!aIBSplitSibling->GetPrevContinuation(), 1.480 + "assigning something other than the first continuation as the " 1.481 + "ib-split sibling"); 1.482 + 1.483 + // Store the ib-split sibling (if we were given one) with the 1.484 + // first frame in the flow. 1.485 + FramePropertyTable* props = aFrame->PresContext()->PropertyTable(); 1.486 + props->Set(aFrame, nsIFrame::IBSplitSibling(), aIBSplitSibling); 1.487 + props->Set(aIBSplitSibling, nsIFrame::IBSplitPrevSibling(), aFrame); 1.488 + } 1.489 +} 1.490 + 1.491 +static nsIFrame* 1.492 +GetIBContainingBlockFor(nsIFrame* aFrame) 1.493 +{ 1.494 + NS_PRECONDITION(IsFramePartOfIBSplit(aFrame), 1.495 + "GetIBContainingBlockFor() should only be called on known IB frames"); 1.496 + 1.497 + // Get the first "normal" ancestor of the target frame. 1.498 + nsIFrame* parentFrame; 1.499 + do { 1.500 + parentFrame = aFrame->GetParent(); 1.501 + 1.502 + if (! parentFrame) { 1.503 + NS_ERROR("no unsplit block frame in IB hierarchy"); 1.504 + return aFrame; 1.505 + } 1.506 + 1.507 + // Note that we ignore non-ib-split frames which have a pseudo on their 1.508 + // style context -- they're not the frames we're looking for! In 1.509 + // particular, they may be hiding a real parent that _is_ in an ib-split. 1.510 + if (!IsFramePartOfIBSplit(parentFrame) && 1.511 + !parentFrame->StyleContext()->GetPseudo()) 1.512 + break; 1.513 + 1.514 + aFrame = parentFrame; 1.515 + } while (1); 1.516 + 1.517 + // post-conditions 1.518 + NS_ASSERTION(parentFrame, "no normal ancestor found for ib-split frame " 1.519 + "in GetIBContainingBlockFor"); 1.520 + NS_ASSERTION(parentFrame != aFrame, "parentFrame is actually the child frame - bogus reslt"); 1.521 + 1.522 + return parentFrame; 1.523 +} 1.524 + 1.525 +//---------------------------------------------------------------------- 1.526 + 1.527 +// Block/inline frame construction logic. We maintain a few invariants here: 1.528 +// 1.529 +// 1. Block frames contain block and inline frames. 1.530 +// 1.531 +// 2. Inline frames only contain inline frames. If an inline parent has a block 1.532 +// child then the block child is migrated upward until it lands in a block 1.533 +// parent (the inline frames containing block is where it will end up). 1.534 + 1.535 +// After this function returns, aLink is pointing to the first link at or 1.536 +// after its starting position for which the next frame is a block. If there 1.537 +// is no such link, it points to the end of the list. 1.538 +static void 1.539 +FindFirstBlock(nsFrameList::FrameLinkEnumerator& aLink) 1.540 +{ 1.541 + for ( ; !aLink.AtEnd(); aLink.Next()) { 1.542 + if (!aLink.NextFrame()->IsInlineOutside()) { 1.543 + return; 1.544 + } 1.545 + } 1.546 +} 1.547 + 1.548 +// This function returns a frame link enumerator pointing to the first link in 1.549 +// the list for which the next frame is not block. If there is no such link, 1.550 +// it points to the end of the list. 1.551 +static nsFrameList::FrameLinkEnumerator 1.552 +FindFirstNonBlock(const nsFrameList& aList) 1.553 +{ 1.554 + nsFrameList::FrameLinkEnumerator link(aList); 1.555 + for (; !link.AtEnd(); link.Next()) { 1.556 + if (link.NextFrame()->IsInlineOutside()) { 1.557 + break; 1.558 + } 1.559 + } 1.560 + return link; 1.561 +} 1.562 + 1.563 +inline void 1.564 +SetInitialSingleChild(nsIFrame* aParent, nsIFrame* aFrame) 1.565 +{ 1.566 + NS_PRECONDITION(!aFrame->GetNextSibling(), "Should be using a frame list"); 1.567 + nsFrameList temp(aFrame, aFrame); 1.568 + aParent->SetInitialChildList(kPrincipalList, temp); 1.569 +} 1.570 + 1.571 +// ----------------------------------------------------------- 1.572 + 1.573 +// Structure used when constructing formatting object trees. 1.574 +struct nsFrameItems : public nsFrameList 1.575 +{ 1.576 + // Appends the frame to the end of the list 1.577 + void AddChild(nsIFrame* aChild); 1.578 +}; 1.579 + 1.580 +void 1.581 +nsFrameItems::AddChild(nsIFrame* aChild) 1.582 +{ 1.583 + NS_PRECONDITION(aChild, "nsFrameItems::AddChild"); 1.584 + 1.585 + // It'd be really nice if we could just AppendFrames(kPrincipalList, aChild) here, 1.586 + // but some of our callers put frames that have different 1.587 + // parents (caption, I'm looking at you) on the same framelist, and 1.588 + // nsFrameList asserts if you try to do that. 1.589 + if (IsEmpty()) { 1.590 + SetFrames(aChild); 1.591 + } 1.592 + else { 1.593 + NS_ASSERTION(aChild != mLastChild, 1.594 + "Same frame being added to frame list twice?"); 1.595 + mLastChild->SetNextSibling(aChild); 1.596 + mLastChild = nsLayoutUtils::GetLastSibling(aChild); 1.597 + } 1.598 +} 1.599 + 1.600 +// ----------------------------------------------------------- 1.601 + 1.602 +// Structure used when constructing formatting object trees. Contains 1.603 +// state information needed for absolutely positioned elements 1.604 +struct nsAbsoluteItems : nsFrameItems { 1.605 + // containing block for absolutely positioned elements 1.606 + nsIFrame* containingBlock; 1.607 + 1.608 + nsAbsoluteItems(nsIFrame* aContainingBlock); 1.609 +#ifdef DEBUG 1.610 + // XXXbz Does this need a debug-only assignment operator that nulls out the 1.611 + // childList in the nsAbsoluteItems we're copying? Introducing a difference 1.612 + // between debug and non-debug behavior seems bad, so I guess not... 1.613 + ~nsAbsoluteItems() { 1.614 + NS_ASSERTION(!FirstChild(), 1.615 + "Dangling child list. Someone forgot to insert it?"); 1.616 + } 1.617 +#endif 1.618 + 1.619 + // Appends the frame to the end of the list 1.620 + void AddChild(nsIFrame* aChild); 1.621 +}; 1.622 + 1.623 +nsAbsoluteItems::nsAbsoluteItems(nsIFrame* aContainingBlock) 1.624 + : containingBlock(aContainingBlock) 1.625 +{ 1.626 +} 1.627 + 1.628 +// Additional behavior is that it sets the frame's NS_FRAME_OUT_OF_FLOW flag 1.629 +void 1.630 +nsAbsoluteItems::AddChild(nsIFrame* aChild) 1.631 +{ 1.632 + NS_ASSERTION(aChild->PresContext()->FrameManager()-> 1.633 + GetPlaceholderFrameFor(aChild), 1.634 + "Child without placeholder being added to nsAbsoluteItems?"); 1.635 + aChild->AddStateBits(NS_FRAME_OUT_OF_FLOW); 1.636 + nsFrameItems::AddChild(aChild); 1.637 +} 1.638 + 1.639 +// ----------------------------------------------------------- 1.640 + 1.641 +// Structure for saving the existing state when pushing/poping containing 1.642 +// blocks. The destructor restores the state to its previous state 1.643 +class MOZ_STACK_CLASS nsFrameConstructorSaveState { 1.644 +public: 1.645 + typedef nsIFrame::ChildListID ChildListID; 1.646 + nsFrameConstructorSaveState(); 1.647 + ~nsFrameConstructorSaveState(); 1.648 + 1.649 +private: 1.650 + nsAbsoluteItems* mItems; // pointer to struct whose data we save/restore 1.651 + nsAbsoluteItems mSavedItems; // copy of original data 1.652 + 1.653 + // The name of the child list in which our frames would belong 1.654 + ChildListID mChildListID; 1.655 + nsFrameConstructorState* mState; 1.656 + 1.657 + // State used only when we're saving the abs-pos state for a transformed 1.658 + // element. 1.659 + nsAbsoluteItems mSavedFixedItems; 1.660 + 1.661 + bool mSavedFixedPosIsAbsPos; 1.662 + 1.663 + friend class nsFrameConstructorState; 1.664 +}; 1.665 + 1.666 +// Structure used to keep track of a list of bindings we need to call 1.667 +// AddToAttachedQueue on. These should be in post-order depth-first 1.668 +// flattened tree traversal order. 1.669 +struct PendingBinding : public LinkedListElement<PendingBinding> 1.670 +{ 1.671 +#ifdef NS_BUILD_REFCNT_LOGGING 1.672 + PendingBinding() { 1.673 + MOZ_COUNT_CTOR(PendingBinding); 1.674 + } 1.675 + ~PendingBinding() { 1.676 + MOZ_COUNT_DTOR(PendingBinding); 1.677 + } 1.678 +#endif 1.679 + 1.680 + nsRefPtr<nsXBLBinding> mBinding; 1.681 +}; 1.682 + 1.683 +// Structure used for maintaining state information during the 1.684 +// frame construction process 1.685 +class MOZ_STACK_CLASS nsFrameConstructorState { 1.686 +public: 1.687 + typedef nsIFrame::ChildListID ChildListID; 1.688 + 1.689 + nsPresContext *mPresContext; 1.690 + nsIPresShell *mPresShell; 1.691 + nsFrameManager *mFrameManager; 1.692 + 1.693 +#ifdef MOZ_XUL 1.694 + // Frames destined for the kPopupList. 1.695 + nsAbsoluteItems mPopupItems; 1.696 +#endif 1.697 + 1.698 + // Containing block information for out-of-flow frames. 1.699 + nsAbsoluteItems mFixedItems; 1.700 + nsAbsoluteItems mAbsoluteItems; 1.701 + nsAbsoluteItems mFloatedItems; 1.702 + 1.703 + nsCOMPtr<nsILayoutHistoryState> mFrameState; 1.704 + // These bits will be added to the state bits of any frame we construct 1.705 + // using this state. 1.706 + nsFrameState mAdditionalStateBits; 1.707 + 1.708 + // When working with the -moz-transform property, we want to hook 1.709 + // the abs-pos and fixed-pos lists together, since transformed 1.710 + // elements are fixed-pos containing blocks. This flag determines 1.711 + // whether or not we want to wire the fixed-pos and abs-pos lists 1.712 + // together. 1.713 + bool mFixedPosIsAbsPos; 1.714 + 1.715 + // A boolean to indicate whether we have a "pending" popupgroup. That is, we 1.716 + // have already created the FrameConstructionItem for the root popupgroup but 1.717 + // we have not yet created the relevant frame. 1.718 + bool mHavePendingPopupgroup; 1.719 + 1.720 + // If false (which is the default) then call SetPrimaryFrame() as needed 1.721 + // during frame construction. If true, don't make any SetPrimaryFrame() 1.722 + // calls, except for generated content which doesn't have a primary frame 1.723 + // yet. The mCreatingExtraFrames == true mode is meant to be used for 1.724 + // construction of random "extra" frames for elements via normal frame 1.725 + // construction APIs (e.g. replication of things across pages in paginated 1.726 + // mode). 1.727 + bool mCreatingExtraFrames; 1.728 + 1.729 + nsCOMArray<nsIContent> mGeneratedTextNodesWithInitializer; 1.730 + 1.731 + TreeMatchContext mTreeMatchContext; 1.732 + 1.733 + // Constructor 1.734 + // Use the passed-in history state. 1.735 + nsFrameConstructorState(nsIPresShell* aPresShell, 1.736 + nsIFrame* aFixedContainingBlock, 1.737 + nsIFrame* aAbsoluteContainingBlock, 1.738 + nsIFrame* aFloatContainingBlock, 1.739 + nsILayoutHistoryState* aHistoryState); 1.740 + // Get the history state from the pres context's pres shell. 1.741 + nsFrameConstructorState(nsIPresShell* aPresShell, 1.742 + nsIFrame* aFixedContainingBlock, 1.743 + nsIFrame* aAbsoluteContainingBlock, 1.744 + nsIFrame* aFloatContainingBlock); 1.745 + 1.746 + ~nsFrameConstructorState(); 1.747 + 1.748 + // Function to push the existing absolute containing block state and 1.749 + // create a new scope. Code that uses this function should get matching 1.750 + // logic in GetAbsoluteContainingBlock. 1.751 + // Also makes aNewAbsoluteContainingBlock the containing block for 1.752 + // fixed-pos elements if necessary. 1.753 + // aPositionedFrame is the frame whose style actually makes 1.754 + // aNewAbsoluteContainingBlock a containing block. E.g. for a scrollable element 1.755 + // aPositionedFrame is the element's primary frame and 1.756 + // aNewAbsoluteContainingBlock is the scrolled frame. 1.757 + void PushAbsoluteContainingBlock(nsIFrame* aNewAbsoluteContainingBlock, 1.758 + nsIFrame* aPositionedFrame, 1.759 + nsFrameConstructorSaveState& aSaveState); 1.760 + 1.761 + // Function to push the existing float containing block state and 1.762 + // create a new scope. Code that uses this function should get matching 1.763 + // logic in GetFloatContainingBlock. 1.764 + // Pushing a null float containing block forbids any frames from being 1.765 + // floated until a new float containing block is pushed. 1.766 + // XXX we should get rid of null float containing blocks and teach the 1.767 + // various frame classes to deal with floats instead. 1.768 + void PushFloatContainingBlock(nsIFrame* aNewFloatContainingBlock, 1.769 + nsFrameConstructorSaveState& aSaveState); 1.770 + 1.771 + // Function to return the proper geometric parent for a frame with display 1.772 + // struct given by aStyleDisplay and parent's frame given by 1.773 + // aContentParentFrame. 1.774 + nsIFrame* GetGeometricParent(const nsStyleDisplay* aStyleDisplay, 1.775 + nsIFrame* aContentParentFrame) const; 1.776 + 1.777 + /** 1.778 + * Function to add a new frame to the right frame list. This MUST be called 1.779 + * on frames before their children have been processed if the frames might 1.780 + * conceivably be out-of-flow; otherwise cleanup in error cases won't work 1.781 + * right. Also, this MUST be called on frames after they have been 1.782 + * initialized. 1.783 + * @param aNewFrame the frame to add 1.784 + * @param aFrameItems the list to add in-flow frames to 1.785 + * @param aContent the content pointer for aNewFrame 1.786 + * @param aStyleContext the style context resolved for aContent 1.787 + * @param aParentFrame the parent frame for the content if it were in-flow 1.788 + * @param aCanBePositioned pass false if the frame isn't allowed to be 1.789 + * positioned 1.790 + * @param aCanBeFloated pass false if the frame isn't allowed to be 1.791 + * floated 1.792 + * @param aIsOutOfFlowPopup pass true if the frame is an out-of-flow popup 1.793 + * (XUL-only) 1.794 + */ 1.795 + void AddChild(nsIFrame* aNewFrame, 1.796 + nsFrameItems& aFrameItems, 1.797 + nsIContent* aContent, 1.798 + nsStyleContext* aStyleContext, 1.799 + nsIFrame* aParentFrame, 1.800 + bool aCanBePositioned = true, 1.801 + bool aCanBeFloated = true, 1.802 + bool aIsOutOfFlowPopup = false, 1.803 + bool aInsertAfter = false, 1.804 + nsIFrame* aInsertAfterFrame = nullptr); 1.805 + 1.806 + /** 1.807 + * Function to return the fixed-pos element list. Normally this will just hand back the 1.808 + * fixed-pos element list, but in case we're dealing with a transformed element that's 1.809 + * acting as an abs-pos and fixed-pos container, we'll hand back the abs-pos list. Callers should 1.810 + * use this function if they want to get the list acting as the fixed-pos item parent. 1.811 + */ 1.812 + nsAbsoluteItems& GetFixedItems() 1.813 + { 1.814 + return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems; 1.815 + } 1.816 + const nsAbsoluteItems& GetFixedItems() const 1.817 + { 1.818 + return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems; 1.819 + } 1.820 + 1.821 + 1.822 + /** 1.823 + * class to automatically push and pop a pending binding in the frame 1.824 + * constructor state. See nsCSSFrameConstructor::FrameConstructionItem 1.825 + * mPendingBinding documentation. 1.826 + */ 1.827 + class PendingBindingAutoPusher; 1.828 + friend class PendingBindingAutoPusher; 1.829 + class MOZ_STACK_CLASS PendingBindingAutoPusher { 1.830 + public: 1.831 + PendingBindingAutoPusher(nsFrameConstructorState& aState, 1.832 + PendingBinding* aPendingBinding) : 1.833 + mState(aState), 1.834 + mPendingBinding(aState.mCurrentPendingBindingInsertionPoint) 1.835 + { 1.836 + if (aPendingBinding) { 1.837 + aState.mCurrentPendingBindingInsertionPoint = aPendingBinding; 1.838 + } 1.839 + } 1.840 + 1.841 + ~PendingBindingAutoPusher() 1.842 + { 1.843 + mState.mCurrentPendingBindingInsertionPoint = mPendingBinding; 1.844 + } 1.845 + 1.846 + private: 1.847 + nsFrameConstructorState& mState; 1.848 + PendingBinding* mPendingBinding; 1.849 + }; 1.850 + 1.851 + /** 1.852 + * Add a new pending binding to the list 1.853 + */ 1.854 + void AddPendingBinding(PendingBinding* aPendingBinding) { 1.855 + if (mCurrentPendingBindingInsertionPoint) { 1.856 + mCurrentPendingBindingInsertionPoint->setPrevious(aPendingBinding); 1.857 + } else { 1.858 + mPendingBindings.insertBack(aPendingBinding); 1.859 + } 1.860 + } 1.861 + 1.862 +protected: 1.863 + friend class nsFrameConstructorSaveState; 1.864 + 1.865 + /** 1.866 + * ProcessFrameInsertions takes the frames in aFrameItems and adds them as 1.867 + * kids to the aChildListID child list of |aFrameItems.containingBlock|. 1.868 + */ 1.869 + void ProcessFrameInsertions(nsAbsoluteItems& aFrameItems, 1.870 + ChildListID aChildListID); 1.871 + 1.872 + // Our list of all pending bindings. When we're done, we need to call 1.873 + // AddToAttachedQueue on all of them, in order. 1.874 + LinkedList<PendingBinding> mPendingBindings; 1.875 + 1.876 + PendingBinding* mCurrentPendingBindingInsertionPoint; 1.877 +}; 1.878 + 1.879 +nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell, 1.880 + nsIFrame* aFixedContainingBlock, 1.881 + nsIFrame* aAbsoluteContainingBlock, 1.882 + nsIFrame* aFloatContainingBlock, 1.883 + nsILayoutHistoryState* aHistoryState) 1.884 + : mPresContext(aPresShell->GetPresContext()), 1.885 + mPresShell(aPresShell), 1.886 + mFrameManager(aPresShell->FrameManager()), 1.887 +#ifdef MOZ_XUL 1.888 + mPopupItems(nullptr), 1.889 +#endif 1.890 + mFixedItems(aFixedContainingBlock), 1.891 + mAbsoluteItems(aAbsoluteContainingBlock), 1.892 + mFloatedItems(aFloatContainingBlock), 1.893 + // See PushAbsoluteContaningBlock below 1.894 + mFrameState(aHistoryState), 1.895 + mAdditionalStateBits(nsFrameState(0)), 1.896 + // If the fixed-pos containing block is equal to the abs-pos containing 1.897 + // block, use the abs-pos containing block's abs-pos list for fixed-pos 1.898 + // frames. 1.899 + mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock), 1.900 + mHavePendingPopupgroup(false), 1.901 + mCreatingExtraFrames(false), 1.902 + mTreeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited, 1.903 + aPresShell->GetDocument()), 1.904 + mCurrentPendingBindingInsertionPoint(nullptr) 1.905 +{ 1.906 +#ifdef MOZ_XUL 1.907 + nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell); 1.908 + if (rootBox) { 1.909 + mPopupItems.containingBlock = rootBox->GetPopupSetFrame(); 1.910 + } 1.911 +#endif 1.912 + MOZ_COUNT_CTOR(nsFrameConstructorState); 1.913 +} 1.914 + 1.915 +nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell, 1.916 + nsIFrame* aFixedContainingBlock, 1.917 + nsIFrame* aAbsoluteContainingBlock, 1.918 + nsIFrame* aFloatContainingBlock) 1.919 + : mPresContext(aPresShell->GetPresContext()), 1.920 + mPresShell(aPresShell), 1.921 + mFrameManager(aPresShell->FrameManager()), 1.922 +#ifdef MOZ_XUL 1.923 + mPopupItems(nullptr), 1.924 +#endif 1.925 + mFixedItems(aFixedContainingBlock), 1.926 + mAbsoluteItems(aAbsoluteContainingBlock), 1.927 + mFloatedItems(aFloatContainingBlock), 1.928 + // See PushAbsoluteContaningBlock below 1.929 + mAdditionalStateBits(nsFrameState(0)), 1.930 + // If the fixed-pos containing block is equal to the abs-pos containing 1.931 + // block, use the abs-pos containing block's abs-pos list for fixed-pos 1.932 + // frames. 1.933 + mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock), 1.934 + mHavePendingPopupgroup(false), 1.935 + mCreatingExtraFrames(false), 1.936 + mTreeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited, 1.937 + aPresShell->GetDocument()), 1.938 + mCurrentPendingBindingInsertionPoint(nullptr) 1.939 +{ 1.940 +#ifdef MOZ_XUL 1.941 + nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell); 1.942 + if (rootBox) { 1.943 + mPopupItems.containingBlock = rootBox->GetPopupSetFrame(); 1.944 + } 1.945 +#endif 1.946 + MOZ_COUNT_CTOR(nsFrameConstructorState); 1.947 + mFrameState = aPresShell->GetDocument()->GetLayoutHistoryState(); 1.948 +} 1.949 + 1.950 +nsFrameConstructorState::~nsFrameConstructorState() 1.951 +{ 1.952 + // Frame order comparison functions only work properly when the placeholders 1.953 + // have been inserted into the frame tree. So for example if we have a new float 1.954 + // containing the placeholder for a new abs-pos frame, and we process the abs-pos 1.955 + // insertion first, then we won't be able to find the right place to insert in 1.956 + // in the abs-pos list. So put floats in first, because they can contain placeholders 1.957 + // for abs-pos and fixed-pos items whose containing blocks are outside the floats. 1.958 + // Then put abs-pos frames in, because they can contain placeholders for fixed-pos 1.959 + // items whose containing block is outside the abs-pos frames. 1.960 + MOZ_COUNT_DTOR(nsFrameConstructorState); 1.961 + ProcessFrameInsertions(mFloatedItems, nsIFrame::kFloatList); 1.962 + ProcessFrameInsertions(mAbsoluteItems, nsIFrame::kAbsoluteList); 1.963 + ProcessFrameInsertions(mFixedItems, nsIFrame::kFixedList); 1.964 +#ifdef MOZ_XUL 1.965 + ProcessFrameInsertions(mPopupItems, nsIFrame::kPopupList); 1.966 +#endif 1.967 + for (int32_t i = mGeneratedTextNodesWithInitializer.Count() - 1; i >= 0; --i) { 1.968 + mGeneratedTextNodesWithInitializer[i]-> 1.969 + DeleteProperty(nsGkAtoms::genConInitializerProperty); 1.970 + } 1.971 + if (!mPendingBindings.isEmpty()) { 1.972 + nsBindingManager* bindingManager = mPresShell->GetDocument()->BindingManager(); 1.973 + do { 1.974 + nsAutoPtr<PendingBinding> pendingBinding; 1.975 + pendingBinding = mPendingBindings.popFirst(); 1.976 + bindingManager->AddToAttachedQueue(pendingBinding->mBinding); 1.977 + } while (!mPendingBindings.isEmpty()); 1.978 + mCurrentPendingBindingInsertionPoint = nullptr; 1.979 + } 1.980 +} 1.981 + 1.982 +static nsIFrame* 1.983 +AdjustAbsoluteContainingBlock(nsIFrame* aContainingBlockIn) 1.984 +{ 1.985 + if (!aContainingBlockIn) { 1.986 + return nullptr; 1.987 + } 1.988 + 1.989 + // Always use the container's first continuation. (Inline frames can have 1.990 + // non-fluid bidi continuations...) 1.991 + return aContainingBlockIn->FirstContinuation(); 1.992 +} 1.993 + 1.994 +void 1.995 +nsFrameConstructorState::PushAbsoluteContainingBlock(nsIFrame* aNewAbsoluteContainingBlock, 1.996 + nsIFrame* aPositionedFrame, 1.997 + nsFrameConstructorSaveState& aSaveState) 1.998 +{ 1.999 + aSaveState.mItems = &mAbsoluteItems; 1.1000 + aSaveState.mSavedItems = mAbsoluteItems; 1.1001 + aSaveState.mChildListID = nsIFrame::kAbsoluteList; 1.1002 + aSaveState.mState = this; 1.1003 + aSaveState.mSavedFixedPosIsAbsPos = mFixedPosIsAbsPos; 1.1004 + 1.1005 + if (mFixedPosIsAbsPos) { 1.1006 + // Since we're going to replace mAbsoluteItems, we need to save it into 1.1007 + // mFixedItems now (and save the current value of mFixedItems). 1.1008 + aSaveState.mSavedFixedItems = mFixedItems; 1.1009 + mFixedItems = mAbsoluteItems; 1.1010 + } 1.1011 + 1.1012 + mAbsoluteItems = 1.1013 + nsAbsoluteItems(AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock)); 1.1014 + 1.1015 + /* See if we're wiring the fixed-pos and abs-pos lists together. This happens iff 1.1016 + * we're a transformed element. 1.1017 + */ 1.1018 + mFixedPosIsAbsPos = aPositionedFrame && 1.1019 + (aPositionedFrame->StyleDisplay()->HasTransform(aPositionedFrame) || 1.1020 + aPositionedFrame->StyleDisplay()->HasPerspectiveStyle()); 1.1021 + 1.1022 + if (aNewAbsoluteContainingBlock) { 1.1023 + aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock(); 1.1024 + } 1.1025 +} 1.1026 + 1.1027 +void 1.1028 +nsFrameConstructorState::PushFloatContainingBlock(nsIFrame* aNewFloatContainingBlock, 1.1029 + nsFrameConstructorSaveState& aSaveState) 1.1030 +{ 1.1031 + NS_PRECONDITION(!aNewFloatContainingBlock || 1.1032 + aNewFloatContainingBlock->IsFloatContainingBlock(), 1.1033 + "Please push a real float containing block!"); 1.1034 + NS_ASSERTION(!aNewFloatContainingBlock || 1.1035 + !ShouldSuppressFloatingOfDescendants(aNewFloatContainingBlock), 1.1036 + "We should not push a frame that is supposed to _suppress_ " 1.1037 + "floats as a float containing block!"); 1.1038 + aSaveState.mItems = &mFloatedItems; 1.1039 + aSaveState.mSavedItems = mFloatedItems; 1.1040 + aSaveState.mChildListID = nsIFrame::kFloatList; 1.1041 + aSaveState.mState = this; 1.1042 + mFloatedItems = nsAbsoluteItems(aNewFloatContainingBlock); 1.1043 +} 1.1044 + 1.1045 +nsIFrame* 1.1046 +nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay* aStyleDisplay, 1.1047 + nsIFrame* aContentParentFrame) const 1.1048 +{ 1.1049 + NS_PRECONDITION(aStyleDisplay, "Must have display struct!"); 1.1050 + 1.1051 + // If there is no container for a fixed, absolute, or floating root 1.1052 + // frame, we will ignore the positioning. This hack is originally 1.1053 + // brought to you by the letter T: tables, since other roots don't 1.1054 + // even call into this code. See bug 178855. 1.1055 + // 1.1056 + // XXX Disabling positioning in this case is a hack. If one was so inclined, 1.1057 + // one could support this either by (1) inserting a dummy block between the 1.1058 + // table and the canvas or (2) teaching the canvas how to reflow positioned 1.1059 + // elements. (1) has the usual problems when multiple frames share the same 1.1060 + // content (notice all the special cases in this file dealing with inner 1.1061 + // tables and outer tables which share the same content). (2) requires some 1.1062 + // work and possible factoring. 1.1063 + // 1.1064 + // XXXbz couldn't we just force position to "static" on roots and 1.1065 + // float to "none"? That's OK per CSS 2.1, as far as I can tell. 1.1066 + 1.1067 + if (aContentParentFrame && aContentParentFrame->IsSVGText()) { 1.1068 + return aContentParentFrame; 1.1069 + } 1.1070 + 1.1071 + if (aStyleDisplay->IsFloatingStyle() && mFloatedItems.containingBlock) { 1.1072 + NS_ASSERTION(!aStyleDisplay->IsAbsolutelyPositionedStyle(), 1.1073 + "Absolutely positioned _and_ floating?"); 1.1074 + return mFloatedItems.containingBlock; 1.1075 + } 1.1076 + 1.1077 + if (aStyleDisplay->mPosition == NS_STYLE_POSITION_ABSOLUTE && 1.1078 + mAbsoluteItems.containingBlock) { 1.1079 + return mAbsoluteItems.containingBlock; 1.1080 + } 1.1081 + 1.1082 + if (aStyleDisplay->mPosition == NS_STYLE_POSITION_FIXED && 1.1083 + GetFixedItems().containingBlock) { 1.1084 + return GetFixedItems().containingBlock; 1.1085 + } 1.1086 + 1.1087 + return aContentParentFrame; 1.1088 +} 1.1089 + 1.1090 +void 1.1091 +nsFrameConstructorState::AddChild(nsIFrame* aNewFrame, 1.1092 + nsFrameItems& aFrameItems, 1.1093 + nsIContent* aContent, 1.1094 + nsStyleContext* aStyleContext, 1.1095 + nsIFrame* aParentFrame, 1.1096 + bool aCanBePositioned, 1.1097 + bool aCanBeFloated, 1.1098 + bool aIsOutOfFlowPopup, 1.1099 + bool aInsertAfter, 1.1100 + nsIFrame* aInsertAfterFrame) 1.1101 +{ 1.1102 + NS_PRECONDITION(!aNewFrame->GetNextSibling(), "Shouldn't happen"); 1.1103 + 1.1104 + const nsStyleDisplay* disp = aNewFrame->StyleDisplay(); 1.1105 + 1.1106 + // The comments in GetGeometricParent regarding root table frames 1.1107 + // all apply here, unfortunately. 1.1108 + 1.1109 + bool needPlaceholder = false; 1.1110 + nsFrameState placeholderType; 1.1111 + nsFrameItems* frameItems = &aFrameItems; 1.1112 +#ifdef MOZ_XUL 1.1113 + if (MOZ_UNLIKELY(aIsOutOfFlowPopup)) { 1.1114 + NS_ASSERTION(aNewFrame->GetParent() == mPopupItems.containingBlock, 1.1115 + "Popup whose parent is not the popup containing block?"); 1.1116 + NS_ASSERTION(mPopupItems.containingBlock, "Must have a popup set frame!"); 1.1117 + needPlaceholder = true; 1.1118 + frameItems = &mPopupItems; 1.1119 + placeholderType = PLACEHOLDER_FOR_POPUP; 1.1120 + } 1.1121 + else 1.1122 +#endif // MOZ_XUL 1.1123 + if (aCanBeFloated && aNewFrame->IsFloating() && 1.1124 + mFloatedItems.containingBlock) { 1.1125 + NS_ASSERTION(aNewFrame->GetParent() == mFloatedItems.containingBlock, 1.1126 + "Float whose parent is not the float containing block?"); 1.1127 + needPlaceholder = true; 1.1128 + frameItems = &mFloatedItems; 1.1129 + placeholderType = PLACEHOLDER_FOR_FLOAT; 1.1130 + } 1.1131 + else if (aCanBePositioned) { 1.1132 + if (disp->mPosition == NS_STYLE_POSITION_ABSOLUTE && 1.1133 + mAbsoluteItems.containingBlock) { 1.1134 + NS_ASSERTION(aNewFrame->GetParent() == mAbsoluteItems.containingBlock, 1.1135 + "Abs pos whose parent is not the abs pos containing block?"); 1.1136 + needPlaceholder = true; 1.1137 + frameItems = &mAbsoluteItems; 1.1138 + placeholderType = PLACEHOLDER_FOR_ABSPOS; 1.1139 + } 1.1140 + if (disp->mPosition == NS_STYLE_POSITION_FIXED && 1.1141 + GetFixedItems().containingBlock) { 1.1142 + NS_ASSERTION(aNewFrame->GetParent() == GetFixedItems().containingBlock, 1.1143 + "Fixed pos whose parent is not the fixed pos containing block?"); 1.1144 + needPlaceholder = true; 1.1145 + frameItems = &GetFixedItems(); 1.1146 + placeholderType = PLACEHOLDER_FOR_FIXEDPOS; 1.1147 + } 1.1148 + } 1.1149 + 1.1150 + if (needPlaceholder) { 1.1151 + NS_ASSERTION(frameItems != &aFrameItems, 1.1152 + "Putting frame in-flow _and_ want a placeholder?"); 1.1153 + nsIFrame* placeholderFrame = 1.1154 + nsCSSFrameConstructor::CreatePlaceholderFrameFor(mPresShell, 1.1155 + aContent, 1.1156 + aNewFrame, 1.1157 + aStyleContext, 1.1158 + aParentFrame, 1.1159 + nullptr, 1.1160 + placeholderType); 1.1161 + 1.1162 + placeholderFrame->AddStateBits(mAdditionalStateBits); 1.1163 + // Add the placeholder frame to the flow 1.1164 + aFrameItems.AddChild(placeholderFrame); 1.1165 + } 1.1166 +#ifdef DEBUG 1.1167 + else { 1.1168 + NS_ASSERTION(aNewFrame->GetParent() == aParentFrame, 1.1169 + "In-flow frame has wrong parent"); 1.1170 + } 1.1171 +#endif 1.1172 + 1.1173 + if (aInsertAfter) { 1.1174 + frameItems->InsertFrame(nullptr, aInsertAfterFrame, aNewFrame); 1.1175 + } else { 1.1176 + frameItems->AddChild(aNewFrame); 1.1177 + } 1.1178 +} 1.1179 + 1.1180 +void 1.1181 +nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems, 1.1182 + ChildListID aChildListID) 1.1183 +{ 1.1184 +#define NS_NONXUL_LIST_TEST (&aFrameItems == &mFloatedItems && \ 1.1185 + aChildListID == nsIFrame::kFloatList) || \ 1.1186 + (&aFrameItems == &mAbsoluteItems && \ 1.1187 + aChildListID == nsIFrame::kAbsoluteList) || \ 1.1188 + (&aFrameItems == &mFixedItems && \ 1.1189 + aChildListID == nsIFrame::kFixedList) 1.1190 +#ifdef MOZ_XUL 1.1191 + NS_PRECONDITION(NS_NONXUL_LIST_TEST || 1.1192 + (&aFrameItems == &mPopupItems && 1.1193 + aChildListID == nsIFrame::kPopupList), 1.1194 + "Unexpected aFrameItems/aChildListID combination"); 1.1195 +#else 1.1196 + NS_PRECONDITION(NS_NONXUL_LIST_TEST, 1.1197 + "Unexpected aFrameItems/aChildListID combination"); 1.1198 +#endif 1.1199 + 1.1200 + if (aFrameItems.IsEmpty()) { 1.1201 + return; 1.1202 + } 1.1203 + 1.1204 + nsIFrame* containingBlock = aFrameItems.containingBlock; 1.1205 + 1.1206 + NS_ASSERTION(containingBlock, 1.1207 + "Child list without containing block?"); 1.1208 + 1.1209 + if (aChildListID == nsIFrame::kFixedList) { 1.1210 + // Put this frame on the transformed-frame's abs-pos list instead, if 1.1211 + // it has abs-pos children instead of fixed-pos children. 1.1212 + aChildListID = containingBlock->GetAbsoluteListID(); 1.1213 + } 1.1214 + 1.1215 + // Insert the frames hanging out in aItems. We can use SetInitialChildList() 1.1216 + // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW 1.1217 + // is set) and doesn't have any frames in the aChildListID child list yet. 1.1218 + const nsFrameList& childList = containingBlock->GetChildList(aChildListID); 1.1219 + DebugOnly<nsresult> rv = NS_OK; 1.1220 + if (childList.IsEmpty() && 1.1221 + (containingBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { 1.1222 + // If we're injecting absolutely positioned frames, inject them on the 1.1223 + // absolute containing block 1.1224 + if (aChildListID == containingBlock->GetAbsoluteListID()) { 1.1225 + rv = containingBlock->GetAbsoluteContainingBlock()-> 1.1226 + SetInitialChildList(containingBlock, aChildListID, aFrameItems); 1.1227 + } else { 1.1228 + rv = containingBlock->SetInitialChildList(aChildListID, aFrameItems); 1.1229 + } 1.1230 + } else { 1.1231 + // Note that whether the frame construction context is doing an append or 1.1232 + // not is not helpful here, since it could be appending to some frame in 1.1233 + // the middle of the document, which means we're not necessarily 1.1234 + // appending to the children of the containing block. 1.1235 + // 1.1236 + // We need to make sure the 'append to the end of document' case is fast. 1.1237 + // So first test the last child of the containing block 1.1238 + nsIFrame* lastChild = childList.LastChild(); 1.1239 + 1.1240 + // CompareTreePosition uses placeholder hierarchy for out of flow frames, 1.1241 + // so this will make out-of-flows respect the ordering of placeholders, 1.1242 + // which is great because it takes care of anonymous content. 1.1243 + nsIFrame* firstNewFrame = aFrameItems.FirstChild(); 1.1244 + 1.1245 + // Cache the ancestor chain so that we can reuse it if needed. 1.1246 + nsAutoTArray<nsIFrame*, 20> firstNewFrameAncestors; 1.1247 + nsIFrame* notCommonAncestor = nullptr; 1.1248 + if (lastChild) { 1.1249 + notCommonAncestor = nsLayoutUtils::FillAncestors(firstNewFrame, 1.1250 + containingBlock, 1.1251 + &firstNewFrameAncestors); 1.1252 + } 1.1253 + 1.1254 + if (!lastChild || 1.1255 + nsLayoutUtils::CompareTreePosition(lastChild, firstNewFrame, 1.1256 + firstNewFrameAncestors, 1.1257 + notCommonAncestor ? 1.1258 + containingBlock : nullptr) < 0) { 1.1259 + // no lastChild, or lastChild comes before the new children, so just append 1.1260 + rv = mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems); 1.1261 + } else { 1.1262 + // Try the other children. First collect them to an array so that a 1.1263 + // reasonable fast binary search can be used to find the insertion point. 1.1264 + nsAutoTArray<nsIFrame*, 128> children; 1.1265 + for (nsIFrame* f = childList.FirstChild(); f != lastChild; 1.1266 + f = f->GetNextSibling()) { 1.1267 + children.AppendElement(f); 1.1268 + } 1.1269 + 1.1270 + nsIFrame* insertionPoint = nullptr; 1.1271 + int32_t imin = 0; 1.1272 + int32_t max = children.Length(); 1.1273 + while (max > imin) { 1.1274 + int32_t imid = imin + ((max - imin) / 2); 1.1275 + nsIFrame* f = children[imid]; 1.1276 + int32_t compare = 1.1277 + nsLayoutUtils::CompareTreePosition(f, firstNewFrame, firstNewFrameAncestors, 1.1278 + notCommonAncestor ? containingBlock : nullptr); 1.1279 + if (compare > 0) { 1.1280 + // f is after the new frame. 1.1281 + max = imid; 1.1282 + insertionPoint = imid > 0 ? children[imid - 1] : nullptr; 1.1283 + } else if (compare < 0) { 1.1284 + // f is before the new frame. 1.1285 + imin = imid + 1; 1.1286 + insertionPoint = f; 1.1287 + } else { 1.1288 + // This is for the old behavior. Should be removed once it is 1.1289 + // guaranteed that CompareTreePosition can't return 0! 1.1290 + // See bug 928645. 1.1291 + NS_WARNING("Something odd happening???"); 1.1292 + insertionPoint = nullptr; 1.1293 + for (uint32_t i = 0; i < children.Length(); ++i) { 1.1294 + nsIFrame* f = children[i]; 1.1295 + if (nsLayoutUtils::CompareTreePosition(f, firstNewFrame, 1.1296 + firstNewFrameAncestors, 1.1297 + notCommonAncestor ? 1.1298 + containingBlock : nullptr) > 0) { 1.1299 + break; 1.1300 + } 1.1301 + insertionPoint = f; 1.1302 + } 1.1303 + break; 1.1304 + } 1.1305 + } 1.1306 + rv = mFrameManager->InsertFrames(containingBlock, aChildListID, 1.1307 + insertionPoint, aFrameItems); 1.1308 + } 1.1309 + } 1.1310 + 1.1311 + NS_POSTCONDITION(aFrameItems.IsEmpty(), "How did that happen?"); 1.1312 + 1.1313 + // XXXbz And if NS_FAILED(rv), what? I guess we need to clean up the list 1.1314 + // and deal with all the placeholders... but what if the placeholders aren't 1.1315 + // in the document yet? Could that happen? 1.1316 + NS_ASSERTION(NS_SUCCEEDED(rv), "Frames getting lost!"); 1.1317 +} 1.1318 + 1.1319 + 1.1320 +nsFrameConstructorSaveState::nsFrameConstructorSaveState() 1.1321 + : mItems(nullptr), 1.1322 + mSavedItems(nullptr), 1.1323 + mChildListID(kPrincipalList), 1.1324 + mState(nullptr), 1.1325 + mSavedFixedItems(nullptr), 1.1326 + mSavedFixedPosIsAbsPos(false) 1.1327 +{ 1.1328 +} 1.1329 + 1.1330 +nsFrameConstructorSaveState::~nsFrameConstructorSaveState() 1.1331 +{ 1.1332 + // Restore the state 1.1333 + if (mItems) { 1.1334 + NS_ASSERTION(mState, "Can't have mItems set without having a state!"); 1.1335 + mState->ProcessFrameInsertions(*mItems, mChildListID); 1.1336 + *mItems = mSavedItems; 1.1337 +#ifdef DEBUG 1.1338 + // We've transferred the child list, so drop the pointer we held to it. 1.1339 + // Note that this only matters for the assert in ~nsAbsoluteItems. 1.1340 + mSavedItems.Clear(); 1.1341 +#endif 1.1342 + if (mItems == &mState->mAbsoluteItems) { 1.1343 + mState->mFixedPosIsAbsPos = mSavedFixedPosIsAbsPos; 1.1344 + if (mSavedFixedPosIsAbsPos) { 1.1345 + // mAbsoluteItems was moved to mFixedItems, so move mFixedItems back 1.1346 + // and repair the old mFixedItems now. 1.1347 + mState->mAbsoluteItems = mState->mFixedItems; 1.1348 + mState->mFixedItems = mSavedFixedItems; 1.1349 +#ifdef DEBUG 1.1350 + mSavedFixedItems.Clear(); 1.1351 +#endif 1.1352 + } 1.1353 + } 1.1354 + NS_ASSERTION(!mItems->LastChild() || !mItems->LastChild()->GetNextSibling(), 1.1355 + "Something corrupted our list"); 1.1356 + } 1.1357 +} 1.1358 + 1.1359 +static 1.1360 +bool IsBorderCollapse(nsIFrame* aFrame) 1.1361 +{ 1.1362 + for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) { 1.1363 + if (nsGkAtoms::tableFrame == frame->GetType()) { 1.1364 + return ((nsTableFrame*)frame)->IsBorderCollapse(); 1.1365 + } 1.1366 + } 1.1367 + NS_ASSERTION(false, "program error"); 1.1368 + return false; 1.1369 +} 1.1370 + 1.1371 +/** 1.1372 + * Moves aFrameList from aOldParent to aNewParent. This updates the parent 1.1373 + * pointer of the frames in the list, and reparents their views as needed. 1.1374 + * nsFrame::SetParent sets the NS_FRAME_HAS_VIEW bit on aNewParent and its 1.1375 + * ancestors as needed. Then it sets the list as the initial child list 1.1376 + * on aNewParent, unless aNewParent either already has kids or has been 1.1377 + * reflowed; in that case it appends the new frames. Note that this 1.1378 + * method differs from ReparentFrames in that it doesn't change the kids' 1.1379 + * style contexts. 1.1380 + */ 1.1381 +// XXXbz Since this is only used for {ib} splits, could we just copy the view 1.1382 +// bits from aOldParent to aNewParent and then use the 1.1383 +// nsFrameList::ApplySetParent? That would still leave us doing two passes 1.1384 +// over the list, of course; if we really wanted to we could factor out the 1.1385 +// relevant part of ReparentFrameViewList, I suppose... Or just get rid of 1.1386 +// views, which would make most of this function go away. 1.1387 +static void 1.1388 +MoveChildrenTo(nsPresContext* aPresContext, 1.1389 + nsIFrame* aOldParent, 1.1390 + nsIFrame* aNewParent, 1.1391 + nsFrameList& aFrameList) 1.1392 +{ 1.1393 + bool sameGrandParent = aOldParent->GetParent() == aNewParent->GetParent(); 1.1394 + 1.1395 + if (aNewParent->HasView() || aOldParent->HasView() || !sameGrandParent) { 1.1396 + // Move the frames into the new view 1.1397 + nsContainerFrame::ReparentFrameViewList(aFrameList, aOldParent, aNewParent); 1.1398 + } 1.1399 + 1.1400 + for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) { 1.1401 + e.get()->SetParent(aNewParent); 1.1402 + } 1.1403 + 1.1404 + if (aNewParent->PrincipalChildList().IsEmpty() && 1.1405 + (aNewParent->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { 1.1406 + aNewParent->SetInitialChildList(kPrincipalList, aFrameList); 1.1407 + } else { 1.1408 + aNewParent->AppendFrames(kPrincipalList, aFrameList); 1.1409 + } 1.1410 +} 1.1411 + 1.1412 +//---------------------------------------------------------------------- 1.1413 + 1.1414 +nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument *aDocument, 1.1415 + nsIPresShell *aPresShell, 1.1416 + nsStyleSet* aStyleSet) 1.1417 + : nsFrameManager(aPresShell, aStyleSet) 1.1418 + , mDocument(aDocument) 1.1419 + , mRootElementFrame(nullptr) 1.1420 + , mRootElementStyleFrame(nullptr) 1.1421 + , mFixedContainingBlock(nullptr) 1.1422 + , mDocElementContainingBlock(nullptr) 1.1423 + , mGfxScrollFrame(nullptr) 1.1424 + , mPageSequenceFrame(nullptr) 1.1425 + , mCurrentDepth(0) 1.1426 + , mUpdateCount(0) 1.1427 + , mQuotesDirty(false) 1.1428 + , mCountersDirty(false) 1.1429 + , mIsDestroyingFrameTree(false) 1.1430 + , mHasRootAbsPosContainingBlock(false) 1.1431 + , mAlwaysCreateFramesForIgnorableWhitespace(false) 1.1432 +{ 1.1433 +#ifdef DEBUG 1.1434 + static bool gFirstTime = true; 1.1435 + if (gFirstTime) { 1.1436 + gFirstTime = false; 1.1437 + char* flags = PR_GetEnv("GECKO_FRAMECTOR_DEBUG_FLAGS"); 1.1438 + if (flags) { 1.1439 + bool error = false; 1.1440 + for (;;) { 1.1441 + char* comma = PL_strchr(flags, ','); 1.1442 + if (comma) 1.1443 + *comma = '\0'; 1.1444 + 1.1445 + bool found = false; 1.1446 + FrameCtorDebugFlags* flag = gFlags; 1.1447 + FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS; 1.1448 + while (flag < limit) { 1.1449 + if (PL_strcasecmp(flag->name, flags) == 0) { 1.1450 + *(flag->on) = true; 1.1451 + printf("nsCSSFrameConstructor: setting %s debug flag on\n", flag->name); 1.1452 + found = true; 1.1453 + break; 1.1454 + } 1.1455 + ++flag; 1.1456 + } 1.1457 + 1.1458 + if (! found) 1.1459 + error = true; 1.1460 + 1.1461 + if (! comma) 1.1462 + break; 1.1463 + 1.1464 + *comma = ','; 1.1465 + flags = comma + 1; 1.1466 + } 1.1467 + 1.1468 + if (error) { 1.1469 + printf("Here are the available GECKO_FRAMECTOR_DEBUG_FLAGS:\n"); 1.1470 + FrameCtorDebugFlags* flag = gFlags; 1.1471 + FrameCtorDebugFlags* limit = gFlags + NUM_DEBUG_FLAGS; 1.1472 + while (flag < limit) { 1.1473 + printf(" %s\n", flag->name); 1.1474 + ++flag; 1.1475 + } 1.1476 + printf("Note: GECKO_FRAMECTOR_DEBUG_FLAGS is a comma separated list of flag\n"); 1.1477 + printf("names (no whitespace)\n"); 1.1478 + } 1.1479 + } 1.1480 + } 1.1481 +#endif 1.1482 +} 1.1483 + 1.1484 +void 1.1485 +nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame) 1.1486 +{ 1.1487 + NS_PRECONDITION(mUpdateCount != 0, 1.1488 + "Should be in an update while destroying frames"); 1.1489 + 1.1490 + if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) { 1.1491 + if (mQuoteList.DestroyNodesFor(aFrame)) 1.1492 + QuotesDirty(); 1.1493 + } 1.1494 + 1.1495 + if (mCounterManager.DestroyNodesFor(aFrame)) { 1.1496 + // Technically we don't need to update anything if we destroyed only 1.1497 + // USE nodes. However, this is unlikely to happen in the real world 1.1498 + // since USE nodes generally go along with INCREMENT nodes. 1.1499 + CountersDirty(); 1.1500 + } 1.1501 + 1.1502 + RestyleManager()->NotifyDestroyingFrame(aFrame); 1.1503 + 1.1504 + nsFrameManager::NotifyDestroyingFrame(aFrame); 1.1505 +} 1.1506 + 1.1507 +struct nsGenConInitializer { 1.1508 + nsAutoPtr<nsGenConNode> mNode; 1.1509 + nsGenConList* mList; 1.1510 + void (nsCSSFrameConstructor::*mDirtyAll)(); 1.1511 + 1.1512 + nsGenConInitializer(nsGenConNode* aNode, nsGenConList* aList, 1.1513 + void (nsCSSFrameConstructor::*aDirtyAll)()) 1.1514 + : mNode(aNode), mList(aList), mDirtyAll(aDirtyAll) {} 1.1515 +}; 1.1516 + 1.1517 +already_AddRefed<nsIContent> 1.1518 +nsCSSFrameConstructor::CreateGenConTextNode(nsFrameConstructorState& aState, 1.1519 + const nsString& aString, 1.1520 + nsCOMPtr<nsIDOMCharacterData>* aText, 1.1521 + nsGenConInitializer* aInitializer) 1.1522 +{ 1.1523 + nsRefPtr<nsTextNode> content = new nsTextNode(mDocument->NodeInfoManager()); 1.1524 + content->SetText(aString, false); 1.1525 + if (aText) { 1.1526 + *aText = content; 1.1527 + } 1.1528 + if (aInitializer) { 1.1529 + content->SetProperty(nsGkAtoms::genConInitializerProperty, aInitializer, 1.1530 + nsINode::DeleteProperty<nsGenConInitializer>); 1.1531 + aState.mGeneratedTextNodesWithInitializer.AppendObject(content); 1.1532 + } 1.1533 + return content.forget(); 1.1534 +} 1.1535 + 1.1536 +already_AddRefed<nsIContent> 1.1537 +nsCSSFrameConstructor::CreateGeneratedContent(nsFrameConstructorState& aState, 1.1538 + nsIContent* aParentContent, 1.1539 + nsStyleContext* aStyleContext, 1.1540 + uint32_t aContentIndex) 1.1541 +{ 1.1542 + // Get the content value 1.1543 + const nsStyleContentData &data = 1.1544 + aStyleContext->StyleContent()->ContentAt(aContentIndex); 1.1545 + nsStyleContentType type = data.mType; 1.1546 + 1.1547 + if (eStyleContentType_Image == type) { 1.1548 + if (!data.mContent.mImage) { 1.1549 + // CSS had something specified that couldn't be converted to an 1.1550 + // image object 1.1551 + return nullptr; 1.1552 + } 1.1553 + 1.1554 + // Create an image content object and pass it the image request. 1.1555 + // XXX Check if it's an image type we can handle... 1.1556 + 1.1557 + nsCOMPtr<nsINodeInfo> nodeInfo; 1.1558 + nodeInfo = mDocument->NodeInfoManager()-> 1.1559 + GetNodeInfo(nsGkAtoms::mozgeneratedcontentimage, nullptr, 1.1560 + kNameSpaceID_XHTML, nsIDOMNode::ELEMENT_NODE); 1.1561 + 1.1562 + nsCOMPtr<nsIContent> content; 1.1563 + NS_NewGenConImageContent(getter_AddRefs(content), nodeInfo.forget(), 1.1564 + data.mContent.mImage); 1.1565 + return content.forget(); 1.1566 + } 1.1567 + 1.1568 + switch (type) { 1.1569 + case eStyleContentType_String: 1.1570 + return CreateGenConTextNode(aState, 1.1571 + nsDependentString(data.mContent.mString), 1.1572 + nullptr, nullptr); 1.1573 + 1.1574 + case eStyleContentType_Attr: 1.1575 + { 1.1576 + nsCOMPtr<nsIAtom> attrName; 1.1577 + int32_t attrNameSpace = kNameSpaceID_None; 1.1578 + nsAutoString contentString(data.mContent.mString); 1.1579 + 1.1580 + int32_t barIndex = contentString.FindChar('|'); // CSS namespace delimiter 1.1581 + if (-1 != barIndex) { 1.1582 + nsAutoString nameSpaceVal; 1.1583 + contentString.Left(nameSpaceVal, barIndex); 1.1584 + nsresult error; 1.1585 + attrNameSpace = nameSpaceVal.ToInteger(&error); 1.1586 + contentString.Cut(0, barIndex + 1); 1.1587 + if (contentString.Length()) { 1.1588 + if (mDocument->IsHTML() && aParentContent->IsHTML()) { 1.1589 + ToLowerCase(contentString); 1.1590 + } 1.1591 + attrName = do_GetAtom(contentString); 1.1592 + } 1.1593 + } 1.1594 + else { 1.1595 + if (mDocument->IsHTML() && aParentContent->IsHTML()) { 1.1596 + ToLowerCase(contentString); 1.1597 + } 1.1598 + attrName = do_GetAtom(contentString); 1.1599 + } 1.1600 + 1.1601 + if (!attrName) { 1.1602 + return nullptr; 1.1603 + } 1.1604 + 1.1605 + nsCOMPtr<nsIContent> content; 1.1606 + NS_NewAttributeContent(mDocument->NodeInfoManager(), 1.1607 + attrNameSpace, attrName, getter_AddRefs(content)); 1.1608 + return content.forget(); 1.1609 + } 1.1610 + 1.1611 + case eStyleContentType_Counter: 1.1612 + case eStyleContentType_Counters: 1.1613 + { 1.1614 + nsCSSValue::Array* counters = data.mContent.mCounters; 1.1615 + nsCounterList* counterList = mCounterManager.CounterListFor( 1.1616 + nsDependentString(counters->Item(0).GetStringBufferValue())); 1.1617 + if (!counterList) 1.1618 + return nullptr; 1.1619 + 1.1620 + nsCounterUseNode* node = 1.1621 + new nsCounterUseNode(counters, aContentIndex, 1.1622 + type == eStyleContentType_Counters); 1.1623 + 1.1624 + nsGenConInitializer* initializer = 1.1625 + new nsGenConInitializer(node, counterList, 1.1626 + &nsCSSFrameConstructor::CountersDirty); 1.1627 + return CreateGenConTextNode(aState, EmptyString(), &node->mText, 1.1628 + initializer); 1.1629 + } 1.1630 + 1.1631 + case eStyleContentType_Image: 1.1632 + NS_NOTREACHED("handled by if above"); 1.1633 + return nullptr; 1.1634 + 1.1635 + case eStyleContentType_OpenQuote: 1.1636 + case eStyleContentType_CloseQuote: 1.1637 + case eStyleContentType_NoOpenQuote: 1.1638 + case eStyleContentType_NoCloseQuote: 1.1639 + { 1.1640 + nsQuoteNode* node = 1.1641 + new nsQuoteNode(type, aContentIndex); 1.1642 + 1.1643 + nsGenConInitializer* initializer = 1.1644 + new nsGenConInitializer(node, &mQuoteList, 1.1645 + &nsCSSFrameConstructor::QuotesDirty); 1.1646 + return CreateGenConTextNode(aState, EmptyString(), &node->mText, 1.1647 + initializer); 1.1648 + } 1.1649 + 1.1650 + case eStyleContentType_AltContent: 1.1651 + { 1.1652 + // Use the "alt" attribute; if that fails and the node is an HTML 1.1653 + // <input>, try the value attribute and then fall back to some default 1.1654 + // localized text we have. 1.1655 + // XXX what if the 'alt' attribute is added later, how will we 1.1656 + // detect that and do the right thing here? 1.1657 + if (aParentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::alt)) { 1.1658 + nsCOMPtr<nsIContent> content; 1.1659 + NS_NewAttributeContent(mDocument->NodeInfoManager(), 1.1660 + kNameSpaceID_None, nsGkAtoms::alt, getter_AddRefs(content)); 1.1661 + return content.forget(); 1.1662 + } 1.1663 + 1.1664 + if (aParentContent->IsHTML() && 1.1665 + aParentContent->NodeInfo()->Equals(nsGkAtoms::input)) { 1.1666 + if (aParentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) { 1.1667 + nsCOMPtr<nsIContent> content; 1.1668 + NS_NewAttributeContent(mDocument->NodeInfoManager(), 1.1669 + kNameSpaceID_None, nsGkAtoms::value, getter_AddRefs(content)); 1.1670 + return content.forget(); 1.1671 + } 1.1672 + 1.1673 + nsXPIDLString temp; 1.1674 + nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES, 1.1675 + "Submit", temp); 1.1676 + return CreateGenConTextNode(aState, temp, nullptr, nullptr); 1.1677 + } 1.1678 + 1.1679 + break; 1.1680 + } 1.1681 + 1.1682 + case eStyleContentType_Uninitialized: 1.1683 + NS_NOTREACHED("uninitialized content type"); 1.1684 + return nullptr; 1.1685 + } // switch 1.1686 + 1.1687 + return nullptr; 1.1688 +} 1.1689 + 1.1690 +/* 1.1691 + * aParentFrame - the frame that should be the parent of the generated 1.1692 + * content. This is the frame for the corresponding content node, 1.1693 + * which must not be a leaf frame. 1.1694 + * 1.1695 + * Any items created are added to aItems. 1.1696 + * 1.1697 + * We create an XML element (tag _moz_generated_content_before or 1.1698 + * _moz_generated_content_after) representing the pseudoelement. We 1.1699 + * create a DOM node for each 'content' item and make those nodes the 1.1700 + * children of the XML element. Then we create a frame subtree for 1.1701 + * the XML element as if it were a regular child of 1.1702 + * aParentFrame/aParentContent, giving the XML element the ::before or 1.1703 + * ::after style. 1.1704 + */ 1.1705 +void 1.1706 +nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aState, 1.1707 + nsIFrame* aParentFrame, 1.1708 + nsIContent* aParentContent, 1.1709 + nsStyleContext* aStyleContext, 1.1710 + nsCSSPseudoElements::Type aPseudoElement, 1.1711 + FrameConstructionItemList& aItems) 1.1712 +{ 1.1713 + // XXXbz is this ever true? 1.1714 + if (!aParentContent->IsElement()) { 1.1715 + NS_ERROR("Bogus generated content parent"); 1.1716 + return; 1.1717 + } 1.1718 + 1.1719 + nsStyleSet *styleSet = mPresShell->StyleSet(); 1.1720 + 1.1721 + // Probe for the existence of the pseudo-element 1.1722 + nsRefPtr<nsStyleContext> pseudoStyleContext; 1.1723 + pseudoStyleContext = 1.1724 + styleSet->ProbePseudoElementStyle(aParentContent->AsElement(), 1.1725 + aPseudoElement, 1.1726 + aStyleContext, 1.1727 + aState.mTreeMatchContext); 1.1728 + if (!pseudoStyleContext) 1.1729 + return; 1.1730 + // |ProbePseudoStyleFor| checked the 'display' property and the 1.1731 + // |ContentCount()| of the 'content' property for us. 1.1732 + nsCOMPtr<nsINodeInfo> nodeInfo; 1.1733 + nsIAtom* elemName = aPseudoElement == nsCSSPseudoElements::ePseudo_before ? 1.1734 + nsGkAtoms::mozgeneratedcontentbefore : nsGkAtoms::mozgeneratedcontentafter; 1.1735 + nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(elemName, nullptr, 1.1736 + kNameSpaceID_None, 1.1737 + nsIDOMNode::ELEMENT_NODE); 1.1738 + nsCOMPtr<Element> container; 1.1739 + nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget()); 1.1740 + if (NS_FAILED(rv)) 1.1741 + return; 1.1742 + container->SetIsNativeAnonymousRoot(); 1.1743 + 1.1744 + rv = container->BindToTree(mDocument, aParentContent, aParentContent, true); 1.1745 + if (NS_FAILED(rv)) { 1.1746 + container->UnbindFromTree(); 1.1747 + return; 1.1748 + } 1.1749 + 1.1750 + uint32_t contentCount = pseudoStyleContext->StyleContent()->ContentCount(); 1.1751 + for (uint32_t contentIndex = 0; contentIndex < contentCount; contentIndex++) { 1.1752 + nsCOMPtr<nsIContent> content = 1.1753 + CreateGeneratedContent(aState, aParentContent, pseudoStyleContext, 1.1754 + contentIndex); 1.1755 + if (content) { 1.1756 + container->AppendChildTo(content, false); 1.1757 + } 1.1758 + } 1.1759 + 1.1760 + AddFrameConstructionItemsInternal(aState, container, aParentFrame, elemName, 1.1761 + kNameSpaceID_None, true, 1.1762 + pseudoStyleContext, 1.1763 + ITEM_IS_GENERATED_CONTENT, nullptr, 1.1764 + aItems); 1.1765 +} 1.1766 + 1.1767 +/**************************************************** 1.1768 + ** BEGIN TABLE SECTION 1.1769 + ****************************************************/ 1.1770 + 1.1771 +// The term pseudo frame is being used instead of anonymous frame, since anonymous 1.1772 +// frame has been used elsewhere to refer to frames that have generated content 1.1773 + 1.1774 +// Return whether the given frame is a table pseudo-frame. Note that 1.1775 +// cell-content and table-outer frames have pseudo-types, but are always 1.1776 +// created, even for non-anonymous cells and tables respectively. So for those 1.1777 +// we have to examine the cell or table frame to see whether it's a pseudo 1.1778 +// frame. In particular, a lone table caption will have an outer table as its 1.1779 +// parent, but will also trigger construction of an empty inner table, which 1.1780 +// will be the one we can examine to see whether the outer was a pseudo-frame. 1.1781 +static bool 1.1782 +IsTablePseudo(nsIFrame* aFrame) 1.1783 +{ 1.1784 + nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo(); 1.1785 + return pseudoType && 1.1786 + (pseudoType == nsCSSAnonBoxes::table || 1.1787 + pseudoType == nsCSSAnonBoxes::inlineTable || 1.1788 + pseudoType == nsCSSAnonBoxes::tableColGroup || 1.1789 + pseudoType == nsCSSAnonBoxes::tableRowGroup || 1.1790 + pseudoType == nsCSSAnonBoxes::tableRow || 1.1791 + pseudoType == nsCSSAnonBoxes::tableCell || 1.1792 + (pseudoType == nsCSSAnonBoxes::cellContent && 1.1793 + aFrame->GetParent()->StyleContext()->GetPseudo() == 1.1794 + nsCSSAnonBoxes::tableCell) || 1.1795 + (pseudoType == nsCSSAnonBoxes::tableOuter && 1.1796 + (aFrame->GetFirstPrincipalChild()->StyleContext()->GetPseudo() == 1.1797 + nsCSSAnonBoxes::table || 1.1798 + aFrame->GetFirstPrincipalChild()->StyleContext()->GetPseudo() == 1.1799 + nsCSSAnonBoxes::inlineTable))); 1.1800 +} 1.1801 + 1.1802 +/* static */ 1.1803 +nsCSSFrameConstructor::ParentType 1.1804 +nsCSSFrameConstructor::GetParentType(nsIAtom* aFrameType) 1.1805 +{ 1.1806 + if (aFrameType == nsGkAtoms::tableFrame) { 1.1807 + return eTypeTable; 1.1808 + } 1.1809 + if (aFrameType == nsGkAtoms::tableRowGroupFrame) { 1.1810 + return eTypeRowGroup; 1.1811 + } 1.1812 + if (aFrameType == nsGkAtoms::tableRowFrame) { 1.1813 + return eTypeRow; 1.1814 + } 1.1815 + if (aFrameType == nsGkAtoms::tableColGroupFrame) { 1.1816 + return eTypeColGroup; 1.1817 + } 1.1818 + 1.1819 + return eTypeBlock; 1.1820 +} 1.1821 + 1.1822 +static nsIFrame* 1.1823 +AdjustCaptionParentFrame(nsIFrame* aParentFrame) 1.1824 +{ 1.1825 + if (nsGkAtoms::tableFrame == aParentFrame->GetType()) { 1.1826 + return aParentFrame->GetParent();; 1.1827 + } 1.1828 + return aParentFrame; 1.1829 +} 1.1830 + 1.1831 +/** 1.1832 + * If the parent frame is a |tableFrame| and the child is a 1.1833 + * |captionFrame|, then we want to insert the frames beneath the 1.1834 + * |tableFrame|'s parent frame. Returns |true| if the parent frame 1.1835 + * needed to be fixed up. 1.1836 + */ 1.1837 +static bool 1.1838 +GetCaptionAdjustedParent(nsIFrame* aParentFrame, 1.1839 + const nsIFrame* aChildFrame, 1.1840 + nsIFrame** aAdjParentFrame) 1.1841 +{ 1.1842 + *aAdjParentFrame = aParentFrame; 1.1843 + bool haveCaption = false; 1.1844 + 1.1845 + if (nsGkAtoms::tableCaptionFrame == aChildFrame->GetType()) { 1.1846 + haveCaption = true; 1.1847 + *aAdjParentFrame = AdjustCaptionParentFrame(aParentFrame); 1.1848 + } 1.1849 + return haveCaption; 1.1850 +} 1.1851 + 1.1852 +void 1.1853 +nsCSSFrameConstructor::AdjustParentFrame(nsIFrame* & aParentFrame, 1.1854 + const FrameConstructionData* aFCData, 1.1855 + nsStyleContext* aStyleContext) 1.1856 +{ 1.1857 + NS_PRECONDITION(aStyleContext, "Must have child's style context"); 1.1858 + NS_PRECONDITION(aFCData, "Must have frame construction data"); 1.1859 + 1.1860 + bool tablePart = ((aFCData->mBits & FCDATA_IS_TABLE_PART) != 0); 1.1861 + 1.1862 + if (tablePart && aStyleContext->StyleDisplay()->mDisplay == 1.1863 + NS_STYLE_DISPLAY_TABLE_CAPTION) { 1.1864 + aParentFrame = AdjustCaptionParentFrame(aParentFrame); 1.1865 + } 1.1866 +} 1.1867 + 1.1868 +// Pull all the captions present in aItems out into aCaptions 1.1869 +static void 1.1870 +PullOutCaptionFrames(nsFrameItems& aItems, nsFrameItems& aCaptions) 1.1871 +{ 1.1872 + nsIFrame *child = aItems.FirstChild(); 1.1873 + while (child) { 1.1874 + nsIFrame *nextSibling = child->GetNextSibling(); 1.1875 + if (nsGkAtoms::tableCaptionFrame == child->GetType()) { 1.1876 + aItems.RemoveFrame(child); 1.1877 + aCaptions.AddChild(child); 1.1878 + } 1.1879 + child = nextSibling; 1.1880 + } 1.1881 +} 1.1882 + 1.1883 + 1.1884 +// Construct the outer, inner table frames and the children frames for the table. 1.1885 +// XXX Page break frames for pseudo table frames are not constructed to avoid the risk 1.1886 +// associated with revising the pseudo frame mechanism. The long term solution 1.1887 +// of having frames handle page-break-before/after will solve the problem. 1.1888 +nsIFrame* 1.1889 +nsCSSFrameConstructor::ConstructTable(nsFrameConstructorState& aState, 1.1890 + FrameConstructionItem& aItem, 1.1891 + nsIFrame* aParentFrame, 1.1892 + const nsStyleDisplay* aDisplay, 1.1893 + nsFrameItems& aFrameItems) 1.1894 +{ 1.1895 + NS_PRECONDITION(aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE || 1.1896 + aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_TABLE, 1.1897 + "Unexpected call"); 1.1898 + 1.1899 + nsIContent* const content = aItem.mContent; 1.1900 + nsStyleContext* const styleContext = aItem.mStyleContext; 1.1901 + const uint32_t nameSpaceID = aItem.mNameSpaceID; 1.1902 + 1.1903 + // create the pseudo SC for the outer table as a child of the inner SC 1.1904 + nsRefPtr<nsStyleContext> outerStyleContext; 1.1905 + outerStyleContext = mPresShell->StyleSet()-> 1.1906 + ResolveAnonymousBoxStyle(nsCSSAnonBoxes::tableOuter, styleContext); 1.1907 + 1.1908 + // Create the outer table frame which holds the caption and inner table frame 1.1909 + nsIFrame* newFrame; 1.1910 + if (kNameSpaceID_MathML == nameSpaceID) 1.1911 + newFrame = NS_NewMathMLmtableOuterFrame(mPresShell, outerStyleContext); 1.1912 + else 1.1913 + newFrame = NS_NewTableOuterFrame(mPresShell, outerStyleContext); 1.1914 + 1.1915 + nsIFrame* geometricParent = 1.1916 + aState.GetGeometricParent(outerStyleContext->StyleDisplay(), 1.1917 + aParentFrame); 1.1918 + 1.1919 + // Init the table outer frame 1.1920 + InitAndRestoreFrame(aState, content, geometricParent, newFrame); 1.1921 + 1.1922 + // Create the inner table frame 1.1923 + nsIFrame* innerFrame; 1.1924 + if (kNameSpaceID_MathML == nameSpaceID) 1.1925 + innerFrame = NS_NewMathMLmtableFrame(mPresShell, styleContext); 1.1926 + else 1.1927 + innerFrame = NS_NewTableFrame(mPresShell, styleContext); 1.1928 + 1.1929 + InitAndRestoreFrame(aState, content, newFrame, innerFrame); 1.1930 + 1.1931 + // Put the newly created frames into the right child list 1.1932 + SetInitialSingleChild(newFrame, innerFrame); 1.1933 + 1.1934 + aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame); 1.1935 + 1.1936 + if (!mRootElementFrame) { 1.1937 + // The frame we're constructing will be the root element frame. 1.1938 + // Set mRootElementFrame before processing children. 1.1939 + mRootElementFrame = newFrame; 1.1940 + } 1.1941 + 1.1942 + nsFrameItems childItems; 1.1943 + 1.1944 + // Process children 1.1945 + nsFrameConstructorSaveState absoluteSaveState; 1.1946 + const nsStyleDisplay* display = outerStyleContext->StyleDisplay(); 1.1947 + 1.1948 + // Mark the table frame as an absolute container if needed 1.1949 + newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); 1.1950 + if (display->IsPositioned(newFrame)) { 1.1951 + aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState); 1.1952 + } 1.1953 + NS_ASSERTION(aItem.mAnonChildren.IsEmpty(), 1.1954 + "nsIAnonymousContentCreator::CreateAnonymousContent " 1.1955 + "implementations for table frames are not currently expected " 1.1956 + "to output a list where the items have their own children"); 1.1957 + if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) { 1.1958 + ConstructFramesFromItemList(aState, aItem.mChildItems, 1.1959 + innerFrame, childItems); 1.1960 + } else { 1.1961 + ProcessChildren(aState, content, styleContext, innerFrame, 1.1962 + true, childItems, false, aItem.mPendingBinding); 1.1963 + } 1.1964 + 1.1965 + nsFrameItems captionItems; 1.1966 + PullOutCaptionFrames(childItems, captionItems); 1.1967 + 1.1968 + // Set the inner table frame's initial primary list 1.1969 + innerFrame->SetInitialChildList(kPrincipalList, childItems); 1.1970 + 1.1971 + // Set the outer table frame's secondary childlist lists 1.1972 + if (captionItems.NotEmpty()) { 1.1973 + newFrame->SetInitialChildList(nsIFrame::kCaptionList, captionItems); 1.1974 + } 1.1975 + 1.1976 + return newFrame; 1.1977 +} 1.1978 + 1.1979 +static void 1.1980 +MakeTablePartAbsoluteContainingBlockIfNeeded(nsFrameConstructorState& aState, 1.1981 + const nsStyleDisplay* aDisplay, 1.1982 + nsFrameConstructorSaveState& aAbsSaveState, 1.1983 + nsIFrame* aFrame) 1.1984 +{ 1.1985 + // If we're positioned, then we need to become an absolute containing block 1.1986 + // for any absolutely positioned children and register for post-reflow fixup. 1.1987 + // 1.1988 + // Note that usually if a frame type can be an absolute containing block, we 1.1989 + // always set NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN, whether it actually is or not. 1.1990 + // However, in this case flag serves the additional purpose of indicating that 1.1991 + // the frame was registered with its table frame. This allows us to avoid the 1.1992 + // overhead of unregistering the frame in most cases. 1.1993 + if (aDisplay->IsPositioned(aFrame)) { 1.1994 + aFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); 1.1995 + aState.PushAbsoluteContainingBlock(aFrame, aFrame, aAbsSaveState); 1.1996 + nsTableFrame::RegisterPositionedTablePart(aFrame); 1.1997 + } 1.1998 +} 1.1999 + 1.2000 +nsIFrame* 1.2001 +nsCSSFrameConstructor::ConstructTableRowOrRowGroup(nsFrameConstructorState& aState, 1.2002 + FrameConstructionItem& aItem, 1.2003 + nsIFrame* aParentFrame, 1.2004 + const nsStyleDisplay* aDisplay, 1.2005 + nsFrameItems& aFrameItems) 1.2006 +{ 1.2007 + NS_PRECONDITION(aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_ROW || 1.2008 + aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_ROW_GROUP || 1.2009 + aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP || 1.2010 + aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_HEADER_GROUP, 1.2011 + "Unexpected call"); 1.2012 + MOZ_ASSERT(aItem.mStyleContext->StyleDisplay() == aDisplay, 1.2013 + "Display style doesn't match style context"); 1.2014 + nsIContent* const content = aItem.mContent; 1.2015 + nsStyleContext* const styleContext = aItem.mStyleContext; 1.2016 + const uint32_t nameSpaceID = aItem.mNameSpaceID; 1.2017 + 1.2018 + nsIFrame* newFrame; 1.2019 + if (aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_ROW) { 1.2020 + if (kNameSpaceID_MathML == nameSpaceID) 1.2021 + newFrame = NS_NewMathMLmtrFrame(mPresShell, styleContext); 1.2022 + else 1.2023 + newFrame = NS_NewTableRowFrame(mPresShell, styleContext); 1.2024 + } else { 1.2025 + newFrame = NS_NewTableRowGroupFrame(mPresShell, styleContext); 1.2026 + } 1.2027 + 1.2028 + InitAndRestoreFrame(aState, content, aParentFrame, newFrame); 1.2029 + 1.2030 + nsFrameConstructorSaveState absoluteSaveState; 1.2031 + MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay, 1.2032 + absoluteSaveState, 1.2033 + newFrame); 1.2034 + 1.2035 + nsFrameItems childItems; 1.2036 + NS_ASSERTION(aItem.mAnonChildren.IsEmpty(), 1.2037 + "nsIAnonymousContentCreator::CreateAnonymousContent " 1.2038 + "implementations for table frames are not currently expected " 1.2039 + "to output a list where the items have their own children"); 1.2040 + if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) { 1.2041 + ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame, 1.2042 + childItems); 1.2043 + } else { 1.2044 + ProcessChildren(aState, content, styleContext, newFrame, 1.2045 + true, childItems, false, aItem.mPendingBinding); 1.2046 + } 1.2047 + 1.2048 + newFrame->SetInitialChildList(kPrincipalList, childItems); 1.2049 + aFrameItems.AddChild(newFrame); 1.2050 + return newFrame; 1.2051 +} 1.2052 + 1.2053 +nsIFrame* 1.2054 +nsCSSFrameConstructor::ConstructTableCol(nsFrameConstructorState& aState, 1.2055 + FrameConstructionItem& aItem, 1.2056 + nsIFrame* aParentFrame, 1.2057 + const nsStyleDisplay* aStyleDisplay, 1.2058 + nsFrameItems& aFrameItems) 1.2059 +{ 1.2060 + nsIContent* const content = aItem.mContent; 1.2061 + nsStyleContext* const styleContext = aItem.mStyleContext; 1.2062 + 1.2063 + nsTableColFrame* colFrame = NS_NewTableColFrame(mPresShell, styleContext); 1.2064 + InitAndRestoreFrame(aState, content, aParentFrame, colFrame); 1.2065 + 1.2066 + NS_ASSERTION(colFrame->StyleContext() == styleContext, 1.2067 + "Unexpected style context"); 1.2068 + 1.2069 + aFrameItems.AddChild(colFrame); 1.2070 + 1.2071 + // construct additional col frames if the col frame has a span > 1 1.2072 + int32_t span = colFrame->GetSpan(); 1.2073 + for (int32_t spanX = 1; spanX < span; spanX++) { 1.2074 + nsTableColFrame* newCol = NS_NewTableColFrame(mPresShell, styleContext); 1.2075 + InitAndRestoreFrame(aState, content, aParentFrame, newCol, false); 1.2076 + aFrameItems.LastChild()->SetNextContinuation(newCol); 1.2077 + newCol->SetPrevContinuation(aFrameItems.LastChild()); 1.2078 + aFrameItems.AddChild(newCol); 1.2079 + newCol->SetColType(eColAnonymousCol); 1.2080 + } 1.2081 + 1.2082 + return colFrame; 1.2083 +} 1.2084 + 1.2085 +nsIFrame* 1.2086 +nsCSSFrameConstructor::ConstructTableCell(nsFrameConstructorState& aState, 1.2087 + FrameConstructionItem& aItem, 1.2088 + nsIFrame* aParentFrame, 1.2089 + const nsStyleDisplay* aDisplay, 1.2090 + nsFrameItems& aFrameItems) 1.2091 +{ 1.2092 + NS_PRECONDITION(aDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL, 1.2093 + "Unexpected call"); 1.2094 + 1.2095 + nsIContent* const content = aItem.mContent; 1.2096 + nsStyleContext* const styleContext = aItem.mStyleContext; 1.2097 + const uint32_t nameSpaceID = aItem.mNameSpaceID; 1.2098 + 1.2099 + bool borderCollapse = IsBorderCollapse(aParentFrame); 1.2100 + nsIFrame* newFrame; 1.2101 + // <mtable> is border separate in mathml.css and the MathML code doesn't implement 1.2102 + // border collapse. For those users who style <mtable> with border collapse, 1.2103 + // give them the default non-MathML table frames that understand border collapse. 1.2104 + // This won't break us because MathML table frames are all subclasses of the default 1.2105 + // table code, and so we can freely mix <mtable> with <mtr> or <tr>, <mtd> or <td>. 1.2106 + // What will happen is just that non-MathML frames won't understand MathML attributes 1.2107 + // and will therefore miss the special handling that the MathML code does. 1.2108 + if (kNameSpaceID_MathML == nameSpaceID && !borderCollapse) 1.2109 + newFrame = NS_NewMathMLmtdFrame(mPresShell, styleContext); 1.2110 + else 1.2111 + // Warning: If you change this and add a wrapper frame around table cell 1.2112 + // frames, make sure Bug 368554 doesn't regress! 1.2113 + // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp. 1.2114 + newFrame = NS_NewTableCellFrame(mPresShell, styleContext, borderCollapse); 1.2115 + 1.2116 + // Initialize the table cell frame 1.2117 + InitAndRestoreFrame(aState, content, aParentFrame, newFrame); 1.2118 + 1.2119 + // Resolve pseudo style and initialize the body cell frame 1.2120 + nsRefPtr<nsStyleContext> innerPseudoStyle; 1.2121 + innerPseudoStyle = mPresShell->StyleSet()-> 1.2122 + ResolveAnonymousBoxStyle(nsCSSAnonBoxes::cellContent, styleContext); 1.2123 + 1.2124 + // Create a block frame that will format the cell's content 1.2125 + bool isBlock; 1.2126 + nsIFrame* cellInnerFrame; 1.2127 + if (kNameSpaceID_MathML == nameSpaceID) { 1.2128 + cellInnerFrame = NS_NewMathMLmtdInnerFrame(mPresShell, innerPseudoStyle); 1.2129 + isBlock = false; 1.2130 + } else { 1.2131 + cellInnerFrame = NS_NewBlockFormattingContext(mPresShell, innerPseudoStyle); 1.2132 + isBlock = true; 1.2133 + } 1.2134 + 1.2135 + InitAndRestoreFrame(aState, content, newFrame, cellInnerFrame); 1.2136 + 1.2137 + nsFrameConstructorSaveState absoluteSaveState; 1.2138 + MakeTablePartAbsoluteContainingBlockIfNeeded(aState, aDisplay, 1.2139 + absoluteSaveState, 1.2140 + newFrame); 1.2141 + 1.2142 + nsFrameItems childItems; 1.2143 + NS_ASSERTION(aItem.mAnonChildren.IsEmpty(), 1.2144 + "nsIAnonymousContentCreator::CreateAnonymousContent " 1.2145 + "implementations for table frames are not currently expected " 1.2146 + "to output a list where the items have their own children"); 1.2147 + if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) { 1.2148 + // Need to push ourselves as a float containing block. 1.2149 + // XXXbz it might be nice to work on getting the parent 1.2150 + // FrameConstructionItem down into ProcessChildren and just making use of 1.2151 + // the push there, but that's a bit of work. 1.2152 + nsFrameConstructorSaveState floatSaveState; 1.2153 + if (!isBlock) { /* MathML case */ 1.2154 + aState.PushFloatContainingBlock(nullptr, floatSaveState); 1.2155 + } else { 1.2156 + aState.PushFloatContainingBlock(cellInnerFrame, floatSaveState); 1.2157 + } 1.2158 + 1.2159 + ConstructFramesFromItemList(aState, aItem.mChildItems, cellInnerFrame, 1.2160 + childItems); 1.2161 + } else { 1.2162 + // Process the child content 1.2163 + ProcessChildren(aState, content, styleContext, cellInnerFrame, 1.2164 + true, childItems, isBlock, aItem.mPendingBinding); 1.2165 + } 1.2166 + 1.2167 + cellInnerFrame->SetInitialChildList(kPrincipalList, childItems); 1.2168 + SetInitialSingleChild(newFrame, cellInnerFrame); 1.2169 + aFrameItems.AddChild(newFrame); 1.2170 + return newFrame; 1.2171 +} 1.2172 + 1.2173 +static inline bool 1.2174 +NeedFrameFor(const nsFrameConstructorState& aState, 1.2175 + nsIFrame* aParentFrame, 1.2176 + nsIContent* aChildContent) 1.2177 +{ 1.2178 + // XXX the GetContent() != aChildContent check is needed due to bug 135040. 1.2179 + // Remove it once that's fixed. 1.2180 + NS_PRECONDITION(!aChildContent->GetPrimaryFrame() || 1.2181 + aState.mCreatingExtraFrames || 1.2182 + aChildContent->GetPrimaryFrame()->GetContent() != aChildContent, 1.2183 + "Why did we get called?"); 1.2184 + 1.2185 + // don't create a whitespace frame if aParentFrame doesn't want it. 1.2186 + // always create frames for children in generated content. counter(), 1.2187 + // quotes, and attr() content can easily change dynamically and we don't 1.2188 + // want to be reconstructing frames. It's not even clear that these 1.2189 + // should be considered ignorable just because they evaluate to 1.2190 + // whitespace. 1.2191 + 1.2192 + // We could handle all this in CreateNeededTablePseudos or some other place 1.2193 + // after we build our frame construction items, but that would involve 1.2194 + // creating frame construction items for whitespace kids of 1.2195 + // eExcludesIgnorableWhitespace frames, where we know we'll be dropping them 1.2196 + // all anyway, and involve an extra walk down the frame construction item 1.2197 + // list. 1.2198 + if (!aParentFrame->IsFrameOfType(nsIFrame::eExcludesIgnorableWhitespace) || 1.2199 + aParentFrame->IsGeneratedContentFrame() || 1.2200 + !aChildContent->IsNodeOfType(nsINode::eTEXT)) { 1.2201 + return true; 1.2202 + } 1.2203 + 1.2204 + aChildContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE | 1.2205 + NS_REFRAME_IF_WHITESPACE); 1.2206 + return !aChildContent->TextIsOnlyWhitespace(); 1.2207 +} 1.2208 + 1.2209 +/*********************************************** 1.2210 + * END TABLE SECTION 1.2211 + ***********************************************/ 1.2212 + 1.2213 +static bool CheckOverflow(nsPresContext* aPresContext, 1.2214 + const nsStyleDisplay* aDisplay) 1.2215 +{ 1.2216 + if (aDisplay->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE) 1.2217 + return false; 1.2218 + 1.2219 + if (aDisplay->mOverflowX == NS_STYLE_OVERFLOW_CLIP) 1.2220 + aPresContext->SetViewportOverflowOverride(NS_STYLE_OVERFLOW_HIDDEN, 1.2221 + NS_STYLE_OVERFLOW_HIDDEN); 1.2222 + else 1.2223 + aPresContext->SetViewportOverflowOverride(aDisplay->mOverflowX, 1.2224 + aDisplay->mOverflowY); 1.2225 + return true; 1.2226 +} 1.2227 + 1.2228 +/** 1.2229 + * This checks the root element and the HTML BODY, if any, for an "overflow" property 1.2230 + * that should be applied to the viewport. If one is found then we return the 1.2231 + * element that we took the overflow from (which should then be treated as 1.2232 + * "overflow:visible"), and we store the overflow style in the prescontext. 1.2233 + * @return if scroll was propagated from some content node, the content node it 1.2234 + * was propagated from. 1.2235 + */ 1.2236 +nsIContent* 1.2237 +nsCSSFrameConstructor::PropagateScrollToViewport() 1.2238 +{ 1.2239 + // Set default 1.2240 + nsPresContext* presContext = mPresShell->GetPresContext(); 1.2241 + presContext->SetViewportOverflowOverride(NS_STYLE_OVERFLOW_AUTO, 1.2242 + NS_STYLE_OVERFLOW_AUTO); 1.2243 + 1.2244 + // We never mess with the viewport scroll state 1.2245 + // when printing or in print preview 1.2246 + if (presContext->IsPaginated()) { 1.2247 + return nullptr; 1.2248 + } 1.2249 + 1.2250 + Element* docElement = mDocument->GetRootElement(); 1.2251 + 1.2252 + // Check the style on the document root element 1.2253 + nsStyleSet *styleSet = mPresShell->StyleSet(); 1.2254 + nsRefPtr<nsStyleContext> rootStyle; 1.2255 + rootStyle = styleSet->ResolveStyleFor(docElement, nullptr); 1.2256 + if (CheckOverflow(presContext, rootStyle->StyleDisplay())) { 1.2257 + // tell caller we stole the overflow style from the root element 1.2258 + return docElement; 1.2259 + } 1.2260 + 1.2261 + // Don't look in the BODY for non-HTML documents or HTML documents 1.2262 + // with non-HTML roots 1.2263 + // XXX this should be earlier; we shouldn't even look at the document root 1.2264 + // for non-HTML documents. Fix this once we support explicit CSS styling 1.2265 + // of the viewport 1.2266 + // XXX what about XHTML? 1.2267 + nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument)); 1.2268 + if (!htmlDoc || !docElement->IsHTML()) { 1.2269 + return nullptr; 1.2270 + } 1.2271 + 1.2272 + nsCOMPtr<nsIDOMHTMLElement> body; 1.2273 + htmlDoc->GetBody(getter_AddRefs(body)); 1.2274 + nsCOMPtr<nsIContent> bodyElement = do_QueryInterface(body); 1.2275 + 1.2276 + if (!bodyElement || 1.2277 + !bodyElement->NodeInfo()->Equals(nsGkAtoms::body)) { 1.2278 + // The body is not a <body> tag, it's a <frameset>. 1.2279 + return nullptr; 1.2280 + } 1.2281 + 1.2282 + nsRefPtr<nsStyleContext> bodyStyle; 1.2283 + bodyStyle = styleSet->ResolveStyleFor(bodyElement->AsElement(), rootStyle); 1.2284 + 1.2285 + if (CheckOverflow(presContext, bodyStyle->StyleDisplay())) { 1.2286 + // tell caller we stole the overflow style from the body element 1.2287 + return bodyElement; 1.2288 + } 1.2289 + 1.2290 + return nullptr; 1.2291 +} 1.2292 + 1.2293 +nsIFrame* 1.2294 +nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocElement, 1.2295 + nsILayoutHistoryState* aFrameState) 1.2296 +{ 1.2297 + NS_PRECONDITION(mFixedContainingBlock, 1.2298 + "No viewport? Someone forgot to call ConstructRootFrame!"); 1.2299 + NS_PRECONDITION(mFixedContainingBlock == GetRootFrame(), 1.2300 + "Unexpected mFixedContainingBlock"); 1.2301 + NS_PRECONDITION(!mDocElementContainingBlock, 1.2302 + "Shouldn't have a doc element containing block here"); 1.2303 + 1.2304 + // Make sure to call PropagateScrollToViewport before 1.2305 + // SetUpDocElementContainingBlock, since it sets up our scrollbar state 1.2306 + // properly. 1.2307 +#ifdef DEBUG 1.2308 + nsIContent* propagatedScrollFrom = 1.2309 +#endif 1.2310 + PropagateScrollToViewport(); 1.2311 + 1.2312 + SetUpDocElementContainingBlock(aDocElement); 1.2313 + 1.2314 + NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now"); 1.2315 + 1.2316 + nsFrameConstructorState state(mPresShell, mFixedContainingBlock, nullptr, 1.2317 + nullptr, aFrameState); 1.2318 + // Initialize the ancestor filter with null for now; we'll push 1.2319 + // aDocElement once we finish resolving style for it. 1.2320 + state.mTreeMatchContext.InitAncestors(nullptr); 1.2321 + 1.2322 + // XXXbz why, exactly? 1.2323 + if (!mTempFrameTreeState) 1.2324 + state.mPresShell->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState)); 1.2325 + 1.2326 + // Make sure that we'll handle restyles for this document element in 1.2327 + // the future. We need this, because the document element might 1.2328 + // have stale restyle bits from a previous frame constructor for 1.2329 + // this document. Unlike in AddFrameConstructionItems, it's safe to 1.2330 + // unset all element restyle flags, since we don't have any 1.2331 + // siblings. 1.2332 + aDocElement->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS); 1.2333 + 1.2334 + // --------- CREATE AREA OR BOX FRAME ------- 1.2335 + nsRefPtr<nsStyleContext> styleContext; 1.2336 + styleContext = mPresShell->StyleSet()->ResolveStyleFor(aDocElement, 1.2337 + nullptr); 1.2338 + 1.2339 + const nsStyleDisplay* display = styleContext->StyleDisplay(); 1.2340 + 1.2341 + // Ensure that our XBL bindings are installed. 1.2342 + if (display->mBinding) { 1.2343 + // Get the XBL loader. 1.2344 + nsresult rv; 1.2345 + bool resolveStyle; 1.2346 + 1.2347 + nsXBLService* xblService = nsXBLService::GetInstance(); 1.2348 + if (!xblService) { 1.2349 + return nullptr; 1.2350 + } 1.2351 + 1.2352 + nsRefPtr<nsXBLBinding> binding; 1.2353 + rv = xblService->LoadBindings(aDocElement, display->mBinding->GetURI(), 1.2354 + display->mBinding->mOriginPrincipal, 1.2355 + getter_AddRefs(binding), &resolveStyle); 1.2356 + if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED) 1.2357 + return nullptr; // Binding will load asynchronously. 1.2358 + 1.2359 + if (binding) { 1.2360 + // For backwards compat, keep firing the root's constructor 1.2361 + // after all of its kids' constructors. So tell the binding 1.2362 + // manager about it right now. 1.2363 + mDocument->BindingManager()->AddToAttachedQueue(binding); 1.2364 + } 1.2365 + 1.2366 + if (resolveStyle) { 1.2367 + styleContext = mPresShell->StyleSet()->ResolveStyleFor(aDocElement, 1.2368 + nullptr); 1.2369 + display = styleContext->StyleDisplay(); 1.2370 + } 1.2371 + } 1.2372 + 1.2373 + // --------- IF SCROLLABLE WRAP IN SCROLLFRAME -------- 1.2374 + 1.2375 +#ifdef DEBUG 1.2376 + NS_ASSERTION(!display->IsScrollableOverflow() || 1.2377 + state.mPresContext->IsPaginated() || 1.2378 + propagatedScrollFrom == aDocElement, 1.2379 + "Scrollbars should have been propagated to the viewport"); 1.2380 +#endif 1.2381 + 1.2382 + if (MOZ_UNLIKELY(display->mDisplay == NS_STYLE_DISPLAY_NONE)) { 1.2383 + SetUndisplayedContent(aDocElement, styleContext); 1.2384 + return nullptr; 1.2385 + } 1.2386 + 1.2387 + TreeMatchContext::AutoAncestorPusher ancestorPusher(state.mTreeMatchContext); 1.2388 + ancestorPusher.PushAncestorAndStyleScope(aDocElement); 1.2389 + 1.2390 + // Make sure to start any background image loads for the root element now. 1.2391 + styleContext->StartBackgroundImageLoads(); 1.2392 + 1.2393 + nsFrameConstructorSaveState absoluteSaveState; 1.2394 + if (mHasRootAbsPosContainingBlock) { 1.2395 + // Push the absolute containing block now so we can absolutely position 1.2396 + // the root element 1.2397 + mDocElementContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); 1.2398 + state.PushAbsoluteContainingBlock(mDocElementContainingBlock, 1.2399 + mDocElementContainingBlock, 1.2400 + absoluteSaveState); 1.2401 + } 1.2402 + 1.2403 + // The rules from CSS 2.1, section 9.2.4, have already been applied 1.2404 + // by the style system, so we can assume that display->mDisplay is 1.2405 + // either NONE, BLOCK, or TABLE. 1.2406 + 1.2407 + // contentFrame is the primary frame for the root element. newFrame 1.2408 + // is the frame that will be the child of the initial containing block. 1.2409 + // These are usually the same frame but they can be different, in 1.2410 + // particular if the root frame is positioned, in which case 1.2411 + // contentFrame is the out-of-flow frame and newFrame is the 1.2412 + // placeholder. 1.2413 + nsIFrame* contentFrame; 1.2414 + nsIFrame* newFrame; 1.2415 + bool processChildren = false; 1.2416 + 1.2417 + // Check whether we need to build a XUL box or SVG root frame 1.2418 +#ifdef MOZ_XUL 1.2419 + if (aDocElement->IsXUL()) { 1.2420 + contentFrame = NS_NewDocElementBoxFrame(mPresShell, styleContext); 1.2421 + InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock, 1.2422 + contentFrame); 1.2423 + newFrame = contentFrame; 1.2424 + processChildren = true; 1.2425 + } 1.2426 + else 1.2427 +#endif 1.2428 + if (aDocElement->IsSVG()) { 1.2429 + if (aDocElement->Tag() != nsGkAtoms::svg) { 1.2430 + return nullptr; 1.2431 + } 1.2432 + // We're going to call the right function ourselves, so no need to give a 1.2433 + // function to this FrameConstructionData. 1.2434 + 1.2435 + // XXXbz on the other hand, if we converted this whole function to 1.2436 + // FrameConstructionData/Item, then we'd need the right function 1.2437 + // here... but would probably be able to get away with less code in this 1.2438 + // function in general. 1.2439 + // Use a null PendingBinding, since our binding is not in fact pending. 1.2440 + static const FrameConstructionData rootSVGData = FCDATA_DECL(0, nullptr); 1.2441 + already_AddRefed<nsStyleContext> extraRef = 1.2442 + nsRefPtr<nsStyleContext>(styleContext).forget(); 1.2443 + FrameConstructionItem item(&rootSVGData, aDocElement, 1.2444 + aDocElement->Tag(), kNameSpaceID_SVG, 1.2445 + nullptr, extraRef, true, nullptr); 1.2446 + 1.2447 + nsFrameItems frameItems; 1.2448 + contentFrame = ConstructOuterSVG(state, item, mDocElementContainingBlock, 1.2449 + styleContext->StyleDisplay(), 1.2450 + frameItems); 1.2451 + newFrame = frameItems.FirstChild(); 1.2452 + NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames"); 1.2453 + } else if (display->mDisplay == NS_STYLE_DISPLAY_FLEX) { 1.2454 + contentFrame = NS_NewFlexContainerFrame(mPresShell, styleContext); 1.2455 + InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock, 1.2456 + contentFrame); 1.2457 + newFrame = contentFrame; 1.2458 + processChildren = true; 1.2459 + } else if (display->mDisplay == NS_STYLE_DISPLAY_GRID) { 1.2460 + contentFrame = NS_NewGridContainerFrame(mPresShell, styleContext); 1.2461 + InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock, 1.2462 + contentFrame); 1.2463 + newFrame = contentFrame; 1.2464 + processChildren = true; 1.2465 + } else if (display->mDisplay == NS_STYLE_DISPLAY_TABLE) { 1.2466 + // We're going to call the right function ourselves, so no need to give a 1.2467 + // function to this FrameConstructionData. 1.2468 + 1.2469 + // XXXbz on the other hand, if we converted this whole function to 1.2470 + // FrameConstructionData/Item, then we'd need the right function 1.2471 + // here... but would probably be able to get away with less code in this 1.2472 + // function in general. 1.2473 + // Use a null PendingBinding, since our binding is not in fact pending. 1.2474 + static const FrameConstructionData rootTableData = FCDATA_DECL(0, nullptr); 1.2475 + already_AddRefed<nsStyleContext> extraRef = 1.2476 + nsRefPtr<nsStyleContext>(styleContext).forget(); 1.2477 + FrameConstructionItem item(&rootTableData, aDocElement, 1.2478 + aDocElement->Tag(), kNameSpaceID_None, 1.2479 + nullptr, extraRef, true, nullptr); 1.2480 + 1.2481 + nsFrameItems frameItems; 1.2482 + // if the document is a table then just populate it. 1.2483 + contentFrame = ConstructTable(state, item, mDocElementContainingBlock, 1.2484 + styleContext->StyleDisplay(), 1.2485 + frameItems); 1.2486 + newFrame = frameItems.FirstChild(); 1.2487 + NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames"); 1.2488 + } else { 1.2489 + MOZ_ASSERT(display->mDisplay == NS_STYLE_DISPLAY_BLOCK, 1.2490 + "Unhandled display type for root element"); 1.2491 + contentFrame = NS_NewBlockFormattingContext(mPresShell, styleContext); 1.2492 + nsFrameItems frameItems; 1.2493 + // Use a null PendingBinding, since our binding is not in fact pending. 1.2494 + ConstructBlock(state, display, aDocElement, 1.2495 + state.GetGeometricParent(display, 1.2496 + mDocElementContainingBlock), 1.2497 + mDocElementContainingBlock, styleContext, 1.2498 + &contentFrame, frameItems, 1.2499 + display->IsPositioned(contentFrame) ? contentFrame : nullptr, 1.2500 + nullptr); 1.2501 + newFrame = frameItems.FirstChild(); 1.2502 + NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames"); 1.2503 + } 1.2504 + 1.2505 + MOZ_ASSERT(newFrame); 1.2506 + MOZ_ASSERT(contentFrame); 1.2507 + 1.2508 + NS_ASSERTION(processChildren ? !mRootElementFrame : 1.2509 + mRootElementFrame == contentFrame, 1.2510 + "unexpected mRootElementFrame"); 1.2511 + mRootElementFrame = contentFrame; 1.2512 + 1.2513 + // Figure out which frame has the main style for the document element, 1.2514 + // assigning it to mRootElementStyleFrame. 1.2515 + // Backgrounds should be propagated from that frame to the viewport. 1.2516 + mRootElementStyleFrame = contentFrame->GetParentStyleContextFrame(); 1.2517 + bool isChild = mRootElementStyleFrame && 1.2518 + mRootElementStyleFrame->GetParent() == contentFrame; 1.2519 + if (!isChild) { 1.2520 + mRootElementStyleFrame = mRootElementFrame; 1.2521 + } 1.2522 + 1.2523 + if (processChildren) { 1.2524 + // Still need to process the child content 1.2525 + nsFrameItems childItems; 1.2526 + 1.2527 + NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame) && 1.2528 + !contentFrame->IsFrameOfType(nsIFrame::eSVG), 1.2529 + "Only XUL frames should reach here"); 1.2530 + // Use a null PendingBinding, since our binding is not in fact pending. 1.2531 + ProcessChildren(state, aDocElement, styleContext, contentFrame, true, 1.2532 + childItems, false, nullptr); 1.2533 + 1.2534 + // Set the initial child lists 1.2535 + contentFrame->SetInitialChildList(kPrincipalList, childItems); 1.2536 + } 1.2537 + 1.2538 + // set the primary frame 1.2539 + aDocElement->SetPrimaryFrame(contentFrame); 1.2540 + 1.2541 + SetInitialSingleChild(mDocElementContainingBlock, newFrame); 1.2542 + 1.2543 + return newFrame; 1.2544 +} 1.2545 + 1.2546 + 1.2547 +nsIFrame* 1.2548 +nsCSSFrameConstructor::ConstructRootFrame() 1.2549 +{ 1.2550 + AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC); 1.2551 + 1.2552 + nsStyleSet *styleSet = mPresShell->StyleSet(); 1.2553 + 1.2554 + // Set up our style rule observer. 1.2555 + // XXXbz wouldn't this make more sense as part of presshell init? 1.2556 + { 1.2557 + styleSet->SetBindingManager(mDocument->BindingManager()); 1.2558 + } 1.2559 + 1.2560 + // --------- BUILD VIEWPORT ----------- 1.2561 + nsIFrame* viewportFrame = nullptr; 1.2562 + nsRefPtr<nsStyleContext> viewportPseudoStyle; 1.2563 + 1.2564 + viewportPseudoStyle = 1.2565 + styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::viewport, nullptr); 1.2566 + 1.2567 + viewportFrame = NS_NewViewportFrame(mPresShell, viewportPseudoStyle); 1.2568 + 1.2569 + // XXXbz do we _have_ to pass a null content pointer to that frame? 1.2570 + // Would it really kill us to pass in the root element or something? 1.2571 + // What would that break? 1.2572 + viewportFrame->Init(nullptr, nullptr, nullptr); 1.2573 + 1.2574 + // Bind the viewport frame to the root view 1.2575 + nsView* rootView = mPresShell->GetViewManager()->GetRootView(); 1.2576 + viewportFrame->SetView(rootView); 1.2577 + 1.2578 + nsContainerFrame::SyncFrameViewProperties(mPresShell->GetPresContext(), viewportFrame, 1.2579 + viewportPseudoStyle, rootView); 1.2580 + nsContainerFrame::SyncWindowProperties(mPresShell->GetPresContext(), viewportFrame, 1.2581 + rootView); 1.2582 + 1.2583 + // The viewport is the containing block for 'fixed' elements 1.2584 + mFixedContainingBlock = viewportFrame; 1.2585 + // Make it an absolute container for fixed-pos elements 1.2586 + mFixedContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); 1.2587 + mFixedContainingBlock->MarkAsAbsoluteContainingBlock(); 1.2588 + 1.2589 + return viewportFrame; 1.2590 +} 1.2591 + 1.2592 +void 1.2593 +nsCSSFrameConstructor::SetUpDocElementContainingBlock(nsIContent* aDocElement) 1.2594 +{ 1.2595 + NS_PRECONDITION(aDocElement, "No element?"); 1.2596 + NS_PRECONDITION(!aDocElement->GetParent(), "Not root content?"); 1.2597 + NS_PRECONDITION(aDocElement->GetCurrentDoc(), "Not in a document?"); 1.2598 + NS_PRECONDITION(aDocElement->GetCurrentDoc()->GetRootElement() == 1.2599 + aDocElement, "Not the root of the document?"); 1.2600 + 1.2601 + /* 1.2602 + how the root frame hierarchy should look 1.2603 + 1.2604 + Galley presentation, non-XUL, with scrolling: 1.2605 + 1.2606 + ViewportFrame [fixed-cb] 1.2607 + nsHTMLScrollFrame 1.2608 + nsCanvasFrame [abs-cb] 1.2609 + root element frame (nsBlockFrame, nsSVGOuterSVGFrame, 1.2610 + nsTableOuterFrame, nsPlaceholderFrame) 1.2611 + 1.2612 + Galley presentation, XUL 1.2613 + 1.2614 + ViewportFrame [fixed-cb] 1.2615 + nsRootBoxFrame 1.2616 + root element frame (nsDocElementBoxFrame) 1.2617 + 1.2618 + Print presentation, non-XUL 1.2619 + 1.2620 + ViewportFrame 1.2621 + nsSimplePageSequenceFrame 1.2622 + nsPageFrame [fixed-cb] 1.2623 + nsPageContentFrame 1.2624 + nsCanvasFrame [abs-cb] 1.2625 + root element frame (nsBlockFrame, nsSVGOuterSVGFrame, 1.2626 + nsTableOuterFrame, nsPlaceholderFrame) 1.2627 + 1.2628 + Print-preview presentation, non-XUL 1.2629 + 1.2630 + ViewportFrame 1.2631 + nsHTMLScrollFrame 1.2632 + nsSimplePageSequenceFrame 1.2633 + nsPageFrame [fixed-cb] 1.2634 + nsPageContentFrame 1.2635 + nsCanvasFrame [abs-cb] 1.2636 + root element frame (nsBlockFrame, nsSVGOuterSVGFrame, 1.2637 + nsTableOuterFrame, nsPlaceholderFrame) 1.2638 + 1.2639 + Print/print preview of XUL is not supported. 1.2640 + [fixed-cb]: the default containing block for fixed-pos content 1.2641 + [abs-cb]: the default containing block for abs-pos content 1.2642 + 1.2643 + Meaning of nsCSSFrameConstructor fields: 1.2644 + mRootElementFrame is "root element frame". This is the primary frame for 1.2645 + the root element. 1.2646 + mDocElementContainingBlock is the parent of mRootElementFrame 1.2647 + (i.e. nsCanvasFrame or nsRootBoxFrame) 1.2648 + mFixedContainingBlock is the [fixed-cb] 1.2649 + mGfxScrollFrame is the nsHTMLScrollFrame mentioned above, or null if there isn't one 1.2650 + mPageSequenceFrame is the nsSimplePageSequenceFrame, or null if there isn't one 1.2651 + */ 1.2652 + 1.2653 + // --------- CREATE ROOT FRAME ------- 1.2654 + 1.2655 + 1.2656 + // Create the root frame. The document element's frame is a child of the 1.2657 + // root frame. 1.2658 + // 1.2659 + // The root frame serves two purposes: 1.2660 + // - reserves space for any margins needed for the document element's frame 1.2661 + // - renders the document element's background. This ensures the background covers 1.2662 + // the entire canvas as specified by the CSS2 spec 1.2663 + 1.2664 + nsPresContext* presContext = mPresShell->GetPresContext(); 1.2665 + bool isPaginated = presContext->IsRootPaginatedDocument(); 1.2666 + nsIFrame* viewportFrame = mFixedContainingBlock; 1.2667 + nsStyleContext* viewportPseudoStyle = viewportFrame->StyleContext(); 1.2668 + 1.2669 + nsIFrame* rootFrame = nullptr; 1.2670 + nsIAtom* rootPseudo; 1.2671 + 1.2672 + if (!isPaginated) { 1.2673 +#ifdef MOZ_XUL 1.2674 + if (aDocElement->IsXUL()) 1.2675 + { 1.2676 + // pass a temporary stylecontext, the correct one will be set later 1.2677 + rootFrame = NS_NewRootBoxFrame(mPresShell, viewportPseudoStyle); 1.2678 + } else 1.2679 +#endif 1.2680 + { 1.2681 + // pass a temporary stylecontext, the correct one will be set later 1.2682 + rootFrame = NS_NewCanvasFrame(mPresShell, viewportPseudoStyle); 1.2683 + mHasRootAbsPosContainingBlock = true; 1.2684 + } 1.2685 + 1.2686 + rootPseudo = nsCSSAnonBoxes::canvas; 1.2687 + mDocElementContainingBlock = rootFrame; 1.2688 + } else { 1.2689 + // Create a page sequence frame 1.2690 + rootFrame = NS_NewSimplePageSequenceFrame(mPresShell, viewportPseudoStyle); 1.2691 + mPageSequenceFrame = rootFrame; 1.2692 + rootPseudo = nsCSSAnonBoxes::pageSequence; 1.2693 + } 1.2694 + 1.2695 + 1.2696 + // --------- IF SCROLLABLE WRAP IN SCROLLFRAME -------- 1.2697 + 1.2698 + // If the device supports scrolling (e.g., in galley mode on the screen and 1.2699 + // for print-preview, but not when printing), then create a scroll frame that 1.2700 + // will act as the scrolling mechanism for the viewport. 1.2701 + // XXX Do we even need a viewport when printing to a printer? 1.2702 + 1.2703 + bool isHTML = aDocElement->IsHTML(); 1.2704 + bool isXUL = false; 1.2705 + 1.2706 + if (!isHTML) { 1.2707 + isXUL = aDocElement->IsXUL(); 1.2708 + } 1.2709 + 1.2710 + // Never create scrollbars for XUL documents 1.2711 + bool isScrollable = isPaginated ? presContext->HasPaginatedScrolling() : !isXUL; 1.2712 + 1.2713 + // We no longer need to do overflow propagation here. It's taken care of 1.2714 + // when we construct frames for the element whose overflow might be 1.2715 + // propagated 1.2716 + NS_ASSERTION(!isScrollable || !isXUL, 1.2717 + "XUL documents should never be scrollable - see above"); 1.2718 + 1.2719 + nsIFrame* newFrame = rootFrame; 1.2720 + nsRefPtr<nsStyleContext> rootPseudoStyle; 1.2721 + // we must create a state because if the scrollbars are GFX it needs the 1.2722 + // state to build the scrollbar frames. 1.2723 + nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr); 1.2724 + 1.2725 + // Start off with the viewport as parent; we'll adjust it as needed. 1.2726 + nsIFrame* parentFrame = viewportFrame; 1.2727 + 1.2728 + nsStyleSet* styleSet = mPresShell->StyleSet(); 1.2729 + // If paginated, make sure we don't put scrollbars in 1.2730 + if (!isScrollable) { 1.2731 + rootPseudoStyle = styleSet->ResolveAnonymousBoxStyle(rootPseudo, 1.2732 + viewportPseudoStyle); 1.2733 + } else { 1.2734 + if (rootPseudo == nsCSSAnonBoxes::canvas) { 1.2735 + rootPseudo = nsCSSAnonBoxes::scrolledCanvas; 1.2736 + } else { 1.2737 + NS_ASSERTION(rootPseudo == nsCSSAnonBoxes::pageSequence, 1.2738 + "Unknown root pseudo"); 1.2739 + rootPseudo = nsCSSAnonBoxes::scrolledPageSequence; 1.2740 + } 1.2741 + 1.2742 + // Build the frame. We give it the content we are wrapping which is the 1.2743 + // document element, the root frame, the parent view port frame, and we 1.2744 + // should get back the new frame and the scrollable view if one was 1.2745 + // created. 1.2746 + 1.2747 + // resolve a context for the scrollframe 1.2748 + nsRefPtr<nsStyleContext> styleContext; 1.2749 + styleContext = styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::viewportScroll, 1.2750 + viewportPseudoStyle); 1.2751 + 1.2752 + // Note that the viewport scrollframe is always built with 1.2753 + // overflow:auto style. This forces the scroll frame to create 1.2754 + // anonymous content for both scrollbars. This is necessary even 1.2755 + // if the HTML or BODY elements are overriding the viewport 1.2756 + // scroll style to 'hidden' --- dynamic style changes might put 1.2757 + // scrollbars back on the viewport and we don't want to have to 1.2758 + // reframe the viewport to create the scrollbar content. 1.2759 + newFrame = nullptr; 1.2760 + rootPseudoStyle = BeginBuildingScrollFrame( state, 1.2761 + aDocElement, 1.2762 + styleContext, 1.2763 + viewportFrame, 1.2764 + rootPseudo, 1.2765 + true, 1.2766 + newFrame); 1.2767 + parentFrame = newFrame; 1.2768 + mGfxScrollFrame = newFrame; 1.2769 + } 1.2770 + 1.2771 + rootFrame->SetStyleContextWithoutNotification(rootPseudoStyle); 1.2772 + rootFrame->Init(aDocElement, parentFrame, nullptr); 1.2773 + 1.2774 + if (isScrollable) { 1.2775 + FinishBuildingScrollFrame(parentFrame, rootFrame); 1.2776 + } 1.2777 + 1.2778 + if (isPaginated) { // paginated 1.2779 + // Create the first page 1.2780 + // Set the initial child lists 1.2781 + nsIFrame* canvasFrame; 1.2782 + nsIFrame* pageFrame = 1.2783 + ConstructPageFrame(mPresShell, presContext, rootFrame, nullptr, 1.2784 + canvasFrame); 1.2785 + SetInitialSingleChild(rootFrame, pageFrame); 1.2786 + 1.2787 + // The eventual parent of the document element frame. 1.2788 + // XXX should this be set for every new page (in ConstructPageFrame)? 1.2789 + mDocElementContainingBlock = canvasFrame; 1.2790 + mHasRootAbsPosContainingBlock = true; 1.2791 + } 1.2792 + 1.2793 + if (viewportFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) { 1.2794 + SetInitialSingleChild(viewportFrame, newFrame); 1.2795 + } else { 1.2796 + nsFrameList newFrameList(newFrame, newFrame); 1.2797 + viewportFrame->AppendFrames(kPrincipalList, newFrameList); 1.2798 + } 1.2799 +} 1.2800 + 1.2801 +nsIFrame* 1.2802 +nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell* aPresShell, 1.2803 + nsPresContext* aPresContext, 1.2804 + nsIFrame* aParentFrame, 1.2805 + nsIFrame* aPrevPageFrame, 1.2806 + nsIFrame*& aCanvasFrame) 1.2807 +{ 1.2808 + nsStyleContext* parentStyleContext = aParentFrame->StyleContext(); 1.2809 + nsStyleSet *styleSet = aPresShell->StyleSet(); 1.2810 + 1.2811 + nsRefPtr<nsStyleContext> pagePseudoStyle; 1.2812 + pagePseudoStyle = styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::page, 1.2813 + parentStyleContext); 1.2814 + 1.2815 + nsIFrame* pageFrame = NS_NewPageFrame(aPresShell, pagePseudoStyle); 1.2816 + 1.2817 + // Initialize the page frame and force it to have a view. This makes printing of 1.2818 + // the pages easier and faster. 1.2819 + pageFrame->Init(nullptr, aParentFrame, aPrevPageFrame); 1.2820 + 1.2821 + nsRefPtr<nsStyleContext> pageContentPseudoStyle; 1.2822 + pageContentPseudoStyle = 1.2823 + styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::pageContent, 1.2824 + pagePseudoStyle); 1.2825 + 1.2826 + nsIFrame* pageContentFrame = NS_NewPageContentFrame(aPresShell, pageContentPseudoStyle); 1.2827 + 1.2828 + // Initialize the page content frame and force it to have a view. Also make it the 1.2829 + // containing block for fixed elements which are repeated on every page. 1.2830 + nsIFrame* prevPageContentFrame = nullptr; 1.2831 + if (aPrevPageFrame) { 1.2832 + prevPageContentFrame = aPrevPageFrame->GetFirstPrincipalChild(); 1.2833 + NS_ASSERTION(prevPageContentFrame, "missing page content frame"); 1.2834 + } 1.2835 + pageContentFrame->Init(nullptr, pageFrame, prevPageContentFrame); 1.2836 + SetInitialSingleChild(pageFrame, pageContentFrame); 1.2837 + mFixedContainingBlock = pageContentFrame; 1.2838 + // Make it an absolute container for fixed-pos elements 1.2839 + mFixedContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); 1.2840 + mFixedContainingBlock->MarkAsAbsoluteContainingBlock(); 1.2841 + 1.2842 + nsRefPtr<nsStyleContext> canvasPseudoStyle; 1.2843 + canvasPseudoStyle = styleSet->ResolveAnonymousBoxStyle(nsCSSAnonBoxes::canvas, 1.2844 + pageContentPseudoStyle); 1.2845 + 1.2846 + aCanvasFrame = NS_NewCanvasFrame(aPresShell, canvasPseudoStyle); 1.2847 + 1.2848 + nsIFrame* prevCanvasFrame = nullptr; 1.2849 + if (prevPageContentFrame) { 1.2850 + prevCanvasFrame = prevPageContentFrame->GetFirstPrincipalChild(); 1.2851 + NS_ASSERTION(prevCanvasFrame, "missing canvas frame"); 1.2852 + } 1.2853 + aCanvasFrame->Init(nullptr, pageContentFrame, prevCanvasFrame); 1.2854 + SetInitialSingleChild(pageContentFrame, aCanvasFrame); 1.2855 + return pageFrame; 1.2856 +} 1.2857 + 1.2858 +/* static */ 1.2859 +nsIFrame* 1.2860 +nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell* aPresShell, 1.2861 + nsIContent* aContent, 1.2862 + nsIFrame* aFrame, 1.2863 + nsStyleContext* aStyleContext, 1.2864 + nsIFrame* aParentFrame, 1.2865 + nsIFrame* aPrevInFlow, 1.2866 + nsFrameState aTypeBit) 1.2867 +{ 1.2868 + nsRefPtr<nsStyleContext> placeholderStyle = aPresShell->StyleSet()-> 1.2869 + ResolveStyleForNonElement(aStyleContext->GetParent()); 1.2870 + 1.2871 + // The placeholder frame gets a pseudo style context 1.2872 + nsPlaceholderFrame* placeholderFrame = 1.2873 + (nsPlaceholderFrame*)NS_NewPlaceholderFrame(aPresShell, placeholderStyle, 1.2874 + aTypeBit); 1.2875 + 1.2876 + placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow); 1.2877 + 1.2878 + // The placeholder frame has a pointer back to the out-of-flow frame 1.2879 + placeholderFrame->SetOutOfFlowFrame(aFrame); 1.2880 + 1.2881 + aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW); 1.2882 + 1.2883 + // Add mapping from absolutely positioned frame to its placeholder frame 1.2884 + aPresShell->FrameManager()->RegisterPlaceholderFrame(placeholderFrame); 1.2885 + 1.2886 + return placeholderFrame; 1.2887 +} 1.2888 + 1.2889 +// Clears any lazy bits set in the range [aStartContent, aEndContent). If 1.2890 +// aEndContent is null, that means to clear bits in all siblings starting with 1.2891 +// aStartContent. aStartContent must not be null unless aEndContent is also 1.2892 +// null. We do this so that when new children are inserted under elements whose 1.2893 +// frame is a leaf the new children don't cause us to try to construct frames 1.2894 +// for the existing children again. 1.2895 +static inline void 1.2896 +ClearLazyBits(nsIContent* aStartContent, nsIContent* aEndContent) 1.2897 +{ 1.2898 + NS_PRECONDITION(aStartContent || !aEndContent, 1.2899 + "Must have start child if we have an end child"); 1.2900 + for (nsIContent* cur = aStartContent; cur != aEndContent; 1.2901 + cur = cur->GetNextSibling()) { 1.2902 + cur->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME); 1.2903 + } 1.2904 +} 1.2905 + 1.2906 +nsIFrame* 1.2907 +nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState, 1.2908 + FrameConstructionItem& aItem, 1.2909 + nsIFrame* aParentFrame, 1.2910 + const nsStyleDisplay* aStyleDisplay, 1.2911 + nsFrameItems& aFrameItems) 1.2912 +{ 1.2913 + nsIContent* const content = aItem.mContent; 1.2914 + nsStyleContext* const styleContext = aItem.mStyleContext; 1.2915 + 1.2916 + // Construct a frame-based listbox or combobox 1.2917 + dom::HTMLSelectElement* sel = dom::HTMLSelectElement::FromContent(content); 1.2918 + MOZ_ASSERT(sel); 1.2919 + if (sel->IsCombobox()) { 1.2920 + // Construct a frame-based combo box. 1.2921 + // The frame-based combo box is built out of three parts. A display area, a button and 1.2922 + // a dropdown list. The display area and button are created through anonymous content. 1.2923 + // The drop-down list's frame is created explicitly. The combobox frame shares its content 1.2924 + // with the drop-down list. 1.2925 + nsFrameState flags = NS_BLOCK_FLOAT_MGR; 1.2926 + nsIFrame* comboboxFrame = NS_NewComboboxControlFrame(mPresShell, styleContext, flags); 1.2927 + 1.2928 + // Save the history state so we don't restore during construction 1.2929 + // since the complete tree is required before we restore. 1.2930 + nsILayoutHistoryState *historyState = aState.mFrameState; 1.2931 + aState.mFrameState = nullptr; 1.2932 + // Initialize the combobox frame 1.2933 + InitAndRestoreFrame(aState, content, 1.2934 + aState.GetGeometricParent(aStyleDisplay, aParentFrame), 1.2935 + comboboxFrame); 1.2936 + 1.2937 + aState.AddChild(comboboxFrame, aFrameItems, content, styleContext, 1.2938 + aParentFrame); 1.2939 + 1.2940 + nsIComboboxControlFrame* comboBox = do_QueryFrame(comboboxFrame); 1.2941 + NS_ASSERTION(comboBox, "NS_NewComboboxControlFrame returned frame that " 1.2942 + "doesn't implement nsIComboboxControlFrame"); 1.2943 + 1.2944 + // Resolve pseudo element style for the dropdown list 1.2945 + nsRefPtr<nsStyleContext> listStyle; 1.2946 + listStyle = mPresShell->StyleSet()-> 1.2947 + ResolveAnonymousBoxStyle(nsCSSAnonBoxes::dropDownList, styleContext); 1.2948 + 1.2949 + // Create a listbox 1.2950 + nsIFrame* listFrame = NS_NewListControlFrame(mPresShell, listStyle); 1.2951 + 1.2952 + // Notify the listbox that it is being used as a dropdown list. 1.2953 + nsIListControlFrame * listControlFrame = do_QueryFrame(listFrame); 1.2954 + if (listControlFrame) { 1.2955 + listControlFrame->SetComboboxFrame(comboboxFrame); 1.2956 + } 1.2957 + // Notify combobox that it should use the listbox as it's popup 1.2958 + comboBox->SetDropDown(listFrame); 1.2959 + 1.2960 + NS_ASSERTION(!listFrame->IsPositioned(), 1.2961 + "Ended up with positioned dropdown list somehow."); 1.2962 + NS_ASSERTION(!listFrame->IsFloating(), 1.2963 + "Ended up with floating dropdown list somehow."); 1.2964 + 1.2965 + // Initialize the scroll frame positioned. Note that it is NOT 1.2966 + // initialized as absolutely positioned. 1.2967 + nsIFrame* scrolledFrame = NS_NewSelectsAreaFrame(mPresShell, styleContext, flags); 1.2968 + 1.2969 + InitializeSelectFrame(aState, listFrame, scrolledFrame, content, 1.2970 + comboboxFrame, listStyle, true, 1.2971 + aItem.mPendingBinding, aFrameItems); 1.2972 + 1.2973 + NS_ASSERTION(listFrame->GetView(), "ListFrame's view is nullptr"); 1.2974 + 1.2975 + // Create display and button frames from the combobox's anonymous content. 1.2976 + // The anonymous content is appended to existing anonymous content for this 1.2977 + // element (the scrollbars). 1.2978 + 1.2979 + nsFrameItems childItems; 1.2980 + CreateAnonymousFrames(aState, content, comboboxFrame, 1.2981 + aItem.mPendingBinding, childItems); 1.2982 + 1.2983 + comboboxFrame->SetInitialChildList(kPrincipalList, childItems); 1.2984 + 1.2985 + // Initialize the additional popup child list which contains the 1.2986 + // dropdown list frame. 1.2987 + nsFrameItems popupItems; 1.2988 + popupItems.AddChild(listFrame); 1.2989 + comboboxFrame->SetInitialChildList(nsIFrame::kSelectPopupList, 1.2990 + popupItems); 1.2991 + 1.2992 + aState.mFrameState = historyState; 1.2993 + if (aState.mFrameState) { 1.2994 + // Restore frame state for the entire subtree of |comboboxFrame|. 1.2995 + RestoreFrameState(comboboxFrame, aState.mFrameState); 1.2996 + } 1.2997 + return comboboxFrame; 1.2998 + } 1.2999 + 1.3000 + // Listbox, not combobox 1.3001 + nsIFrame* listFrame = NS_NewListControlFrame(mPresShell, styleContext); 1.3002 + 1.3003 + nsIFrame* scrolledFrame = NS_NewSelectsAreaFrame( 1.3004 + mPresShell, styleContext, NS_BLOCK_FLOAT_MGR); 1.3005 + 1.3006 + // ******* this code stolen from Initialze ScrollFrame ******** 1.3007 + // please adjust this code to use BuildScrollFrame. 1.3008 + 1.3009 + InitializeSelectFrame(aState, listFrame, scrolledFrame, content, 1.3010 + aParentFrame, styleContext, false, 1.3011 + aItem.mPendingBinding, aFrameItems); 1.3012 + 1.3013 + return listFrame; 1.3014 +} 1.3015 + 1.3016 +/** 1.3017 + * Used to be InitializeScrollFrame but now it's only used for the select tag 1.3018 + * But the select tag should really be fixed to use GFX scrollbars that can 1.3019 + * be create with BuildScrollFrame. 1.3020 + */ 1.3021 +nsresult 1.3022 +nsCSSFrameConstructor::InitializeSelectFrame(nsFrameConstructorState& aState, 1.3023 + nsIFrame* scrollFrame, 1.3024 + nsIFrame* scrolledFrame, 1.3025 + nsIContent* aContent, 1.3026 + nsIFrame* aParentFrame, 1.3027 + nsStyleContext* aStyleContext, 1.3028 + bool aBuildCombobox, 1.3029 + PendingBinding* aPendingBinding, 1.3030 + nsFrameItems& aFrameItems) 1.3031 +{ 1.3032 + const nsStyleDisplay* display = aStyleContext->StyleDisplay(); 1.3033 + 1.3034 + // Initialize it 1.3035 + nsIFrame* geometricParent = aState.GetGeometricParent(display, aParentFrame); 1.3036 + 1.3037 + // We don't call InitAndRestoreFrame for scrollFrame because we can only 1.3038 + // restore the frame state after its parts have been created (in particular, 1.3039 + // the scrollable view). So we have to split Init and Restore. 1.3040 + 1.3041 + // Initialize the frame 1.3042 + scrollFrame->Init(aContent, geometricParent, nullptr); 1.3043 + 1.3044 + if (!aBuildCombobox) { 1.3045 + aState.AddChild(scrollFrame, aFrameItems, aContent, 1.3046 + aStyleContext, aParentFrame); 1.3047 + } 1.3048 + 1.3049 + if (aBuildCombobox) { 1.3050 + nsContainerFrame::CreateViewForFrame(scrollFrame, true); 1.3051 + } 1.3052 + 1.3053 + BuildScrollFrame(aState, aContent, aStyleContext, scrolledFrame, 1.3054 + geometricParent, scrollFrame); 1.3055 + 1.3056 + if (aState.mFrameState) { 1.3057 + // Restore frame state for the scroll frame 1.3058 + RestoreFrameStateFor(scrollFrame, aState.mFrameState); 1.3059 + } 1.3060 + 1.3061 + // Process children 1.3062 + nsFrameItems childItems; 1.3063 + 1.3064 + ProcessChildren(aState, aContent, aStyleContext, scrolledFrame, false, 1.3065 + childItems, false, aPendingBinding); 1.3066 + 1.3067 + // Set the scrolled frame's initial child lists 1.3068 + scrolledFrame->SetInitialChildList(kPrincipalList, childItems); 1.3069 + return NS_OK; 1.3070 +} 1.3071 + 1.3072 +nsIFrame* 1.3073 +nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState& aState, 1.3074 + FrameConstructionItem& aItem, 1.3075 + nsIFrame* aParentFrame, 1.3076 + const nsStyleDisplay* aStyleDisplay, 1.3077 + nsFrameItems& aFrameItems) 1.3078 +{ 1.3079 + nsIContent* const content = aItem.mContent; 1.3080 + nsStyleContext* const styleContext = aItem.mStyleContext; 1.3081 + 1.3082 + nsIFrame* fieldsetFrame = NS_NewFieldSetFrame(mPresShell, styleContext); 1.3083 + 1.3084 + // Initialize it 1.3085 + InitAndRestoreFrame(aState, content, 1.3086 + aState.GetGeometricParent(aStyleDisplay, aParentFrame), 1.3087 + fieldsetFrame); 1.3088 + 1.3089 + // Resolve style and initialize the frame 1.3090 + nsRefPtr<nsStyleContext> fieldsetContentStyle; 1.3091 + fieldsetContentStyle = mPresShell->StyleSet()-> 1.3092 + ResolveAnonymousBoxStyle(nsCSSAnonBoxes::fieldsetContent, styleContext); 1.3093 + 1.3094 + const nsStyleDisplay* fieldsetContentDisplay = fieldsetContentStyle->StyleDisplay(); 1.3095 + bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow(); 1.3096 + nsIFrame* scrollFrame = nullptr; 1.3097 + if (isScrollable) { 1.3098 + fieldsetContentStyle = 1.3099 + BeginBuildingScrollFrame(aState, content, fieldsetContentStyle, 1.3100 + fieldsetFrame, nsCSSAnonBoxes::scrolledContent, 1.3101 + false, scrollFrame); 1.3102 + } 1.3103 + 1.3104 + nsIFrame* blockFrame = NS_NewBlockFrame(mPresShell, fieldsetContentStyle, 1.3105 + NS_BLOCK_FLOAT_MGR | 1.3106 + NS_BLOCK_MARGIN_ROOT); 1.3107 + InitAndRestoreFrame(aState, content, 1.3108 + scrollFrame ? scrollFrame : fieldsetFrame, blockFrame); 1.3109 + 1.3110 + aState.AddChild(fieldsetFrame, aFrameItems, content, styleContext, aParentFrame); 1.3111 + 1.3112 + // Process children 1.3113 + nsFrameConstructorSaveState absoluteSaveState; 1.3114 + nsFrameItems childItems; 1.3115 + 1.3116 + blockFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); 1.3117 + if (fieldsetFrame->IsPositioned()) { 1.3118 + aState.PushAbsoluteContainingBlock(blockFrame, fieldsetFrame, absoluteSaveState); 1.3119 + } 1.3120 + 1.3121 + ProcessChildren(aState, content, styleContext, blockFrame, true, 1.3122 + childItems, true, aItem.mPendingBinding); 1.3123 + 1.3124 + nsFrameItems fieldsetKids; 1.3125 + fieldsetKids.AddChild(scrollFrame ? scrollFrame : blockFrame); 1.3126 + 1.3127 + for (nsFrameList::Enumerator e(childItems); !e.AtEnd(); e.Next()) { 1.3128 + nsIFrame* child = e.get(); 1.3129 + if (child->GetContentInsertionFrame()->GetType() == nsGkAtoms::legendFrame) { 1.3130 + // We want the legend to be the first frame in the fieldset child list. 1.3131 + // That way the EventStateManager will do the right thing when tabbing 1.3132 + // from a selection point within the legend (bug 236071), which is 1.3133 + // used for implementing legend access keys (bug 81481). 1.3134 + // GetAdjustedParentFrame() below depends on this frame order. 1.3135 + childItems.RemoveFrame(child); 1.3136 + // Make sure to reparent the legend so it has the fieldset as the parent. 1.3137 + fieldsetKids.InsertFrame(fieldsetFrame, nullptr, child); 1.3138 + if (scrollFrame) { 1.3139 + StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary( 1.3140 + child, blockFrame); 1.3141 + } 1.3142 + break; 1.3143 + } 1.3144 + } 1.3145 + 1.3146 + if (isScrollable) { 1.3147 + FinishBuildingScrollFrame(scrollFrame, blockFrame); 1.3148 + } 1.3149 + 1.3150 + // Set the inner frame's initial child lists 1.3151 + blockFrame->SetInitialChildList(kPrincipalList, childItems); 1.3152 + 1.3153 + // Set the outer frame's initial child list 1.3154 + fieldsetFrame->SetInitialChildList(kPrincipalList, fieldsetKids); 1.3155 + 1.3156 + fieldsetFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT); 1.3157 + 1.3158 + // Our new frame returned is the outer frame, which is the fieldset frame. 1.3159 + return fieldsetFrame; 1.3160 +} 1.3161 + 1.3162 +static nsIFrame* 1.3163 +FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame) 1.3164 +{ 1.3165 + for (nsIFrame* f = aFrame->GetParent(); f; f = f->GetParent()) { 1.3166 + NS_ASSERTION(f->IsGeneratedContentFrame(), 1.3167 + "should not have exited generated content"); 1.3168 + nsIAtom* pseudo = f->StyleContext()->GetPseudo(); 1.3169 + if (pseudo == nsCSSPseudoElements::before || 1.3170 + pseudo == nsCSSPseudoElements::after) 1.3171 + return f; 1.3172 + } 1.3173 + return nullptr; 1.3174 +} 1.3175 + 1.3176 +#define SIMPLE_FCDATA(_func) FCDATA_DECL(0, _func) 1.3177 +#define FULL_CTOR_FCDATA(_flags, _func) \ 1.3178 + { _flags | FCDATA_FUNC_IS_FULL_CTOR, { nullptr }, _func, nullptr } 1.3179 + 1.3180 +/* static */ 1.3181 +const nsCSSFrameConstructor::FrameConstructionData* 1.3182 +nsCSSFrameConstructor::FindTextData(nsIFrame* aParentFrame) 1.3183 +{ 1.3184 + if (aParentFrame && IsFrameForSVG(aParentFrame)) { 1.3185 + nsIFrame *ancestorFrame = 1.3186 + nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame); 1.3187 + if (ancestorFrame) { 1.3188 + static const FrameConstructionData sSVGTextData = 1.3189 + FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_SVG_TEXT, 1.3190 + NS_NewTextFrame); 1.3191 + if (ancestorFrame->IsSVGText()) { 1.3192 + return &sSVGTextData; 1.3193 + } 1.3194 + } 1.3195 + return nullptr; 1.3196 + } 1.3197 + 1.3198 + static const FrameConstructionData sTextData = 1.3199 + FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT, NS_NewTextFrame); 1.3200 + return &sTextData; 1.3201 +} 1.3202 + 1.3203 +void 1.3204 +nsCSSFrameConstructor::ConstructTextFrame(const FrameConstructionData* aData, 1.3205 + nsFrameConstructorState& aState, 1.3206 + nsIContent* aContent, 1.3207 + nsIFrame* aParentFrame, 1.3208 + nsStyleContext* aStyleContext, 1.3209 + nsFrameItems& aFrameItems) 1.3210 +{ 1.3211 + NS_PRECONDITION(aData, "Must have frame construction data"); 1.3212 + 1.3213 + nsIFrame* newFrame = (*aData->mFunc.mCreationFunc)(mPresShell, aStyleContext); 1.3214 + 1.3215 + InitAndRestoreFrame(aState, aContent, aParentFrame, newFrame); 1.3216 + 1.3217 + // We never need to create a view for a text frame. 1.3218 + 1.3219 + if (newFrame->IsGeneratedContentFrame()) { 1.3220 + nsAutoPtr<nsGenConInitializer> initializer; 1.3221 + initializer = 1.3222 + static_cast<nsGenConInitializer*>( 1.3223 + aContent->UnsetProperty(nsGkAtoms::genConInitializerProperty)); 1.3224 + if (initializer) { 1.3225 + if (initializer->mNode->InitTextFrame(initializer->mList, 1.3226 + FindAncestorWithGeneratedContentPseudo(newFrame), newFrame)) { 1.3227 + (this->*(initializer->mDirtyAll))(); 1.3228 + } 1.3229 + initializer->mNode.forget(); 1.3230 + } 1.3231 + } 1.3232 + 1.3233 + // Add the newly constructed frame to the flow 1.3234 + aFrameItems.AddChild(newFrame); 1.3235 + 1.3236 + if (!aState.mCreatingExtraFrames) 1.3237 + aContent->SetPrimaryFrame(newFrame); 1.3238 +} 1.3239 + 1.3240 +/* static */ 1.3241 +const nsCSSFrameConstructor::FrameConstructionData* 1.3242 +nsCSSFrameConstructor::FindDataByInt(int32_t aInt, 1.3243 + Element* aElement, 1.3244 + nsStyleContext* aStyleContext, 1.3245 + const FrameConstructionDataByInt* aDataPtr, 1.3246 + uint32_t aDataLength) 1.3247 +{ 1.3248 + for (const FrameConstructionDataByInt *curData = aDataPtr, 1.3249 + *endData = aDataPtr + aDataLength; 1.3250 + curData != endData; 1.3251 + ++curData) { 1.3252 + if (curData->mInt == aInt) { 1.3253 + const FrameConstructionData* data = &curData->mData; 1.3254 + if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) { 1.3255 + return data->mFunc.mDataGetter(aElement, aStyleContext); 1.3256 + } 1.3257 + 1.3258 + return data; 1.3259 + } 1.3260 + } 1.3261 + 1.3262 + return nullptr; 1.3263 +} 1.3264 + 1.3265 +/* static */ 1.3266 +const nsCSSFrameConstructor::FrameConstructionData* 1.3267 +nsCSSFrameConstructor::FindDataByTag(nsIAtom* aTag, 1.3268 + Element* aElement, 1.3269 + nsStyleContext* aStyleContext, 1.3270 + const FrameConstructionDataByTag* aDataPtr, 1.3271 + uint32_t aDataLength) 1.3272 +{ 1.3273 + for (const FrameConstructionDataByTag *curData = aDataPtr, 1.3274 + *endData = aDataPtr + aDataLength; 1.3275 + curData != endData; 1.3276 + ++curData) { 1.3277 + if (*curData->mTag == aTag) { 1.3278 + const FrameConstructionData* data = &curData->mData; 1.3279 + if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) { 1.3280 + return data->mFunc.mDataGetter(aElement, aStyleContext); 1.3281 + } 1.3282 + 1.3283 + return data; 1.3284 + } 1.3285 + } 1.3286 + 1.3287 + return nullptr; 1.3288 +} 1.3289 + 1.3290 +#define SUPPRESS_FCDATA() FCDATA_DECL(FCDATA_SUPPRESS_FRAME, nullptr) 1.3291 +#define SIMPLE_INT_CREATE(_int, _func) { _int, SIMPLE_FCDATA(_func) } 1.3292 +#define SIMPLE_INT_CHAIN(_int, _func) \ 1.3293 + { _int, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) } 1.3294 +#define COMPLEX_INT_CREATE(_int, _func) \ 1.3295 + { _int, FULL_CTOR_FCDATA(0, _func) } 1.3296 + 1.3297 +#define SIMPLE_TAG_CREATE(_tag, _func) \ 1.3298 + { &nsGkAtoms::_tag, SIMPLE_FCDATA(_func) } 1.3299 +#define SIMPLE_TAG_CHAIN(_tag, _func) \ 1.3300 + { &nsGkAtoms::_tag, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) } 1.3301 +#define COMPLEX_TAG_CREATE(_tag, _func) \ 1.3302 + { &nsGkAtoms::_tag, FULL_CTOR_FCDATA(0, _func) } 1.3303 + 1.3304 +static bool 1.3305 +IsFrameForFieldSet(nsIFrame* aFrame, nsIAtom* aFrameType) 1.3306 +{ 1.3307 + nsIAtom* pseudo = aFrame->StyleContext()->GetPseudo(); 1.3308 + if (pseudo == nsCSSAnonBoxes::fieldsetContent || 1.3309 + pseudo == nsCSSAnonBoxes::scrolledContent) { 1.3310 + return IsFrameForFieldSet(aFrame->GetParent(), aFrame->GetParent()->GetType()); 1.3311 + } 1.3312 + return aFrameType == nsGkAtoms::fieldSetFrame; 1.3313 +} 1.3314 + 1.3315 +/* static */ 1.3316 +const nsCSSFrameConstructor::FrameConstructionData* 1.3317 +nsCSSFrameConstructor::FindHTMLData(Element* aElement, 1.3318 + nsIAtom* aTag, 1.3319 + int32_t aNameSpaceID, 1.3320 + nsIFrame* aParentFrame, 1.3321 + nsStyleContext* aStyleContext) 1.3322 +{ 1.3323 + // Ignore the tag if it's not HTML content and if it doesn't extend (via XBL) 1.3324 + // a valid HTML namespace. This check must match the one in 1.3325 + // ShouldHaveFirstLineStyle. 1.3326 + if (aNameSpaceID != kNameSpaceID_XHTML) { 1.3327 + return nullptr; 1.3328 + } 1.3329 + 1.3330 + NS_ASSERTION(!aParentFrame || 1.3331 + aParentFrame->StyleContext()->GetPseudo() != 1.3332 + nsCSSAnonBoxes::fieldsetContent || 1.3333 + aParentFrame->GetParent()->GetType() == nsGkAtoms::fieldSetFrame, 1.3334 + "Unexpected parent for fieldset content anon box"); 1.3335 + if (aTag == nsGkAtoms::legend && 1.3336 + (!aParentFrame || 1.3337 + !IsFrameForFieldSet(aParentFrame, aParentFrame->GetType()) || 1.3338 + !aElement->GetParent() || 1.3339 + !aElement->GetParent()->IsHTML(nsGkAtoms::fieldset) || 1.3340 + aStyleContext->StyleDisplay()->IsFloatingStyle() || 1.3341 + aStyleContext->StyleDisplay()->IsAbsolutelyPositionedStyle())) { 1.3342 + // <legend> is only special inside fieldset, check both the frame tree 1.3343 + // parent and content tree parent due to XBL issues. For floated or 1.3344 + // absolutely positioned legends we want to construct by display type and 1.3345 + // not do special legend stuff. 1.3346 + // XXXbz it would be nice if we could just decide this based on the parent 1.3347 + // tag, and hence just use a SIMPLE_TAG_CHAIN for legend below, but the 1.3348 + // fact that with XBL we could end up with this legend element in some 1.3349 + // totally weird insertion point makes that chancy, I think. 1.3350 + return nullptr; 1.3351 + } 1.3352 + 1.3353 + static const FrameConstructionDataByTag sHTMLData[] = { 1.3354 + SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData), 1.3355 + SIMPLE_TAG_CHAIN(mozgeneratedcontentimage, 1.3356 + nsCSSFrameConstructor::FindImgData), 1.3357 + { &nsGkAtoms::br, 1.3358 + FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT | FCDATA_IS_LINE_BREAK, 1.3359 + NS_NewBRFrame) }, 1.3360 + SIMPLE_TAG_CREATE(wbr, NS_NewWBRFrame), 1.3361 + SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData), 1.3362 + SIMPLE_TAG_CREATE(textarea, NS_NewTextControlFrame), 1.3363 + COMPLEX_TAG_CREATE(select, &nsCSSFrameConstructor::ConstructSelectFrame), 1.3364 + SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData), 1.3365 + SIMPLE_TAG_CHAIN(applet, nsCSSFrameConstructor::FindObjectData), 1.3366 + SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData), 1.3367 + COMPLEX_TAG_CREATE(fieldset, 1.3368 + &nsCSSFrameConstructor::ConstructFieldSetFrame), 1.3369 + { &nsGkAtoms::legend, 1.3370 + FCDATA_DECL(FCDATA_ALLOW_BLOCK_STYLES | FCDATA_MAY_NEED_SCROLLFRAME, 1.3371 + NS_NewLegendFrame) }, 1.3372 + SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame), 1.3373 + SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame), 1.3374 + { &nsGkAtoms::button, 1.3375 + FCDATA_WITH_WRAPPING_BLOCK(FCDATA_ALLOW_BLOCK_STYLES, 1.3376 + NS_NewHTMLButtonControlFrame, 1.3377 + nsCSSAnonBoxes::buttonContent) }, 1.3378 + SIMPLE_TAG_CHAIN(canvas, nsCSSFrameConstructor::FindCanvasData), 1.3379 + SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame), 1.3380 + SIMPLE_TAG_CREATE(audio, NS_NewHTMLVideoFrame), 1.3381 + SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame), 1.3382 + SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame) 1.3383 + }; 1.3384 + 1.3385 + return FindDataByTag(aTag, aElement, aStyleContext, sHTMLData, 1.3386 + ArrayLength(sHTMLData)); 1.3387 +} 1.3388 + 1.3389 +/* static */ 1.3390 +const nsCSSFrameConstructor::FrameConstructionData* 1.3391 +nsCSSFrameConstructor::FindImgData(Element* aElement, 1.3392 + nsStyleContext* aStyleContext) 1.3393 +{ 1.3394 + if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyleContext)) { 1.3395 + return nullptr; 1.3396 + } 1.3397 + 1.3398 + static const FrameConstructionData sImgData = SIMPLE_FCDATA(NS_NewImageFrame); 1.3399 + return &sImgData; 1.3400 +} 1.3401 + 1.3402 +/* static */ 1.3403 +const nsCSSFrameConstructor::FrameConstructionData* 1.3404 +nsCSSFrameConstructor::FindImgControlData(Element* aElement, 1.3405 + nsStyleContext* aStyleContext) 1.3406 +{ 1.3407 + if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyleContext)) { 1.3408 + return nullptr; 1.3409 + } 1.3410 + 1.3411 + static const FrameConstructionData sImgControlData = 1.3412 + SIMPLE_FCDATA(NS_NewImageControlFrame); 1.3413 + return &sImgControlData; 1.3414 +} 1.3415 + 1.3416 +/* static */ 1.3417 +const nsCSSFrameConstructor::FrameConstructionData* 1.3418 +nsCSSFrameConstructor::FindInputData(Element* aElement, 1.3419 + nsStyleContext* aStyleContext) 1.3420 +{ 1.3421 + static const FrameConstructionDataByInt sInputData[] = { 1.3422 + SIMPLE_INT_CREATE(NS_FORM_INPUT_CHECKBOX, NS_NewGfxCheckboxControlFrame), 1.3423 + SIMPLE_INT_CREATE(NS_FORM_INPUT_RADIO, NS_NewGfxRadioControlFrame), 1.3424 + SIMPLE_INT_CREATE(NS_FORM_INPUT_FILE, NS_NewFileControlFrame), 1.3425 + SIMPLE_INT_CHAIN(NS_FORM_INPUT_IMAGE, 1.3426 + nsCSSFrameConstructor::FindImgControlData), 1.3427 + SIMPLE_INT_CREATE(NS_FORM_INPUT_EMAIL, NS_NewTextControlFrame), 1.3428 + SIMPLE_INT_CREATE(NS_FORM_INPUT_SEARCH, NS_NewTextControlFrame), 1.3429 + SIMPLE_INT_CREATE(NS_FORM_INPUT_TEXT, NS_NewTextControlFrame), 1.3430 + SIMPLE_INT_CREATE(NS_FORM_INPUT_TEL, NS_NewTextControlFrame), 1.3431 + SIMPLE_INT_CREATE(NS_FORM_INPUT_URL, NS_NewTextControlFrame), 1.3432 + SIMPLE_INT_CREATE(NS_FORM_INPUT_RANGE, NS_NewRangeFrame), 1.3433 + SIMPLE_INT_CREATE(NS_FORM_INPUT_PASSWORD, NS_NewTextControlFrame), 1.3434 + { NS_FORM_INPUT_COLOR, 1.3435 + FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewColorControlFrame, 1.3436 + nsCSSAnonBoxes::buttonContent) }, 1.3437 + // TODO: this is temporary until a frame is written: bug 635240. 1.3438 + SIMPLE_INT_CREATE(NS_FORM_INPUT_NUMBER, NS_NewNumberControlFrame), 1.3439 + // TODO: this is temporary until a frame is written: bug 773205. 1.3440 + SIMPLE_INT_CREATE(NS_FORM_INPUT_DATE, NS_NewTextControlFrame), 1.3441 + // TODO: this is temporary until a frame is written: bug 773205 1.3442 + SIMPLE_INT_CREATE(NS_FORM_INPUT_TIME, NS_NewTextControlFrame), 1.3443 + { NS_FORM_INPUT_SUBMIT, 1.3444 + FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame, 1.3445 + nsCSSAnonBoxes::buttonContent) }, 1.3446 + { NS_FORM_INPUT_RESET, 1.3447 + FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame, 1.3448 + nsCSSAnonBoxes::buttonContent) }, 1.3449 + { NS_FORM_INPUT_BUTTON, 1.3450 + FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame, 1.3451 + nsCSSAnonBoxes::buttonContent) } 1.3452 + // Keeping hidden inputs out of here on purpose for so they get frames by 1.3453 + // display (in practice, none). 1.3454 + }; 1.3455 + 1.3456 + nsCOMPtr<nsIFormControl> control = do_QueryInterface(aElement); 1.3457 + NS_ASSERTION(control, "input doesn't implement nsIFormControl?"); 1.3458 + 1.3459 + return FindDataByInt(control->GetType(), aElement, aStyleContext, 1.3460 + sInputData, ArrayLength(sInputData)); 1.3461 +} 1.3462 + 1.3463 +/* static */ 1.3464 +const nsCSSFrameConstructor::FrameConstructionData* 1.3465 +nsCSSFrameConstructor::FindObjectData(Element* aElement, 1.3466 + nsStyleContext* aStyleContext) 1.3467 +{ 1.3468 + // GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for 1.3469 + // cases when the object is broken/suppressed/etc (e.g. a broken image), but 1.3470 + // we want to treat those cases as TYPE_NULL 1.3471 + uint32_t type; 1.3472 + if (aElement->State().HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN | 1.3473 + NS_EVENT_STATE_USERDISABLED | 1.3474 + NS_EVENT_STATE_SUPPRESSED)) { 1.3475 + type = nsIObjectLoadingContent::TYPE_NULL; 1.3476 + } else { 1.3477 + nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(aElement)); 1.3478 + NS_ASSERTION(objContent, 1.3479 + "applet, embed and object must implement " 1.3480 + "nsIObjectLoadingContent!"); 1.3481 + 1.3482 + objContent->GetDisplayedType(&type); 1.3483 + } 1.3484 + 1.3485 + static const FrameConstructionDataByInt sObjectData[] = { 1.3486 + SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING, 1.3487 + NS_NewEmptyFrame), 1.3488 + SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_PLUGIN, 1.3489 + NS_NewObjectFrame), 1.3490 + SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE, 1.3491 + NS_NewImageFrame), 1.3492 + SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT, 1.3493 + NS_NewSubDocumentFrame) 1.3494 + // Nothing for TYPE_NULL so we'll construct frames by display there 1.3495 + }; 1.3496 + 1.3497 + return FindDataByInt((int32_t)type, aElement, aStyleContext, 1.3498 + sObjectData, ArrayLength(sObjectData)); 1.3499 +} 1.3500 + 1.3501 +/* static */ 1.3502 +const nsCSSFrameConstructor::FrameConstructionData* 1.3503 +nsCSSFrameConstructor::FindCanvasData(Element* aElement, 1.3504 + nsStyleContext* aStyleContext) 1.3505 +{ 1.3506 + // We want to check whether script is enabled on the document that 1.3507 + // could be painting to the canvas. That's the owner document of 1.3508 + // the canvas, except when the owner document is a static document, 1.3509 + // in which case it's the original document it was cloned from. 1.3510 + nsIDocument* doc = aElement->OwnerDoc(); 1.3511 + if (doc->IsStaticDocument()) { 1.3512 + doc = doc->GetOriginalDocument(); 1.3513 + } 1.3514 + if (!doc->IsScriptEnabled()) { 1.3515 + return nullptr; 1.3516 + } 1.3517 + 1.3518 + static const FrameConstructionData sCanvasData = 1.3519 + FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewHTMLCanvasFrame, 1.3520 + nsCSSAnonBoxes::htmlCanvasContent); 1.3521 + return &sCanvasData; 1.3522 +} 1.3523 + 1.3524 +void 1.3525 +nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aItem, 1.3526 + nsFrameConstructorState& aState, 1.3527 + nsIFrame* aParentFrame, 1.3528 + nsFrameItems& aFrameItems) 1.3529 +{ 1.3530 + const FrameConstructionData* data = aItem.mFCData; 1.3531 + NS_ASSERTION(data, "Must have frame construction data"); 1.3532 + 1.3533 + uint32_t bits = data->mBits; 1.3534 + 1.3535 + NS_ASSERTION(!(bits & FCDATA_FUNC_IS_DATA_GETTER), 1.3536 + "Should have dealt with this inside the data finder"); 1.3537 + 1.3538 + // Some sets of bits are not compatible with each other 1.3539 +#define CHECK_ONLY_ONE_BIT(_bit1, _bit2) \ 1.3540 + NS_ASSERTION(!(bits & _bit1) || !(bits & _bit2), \ 1.3541 + "Only one of these bits should be set") 1.3542 + CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_FORCE_NULL_ABSPOS_CONTAINER); 1.3543 + CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_WRAP_KIDS_IN_BLOCKS); 1.3544 + CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_MAY_NEED_SCROLLFRAME); 1.3545 + CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_IS_POPUP); 1.3546 + CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_SKIP_ABSPOS_PUSH); 1.3547 + CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, 1.3548 + FCDATA_DISALLOW_GENERATED_CONTENT); 1.3549 + CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_ALLOW_BLOCK_STYLES); 1.3550 + CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, 1.3551 + FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS); 1.3552 + CHECK_ONLY_ONE_BIT(FCDATA_WRAP_KIDS_IN_BLOCKS, 1.3553 + FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS); 1.3554 +#undef CHECK_ONLY_ONE_BIT 1.3555 + NS_ASSERTION(!(bits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) || 1.3556 + ((bits & FCDATA_FUNC_IS_FULL_CTOR) && 1.3557 + data->mFullConstructor == 1.3558 + &nsCSSFrameConstructor::ConstructNonScrollableBlock), 1.3559 + "Unexpected FCDATA_FORCED_NON_SCROLLABLE_BLOCK flag"); 1.3560 + 1.3561 + // Don't create a subdocument frame for iframes if we're creating extra frames 1.3562 + if (aState.mCreatingExtraFrames && aItem.mContent->IsHTML() && 1.3563 + aItem.mContent->Tag() == nsGkAtoms::iframe) 1.3564 + { 1.3565 + return; 1.3566 + } 1.3567 + 1.3568 + nsStyleContext* const styleContext = aItem.mStyleContext; 1.3569 + const nsStyleDisplay* display = styleContext->StyleDisplay(); 1.3570 + nsIContent* const content = aItem.mContent; 1.3571 + 1.3572 + // Get the parent of the content and check if it is a XBL children element. 1.3573 + // Push the children element as an ancestor here because it does 1.3574 + // not have a frame and would not otherwise be pushed as an ancestor. It is 1.3575 + // necessary to do so in order to correctly handle style resolution on 1.3576 + // descendants. 1.3577 + nsIContent* parent = content->GetParent(); 1.3578 + TreeMatchContext::AutoAncestorPusher 1.3579 + insertionPointPusher(aState.mTreeMatchContext); 1.3580 + if (parent && nsContentUtils::IsContentInsertionPoint(parent)) { 1.3581 + if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) { 1.3582 + insertionPointPusher.PushAncestorAndStyleScope(parent); 1.3583 + } else { 1.3584 + insertionPointPusher.PushStyleScope(parent); 1.3585 + } 1.3586 + } 1.3587 + 1.3588 + // Push the content as a style ancestor now, so we don't have to do 1.3589 + // it in our various full-constructor functions. In particular, 1.3590 + // since a number of full-constructor functions don't actually call 1.3591 + // ProcessChildren in some cases (e.g. for CSS anonymous table boxes 1.3592 + // or for situations where only anonymouse children are having 1.3593 + // frames constructed), this is the best place to bottleneck the 1.3594 + // pushing of the content instead of having to do it in multiple 1.3595 + // places. 1.3596 + TreeMatchContext::AutoAncestorPusher 1.3597 + ancestorPusher(aState.mTreeMatchContext); 1.3598 + if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) { 1.3599 + ancestorPusher.PushAncestorAndStyleScope(content); 1.3600 + } else { 1.3601 + ancestorPusher.PushStyleScope(content); 1.3602 + } 1.3603 + 1.3604 + nsIFrame* newFrame; 1.3605 + nsIFrame* primaryFrame; 1.3606 + if (bits & FCDATA_FUNC_IS_FULL_CTOR) { 1.3607 + newFrame = 1.3608 + (this->*(data->mFullConstructor))(aState, aItem, aParentFrame, 1.3609 + display, aFrameItems); 1.3610 + MOZ_ASSERT(newFrame, "Full constructor failed"); 1.3611 + primaryFrame = newFrame; 1.3612 + } else { 1.3613 + newFrame = 1.3614 + (*data->mFunc.mCreationFunc)(mPresShell, styleContext); 1.3615 + 1.3616 + bool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW); 1.3617 + bool isPopup = aItem.mIsPopup; 1.3618 + NS_ASSERTION(!isPopup || 1.3619 + (aState.mPopupItems.containingBlock && 1.3620 + aState.mPopupItems.containingBlock->GetType() == 1.3621 + nsGkAtoms::popupSetFrame), 1.3622 + "Should have a containing block here!"); 1.3623 + 1.3624 + nsIFrame* geometricParent = 1.3625 + isPopup ? aState.mPopupItems.containingBlock : 1.3626 + (allowOutOfFlow ? aState.GetGeometricParent(display, aParentFrame) 1.3627 + : aParentFrame); 1.3628 + 1.3629 + // Must init frameToAddToList to null, since it's inout 1.3630 + nsIFrame* frameToAddToList = nullptr; 1.3631 + if ((bits & FCDATA_MAY_NEED_SCROLLFRAME) && 1.3632 + display->IsScrollableOverflow()) { 1.3633 + BuildScrollFrame(aState, content, styleContext, newFrame, 1.3634 + geometricParent, frameToAddToList); 1.3635 + } else { 1.3636 + InitAndRestoreFrame(aState, content, geometricParent, newFrame); 1.3637 + // See whether we need to create a view 1.3638 + nsContainerFrame::CreateViewForFrame(newFrame, false); 1.3639 + frameToAddToList = newFrame; 1.3640 + } 1.3641 + 1.3642 + // Use frameToAddToList as the primary frame. In the non-scrollframe case 1.3643 + // they're equal, but in the scrollframe case newFrame is the scrolled 1.3644 + // frame, while frameToAddToList is the scrollframe (and should be the 1.3645 + // primary frame). 1.3646 + primaryFrame = frameToAddToList; 1.3647 + 1.3648 + // If we need to create a block formatting context to wrap our 1.3649 + // kids, do it now. 1.3650 + const nsStyleDisplay* maybeAbsoluteContainingBlockDisplay = display; 1.3651 + nsIFrame* maybeAbsoluteContainingBlock = newFrame; 1.3652 + nsIFrame* possiblyLeafFrame = newFrame; 1.3653 + if (bits & FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS) { 1.3654 + nsRefPtr<nsStyleContext> blockContext; 1.3655 + blockContext = 1.3656 + mPresShell->StyleSet()->ResolveAnonymousBoxStyle(*data->mAnonBoxPseudo, 1.3657 + styleContext); 1.3658 + nsIFrame* blockFrame = 1.3659 + NS_NewBlockFormattingContext(mPresShell, blockContext); 1.3660 + 1.3661 + InitAndRestoreFrame(aState, content, newFrame, blockFrame); 1.3662 + 1.3663 + SetInitialSingleChild(newFrame, blockFrame); 1.3664 + 1.3665 + // Now figure out whether newFrame or blockFrame should be the 1.3666 + // absolute container. It should be the latter if it's 1.3667 + // positioned, otherwise the former. 1.3668 + const nsStyleDisplay* blockDisplay = blockContext->StyleDisplay(); 1.3669 + if (blockDisplay->IsPositioned(blockFrame)) { 1.3670 + maybeAbsoluteContainingBlockDisplay = blockDisplay; 1.3671 + maybeAbsoluteContainingBlock = blockFrame; 1.3672 + } 1.3673 + 1.3674 + // Our kids should go into the blockFrame 1.3675 + newFrame = blockFrame; 1.3676 + } 1.3677 + 1.3678 + aState.AddChild(frameToAddToList, aFrameItems, content, styleContext, 1.3679 + aParentFrame, allowOutOfFlow, allowOutOfFlow, isPopup); 1.3680 + 1.3681 +#ifdef MOZ_XUL 1.3682 + // Icky XUL stuff, sadly 1.3683 + 1.3684 + if (aItem.mIsRootPopupgroup) { 1.3685 + NS_ASSERTION(nsIRootBox::GetRootBox(mPresShell) && 1.3686 + nsIRootBox::GetRootBox(mPresShell)->GetPopupSetFrame() == 1.3687 + newFrame, 1.3688 + "Unexpected PopupSetFrame"); 1.3689 + aState.mPopupItems.containingBlock = newFrame; 1.3690 + aState.mHavePendingPopupgroup = false; 1.3691 + } 1.3692 +#endif /* MOZ_XUL */ 1.3693 + 1.3694 + // Process the child content if requested 1.3695 + nsFrameItems childItems; 1.3696 + nsFrameConstructorSaveState absoluteSaveState; 1.3697 + 1.3698 + if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER) { 1.3699 + aState.PushAbsoluteContainingBlock(nullptr, nullptr, absoluteSaveState); 1.3700 + } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH)) { 1.3701 + nsIFrame* cb = maybeAbsoluteContainingBlock; 1.3702 + cb->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); 1.3703 + // This check is identical to nsStyleDisplay::IsPositioned except without 1.3704 + // the assertion that the style display and frame match. When constructing 1.3705 + // scroll frames we intentionally use the style display for the outer, but 1.3706 + // make the inner the containing block. 1.3707 + if ((maybeAbsoluteContainingBlockDisplay->IsAbsolutelyPositionedStyle() || 1.3708 + maybeAbsoluteContainingBlockDisplay->IsRelativelyPositionedStyle() || 1.3709 + (maybeAbsoluteContainingBlockDisplay->HasTransformStyle() && 1.3710 + cb->IsFrameOfType(nsIFrame::eSupportsCSSTransforms)) || 1.3711 + maybeAbsoluteContainingBlockDisplay->HasPerspectiveStyle()) && 1.3712 + !cb->IsSVGText()) { 1.3713 + aState.PushAbsoluteContainingBlock(cb, cb, absoluteSaveState); 1.3714 + } 1.3715 + } 1.3716 + 1.3717 + if (!aItem.mAnonChildren.IsEmpty()) { 1.3718 + NS_ASSERTION(!(bits & FCDATA_USE_CHILD_ITEMS), 1.3719 + "We should not have both anonymous and non-anonymous " 1.3720 + "children in a given FrameConstructorItem"); 1.3721 + AddFCItemsForAnonymousContent(aState, newFrame, aItem.mAnonChildren, 1.3722 + aItem.mChildItems); 1.3723 + bits |= FCDATA_USE_CHILD_ITEMS; 1.3724 + } 1.3725 + 1.3726 + if (bits & FCDATA_USE_CHILD_ITEMS) { 1.3727 + nsFrameConstructorSaveState floatSaveState; 1.3728 + 1.3729 + if (ShouldSuppressFloatingOfDescendants(newFrame)) { 1.3730 + aState.PushFloatContainingBlock(nullptr, floatSaveState); 1.3731 + } else if (newFrame->IsFloatContainingBlock()) { 1.3732 + aState.PushFloatContainingBlock(newFrame, floatSaveState); 1.3733 + } 1.3734 + ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame, 1.3735 + childItems); 1.3736 + } else { 1.3737 + // Process the child frames. 1.3738 + ProcessChildren(aState, content, styleContext, newFrame, 1.3739 + !(bits & FCDATA_DISALLOW_GENERATED_CONTENT), 1.3740 + childItems, 1.3741 + (bits & FCDATA_ALLOW_BLOCK_STYLES) != 0, 1.3742 + aItem.mPendingBinding, possiblyLeafFrame); 1.3743 + } 1.3744 + 1.3745 +#ifdef MOZ_XUL 1.3746 + // More icky XUL stuff 1.3747 + if (aItem.mNameSpaceID == kNameSpaceID_XUL && 1.3748 + (aItem.mTag == nsGkAtoms::treechildren || // trees always need titletips 1.3749 + content->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext) || 1.3750 + content->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltip))) { 1.3751 + nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell); 1.3752 + if (rootBox) { 1.3753 + rootBox->AddTooltipSupport(content); 1.3754 + } 1.3755 + } 1.3756 +#endif 1.3757 + 1.3758 + if (bits & FCDATA_WRAP_KIDS_IN_BLOCKS) { 1.3759 + nsFrameItems newItems; 1.3760 + nsFrameItems currentBlockItems; 1.3761 + nsIFrame* f; 1.3762 + while ((f = childItems.FirstChild()) != nullptr) { 1.3763 + bool wrapFrame = IsInlineFrame(f) || IsFramePartOfIBSplit(f); 1.3764 + if (!wrapFrame) { 1.3765 + FlushAccumulatedBlock(aState, content, newFrame, 1.3766 + currentBlockItems, newItems); 1.3767 + } 1.3768 + 1.3769 + childItems.RemoveFrame(f); 1.3770 + if (wrapFrame) { 1.3771 + currentBlockItems.AddChild(f); 1.3772 + } else { 1.3773 + newItems.AddChild(f); 1.3774 + } 1.3775 + } 1.3776 + FlushAccumulatedBlock(aState, content, newFrame, 1.3777 + currentBlockItems, newItems); 1.3778 + 1.3779 + if (childItems.NotEmpty()) { 1.3780 + // an error must have occurred, delete unprocessed frames 1.3781 + childItems.DestroyFrames(); 1.3782 + } 1.3783 + 1.3784 + childItems = newItems; 1.3785 + } 1.3786 + 1.3787 + // Set the frame's initial child list 1.3788 + // Note that MathML depends on this being called even if 1.3789 + // childItems is empty! 1.3790 + newFrame->SetInitialChildList(kPrincipalList, childItems); 1.3791 + } 1.3792 + 1.3793 + NS_ASSERTION(newFrame->IsFrameOfType(nsIFrame::eLineParticipant) == 1.3794 + ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0), 1.3795 + "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits"); 1.3796 + 1.3797 + if (aItem.mIsAnonymousContentCreatorContent) { 1.3798 + primaryFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT); 1.3799 + } 1.3800 + 1.3801 + // Even if mCreatingExtraFrames is set, we may need to SetPrimaryFrame for 1.3802 + // generated content that doesn't have one yet. Note that we have to examine 1.3803 + // the frame bit, because by this point mIsGeneratedContent has been cleared 1.3804 + // on aItem. 1.3805 + if ((!aState.mCreatingExtraFrames || 1.3806 + ((primaryFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) && 1.3807 + !aItem.mContent->GetPrimaryFrame())) && 1.3808 + !(bits & FCDATA_SKIP_FRAMESET)) { 1.3809 + aItem.mContent->SetPrimaryFrame(primaryFrame); 1.3810 + } 1.3811 +} 1.3812 + 1.3813 +// after the node has been constructed and initialized create any 1.3814 +// anonymous content a node needs. 1.3815 +nsresult 1.3816 +nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState, 1.3817 + nsIContent* aParent, 1.3818 + nsIFrame* aParentFrame, 1.3819 + PendingBinding* aPendingBinding, 1.3820 + nsFrameItems& aChildItems) 1.3821 +{ 1.3822 + nsAutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> newAnonymousItems; 1.3823 + nsresult rv = GetAnonymousContent(aParent, aParentFrame, newAnonymousItems); 1.3824 + NS_ENSURE_SUCCESS(rv, rv); 1.3825 + 1.3826 + uint32_t count = newAnonymousItems.Length(); 1.3827 + if (count == 0) { 1.3828 + return NS_OK; 1.3829 + } 1.3830 + 1.3831 + nsFrameConstructorState::PendingBindingAutoPusher pusher(aState, 1.3832 + aPendingBinding); 1.3833 + TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext); 1.3834 + if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) { 1.3835 + ancestorPusher.PushAncestorAndStyleScope(aParent->AsElement()); 1.3836 + } else { 1.3837 + ancestorPusher.PushStyleScope(aParent->AsElement()); 1.3838 + } 1.3839 + 1.3840 + nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame); 1.3841 + NS_ASSERTION(creator, 1.3842 + "How can that happen if we have nodes to construct frames for?"); 1.3843 + 1.3844 + for (uint32_t i=0; i < count; i++) { 1.3845 + nsIContent* content = newAnonymousItems[i].mContent; 1.3846 + NS_ASSERTION(content, "null anonymous content?"); 1.3847 + NS_ASSERTION(!newAnonymousItems[i].mStyleContext, "Unexpected style context"); 1.3848 + NS_ASSERTION(newAnonymousItems[i].mChildren.IsEmpty(), 1.3849 + "This method is not currently used with frames that implement " 1.3850 + "nsIAnonymousContentCreator::CreateAnonymousContent to " 1.3851 + "output a list where the items have their own children"); 1.3852 + 1.3853 + nsIFrame* newFrame = creator->CreateFrameFor(content); 1.3854 + if (newFrame) { 1.3855 + NS_ASSERTION(content->GetPrimaryFrame(), 1.3856 + "Content must have a primary frame now"); 1.3857 + newFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT); 1.3858 + aChildItems.AddChild(newFrame); 1.3859 + } else { 1.3860 + FrameConstructionItemList items; 1.3861 + { 1.3862 + // Skip flex item style-fixup during our AddFrameConstructionItems() call: 1.3863 + TreeMatchContext::AutoFlexItemStyleFixupSkipper 1.3864 + flexItemStyleFixupSkipper(aState.mTreeMatchContext); 1.3865 + 1.3866 + AddFrameConstructionItems(aState, content, true, aParentFrame, items); 1.3867 + } 1.3868 + ConstructFramesFromItemList(aState, items, aParentFrame, aChildItems); 1.3869 + } 1.3870 + } 1.3871 + 1.3872 + return NS_OK; 1.3873 +} 1.3874 + 1.3875 +static void 1.3876 +SetFlagsOnSubtree(nsIContent *aNode, uintptr_t aFlagsToSet) 1.3877 +{ 1.3878 +#ifdef DEBUG 1.3879 + // Make sure that the node passed to us doesn't have any XBL children 1.3880 + { 1.3881 + FlattenedChildIterator iter(aNode); 1.3882 + NS_ASSERTION(!iter.XBLInvolved() || !iter.GetNextChild(), 1.3883 + "The node should not have any XBL children"); 1.3884 + } 1.3885 +#endif 1.3886 + 1.3887 + // Set the flag on the node itself 1.3888 + aNode->SetFlags(aFlagsToSet); 1.3889 + 1.3890 + // Set the flag on all of its children recursively 1.3891 + uint32_t count; 1.3892 + nsIContent * const *children = aNode->GetChildArray(&count); 1.3893 + 1.3894 + for (uint32_t index = 0; index < count; ++index) { 1.3895 + SetFlagsOnSubtree(children[index], aFlagsToSet); 1.3896 + } 1.3897 +} 1.3898 + 1.3899 +/** 1.3900 + * This function takes a tree of nsIAnonymousContentCreator::ContentInfo 1.3901 + * objects where the nsIContent nodes have just been created, and appends the 1.3902 + * nsIContent children in the tree to their parent. The leaf nsIContent objects 1.3903 + * are appended first to minimize the number of notifications that are sent 1.3904 + * out (i.e. by appending as many descendants as posible while their parent is 1.3905 + * not yet in the document tree). 1.3906 + * 1.3907 + * This function is used simply as a convenience so that implementations of 1.3908 + * nsIAnonymousContentCreator::CreateAnonymousContent don't all have to have 1.3909 + * their own code to connect the elements that they create. 1.3910 + */ 1.3911 +static void 1.3912 +ConnectAnonymousTreeDescendants(nsIContent* aParent, 1.3913 + nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent) 1.3914 +{ 1.3915 + uint32_t count = aContent.Length(); 1.3916 + for (uint32_t i=0; i < count; i++) { 1.3917 + nsIContent* content = aContent[i].mContent; 1.3918 + NS_ASSERTION(content, "null anonymous content?"); 1.3919 + 1.3920 + ConnectAnonymousTreeDescendants(content, aContent[i].mChildren); 1.3921 + 1.3922 + aParent->AppendChildTo(content, false); 1.3923 + } 1.3924 +} 1.3925 + 1.3926 +nsresult 1.3927 +nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent, 1.3928 + nsIFrame* aParentFrame, 1.3929 + nsTArray<nsIAnonymousContentCreator::ContentInfo>& aContent) 1.3930 +{ 1.3931 + nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame); 1.3932 + if (!creator) 1.3933 + return NS_OK; 1.3934 + 1.3935 + nsresult rv = creator->CreateAnonymousContent(aContent); 1.3936 + NS_ENSURE_SUCCESS(rv, rv); 1.3937 + 1.3938 + uint32_t count = aContent.Length(); 1.3939 + for (uint32_t i=0; i < count; i++) { 1.3940 + // get our child's content and set its parent to our content 1.3941 + nsIContent* content = aContent[i].mContent; 1.3942 + NS_ASSERTION(content, "null anonymous content?"); 1.3943 + 1.3944 + // least-surprise CSS binding until we do the SVG specified 1.3945 + // cascading rules for <svg:use> - bug 265894 1.3946 + if (aParentFrame->GetType() == nsGkAtoms::svgUseFrame) { 1.3947 + content->SetFlags(NODE_IS_ANONYMOUS_ROOT); 1.3948 + } else { 1.3949 + content->SetIsNativeAnonymousRoot(); 1.3950 + } 1.3951 + 1.3952 + ConnectAnonymousTreeDescendants(content, aContent[i].mChildren); 1.3953 + 1.3954 + bool anonContentIsEditable = content->HasFlag(NODE_IS_EDITABLE); 1.3955 + rv = content->BindToTree(mDocument, aParent, aParent, true); 1.3956 + // If the anonymous content creator requested that the content should be 1.3957 + // editable, honor its request. 1.3958 + // We need to set the flag on the whole subtree, because existing 1.3959 + // children's flags have already been set as part of the BindToTree operation. 1.3960 + if (anonContentIsEditable) { 1.3961 + NS_ASSERTION(aParentFrame->GetType() == nsGkAtoms::textInputFrame, 1.3962 + "We only expect this for anonymous content under a text control frame"); 1.3963 + SetFlagsOnSubtree(content, NODE_IS_EDITABLE); 1.3964 + } 1.3965 + if (NS_FAILED(rv)) { 1.3966 + content->UnbindFromTree(); 1.3967 + return rv; 1.3968 + } 1.3969 + } 1.3970 + 1.3971 + return NS_OK; 1.3972 +} 1.3973 + 1.3974 +static 1.3975 +bool IsXULDisplayType(const nsStyleDisplay* aDisplay) 1.3976 +{ 1.3977 + return (aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_BOX || 1.3978 +#ifdef MOZ_XUL 1.3979 + aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_XUL_GRID || 1.3980 + aDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE_STACK || 1.3981 +#endif 1.3982 + aDisplay->mDisplay == NS_STYLE_DISPLAY_BOX 1.3983 +#ifdef MOZ_XUL 1.3984 + || aDisplay->mDisplay == NS_STYLE_DISPLAY_XUL_GRID || 1.3985 + aDisplay->mDisplay == NS_STYLE_DISPLAY_STACK || 1.3986 + aDisplay->mDisplay == NS_STYLE_DISPLAY_XUL_GRID_GROUP || 1.3987 + aDisplay->mDisplay == NS_STYLE_DISPLAY_XUL_GRID_LINE || 1.3988 + aDisplay->mDisplay == NS_STYLE_DISPLAY_DECK || 1.3989 + aDisplay->mDisplay == NS_STYLE_DISPLAY_POPUP || 1.3990 + aDisplay->mDisplay == NS_STYLE_DISPLAY_GROUPBOX 1.3991 +#endif 1.3992 + ); 1.3993 +} 1.3994 + 1.3995 + 1.3996 +// XUL frames are not allowed to be out of flow. 1.3997 +#define SIMPLE_XUL_FCDATA(_func) \ 1.3998 + FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH, \ 1.3999 + _func) 1.4000 +#define SCROLLABLE_XUL_FCDATA(_func) \ 1.4001 + FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH | \ 1.4002 + FCDATA_MAY_NEED_SCROLLFRAME, _func) 1.4003 +// .. but we allow some XUL frames to be _containers_ for out-of-flow content 1.4004 +// (This is the same as SCROLLABLE_XUL_FCDATA, but w/o FCDATA_SKIP_ABSPOS_PUSH) 1.4005 +#define SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func) \ 1.4006 + FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \ 1.4007 + FCDATA_MAY_NEED_SCROLLFRAME, _func) 1.4008 + 1.4009 +#define SIMPLE_XUL_CREATE(_tag, _func) \ 1.4010 + { &nsGkAtoms::_tag, SIMPLE_XUL_FCDATA(_func) } 1.4011 +#define SCROLLABLE_XUL_CREATE(_tag, _func) \ 1.4012 + { &nsGkAtoms::_tag, SCROLLABLE_XUL_FCDATA(_func) } 1.4013 +#define SIMPLE_XUL_INT_CREATE(_int, _func) \ 1.4014 + { _int, SIMPLE_XUL_FCDATA(_func) } 1.4015 +#define SCROLLABLE_XUL_INT_CREATE(_int, _func) \ 1.4016 + { _int, SCROLLABLE_XUL_FCDATA(_func) } 1.4017 +#define SCROLLABLE_ABSPOS_CONTAINER_XUL_INT_CREATE(_int, _func) \ 1.4018 + { _int, SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func) } 1.4019 + 1.4020 +static 1.4021 +nsIFrame* NS_NewGridBoxFrame(nsIPresShell* aPresShell, 1.4022 + nsStyleContext* aStyleContext) 1.4023 +{ 1.4024 + nsCOMPtr<nsBoxLayout> layout; 1.4025 + NS_NewGridLayout2(aPresShell, getter_AddRefs(layout)); 1.4026 + return NS_NewBoxFrame(aPresShell, aStyleContext, false, layout); 1.4027 +} 1.4028 + 1.4029 +/* static */ 1.4030 +const nsCSSFrameConstructor::FrameConstructionData* 1.4031 +nsCSSFrameConstructor::FindXULTagData(Element* aElement, 1.4032 + nsIAtom* aTag, 1.4033 + int32_t aNameSpaceID, 1.4034 + nsStyleContext* aStyleContext) 1.4035 +{ 1.4036 + if (aNameSpaceID != kNameSpaceID_XUL) { 1.4037 + return nullptr; 1.4038 + } 1.4039 + 1.4040 + static const FrameConstructionDataByTag sXULTagData[] = { 1.4041 +#ifdef MOZ_XUL 1.4042 + SCROLLABLE_XUL_CREATE(button, NS_NewButtonBoxFrame), 1.4043 + SCROLLABLE_XUL_CREATE(checkbox, NS_NewButtonBoxFrame), 1.4044 + SCROLLABLE_XUL_CREATE(radio, NS_NewButtonBoxFrame), 1.4045 + SCROLLABLE_XUL_CREATE(autorepeatbutton, NS_NewAutoRepeatBoxFrame), 1.4046 + SCROLLABLE_XUL_CREATE(titlebar, NS_NewTitleBarFrame), 1.4047 + SCROLLABLE_XUL_CREATE(resizer, NS_NewResizerFrame), 1.4048 + SIMPLE_XUL_CREATE(image, NS_NewImageBoxFrame), 1.4049 + SIMPLE_XUL_CREATE(spring, NS_NewLeafBoxFrame), 1.4050 + SIMPLE_XUL_CREATE(spacer, NS_NewLeafBoxFrame), 1.4051 + SIMPLE_XUL_CREATE(treechildren, NS_NewTreeBodyFrame), 1.4052 + SIMPLE_XUL_CREATE(treecol, NS_NewTreeColFrame), 1.4053 + SIMPLE_XUL_CREATE(text, NS_NewTextBoxFrame), 1.4054 + SIMPLE_TAG_CHAIN(label, nsCSSFrameConstructor::FindXULLabelData), 1.4055 + SIMPLE_TAG_CHAIN(description, nsCSSFrameConstructor::FindXULDescriptionData), 1.4056 + SIMPLE_XUL_CREATE(menu, NS_NewMenuFrame), 1.4057 + SIMPLE_XUL_CREATE(menubutton, NS_NewMenuFrame), 1.4058 + SIMPLE_XUL_CREATE(menuitem, NS_NewMenuItemFrame), 1.4059 +#ifdef XP_MACOSX 1.4060 + SIMPLE_TAG_CHAIN(menubar, nsCSSFrameConstructor::FindXULMenubarData), 1.4061 +#else 1.4062 + SIMPLE_XUL_CREATE(menubar, NS_NewMenuBarFrame), 1.4063 +#endif /* XP_MACOSX */ 1.4064 + SIMPLE_TAG_CHAIN(popupgroup, nsCSSFrameConstructor::FindPopupGroupData), 1.4065 + SIMPLE_XUL_CREATE(iframe, NS_NewSubDocumentFrame), 1.4066 + SIMPLE_XUL_CREATE(editor, NS_NewSubDocumentFrame), 1.4067 + SIMPLE_XUL_CREATE(browser, NS_NewSubDocumentFrame), 1.4068 + SIMPLE_XUL_CREATE(progressmeter, NS_NewProgressMeterFrame), 1.4069 + SIMPLE_XUL_CREATE(splitter, NS_NewSplitterFrame), 1.4070 + SIMPLE_TAG_CHAIN(listboxbody, 1.4071 + nsCSSFrameConstructor::FindXULListBoxBodyData), 1.4072 + SIMPLE_TAG_CHAIN(listitem, nsCSSFrameConstructor::FindXULListItemData), 1.4073 +#endif /* MOZ_XUL */ 1.4074 + SIMPLE_XUL_CREATE(slider, NS_NewSliderFrame), 1.4075 + SIMPLE_XUL_CREATE(scrollbar, NS_NewScrollbarFrame), 1.4076 + SIMPLE_XUL_CREATE(scrollbarbutton, NS_NewScrollbarButtonFrame) 1.4077 +}; 1.4078 + 1.4079 + return FindDataByTag(aTag, aElement, aStyleContext, sXULTagData, 1.4080 + ArrayLength(sXULTagData)); 1.4081 +} 1.4082 + 1.4083 +#ifdef MOZ_XUL 1.4084 +/* static */ 1.4085 +const nsCSSFrameConstructor::FrameConstructionData* 1.4086 +nsCSSFrameConstructor::FindPopupGroupData(Element* aElement, 1.4087 + nsStyleContext* /* unused */) 1.4088 +{ 1.4089 + if (!aElement->IsRootOfNativeAnonymousSubtree()) { 1.4090 + return nullptr; 1.4091 + } 1.4092 + 1.4093 + static const FrameConstructionData sPopupSetData = 1.4094 + SIMPLE_XUL_FCDATA(NS_NewPopupSetFrame); 1.4095 + return &sPopupSetData; 1.4096 +} 1.4097 + 1.4098 +/* static */ 1.4099 +const nsCSSFrameConstructor::FrameConstructionData 1.4100 +nsCSSFrameConstructor::sXULTextBoxData = SIMPLE_XUL_FCDATA(NS_NewTextBoxFrame); 1.4101 + 1.4102 +/* static */ 1.4103 +const nsCSSFrameConstructor::FrameConstructionData* 1.4104 +nsCSSFrameConstructor::FindXULLabelData(Element* aElement, 1.4105 + nsStyleContext* /* unused */) 1.4106 +{ 1.4107 + if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) { 1.4108 + return &sXULTextBoxData; 1.4109 + } 1.4110 + 1.4111 + static const FrameConstructionData sLabelData = 1.4112 + SIMPLE_XUL_FCDATA(NS_NewXULLabelFrame); 1.4113 + return &sLabelData; 1.4114 +} 1.4115 + 1.4116 +static nsIFrame* 1.4117 +NS_NewXULDescriptionFrame(nsIPresShell* aPresShell, nsStyleContext *aContext) 1.4118 +{ 1.4119 + // XXXbz do we really need to set those flags? If the parent is not 1.4120 + // a block we'll get them anyway, and if it is, do we want them? 1.4121 + return NS_NewBlockFrame(aPresShell, aContext, 1.4122 + NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT); 1.4123 +} 1.4124 + 1.4125 +/* static */ 1.4126 +const nsCSSFrameConstructor::FrameConstructionData* 1.4127 +nsCSSFrameConstructor::FindXULDescriptionData(Element* aElement, 1.4128 + nsStyleContext* /* unused */) 1.4129 +{ 1.4130 + if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) { 1.4131 + return &sXULTextBoxData; 1.4132 + } 1.4133 + 1.4134 + static const FrameConstructionData sDescriptionData = 1.4135 + SIMPLE_XUL_FCDATA(NS_NewXULDescriptionFrame); 1.4136 + return &sDescriptionData; 1.4137 +} 1.4138 + 1.4139 +#ifdef XP_MACOSX 1.4140 +/* static */ 1.4141 +const nsCSSFrameConstructor::FrameConstructionData* 1.4142 +nsCSSFrameConstructor::FindXULMenubarData(Element* aElement, 1.4143 + nsStyleContext* aStyleContext) 1.4144 +{ 1.4145 + nsCOMPtr<nsIDocShell> treeItem = 1.4146 + aStyleContext->PresContext()->GetDocShell(); 1.4147 + if (treeItem && nsIDocShellTreeItem::typeChrome == treeItem->ItemType()) { 1.4148 + nsCOMPtr<nsIDocShellTreeItem> parent; 1.4149 + treeItem->GetParent(getter_AddRefs(parent)); 1.4150 + if (!parent) { 1.4151 + // This is the root. Suppress the menubar, since on Mac 1.4152 + // window menus are not attached to the window. 1.4153 + static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA(); 1.4154 + return &sSuppressData; 1.4155 + } 1.4156 + } 1.4157 + 1.4158 + static const FrameConstructionData sMenubarData = 1.4159 + SIMPLE_XUL_FCDATA(NS_NewMenuBarFrame); 1.4160 + return &sMenubarData; 1.4161 +} 1.4162 +#endif /* XP_MACOSX */ 1.4163 + 1.4164 +/* static */ 1.4165 +const nsCSSFrameConstructor::FrameConstructionData* 1.4166 +nsCSSFrameConstructor::FindXULListBoxBodyData(Element* aElement, 1.4167 + nsStyleContext* aStyleContext) 1.4168 +{ 1.4169 + if (aStyleContext->StyleDisplay()->mDisplay != 1.4170 + NS_STYLE_DISPLAY_XUL_GRID_GROUP) { 1.4171 + return nullptr; 1.4172 + } 1.4173 + 1.4174 + static const FrameConstructionData sListBoxBodyData = 1.4175 + SCROLLABLE_XUL_FCDATA(NS_NewListBoxBodyFrame); 1.4176 + return &sListBoxBodyData; 1.4177 +} 1.4178 + 1.4179 +/* static */ 1.4180 +const nsCSSFrameConstructor::FrameConstructionData* 1.4181 +nsCSSFrameConstructor::FindXULListItemData(Element* aElement, 1.4182 + nsStyleContext* aStyleContext) 1.4183 +{ 1.4184 + if (aStyleContext->StyleDisplay()->mDisplay != 1.4185 + NS_STYLE_DISPLAY_XUL_GRID_LINE) { 1.4186 + return nullptr; 1.4187 + } 1.4188 + 1.4189 + static const FrameConstructionData sListItemData = 1.4190 + SCROLLABLE_XUL_FCDATA(NS_NewListItemFrame); 1.4191 + return &sListItemData; 1.4192 +} 1.4193 + 1.4194 +#endif /* MOZ_XUL */ 1.4195 + 1.4196 +/* static */ 1.4197 +const nsCSSFrameConstructor::FrameConstructionData* 1.4198 +nsCSSFrameConstructor::FindXULDisplayData(const nsStyleDisplay* aDisplay, 1.4199 + Element* aElement, 1.4200 + nsStyleContext* aStyleContext) 1.4201 +{ 1.4202 + static const FrameConstructionDataByInt sXULDisplayData[] = { 1.4203 + SCROLLABLE_ABSPOS_CONTAINER_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_BOX, 1.4204 + NS_NewBoxFrame), 1.4205 + SCROLLABLE_ABSPOS_CONTAINER_XUL_INT_CREATE(NS_STYLE_DISPLAY_BOX, 1.4206 + NS_NewBoxFrame), 1.4207 +#ifdef MOZ_XUL 1.4208 + SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_XUL_GRID, NS_NewGridBoxFrame), 1.4209 + SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_XUL_GRID, NS_NewGridBoxFrame), 1.4210 + SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_XUL_GRID_GROUP, 1.4211 + NS_NewGridRowGroupFrame), 1.4212 + SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_XUL_GRID_LINE, 1.4213 + NS_NewGridRowLeafFrame), 1.4214 + SIMPLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_DECK, NS_NewDeckFrame), 1.4215 + SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GROUPBOX, NS_NewGroupBoxFrame), 1.4216 + SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_STACK, NS_NewStackFrame), 1.4217 + SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_STACK, NS_NewStackFrame), 1.4218 + { NS_STYLE_DISPLAY_POPUP, 1.4219 + FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_IS_POPUP | 1.4220 + FCDATA_SKIP_ABSPOS_PUSH, NS_NewMenuPopupFrame) } 1.4221 +#endif /* MOZ_XUL */ 1.4222 + }; 1.4223 + 1.4224 + // Processing by display here: 1.4225 + return FindDataByInt(aDisplay->mDisplay, aElement, aStyleContext, 1.4226 + sXULDisplayData, ArrayLength(sXULDisplayData)); 1.4227 +} 1.4228 + 1.4229 +already_AddRefed<nsStyleContext> 1.4230 +nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState& aState, 1.4231 + nsIContent* aContent, 1.4232 + nsStyleContext* aContentStyle, 1.4233 + nsIFrame* aParentFrame, 1.4234 + nsIAtom* aScrolledPseudo, 1.4235 + bool aIsRoot, 1.4236 + nsIFrame*& aNewFrame) 1.4237 +{ 1.4238 + nsIFrame* gfxScrollFrame = aNewFrame; 1.4239 + 1.4240 + nsFrameItems anonymousItems; 1.4241 + 1.4242 + nsRefPtr<nsStyleContext> contentStyle = aContentStyle; 1.4243 + 1.4244 + if (!gfxScrollFrame) { 1.4245 + // Build a XULScrollFrame when the child is a box, otherwise an 1.4246 + // HTMLScrollFrame 1.4247 + // XXXbz this is the lone remaining consumer of IsXULDisplayType. 1.4248 + // I wonder whether we can eliminate that somehow. 1.4249 + const nsStyleDisplay* displayStyle = aContentStyle->StyleDisplay(); 1.4250 + if (IsXULDisplayType(displayStyle)) { 1.4251 + gfxScrollFrame = NS_NewXULScrollFrame(mPresShell, contentStyle, aIsRoot, 1.4252 + displayStyle->mDisplay == NS_STYLE_DISPLAY_STACK || 1.4253 + displayStyle->mDisplay == NS_STYLE_DISPLAY_INLINE_STACK); 1.4254 + } else { 1.4255 + gfxScrollFrame = NS_NewHTMLScrollFrame(mPresShell, contentStyle, aIsRoot); 1.4256 + } 1.4257 + 1.4258 + InitAndRestoreFrame(aState, aContent, aParentFrame, gfxScrollFrame); 1.4259 + } 1.4260 + 1.4261 + // if there are any anonymous children for the scroll frame, create 1.4262 + // frames for them. 1.4263 + // Pass a null pending binding: we don't care how constructors for any of 1.4264 + // this anonymous content order with anything else. It's never been 1.4265 + // consistent anyway. 1.4266 + CreateAnonymousFrames(aState, aContent, gfxScrollFrame, nullptr, 1.4267 + anonymousItems); 1.4268 + 1.4269 + aNewFrame = gfxScrollFrame; 1.4270 + 1.4271 + // we used the style that was passed in. So resolve another one. 1.4272 + nsStyleSet *styleSet = mPresShell->StyleSet(); 1.4273 + nsRefPtr<nsStyleContext> scrolledChildStyle = 1.4274 + styleSet->ResolveAnonymousBoxStyle(aScrolledPseudo, contentStyle); 1.4275 + 1.4276 + if (gfxScrollFrame) { 1.4277 + gfxScrollFrame->SetInitialChildList(kPrincipalList, anonymousItems); 1.4278 + } 1.4279 + 1.4280 + return scrolledChildStyle.forget(); 1.4281 +} 1.4282 + 1.4283 +void 1.4284 +nsCSSFrameConstructor::FinishBuildingScrollFrame(nsIFrame* aScrollFrame, 1.4285 + nsIFrame* aScrolledFrame) 1.4286 +{ 1.4287 + nsFrameList scrolled(aScrolledFrame, aScrolledFrame); 1.4288 + aScrollFrame->AppendFrames(kPrincipalList, scrolled); 1.4289 +} 1.4290 + 1.4291 + 1.4292 +/** 1.4293 + * Called to wrap a gfx scrollframe around a frame. The hierarchy will look like this 1.4294 + * 1.4295 + * ------- for gfx scrollbars ------ 1.4296 + * 1.4297 + * 1.4298 + * ScrollFrame 1.4299 + * ^ 1.4300 + * | 1.4301 + * Frame (scrolled frame you passed in) 1.4302 + * 1.4303 + * 1.4304 + *----------------------------------- 1.4305 + * LEGEND: 1.4306 + * 1.4307 + * ScrollFrame: This is a frame that manages gfx cross platform frame based scrollbars. 1.4308 + * 1.4309 + * @param aContent the content node of the child to wrap. 1.4310 + * @param aScrolledFrame The frame of the content to wrap. This should not be 1.4311 + * Initialized. This method will initialize it with a scrolled pseudo 1.4312 + * and no nsIContent. The content will be attached to the scrollframe 1.4313 + * returned. 1.4314 + * @param aContentStyle the style context that has already been resolved for the content being passed in. 1.4315 + * 1.4316 + * @param aParentFrame The parent to attach the scroll frame to 1.4317 + * 1.4318 + * @param aNewFrame The new scrollframe or gfx scrollframe that we create. It will contain the 1.4319 + * scrolled frame you passed in. (returned) 1.4320 + * If this is not null, we'll just use it 1.4321 + * @param aScrolledContentStyle the style that was resolved for the scrolled frame. (returned) 1.4322 + */ 1.4323 +nsresult 1.4324 +nsCSSFrameConstructor::BuildScrollFrame(nsFrameConstructorState& aState, 1.4325 + nsIContent* aContent, 1.4326 + nsStyleContext* aContentStyle, 1.4327 + nsIFrame* aScrolledFrame, 1.4328 + nsIFrame* aParentFrame, 1.4329 + nsIFrame*& aNewFrame) 1.4330 +{ 1.4331 + nsRefPtr<nsStyleContext> scrolledContentStyle = 1.4332 + BeginBuildingScrollFrame(aState, aContent, aContentStyle, aParentFrame, 1.4333 + nsCSSAnonBoxes::scrolledContent, 1.4334 + false, aNewFrame); 1.4335 + 1.4336 + aScrolledFrame->SetStyleContextWithoutNotification(scrolledContentStyle); 1.4337 + InitAndRestoreFrame(aState, aContent, aNewFrame, aScrolledFrame); 1.4338 + 1.4339 + FinishBuildingScrollFrame(aNewFrame, aScrolledFrame); 1.4340 + return NS_OK; 1.4341 +} 1.4342 + 1.4343 +const nsCSSFrameConstructor::FrameConstructionData* 1.4344 +nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay, 1.4345 + Element* aElement, 1.4346 + nsIFrame* aParentFrame, 1.4347 + nsStyleContext* aStyleContext) 1.4348 +{ 1.4349 + PR_STATIC_ASSERT(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET))); 1.4350 + 1.4351 + // The style system ensures that floated and positioned frames are 1.4352 + // block-level. 1.4353 + NS_ASSERTION(!(aDisplay->IsFloatingStyle() || 1.4354 + aDisplay->IsAbsolutelyPositionedStyle()) || 1.4355 + aDisplay->IsBlockOutsideStyle(), 1.4356 + "Style system did not apply CSS2.1 section 9.7 fixups"); 1.4357 + 1.4358 + // If this is "body", try propagating its scroll style to the viewport 1.4359 + // Note that we need to do this even if the body is NOT scrollable; 1.4360 + // it might have dynamically changed from scrollable to not scrollable, 1.4361 + // and that might need to be propagated. 1.4362 + // XXXbz is this the right place to do this? If this code moves, 1.4363 + // make this function static. 1.4364 + bool propagatedScrollToViewport = false; 1.4365 + if (aElement->IsHTML(nsGkAtoms::body)) { 1.4366 + propagatedScrollToViewport = 1.4367 + PropagateScrollToViewport() == aElement; 1.4368 + } 1.4369 + 1.4370 + NS_ASSERTION(!propagatedScrollToViewport || 1.4371 + !mPresShell->GetPresContext()->IsPaginated(), 1.4372 + "Shouldn't propagate scroll in paginated contexts"); 1.4373 + 1.4374 + // If the frame is a block-level frame and is scrollable, then wrap it in a 1.4375 + // scroll frame. 1.4376 + // XXX Ignore tables for the time being 1.4377 + // XXXbz it would be nice to combine this with the other block 1.4378 + // case... Think about how do do this? 1.4379 + if (aDisplay->IsBlockInsideStyle() && 1.4380 + aDisplay->IsScrollableOverflow() && 1.4381 + !propagatedScrollToViewport) { 1.4382 + // Except we don't want to do that for paginated contexts for 1.4383 + // frames that are block-outside and aren't frames for native 1.4384 + // anonymous stuff. 1.4385 + if (mPresShell->GetPresContext()->IsPaginated() && 1.4386 + aDisplay->IsBlockOutsideStyle() && 1.4387 + !aElement->IsInNativeAnonymousSubtree()) { 1.4388 + static const FrameConstructionData sForcedNonScrollableBlockData = 1.4389 + FULL_CTOR_FCDATA(FCDATA_FORCED_NON_SCROLLABLE_BLOCK, 1.4390 + &nsCSSFrameConstructor::ConstructNonScrollableBlock); 1.4391 + return &sForcedNonScrollableBlockData; 1.4392 + } 1.4393 + 1.4394 + static const FrameConstructionData sScrollableBlockData = 1.4395 + FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructScrollableBlock); 1.4396 + return &sScrollableBlockData; 1.4397 + } 1.4398 + 1.4399 + // Handle various non-scrollable blocks 1.4400 + if (aDisplay->IsBlockInsideStyle()) { 1.4401 + static const FrameConstructionData sNonScrollableBlockData = 1.4402 + FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructNonScrollableBlock); 1.4403 + return &sNonScrollableBlockData; 1.4404 + } 1.4405 + 1.4406 + static const FrameConstructionDataByInt sDisplayData[] = { 1.4407 + // To keep the hash table small don't add inline frames (they're 1.4408 + // typically things like FONT and B), because we can quickly 1.4409 + // find them if we need to. 1.4410 + // XXXbz the "quickly" part is a bald-faced lie! 1.4411 + { NS_STYLE_DISPLAY_INLINE, 1.4412 + FULL_CTOR_FCDATA(FCDATA_IS_INLINE | FCDATA_IS_LINE_PARTICIPANT, 1.4413 + &nsCSSFrameConstructor::ConstructInline) }, 1.4414 + { NS_STYLE_DISPLAY_FLEX, 1.4415 + FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame) }, 1.4416 + { NS_STYLE_DISPLAY_INLINE_FLEX, 1.4417 + FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame) }, 1.4418 + { NS_STYLE_DISPLAY_GRID, 1.4419 + FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame) }, 1.4420 + { NS_STYLE_DISPLAY_INLINE_GRID, 1.4421 + FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame) }, 1.4422 + { NS_STYLE_DISPLAY_TABLE, 1.4423 + FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable) }, 1.4424 + { NS_STYLE_DISPLAY_INLINE_TABLE, 1.4425 + FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable) }, 1.4426 + // NOTE: In the unlikely event that we add another table-part here that has 1.4427 + // a desired-parent-type (& hence triggers table fixup), we'll need to also 1.4428 + // update the flexbox chunk in nsStyleContext::ApplyStyleFixups(). 1.4429 + { NS_STYLE_DISPLAY_TABLE_CAPTION, 1.4430 + FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_ALLOW_BLOCK_STYLES | 1.4431 + FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH | 1.4432 + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), 1.4433 + NS_NewTableCaptionFrame) }, 1.4434 + { NS_STYLE_DISPLAY_TABLE_ROW_GROUP, 1.4435 + FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | 1.4436 + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), 1.4437 + &nsCSSFrameConstructor::ConstructTableRowOrRowGroup) }, 1.4438 + { NS_STYLE_DISPLAY_TABLE_HEADER_GROUP, 1.4439 + FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | 1.4440 + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), 1.4441 + &nsCSSFrameConstructor::ConstructTableRowOrRowGroup) }, 1.4442 + { NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP, 1.4443 + FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | 1.4444 + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), 1.4445 + &nsCSSFrameConstructor::ConstructTableRowOrRowGroup) }, 1.4446 + { NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP, 1.4447 + FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW | 1.4448 + FCDATA_SKIP_ABSPOS_PUSH | 1.4449 + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), 1.4450 + NS_NewTableColGroupFrame) }, 1.4451 + { NS_STYLE_DISPLAY_TABLE_COLUMN, 1.4452 + FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | 1.4453 + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeColGroup), 1.4454 + &nsCSSFrameConstructor::ConstructTableCol) }, 1.4455 + { NS_STYLE_DISPLAY_TABLE_ROW, 1.4456 + FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | 1.4457 + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup), 1.4458 + &nsCSSFrameConstructor::ConstructTableRowOrRowGroup) }, 1.4459 + { NS_STYLE_DISPLAY_TABLE_CELL, 1.4460 + FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | 1.4461 + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow), 1.4462 + &nsCSSFrameConstructor::ConstructTableCell) } 1.4463 + }; 1.4464 + 1.4465 + return FindDataByInt(aDisplay->mDisplay, 1.4466 + aElement, aStyleContext, sDisplayData, 1.4467 + ArrayLength(sDisplayData)); 1.4468 +} 1.4469 + 1.4470 +nsIFrame* 1.4471 +nsCSSFrameConstructor::ConstructScrollableBlock(nsFrameConstructorState& aState, 1.4472 + FrameConstructionItem& aItem, 1.4473 + nsIFrame* aParentFrame, 1.4474 + const nsStyleDisplay* aDisplay, 1.4475 + nsFrameItems& aFrameItems) 1.4476 +{ 1.4477 + nsIContent* const content = aItem.mContent; 1.4478 + nsStyleContext* const styleContext = aItem.mStyleContext; 1.4479 + 1.4480 + nsIFrame* newFrame = nullptr; 1.4481 + nsRefPtr<nsStyleContext> scrolledContentStyle 1.4482 + = BeginBuildingScrollFrame(aState, content, styleContext, 1.4483 + aState.GetGeometricParent(aDisplay, aParentFrame), 1.4484 + nsCSSAnonBoxes::scrolledContent, 1.4485 + false, newFrame); 1.4486 + 1.4487 + // Create our block frame 1.4488 + // pass a temporary stylecontext, the correct one will be set later 1.4489 + nsIFrame* scrolledFrame = 1.4490 + NS_NewBlockFormattingContext(mPresShell, styleContext); 1.4491 + 1.4492 + // Make sure to AddChild before we call ConstructBlock so that we 1.4493 + // end up before our descendants in fixed-pos lists as needed. 1.4494 + aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame); 1.4495 + 1.4496 + nsFrameItems blockItem; 1.4497 + ConstructBlock(aState, scrolledContentStyle->StyleDisplay(), content, 1.4498 + newFrame, newFrame, scrolledContentStyle, 1.4499 + &scrolledFrame, blockItem, 1.4500 + aDisplay->IsPositioned(newFrame) ? newFrame : nullptr, 1.4501 + aItem.mPendingBinding); 1.4502 + 1.4503 + NS_ASSERTION(blockItem.FirstChild() == scrolledFrame, 1.4504 + "Scrollframe's frameItems should be exactly the scrolled frame"); 1.4505 + FinishBuildingScrollFrame(newFrame, scrolledFrame); 1.4506 + 1.4507 + return newFrame; 1.4508 +} 1.4509 + 1.4510 +nsIFrame* 1.4511 +nsCSSFrameConstructor::ConstructNonScrollableBlock(nsFrameConstructorState& aState, 1.4512 + FrameConstructionItem& aItem, 1.4513 + nsIFrame* aParentFrame, 1.4514 + const nsStyleDisplay* aDisplay, 1.4515 + nsFrameItems& aFrameItems) 1.4516 +{ 1.4517 + nsStyleContext* const styleContext = aItem.mStyleContext; 1.4518 + 1.4519 + // We want a block formatting context root in paginated contexts for 1.4520 + // every block that would be scrollable in a non-paginated context. 1.4521 + // We mark our blocks with a bit here if this condition is true, so 1.4522 + // we can check it later in nsFrame::ApplyPaginatedOverflowClipping. 1.4523 + bool clipPaginatedOverflow = 1.4524 + (aItem.mFCData->mBits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) != 0; 1.4525 + nsIFrame* newFrame; 1.4526 + if ((aDisplay->IsAbsolutelyPositionedStyle() || 1.4527 + aDisplay->IsFloatingStyle() || 1.4528 + NS_STYLE_DISPLAY_INLINE_BLOCK == aDisplay->mDisplay || 1.4529 + clipPaginatedOverflow) && 1.4530 + !aParentFrame->IsSVGText()) { 1.4531 + newFrame = NS_NewBlockFormattingContext(mPresShell, styleContext); 1.4532 + if (clipPaginatedOverflow) { 1.4533 + newFrame->AddStateBits(NS_BLOCK_CLIP_PAGINATED_OVERFLOW); 1.4534 + } 1.4535 + } else { 1.4536 + newFrame = NS_NewBlockFrame(mPresShell, styleContext); 1.4537 + } 1.4538 + 1.4539 + ConstructBlock(aState, aDisplay, aItem.mContent, 1.4540 + aState.GetGeometricParent(aDisplay, aParentFrame), 1.4541 + aParentFrame, styleContext, &newFrame, 1.4542 + aFrameItems, 1.4543 + aDisplay->IsPositioned(newFrame) ? newFrame : nullptr, 1.4544 + aItem.mPendingBinding); 1.4545 + return newFrame; 1.4546 +} 1.4547 + 1.4548 + 1.4549 +void 1.4550 +nsCSSFrameConstructor::InitAndRestoreFrame(const nsFrameConstructorState& aState, 1.4551 + nsIContent* aContent, 1.4552 + nsIFrame* aParentFrame, 1.4553 + nsIFrame* aNewFrame, 1.4554 + bool aAllowCounters) 1.4555 +{ 1.4556 + NS_PRECONDITION(mUpdateCount != 0, 1.4557 + "Should be in an update while creating frames"); 1.4558 + 1.4559 + MOZ_ASSERT(aNewFrame, "Null frame cannot be initialized"); 1.4560 + 1.4561 + // Initialize the frame 1.4562 + aNewFrame->Init(aContent, aParentFrame, nullptr); 1.4563 + aNewFrame->AddStateBits(aState.mAdditionalStateBits); 1.4564 + 1.4565 + if (aState.mFrameState) { 1.4566 + // Restore frame state for just the newly created frame. 1.4567 + RestoreFrameStateFor(aNewFrame, aState.mFrameState); 1.4568 + } 1.4569 + 1.4570 + if (aAllowCounters && 1.4571 + mCounterManager.AddCounterResetsAndIncrements(aNewFrame)) { 1.4572 + CountersDirty(); 1.4573 + } 1.4574 +} 1.4575 + 1.4576 +already_AddRefed<nsStyleContext> 1.4577 +nsCSSFrameConstructor::ResolveStyleContext(nsIFrame* aParentFrame, 1.4578 + nsIContent* aContent, 1.4579 + nsFrameConstructorState* aState) 1.4580 +{ 1.4581 + nsStyleContext* parentStyleContext = nullptr; 1.4582 + NS_ASSERTION(aContent->GetParent(), "Must have parent here"); 1.4583 + 1.4584 + aParentFrame = nsFrame::CorrectStyleParentFrame(aParentFrame, nullptr); 1.4585 + 1.4586 + if (aParentFrame) { 1.4587 + // Resolve the style context based on the content object and the parent 1.4588 + // style context 1.4589 + parentStyleContext = aParentFrame->StyleContext(); 1.4590 + } else { 1.4591 + // Perhaps aParentFrame is a canvasFrame and we're replicating 1.4592 + // fixed-pos frames. 1.4593 + // XXX should we create a way to tell ConstructFrame which style 1.4594 + // context to use, and pass it the style context for the 1.4595 + // previous page's fixed-pos frame? 1.4596 + } 1.4597 + 1.4598 + return ResolveStyleContext(parentStyleContext, aContent, aState); 1.4599 +} 1.4600 + 1.4601 +already_AddRefed<nsStyleContext> 1.4602 +nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext* aParentStyleContext, 1.4603 + nsIContent* aContent, 1.4604 + nsFrameConstructorState* aState) 1.4605 +{ 1.4606 + nsStyleSet *styleSet = mPresShell->StyleSet(); 1.4607 + aContent->OwnerDoc()->FlushPendingLinkUpdates(); 1.4608 + 1.4609 + if (aContent->IsElement()) { 1.4610 + if (aState) { 1.4611 + return styleSet->ResolveStyleFor(aContent->AsElement(), 1.4612 + aParentStyleContext, 1.4613 + aState->mTreeMatchContext); 1.4614 + } 1.4615 + return styleSet->ResolveStyleFor(aContent->AsElement(), aParentStyleContext); 1.4616 + 1.4617 + } 1.4618 + 1.4619 + NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT), 1.4620 + "shouldn't waste time creating style contexts for " 1.4621 + "comments and processing instructions"); 1.4622 + 1.4623 + return styleSet->ResolveStyleForNonElement(aParentStyleContext); 1.4624 +} 1.4625 + 1.4626 +// MathML Mod - RBS 1.4627 +void 1.4628 +nsCSSFrameConstructor::FlushAccumulatedBlock(nsFrameConstructorState& aState, 1.4629 + nsIContent* aContent, 1.4630 + nsIFrame* aParentFrame, 1.4631 + nsFrameItems& aBlockItems, 1.4632 + nsFrameItems& aNewItems) 1.4633 +{ 1.4634 + if (aBlockItems.IsEmpty()) { 1.4635 + // Nothing to do 1.4636 + return; 1.4637 + } 1.4638 + 1.4639 + nsIAtom* anonPseudo = nsCSSAnonBoxes::mozMathMLAnonymousBlock; 1.4640 + 1.4641 + nsStyleContext* parentContext = 1.4642 + nsFrame::CorrectStyleParentFrame(aParentFrame, 1.4643 + anonPseudo)->StyleContext(); 1.4644 + nsStyleSet* styleSet = mPresShell->StyleSet(); 1.4645 + nsRefPtr<nsStyleContext> blockContext; 1.4646 + blockContext = styleSet-> 1.4647 + ResolveAnonymousBoxStyle(anonPseudo, parentContext); 1.4648 + 1.4649 + 1.4650 + // then, create a block frame that will wrap the child frames. Make it a 1.4651 + // MathML frame so that Get(Absolute/Float)ContainingBlockFor know that this 1.4652 + // is not a suitable block. 1.4653 + nsIFrame* blockFrame = 1.4654 + NS_NewMathMLmathBlockFrame(mPresShell, blockContext, 1.4655 + NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT); 1.4656 + 1.4657 + InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame); 1.4658 + ReparentFrames(this, blockFrame, aBlockItems); 1.4659 + // abs-pos and floats are disabled in MathML children so we don't have to 1.4660 + // worry about messing up those. 1.4661 + blockFrame->SetInitialChildList(kPrincipalList, aBlockItems); 1.4662 + NS_ASSERTION(aBlockItems.IsEmpty(), "What happened?"); 1.4663 + aBlockItems.Clear(); 1.4664 + aNewItems.AddChild(blockFrame); 1.4665 +} 1.4666 + 1.4667 +// Only <math> elements can be floated or positioned. All other MathML 1.4668 +// should be in-flow. 1.4669 +#define SIMPLE_MATHML_CREATE(_tag, _func) \ 1.4670 + { &nsGkAtoms::_tag, \ 1.4671 + FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \ 1.4672 + FCDATA_FORCE_NULL_ABSPOS_CONTAINER | \ 1.4673 + FCDATA_WRAP_KIDS_IN_BLOCKS, _func) } 1.4674 + 1.4675 +/* static */ 1.4676 +const nsCSSFrameConstructor::FrameConstructionData* 1.4677 +nsCSSFrameConstructor::FindMathMLData(Element* aElement, 1.4678 + nsIAtom* aTag, 1.4679 + int32_t aNameSpaceID, 1.4680 + nsStyleContext* aStyleContext) 1.4681 +{ 1.4682 + // Make sure that we remain confined in the MathML world 1.4683 + if (aNameSpaceID != kNameSpaceID_MathML) 1.4684 + return nullptr; 1.4685 + 1.4686 + // Handle <math> specially, because it sometimes produces inlines 1.4687 + if (aTag == nsGkAtoms::math) { 1.4688 + // This needs to match the test in EnsureBlockDisplay in 1.4689 + // nsRuleNode.cpp. Though the behavior here for the display:table 1.4690 + // case is pretty weird... 1.4691 + if (aStyleContext->StyleDisplay()->IsBlockOutsideStyle()) { 1.4692 + static const FrameConstructionData sBlockMathData = 1.4693 + FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER | 1.4694 + FCDATA_WRAP_KIDS_IN_BLOCKS, 1.4695 + NS_CreateNewMathMLmathBlockFrame); 1.4696 + return &sBlockMathData; 1.4697 + } 1.4698 + 1.4699 + static const FrameConstructionData sInlineMathData = 1.4700 + FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER | 1.4701 + FCDATA_IS_LINE_PARTICIPANT | 1.4702 + FCDATA_WRAP_KIDS_IN_BLOCKS, 1.4703 + NS_NewMathMLmathInlineFrame); 1.4704 + return &sInlineMathData; 1.4705 + } 1.4706 + 1.4707 + 1.4708 + static const FrameConstructionDataByTag sMathMLData[] = { 1.4709 + SIMPLE_MATHML_CREATE(annotation_, NS_NewMathMLTokenFrame), 1.4710 + SIMPLE_MATHML_CREATE(annotation_xml_, NS_NewMathMLmrowFrame), 1.4711 + SIMPLE_MATHML_CREATE(mi_, NS_NewMathMLTokenFrame), 1.4712 + SIMPLE_MATHML_CREATE(mn_, NS_NewMathMLTokenFrame), 1.4713 + SIMPLE_MATHML_CREATE(ms_, NS_NewMathMLTokenFrame), 1.4714 + SIMPLE_MATHML_CREATE(mtext_, NS_NewMathMLTokenFrame), 1.4715 + SIMPLE_MATHML_CREATE(mo_, NS_NewMathMLmoFrame), 1.4716 + SIMPLE_MATHML_CREATE(mfrac_, NS_NewMathMLmfracFrame), 1.4717 + SIMPLE_MATHML_CREATE(msup_, NS_NewMathMLmmultiscriptsFrame), 1.4718 + SIMPLE_MATHML_CREATE(msub_, NS_NewMathMLmmultiscriptsFrame), 1.4719 + SIMPLE_MATHML_CREATE(msubsup_, NS_NewMathMLmmultiscriptsFrame), 1.4720 + SIMPLE_MATHML_CREATE(munder_, NS_NewMathMLmunderoverFrame), 1.4721 + SIMPLE_MATHML_CREATE(mover_, NS_NewMathMLmunderoverFrame), 1.4722 + SIMPLE_MATHML_CREATE(munderover_, NS_NewMathMLmunderoverFrame), 1.4723 + SIMPLE_MATHML_CREATE(mphantom_, NS_NewMathMLmphantomFrame), 1.4724 + SIMPLE_MATHML_CREATE(mpadded_, NS_NewMathMLmpaddedFrame), 1.4725 + SIMPLE_MATHML_CREATE(mspace_, NS_NewMathMLmspaceFrame), 1.4726 + SIMPLE_MATHML_CREATE(none, NS_NewMathMLmspaceFrame), 1.4727 + SIMPLE_MATHML_CREATE(mprescripts_, NS_NewMathMLmspaceFrame), 1.4728 + SIMPLE_MATHML_CREATE(mfenced_, NS_NewMathMLmfencedFrame), 1.4729 + SIMPLE_MATHML_CREATE(mmultiscripts_, NS_NewMathMLmmultiscriptsFrame), 1.4730 + SIMPLE_MATHML_CREATE(mstyle_, NS_NewMathMLmrowFrame), 1.4731 + SIMPLE_MATHML_CREATE(msqrt_, NS_NewMathMLmsqrtFrame), 1.4732 + SIMPLE_MATHML_CREATE(mroot_, NS_NewMathMLmrootFrame), 1.4733 + SIMPLE_MATHML_CREATE(maction_, NS_NewMathMLmactionFrame), 1.4734 + SIMPLE_MATHML_CREATE(mrow_, NS_NewMathMLmrowFrame), 1.4735 + SIMPLE_MATHML_CREATE(merror_, NS_NewMathMLmrowFrame), 1.4736 + SIMPLE_MATHML_CREATE(menclose_, NS_NewMathMLmencloseFrame), 1.4737 + SIMPLE_MATHML_CREATE(semantics_, NS_NewMathMLsemanticsFrame) 1.4738 + }; 1.4739 + 1.4740 + return FindDataByTag(aTag, aElement, aStyleContext, sMathMLData, 1.4741 + ArrayLength(sMathMLData)); 1.4742 +} 1.4743 + 1.4744 + 1.4745 +nsIFrame* 1.4746 +nsCSSFrameConstructor::ConstructFrameWithAnonymousChild( 1.4747 + nsFrameConstructorState& aState, 1.4748 + FrameConstructionItem& aItem, 1.4749 + nsIFrame* aParentFrame, 1.4750 + const nsStyleDisplay* aDisplay, 1.4751 + nsFrameItems& aFrameItems, 1.4752 + FrameCreationFunc aConstructor, 1.4753 + FrameCreationFunc aInnerConstructor, 1.4754 + nsICSSAnonBoxPseudo* aInnerPseudo, 1.4755 + bool aCandidateRootFrame) 1.4756 +{ 1.4757 + nsIContent* const content = aItem.mContent; 1.4758 + nsStyleContext* const styleContext = aItem.mStyleContext; 1.4759 + 1.4760 + // Create the outer frame: 1.4761 + nsIFrame* newFrame = aConstructor(mPresShell, styleContext); 1.4762 + 1.4763 + InitAndRestoreFrame(aState, content, 1.4764 + aCandidateRootFrame ? 1.4765 + aState.GetGeometricParent(styleContext->StyleDisplay(), 1.4766 + aParentFrame) : 1.4767 + aParentFrame, 1.4768 + newFrame); 1.4769 + 1.4770 + // Create the pseudo SC for the anonymous wrapper child as a child of the SC: 1.4771 + nsRefPtr<nsStyleContext> scForAnon; 1.4772 + scForAnon = mPresShell->StyleSet()-> 1.4773 + ResolveAnonymousBoxStyle(aInnerPseudo, styleContext); 1.4774 + 1.4775 + // Create the anonymous inner wrapper frame 1.4776 + nsIFrame* innerFrame = aInnerConstructor(mPresShell, scForAnon); 1.4777 + 1.4778 + InitAndRestoreFrame(aState, content, newFrame, innerFrame); 1.4779 + 1.4780 + // Put the newly created frames into the right child list 1.4781 + SetInitialSingleChild(newFrame, innerFrame); 1.4782 + 1.4783 + aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame, 1.4784 + aCandidateRootFrame, aCandidateRootFrame); 1.4785 + 1.4786 + if (!mRootElementFrame && aCandidateRootFrame) { 1.4787 + // The frame we're constructing will be the root element frame. 1.4788 + // Set mRootElementFrame before processing children. 1.4789 + mRootElementFrame = newFrame; 1.4790 + } 1.4791 + 1.4792 + nsFrameItems childItems; 1.4793 + 1.4794 + // Process children 1.4795 + NS_ASSERTION(aItem.mAnonChildren.IsEmpty(), 1.4796 + "nsIAnonymousContentCreator::CreateAnonymousContent should not " 1.4797 + "be implemented for frames for which we explicitly create an " 1.4798 + "anonymous child to wrap its child frames"); 1.4799 + if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) { 1.4800 + ConstructFramesFromItemList(aState, aItem.mChildItems, 1.4801 + innerFrame, childItems); 1.4802 + } else { 1.4803 + ProcessChildren(aState, content, styleContext, innerFrame, 1.4804 + true, childItems, false, aItem.mPendingBinding); 1.4805 + } 1.4806 + 1.4807 + // Set the inner wrapper frame's initial primary list 1.4808 + innerFrame->SetInitialChildList(kPrincipalList, childItems); 1.4809 + 1.4810 + return newFrame; 1.4811 +} 1.4812 + 1.4813 +nsIFrame* 1.4814 +nsCSSFrameConstructor::ConstructOuterSVG(nsFrameConstructorState& aState, 1.4815 + FrameConstructionItem& aItem, 1.4816 + nsIFrame* aParentFrame, 1.4817 + const nsStyleDisplay* aDisplay, 1.4818 + nsFrameItems& aFrameItems) 1.4819 +{ 1.4820 + return ConstructFrameWithAnonymousChild( 1.4821 + aState, aItem, aParentFrame, aDisplay, aFrameItems, 1.4822 + NS_NewSVGOuterSVGFrame, NS_NewSVGOuterSVGAnonChildFrame, 1.4823 + nsCSSAnonBoxes::mozSVGOuterSVGAnonChild, true); 1.4824 +} 1.4825 + 1.4826 +nsIFrame* 1.4827 +nsCSSFrameConstructor::ConstructMarker(nsFrameConstructorState& aState, 1.4828 + FrameConstructionItem& aItem, 1.4829 + nsIFrame* aParentFrame, 1.4830 + const nsStyleDisplay* aDisplay, 1.4831 + nsFrameItems& aFrameItems) 1.4832 +{ 1.4833 + return ConstructFrameWithAnonymousChild( 1.4834 + aState, aItem, aParentFrame, aDisplay, aFrameItems, 1.4835 + NS_NewSVGMarkerFrame, NS_NewSVGMarkerAnonChildFrame, 1.4836 + nsCSSAnonBoxes::mozSVGMarkerAnonChild, false); 1.4837 +} 1.4838 + 1.4839 +// Only outer <svg> elements can be floated or positioned. All other SVG 1.4840 +// should be in-flow. 1.4841 +#define SIMPLE_SVG_FCDATA(_func) \ 1.4842 + FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | \ 1.4843 + FCDATA_SKIP_ABSPOS_PUSH | \ 1.4844 + FCDATA_DISALLOW_GENERATED_CONTENT, _func) 1.4845 +#define SIMPLE_SVG_CREATE(_tag, _func) \ 1.4846 + { &nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func) } 1.4847 + 1.4848 +static bool 1.4849 +IsFilterPrimitiveChildTag(const nsIAtom* aTag) 1.4850 +{ 1.4851 + return aTag == nsGkAtoms::feDistantLight || 1.4852 + aTag == nsGkAtoms::fePointLight || 1.4853 + aTag == nsGkAtoms::feSpotLight || 1.4854 + aTag == nsGkAtoms::feFuncR || 1.4855 + aTag == nsGkAtoms::feFuncG || 1.4856 + aTag == nsGkAtoms::feFuncB || 1.4857 + aTag == nsGkAtoms::feFuncA || 1.4858 + aTag == nsGkAtoms::feMergeNode; 1.4859 +} 1.4860 + 1.4861 +/* static */ 1.4862 +const nsCSSFrameConstructor::FrameConstructionData* 1.4863 +nsCSSFrameConstructor::FindSVGData(Element* aElement, 1.4864 + nsIAtom* aTag, 1.4865 + int32_t aNameSpaceID, 1.4866 + nsIFrame* aParentFrame, 1.4867 + bool aIsWithinSVGText, 1.4868 + bool aAllowsTextPathChild, 1.4869 + nsStyleContext* aStyleContext) 1.4870 +{ 1.4871 + if (aNameSpaceID != kNameSpaceID_SVG) { 1.4872 + return nullptr; 1.4873 + } 1.4874 + 1.4875 + static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA(); 1.4876 + static const FrameConstructionData sContainerData = 1.4877 + SIMPLE_SVG_FCDATA(NS_NewSVGContainerFrame); 1.4878 + 1.4879 + bool parentIsSVG = aIsWithinSVGText; 1.4880 + nsIContent* parentContent = 1.4881 + aParentFrame ? aParentFrame->GetContent() : nullptr; 1.4882 + // XXXbz should this really be based on the XBL-resolved tag of the parent 1.4883 + // frame's content? Should it not be based on the type of the parent frame 1.4884 + // (e.g. whether it's an SVG frame)? 1.4885 + if (parentContent) { 1.4886 + int32_t parentNSID; 1.4887 + nsIAtom* parentTag = 1.4888 + parentContent->OwnerDoc()->BindingManager()-> 1.4889 + ResolveTag(parentContent, &parentNSID); 1.4890 + 1.4891 + // It's not clear whether the SVG spec intends to allow any SVG 1.4892 + // content within svg:foreignObject at all (SVG 1.1, section 1.4893 + // 23.2), but if it does, it better be svg:svg. So given that 1.4894 + // we're allowing it, treat it as a non-SVG parent. 1.4895 + parentIsSVG = parentNSID == kNameSpaceID_SVG && 1.4896 + parentTag != nsGkAtoms::foreignObject; 1.4897 + } 1.4898 + 1.4899 + if ((aTag != nsGkAtoms::svg && !parentIsSVG) || 1.4900 + (aTag == nsGkAtoms::desc || aTag == nsGkAtoms::title)) { 1.4901 + // Sections 5.1 and G.4 of SVG 1.1 say that SVG elements other than 1.4902 + // svg:svg not contained within svg:svg are incorrect, although they 1.4903 + // don't seem to specify error handling. Ignore them, since many of 1.4904 + // our frame classes can't deal. It *may* be that the document 1.4905 + // should at that point be considered in error according to F.2, but 1.4906 + // it's hard to tell. 1.4907 + // 1.4908 + // Style mutation can't change this situation, so don't bother 1.4909 + // adding to the undisplayed content map. 1.4910 + // 1.4911 + // We don't currently handle any UI for desc/title 1.4912 + return &sSuppressData; 1.4913 + } 1.4914 + 1.4915 + // We don't need frames for animation elements 1.4916 + if (aElement->IsNodeOfType(nsINode::eANIMATION)) { 1.4917 + return &sSuppressData; 1.4918 + } 1.4919 + 1.4920 + if (aTag == nsGkAtoms::svg && !parentIsSVG) { 1.4921 + // We need outer <svg> elements to have an nsSVGOuterSVGFrame regardless 1.4922 + // of whether they fail conditional processing attributes, since various 1.4923 + // SVG frames assume that one exists. We handle the non-rendering 1.4924 + // of failing outer <svg> element contents like <switch> statements, 1.4925 + // and do the PassesConditionalProcessingTests call in 1.4926 + // nsSVGOuterSVGFrame::Init. 1.4927 + static const FrameConstructionData sOuterSVGData = 1.4928 + FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructOuterSVG); 1.4929 + return &sOuterSVGData; 1.4930 + } 1.4931 + 1.4932 + if (aTag == nsGkAtoms::marker) { 1.4933 + static const FrameConstructionData sMarkerSVGData = 1.4934 + FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructMarker); 1.4935 + return &sMarkerSVGData; 1.4936 + } 1.4937 + 1.4938 + nsCOMPtr<SVGTests> tests(do_QueryInterface(aElement)); 1.4939 + if (tests && !tests->PassesConditionalProcessingTests()) { 1.4940 + // Elements with failing conditional processing attributes never get 1.4941 + // rendered. Note that this is not where we select which frame in a 1.4942 + // <switch> to render! That happens in nsSVGSwitchFrame::PaintSVG. 1.4943 + return &sContainerData; 1.4944 + } 1.4945 + 1.4946 + // Prevent bad frame types being children of filters or parents of filter 1.4947 + // primitives. If aParentFrame is null, we know that the frame that will 1.4948 + // be created will be an nsInlineFrame, so it can never be a filter. 1.4949 + bool parentIsFilter = aParentFrame && 1.4950 + aParentFrame->GetType() == nsGkAtoms::svgFilterFrame; 1.4951 + bool filterPrimitive = aElement->IsNodeOfType(nsINode::eFILTER); 1.4952 + if ((parentIsFilter && !filterPrimitive) || 1.4953 + (!parentIsFilter && filterPrimitive)) { 1.4954 + return &sSuppressData; 1.4955 + } 1.4956 + 1.4957 + // Prevent bad frame types being children of filter primitives or parents of 1.4958 + // filter primitive children. If aParentFrame is null, we know that the frame 1.4959 + // that will be created will be an nsInlineFrame, so it can never be a filter 1.4960 + // primitive. 1.4961 + bool parentIsFEContainerFrame = aParentFrame && 1.4962 + aParentFrame->GetType() == nsGkAtoms::svgFEContainerFrame; 1.4963 + if ((parentIsFEContainerFrame && !IsFilterPrimitiveChildTag(aTag)) || 1.4964 + (!parentIsFEContainerFrame && IsFilterPrimitiveChildTag(aTag))) { 1.4965 + return &sSuppressData; 1.4966 + } 1.4967 + 1.4968 + // Special cases for text/tspan/textPath, because the kind of frame 1.4969 + // they get depends on the parent frame. We ignore 'a' elements when 1.4970 + // determining the parent, however. 1.4971 + if (aIsWithinSVGText) { 1.4972 + // If aIsWithinSVGText is true, then we know that the "SVG text uses 1.4973 + // CSS frames" pref was true when this SVG fragment was first constructed. 1.4974 + 1.4975 + // We don't use ConstructInline because we want different behavior 1.4976 + // for generated content. 1.4977 + static const FrameConstructionData sTSpanData = 1.4978 + FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | 1.4979 + FCDATA_SKIP_ABSPOS_PUSH | 1.4980 + FCDATA_DISALLOW_GENERATED_CONTENT | 1.4981 + FCDATA_IS_LINE_PARTICIPANT | 1.4982 + FCDATA_IS_INLINE | 1.4983 + FCDATA_USE_CHILD_ITEMS, 1.4984 + NS_NewInlineFrame); 1.4985 + if (aTag == nsGkAtoms::textPath) { 1.4986 + if (aAllowsTextPathChild) { 1.4987 + return &sTSpanData; 1.4988 + } 1.4989 + } else if (aTag == nsGkAtoms::tspan || 1.4990 + aTag == nsGkAtoms::altGlyph || 1.4991 + aTag == nsGkAtoms::a) { 1.4992 + return &sTSpanData; 1.4993 + } 1.4994 + return &sSuppressData; 1.4995 + } else if (aTag == nsGkAtoms::text) { 1.4996 + static const FrameConstructionData sTextData = 1.4997 + FCDATA_WITH_WRAPPING_BLOCK(FCDATA_DISALLOW_OUT_OF_FLOW | 1.4998 + FCDATA_ALLOW_BLOCK_STYLES, 1.4999 + NS_NewSVGTextFrame, 1.5000 + nsCSSAnonBoxes::mozSVGText); 1.5001 + return &sTextData; 1.5002 + } else if (aTag == nsGkAtoms::tspan || 1.5003 + aTag == nsGkAtoms::altGlyph || 1.5004 + aTag == nsGkAtoms::textPath) { 1.5005 + return &sSuppressData; 1.5006 + } 1.5007 + 1.5008 + static const FrameConstructionDataByTag sSVGData[] = { 1.5009 + SIMPLE_SVG_CREATE(svg, NS_NewSVGInnerSVGFrame), 1.5010 + SIMPLE_SVG_CREATE(g, NS_NewSVGGFrame), 1.5011 + SIMPLE_SVG_CREATE(svgSwitch, NS_NewSVGSwitchFrame), 1.5012 + SIMPLE_SVG_CREATE(polygon, NS_NewSVGPathGeometryFrame), 1.5013 + SIMPLE_SVG_CREATE(polyline, NS_NewSVGPathGeometryFrame), 1.5014 + SIMPLE_SVG_CREATE(circle, NS_NewSVGPathGeometryFrame), 1.5015 + SIMPLE_SVG_CREATE(ellipse, NS_NewSVGPathGeometryFrame), 1.5016 + SIMPLE_SVG_CREATE(line, NS_NewSVGPathGeometryFrame), 1.5017 + SIMPLE_SVG_CREATE(rect, NS_NewSVGPathGeometryFrame), 1.5018 + SIMPLE_SVG_CREATE(path, NS_NewSVGPathGeometryFrame), 1.5019 + SIMPLE_SVG_CREATE(defs, NS_NewSVGContainerFrame), 1.5020 + SIMPLE_SVG_CREATE(generic_, NS_NewSVGGenericContainerFrame), 1.5021 + { &nsGkAtoms::foreignObject, 1.5022 + FCDATA_WITH_WRAPPING_BLOCK(FCDATA_DISALLOW_OUT_OF_FLOW, 1.5023 + NS_NewSVGForeignObjectFrame, 1.5024 + nsCSSAnonBoxes::mozSVGForeignContent) }, 1.5025 + SIMPLE_SVG_CREATE(a, NS_NewSVGAFrame), 1.5026 + SIMPLE_SVG_CREATE(linearGradient, NS_NewSVGLinearGradientFrame), 1.5027 + SIMPLE_SVG_CREATE(radialGradient, NS_NewSVGRadialGradientFrame), 1.5028 + SIMPLE_SVG_CREATE(stop, NS_NewSVGStopFrame), 1.5029 + SIMPLE_SVG_CREATE(use, NS_NewSVGUseFrame), 1.5030 + SIMPLE_SVG_CREATE(view, NS_NewSVGViewFrame), 1.5031 + SIMPLE_SVG_CREATE(image, NS_NewSVGImageFrame), 1.5032 + SIMPLE_SVG_CREATE(clipPath, NS_NewSVGClipPathFrame), 1.5033 + SIMPLE_SVG_CREATE(filter, NS_NewSVGFilterFrame), 1.5034 + SIMPLE_SVG_CREATE(pattern, NS_NewSVGPatternFrame), 1.5035 + SIMPLE_SVG_CREATE(mask, NS_NewSVGMaskFrame), 1.5036 + SIMPLE_SVG_CREATE(feDistantLight, NS_NewSVGFEUnstyledLeafFrame), 1.5037 + SIMPLE_SVG_CREATE(fePointLight, NS_NewSVGFEUnstyledLeafFrame), 1.5038 + SIMPLE_SVG_CREATE(feSpotLight, NS_NewSVGFEUnstyledLeafFrame), 1.5039 + SIMPLE_SVG_CREATE(feBlend, NS_NewSVGFELeafFrame), 1.5040 + SIMPLE_SVG_CREATE(feColorMatrix, NS_NewSVGFELeafFrame), 1.5041 + SIMPLE_SVG_CREATE(feFuncR, NS_NewSVGFEUnstyledLeafFrame), 1.5042 + SIMPLE_SVG_CREATE(feFuncG, NS_NewSVGFEUnstyledLeafFrame), 1.5043 + SIMPLE_SVG_CREATE(feFuncB, NS_NewSVGFEUnstyledLeafFrame), 1.5044 + SIMPLE_SVG_CREATE(feFuncA, NS_NewSVGFEUnstyledLeafFrame), 1.5045 + SIMPLE_SVG_CREATE(feComposite, NS_NewSVGFELeafFrame), 1.5046 + SIMPLE_SVG_CREATE(feComponentTransfer, NS_NewSVGFEContainerFrame), 1.5047 + SIMPLE_SVG_CREATE(feConvolveMatrix, NS_NewSVGFELeafFrame), 1.5048 + SIMPLE_SVG_CREATE(feDiffuseLighting, NS_NewSVGFEContainerFrame), 1.5049 + SIMPLE_SVG_CREATE(feDisplacementMap, NS_NewSVGFELeafFrame), 1.5050 + SIMPLE_SVG_CREATE(feDropShadow, NS_NewSVGFELeafFrame), 1.5051 + SIMPLE_SVG_CREATE(feFlood, NS_NewSVGFELeafFrame), 1.5052 + SIMPLE_SVG_CREATE(feGaussianBlur, NS_NewSVGFELeafFrame), 1.5053 + SIMPLE_SVG_CREATE(feImage, NS_NewSVGFEImageFrame), 1.5054 + SIMPLE_SVG_CREATE(feMerge, NS_NewSVGFEContainerFrame), 1.5055 + SIMPLE_SVG_CREATE(feMergeNode, NS_NewSVGFEUnstyledLeafFrame), 1.5056 + SIMPLE_SVG_CREATE(feMorphology, NS_NewSVGFELeafFrame), 1.5057 + SIMPLE_SVG_CREATE(feOffset, NS_NewSVGFELeafFrame), 1.5058 + SIMPLE_SVG_CREATE(feSpecularLighting, NS_NewSVGFEContainerFrame), 1.5059 + SIMPLE_SVG_CREATE(feTile, NS_NewSVGFELeafFrame), 1.5060 + SIMPLE_SVG_CREATE(feTurbulence, NS_NewSVGFELeafFrame) 1.5061 + }; 1.5062 + 1.5063 + const FrameConstructionData* data = 1.5064 + FindDataByTag(aTag, aElement, aStyleContext, sSVGData, 1.5065 + ArrayLength(sSVGData)); 1.5066 + 1.5067 + if (!data) { 1.5068 + data = &sContainerData; 1.5069 + } 1.5070 + 1.5071 + return data; 1.5072 +} 1.5073 + 1.5074 +void 1.5075 +nsCSSFrameConstructor::AddPageBreakItem(nsIContent* aContent, 1.5076 + nsStyleContext* aMainStyleContext, 1.5077 + FrameConstructionItemList& aItems) 1.5078 +{ 1.5079 + // Use the same parent style context that |aMainStyleContext| has, since 1.5080 + // that's easier to re-resolve and it doesn't matter in practice. 1.5081 + // (Getting different parents can result in framechange hints, e.g., 1.5082 + // for user-modify.) 1.5083 + nsRefPtr<nsStyleContext> pseudoStyle = 1.5084 + mPresShell->StyleSet()-> 1.5085 + ResolveAnonymousBoxStyle(nsCSSAnonBoxes::pageBreak, 1.5086 + aMainStyleContext->GetParent()); 1.5087 + 1.5088 + NS_ASSERTION(pseudoStyle->StyleDisplay()->mDisplay == 1.5089 + NS_STYLE_DISPLAY_BLOCK, "Unexpected display"); 1.5090 + 1.5091 + static const FrameConstructionData sPageBreakData = 1.5092 + FCDATA_DECL(FCDATA_SKIP_FRAMESET, NS_NewPageBreakFrame); 1.5093 + 1.5094 + // Lie about the tag and namespace so we don't trigger anything 1.5095 + // interesting during frame construction. 1.5096 + aItems.AppendItem(&sPageBreakData, aContent, nsCSSAnonBoxes::pageBreak, 1.5097 + kNameSpaceID_None, nullptr, pseudoStyle.forget(), 1.5098 + true, nullptr); 1.5099 +} 1.5100 + 1.5101 +void 1.5102 +nsCSSFrameConstructor::AddFrameConstructionItems(nsFrameConstructorState& aState, 1.5103 + nsIContent* aContent, 1.5104 + bool aSuppressWhiteSpaceOptimizations, 1.5105 + nsIFrame* aParentFrame, 1.5106 + FrameConstructionItemList& aItems) 1.5107 +{ 1.5108 + aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME); 1.5109 + if (aContent->IsElement()) { 1.5110 + // We can't just remove our pending restyle flags, since we may 1.5111 + // have restyle-later-siblings set on us. But we _can_ remove the 1.5112 + // "is possible restyle root" flags, and need to. Otherwise we can 1.5113 + // end up with stale such flags (e.g. if we used to have a 1.5114 + // display:none parent when our last restyle was posted and 1.5115 + // processed and now no longer do). 1.5116 + aContent->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS & 1.5117 + ~ELEMENT_PENDING_RESTYLE_FLAGS); 1.5118 + } 1.5119 + 1.5120 + // XXX the GetContent() != aContent check is needed due to bug 135040. 1.5121 + // Remove it once that's fixed. 1.5122 + if (aContent->GetPrimaryFrame() && 1.5123 + aContent->GetPrimaryFrame()->GetContent() == aContent && 1.5124 + !aState.mCreatingExtraFrames) { 1.5125 + NS_ERROR("asked to create frame construction item for a node that already " 1.5126 + "has a frame"); 1.5127 + return; 1.5128 + } 1.5129 + 1.5130 + // don't create a whitespace frame if aParent doesn't want it 1.5131 + if (!NeedFrameFor(aState, aParentFrame, aContent)) { 1.5132 + return; 1.5133 + } 1.5134 + 1.5135 + // never create frames for comments or PIs 1.5136 + if (aContent->IsNodeOfType(nsINode::eCOMMENT) || 1.5137 + aContent->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) 1.5138 + return; 1.5139 + 1.5140 + nsRefPtr<nsStyleContext> styleContext; 1.5141 + styleContext = ResolveStyleContext(aParentFrame, aContent, &aState); 1.5142 + 1.5143 + uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK; 1.5144 + if (aParentFrame->IsSVGText()) { 1.5145 + flags |= ITEM_IS_WITHIN_SVG_TEXT; 1.5146 + } 1.5147 + if (aParentFrame->GetType() == nsGkAtoms::blockFrame && 1.5148 + aParentFrame->GetParent() && 1.5149 + aParentFrame->GetParent()->GetType() == nsGkAtoms::svgTextFrame) { 1.5150 + flags |= ITEM_ALLOWS_TEXT_PATH_CHILD; 1.5151 + } 1.5152 + AddFrameConstructionItemsInternal(aState, aContent, aParentFrame, 1.5153 + aContent->Tag(), aContent->GetNameSpaceID(), 1.5154 + aSuppressWhiteSpaceOptimizations, 1.5155 + styleContext, 1.5156 + flags, nullptr, 1.5157 + aItems); 1.5158 +} 1.5159 + 1.5160 +/* static */ void 1.5161 +nsCSSFrameConstructor::SetAsUndisplayedContent(FrameConstructionItemList& aList, 1.5162 + nsIContent* aContent, 1.5163 + nsStyleContext* aStyleContext, 1.5164 + bool aIsGeneratedContent) 1.5165 +{ 1.5166 + if (aStyleContext->GetPseudo()) { 1.5167 + if (aIsGeneratedContent) { 1.5168 + aContent->UnbindFromTree(); 1.5169 + } 1.5170 + return; 1.5171 + } 1.5172 + 1.5173 + NS_ASSERTION(!aIsGeneratedContent, "Should have had pseudo type"); 1.5174 + aList.AppendUndisplayedItem(aContent, aStyleContext); 1.5175 +} 1.5176 + 1.5177 +void 1.5178 +nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState& aState, 1.5179 + nsIContent* aContent, 1.5180 + nsIFrame* aParentFrame, 1.5181 + nsIAtom* aTag, 1.5182 + int32_t aNameSpaceID, 1.5183 + bool aSuppressWhiteSpaceOptimizations, 1.5184 + nsStyleContext* aStyleContext, 1.5185 + uint32_t aFlags, 1.5186 + nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren, 1.5187 + FrameConstructionItemList& aItems) 1.5188 +{ 1.5189 + NS_PRECONDITION(aContent->IsNodeOfType(nsINode::eTEXT) || 1.5190 + aContent->IsElement(), 1.5191 + "Shouldn't get anything else here!"); 1.5192 + 1.5193 + // The following code allows the user to specify the base tag 1.5194 + // of an element using XBL. XUL and HTML objects (like boxes, menus, etc.) 1.5195 + // can then be extended arbitrarily. 1.5196 + const nsStyleDisplay* display = aStyleContext->StyleDisplay(); 1.5197 + nsRefPtr<nsStyleContext> styleContext(aStyleContext); 1.5198 + PendingBinding* pendingBinding = nullptr; 1.5199 + if ((aFlags & ITEM_ALLOW_XBL_BASE) && display->mBinding) 1.5200 + { 1.5201 + // Ensure that our XBL bindings are installed. 1.5202 + 1.5203 + nsXBLService* xblService = nsXBLService::GetInstance(); 1.5204 + if (!xblService) 1.5205 + return; 1.5206 + 1.5207 + bool resolveStyle; 1.5208 + 1.5209 + nsAutoPtr<PendingBinding> newPendingBinding(new PendingBinding()); 1.5210 + 1.5211 + nsresult rv = xblService->LoadBindings(aContent, display->mBinding->GetURI(), 1.5212 + display->mBinding->mOriginPrincipal, 1.5213 + getter_AddRefs(newPendingBinding->mBinding), 1.5214 + &resolveStyle); 1.5215 + if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED) 1.5216 + return; 1.5217 + 1.5218 + if (newPendingBinding->mBinding) { 1.5219 + pendingBinding = newPendingBinding; 1.5220 + // aState takes over owning newPendingBinding 1.5221 + aState.AddPendingBinding(newPendingBinding.forget()); 1.5222 + } 1.5223 + 1.5224 + if (resolveStyle) { 1.5225 + styleContext = 1.5226 + ResolveStyleContext(styleContext->GetParent(), aContent, &aState); 1.5227 + display = styleContext->StyleDisplay(); 1.5228 + aStyleContext = styleContext; 1.5229 + } 1.5230 + 1.5231 + aTag = mDocument->BindingManager()->ResolveTag(aContent, &aNameSpaceID); 1.5232 + } 1.5233 + 1.5234 + bool isGeneratedContent = ((aFlags & ITEM_IS_GENERATED_CONTENT) != 0); 1.5235 + 1.5236 + // Pre-check for display "none" - if we find that, don't create 1.5237 + // any frame at all 1.5238 + if (NS_STYLE_DISPLAY_NONE == display->mDisplay) { 1.5239 + SetAsUndisplayedContent(aItems, aContent, styleContext, isGeneratedContent); 1.5240 + return; 1.5241 + } 1.5242 + 1.5243 + bool isText = !aContent->IsElement(); 1.5244 + 1.5245 + // never create frames for non-option/optgroup kids of <select> and 1.5246 + // non-option kids of <optgroup> inside a <select>. 1.5247 + // XXXbz it's not clear how this should best work with XBL. 1.5248 + nsIContent *parent = aContent->GetParent(); 1.5249 + if (parent) { 1.5250 + // Check tag first, since that check will usually fail 1.5251 + nsIAtom* parentTag = parent->Tag(); 1.5252 + if ((parentTag == nsGkAtoms::select || parentTag == nsGkAtoms::optgroup) && 1.5253 + parent->IsHTML() && 1.5254 + // <option> is ok no matter what 1.5255 + !aContent->IsHTML(nsGkAtoms::option) && 1.5256 + // <optgroup> is OK in <select> but not in <optgroup> 1.5257 + (!aContent->IsHTML(nsGkAtoms::optgroup) || 1.5258 + parentTag != nsGkAtoms::select) && 1.5259 + // Allow native anonymous content no matter what 1.5260 + !aContent->IsRootOfNativeAnonymousSubtree()) { 1.5261 + // No frame for aContent 1.5262 + if (!isText) { 1.5263 + SetAsUndisplayedContent(aItems, aContent, styleContext, 1.5264 + isGeneratedContent); 1.5265 + } 1.5266 + return; 1.5267 + } 1.5268 + } 1.5269 + 1.5270 + bool isPopup = false; 1.5271 + // Try to find frame construction data for this content 1.5272 + const FrameConstructionData* data; 1.5273 + if (isText) { 1.5274 + data = FindTextData(aParentFrame); 1.5275 + if (!data) { 1.5276 + // Nothing to do here; suppressed text inside SVG 1.5277 + return; 1.5278 + } 1.5279 + } else { 1.5280 + Element* element = aContent->AsElement(); 1.5281 + 1.5282 + // Don't create frames for non-SVG element children of SVG elements. 1.5283 + if (aNameSpaceID != kNameSpaceID_SVG && 1.5284 + ((aParentFrame && 1.5285 + IsFrameForSVG(aParentFrame) && 1.5286 + !aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)) || 1.5287 + (aFlags & ITEM_IS_WITHIN_SVG_TEXT))) { 1.5288 + SetAsUndisplayedContent(aItems, element, styleContext, 1.5289 + isGeneratedContent); 1.5290 + return; 1.5291 + } 1.5292 + 1.5293 + data = FindHTMLData(element, aTag, aNameSpaceID, aParentFrame, 1.5294 + styleContext); 1.5295 + if (!data) { 1.5296 + data = FindXULTagData(element, aTag, aNameSpaceID, styleContext); 1.5297 + } 1.5298 + if (!data) { 1.5299 + data = FindMathMLData(element, aTag, aNameSpaceID, styleContext); 1.5300 + } 1.5301 + if (!data) { 1.5302 + data = FindSVGData(element, aTag, aNameSpaceID, aParentFrame, 1.5303 + aFlags & ITEM_IS_WITHIN_SVG_TEXT, 1.5304 + aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD, 1.5305 + styleContext); 1.5306 + } 1.5307 + 1.5308 + // Now check for XUL display types 1.5309 + if (!data) { 1.5310 + data = FindXULDisplayData(display, element, styleContext); 1.5311 + } 1.5312 + 1.5313 + // And general display types 1.5314 + if (!data) { 1.5315 + data = FindDisplayData(display, element, aParentFrame, styleContext); 1.5316 + } 1.5317 + 1.5318 + NS_ASSERTION(data, "Should have frame construction data now"); 1.5319 + 1.5320 + if (data->mBits & FCDATA_SUPPRESS_FRAME) { 1.5321 + SetAsUndisplayedContent(aItems, element, styleContext, isGeneratedContent); 1.5322 + return; 1.5323 + } 1.5324 + 1.5325 +#ifdef MOZ_XUL 1.5326 + if ((data->mBits & FCDATA_IS_POPUP) && 1.5327 + (!aParentFrame || // Parent is inline 1.5328 + aParentFrame->GetType() != nsGkAtoms::menuFrame)) { 1.5329 + if (!aState.mPopupItems.containingBlock && 1.5330 + !aState.mHavePendingPopupgroup) { 1.5331 + SetAsUndisplayedContent(aItems, element, styleContext, 1.5332 + isGeneratedContent); 1.5333 + return; 1.5334 + } 1.5335 + 1.5336 + isPopup = true; 1.5337 + } 1.5338 +#endif /* MOZ_XUL */ 1.5339 + } 1.5340 + 1.5341 + uint32_t bits = data->mBits; 1.5342 + 1.5343 + // Inside colgroups, suppress everything except columns. 1.5344 + if (aParentFrame && 1.5345 + aParentFrame->GetType() == nsGkAtoms::tableColGroupFrame && 1.5346 + (!(bits & FCDATA_IS_TABLE_PART) || 1.5347 + display->mDisplay != NS_STYLE_DISPLAY_TABLE_COLUMN)) { 1.5348 + SetAsUndisplayedContent(aItems, aContent, styleContext, isGeneratedContent); 1.5349 + return; 1.5350 + } 1.5351 + 1.5352 + bool canHavePageBreak = 1.5353 + (aFlags & ITEM_ALLOW_PAGE_BREAK) && 1.5354 + aState.mPresContext->IsPaginated() && 1.5355 + !display->IsAbsolutelyPositionedStyle() && 1.5356 + !(bits & FCDATA_IS_TABLE_PART) && 1.5357 + !(bits & FCDATA_IS_SVG_TEXT); 1.5358 + 1.5359 + if (canHavePageBreak && display->mBreakBefore) { 1.5360 + AddPageBreakItem(aContent, aStyleContext, aItems); 1.5361 + } 1.5362 + 1.5363 + FrameConstructionItem* item = 1.5364 + aItems.AppendItem(data, aContent, aTag, aNameSpaceID, 1.5365 + pendingBinding, styleContext.forget(), 1.5366 + aSuppressWhiteSpaceOptimizations, aAnonChildren); 1.5367 + if (!item) { 1.5368 + if (isGeneratedContent) { 1.5369 + aContent->UnbindFromTree(); 1.5370 + } 1.5371 + return; 1.5372 + } 1.5373 + 1.5374 + item->mIsText = isText; 1.5375 + item->mIsGeneratedContent = isGeneratedContent; 1.5376 + item->mIsAnonymousContentCreatorContent = 1.5377 + aFlags & ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT; 1.5378 + if (isGeneratedContent) { 1.5379 + NS_ADDREF(item->mContent); 1.5380 + } 1.5381 + item->mIsRootPopupgroup = 1.5382 + aNameSpaceID == kNameSpaceID_XUL && aTag == nsGkAtoms::popupgroup && 1.5383 + aContent->IsRootOfNativeAnonymousSubtree(); 1.5384 + if (item->mIsRootPopupgroup) { 1.5385 + aState.mHavePendingPopupgroup = true; 1.5386 + } 1.5387 + item->mIsPopup = isPopup; 1.5388 + item->mIsForSVGAElement = aNameSpaceID == kNameSpaceID_SVG && 1.5389 + aTag == nsGkAtoms::a; 1.5390 + 1.5391 + if (canHavePageBreak && display->mBreakAfter) { 1.5392 + AddPageBreakItem(aContent, aStyleContext, aItems); 1.5393 + } 1.5394 + 1.5395 + if (bits & FCDATA_IS_INLINE) { 1.5396 + // To correctly set item->mIsAllInline we need to build up our child items 1.5397 + // right now. 1.5398 + BuildInlineChildItems(aState, *item, 1.5399 + aFlags & ITEM_IS_WITHIN_SVG_TEXT, 1.5400 + aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD); 1.5401 + item->mHasInlineEnds = true; 1.5402 + item->mIsBlock = false; 1.5403 + } else { 1.5404 + // Compute a boolean isInline which is guaranteed to be false for blocks 1.5405 + // (but may also be false for some inlines). 1.5406 + bool isInline = 1.5407 + // Table-internal things are inline-outside if and only if they're kids of 1.5408 + // inlines, since they'll trigger construction of inline-table 1.5409 + // pseudos. 1.5410 + ((bits & FCDATA_IS_TABLE_PART) && 1.5411 + (!aParentFrame || // No aParentFrame means inline 1.5412 + aParentFrame->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_INLINE)) || 1.5413 + // Things that are inline-outside but aren't inline frames are inline 1.5414 + display->IsInlineOutsideStyle() || 1.5415 + // Popups that are certainly out of flow. 1.5416 + isPopup; 1.5417 + 1.5418 + // Set mIsAllInline conservatively. It just might be that even an inline 1.5419 + // that has mIsAllInline false doesn't need an {ib} split. So this is just 1.5420 + // an optimization to keep from doing too much work in cases when we can 1.5421 + // show that mIsAllInline is true.. 1.5422 + item->mIsAllInline = item->mHasInlineEnds = isInline || 1.5423 + // Figure out whether we're guaranteed this item will be out of flow. 1.5424 + // This is not a precise test, since one of our ancestor inlines might add 1.5425 + // an absolute containing block (if it's relatively positioned) when there 1.5426 + // wasn't such a containing block before. But it's conservative in the 1.5427 + // sense that anything that will really end up as an in-flow non-inline 1.5428 + // will test false here. In other words, if this test is true we're 1.5429 + // guaranteed to be inline; if it's false we don't know what we'll end up 1.5430 + // as. 1.5431 + // 1.5432 + // If we make this test precise, we can remove some of the code dealing 1.5433 + // with the imprecision in ConstructInline and adjust the comments on 1.5434 + // mIsAllInline and mIsBlock in the header. And probably remove mIsBlock 1.5435 + // altogether, since then it will always be equal to !mHasInlineEnds. 1.5436 + (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW) && 1.5437 + aState.GetGeometricParent(display, nullptr)); 1.5438 + 1.5439 + // Set mIsBlock conservatively. It's OK to set it false for some real 1.5440 + // blocks, but not OK to set it true for things that aren't blocks. Since 1.5441 + // isOutOfFlow might be false even in cases when the frame will end up 1.5442 + // out-of-flow, we can't use it here. But we _can_ say that the frame will 1.5443 + // for sure end up in-flow if it's not floated or absolutely positioned. 1.5444 + item->mIsBlock = !isInline && 1.5445 + !display->IsAbsolutelyPositionedStyle() && 1.5446 + !display->IsFloatingStyle() && 1.5447 + !(bits & FCDATA_IS_SVG_TEXT); 1.5448 + } 1.5449 + 1.5450 + if (item->mIsAllInline) { 1.5451 + aItems.InlineItemAdded(); 1.5452 + } else if (item->mIsBlock) { 1.5453 + aItems.BlockItemAdded(); 1.5454 + } 1.5455 + 1.5456 + // Our item should be treated as a line participant if we have the relevant 1.5457 + // bit and are going to be in-flow. Note that this really only matters if 1.5458 + // our ancestor is a box or some such, so the fact that we might have an 1.5459 + // inline ancestor that might become a containing block is not relevant here. 1.5460 + if ((bits & FCDATA_IS_LINE_PARTICIPANT) && 1.5461 + ((bits & FCDATA_DISALLOW_OUT_OF_FLOW) || 1.5462 + !aState.GetGeometricParent(display, nullptr))) { 1.5463 + item->mIsLineParticipant = true; 1.5464 + aItems.LineParticipantItemAdded(); 1.5465 + } 1.5466 +} 1.5467 + 1.5468 +static void 1.5469 +DestroyContent(void* aPropertyValue) 1.5470 +{ 1.5471 + nsIContent* content = static_cast<nsIContent*>(aPropertyValue); 1.5472 + content->UnbindFromTree(); 1.5473 + NS_RELEASE(content); 1.5474 +} 1.5475 + 1.5476 +NS_DECLARE_FRAME_PROPERTY(BeforeProperty, DestroyContent) 1.5477 +NS_DECLARE_FRAME_PROPERTY(AfterProperty, DestroyContent) 1.5478 + 1.5479 +static const FramePropertyDescriptor* 1.5480 +GenConPseudoToProperty(nsIAtom* aPseudo) 1.5481 +{ 1.5482 + NS_ASSERTION(aPseudo == nsCSSPseudoElements::before || 1.5483 + aPseudo == nsCSSPseudoElements::after, 1.5484 + "Bad gen-con pseudo"); 1.5485 + return aPseudo == nsCSSPseudoElements::before ? BeforeProperty() 1.5486 + : AfterProperty(); 1.5487 +} 1.5488 + 1.5489 +/** 1.5490 + * Return true if the frame construction item pointed to by aIter will 1.5491 + * create a frame adjacent to a line boundary in the frame tree, and that 1.5492 + * line boundary is induced by a content node adjacent to the frame's 1.5493 + * content node in the content tree. The latter condition is necessary so 1.5494 + * that ContentAppended/ContentInserted/ContentRemoved can easily find any 1.5495 + * text nodes that were suppressed here. 1.5496 + */ 1.5497 +bool 1.5498 +nsCSSFrameConstructor::AtLineBoundary(FCItemIterator& aIter) 1.5499 +{ 1.5500 + if (aIter.item().mSuppressWhiteSpaceOptimizations) { 1.5501 + return false; 1.5502 + } 1.5503 + 1.5504 + if (aIter.AtStart()) { 1.5505 + if (aIter.List()->HasLineBoundaryAtStart() && 1.5506 + !aIter.item().mContent->GetPreviousSibling()) 1.5507 + return true; 1.5508 + } else { 1.5509 + FCItemIterator prev = aIter; 1.5510 + prev.Prev(); 1.5511 + if (prev.item().IsLineBoundary() && 1.5512 + !prev.item().mSuppressWhiteSpaceOptimizations && 1.5513 + aIter.item().mContent->GetPreviousSibling() == prev.item().mContent) 1.5514 + return true; 1.5515 + } 1.5516 + 1.5517 + FCItemIterator next = aIter; 1.5518 + next.Next(); 1.5519 + if (next.IsDone()) { 1.5520 + if (aIter.List()->HasLineBoundaryAtEnd() && 1.5521 + !aIter.item().mContent->GetNextSibling()) 1.5522 + return true; 1.5523 + } else { 1.5524 + if (next.item().IsLineBoundary() && 1.5525 + !next.item().mSuppressWhiteSpaceOptimizations && 1.5526 + aIter.item().mContent->GetNextSibling() == next.item().mContent) 1.5527 + return true; 1.5528 + } 1.5529 + 1.5530 + return false; 1.5531 +} 1.5532 + 1.5533 +void 1.5534 +nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState& aState, 1.5535 + FCItemIterator& aIter, 1.5536 + nsIFrame* aParentFrame, 1.5537 + nsFrameItems& aFrameItems) 1.5538 +{ 1.5539 + nsIFrame* adjParentFrame = aParentFrame; 1.5540 + FrameConstructionItem& item = aIter.item(); 1.5541 + nsStyleContext* styleContext = item.mStyleContext; 1.5542 + AdjustParentFrame(adjParentFrame, item.mFCData, styleContext); 1.5543 + 1.5544 + if (item.mIsText) { 1.5545 + // If this is collapsible whitespace next to a line boundary, 1.5546 + // don't create a frame. item.IsWhitespace() also sets the 1.5547 + // NS_CREATE_FRAME_IF_NON_WHITESPACE flag in the text node. (If we 1.5548 + // end up creating a frame, nsTextFrame::Init will clear the flag.) 1.5549 + // We don't do this for generated content, because some generated 1.5550 + // text content is empty text nodes that are about to be initialized. 1.5551 + // (We check mAdditionalStateBits because only the generated content 1.5552 + // container's frame construction item is marked with 1.5553 + // mIsGeneratedContent, and we might not have an aParentFrame.) 1.5554 + // We don't do it for content that may have XBL anonymous siblings, 1.5555 + // because they make it difficult to correctly create the frame 1.5556 + // due to dynamic changes. 1.5557 + // We don't do it for SVG text, since we might need to position and 1.5558 + // measure the white space glyphs due to x/y/dx/dy attributes. 1.5559 + if (AtLineBoundary(aIter) && 1.5560 + !styleContext->StyleText()->WhiteSpaceOrNewlineIsSignificant() && 1.5561 + aIter.List()->ParentHasNoXBLChildren() && 1.5562 + !(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) && 1.5563 + (item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) && 1.5564 + !(item.mFCData->mBits & FCDATA_IS_SVG_TEXT) && 1.5565 + !mAlwaysCreateFramesForIgnorableWhitespace && 1.5566 + item.IsWhitespace(aState)) 1.5567 + return; 1.5568 + 1.5569 + ConstructTextFrame(item.mFCData, aState, item.mContent, 1.5570 + adjParentFrame, styleContext, 1.5571 + aFrameItems); 1.5572 + return; 1.5573 + } 1.5574 + 1.5575 + // Start background loads during frame construction so that we're 1.5576 + // guaranteed that they will be started before onload fires. 1.5577 + styleContext->StartBackgroundImageLoads(); 1.5578 + 1.5579 + nsFrameState savedStateBits = aState.mAdditionalStateBits; 1.5580 + if (item.mIsGeneratedContent) { 1.5581 + // Ensure that frames created here are all tagged with 1.5582 + // NS_FRAME_GENERATED_CONTENT. 1.5583 + aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT; 1.5584 + 1.5585 + // Note that we're not necessarily setting this property on the primary 1.5586 + // frame for the content for which this is generated content. We might be 1.5587 + // setting it on a table pseudo-frame inserted under that instead. That's 1.5588 + // OK, though; we just need to do the property set so that the content will 1.5589 + // get cleaned up when the frame is destroyed. 1.5590 + aParentFrame->Properties().Set(GenConPseudoToProperty(styleContext->GetPseudo()), 1.5591 + item.mContent); 1.5592 + 1.5593 + // Now that we've passed ownership of item.mContent to the frame, unset 1.5594 + // our generated content flag so we don't release or unbind it ourselves. 1.5595 + item.mIsGeneratedContent = false; 1.5596 + } 1.5597 + 1.5598 + // XXXbz maybe just inline ConstructFrameFromItemInternal here or something? 1.5599 + ConstructFrameFromItemInternal(item, aState, adjParentFrame, aFrameItems); 1.5600 + 1.5601 + aState.mAdditionalStateBits = savedStateBits; 1.5602 +} 1.5603 + 1.5604 + 1.5605 +inline bool 1.5606 +IsRootBoxFrame(nsIFrame *aFrame) 1.5607 +{ 1.5608 + return (aFrame->GetType() == nsGkAtoms::rootFrame); 1.5609 +} 1.5610 + 1.5611 +nsresult 1.5612 +nsCSSFrameConstructor::ReconstructDocElementHierarchy() 1.5613 +{ 1.5614 + Element* rootElement = mDocument->GetRootElement(); 1.5615 + if (!rootElement) { 1.5616 + /* nothing to do */ 1.5617 + return NS_OK; 1.5618 + } 1.5619 + return RecreateFramesForContent(rootElement, false); 1.5620 +} 1.5621 + 1.5622 +nsIFrame* 1.5623 +nsCSSFrameConstructor::GetFrameFor(nsIContent* aContent) 1.5624 +{ 1.5625 + // Get the primary frame associated with the content 1.5626 + nsIFrame* frame = aContent->GetPrimaryFrame(); 1.5627 + 1.5628 + if (!frame) 1.5629 + return nullptr; 1.5630 + 1.5631 + // If the content of the frame is not the desired content then this is not 1.5632 + // really a frame for the desired content. 1.5633 + // XXX This check is needed due to bug 135040. Remove it once that's fixed. 1.5634 + if (frame->GetContent() != aContent) { 1.5635 + return nullptr; 1.5636 + } 1.5637 + 1.5638 + nsIFrame* insertionFrame = frame->GetContentInsertionFrame(); 1.5639 + 1.5640 + NS_ASSERTION(insertionFrame == frame || !frame->IsLeaf(), 1.5641 + "The insertion frame is the primary frame or the primary frame isn't a leaf"); 1.5642 + 1.5643 + return insertionFrame; 1.5644 +} 1.5645 + 1.5646 +nsIFrame* 1.5647 +nsCSSFrameConstructor::GetAbsoluteContainingBlock(nsIFrame* aFrame, 1.5648 + ContainingBlockType aType) 1.5649 +{ 1.5650 + NS_PRECONDITION(nullptr != mRootElementFrame, "no root element frame"); 1.5651 + 1.5652 + // Starting with aFrame, look for a frame that is absolutely positioned or 1.5653 + // relatively positioned (and transformed, if aType is FIXED) 1.5654 + for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) { 1.5655 + if (frame->IsFrameOfType(nsIFrame::eMathML)) { 1.5656 + // If it's mathml, bail out -- no absolute positioning out from inside 1.5657 + // mathml frames. Note that we don't make this part of the loop 1.5658 + // condition because of the stuff at the end of this method... 1.5659 + return nullptr; 1.5660 + } 1.5661 + 1.5662 + // If the frame is positioned, we will probably return it as the containing 1.5663 + // block (see the exceptions below). Otherwise, we'll start looking at the 1.5664 + // parent frame, unless we're dealing with a scrollframe. 1.5665 + // Scrollframes are special since they're not positioned, but their 1.5666 + // scrolledframe might be. So, we need to check this special case to return 1.5667 + // the correct containing block (the scrolledframe) in that case. 1.5668 + // If we're looking for a fixed-pos containing block and the frame is 1.5669 + // not transformed, skip it. 1.5670 + if (!frame->IsPositioned() || 1.5671 + (aType == FIXED_POS && 1.5672 + !frame->StyleDisplay()->HasTransform(frame) && 1.5673 + !frame->StyleDisplay()->HasPerspectiveStyle())) { 1.5674 + continue; 1.5675 + } 1.5676 + nsIFrame* absPosCBCandidate = frame; 1.5677 + nsIAtom* type = absPosCBCandidate->GetType(); 1.5678 + if (type == nsGkAtoms::fieldSetFrame) { 1.5679 + absPosCBCandidate = static_cast<nsFieldSetFrame*>(absPosCBCandidate)->GetInner(); 1.5680 + if (!absPosCBCandidate) { 1.5681 + continue; 1.5682 + } 1.5683 + type = absPosCBCandidate->GetType(); 1.5684 + } 1.5685 + if (type == nsGkAtoms::scrollFrame) { 1.5686 + nsIScrollableFrame* scrollFrame = do_QueryFrame(absPosCBCandidate); 1.5687 + absPosCBCandidate = scrollFrame->GetScrolledFrame(); 1.5688 + if (!absPosCBCandidate) { 1.5689 + continue; 1.5690 + } 1.5691 + type = absPosCBCandidate->GetType(); 1.5692 + } 1.5693 + // Only first continuations can be containing blocks. 1.5694 + absPosCBCandidate = absPosCBCandidate->FirstContinuation(); 1.5695 + // Is the frame really an absolute container? 1.5696 + if (!absPosCBCandidate->IsAbsoluteContainer()) { 1.5697 + continue; 1.5698 + } 1.5699 + 1.5700 + // For tables, skip the inner frame and consider the outer table frame. 1.5701 + if (type == nsGkAtoms::tableFrame) { 1.5702 + continue; 1.5703 + } 1.5704 + // For outer table frames, we can just return absPosCBCandidate. 1.5705 + return absPosCBCandidate; 1.5706 + } 1.5707 + 1.5708 + // It is possible for the search for the containing block to fail, because 1.5709 + // no absolute container can be found in the parent chain. In those cases, 1.5710 + // we fall back to the document element's containing block. 1.5711 + if (aType == FIXED_POS) { 1.5712 + return mFixedContainingBlock; 1.5713 + } 1.5714 + return mHasRootAbsPosContainingBlock ? mDocElementContainingBlock : nullptr; 1.5715 +} 1.5716 + 1.5717 +nsIFrame* 1.5718 +nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame) 1.5719 +{ 1.5720 + // Starting with aFrame, look for a frame that is a float containing block. 1.5721 + // IF we hit a mathml frame, bail out; we don't allow floating out of mathml 1.5722 + // frames, because they don't seem to be able to deal. 1.5723 + // The logic here needs to match the logic in ProcessChildren() 1.5724 + for (nsIFrame* containingBlock = aFrame; 1.5725 + containingBlock && 1.5726 + !ShouldSuppressFloatingOfDescendants(containingBlock); 1.5727 + containingBlock = containingBlock->GetParent()) { 1.5728 + if (containingBlock->IsFloatContainingBlock()) { 1.5729 + return containingBlock; 1.5730 + } 1.5731 + } 1.5732 + 1.5733 + // If we didn't find a containing block, then there just isn't 1.5734 + // one.... return null 1.5735 + return nullptr; 1.5736 +} 1.5737 + 1.5738 +/** 1.5739 + * This function will check whether aContainer has :after generated content. 1.5740 + * If so, appending to it should actually insert. The return value is the 1.5741 + * parent to use for newly-appended content. *aAfterFrame points to the :after 1.5742 + * frame before which appended content should go, if there is one. 1.5743 + */ 1.5744 +static nsIFrame* 1.5745 +AdjustAppendParentForAfterContent(nsPresContext* aPresContext, 1.5746 + nsIContent* aContainer, 1.5747 + nsIFrame* aParentFrame, 1.5748 + nsIFrame** aAfterFrame) 1.5749 +{ 1.5750 + // See if the parent has an :after pseudo-element. Check for the presence 1.5751 + // of style first, since nsLayoutUtils::GetAfterFrame is sorta expensive. 1.5752 + nsStyleContext* parentStyle = aParentFrame->StyleContext(); 1.5753 + if (nsLayoutUtils::HasPseudoStyle(aContainer, parentStyle, 1.5754 + nsCSSPseudoElements::ePseudo_after, 1.5755 + aPresContext)) { 1.5756 + // Ensure that the :after frame is on the principal child list. 1.5757 + aParentFrame->DrainSelfOverflowList(); 1.5758 + 1.5759 + nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(aParentFrame); 1.5760 + if (afterFrame) { 1.5761 + *aAfterFrame = afterFrame; 1.5762 + return afterFrame->GetParent(); 1.5763 + } 1.5764 + } 1.5765 + 1.5766 + *aAfterFrame = nullptr; 1.5767 + 1.5768 + if (IsFramePartOfIBSplit(aParentFrame)) { 1.5769 + // We might be in a situation where the last part of the {ib} split was 1.5770 + // empty. Since we have no ::after pseudo-element, we do in fact want to be 1.5771 + // appending to that last part, so advance to it if needed. Note that here 1.5772 + // aParentFrame is the result of a GetLastIBSplitSibling call, so must be 1.5773 + // either the last or next to last ib-split sibling. 1.5774 + nsIFrame* trailingInline = GetIBSplitSibling(aParentFrame); 1.5775 + if (trailingInline) { 1.5776 + aParentFrame = trailingInline; 1.5777 + } 1.5778 + 1.5779 + // Always make sure to look at the last continuation of the frame 1.5780 + // for the {ib} case, even if that continuation is empty. We 1.5781 + // don't do this for the non-ib-split-frame case, since in the 1.5782 + // other cases appending to the last nonempty continuation is fine 1.5783 + // and in fact not doing that can confuse code that doesn't know 1.5784 + // to pull kids from continuations other than its next one. 1.5785 + aParentFrame = aParentFrame->LastContinuation(); 1.5786 + } 1.5787 + 1.5788 + return aParentFrame; 1.5789 +} 1.5790 + 1.5791 +/** 1.5792 + * This function will get the previous sibling to use for an append operation. 1.5793 + * it takes a parent frame (must not be null) and its :after frame (may be 1.5794 + * null). 1.5795 + */ 1.5796 +static nsIFrame* 1.5797 +FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aAfterFrame) 1.5798 +{ 1.5799 + if (aAfterFrame) { 1.5800 + NS_ASSERTION(aAfterFrame->GetParent() == aParentFrame, "Wrong parent"); 1.5801 + NS_ASSERTION(aAfterFrame->GetPrevSibling() || 1.5802 + aParentFrame->GetFirstPrincipalChild() == aAfterFrame, 1.5803 + ":after frame must be on the principal child list here"); 1.5804 + return aAfterFrame->GetPrevSibling(); 1.5805 + } 1.5806 + 1.5807 + aParentFrame->DrainSelfOverflowList(); 1.5808 + 1.5809 + return aParentFrame->GetLastChild(kPrincipalList); 1.5810 +} 1.5811 + 1.5812 +/** 1.5813 + * This function will get the next sibling for a frame insert operation given 1.5814 + * the parent and previous sibling. aPrevSibling may be null. 1.5815 + */ 1.5816 +static nsIFrame* 1.5817 +GetInsertNextSibling(nsIFrame* aParentFrame, nsIFrame* aPrevSibling) 1.5818 +{ 1.5819 + if (aPrevSibling) { 1.5820 + return aPrevSibling->GetNextSibling(); 1.5821 + } 1.5822 + 1.5823 + return aParentFrame->GetFirstPrincipalChild(); 1.5824 +} 1.5825 + 1.5826 +/** 1.5827 + * This function is called by ContentAppended() and ContentInserted() when 1.5828 + * appending flowed frames to a parent's principal child list. It handles the 1.5829 + * case where the parent is the trailing inline of an {ib} split. 1.5830 + */ 1.5831 +nsresult 1.5832 +nsCSSFrameConstructor::AppendFramesToParent(nsFrameConstructorState& aState, 1.5833 + nsIFrame* aParentFrame, 1.5834 + nsFrameItems& aFrameList, 1.5835 + nsIFrame* aPrevSibling, 1.5836 + bool aIsRecursiveCall) 1.5837 +{ 1.5838 + NS_PRECONDITION(!IsFramePartOfIBSplit(aParentFrame) || 1.5839 + !GetIBSplitSibling(aParentFrame) || 1.5840 + !GetIBSplitSibling(aParentFrame)->GetFirstPrincipalChild(), 1.5841 + "aParentFrame has a ib-split sibling with kids?"); 1.5842 + NS_PRECONDITION(!aPrevSibling || aPrevSibling->GetParent() == aParentFrame, 1.5843 + "Parent and prevsibling don't match"); 1.5844 + 1.5845 + nsIFrame* nextSibling = ::GetInsertNextSibling(aParentFrame, aPrevSibling); 1.5846 + 1.5847 + NS_ASSERTION(nextSibling || 1.5848 + !aParentFrame->GetNextContinuation() || 1.5849 + !aParentFrame->GetNextContinuation()->GetFirstPrincipalChild() || 1.5850 + aIsRecursiveCall, 1.5851 + "aParentFrame has later continuations with kids?"); 1.5852 + NS_ASSERTION(nextSibling || 1.5853 + !IsFramePartOfIBSplit(aParentFrame) || 1.5854 + (IsInlineFrame(aParentFrame) && 1.5855 + !GetIBSplitSibling(aParentFrame) && 1.5856 + !aParentFrame->GetNextContinuation()) || 1.5857 + aIsRecursiveCall, 1.5858 + "aParentFrame is not last?"); 1.5859 + 1.5860 + // If we're inserting a list of frames at the end of the trailing inline 1.5861 + // of an {ib} split, we may need to create additional {ib} siblings to parent 1.5862 + // them. 1.5863 + if (!nextSibling && IsFramePartOfIBSplit(aParentFrame)) { 1.5864 + // When we get here, our frame list might start with a block. If it does 1.5865 + // so, and aParentFrame is an inline, and it and all its previous 1.5866 + // continuations have no siblings, then put the initial blocks from the 1.5867 + // frame list into the previous block of the {ib} split. Note that we 1.5868 + // didn't want to stop at the block part of the split when figuring out 1.5869 + // initial parent, because that could screw up float parenting; it's easier 1.5870 + // to do this little fixup here instead. 1.5871 + if (aFrameList.NotEmpty() && !aFrameList.FirstChild()->IsInlineOutside()) { 1.5872 + // See whether our trailing inline is empty 1.5873 + nsIFrame* firstContinuation = aParentFrame->FirstContinuation(); 1.5874 + if (firstContinuation->PrincipalChildList().IsEmpty()) { 1.5875 + // Our trailing inline is empty. Collect our starting blocks from 1.5876 + // aFrameList, get the right parent frame for them, and put them in. 1.5877 + nsFrameList::FrameLinkEnumerator firstNonBlockEnumerator = 1.5878 + FindFirstNonBlock(aFrameList); 1.5879 + nsFrameList blockKids = aFrameList.ExtractHead(firstNonBlockEnumerator); 1.5880 + NS_ASSERTION(blockKids.NotEmpty(), "No blocks?"); 1.5881 + 1.5882 + nsIFrame* prevBlock = 1.5883 + GetIBSplitPrevSibling(firstContinuation)->LastContinuation(); 1.5884 + NS_ASSERTION(prevBlock, "Should have previous block here"); 1.5885 + 1.5886 + MoveChildrenTo(aState.mPresContext, aParentFrame, prevBlock, blockKids); 1.5887 + } 1.5888 + } 1.5889 + 1.5890 + // We want to put some of the frames into this inline frame. 1.5891 + nsFrameList::FrameLinkEnumerator firstBlockEnumerator(aFrameList); 1.5892 + FindFirstBlock(firstBlockEnumerator); 1.5893 + 1.5894 + nsFrameList inlineKids = aFrameList.ExtractHead(firstBlockEnumerator); 1.5895 + if (!inlineKids.IsEmpty()) { 1.5896 + AppendFrames(aParentFrame, kPrincipalList, inlineKids); 1.5897 + } 1.5898 + 1.5899 + if (!aFrameList.IsEmpty()) { 1.5900 + bool positioned = aParentFrame->IsRelativelyPositioned(); 1.5901 + nsFrameItems ibSiblings; 1.5902 + CreateIBSiblings(aState, aParentFrame, positioned, aFrameList, 1.5903 + ibSiblings); 1.5904 + 1.5905 + // Make sure to trigger reflow of the inline that used to be our 1.5906 + // last one and now isn't anymore, since its GetSkipSides() has 1.5907 + // changed. 1.5908 + mPresShell->FrameNeedsReflow(aParentFrame, 1.5909 + nsIPresShell::eTreeChange, 1.5910 + NS_FRAME_HAS_DIRTY_CHILDREN); 1.5911 + 1.5912 + // Recurse so we create new ib siblings as needed for aParentFrame's parent 1.5913 + return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings, 1.5914 + aParentFrame, true); 1.5915 + } 1.5916 + 1.5917 + return NS_OK; 1.5918 + } 1.5919 + 1.5920 + // Insert the frames after our aPrevSibling 1.5921 + return InsertFrames(aParentFrame, kPrincipalList, aPrevSibling, aFrameList); 1.5922 +} 1.5923 + 1.5924 +#define UNSET_DISPLAY 255 1.5925 + 1.5926 +// This gets called to see if the frames corresponding to aSibling and aContent 1.5927 +// should be siblings in the frame tree. Although (1) rows and cols, (2) row 1.5928 +// groups and col groups, (3) row groups and captions, (4) legends and content 1.5929 +// inside fieldsets, (5) popups and other kids of the menu are siblings from a 1.5930 +// content perspective, they are not considered siblings in the frame tree. 1.5931 +bool 1.5932 +nsCSSFrameConstructor::IsValidSibling(nsIFrame* aSibling, 1.5933 + nsIContent* aContent, 1.5934 + uint8_t& aDisplay) 1.5935 +{ 1.5936 + nsIFrame* parentFrame = aSibling->GetParent(); 1.5937 + nsIAtom* parentType = nullptr; 1.5938 + if (parentFrame) { 1.5939 + parentType = parentFrame->GetType(); 1.5940 + } 1.5941 + 1.5942 + uint8_t siblingDisplay = aSibling->GetDisplay(); 1.5943 + if ((NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == siblingDisplay) || 1.5944 + (NS_STYLE_DISPLAY_TABLE_COLUMN == siblingDisplay) || 1.5945 + (NS_STYLE_DISPLAY_TABLE_CAPTION == siblingDisplay) || 1.5946 + (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == siblingDisplay) || 1.5947 + (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == siblingDisplay) || 1.5948 + (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == siblingDisplay) || 1.5949 + nsGkAtoms::menuFrame == parentType) { 1.5950 + // if we haven't already, construct a style context to find the display type of aContent 1.5951 + if (UNSET_DISPLAY == aDisplay) { 1.5952 + nsRefPtr<nsStyleContext> styleContext; 1.5953 + nsIFrame* styleParent = aSibling->GetParentStyleContextFrame(); 1.5954 + if (!styleParent) { 1.5955 + NS_NOTREACHED("Shouldn't happen"); 1.5956 + return false; 1.5957 + } 1.5958 + // XXXbz when this code is killed, the state argument to 1.5959 + // ResolveStyleContext can be made non-optional. 1.5960 + styleContext = ResolveStyleContext(styleParent, aContent, nullptr); 1.5961 + const nsStyleDisplay* display = styleContext->StyleDisplay(); 1.5962 + aDisplay = display->mDisplay; 1.5963 + } 1.5964 + if (nsGkAtoms::menuFrame == parentType) { 1.5965 + return 1.5966 + (NS_STYLE_DISPLAY_POPUP == aDisplay) == 1.5967 + (NS_STYLE_DISPLAY_POPUP == siblingDisplay); 1.5968 + } 1.5969 + // To have decent performance we want to return false in cases in which 1.5970 + // reordering the two siblings has no effect on display. To ensure 1.5971 + // correctness, we MUST return false in cases where the two siblings have 1.5972 + // the same desired parent type and live on different display lists. 1.5973 + // Specificaly, columns and column groups should only consider columns and 1.5974 + // column groups as valid siblings. Captions should only consider other 1.5975 + // captions. All other things should consider each other as valid 1.5976 + // siblings. The restriction in the |if| above on siblingDisplay is ok, 1.5977 + // because for correctness the only part that really needs to happen is to 1.5978 + // not consider captions, column groups, and row/header/footer groups 1.5979 + // siblings of each other. Treating a column or colgroup as a valid 1.5980 + // sibling of a non-table-related frame will just mean we end up reframing. 1.5981 + if ((siblingDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION) != 1.5982 + (aDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION)) { 1.5983 + // One's a caption and the other is not. Not valid siblings. 1.5984 + return false; 1.5985 + } 1.5986 + 1.5987 + if ((siblingDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP || 1.5988 + siblingDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN) != 1.5989 + (aDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP || 1.5990 + aDisplay == NS_STYLE_DISPLAY_TABLE_COLUMN)) { 1.5991 + // One's a column or column group and the other is not. Not valid 1.5992 + // siblings. 1.5993 + return false; 1.5994 + } 1.5995 + // Fall through; it's possible that the display type was overridden and 1.5996 + // a different sort of frame was constructed, so we may need to return false 1.5997 + // below. 1.5998 + } 1.5999 + 1.6000 + if (IsFrameForFieldSet(parentFrame, parentType)) { 1.6001 + // Legends can be sibling of legends but not of other content in the fieldset 1.6002 + nsIAtom* sibType = aSibling->GetContentInsertionFrame()->GetType(); 1.6003 + bool legendContent = aContent->IsHTML(nsGkAtoms::legend); 1.6004 + 1.6005 + if ((legendContent && (nsGkAtoms::legendFrame != sibType)) || 1.6006 + (!legendContent && (nsGkAtoms::legendFrame == sibType))) 1.6007 + return false; 1.6008 + } 1.6009 + 1.6010 + return true; 1.6011 +} 1.6012 + 1.6013 +nsIFrame* 1.6014 +nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent* aContent, 1.6015 + nsIContent* aTargetContent, 1.6016 + uint8_t& aTargetContentDisplay, 1.6017 + bool aPrevSibling) 1.6018 +{ 1.6019 + nsIFrame* sibling = aContent->GetPrimaryFrame(); 1.6020 + if (!sibling || sibling->GetContent() != aContent) { 1.6021 + // XXX the GetContent() != aContent check is needed due to bug 135040. 1.6022 + // Remove it once that's fixed. 1.6023 + return nullptr; 1.6024 + } 1.6025 + 1.6026 + // If the frame is out-of-flow, GetPrimaryFrame() will have returned the 1.6027 + // out-of-flow frame; we want the placeholder. 1.6028 + if (sibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { 1.6029 + nsIFrame* placeholderFrame = GetPlaceholderFrameFor(sibling); 1.6030 + NS_ASSERTION(placeholderFrame, "no placeholder for out-of-flow frame"); 1.6031 + sibling = placeholderFrame; 1.6032 + } 1.6033 + 1.6034 + // The frame we have now should never be a continuation 1.6035 + NS_ASSERTION(!sibling->GetPrevContinuation(), "How did that happen?"); 1.6036 + 1.6037 + if (aPrevSibling) { 1.6038 + // The frame may be a ib-split frame (a split inline frame that 1.6039 + // contains a block). Get the last part of that split. 1.6040 + if (IsFramePartOfIBSplit(sibling)) { 1.6041 + sibling = GetLastIBSplitSibling(sibling, true); 1.6042 + } 1.6043 + 1.6044 + // The frame may have a continuation. If so, we want the last 1.6045 + // non-overflow-container continuation as our previous sibling. 1.6046 + sibling = sibling->GetTailContinuation(); 1.6047 + } 1.6048 + 1.6049 + if (aTargetContent && 1.6050 + !IsValidSibling(sibling, aTargetContent, aTargetContentDisplay)) { 1.6051 + sibling = nullptr; 1.6052 + } 1.6053 + 1.6054 + return sibling; 1.6055 +} 1.6056 + 1.6057 +nsIFrame* 1.6058 +nsCSSFrameConstructor::FindPreviousSibling(FlattenedChildIterator aIter, 1.6059 + uint8_t& aTargetContentDisplay) 1.6060 +{ 1.6061 + nsIContent* child = aIter.Get(); 1.6062 + 1.6063 + // Note: not all content objects are associated with a frame (e.g., if it's 1.6064 + // `display: none') so keep looking until we find a previous frame 1.6065 + while (nsIContent* sibling = aIter.GetPreviousChild()) { 1.6066 + nsIFrame* prevSibling = 1.6067 + FindFrameForContentSibling(sibling, child, aTargetContentDisplay, true); 1.6068 + 1.6069 + if (prevSibling) { 1.6070 + // Found a previous sibling, we're done! 1.6071 + return prevSibling; 1.6072 + } 1.6073 + } 1.6074 + 1.6075 + return nullptr; 1.6076 +} 1.6077 + 1.6078 +nsIFrame* 1.6079 +nsCSSFrameConstructor::FindNextSibling(FlattenedChildIterator aIter, 1.6080 + uint8_t& aTargetContentDisplay) 1.6081 +{ 1.6082 + nsIContent* child = aIter.Get(); 1.6083 + 1.6084 + while (nsIContent* sibling = aIter.GetNextChild()) { 1.6085 + nsIFrame* nextSibling = 1.6086 + FindFrameForContentSibling(sibling, child, aTargetContentDisplay, false); 1.6087 + 1.6088 + if (nextSibling) { 1.6089 + // We found a next sibling, we're done! 1.6090 + return nextSibling; 1.6091 + } 1.6092 + } 1.6093 + 1.6094 + return nullptr; 1.6095 +} 1.6096 + 1.6097 +// For fieldsets, returns the area frame, if the child is not a legend. 1.6098 +static nsIFrame* 1.6099 +GetAdjustedParentFrame(nsIFrame* aParentFrame, 1.6100 + nsIAtom* aParentFrameType, 1.6101 + nsIContent* aChildContent) 1.6102 +{ 1.6103 + NS_PRECONDITION(nsGkAtoms::tableOuterFrame != aParentFrameType, 1.6104 + "Shouldn't be happening!"); 1.6105 + 1.6106 + nsIFrame* newParent = nullptr; 1.6107 + 1.6108 + if (nsGkAtoms::fieldSetFrame == aParentFrameType) { 1.6109 + // If the parent is a fieldSet, use the fieldSet's area frame as the 1.6110 + // parent unless the new content is a legend. 1.6111 + if (!aChildContent->IsHTML(nsGkAtoms::legend)) { 1.6112 + newParent = GetFieldSetBlockFrame(aParentFrame); 1.6113 + } 1.6114 + } 1.6115 + return (newParent) ? newParent : aParentFrame; 1.6116 +} 1.6117 + 1.6118 +nsIFrame* 1.6119 +nsCSSFrameConstructor::GetInsertionPrevSibling(nsIFrame*& aParentFrame, 1.6120 + nsIContent* aContainer, 1.6121 + nsIContent* aChild, 1.6122 + bool* aIsAppend, 1.6123 + bool* aIsRangeInsertSafe, 1.6124 + nsIContent* aStartSkipChild, 1.6125 + nsIContent* aEndSkipChild) 1.6126 +{ 1.6127 + *aIsAppend = false; 1.6128 + 1.6129 + // Find the frame that precedes the insertion point. Walk backwards 1.6130 + // from the parent frame to get the parent content, because if an 1.6131 + // XBL insertion point is involved, we'll need to use _that_ to find 1.6132 + // the preceding frame. 1.6133 + 1.6134 + NS_PRECONDITION(aParentFrame, "Must have parent frame to start with"); 1.6135 + nsIContent* container = aParentFrame->GetContent(); 1.6136 + 1.6137 + FlattenedChildIterator iter(container); 1.6138 + bool xblCase = iter.XBLInvolved() || container != aContainer; 1.6139 + if (xblCase || !aChild->IsRootOfAnonymousSubtree()) { 1.6140 + // The check for IsRootOfAnonymousSubtree() is because editor is 1.6141 + // severely broken and calls us directly for native anonymous 1.6142 + // nodes that it creates. 1.6143 + if (aStartSkipChild) { 1.6144 + iter.Seek(aStartSkipChild); 1.6145 + } else { 1.6146 + iter.Seek(aChild); 1.6147 + } 1.6148 + } else { 1.6149 + // Prime the iterator for the call to FindPreviousSibling. 1.6150 + iter.GetNextChild(); 1.6151 + NS_WARNING("Someone passed native anonymous content directly into frame " 1.6152 + "construction. Stop doing that!"); 1.6153 + } 1.6154 + 1.6155 + // Note that FindPreviousSibling is passed the iterator by value, so that 1.6156 + // the later usage of the iterator starts from the same place. 1.6157 + uint8_t childDisplay = UNSET_DISPLAY; 1.6158 + nsIFrame* prevSibling = FindPreviousSibling(iter, childDisplay); 1.6159 + 1.6160 + // Now, find the geometric parent so that we can handle 1.6161 + // continuations properly. Use the prev sibling if we have it; 1.6162 + // otherwise use the next sibling. 1.6163 + if (prevSibling) { 1.6164 + aParentFrame = prevSibling->GetParent()->GetContentInsertionFrame(); 1.6165 + } 1.6166 + else { 1.6167 + // If there is no previous sibling, then find the frame that follows 1.6168 + if (aEndSkipChild) { 1.6169 + iter.Seek(aEndSkipChild); 1.6170 + iter.GetPreviousChild(); 1.6171 + } 1.6172 + nsIFrame* nextSibling = FindNextSibling(iter, childDisplay); 1.6173 + 1.6174 + if (nextSibling) { 1.6175 + aParentFrame = nextSibling->GetParent()->GetContentInsertionFrame(); 1.6176 + } 1.6177 + else { 1.6178 + // No previous or next sibling, so treat this like an appended frame. 1.6179 + *aIsAppend = true; 1.6180 + if (IsFramePartOfIBSplit(aParentFrame)) { 1.6181 + // Since we're appending, we'll walk to the last anonymous frame 1.6182 + // that was created for the broken inline frame. But don't walk 1.6183 + // to the trailing inline if it's empty; stop at the block. 1.6184 + aParentFrame = GetLastIBSplitSibling(aParentFrame, false); 1.6185 + } 1.6186 + // Get continuation that parents the last child. This MUST be done 1.6187 + // before the AdjustAppendParentForAfterContent call. 1.6188 + aParentFrame = nsLayoutUtils::LastContinuationWithChild(aParentFrame); 1.6189 + // Deal with fieldsets 1.6190 + aParentFrame = ::GetAdjustedParentFrame(aParentFrame, 1.6191 + aParentFrame->GetType(), 1.6192 + aChild); 1.6193 + nsIFrame* appendAfterFrame; 1.6194 + aParentFrame = 1.6195 + ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(), 1.6196 + container, aParentFrame, 1.6197 + &appendAfterFrame); 1.6198 + prevSibling = ::FindAppendPrevSibling(aParentFrame, appendAfterFrame); 1.6199 + } 1.6200 + } 1.6201 + 1.6202 + *aIsRangeInsertSafe = (childDisplay == UNSET_DISPLAY); 1.6203 + return prevSibling; 1.6204 +} 1.6205 + 1.6206 +static bool 1.6207 +IsSpecialFramesetChild(nsIContent* aContent) 1.6208 +{ 1.6209 + // IMPORTANT: This must match the conditions in nsHTMLFramesetFrame::Init. 1.6210 + return aContent->IsHTML() && 1.6211 + (aContent->Tag() == nsGkAtoms::frameset || 1.6212 + aContent->Tag() == nsGkAtoms::frame); 1.6213 +} 1.6214 + 1.6215 +static void 1.6216 +InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node); 1.6217 + 1.6218 +#ifdef MOZ_XUL 1.6219 + 1.6220 +static 1.6221 +bool 1.6222 +IsXULListBox(nsIContent* aContainer) 1.6223 +{ 1.6224 + return (aContainer->IsXUL() && aContainer->Tag() == nsGkAtoms::listbox); 1.6225 +} 1.6226 + 1.6227 +static 1.6228 +nsListBoxBodyFrame* 1.6229 +MaybeGetListBoxBodyFrame(nsIContent* aContainer, nsIContent* aChild) 1.6230 +{ 1.6231 + if (!aContainer) 1.6232 + return nullptr; 1.6233 + 1.6234 + if (IsXULListBox(aContainer) && 1.6235 + aChild->IsXUL() && aChild->Tag() == nsGkAtoms::listitem) { 1.6236 + nsCOMPtr<nsIDOMXULElement> xulElement = do_QueryInterface(aContainer); 1.6237 + nsCOMPtr<nsIBoxObject> boxObject; 1.6238 + xulElement->GetBoxObject(getter_AddRefs(boxObject)); 1.6239 + nsCOMPtr<nsPIListBoxObject> listBoxObject = do_QueryInterface(boxObject); 1.6240 + if (listBoxObject) { 1.6241 + return listBoxObject->GetListBoxBody(false); 1.6242 + } 1.6243 + } 1.6244 + 1.6245 + return nullptr; 1.6246 +} 1.6247 +#endif 1.6248 + 1.6249 +void 1.6250 +nsCSSFrameConstructor::AddTextItemIfNeeded(nsFrameConstructorState& aState, 1.6251 + nsIFrame* aParentFrame, 1.6252 + nsIContent* aPossibleTextContent, 1.6253 + FrameConstructionItemList& aItems) 1.6254 +{ 1.6255 + NS_PRECONDITION(aPossibleTextContent, "Must have node"); 1.6256 + if (!aPossibleTextContent->IsNodeOfType(nsINode::eTEXT) || 1.6257 + !aPossibleTextContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) { 1.6258 + // Not text, or not suppressed due to being all-whitespace (if it 1.6259 + // were being suppressed, it would have the 1.6260 + // NS_CREATE_FRAME_IF_NON_WHITESPACE flag) 1.6261 + return; 1.6262 + } 1.6263 + NS_ASSERTION(!aPossibleTextContent->GetPrimaryFrame(), 1.6264 + "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"); 1.6265 + AddFrameConstructionItems(aState, aPossibleTextContent, false, 1.6266 + aParentFrame, aItems); 1.6267 +} 1.6268 + 1.6269 +void 1.6270 +nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aParentContent, 1.6271 + nsIContent* aContent) 1.6272 +{ 1.6273 + if (!aContent->IsNodeOfType(nsINode::eTEXT) || 1.6274 + !aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE)) { 1.6275 + // Not text, or not suppressed due to being all-whitespace (if it 1.6276 + // were being suppressed, it would have the 1.6277 + // NS_CREATE_FRAME_IF_NON_WHITESPACE flag) 1.6278 + return; 1.6279 + } 1.6280 + NS_ASSERTION(!aContent->GetPrimaryFrame(), 1.6281 + "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE"); 1.6282 + ContentInserted(aParentContent, aContent, nullptr, false); 1.6283 +} 1.6284 + 1.6285 +// For inserts aChild should be valid, for appends it should be null. 1.6286 +// Returns true if this operation can be lazy, false if not. 1.6287 +bool 1.6288 +nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation, 1.6289 + nsIContent* aContainer, 1.6290 + nsIContent* aChild) 1.6291 +{ 1.6292 + if (mPresShell->GetPresContext()->IsChrome() || !aContainer || 1.6293 + aContainer->IsInNativeAnonymousSubtree() || aContainer->IsXUL()) { 1.6294 + return false; 1.6295 + } 1.6296 + 1.6297 + if (aOperation == CONTENTINSERT) { 1.6298 + if (aChild->IsRootOfAnonymousSubtree() || 1.6299 + aChild->HasFlag(NODE_IS_IN_SHADOW_TREE) || 1.6300 + aChild->IsEditable() || aChild->IsXUL()) { 1.6301 + return false; 1.6302 + } 1.6303 + } else { // CONTENTAPPEND 1.6304 + NS_ASSERTION(aOperation == CONTENTAPPEND, 1.6305 + "operation should be either insert or append"); 1.6306 + for (nsIContent* child = aChild; child; child = child->GetNextSibling()) { 1.6307 + NS_ASSERTION(!child->IsRootOfAnonymousSubtree(), 1.6308 + "Should be coming through the CONTENTAPPEND case"); 1.6309 + if (child->IsXUL() || child->IsEditable()) { 1.6310 + return false; 1.6311 + } 1.6312 + } 1.6313 + } 1.6314 + 1.6315 + // We can construct lazily; just need to set suitable bits in the content 1.6316 + // tree. 1.6317 + 1.6318 + // Walk up the tree setting the NODE_DESCENDANTS_NEED_FRAMES bit as we go. 1.6319 + nsIContent* content = aContainer; 1.6320 +#ifdef DEBUG 1.6321 + // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set 1.6322 + // we want to assert, but leaf frames that process their own children and may 1.6323 + // ignore anonymous children (eg framesets) make this complicated. So we set 1.6324 + // these two booleans if we encounter these situations and unset them if we 1.6325 + // hit a node with a leaf frame. 1.6326 + bool noPrimaryFrame = false; 1.6327 + bool needsFrameBitSet = false; 1.6328 +#endif 1.6329 + while (content && 1.6330 + !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) { 1.6331 +#ifdef DEBUG 1.6332 + if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) { 1.6333 + noPrimaryFrame = needsFrameBitSet = false; 1.6334 + } 1.6335 + if (!noPrimaryFrame && !content->GetPrimaryFrame()) { 1.6336 + noPrimaryFrame = true; 1.6337 + } 1.6338 + if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) { 1.6339 + needsFrameBitSet = true; 1.6340 + } 1.6341 +#endif 1.6342 + content->SetFlags(NODE_DESCENDANTS_NEED_FRAMES); 1.6343 + content = content->GetFlattenedTreeParent(); 1.6344 + } 1.6345 +#ifdef DEBUG 1.6346 + if (content && content->GetPrimaryFrame() && 1.6347 + content->GetPrimaryFrame()->IsLeaf()) { 1.6348 + noPrimaryFrame = needsFrameBitSet = false; 1.6349 + } 1.6350 + NS_ASSERTION(!noPrimaryFrame, "Ancestors of nodes with frames to be " 1.6351 + "constructed lazily should have frames"); 1.6352 + NS_ASSERTION(!needsFrameBitSet, "Ancestors of nodes with frames to be " 1.6353 + "constructed lazily should not have NEEDS_FRAME bit set"); 1.6354 +#endif 1.6355 + 1.6356 + // Set NODE_NEEDS_FRAME on the new nodes. 1.6357 + if (aOperation == CONTENTINSERT) { 1.6358 + NS_ASSERTION(!aChild->GetPrimaryFrame() || 1.6359 + aChild->GetPrimaryFrame()->GetContent() != aChild, 1.6360 + //XXX the aChild->GetPrimaryFrame()->GetContent() != aChild 1.6361 + // check is needed due to bug 135040. Remove it once that's 1.6362 + // fixed. 1.6363 + "setting NEEDS_FRAME on a node that already has a frame?"); 1.6364 + aChild->SetFlags(NODE_NEEDS_FRAME); 1.6365 + } else { // CONTENTAPPEND 1.6366 + for (nsIContent* child = aChild; child; child = child->GetNextSibling()) { 1.6367 + NS_ASSERTION(!child->GetPrimaryFrame() || 1.6368 + child->GetPrimaryFrame()->GetContent() != child, 1.6369 + //XXX the child->GetPrimaryFrame()->GetContent() != child 1.6370 + // check is needed due to bug 135040. Remove it once that's 1.6371 + // fixed. 1.6372 + "setting NEEDS_FRAME on a node that already has a frame?"); 1.6373 + child->SetFlags(NODE_NEEDS_FRAME); 1.6374 + } 1.6375 + } 1.6376 + 1.6377 + RestyleManager()->PostRestyleEventForLazyConstruction(); 1.6378 + return true; 1.6379 +} 1.6380 + 1.6381 +void 1.6382 +nsCSSFrameConstructor::CreateNeededFrames(nsIContent* aContent) 1.6383 +{ 1.6384 + NS_ASSERTION(!aContent->HasFlag(NODE_NEEDS_FRAME), 1.6385 + "shouldn't get here with a content node that has needs frame bit set"); 1.6386 + NS_ASSERTION(aContent->HasFlag(NODE_DESCENDANTS_NEED_FRAMES), 1.6387 + "should only get here with a content node that has descendants needing frames"); 1.6388 + 1.6389 + aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES); 1.6390 + 1.6391 + // We could either descend first (on nodes that don't have NODE_NEEDS_FRAME 1.6392 + // set) or issue content notifications for our kids first. In absence of 1.6393 + // anything definitive either way we'll go with the latter. 1.6394 + 1.6395 + // It might be better to use GetChildArray and scan it completely first and 1.6396 + // then issue all notifications. (We have to scan it completely first because 1.6397 + // constructing frames can set attributes, which can change the storage of 1.6398 + // child lists). 1.6399 + 1.6400 + // Scan the children of aContent to see what operations (if any) we need to 1.6401 + // perform. 1.6402 + uint32_t childCount = aContent->GetChildCount(); 1.6403 + bool inRun = false; 1.6404 + nsIContent* firstChildInRun = nullptr; 1.6405 + for (uint32_t i = 0; i < childCount; i++) { 1.6406 + nsIContent* child = aContent->GetChildAt(i); 1.6407 + if (child->HasFlag(NODE_NEEDS_FRAME)) { 1.6408 + NS_ASSERTION(!child->GetPrimaryFrame() || 1.6409 + child->GetPrimaryFrame()->GetContent() != child, 1.6410 + //XXX the child->GetPrimaryFrame()->GetContent() != child 1.6411 + // check is needed due to bug 135040. Remove it once that's 1.6412 + // fixed. 1.6413 + "NEEDS_FRAME set on a node that already has a frame?"); 1.6414 + if (!inRun) { 1.6415 + inRun = true; 1.6416 + firstChildInRun = child; 1.6417 + } 1.6418 + } else { 1.6419 + if (inRun) { 1.6420 + inRun = false; 1.6421 + // generate a ContentRangeInserted for [startOfRun,i) 1.6422 + ContentRangeInserted(aContent, firstChildInRun, child, nullptr, 1.6423 + false); 1.6424 + } 1.6425 + } 1.6426 + } 1.6427 + if (inRun) { 1.6428 + ContentAppended(aContent, firstChildInRun, false); 1.6429 + } 1.6430 + 1.6431 + // Now descend. 1.6432 + FlattenedChildIterator iter(aContent); 1.6433 + for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { 1.6434 + if (child->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) { 1.6435 + CreateNeededFrames(child); 1.6436 + } 1.6437 + } 1.6438 +} 1.6439 + 1.6440 +void nsCSSFrameConstructor::CreateNeededFrames() 1.6441 +{ 1.6442 + NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), 1.6443 + "Someone forgot a script blocker"); 1.6444 + 1.6445 + Element* rootElement = mDocument->GetRootElement(); 1.6446 + NS_ASSERTION(!rootElement || !rootElement->HasFlag(NODE_NEEDS_FRAME), 1.6447 + "root element should not have frame created lazily"); 1.6448 + if (rootElement && rootElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) { 1.6449 + BeginUpdate(); 1.6450 + CreateNeededFrames(rootElement); 1.6451 + EndUpdate(); 1.6452 + } 1.6453 +} 1.6454 + 1.6455 +void 1.6456 +nsCSSFrameConstructor::IssueSingleInsertNofications(nsIContent* aContainer, 1.6457 + nsIContent* aStartChild, 1.6458 + nsIContent* aEndChild, 1.6459 + bool aAllowLazyConstruction) 1.6460 +{ 1.6461 + for (nsIContent* child = aStartChild; 1.6462 + child != aEndChild; 1.6463 + child = child->GetNextSibling()) { 1.6464 + if ((child->GetPrimaryFrame() || 1.6465 + GetUndisplayedContent(child)) 1.6466 +#ifdef MOZ_XUL 1.6467 + // Except listboxes suck, so do NOT skip anything here if 1.6468 + // we plan to notify a listbox. 1.6469 + && !MaybeGetListBoxBodyFrame(aContainer, child) 1.6470 +#endif 1.6471 + ) { 1.6472 + // Already have a frame or undisplayed entry for this content; a 1.6473 + // previous ContentInserted in this loop must have reconstructed 1.6474 + // its insertion parent. Skip it. 1.6475 + continue; 1.6476 + } 1.6477 + // Call ContentInserted with this node. 1.6478 + ContentInserted(aContainer, child, mTempFrameTreeState, 1.6479 + aAllowLazyConstruction); 1.6480 + } 1.6481 +} 1.6482 + 1.6483 +nsIFrame* 1.6484 +nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent* aContainer, 1.6485 + nsIContent* aStartChild, 1.6486 + nsIContent* aEndChild, 1.6487 + bool aAllowLazyConstruction) 1.6488 +{ 1.6489 + // See if we have an XBL insertion point. If so, then that's our 1.6490 + // real parent frame; if not, then the frame hasn't been built yet 1.6491 + // and we just bail. 1.6492 + bool multiple = false; 1.6493 + nsIFrame* insertionPoint = GetInsertionPoint(aContainer, nullptr, &multiple); 1.6494 + if (!insertionPoint && !multiple) 1.6495 + return nullptr; // Don't build the frames. 1.6496 + 1.6497 + bool hasInsertion = false; 1.6498 + if (!multiple) { 1.6499 + // XXXbz XBL2/sXBL issue 1.6500 + nsIDocument* document = aStartChild->GetDocument(); 1.6501 + // XXXbz how would |document| be null here? 1.6502 + if (document && aStartChild->GetXBLInsertionParent()) { 1.6503 + hasInsertion = true; 1.6504 + } 1.6505 + } 1.6506 + 1.6507 + if (multiple || hasInsertion) { 1.6508 + // We have an insertion point. There are some additional tests we need to do 1.6509 + // in order to ensure that an append is a safe operation. 1.6510 + uint32_t childCount = 0; 1.6511 + 1.6512 + if (!multiple) { 1.6513 + // We may need to make multiple ContentInserted calls instead. A 1.6514 + // reasonable heuristic to employ (in order to maintain good performance) 1.6515 + // is to find out if the insertion point's content node contains any 1.6516 + // explicit children. If it does not, then it is highly likely that 1.6517 + // an append is occurring. (Note it is not definite, and there are insane 1.6518 + // cases we will not deal with by employing this heuristic, but it beats 1.6519 + // always falling back to multiple ContentInserted calls). 1.6520 + // 1.6521 + // In the multiple insertion point case, we know we're going to need to do 1.6522 + // multiple ContentInserted calls anyway. 1.6523 + // XXXndeakin This test doesn't work in the new world. Or rather, it works, but 1.6524 + // it's slow 1.6525 + childCount = insertionPoint->GetContent()->GetChildCount(); 1.6526 + } 1.6527 + 1.6528 + // If we have multiple insertion points or if we have an insertion point 1.6529 + // and the operation is not a true append or if the insertion point already 1.6530 + // has explicit children, then we must fall back. 1.6531 + if (multiple || aEndChild != nullptr || childCount > 0) { 1.6532 + // Now comes the fun part. For each inserted child, make a 1.6533 + // ContentInserted call as if it had just gotten inserted and 1.6534 + // let ContentInserted handle the mess. 1.6535 + IssueSingleInsertNofications(aContainer, aStartChild, aEndChild, 1.6536 + aAllowLazyConstruction); 1.6537 + return nullptr; 1.6538 + } 1.6539 + } 1.6540 + 1.6541 + return insertionPoint; 1.6542 +} 1.6543 + 1.6544 +bool 1.6545 +nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame, 1.6546 + nsIContent* aStartChild, 1.6547 + nsIContent* aEndChild) 1.6548 +{ 1.6549 + if (aParentFrame->GetType() == nsGkAtoms::frameSetFrame) { 1.6550 + // Check whether we have any kids we care about. 1.6551 + for (nsIContent* cur = aStartChild; 1.6552 + cur != aEndChild; 1.6553 + cur = cur->GetNextSibling()) { 1.6554 + if (IsSpecialFramesetChild(cur)) { 1.6555 + // Just reframe the parent, since framesets are weird like that. 1.6556 + RecreateFramesForContent(aParentFrame->GetContent(), false); 1.6557 + return true; 1.6558 + } 1.6559 + } 1.6560 + } 1.6561 + return false; 1.6562 +} 1.6563 + 1.6564 +nsresult 1.6565 +nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, 1.6566 + nsIContent* aFirstNewContent, 1.6567 + bool aAllowLazyConstruction) 1.6568 +{ 1.6569 + AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC); 1.6570 + NS_PRECONDITION(mUpdateCount != 0, 1.6571 + "Should be in an update while creating frames"); 1.6572 + 1.6573 +#ifdef DEBUG 1.6574 + if (gNoisyContentUpdates) { 1.6575 + printf("nsCSSFrameConstructor::ContentAppended container=%p " 1.6576 + "first-child=%p lazy=%d\n", 1.6577 + static_cast<void*>(aContainer), aFirstNewContent, 1.6578 + aAllowLazyConstruction); 1.6579 + if (gReallyNoisyContentUpdates && aContainer) { 1.6580 + aContainer->List(stdout, 0); 1.6581 + } 1.6582 + } 1.6583 +#endif 1.6584 + 1.6585 +#ifdef DEBUG 1.6586 + for (nsIContent* child = aFirstNewContent; 1.6587 + child; 1.6588 + child = child->GetNextSibling()) { 1.6589 + // XXX the GetContent() != child check is needed due to bug 135040. 1.6590 + // Remove it once that's fixed. 1.6591 + NS_ASSERTION(!child->GetPrimaryFrame() || 1.6592 + child->GetPrimaryFrame()->GetContent() != child, 1.6593 + "asked to construct a frame for a node that already has a frame"); 1.6594 + } 1.6595 +#endif 1.6596 + 1.6597 +#ifdef MOZ_XUL 1.6598 + if (aContainer) { 1.6599 + int32_t namespaceID; 1.6600 + nsIAtom* tag = 1.6601 + mDocument->BindingManager()->ResolveTag(aContainer, &namespaceID); 1.6602 + 1.6603 + // Just ignore tree tags, anyway we don't create any frames for them. 1.6604 + if (tag == nsGkAtoms::treechildren || 1.6605 + tag == nsGkAtoms::treeitem || 1.6606 + tag == nsGkAtoms::treerow) 1.6607 + return NS_OK; 1.6608 + 1.6609 + } 1.6610 +#endif // MOZ_XUL 1.6611 + 1.6612 + if (aContainer && aContainer->HasFlag(NODE_IS_IN_SHADOW_TREE)) { 1.6613 + // Recreate frames if content is appended into a ShadowRoot 1.6614 + // because children of ShadowRoot are rendered in place of children 1.6615 + // of the host. 1.6616 + nsIContent* bindingParent = aContainer->GetBindingParent(); 1.6617 + LAYOUT_PHASE_TEMP_EXIT(); 1.6618 + nsresult rv = RecreateFramesForContent(bindingParent, false); 1.6619 + LAYOUT_PHASE_TEMP_REENTER(); 1.6620 + return rv; 1.6621 + } 1.6622 + 1.6623 + // Get the frame associated with the content 1.6624 + nsIFrame* parentFrame = GetFrameFor(aContainer); 1.6625 + 1.6626 + // See comment in ContentRangeInserted for why this is necessary. 1.6627 + if (!parentFrame && !aContainer->IsActiveChildrenElement()) { 1.6628 + return NS_OK; 1.6629 + } 1.6630 + 1.6631 + if (aAllowLazyConstruction && 1.6632 + MaybeConstructLazily(CONTENTAPPEND, aContainer, aFirstNewContent)) { 1.6633 + return NS_OK; 1.6634 + } 1.6635 + 1.6636 + LAYOUT_PHASE_TEMP_EXIT(); 1.6637 + parentFrame = GetRangeInsertionPoint(aContainer, 1.6638 + aFirstNewContent, nullptr, 1.6639 + aAllowLazyConstruction); 1.6640 + LAYOUT_PHASE_TEMP_REENTER(); 1.6641 + if (!parentFrame) { 1.6642 + return NS_OK; 1.6643 + } 1.6644 + 1.6645 + LAYOUT_PHASE_TEMP_EXIT(); 1.6646 + if (MaybeRecreateForFrameset(parentFrame, aFirstNewContent, nullptr)) { 1.6647 + LAYOUT_PHASE_TEMP_REENTER(); 1.6648 + return NS_OK; 1.6649 + } 1.6650 + LAYOUT_PHASE_TEMP_REENTER(); 1.6651 + 1.6652 + if (parentFrame->IsLeaf()) { 1.6653 + // Nothing to do here; we shouldn't be constructing kids of leaves 1.6654 + // Clear lazy bits so we don't try to construct again. 1.6655 + ClearLazyBits(aFirstNewContent, nullptr); 1.6656 + return NS_OK; 1.6657 + } 1.6658 + 1.6659 + if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) { 1.6660 + LAYOUT_PHASE_TEMP_EXIT(); 1.6661 + nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false); 1.6662 + LAYOUT_PHASE_TEMP_REENTER(); 1.6663 + return rv; 1.6664 + } 1.6665 + 1.6666 + // If the frame we are manipulating is a ib-split frame (that is, one 1.6667 + // that's been created as a result of a block-in-inline situation) then we 1.6668 + // need to append to the last ib-split sibling, not to the frame itself. 1.6669 + bool parentIBSplit = IsFramePartOfIBSplit(parentFrame); 1.6670 + if (parentIBSplit) { 1.6671 +#ifdef DEBUG 1.6672 + if (gNoisyContentUpdates) { 1.6673 + printf("nsCSSFrameConstructor::ContentAppended: parentFrame="); 1.6674 + nsFrame::ListTag(stdout, parentFrame); 1.6675 + printf(" is ib-split\n"); 1.6676 + } 1.6677 +#endif 1.6678 + 1.6679 + // Since we're appending, we'll walk to the last anonymous frame 1.6680 + // that was created for the broken inline frame. But don't walk 1.6681 + // to the trailing inline if it's empty; stop at the block. 1.6682 + parentFrame = GetLastIBSplitSibling(parentFrame, false); 1.6683 + } 1.6684 + 1.6685 + // Get continuation that parents the last child. This MUST be done 1.6686 + // before the AdjustAppendParentForAfterContent call. 1.6687 + parentFrame = nsLayoutUtils::LastContinuationWithChild(parentFrame); 1.6688 + 1.6689 + // We should never get here with fieldsets, since they have multiple 1.6690 + // insertion points. 1.6691 + NS_ASSERTION(parentFrame->GetType() != nsGkAtoms::fieldSetFrame, 1.6692 + "Unexpected parent"); 1.6693 + 1.6694 + // Deal with possible :after generated content on the parent 1.6695 + nsIFrame* parentAfterFrame; 1.6696 + parentFrame = 1.6697 + ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(), 1.6698 + aContainer, parentFrame, 1.6699 + &parentAfterFrame); 1.6700 + 1.6701 + // Create some new frames 1.6702 + nsFrameConstructorState state(mPresShell, 1.6703 + GetAbsoluteContainingBlock(parentFrame, FIXED_POS), 1.6704 + GetAbsoluteContainingBlock(parentFrame, ABS_POS), 1.6705 + GetFloatContainingBlock(parentFrame)); 1.6706 + state.mTreeMatchContext.InitAncestors(aContainer->AsElement()); 1.6707 + 1.6708 + // See if the containing block has :first-letter style applied. 1.6709 + bool haveFirstLetterStyle = false, haveFirstLineStyle = false; 1.6710 + nsIFrame* containingBlock = state.mFloatedItems.containingBlock; 1.6711 + if (containingBlock) { 1.6712 + haveFirstLetterStyle = HasFirstLetterStyle(containingBlock); 1.6713 + haveFirstLineStyle = 1.6714 + ShouldHaveFirstLineStyle(containingBlock->GetContent(), 1.6715 + containingBlock->StyleContext()); 1.6716 + } 1.6717 + 1.6718 + if (haveFirstLetterStyle) { 1.6719 + // Before we get going, remove the current letter frames 1.6720 + RemoveLetterFrames(state.mPresContext, state.mPresShell, 1.6721 + containingBlock); 1.6722 + } 1.6723 + 1.6724 + nsIAtom* frameType = parentFrame->GetType(); 1.6725 + 1.6726 + FlattenedChildIterator iter(aContainer); 1.6727 + bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild()); 1.6728 + FrameConstructionItemList items; 1.6729 + if (aFirstNewContent->GetPreviousSibling() && 1.6730 + GetParentType(frameType) == eTypeBlock && 1.6731 + haveNoXBLChildren) { 1.6732 + // If there's a text node in the normal content list just before the new 1.6733 + // items, and it has no frame, make a frame construction item for it. If it 1.6734 + // doesn't need a frame, ConstructFramesFromItemList below won't give it 1.6735 + // one. No need to do all this if our parent type is not block, though, 1.6736 + // since WipeContainingBlock already handles that situation. 1.6737 + // 1.6738 + // Because we're appending, we don't need to worry about any text 1.6739 + // after the appended content; there can only be XBL anonymous content 1.6740 + // (text in an XBL binding is not suppressed) or generated content 1.6741 + // (and bare text nodes are not generated). Native anonymous content 1.6742 + // generated by frames never participates in inline layout. 1.6743 + AddTextItemIfNeeded(state, parentFrame, 1.6744 + aFirstNewContent->GetPreviousSibling(), items); 1.6745 + } 1.6746 + for (nsIContent* child = aFirstNewContent; 1.6747 + child; 1.6748 + child = child->GetNextSibling()) { 1.6749 + AddFrameConstructionItems(state, child, false, parentFrame, items); 1.6750 + } 1.6751 + 1.6752 + nsIFrame* prevSibling = ::FindAppendPrevSibling(parentFrame, parentAfterFrame); 1.6753 + 1.6754 + // Perform special check for diddling around with the frames in 1.6755 + // a ib-split inline frame. 1.6756 + // If we're appending before :after content, then we're not really 1.6757 + // appending, so let WipeContainingBlock know that. 1.6758 + LAYOUT_PHASE_TEMP_EXIT(); 1.6759 + if (WipeContainingBlock(state, containingBlock, parentFrame, items, 1.6760 + true, prevSibling)) { 1.6761 + LAYOUT_PHASE_TEMP_REENTER(); 1.6762 + return NS_OK; 1.6763 + } 1.6764 + LAYOUT_PHASE_TEMP_REENTER(); 1.6765 + 1.6766 + // If the parent is a block frame, and we're not in a special case 1.6767 + // where frames can be moved around, determine if the list is for the 1.6768 + // start or end of the block. 1.6769 + if (nsLayoutUtils::GetAsBlock(parentFrame) && !haveFirstLetterStyle && 1.6770 + !haveFirstLineStyle && !parentIBSplit) { 1.6771 + items.SetLineBoundaryAtStart(!prevSibling || 1.6772 + !prevSibling->IsInlineOutside() || 1.6773 + prevSibling->GetType() == nsGkAtoms::brFrame); 1.6774 + // :after content can't be <br> so no need to check it 1.6775 + items.SetLineBoundaryAtEnd(!parentAfterFrame || 1.6776 + !parentAfterFrame->IsInlineOutside()); 1.6777 + } 1.6778 + // To suppress whitespace-only text frames, we have to verify that 1.6779 + // our container's DOM child list matches its flattened tree child list. 1.6780 + items.SetParentHasNoXBLChildren(haveNoXBLChildren); 1.6781 + 1.6782 + nsFrameItems frameItems; 1.6783 + ConstructFramesFromItemList(state, items, parentFrame, frameItems); 1.6784 + 1.6785 + for (nsIContent* child = aFirstNewContent; 1.6786 + child; 1.6787 + child = child->GetNextSibling()) { 1.6788 + // Invalidate now instead of before the WipeContainingBlock call, just in 1.6789 + // case we do wipe; in that case we don't need to do this walk at all. 1.6790 + // XXXbz does that matter? Would it make more sense to save some virtual 1.6791 + // GetChildAt calls instead and do this during construction of our 1.6792 + // FrameConstructionItemList? 1.6793 + InvalidateCanvasIfNeeded(mPresShell, child); 1.6794 + } 1.6795 + 1.6796 + // if the container is a table and a caption was appended, it needs to be put 1.6797 + // in the outer table frame's additional child list. 1.6798 + nsFrameItems captionItems; 1.6799 + if (nsGkAtoms::tableFrame == frameType) { 1.6800 + // Pull out the captions. Note that we don't want to do that as we go, 1.6801 + // because processing a single caption can add a whole bunch of things to 1.6802 + // the frame items due to pseudoframe processing. So we'd have to pull 1.6803 + // captions from a list anyway; might as well do that here. 1.6804 + // XXXbz this is no longer true; we could pull captions directly out of the 1.6805 + // FrameConstructionItemList now. 1.6806 + PullOutCaptionFrames(frameItems, captionItems); 1.6807 + } 1.6808 + 1.6809 + if (haveFirstLineStyle && parentFrame == containingBlock) { 1.6810 + // It's possible that some of the new frames go into a 1.6811 + // first-line frame. Look at them and see... 1.6812 + AppendFirstLineFrames(state, containingBlock->GetContent(), 1.6813 + containingBlock, frameItems); 1.6814 + } 1.6815 + 1.6816 + // Notify the parent frame passing it the list of new frames 1.6817 + // Append the flowed frames to the principal child list; captions 1.6818 + // need special treatment 1.6819 + if (captionItems.NotEmpty()) { // append the caption to the outer table 1.6820 + NS_ASSERTION(nsGkAtoms::tableFrame == frameType, "how did that happen?"); 1.6821 + nsIFrame* outerTable = parentFrame->GetParent(); 1.6822 + AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems); 1.6823 + } 1.6824 + 1.6825 + if (frameItems.NotEmpty()) { // append the in-flow kids 1.6826 + AppendFramesToParent(state, parentFrame, frameItems, prevSibling); 1.6827 + } 1.6828 + 1.6829 + // Recover first-letter frames 1.6830 + if (haveFirstLetterStyle) { 1.6831 + RecoverLetterFrames(containingBlock); 1.6832 + } 1.6833 + 1.6834 +#ifdef DEBUG 1.6835 + if (gReallyNoisyContentUpdates) { 1.6836 + printf("nsCSSFrameConstructor::ContentAppended: resulting frame model:\n"); 1.6837 + parentFrame->List(stdout, 0); 1.6838 + } 1.6839 +#endif 1.6840 + 1.6841 +#ifdef ACCESSIBILITY 1.6842 + nsAccessibilityService* accService = nsIPresShell::AccService(); 1.6843 + if (accService) { 1.6844 + accService->ContentRangeInserted(mPresShell, aContainer, 1.6845 + aFirstNewContent, nullptr); 1.6846 + } 1.6847 +#endif 1.6848 + 1.6849 + return NS_OK; 1.6850 +} 1.6851 + 1.6852 +#ifdef MOZ_XUL 1.6853 + 1.6854 +enum content_operation 1.6855 +{ 1.6856 + CONTENT_INSERTED, 1.6857 + CONTENT_REMOVED 1.6858 +}; 1.6859 + 1.6860 +// Helper function to lookup the listbox body frame and send a notification 1.6861 +// for insertion or removal of content 1.6862 +static 1.6863 +bool NotifyListBoxBody(nsPresContext* aPresContext, 1.6864 + nsIContent* aContainer, 1.6865 + nsIContent* aChild, 1.6866 + // Only used for the removed notification 1.6867 + nsIContent* aOldNextSibling, 1.6868 + nsIDocument* aDocument, 1.6869 + nsIFrame* aChildFrame, 1.6870 + content_operation aOperation) 1.6871 +{ 1.6872 + nsListBoxBodyFrame* listBoxBodyFrame = 1.6873 + MaybeGetListBoxBodyFrame(aContainer, aChild); 1.6874 + if (listBoxBodyFrame) { 1.6875 + if (aOperation == CONTENT_REMOVED) { 1.6876 + // Except if we have an aChildFrame and its parent is not the right 1.6877 + // thing, then we don't do this. Pseudo frames are so much fun.... 1.6878 + if (!aChildFrame || aChildFrame->GetParent() == listBoxBodyFrame) { 1.6879 + listBoxBodyFrame->OnContentRemoved(aPresContext, aContainer, 1.6880 + aChildFrame, aOldNextSibling); 1.6881 + return true; 1.6882 + } 1.6883 + } else { 1.6884 + listBoxBodyFrame->OnContentInserted(aPresContext, aChild); 1.6885 + return true; 1.6886 + } 1.6887 + } 1.6888 + 1.6889 + return false; 1.6890 +} 1.6891 +#endif // MOZ_XUL 1.6892 + 1.6893 +nsresult 1.6894 +nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer, 1.6895 + nsIContent* aChild, 1.6896 + nsILayoutHistoryState* aFrameState, 1.6897 + bool aAllowLazyConstruction) 1.6898 +{ 1.6899 + return ContentRangeInserted(aContainer, 1.6900 + aChild, 1.6901 + aChild->GetNextSibling(), 1.6902 + aFrameState, 1.6903 + aAllowLazyConstruction); 1.6904 +} 1.6905 + 1.6906 +// ContentRangeInserted handles creating frames for a range of nodes that 1.6907 +// aren't at the end of their childlist. ContentRangeInserted isn't a real 1.6908 +// content notification, but rather it handles regular ContentInserted calls 1.6909 +// for a single node as well as the lazy construction of frames for a range of 1.6910 +// nodes when called from CreateNeededFrames. For a range of nodes to be 1.6911 +// suitable to have its frames constructed all at once they must meet the same 1.6912 +// conditions that ContentAppended imposes (GetRangeInsertionPoint checks 1.6913 +// these), plus more. Namely when finding the insertion prevsibling we must not 1.6914 +// need to consult something specific to any one node in the range, so that the 1.6915 +// insertion prevsibling would be the same for each node in the range. So we 1.6916 +// pass the first node in the range to GetInsertionPrevSibling, and if 1.6917 +// IsValidSibling (the only place GetInsertionPrevSibling might look at the 1.6918 +// passed in node itself) needs to resolve style on the node we record this and 1.6919 +// return that this range needs to be split up and inserted separately. Table 1.6920 +// captions need extra attention as we need to determine where to insert them 1.6921 +// in the caption list, while skipping any nodes in the range being inserted 1.6922 +// (because when we treat the caption frames the other nodes have had their 1.6923 +// frames constructed but not yet inserted into the frame tree). 1.6924 +nsresult 1.6925 +nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, 1.6926 + nsIContent* aStartChild, 1.6927 + nsIContent* aEndChild, 1.6928 + nsILayoutHistoryState* aFrameState, 1.6929 + bool aAllowLazyConstruction) 1.6930 +{ 1.6931 + AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC); 1.6932 + NS_PRECONDITION(mUpdateCount != 0, 1.6933 + "Should be in an update while creating frames"); 1.6934 + 1.6935 + NS_PRECONDITION(aStartChild, "must always pass a child"); 1.6936 + 1.6937 + // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and 1.6938 + // the :empty pseudo-class? 1.6939 +#ifdef DEBUG 1.6940 + if (gNoisyContentUpdates) { 1.6941 + printf("nsCSSFrameConstructor::ContentRangeInserted container=%p " 1.6942 + "start-child=%p end-child=%p lazy=%d\n", 1.6943 + static_cast<void*>(aContainer), 1.6944 + static_cast<void*>(aStartChild), static_cast<void*>(aEndChild), 1.6945 + aAllowLazyConstruction); 1.6946 + if (gReallyNoisyContentUpdates) { 1.6947 + if (aContainer) { 1.6948 + aContainer->List(stdout,0); 1.6949 + } else { 1.6950 + aStartChild->List(stdout, 0); 1.6951 + } 1.6952 + } 1.6953 + } 1.6954 +#endif 1.6955 + 1.6956 +#ifdef DEBUG 1.6957 + for (nsIContent* child = aStartChild; 1.6958 + child != aEndChild; 1.6959 + child = child->GetNextSibling()) { 1.6960 + // XXX the GetContent() != child check is needed due to bug 135040. 1.6961 + // Remove it once that's fixed. 1.6962 + NS_ASSERTION(!child->GetPrimaryFrame() || 1.6963 + child->GetPrimaryFrame()->GetContent() != child, 1.6964 + "asked to construct a frame for a node that already has a frame"); 1.6965 + } 1.6966 +#endif 1.6967 + 1.6968 + bool isSingleInsert = (aStartChild->GetNextSibling() == aEndChild); 1.6969 + NS_ASSERTION(isSingleInsert || !aAllowLazyConstruction, 1.6970 + "range insert shouldn't be lazy"); 1.6971 + NS_ASSERTION(isSingleInsert || aEndChild, 1.6972 + "range should not include all nodes after aStartChild"); 1.6973 + 1.6974 +#ifdef MOZ_XUL 1.6975 + if (aContainer && IsXULListBox(aContainer)) { 1.6976 + if (isSingleInsert) { 1.6977 + if (NotifyListBoxBody(mPresShell->GetPresContext(), aContainer, 1.6978 + // The insert case in NotifyListBoxBody 1.6979 + // doesn't use "old next sibling". 1.6980 + aStartChild, nullptr, 1.6981 + mDocument, nullptr, CONTENT_INSERTED)) { 1.6982 + return NS_OK; 1.6983 + } 1.6984 + } else { 1.6985 + // We don't handle a range insert to a listbox parent, issue single 1.6986 + // ContertInserted calls for each node inserted. 1.6987 + LAYOUT_PHASE_TEMP_EXIT(); 1.6988 + IssueSingleInsertNofications(aContainer, aStartChild, aEndChild, 1.6989 + aAllowLazyConstruction); 1.6990 + LAYOUT_PHASE_TEMP_REENTER(); 1.6991 + return NS_OK; 1.6992 + } 1.6993 + } 1.6994 +#endif // MOZ_XUL 1.6995 + 1.6996 + // If we have a null parent, then this must be the document element being 1.6997 + // inserted, or some other child of the document in the DOM (might be a PI, 1.6998 + // say). 1.6999 + if (! aContainer) { 1.7000 + NS_ASSERTION(isSingleInsert, 1.7001 + "root node insertion should be a single insertion"); 1.7002 + Element *docElement = mDocument->GetRootElement(); 1.7003 + 1.7004 + if (aStartChild != docElement) { 1.7005 + // Not the root element; just bail out 1.7006 + return NS_OK; 1.7007 + } 1.7008 + 1.7009 + NS_PRECONDITION(nullptr == mRootElementFrame, 1.7010 + "root element frame already created"); 1.7011 + 1.7012 + // Create frames for the document element and its child elements 1.7013 + nsIFrame* docElementFrame = 1.7014 + ConstructDocElementFrame(docElement, aFrameState); 1.7015 + 1.7016 + if (docElementFrame) { 1.7017 + InvalidateCanvasIfNeeded(mPresShell, aStartChild); 1.7018 +#ifdef DEBUG 1.7019 + if (gReallyNoisyContentUpdates) { 1.7020 + printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame " 1.7021 + "model:\n"); 1.7022 + mFixedContainingBlock->List(stdout, 0); 1.7023 + } 1.7024 +#endif 1.7025 + } 1.7026 + 1.7027 + if (aFrameState) { 1.7028 + // Restore frame state for the root scroll frame if there is one 1.7029 + nsIFrame* rootScrollFrame = mPresShell->GetRootScrollFrame(); 1.7030 + if (rootScrollFrame) { 1.7031 + RestoreFrameStateFor(rootScrollFrame, aFrameState); 1.7032 + } 1.7033 + } 1.7034 + 1.7035 +#ifdef ACCESSIBILITY 1.7036 + nsAccessibilityService* accService = nsIPresShell::AccService(); 1.7037 + if (accService) { 1.7038 + accService->ContentRangeInserted(mPresShell, aContainer, 1.7039 + aStartChild, aEndChild); 1.7040 + } 1.7041 +#endif 1.7042 + 1.7043 + return NS_OK; 1.7044 + } 1.7045 + 1.7046 + if (aContainer->HasFlag(NODE_IS_IN_SHADOW_TREE)) { 1.7047 + // Recreate frames if content is inserted into a ShadowRoot 1.7048 + // because children of ShadowRoot are rendered in place of 1.7049 + // the children of the host. 1.7050 + nsIContent* bindingParent = aContainer->GetBindingParent(); 1.7051 + LAYOUT_PHASE_TEMP_EXIT(); 1.7052 + nsresult rv = RecreateFramesForContent(bindingParent, false); 1.7053 + LAYOUT_PHASE_TEMP_REENTER(); 1.7054 + return rv; 1.7055 + } 1.7056 + 1.7057 + nsIFrame* parentFrame = GetFrameFor(aContainer); 1.7058 + // The xbl:children element won't have a frame, but default content can have the children as 1.7059 + // a parent. While its uncommon to change the structure of the default content itself, a label, 1.7060 + // for example, can be reframed by having its value attribute set or removed. 1.7061 + if (!parentFrame && !aContainer->IsActiveChildrenElement()) { 1.7062 + return NS_OK; 1.7063 + } 1.7064 + 1.7065 + // Otherwise, we've got parent content. Find its frame. 1.7066 + NS_ASSERTION(!parentFrame || parentFrame->GetContent() == aContainer, "New XBL code is possibly wrong!"); 1.7067 + 1.7068 + if (aAllowLazyConstruction && 1.7069 + MaybeConstructLazily(CONTENTINSERT, aContainer, aStartChild)) { 1.7070 + return NS_OK; 1.7071 + } 1.7072 + 1.7073 + if (isSingleInsert) { 1.7074 + // See if we have an XBL insertion point. If so, then that's our 1.7075 + // real parent frame; if not, then the frame hasn't been built yet 1.7076 + // and we just bail. 1.7077 + parentFrame = GetInsertionPoint(aContainer, aStartChild); 1.7078 + } else { 1.7079 + // Get our insertion point. If we need to issue single ContentInserted's 1.7080 + // GetRangeInsertionPoint will take care of that for us. 1.7081 + LAYOUT_PHASE_TEMP_EXIT(); 1.7082 + parentFrame = GetRangeInsertionPoint(aContainer, aStartChild, aEndChild, 1.7083 + aAllowLazyConstruction); 1.7084 + LAYOUT_PHASE_TEMP_REENTER(); 1.7085 + } 1.7086 + 1.7087 + if (!parentFrame) { 1.7088 + return NS_OK; 1.7089 + } 1.7090 + 1.7091 + bool isAppend, isRangeInsertSafe; 1.7092 + nsIFrame* prevSibling = 1.7093 + GetInsertionPrevSibling(parentFrame, aContainer, aStartChild, 1.7094 + &isAppend, &isRangeInsertSafe); 1.7095 + 1.7096 + // check if range insert is safe 1.7097 + if (!isSingleInsert && !isRangeInsertSafe) { 1.7098 + // must fall back to a single ContertInserted for each child in the range 1.7099 + LAYOUT_PHASE_TEMP_EXIT(); 1.7100 + IssueSingleInsertNofications(aContainer, aStartChild, aEndChild, 1.7101 + aAllowLazyConstruction); 1.7102 + LAYOUT_PHASE_TEMP_REENTER(); 1.7103 + return NS_OK; 1.7104 + } 1.7105 + 1.7106 + nsIContent* container = parentFrame->GetContent(); 1.7107 + 1.7108 + nsIAtom* frameType = parentFrame->GetType(); 1.7109 + LAYOUT_PHASE_TEMP_EXIT(); 1.7110 + if (MaybeRecreateForFrameset(parentFrame, aStartChild, aEndChild)) { 1.7111 + LAYOUT_PHASE_TEMP_REENTER(); 1.7112 + return NS_OK; 1.7113 + } 1.7114 + LAYOUT_PHASE_TEMP_REENTER(); 1.7115 + 1.7116 + // We should only get here with fieldsets when doing a single insert, because 1.7117 + // fieldsets have multiple insertion points. 1.7118 + NS_ASSERTION(isSingleInsert || frameType != nsGkAtoms::fieldSetFrame, 1.7119 + "Unexpected parent"); 1.7120 + if (IsFrameForFieldSet(parentFrame, frameType) && 1.7121 + aStartChild->Tag() == nsGkAtoms::legend) { 1.7122 + // Just reframe the parent, since figuring out whether this 1.7123 + // should be the new legend and then handling it is too complex. 1.7124 + // We could do a little better here --- check if the fieldset already 1.7125 + // has a legend which occurs earlier in its child list than this node, 1.7126 + // and if so, proceed. But we'd have to extend nsFieldSetFrame 1.7127 + // to locate this legend in the inserted frames and extract it. 1.7128 + LAYOUT_PHASE_TEMP_EXIT(); 1.7129 + nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false); 1.7130 + LAYOUT_PHASE_TEMP_REENTER(); 1.7131 + return rv; 1.7132 + } 1.7133 + 1.7134 + // Don't construct kids of leaves 1.7135 + if (parentFrame->IsLeaf()) { 1.7136 + // Clear lazy bits so we don't try to construct again. 1.7137 + ClearLazyBits(aStartChild, aEndChild); 1.7138 + return NS_OK; 1.7139 + } 1.7140 + 1.7141 + if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) { 1.7142 + LAYOUT_PHASE_TEMP_EXIT(); 1.7143 + nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false); 1.7144 + LAYOUT_PHASE_TEMP_REENTER(); 1.7145 + return rv; 1.7146 + } 1.7147 + 1.7148 + nsFrameConstructorState state(mPresShell, 1.7149 + GetAbsoluteContainingBlock(parentFrame, FIXED_POS), 1.7150 + GetAbsoluteContainingBlock(parentFrame, ABS_POS), 1.7151 + GetFloatContainingBlock(parentFrame), 1.7152 + aFrameState); 1.7153 + state.mTreeMatchContext.InitAncestors(aContainer ? 1.7154 + aContainer->AsElement() : 1.7155 + nullptr); 1.7156 + 1.7157 + // Recover state for the containing block - we need to know if 1.7158 + // it has :first-letter or :first-line style applied to it. The 1.7159 + // reason we care is that the internal structure in these cases 1.7160 + // is not the normal structure and requires custom updating 1.7161 + // logic. 1.7162 + nsIFrame* containingBlock = state.mFloatedItems.containingBlock; 1.7163 + bool haveFirstLetterStyle = false; 1.7164 + bool haveFirstLineStyle = false; 1.7165 + 1.7166 + // In order to shave off some cycles, we only dig up the 1.7167 + // containing block haveFirst* flags if the parent frame where 1.7168 + // the insertion/append is occurring is an inline or block 1.7169 + // container. For other types of containers this isn't relevant. 1.7170 + uint8_t parentDisplay = parentFrame->GetDisplay(); 1.7171 + 1.7172 + // Examine the parentFrame where the insertion is taking 1.7173 + // place. If it's a certain kind of container then some special 1.7174 + // processing is done. 1.7175 + if ((NS_STYLE_DISPLAY_BLOCK == parentDisplay) || 1.7176 + (NS_STYLE_DISPLAY_LIST_ITEM == parentDisplay) || 1.7177 + (NS_STYLE_DISPLAY_INLINE == parentDisplay) || 1.7178 + (NS_STYLE_DISPLAY_INLINE_BLOCK == parentDisplay)) { 1.7179 + // Recover the special style flags for the containing block 1.7180 + if (containingBlock) { 1.7181 + haveFirstLetterStyle = HasFirstLetterStyle(containingBlock); 1.7182 + haveFirstLineStyle = 1.7183 + ShouldHaveFirstLineStyle(containingBlock->GetContent(), 1.7184 + containingBlock->StyleContext()); 1.7185 + } 1.7186 + 1.7187 + if (haveFirstLetterStyle) { 1.7188 + // If our current parentFrame is a Letter frame, use its parent as our 1.7189 + // new parent hint 1.7190 + if (parentFrame->GetType() == nsGkAtoms::letterFrame) { 1.7191 + // If parentFrame is out of flow, then we actually want the parent of 1.7192 + // the placeholder frame. 1.7193 + if (parentFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { 1.7194 + nsPlaceholderFrame* placeholderFrame = 1.7195 + GetPlaceholderFrameFor(parentFrame); 1.7196 + NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?"); 1.7197 + parentFrame = placeholderFrame->GetParent(); 1.7198 + } else { 1.7199 + parentFrame = parentFrame->GetParent(); 1.7200 + } 1.7201 + } 1.7202 + 1.7203 + // Remove the old letter frames before doing the insertion 1.7204 + RemoveLetterFrames(state.mPresContext, mPresShell, 1.7205 + state.mFloatedItems.containingBlock); 1.7206 + 1.7207 + // Removing the letterframes messes around with the frame tree, removing 1.7208 + // and creating frames. We need to reget our prevsibling, parent frame, 1.7209 + // etc. 1.7210 + prevSibling = GetInsertionPrevSibling(parentFrame, aContainer, 1.7211 + aStartChild, &isAppend, 1.7212 + &isRangeInsertSafe); 1.7213 + 1.7214 + // Need check whether a range insert is still safe. 1.7215 + if (!isSingleInsert && !isRangeInsertSafe) { 1.7216 + // Need to recover the letter frames first. 1.7217 + RecoverLetterFrames(state.mFloatedItems.containingBlock); 1.7218 + 1.7219 + // must fall back to a single ContertInserted for each child in the range 1.7220 + LAYOUT_PHASE_TEMP_EXIT(); 1.7221 + IssueSingleInsertNofications(aContainer, aStartChild, aEndChild, 1.7222 + aAllowLazyConstruction); 1.7223 + LAYOUT_PHASE_TEMP_REENTER(); 1.7224 + return NS_OK; 1.7225 + } 1.7226 + 1.7227 + container = parentFrame->GetContent(); 1.7228 + frameType = parentFrame->GetType(); 1.7229 + } 1.7230 + } 1.7231 + 1.7232 + if (!prevSibling) { 1.7233 + // We're inserting the new frames as the first child. See if the 1.7234 + // parent has a :before pseudo-element 1.7235 + nsIFrame* firstChild = parentFrame->GetFirstPrincipalChild(); 1.7236 + 1.7237 + if (firstChild && 1.7238 + nsLayoutUtils::IsGeneratedContentFor(container, firstChild, 1.7239 + nsCSSPseudoElements::before)) { 1.7240 + // Insert the new frames after the last continuation of the :before 1.7241 + prevSibling = firstChild->GetTailContinuation(); 1.7242 + parentFrame = prevSibling->GetParent()->GetContentInsertionFrame(); 1.7243 + // Don't change isAppend here; we'll can call AppendFrames as needed, and 1.7244 + // the change to our prevSibling doesn't affect that. 1.7245 + } 1.7246 + } 1.7247 + 1.7248 + FrameConstructionItemList items; 1.7249 + ParentType parentType = GetParentType(frameType); 1.7250 + FlattenedChildIterator iter(aContainer); 1.7251 + bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild()); 1.7252 + if (aStartChild->GetPreviousSibling() && 1.7253 + parentType == eTypeBlock && haveNoXBLChildren) { 1.7254 + // If there's a text node in the normal content list just before the 1.7255 + // new nodes, and it has no frame, make a frame construction item for 1.7256 + // it, because it might need a frame now. No need to do this if our 1.7257 + // parent type is not block, though, since WipeContainingBlock 1.7258 + // already handles that sitation. 1.7259 + AddTextItemIfNeeded(state, parentFrame, aStartChild->GetPreviousSibling(), 1.7260 + items); 1.7261 + } 1.7262 + 1.7263 + if (isSingleInsert) { 1.7264 + AddFrameConstructionItems(state, aStartChild, 1.7265 + aStartChild->IsRootOfAnonymousSubtree(), 1.7266 + parentFrame, items); 1.7267 + } else { 1.7268 + for (nsIContent* child = aStartChild; 1.7269 + child != aEndChild; 1.7270 + child = child->GetNextSibling()){ 1.7271 + AddFrameConstructionItems(state, child, false, parentFrame, items); 1.7272 + } 1.7273 + } 1.7274 + 1.7275 + if (aEndChild && parentType == eTypeBlock && haveNoXBLChildren) { 1.7276 + // If there's a text node in the normal content list just after the 1.7277 + // new nodes, and it has no frame, make a frame construction item for 1.7278 + // it, because it might need a frame now. No need to do this if our 1.7279 + // parent type is not block, though, since WipeContainingBlock 1.7280 + // already handles that sitation. 1.7281 + AddTextItemIfNeeded(state, parentFrame, aEndChild, items); 1.7282 + } 1.7283 + 1.7284 + // Perform special check for diddling around with the frames in 1.7285 + // a special inline frame. 1.7286 + // If we're appending before :after content, then we're not really 1.7287 + // appending, so let WipeContainingBlock know that. 1.7288 + LAYOUT_PHASE_TEMP_EXIT(); 1.7289 + if (WipeContainingBlock(state, containingBlock, parentFrame, items, 1.7290 + isAppend, prevSibling)) { 1.7291 + LAYOUT_PHASE_TEMP_REENTER(); 1.7292 + return NS_OK; 1.7293 + } 1.7294 + LAYOUT_PHASE_TEMP_REENTER(); 1.7295 + 1.7296 + // If the container is a table and a caption will be appended, it needs to be 1.7297 + // put in the outer table frame's additional child list. 1.7298 + // We make no attempt here to set flags to indicate whether the list 1.7299 + // will be at the start or end of a block. It doesn't seem worthwhile. 1.7300 + nsFrameItems frameItems, captionItems; 1.7301 + ConstructFramesFromItemList(state, items, parentFrame, frameItems); 1.7302 + 1.7303 + if (frameItems.NotEmpty()) { 1.7304 + for (nsIContent* child = aStartChild; 1.7305 + child != aEndChild; 1.7306 + child = child->GetNextSibling()){ 1.7307 + InvalidateCanvasIfNeeded(mPresShell, child); 1.7308 + } 1.7309 + 1.7310 + if (nsGkAtoms::tableFrame == frameType || 1.7311 + nsGkAtoms::tableOuterFrame == frameType) { 1.7312 + PullOutCaptionFrames(frameItems, captionItems); 1.7313 + } 1.7314 + } 1.7315 + 1.7316 + // If the parent of our current prevSibling is different from the frame we'll 1.7317 + // actually use as the parent, then the calculated insertion point is now 1.7318 + // invalid and as it is unknown where to insert correctly we append instead 1.7319 + // (bug 341858). 1.7320 + // This can affect our prevSibling and isAppend, but should not have any 1.7321 + // effect on the WipeContainingBlock above, since this should only happen 1.7322 + // when neither parent is a ib-split frame and should not affect whitespace 1.7323 + // handling inside table-related frames (and in fact, can only happen when 1.7324 + // one of the parents is an outer table and one is an inner table or when the 1.7325 + // parent is a fieldset or fieldset content frame). So it won't affect the 1.7326 + // {ib} or XUL box cases in WipeContainingBlock(), and the table pseudo 1.7327 + // handling will only be affected by us maybe thinking we're not inserting 1.7328 + // at the beginning, whereas we really are. That would have made us reframe 1.7329 + // unnecessarily, but that's ok. 1.7330 + // XXXbz we should push our frame construction item code up higher, so we 1.7331 + // know what our items are by the time we start figuring out previous 1.7332 + // siblings 1.7333 + if (prevSibling && frameItems.NotEmpty() && 1.7334 + frameItems.FirstChild()->GetParent() != prevSibling->GetParent()) { 1.7335 +#ifdef DEBUG 1.7336 + nsIFrame* frame1 = frameItems.FirstChild()->GetParent(); 1.7337 + nsIFrame* frame2 = prevSibling->GetParent(); 1.7338 + NS_ASSERTION(!IsFramePartOfIBSplit(frame1) && 1.7339 + !IsFramePartOfIBSplit(frame2), 1.7340 + "Neither should be ib-split"); 1.7341 + NS_ASSERTION((frame1->GetType() == nsGkAtoms::tableFrame && 1.7342 + frame2->GetType() == nsGkAtoms::tableOuterFrame) || 1.7343 + (frame1->GetType() == nsGkAtoms::tableOuterFrame && 1.7344 + frame2->GetType() == nsGkAtoms::tableFrame) || 1.7345 + frame1->GetType() == nsGkAtoms::fieldSetFrame || 1.7346 + (frame1->GetParent() && 1.7347 + frame1->GetParent()->GetType() == nsGkAtoms::fieldSetFrame), 1.7348 + "Unexpected frame types"); 1.7349 +#endif 1.7350 + isAppend = true; 1.7351 + nsIFrame* appendAfterFrame; 1.7352 + parentFrame = 1.7353 + ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(), 1.7354 + container, 1.7355 + frameItems.FirstChild()->GetParent(), 1.7356 + &appendAfterFrame); 1.7357 + prevSibling = ::FindAppendPrevSibling(parentFrame, appendAfterFrame); 1.7358 + } 1.7359 + 1.7360 + if (haveFirstLineStyle && parentFrame == containingBlock) { 1.7361 + // It's possible that the new frame goes into a first-line 1.7362 + // frame. Look at it and see... 1.7363 + if (isAppend) { 1.7364 + // Use append logic when appending 1.7365 + AppendFirstLineFrames(state, containingBlock->GetContent(), 1.7366 + containingBlock, frameItems); 1.7367 + } 1.7368 + else { 1.7369 + // Use more complicated insert logic when inserting 1.7370 + // XXXbz this method is a no-op, so it's easy for the args being passed 1.7371 + // here to make no sense without anyone noticing... If it ever stops 1.7372 + // being a no-op, vet them carefully! 1.7373 + InsertFirstLineFrames(state, container, containingBlock, &parentFrame, 1.7374 + prevSibling, frameItems); 1.7375 + } 1.7376 + } 1.7377 + 1.7378 + // We might have captions; put them into the caption list of the 1.7379 + // outer table frame. 1.7380 + if (captionItems.NotEmpty()) { 1.7381 + NS_ASSERTION(nsGkAtoms::tableFrame == frameType || 1.7382 + nsGkAtoms::tableOuterFrame == frameType, 1.7383 + "parent for caption is not table?"); 1.7384 + // We need to determine where to put the caption items; start with the 1.7385 + // the parent frame that has already been determined and get the insertion 1.7386 + // prevsibling of the first caption item. 1.7387 + nsIFrame* captionParent = parentFrame; 1.7388 + bool captionIsAppend; 1.7389 + nsIFrame* captionPrevSibling = nullptr; 1.7390 + 1.7391 + // aIsRangeInsertSafe is ignored on purpose because it is irrelevant here. 1.7392 + bool ignored; 1.7393 + if (isSingleInsert) { 1.7394 + captionPrevSibling = 1.7395 + GetInsertionPrevSibling(captionParent, aContainer, aStartChild, 1.7396 + &captionIsAppend, &ignored); 1.7397 + } else { 1.7398 + nsIContent* firstCaption = captionItems.FirstChild()->GetContent(); 1.7399 + // It is very important here that we skip the children in 1.7400 + // [aStartChild,aEndChild) when looking for a 1.7401 + // prevsibling. 1.7402 + captionPrevSibling = 1.7403 + GetInsertionPrevSibling(captionParent, aContainer, firstCaption, 1.7404 + &captionIsAppend, &ignored, 1.7405 + aStartChild, aEndChild); 1.7406 + } 1.7407 + 1.7408 + nsIFrame* outerTable = nullptr; 1.7409 + if (GetCaptionAdjustedParent(captionParent, captionItems.FirstChild(), 1.7410 + &outerTable)) { 1.7411 + // If the parent is not an outer table frame we will try to add frames 1.7412 + // to a named child list that the parent does not honour and the frames 1.7413 + // will get lost 1.7414 + NS_ASSERTION(nsGkAtoms::tableOuterFrame == outerTable->GetType(), 1.7415 + "Pseudo frame construction failure; " 1.7416 + "a caption can be only a child of an outer table frame"); 1.7417 + 1.7418 + // If the parent of our current prevSibling is different from the frame 1.7419 + // we'll actually use as the parent, then the calculated insertion 1.7420 + // point is now invalid (bug 341382). 1.7421 + if (captionPrevSibling && 1.7422 + captionPrevSibling->GetParent() != outerTable) { 1.7423 + captionPrevSibling = nullptr; 1.7424 + } 1.7425 + if (captionIsAppend) { 1.7426 + AppendFrames(outerTable, nsIFrame::kCaptionList, captionItems); 1.7427 + } else { 1.7428 + InsertFrames(outerTable, nsIFrame::kCaptionList, 1.7429 + captionPrevSibling, captionItems); 1.7430 + } 1.7431 + } 1.7432 + } 1.7433 + 1.7434 + if (frameItems.NotEmpty()) { 1.7435 + // Notify the parent frame 1.7436 + if (isAppend) { 1.7437 + AppendFramesToParent(state, parentFrame, frameItems, prevSibling); 1.7438 + } else { 1.7439 + InsertFrames(parentFrame, kPrincipalList, prevSibling, frameItems); 1.7440 + } 1.7441 + } 1.7442 + 1.7443 + if (haveFirstLetterStyle) { 1.7444 + // Recover the letter frames for the containing block when 1.7445 + // it has first-letter style. 1.7446 + RecoverLetterFrames(state.mFloatedItems.containingBlock); 1.7447 + } 1.7448 + 1.7449 +#ifdef DEBUG 1.7450 + if (gReallyNoisyContentUpdates && parentFrame) { 1.7451 + printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame model:\n"); 1.7452 + parentFrame->List(stdout, 0); 1.7453 + } 1.7454 +#endif 1.7455 + 1.7456 +#ifdef ACCESSIBILITY 1.7457 + nsAccessibilityService* accService = nsIPresShell::AccService(); 1.7458 + if (accService) { 1.7459 + accService->ContentRangeInserted(mPresShell, aContainer, 1.7460 + aStartChild, aEndChild); 1.7461 + } 1.7462 +#endif 1.7463 + 1.7464 + return NS_OK; 1.7465 +} 1.7466 + 1.7467 +nsresult 1.7468 +nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, 1.7469 + nsIContent* aChild, 1.7470 + nsIContent* aOldNextSibling, 1.7471 + RemoveFlags aFlags, 1.7472 + bool* aDidReconstruct) 1.7473 +{ 1.7474 + AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC); 1.7475 + NS_PRECONDITION(mUpdateCount != 0, 1.7476 + "Should be in an update while destroying frames"); 1.7477 + 1.7478 + *aDidReconstruct = false; 1.7479 + 1.7480 + // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and 1.7481 + // the :empty pseudo-class? 1.7482 + 1.7483 +#ifdef DEBUG 1.7484 + if (gNoisyContentUpdates) { 1.7485 + printf("nsCSSFrameConstructor::ContentRemoved container=%p child=%p " 1.7486 + "old-next-sibling=%p\n", 1.7487 + static_cast<void*>(aContainer), 1.7488 + static_cast<void*>(aChild), 1.7489 + static_cast<void*>(aOldNextSibling)); 1.7490 + if (gReallyNoisyContentUpdates) { 1.7491 + aContainer->List(stdout, 0); 1.7492 + } 1.7493 + } 1.7494 +#endif 1.7495 + 1.7496 + nsPresContext *presContext = mPresShell->GetPresContext(); 1.7497 + nsresult rv = NS_OK; 1.7498 + 1.7499 + // Find the child frame that maps the content 1.7500 + nsIFrame* childFrame = aChild->GetPrimaryFrame(); 1.7501 + 1.7502 + if (!childFrame || childFrame->GetContent() != aChild) { 1.7503 + // XXXbz the GetContent() != aChild check is needed due to bug 135040. 1.7504 + // Remove it once that's fixed. 1.7505 + ClearUndisplayedContentIn(aChild, aContainer); 1.7506 + } 1.7507 + 1.7508 +#ifdef MOZ_XUL 1.7509 + if (NotifyListBoxBody(presContext, aContainer, aChild, aOldNextSibling, 1.7510 + mDocument, childFrame, CONTENT_REMOVED)) 1.7511 + return NS_OK; 1.7512 + 1.7513 +#endif // MOZ_XUL 1.7514 + 1.7515 + // If we're removing the root, then make sure to remove things starting at 1.7516 + // the viewport's child instead of the primary frame (which might even be 1.7517 + // null if the root had an XBL binding or display:none, even though the 1.7518 + // frames above it got created). We do the adjustment after the childFrame 1.7519 + // check above, because we do want to clear any undisplayed content we might 1.7520 + // have for the root. Detecting removal of a root is a little exciting; in 1.7521 + // particular, having a null aContainer is necessary but NOT sufficient. Due 1.7522 + // to how we process reframes, the content node might not even be in our 1.7523 + // document by now. So explicitly check whether the viewport's first kid's 1.7524 + // content node is aChild. 1.7525 + bool isRoot = false; 1.7526 + if (!aContainer) { 1.7527 + nsIFrame* viewport = GetRootFrame(); 1.7528 + if (viewport) { 1.7529 + nsIFrame* firstChild = viewport->GetFirstPrincipalChild(); 1.7530 + if (firstChild && firstChild->GetContent() == aChild) { 1.7531 + isRoot = true; 1.7532 + childFrame = firstChild; 1.7533 + NS_ASSERTION(!childFrame->GetNextSibling(), "How did that happen?"); 1.7534 + } 1.7535 + } 1.7536 + } 1.7537 + 1.7538 + if (aContainer && aContainer->HasFlag(NODE_IS_IN_SHADOW_TREE)) { 1.7539 + // Recreate frames if content is removed from a ShadowRoot 1.7540 + // because it may contain an insertion point which can change 1.7541 + // how the host is rendered. 1.7542 + nsIContent* bindingParent = aContainer->GetBindingParent(); 1.7543 + *aDidReconstruct = true; 1.7544 + LAYOUT_PHASE_TEMP_EXIT(); 1.7545 + nsresult rv = RecreateFramesForContent(bindingParent, false); 1.7546 + LAYOUT_PHASE_TEMP_REENTER(); 1.7547 + return rv; 1.7548 + } 1.7549 + 1.7550 + if (childFrame) { 1.7551 + InvalidateCanvasIfNeeded(mPresShell, aChild); 1.7552 + 1.7553 + // See whether we need to remove more than just childFrame 1.7554 + LAYOUT_PHASE_TEMP_EXIT(); 1.7555 + if (MaybeRecreateContainerForFrameRemoval(childFrame, &rv)) { 1.7556 + LAYOUT_PHASE_TEMP_REENTER(); 1.7557 + *aDidReconstruct = true; 1.7558 + return rv; 1.7559 + } 1.7560 + LAYOUT_PHASE_TEMP_REENTER(); 1.7561 + 1.7562 + // Get the childFrame's parent frame 1.7563 + nsIFrame* parentFrame = childFrame->GetParent(); 1.7564 + nsIAtom* parentType = parentFrame->GetType(); 1.7565 + 1.7566 + if (parentType == nsGkAtoms::frameSetFrame && 1.7567 + IsSpecialFramesetChild(aChild)) { 1.7568 + // Just reframe the parent, since framesets are weird like that. 1.7569 + *aDidReconstruct = true; 1.7570 + LAYOUT_PHASE_TEMP_EXIT(); 1.7571 + nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false); 1.7572 + LAYOUT_PHASE_TEMP_REENTER(); 1.7573 + return rv; 1.7574 + } 1.7575 + 1.7576 + // If we're a child of MathML, then we should reframe the MathML content. 1.7577 + // If we're non-MathML, then we would be wrapped in a block so we need to 1.7578 + // check our grandparent in that case. 1.7579 + nsIFrame* possibleMathMLAncestor = parentType == nsGkAtoms::blockFrame ? 1.7580 + parentFrame->GetParent() : parentFrame; 1.7581 + if (possibleMathMLAncestor->IsFrameOfType(nsIFrame::eMathML)) { 1.7582 + *aDidReconstruct = true; 1.7583 + LAYOUT_PHASE_TEMP_EXIT(); 1.7584 + nsresult rv = RecreateFramesForContent(possibleMathMLAncestor->GetContent(), false); 1.7585 + LAYOUT_PHASE_TEMP_REENTER(); 1.7586 + return rv; 1.7587 + } 1.7588 + 1.7589 + // Undo XUL wrapping if it's no longer needed. 1.7590 + // (If we're in the XUL block-wrapping situation, parentFrame is the 1.7591 + // wrapper frame.) 1.7592 + nsIFrame* grandparentFrame = parentFrame->GetParent(); 1.7593 + if (grandparentFrame && grandparentFrame->IsBoxFrame() && 1.7594 + (grandparentFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) && 1.7595 + // check if this frame is the only one needing wrapping 1.7596 + aChild == AnyKidsNeedBlockParent(parentFrame->GetFirstPrincipalChild()) && 1.7597 + !AnyKidsNeedBlockParent(childFrame->GetNextSibling())) { 1.7598 + *aDidReconstruct = true; 1.7599 + LAYOUT_PHASE_TEMP_EXIT(); 1.7600 + nsresult rv = RecreateFramesForContent(grandparentFrame->GetContent(), true); 1.7601 + LAYOUT_PHASE_TEMP_REENTER(); 1.7602 + return rv; 1.7603 + } 1.7604 + 1.7605 +#ifdef ACCESSIBILITY 1.7606 + nsAccessibilityService* accService = nsIPresShell::AccService(); 1.7607 + if (accService) { 1.7608 + accService->ContentRemoved(mPresShell, aContainer, aChild); 1.7609 + } 1.7610 +#endif 1.7611 + 1.7612 + // Examine the containing-block for the removed content and see if 1.7613 + // :first-letter style applies. 1.7614 + nsIFrame* inflowChild = childFrame; 1.7615 + if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { 1.7616 + inflowChild = GetPlaceholderFrameFor(childFrame); 1.7617 + NS_ASSERTION(inflowChild, "No placeholder for out-of-flow?"); 1.7618 + } 1.7619 + nsIFrame* containingBlock = 1.7620 + GetFloatContainingBlock(inflowChild->GetParent()); 1.7621 + bool haveFLS = containingBlock && HasFirstLetterStyle(containingBlock); 1.7622 + if (haveFLS) { 1.7623 + // Trap out to special routine that handles adjusting a blocks 1.7624 + // frame tree when first-letter style is present. 1.7625 +#ifdef NOISY_FIRST_LETTER 1.7626 + printf("ContentRemoved: containingBlock="); 1.7627 + nsFrame::ListTag(stdout, containingBlock); 1.7628 + printf(" parentFrame="); 1.7629 + nsFrame::ListTag(stdout, parentFrame); 1.7630 + printf(" childFrame="); 1.7631 + nsFrame::ListTag(stdout, childFrame); 1.7632 + printf("\n"); 1.7633 +#endif 1.7634 + 1.7635 + // First update the containing blocks structure by removing the 1.7636 + // existing letter frames. This makes the subsequent logic 1.7637 + // simpler. 1.7638 + RemoveLetterFrames(presContext, mPresShell, containingBlock); 1.7639 + 1.7640 + // Recover childFrame and parentFrame 1.7641 + childFrame = aChild->GetPrimaryFrame(); 1.7642 + if (!childFrame || childFrame->GetContent() != aChild) { 1.7643 + // XXXbz the GetContent() != aChild check is needed due to bug 135040. 1.7644 + // Remove it once that's fixed. 1.7645 + ClearUndisplayedContentIn(aChild, aContainer); 1.7646 + return NS_OK; 1.7647 + } 1.7648 + parentFrame = childFrame->GetParent(); 1.7649 + parentType = parentFrame->GetType(); 1.7650 + 1.7651 +#ifdef NOISY_FIRST_LETTER 1.7652 + printf(" ==> revised parentFrame="); 1.7653 + nsFrame::ListTag(stdout, parentFrame); 1.7654 + printf(" childFrame="); 1.7655 + nsFrame::ListTag(stdout, childFrame); 1.7656 + printf("\n"); 1.7657 +#endif 1.7658 + } 1.7659 + 1.7660 +#ifdef DEBUG 1.7661 + if (gReallyNoisyContentUpdates) { 1.7662 + printf("nsCSSFrameConstructor::ContentRemoved: childFrame="); 1.7663 + nsFrame::ListTag(stdout, childFrame); 1.7664 + putchar('\n'); 1.7665 + parentFrame->List(stdout, 0); 1.7666 + } 1.7667 +#endif 1.7668 + 1.7669 + 1.7670 + // Notify the parent frame that it should delete the frame 1.7671 + if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { 1.7672 + childFrame = GetPlaceholderFrameFor(childFrame); 1.7673 + NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow."); 1.7674 + parentFrame = childFrame->GetParent(); 1.7675 + } 1.7676 + rv = RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame), 1.7677 + childFrame); 1.7678 + //XXXfr NS_ENSURE_SUCCESS(rv, rv) ? 1.7679 + 1.7680 + if (isRoot) { 1.7681 + mRootElementFrame = nullptr; 1.7682 + mRootElementStyleFrame = nullptr; 1.7683 + mDocElementContainingBlock = nullptr; 1.7684 + mPageSequenceFrame = nullptr; 1.7685 + mGfxScrollFrame = nullptr; 1.7686 + mHasRootAbsPosContainingBlock = false; 1.7687 + mFixedContainingBlock = GetRootFrame(); 1.7688 + } 1.7689 + 1.7690 + if (haveFLS && mRootElementFrame) { 1.7691 + RecoverLetterFrames(containingBlock); 1.7692 + } 1.7693 + 1.7694 + // If we're just reconstructing frames for the element, then the 1.7695 + // following ContentInserted notification on the element will 1.7696 + // take care of fixing up any adjacent text nodes. We don't need 1.7697 + // to do this if the table parent type of our parent type is not 1.7698 + // eTypeBlock, though, because in that case the whitespace isn't 1.7699 + // being suppressed due to us anyway. 1.7700 + if (aContainer && !aChild->IsRootOfAnonymousSubtree() && 1.7701 + aFlags != REMOVE_FOR_RECONSTRUCTION && 1.7702 + GetParentType(parentType) == eTypeBlock) { 1.7703 + // Adjacent whitespace-only text nodes might have been suppressed if 1.7704 + // this node does not have inline ends. Create frames for them now 1.7705 + // if necessary. 1.7706 + // Reframe any text node just before the node being removed, if there is 1.7707 + // one, and if it's not the last child or the first child. If a whitespace 1.7708 + // textframe was being suppressed and it's now the last child or first 1.7709 + // child then it can stay suppressed since the parent must be a block 1.7710 + // and hence it's adjacent to a block end. 1.7711 + // If aOldNextSibling is null, then the text node before the node being 1.7712 + // removed is the last node, and we don't need to worry about it. 1.7713 + if (aOldNextSibling) { 1.7714 + nsIContent* prevSibling = aOldNextSibling->GetPreviousSibling(); 1.7715 + if (prevSibling && prevSibling->GetPreviousSibling()) { 1.7716 + LAYOUT_PHASE_TEMP_EXIT(); 1.7717 + ReframeTextIfNeeded(aContainer, prevSibling); 1.7718 + LAYOUT_PHASE_TEMP_REENTER(); 1.7719 + } 1.7720 + } 1.7721 + // Reframe any text node just after the node being removed, if there is 1.7722 + // one, and if it's not the last child or the first child. 1.7723 + if (aOldNextSibling && aOldNextSibling->GetNextSibling() && 1.7724 + aOldNextSibling->GetPreviousSibling()) { 1.7725 + LAYOUT_PHASE_TEMP_EXIT(); 1.7726 + ReframeTextIfNeeded(aContainer, aOldNextSibling); 1.7727 + LAYOUT_PHASE_TEMP_REENTER(); 1.7728 + } 1.7729 + } 1.7730 + 1.7731 +#ifdef DEBUG 1.7732 + if (gReallyNoisyContentUpdates && parentFrame) { 1.7733 + printf("nsCSSFrameConstructor::ContentRemoved: resulting frame model:\n"); 1.7734 + parentFrame->List(stdout, 0); 1.7735 + } 1.7736 +#endif 1.7737 + } 1.7738 + 1.7739 + return rv; 1.7740 +} 1.7741 + 1.7742 +/** 1.7743 + * This method invalidates the canvas when frames are removed or added for a 1.7744 + * node that might have its background propagated to the canvas, i.e., a 1.7745 + * document root node or an HTML BODY which is a child of the root node. 1.7746 + * 1.7747 + * @param aFrame a frame for a content node about to be removed or a frame that 1.7748 + * was just created for a content node that was inserted. 1.7749 + */ 1.7750 +static void 1.7751 +InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node) 1.7752 +{ 1.7753 + NS_PRECONDITION(presShell->GetRootFrame(), "What happened here?"); 1.7754 + NS_PRECONDITION(presShell->GetPresContext(), "Say what?"); 1.7755 + 1.7756 + // Note that both in ContentRemoved and ContentInserted the content node 1.7757 + // will still have the right parent pointer, so looking at that is ok. 1.7758 + 1.7759 + nsIContent* parent = node->GetParent(); 1.7760 + if (parent) { 1.7761 + // Has a parent; might not be what we want 1.7762 + nsIContent* grandParent = parent->GetParent(); 1.7763 + if (grandParent) { 1.7764 + // Has a grandparent, so not what we want 1.7765 + return; 1.7766 + } 1.7767 + 1.7768 + // Check whether it's an HTML body 1.7769 + if (node->Tag() != nsGkAtoms::body || 1.7770 + !node->IsHTML()) { 1.7771 + return; 1.7772 + } 1.7773 + } 1.7774 + 1.7775 + // At this point the node has no parent or it's an HTML <body> child of the 1.7776 + // root. We might not need to invalidate in this case (eg we might be in 1.7777 + // XHTML or something), but chances are we want to. Play it safe. 1.7778 + // Invalidate the viewport. 1.7779 + 1.7780 + nsIFrame* rootFrame = presShell->GetRootFrame(); 1.7781 + rootFrame->InvalidateFrameSubtree(); 1.7782 +} 1.7783 + 1.7784 +nsIFrame* 1.7785 +nsCSSFrameConstructor::EnsureFrameForTextNode(nsGenericDOMDataNode* aContent) 1.7786 +{ 1.7787 + if (aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) && 1.7788 + !mAlwaysCreateFramesForIgnorableWhitespace) { 1.7789 + // Text frame may have been suppressed. Disable suppression and signal 1.7790 + // that a flush should be performed. We do this on a document-wide 1.7791 + // basis so that pages that repeatedly query metrics for 1.7792 + // collapsed-whitespace text nodes don't trigger pathological behavior. 1.7793 + mAlwaysCreateFramesForIgnorableWhitespace = true; 1.7794 + nsAutoScriptBlocker blocker; 1.7795 + BeginUpdate(); 1.7796 + ReconstructDocElementHierarchy(); 1.7797 + EndUpdate(); 1.7798 + } 1.7799 + return aContent->GetPrimaryFrame(); 1.7800 +} 1.7801 + 1.7802 +nsresult 1.7803 +nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent, 1.7804 + CharacterDataChangeInfo* aInfo) 1.7805 +{ 1.7806 + AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC); 1.7807 + nsresult rv = NS_OK; 1.7808 + 1.7809 + if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) && 1.7810 + !aContent->TextIsOnlyWhitespace()) || 1.7811 + (aContent->HasFlag(NS_REFRAME_IF_WHITESPACE) && 1.7812 + aContent->TextIsOnlyWhitespace())) { 1.7813 +#ifdef DEBUG 1.7814 + nsIFrame* frame = aContent->GetPrimaryFrame(); 1.7815 + NS_ASSERTION(!frame || !frame->IsGeneratedContentFrame(), 1.7816 + "Bit should never be set on generated content"); 1.7817 +#endif 1.7818 + LAYOUT_PHASE_TEMP_EXIT(); 1.7819 + nsresult rv = RecreateFramesForContent(aContent, false); 1.7820 + LAYOUT_PHASE_TEMP_REENTER(); 1.7821 + return rv; 1.7822 + } 1.7823 + 1.7824 + // Find the child frame 1.7825 + nsIFrame* frame = aContent->GetPrimaryFrame(); 1.7826 + 1.7827 + // Notify the first frame that maps the content. It will generate a reflow 1.7828 + // command 1.7829 + 1.7830 + // It's possible the frame whose content changed isn't inserted into the 1.7831 + // frame hierarchy yet, or that there is no frame that maps the content 1.7832 + if (nullptr != frame) { 1.7833 +#if 0 1.7834 + NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, 1.7835 + ("nsCSSFrameConstructor::CharacterDataChanged: content=%p[%s] subcontent=%p frame=%p", 1.7836 + aContent, ContentTag(aContent, 0), 1.7837 + aSubContent, frame)); 1.7838 +#endif 1.7839 + 1.7840 + // Special check for text content that is a child of a letter frame. If 1.7841 + // this happens, we should remove the letter frame, do whatever we're 1.7842 + // planning to do with this notification, then put the letter frame back. 1.7843 + // Note that this is basically what RecreateFramesForContent ends up doing; 1.7844 + // the reason we dont' want to call that here is that our text content 1.7845 + // could be native anonymous, in which case RecreateFramesForContent would 1.7846 + // completely barf on it. And recreating the non-anonymous ancestor would 1.7847 + // just lead us to come back into this notification (e.g. if quotes or 1.7848 + // counters are involved), leading to a loop. 1.7849 + nsIFrame* block = GetFloatContainingBlock(frame); 1.7850 + bool haveFirstLetterStyle = false; 1.7851 + if (block) { 1.7852 + // See if the block has first-letter style applied to it. 1.7853 + haveFirstLetterStyle = HasFirstLetterStyle(block); 1.7854 + if (haveFirstLetterStyle) { 1.7855 + RemoveLetterFrames(mPresShell->GetPresContext(), mPresShell, 1.7856 + block); 1.7857 + // Reget |frame|, since we might have killed it. 1.7858 + // Do we really need to call CharacterDataChanged in this case, though? 1.7859 + frame = aContent->GetPrimaryFrame(); 1.7860 + NS_ASSERTION(frame, "Should have frame here!"); 1.7861 + } 1.7862 + } 1.7863 + 1.7864 + frame->CharacterDataChanged(aInfo); 1.7865 + 1.7866 + if (haveFirstLetterStyle) { 1.7867 + RecoverLetterFrames(block); 1.7868 + } 1.7869 + } 1.7870 + 1.7871 + return rv; 1.7872 +} 1.7873 + 1.7874 +void 1.7875 +nsCSSFrameConstructor::BeginUpdate() { 1.7876 + NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), 1.7877 + "Someone forgot a script blocker"); 1.7878 + 1.7879 + nsRootPresContext* rootPresContext = 1.7880 + mPresShell->GetPresContext()->GetRootPresContext(); 1.7881 + if (rootPresContext) { 1.7882 + rootPresContext->IncrementDOMGeneration(); 1.7883 + } 1.7884 + 1.7885 + ++sGlobalGenerationNumber; 1.7886 + ++mUpdateCount; 1.7887 +} 1.7888 + 1.7889 +void 1.7890 +nsCSSFrameConstructor::EndUpdate() 1.7891 +{ 1.7892 + if (mUpdateCount == 1) { 1.7893 + // This is the end of our last update. Before we decrement 1.7894 + // mUpdateCount, recalc quotes and counters as needed. 1.7895 + 1.7896 + RecalcQuotesAndCounters(); 1.7897 + NS_ASSERTION(mUpdateCount == 1, "Odd update count"); 1.7898 + } 1.7899 + NS_ASSERTION(mUpdateCount, "Negative mUpdateCount!"); 1.7900 + --mUpdateCount; 1.7901 +} 1.7902 + 1.7903 +void 1.7904 +nsCSSFrameConstructor::RecalcQuotesAndCounters() 1.7905 +{ 1.7906 + if (mQuotesDirty) { 1.7907 + mQuotesDirty = false; 1.7908 + mQuoteList.RecalcAll(); 1.7909 + } 1.7910 + 1.7911 + if (mCountersDirty) { 1.7912 + mCountersDirty = false; 1.7913 + mCounterManager.RecalcAll(); 1.7914 + } 1.7915 + 1.7916 + NS_ASSERTION(!mQuotesDirty, "Quotes updates will be lost"); 1.7917 + NS_ASSERTION(!mCountersDirty, "Counter updates will be lost"); 1.7918 +} 1.7919 + 1.7920 +void 1.7921 +nsCSSFrameConstructor::WillDestroyFrameTree() 1.7922 +{ 1.7923 +#if defined(DEBUG_dbaron_off) 1.7924 + mCounterManager.Dump(); 1.7925 +#endif 1.7926 + 1.7927 + mIsDestroyingFrameTree = true; 1.7928 + 1.7929 + // Prevent frame tree destruction from being O(N^2) 1.7930 + mQuoteList.Clear(); 1.7931 + mCounterManager.Clear(); 1.7932 + 1.7933 + // Remove our presshell as a style flush observer. But leave 1.7934 + // RestyleManager::mObservingRefreshDriver true so we don't readd to 1.7935 + // it even if someone tries to post restyle events on us from this 1.7936 + // point on for some reason. 1.7937 + mPresShell->GetPresContext()->RefreshDriver()-> 1.7938 + RemoveStyleFlushObserver(mPresShell); 1.7939 + 1.7940 + nsFrameManager::Destroy(); 1.7941 +} 1.7942 + 1.7943 +//STATIC 1.7944 + 1.7945 +// XXXbz I'd really like this method to go away. Once we have inline-block and 1.7946 +// I can just use that for sized broken images, that can happen, maybe. 1.7947 +void nsCSSFrameConstructor::GetAlternateTextFor(nsIContent* aContent, 1.7948 + nsIAtom* aTag, // content object's tag 1.7949 + nsXPIDLString& aAltText) 1.7950 +{ 1.7951 + // The "alt" attribute specifies alternate text that is rendered 1.7952 + // when the image can not be displayed 1.7953 + 1.7954 + // If there's no "alt" attribute, and aContent is an input 1.7955 + // element, then use the value of the "value" attribute 1.7956 + if (!aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aAltText) && 1.7957 + nsGkAtoms::input == aTag) { 1.7958 + // If there's no "value" attribute either, then use the localized string 1.7959 + // for "Submit" as the alternate text. 1.7960 + if (!aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aAltText)) { 1.7961 + nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES, 1.7962 + "Submit", aAltText); 1.7963 + } 1.7964 + } 1.7965 +} 1.7966 + 1.7967 +nsIFrame* 1.7968 +nsCSSFrameConstructor::CreateContinuingOuterTableFrame(nsIPresShell* aPresShell, 1.7969 + nsPresContext* aPresContext, 1.7970 + nsIFrame* aFrame, 1.7971 + nsIFrame* aParentFrame, 1.7972 + nsIContent* aContent, 1.7973 + nsStyleContext* aStyleContext) 1.7974 +{ 1.7975 + nsIFrame* newFrame = NS_NewTableOuterFrame(aPresShell, aStyleContext); 1.7976 + 1.7977 + newFrame->Init(aContent, aParentFrame, aFrame); 1.7978 + 1.7979 + // Create a continuing inner table frame, and if there's a caption then 1.7980 + // replicate the caption 1.7981 + nsFrameItems newChildFrames; 1.7982 + 1.7983 + nsIFrame* childFrame = aFrame->GetFirstPrincipalChild(); 1.7984 + if (childFrame) { 1.7985 + nsIFrame* continuingTableFrame = 1.7986 + CreateContinuingFrame(aPresContext, childFrame, newFrame); 1.7987 + newChildFrames.AddChild(continuingTableFrame); 1.7988 + 1.7989 + NS_ASSERTION(!childFrame->GetNextSibling(),"there can be only one inner table frame"); 1.7990 + } 1.7991 + 1.7992 + // Set the outer table's initial child list 1.7993 + newFrame->SetInitialChildList(kPrincipalList, newChildFrames); 1.7994 + 1.7995 + return newFrame; 1.7996 +} 1.7997 + 1.7998 +nsIFrame* 1.7999 +nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell* aPresShell, 1.8000 + nsPresContext* aPresContext, 1.8001 + nsIFrame* aFrame, 1.8002 + nsIFrame* aParentFrame, 1.8003 + nsIContent* aContent, 1.8004 + nsStyleContext* aStyleContext) 1.8005 +{ 1.8006 + nsIFrame* newFrame = NS_NewTableFrame(aPresShell, aStyleContext); 1.8007 + 1.8008 + newFrame->Init(aContent, aParentFrame, aFrame); 1.8009 + 1.8010 + // Replicate any header/footer frames 1.8011 + nsFrameItems childFrames; 1.8012 + nsIFrame* childFrame = aFrame->GetFirstPrincipalChild(); 1.8013 + for ( ; childFrame; childFrame = childFrame->GetNextSibling()) { 1.8014 + // See if it's a header/footer, possibly wrapped in a scroll frame. 1.8015 + nsTableRowGroupFrame* rowGroupFrame = 1.8016 + static_cast<nsTableRowGroupFrame*>(childFrame); 1.8017 + // If the row group was continued, then don't replicate it. 1.8018 + nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow(); 1.8019 + if (rgNextInFlow) { 1.8020 + rowGroupFrame->SetRepeatable(false); 1.8021 + } 1.8022 + else if (rowGroupFrame->IsRepeatable()) { 1.8023 + // Replicate the header/footer frame. 1.8024 + nsTableRowGroupFrame* headerFooterFrame; 1.8025 + nsFrameItems childItems; 1.8026 + nsFrameConstructorState state(mPresShell, 1.8027 + GetAbsoluteContainingBlock(newFrame, FIXED_POS), 1.8028 + GetAbsoluteContainingBlock(newFrame, ABS_POS), 1.8029 + nullptr); 1.8030 + state.mCreatingExtraFrames = true; 1.8031 + 1.8032 + nsStyleContext* const headerFooterStyleContext = rowGroupFrame->StyleContext(); 1.8033 + headerFooterFrame = static_cast<nsTableRowGroupFrame*> 1.8034 + (NS_NewTableRowGroupFrame(aPresShell, headerFooterStyleContext)); 1.8035 + 1.8036 + nsIContent* headerFooter = rowGroupFrame->GetContent(); 1.8037 + headerFooterFrame->Init(headerFooter, newFrame, nullptr); 1.8038 + 1.8039 + nsFrameConstructorSaveState absoluteSaveState; 1.8040 + MakeTablePartAbsoluteContainingBlockIfNeeded(state, 1.8041 + headerFooterStyleContext->StyleDisplay(), 1.8042 + absoluteSaveState, 1.8043 + headerFooterFrame); 1.8044 + 1.8045 + ProcessChildren(state, headerFooter, rowGroupFrame->StyleContext(), 1.8046 + headerFooterFrame, true, childItems, false, 1.8047 + nullptr); 1.8048 + NS_ASSERTION(state.mFloatedItems.IsEmpty(), "unexpected floated element"); 1.8049 + headerFooterFrame->SetInitialChildList(kPrincipalList, childItems); 1.8050 + headerFooterFrame->SetRepeatable(true); 1.8051 + 1.8052 + // Table specific initialization 1.8053 + headerFooterFrame->InitRepeatedFrame(aPresContext, rowGroupFrame); 1.8054 + 1.8055 + // XXX Deal with absolute and fixed frames... 1.8056 + childFrames.AddChild(headerFooterFrame); 1.8057 + } 1.8058 + } 1.8059 + 1.8060 + // Set the table frame's initial child list 1.8061 + newFrame->SetInitialChildList(kPrincipalList, childFrames); 1.8062 + 1.8063 + return newFrame; 1.8064 +} 1.8065 + 1.8066 +nsIFrame* 1.8067 +nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext, 1.8068 + nsIFrame* aFrame, 1.8069 + nsIFrame* aParentFrame, 1.8070 + bool aIsFluid) 1.8071 +{ 1.8072 + nsIPresShell* shell = aPresContext->PresShell(); 1.8073 + nsStyleContext* styleContext = aFrame->StyleContext(); 1.8074 + nsIFrame* newFrame = nullptr; 1.8075 + nsIFrame* nextContinuation = aFrame->GetNextContinuation(); 1.8076 + nsIFrame* nextInFlow = aFrame->GetNextInFlow(); 1.8077 + 1.8078 + // Use the frame type to determine what type of frame to create 1.8079 + nsIAtom* frameType = aFrame->GetType(); 1.8080 + nsIContent* content = aFrame->GetContent(); 1.8081 + 1.8082 + NS_ASSERTION(aFrame->GetSplittableType() != NS_FRAME_NOT_SPLITTABLE, 1.8083 + "why CreateContinuingFrame for a non-splittable frame?"); 1.8084 + 1.8085 + if (nsGkAtoms::textFrame == frameType) { 1.8086 + newFrame = NS_NewContinuingTextFrame(shell, styleContext); 1.8087 + newFrame->Init(content, aParentFrame, aFrame); 1.8088 + } else if (nsGkAtoms::inlineFrame == frameType) { 1.8089 + newFrame = NS_NewInlineFrame(shell, styleContext); 1.8090 + newFrame->Init(content, aParentFrame, aFrame); 1.8091 + } else if (nsGkAtoms::blockFrame == frameType) { 1.8092 + newFrame = NS_NewBlockFrame(shell, styleContext); 1.8093 + newFrame->Init(content, aParentFrame, aFrame); 1.8094 +#ifdef MOZ_XUL 1.8095 + } else if (nsGkAtoms::XULLabelFrame == frameType) { 1.8096 + newFrame = NS_NewXULLabelFrame(shell, styleContext); 1.8097 + newFrame->Init(content, aParentFrame, aFrame); 1.8098 +#endif 1.8099 + } else if (nsGkAtoms::columnSetFrame == frameType) { 1.8100 + newFrame = NS_NewColumnSetFrame(shell, styleContext, nsFrameState(0)); 1.8101 + newFrame->Init(content, aParentFrame, aFrame); 1.8102 + } else if (nsGkAtoms::pageFrame == frameType) { 1.8103 + nsIFrame* canvasFrame; 1.8104 + newFrame = ConstructPageFrame(shell, aPresContext, aParentFrame, aFrame, 1.8105 + canvasFrame); 1.8106 + } else if (nsGkAtoms::tableOuterFrame == frameType) { 1.8107 + newFrame = 1.8108 + CreateContinuingOuterTableFrame(shell, aPresContext, aFrame, aParentFrame, 1.8109 + content, styleContext); 1.8110 + 1.8111 + } else if (nsGkAtoms::tableFrame == frameType) { 1.8112 + newFrame = 1.8113 + CreateContinuingTableFrame(shell, aPresContext, aFrame, aParentFrame, 1.8114 + content, styleContext); 1.8115 + 1.8116 + } else if (nsGkAtoms::tableRowGroupFrame == frameType) { 1.8117 + newFrame = NS_NewTableRowGroupFrame(shell, styleContext); 1.8118 + newFrame->Init(content, aParentFrame, aFrame); 1.8119 + if (newFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) { 1.8120 + nsTableFrame::RegisterPositionedTablePart(newFrame); 1.8121 + } 1.8122 + } else if (nsGkAtoms::tableRowFrame == frameType) { 1.8123 + newFrame = NS_NewTableRowFrame(shell, styleContext); 1.8124 + 1.8125 + newFrame->Init(content, aParentFrame, aFrame); 1.8126 + if (newFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) { 1.8127 + nsTableFrame::RegisterPositionedTablePart(newFrame); 1.8128 + } 1.8129 + 1.8130 + // Create a continuing frame for each table cell frame 1.8131 + nsFrameItems newChildList; 1.8132 + nsIFrame* cellFrame = aFrame->GetFirstPrincipalChild(); 1.8133 + while (cellFrame) { 1.8134 + // See if it's a table cell frame 1.8135 + if (IS_TABLE_CELL(cellFrame->GetType())) { 1.8136 + nsIFrame* continuingCellFrame = 1.8137 + CreateContinuingFrame(aPresContext, cellFrame, newFrame); 1.8138 + newChildList.AddChild(continuingCellFrame); 1.8139 + } 1.8140 + cellFrame = cellFrame->GetNextSibling(); 1.8141 + } 1.8142 + 1.8143 + // Set the table cell's initial child list 1.8144 + newFrame->SetInitialChildList(kPrincipalList, newChildList); 1.8145 + 1.8146 + } else if (IS_TABLE_CELL(frameType)) { 1.8147 + // Warning: If you change this and add a wrapper frame around table cell 1.8148 + // frames, make sure Bug 368554 doesn't regress! 1.8149 + // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp. 1.8150 + newFrame = NS_NewTableCellFrame(shell, styleContext, IsBorderCollapse(aParentFrame)); 1.8151 + 1.8152 + newFrame->Init(content, aParentFrame, aFrame); 1.8153 + if (newFrame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) { 1.8154 + nsTableFrame::RegisterPositionedTablePart(newFrame); 1.8155 + } 1.8156 + 1.8157 + // Create a continuing area frame 1.8158 + nsIFrame* blockFrame = aFrame->GetFirstPrincipalChild(); 1.8159 + nsIFrame* continuingBlockFrame = 1.8160 + CreateContinuingFrame(aPresContext, blockFrame, newFrame); 1.8161 + 1.8162 + // Set the table cell's initial child list 1.8163 + SetInitialSingleChild(newFrame, continuingBlockFrame); 1.8164 + } else if (nsGkAtoms::lineFrame == frameType) { 1.8165 + newFrame = NS_NewFirstLineFrame(shell, styleContext); 1.8166 + newFrame->Init(content, aParentFrame, aFrame); 1.8167 + } else if (nsGkAtoms::letterFrame == frameType) { 1.8168 + newFrame = NS_NewFirstLetterFrame(shell, styleContext); 1.8169 + newFrame->Init(content, aParentFrame, aFrame); 1.8170 + } else if (nsGkAtoms::imageFrame == frameType) { 1.8171 + newFrame = NS_NewImageFrame(shell, styleContext); 1.8172 + newFrame->Init(content, aParentFrame, aFrame); 1.8173 + } else if (nsGkAtoms::imageControlFrame == frameType) { 1.8174 + newFrame = NS_NewImageControlFrame(shell, styleContext); 1.8175 + newFrame->Init(content, aParentFrame, aFrame); 1.8176 + } else if (nsGkAtoms::placeholderFrame == frameType) { 1.8177 + // create a continuing out of flow frame 1.8178 + nsIFrame* oofFrame = nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame); 1.8179 + nsIFrame* oofContFrame = 1.8180 + CreateContinuingFrame(aPresContext, oofFrame, aParentFrame); 1.8181 + newFrame = 1.8182 + CreatePlaceholderFrameFor(shell, content, oofContFrame, styleContext, 1.8183 + aParentFrame, aFrame, 1.8184 + aFrame->GetStateBits() & PLACEHOLDER_TYPE_MASK); 1.8185 + } else if (nsGkAtoms::fieldSetFrame == frameType) { 1.8186 + newFrame = NS_NewFieldSetFrame(shell, styleContext); 1.8187 + 1.8188 + newFrame->Init(content, aParentFrame, aFrame); 1.8189 + 1.8190 + // Create a continuing area frame 1.8191 + // XXXbz we really shouldn't have to do this by hand! 1.8192 + nsIFrame* blockFrame = GetFieldSetBlockFrame(aFrame); 1.8193 + if (blockFrame) { 1.8194 + nsIFrame* continuingBlockFrame = 1.8195 + CreateContinuingFrame(aPresContext, blockFrame, newFrame); 1.8196 + // Set the fieldset's initial child list 1.8197 + SetInitialSingleChild(newFrame, continuingBlockFrame); 1.8198 + } else { 1.8199 + MOZ_ASSERT(aFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER, 1.8200 + "FieldSet block may only be null for overflow containers"); 1.8201 + } 1.8202 + } else if (nsGkAtoms::legendFrame == frameType) { 1.8203 + newFrame = NS_NewLegendFrame(shell, styleContext); 1.8204 + newFrame->Init(content, aParentFrame, aFrame); 1.8205 + } else if (nsGkAtoms::flexContainerFrame == frameType) { 1.8206 + newFrame = NS_NewFlexContainerFrame(shell, styleContext); 1.8207 + newFrame->Init(content, aParentFrame, aFrame); 1.8208 + } else { 1.8209 + NS_RUNTIMEABORT("unexpected frame type"); 1.8210 + } 1.8211 + 1.8212 + // Init() set newFrame to be a fluid continuation of aFrame. 1.8213 + // If we want a non-fluid continuation, we need to call SetPrevContinuation() 1.8214 + // to reset NS_FRAME_IS_FLUID_CONTINUATION. 1.8215 + if (!aIsFluid) { 1.8216 + newFrame->SetPrevContinuation(aFrame); 1.8217 + } 1.8218 + 1.8219 + // A continuation of generated content is also generated content 1.8220 + if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) { 1.8221 + newFrame->AddStateBits(NS_FRAME_GENERATED_CONTENT); 1.8222 + } 1.8223 + 1.8224 + // A continuation of nsIAnonymousContentCreator content is also 1.8225 + // nsIAnonymousContentCreator created content 1.8226 + if (aFrame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) { 1.8227 + newFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT); 1.8228 + } 1.8229 + 1.8230 + // A continuation of an out-of-flow is also an out-of-flow 1.8231 + if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { 1.8232 + newFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW); 1.8233 + } 1.8234 + 1.8235 + if (nextInFlow) { 1.8236 + nextInFlow->SetPrevInFlow(newFrame); 1.8237 + newFrame->SetNextInFlow(nextInFlow); 1.8238 + } else if (nextContinuation) { 1.8239 + nextContinuation->SetPrevContinuation(newFrame); 1.8240 + newFrame->SetNextContinuation(nextContinuation); 1.8241 + } 1.8242 + 1.8243 + NS_POSTCONDITION(!newFrame->GetNextSibling(), "unexpected sibling"); 1.8244 + return newFrame; 1.8245 +} 1.8246 + 1.8247 +nsresult 1.8248 +nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame) 1.8249 +{ 1.8250 + // Now deal with fixed-pos things.... They should appear on all pages, 1.8251 + // so we want to move over the placeholders when processing the child 1.8252 + // of the pageContentFrame. 1.8253 + 1.8254 + nsIFrame* prevPageContentFrame = aParentFrame->GetPrevInFlow(); 1.8255 + if (!prevPageContentFrame) { 1.8256 + return NS_OK; 1.8257 + } 1.8258 + nsIFrame* canvasFrame = aParentFrame->GetFirstPrincipalChild(); 1.8259 + nsIFrame* prevCanvasFrame = prevPageContentFrame->GetFirstPrincipalChild(); 1.8260 + if (!canvasFrame || !prevCanvasFrame) { 1.8261 + // document's root element frame missing 1.8262 + return NS_ERROR_UNEXPECTED; 1.8263 + } 1.8264 + 1.8265 + nsFrameItems fixedPlaceholders; 1.8266 + nsIFrame* firstFixed = prevPageContentFrame->GetFirstChild(nsIFrame::kFixedList); 1.8267 + if (!firstFixed) { 1.8268 + return NS_OK; 1.8269 + } 1.8270 + 1.8271 + // Don't allow abs-pos descendants of the fixed content to escape the content. 1.8272 + // This should not normally be possible (because fixed-pos elements should 1.8273 + // be absolute containers) but fixed-pos tables currently aren't abs-pos 1.8274 + // containers. 1.8275 + nsFrameConstructorState state(mPresShell, aParentFrame, 1.8276 + nullptr, 1.8277 + mRootElementFrame); 1.8278 + state.mCreatingExtraFrames = true; 1.8279 + 1.8280 + // We can't use an ancestor filter here, because we're not going to 1.8281 + // be usefully recurring down the tree. This means that other 1.8282 + // places in frame construction can't assume a filter is 1.8283 + // initialized! 1.8284 + 1.8285 + // Iterate across fixed frames and replicate each whose placeholder is a 1.8286 + // descendant of aFrame. (We don't want to explicitly copy placeholders that 1.8287 + // are within fixed frames, because that would cause duplicates on the new 1.8288 + // page - bug 389619) 1.8289 + for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) { 1.8290 + nsIFrame* prevPlaceholder = GetPlaceholderFrameFor(fixed); 1.8291 + if (prevPlaceholder && 1.8292 + nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) { 1.8293 + // We want to use the same style as the primary style frame for 1.8294 + // our content 1.8295 + nsIContent* content = fixed->GetContent(); 1.8296 + nsStyleContext* styleContext = 1.8297 + nsLayoutUtils::GetStyleFrame(content)->StyleContext(); 1.8298 + FrameConstructionItemList items; 1.8299 + AddFrameConstructionItemsInternal(state, content, canvasFrame, 1.8300 + content->Tag(), 1.8301 + content->GetNameSpaceID(), 1.8302 + true, 1.8303 + styleContext, 1.8304 + ITEM_ALLOW_XBL_BASE | 1.8305 + ITEM_ALLOW_PAGE_BREAK, 1.8306 + nullptr, items); 1.8307 + ConstructFramesFromItemList(state, items, canvasFrame, fixedPlaceholders); 1.8308 + } 1.8309 + } 1.8310 + 1.8311 + // Add the placeholders to our primary child list. 1.8312 + // XXXbz this is a little screwed up, since the fixed frames will have 1.8313 + // broken auto-positioning. Oh, well. 1.8314 + NS_ASSERTION(!canvasFrame->GetFirstPrincipalChild(), 1.8315 + "leaking frames; doc root continuation must be empty"); 1.8316 + canvasFrame->SetInitialChildList(kPrincipalList, fixedPlaceholders); 1.8317 + return NS_OK; 1.8318 +} 1.8319 + 1.8320 +nsIFrame* 1.8321 +nsCSSFrameConstructor::GetInsertionPoint(nsIContent* aContainer, 1.8322 + nsIContent* aChildContent, 1.8323 + bool* aMultiple) 1.8324 +{ 1.8325 + nsBindingManager *bindingManager = mDocument->BindingManager(); 1.8326 + 1.8327 + nsIContent* insertionElement; 1.8328 + if (aChildContent) { 1.8329 + // We've got an explicit insertion child. Check to see if it's 1.8330 + // anonymous. 1.8331 + if (aChildContent->GetBindingParent() == aContainer) { 1.8332 + // This child content is anonymous. Don't use the insertion 1.8333 + // point, since that's only for the explicit kids. 1.8334 + return GetFrameFor(aContainer); 1.8335 + } 1.8336 + 1.8337 + insertionElement = bindingManager->FindNestedInsertionPoint(aContainer, aChildContent); 1.8338 + } 1.8339 + else { 1.8340 + bool multiple; 1.8341 + insertionElement = bindingManager->FindNestedSingleInsertionPoint(aContainer, &multiple); 1.8342 + 1.8343 + if (multiple) { 1.8344 + if (aMultiple) { 1.8345 + *aMultiple = true; 1.8346 + } 1.8347 + return nullptr; 1.8348 + } 1.8349 + } 1.8350 + 1.8351 + if (!insertionElement) { 1.8352 + insertionElement = aContainer; 1.8353 + } 1.8354 + 1.8355 + nsIFrame* insertionPoint = GetFrameFor(insertionElement); 1.8356 + 1.8357 + // fieldsets have multiple insertion points. Note that we might 1.8358 + // have to look at insertionElement here... 1.8359 + if (aMultiple && insertionElement->IsHTML(nsGkAtoms::fieldset)) { 1.8360 + *aMultiple = true; 1.8361 + } 1.8362 + 1.8363 + return insertionPoint; 1.8364 +} 1.8365 + 1.8366 +// Capture state for the frame tree rooted at the frame associated with the 1.8367 +// content object, aContent 1.8368 +void 1.8369 +nsCSSFrameConstructor::CaptureStateForFramesOf(nsIContent* aContent, 1.8370 + nsILayoutHistoryState* aHistoryState) 1.8371 +{ 1.8372 + if (!aHistoryState) { 1.8373 + return; 1.8374 + } 1.8375 + nsIFrame* frame = aContent->GetPrimaryFrame(); 1.8376 + if (frame == mRootElementFrame) { 1.8377 + frame = mFixedContainingBlock; 1.8378 + } 1.8379 + for ( ; frame; 1.8380 + frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame)) { 1.8381 + CaptureFrameState(frame, aHistoryState); 1.8382 + } 1.8383 +} 1.8384 + 1.8385 +static bool EqualURIs(mozilla::css::URLValue *aURI1, 1.8386 + mozilla::css::URLValue *aURI2) 1.8387 +{ 1.8388 + return aURI1 == aURI2 || // handle null==null, and optimize 1.8389 + (aURI1 && aURI2 && aURI1->URIEquals(*aURI2)); 1.8390 +} 1.8391 + 1.8392 +nsresult 1.8393 +nsCSSFrameConstructor::MaybeRecreateFramesForElement(Element* aElement) 1.8394 +{ 1.8395 + nsRefPtr<nsStyleContext> oldContext = GetUndisplayedContent(aElement); 1.8396 + if (!oldContext) { 1.8397 + return NS_OK; 1.8398 + } 1.8399 + 1.8400 + // The parent has a frame, so try resolving a new context. 1.8401 + nsRefPtr<nsStyleContext> newContext = mPresShell->StyleSet()-> 1.8402 + ResolveStyleFor(aElement, oldContext->GetParent()); 1.8403 + 1.8404 + ChangeUndisplayedContent(aElement, newContext); 1.8405 + const nsStyleDisplay* disp = newContext->StyleDisplay(); 1.8406 + if (disp->mDisplay == NS_STYLE_DISPLAY_NONE) { 1.8407 + // We can skip trying to recreate frames here, but only if our style 1.8408 + // context does not have a binding URI that differs from our old one. 1.8409 + // Otherwise, we should try to recreate, because we may want to apply the 1.8410 + // new binding 1.8411 + if (!disp->mBinding) { 1.8412 + return NS_OK; 1.8413 + } 1.8414 + const nsStyleDisplay* oldDisp = oldContext->PeekStyleDisplay(); 1.8415 + if (oldDisp && EqualURIs(disp->mBinding, oldDisp->mBinding)) { 1.8416 + return NS_OK; 1.8417 + } 1.8418 + } 1.8419 + 1.8420 + return RecreateFramesForContent(aElement, false); 1.8421 +} 1.8422 + 1.8423 +static nsIFrame* 1.8424 +FindFirstNonWhitespaceChild(nsIFrame* aParentFrame) 1.8425 +{ 1.8426 + nsIFrame* f = aParentFrame->GetFirstPrincipalChild(); 1.8427 + while (f && f->GetType() == nsGkAtoms::textFrame && 1.8428 + f->GetContent()->TextIsOnlyWhitespace()) { 1.8429 + f = f->GetNextSibling(); 1.8430 + } 1.8431 + return f; 1.8432 +} 1.8433 + 1.8434 +static nsIFrame* 1.8435 +FindNextNonWhitespaceSibling(nsIFrame* aFrame) 1.8436 +{ 1.8437 + nsIFrame* f = aFrame; 1.8438 + do { 1.8439 + f = f->GetNextSibling(); 1.8440 + } while (f && f->GetType() == nsGkAtoms::textFrame && 1.8441 + f->GetContent()->TextIsOnlyWhitespace()); 1.8442 + return f; 1.8443 +} 1.8444 + 1.8445 +static nsIFrame* 1.8446 +FindPreviousNonWhitespaceSibling(nsIFrame* aFrame) 1.8447 +{ 1.8448 + nsIFrame* f = aFrame; 1.8449 + do { 1.8450 + f = f->GetPrevSibling(); 1.8451 + } while (f && f->GetType() == nsGkAtoms::textFrame && 1.8452 + f->GetContent()->TextIsOnlyWhitespace()); 1.8453 + return f; 1.8454 +} 1.8455 + 1.8456 +bool 1.8457 +nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame, 1.8458 + nsresult* aResult) 1.8459 +{ 1.8460 + NS_PRECONDITION(aFrame, "Must have a frame"); 1.8461 + NS_PRECONDITION(aFrame->GetParent(), "Frame shouldn't be root"); 1.8462 + NS_PRECONDITION(aResult, "Null out param?"); 1.8463 + NS_PRECONDITION(aFrame == aFrame->FirstContinuation(), 1.8464 + "aFrame not the result of GetPrimaryFrame()?"); 1.8465 + 1.8466 + if (IsFramePartOfIBSplit(aFrame)) { 1.8467 + // The removal functions can't handle removal of an {ib} split directly; we 1.8468 + // need to rebuild the containing block. 1.8469 +#ifdef DEBUG 1.8470 + if (gNoisyContentUpdates) { 1.8471 + printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: " 1.8472 + "frame="); 1.8473 + nsFrame::ListTag(stdout, aFrame); 1.8474 + printf(" is ib-split\n"); 1.8475 + } 1.8476 +#endif 1.8477 + 1.8478 + *aResult = ReframeContainingBlock(aFrame); 1.8479 + return true; 1.8480 + } 1.8481 + 1.8482 + if (aFrame->GetContentInsertionFrame()->GetType() == nsGkAtoms::legendFrame && 1.8483 + aFrame->GetParent()->GetType() == nsGkAtoms::fieldSetFrame) { 1.8484 + // When we remove the legend for a fieldset, we should reframe 1.8485 + // the fieldset to ensure another legend is used, if there is one 1.8486 + *aResult = RecreateFramesForContent(aFrame->GetParent()->GetContent(), false); 1.8487 + return true; 1.8488 + } 1.8489 + 1.8490 + // Now check for possibly needing to reconstruct due to a pseudo parent 1.8491 + nsIFrame* inFlowFrame = 1.8492 + (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ? 1.8493 + GetPlaceholderFrameFor(aFrame) : aFrame; 1.8494 + MOZ_ASSERT(inFlowFrame, "How did that happen?"); 1.8495 + MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(), 1.8496 + "placeholder for primary frame has previous continuations?"); 1.8497 + nsIFrame* parent = inFlowFrame->GetParent(); 1.8498 + if (IsTablePseudo(parent)) { 1.8499 + if (FindFirstNonWhitespaceChild(parent) == inFlowFrame || 1.8500 + !FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation()) || 1.8501 + // If we're a table-column-group, then the GetFirstChild check above is 1.8502 + // not going to catch cases when we're the first child. 1.8503 + (inFlowFrame->GetType() == nsGkAtoms::tableColGroupFrame && 1.8504 + parent->GetFirstChild(nsIFrame::kColGroupList) == inFlowFrame) || 1.8505 + // Similar if we're a table-caption. 1.8506 + (inFlowFrame->GetType() == nsGkAtoms::tableCaptionFrame && 1.8507 + parent->GetFirstChild(nsIFrame::kCaptionList) == inFlowFrame)) { 1.8508 + // We're the first or last frame in the pseudo. Need to reframe. 1.8509 + // Good enough to recreate frames for |parent|'s content 1.8510 + *aResult = RecreateFramesForContent(parent->GetContent(), true); 1.8511 + return true; 1.8512 + } 1.8513 + } 1.8514 + 1.8515 + // Might need to reconstruct things if this frame's nextSibling is a table 1.8516 + // pseudo, since removal of this frame might mean that this pseudo needs to 1.8517 + // get merged with the frame's prevSibling if that's also a table pseudo. 1.8518 + nsIFrame* nextSibling = 1.8519 + FindNextNonWhitespaceSibling(inFlowFrame->LastContinuation()); 1.8520 + NS_ASSERTION(!IsTablePseudo(inFlowFrame), "Shouldn't happen here"); 1.8521 + if (nextSibling && IsTablePseudo(nextSibling)) { 1.8522 + nsIFrame* prevSibling = FindPreviousNonWhitespaceSibling(inFlowFrame); 1.8523 + if (prevSibling && IsTablePseudo(prevSibling)) { 1.8524 +#ifdef DEBUG 1.8525 + if (gNoisyContentUpdates) { 1.8526 + printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: " 1.8527 + "frame="); 1.8528 + nsFrame::ListTag(stdout, aFrame); 1.8529 + printf(" has a table pseudo next sibling of different type and a " 1.8530 + "table pseudo prevsibling\n"); 1.8531 + } 1.8532 +#endif 1.8533 + // Good enough to recreate frames for aFrame's parent's content; even if 1.8534 + // aFrame's parent is a table pseudo, that'll be the right content node. 1.8535 + *aResult = RecreateFramesForContent(parent->GetContent(), true); 1.8536 + return true; 1.8537 + } 1.8538 + } 1.8539 + 1.8540 + // Might need to reconstruct things if the removed frame's nextSibling is an 1.8541 + // anonymous flex item. The removed frame might've been what divided two 1.8542 + // runs of inline content into two anonymous flex items, which would now 1.8543 + // need to be merged. 1.8544 + // NOTE: It's fine that we've advanced nextSibling past whitespace (up above); 1.8545 + // we're only interested in anonymous flex items here, and those can never 1.8546 + // be adjacent to whitespace, since they absorb contiguous runs of inline 1.8547 + // non-replaced content (including whitespace). 1.8548 + if (nextSibling && IsAnonymousFlexItem(nextSibling)) { 1.8549 + NS_ABORT_IF_FALSE(parent->GetType() == nsGkAtoms::flexContainerFrame, 1.8550 + "anonymous flex items should only exist as children " 1.8551 + "of flex container frames"); 1.8552 +#ifdef DEBUG 1.8553 + if (gNoisyContentUpdates) { 1.8554 + printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: " 1.8555 + "frame="); 1.8556 + nsFrame::ListTag(stdout, aFrame); 1.8557 + printf(" has an anonymous flex item as its next sibling\n"); 1.8558 + } 1.8559 +#endif // DEBUG 1.8560 + // Recreate frames for the flex container (the removed frame's parent) 1.8561 + *aResult = RecreateFramesForContent(parent->GetContent(), true); 1.8562 + return true; 1.8563 + } 1.8564 + 1.8565 + // Might need to reconstruct things if the removed frame's nextSibling is 1.8566 + // null and its parent is an anonymous flex item. (This might be the last 1.8567 + // remaining child of that anonymous flex item, which can then go away.) 1.8568 + if (!nextSibling && IsAnonymousFlexItem(parent)) { 1.8569 + NS_ABORT_IF_FALSE(parent->GetParent() && 1.8570 + parent->GetParent()->GetType() == nsGkAtoms::flexContainerFrame, 1.8571 + "anonymous flex items should only exist as children " 1.8572 + "of flex container frames"); 1.8573 +#ifdef DEBUG 1.8574 + if (gNoisyContentUpdates) { 1.8575 + printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: " 1.8576 + "frame="); 1.8577 + nsFrame::ListTag(stdout, aFrame); 1.8578 + printf(" has an anonymous flex item as its parent\n"); 1.8579 + } 1.8580 +#endif // DEBUG 1.8581 + // Recreate frames for the flex container (the removed frame's grandparent) 1.8582 + *aResult = RecreateFramesForContent(parent->GetParent()->GetContent(), 1.8583 + true); 1.8584 + return true; 1.8585 + } 1.8586 + 1.8587 +#ifdef MOZ_XUL 1.8588 + if (aFrame->GetType() == nsGkAtoms::popupSetFrame) { 1.8589 + nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell); 1.8590 + if (rootBox && rootBox->GetPopupSetFrame() == aFrame) { 1.8591 + *aResult = ReconstructDocElementHierarchy(); 1.8592 + return true; 1.8593 + } 1.8594 + } 1.8595 +#endif 1.8596 + 1.8597 + // Reconstruct if inflowFrame is parent's only child, and parent is, or has, 1.8598 + // a non-fluid continuation, i.e. it was split by bidi resolution 1.8599 + if (!inFlowFrame->GetPrevSibling() && 1.8600 + !inFlowFrame->GetNextSibling() && 1.8601 + ((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) || 1.8602 + (parent->GetNextContinuation() && !parent->GetNextInFlow()))) { 1.8603 + *aResult = RecreateFramesForContent(parent->GetContent(), true); 1.8604 + return true; 1.8605 + } 1.8606 + 1.8607 + // We might still need to reconstruct things if the parent of inFlowFrame is 1.8608 + // ib-split, since in that case the removal of aFrame might affect the 1.8609 + // splitting of its parent. 1.8610 + if (!IsFramePartOfIBSplit(parent)) { 1.8611 + return false; 1.8612 + } 1.8613 + 1.8614 + // If inFlowFrame is not the only in-flow child of |parent|, then removing 1.8615 + // it will change nothing about the {ib} split. 1.8616 + if (inFlowFrame != parent->GetFirstPrincipalChild() || 1.8617 + inFlowFrame->LastContinuation()->GetNextSibling()) { 1.8618 + return false; 1.8619 + } 1.8620 + 1.8621 + // If the parent is the first or last part of the {ib} split, then 1.8622 + // removing one of its kids will have no effect on the splitting. 1.8623 + // Get the first continuation up front so we don't have to do it twice. 1.8624 + nsIFrame* parentFirstContinuation = parent->FirstContinuation(); 1.8625 + if (!GetIBSplitSibling(parentFirstContinuation) || 1.8626 + !GetIBSplitPrevSibling(parentFirstContinuation)) { 1.8627 + return false; 1.8628 + } 1.8629 + 1.8630 +#ifdef DEBUG 1.8631 + if (gNoisyContentUpdates) { 1.8632 + printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: " 1.8633 + "frame="); 1.8634 + nsFrame::ListTag(stdout, parent); 1.8635 + printf(" is ib-split\n"); 1.8636 + } 1.8637 +#endif 1.8638 + 1.8639 + *aResult = ReframeContainingBlock(parent); 1.8640 + return true; 1.8641 +} 1.8642 + 1.8643 +nsresult 1.8644 +nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent, 1.8645 + bool aAsyncInsert) 1.8646 +{ 1.8647 + NS_PRECONDITION(!aAsyncInsert || aContent->IsElement(), 1.8648 + "Can only insert elements async"); 1.8649 + // If there is no document, we don't want to recreate frames for it. (You 1.8650 + // shouldn't generally be giving this method content without a document 1.8651 + // anyway). 1.8652 + // Rebuilding the frame tree can have bad effects, especially if it's the 1.8653 + // frame tree for chrome (see bug 157322). 1.8654 + NS_ENSURE_TRUE(aContent->GetDocument(), NS_ERROR_FAILURE); 1.8655 + 1.8656 + // Is the frame ib-split? If so, we need to reframe the containing 1.8657 + // block *here*, rather than trying to remove and re-insert the 1.8658 + // content (which would otherwise result in *two* nested reframe 1.8659 + // containing block from ContentRemoved() and ContentInserted(), 1.8660 + // below!). We'd really like to optimize away one of those 1.8661 + // containing block reframes, hence the code here. 1.8662 + 1.8663 + nsIFrame* frame = aContent->GetPrimaryFrame(); 1.8664 + if (frame && frame->IsFrameOfType(nsIFrame::eMathML)) { 1.8665 + // Reframe the topmost MathML element to prevent exponential blowup 1.8666 + // (see bug 397518) 1.8667 + while (true) { 1.8668 + nsIContent* parentContent = aContent->GetParent(); 1.8669 + nsIFrame* parentContentFrame = parentContent->GetPrimaryFrame(); 1.8670 + if (!parentContentFrame || !parentContentFrame->IsFrameOfType(nsIFrame::eMathML)) 1.8671 + break; 1.8672 + aContent = parentContent; 1.8673 + frame = parentContentFrame; 1.8674 + } 1.8675 + } 1.8676 + 1.8677 + if (frame) { 1.8678 + nsIFrame* nonGeneratedAncestor = nsLayoutUtils::GetNonGeneratedAncestor(frame); 1.8679 + if (nonGeneratedAncestor->GetContent() != aContent) { 1.8680 + return RecreateFramesForContent(nonGeneratedAncestor->GetContent(), aAsyncInsert); 1.8681 + } 1.8682 + 1.8683 + if (frame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) { 1.8684 + // Recreate the frames for the entire nsIAnonymousContentCreator tree 1.8685 + // since |frame| or one of its descendants may need an nsStyleContext 1.8686 + // that associates it to a CSS pseudo-element, and only the 1.8687 + // nsIAnonymousContentCreator that created this content knows how to make 1.8688 + // that happen. 1.8689 + nsIAnonymousContentCreator* acc = nullptr; 1.8690 + nsIFrame* ancestor = frame->GetParent(); 1.8691 + while (!(acc = do_QueryFrame(ancestor))) { 1.8692 + ancestor = ancestor->GetParent(); 1.8693 + } 1.8694 + NS_ASSERTION(acc, "Where is the nsIAnonymousContentCreator? We may fail " 1.8695 + "to recreate its content correctly"); 1.8696 + // nsSVGUseFrame is special, and we know this is unnecessary for it. 1.8697 + if (ancestor->GetType() != nsGkAtoms::svgUseFrame) { 1.8698 + NS_ASSERTION(aContent->IsInNativeAnonymousSubtree(), 1.8699 + "Why is NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT set?"); 1.8700 + return RecreateFramesForContent(ancestor->GetContent(), aAsyncInsert); 1.8701 + } 1.8702 + } 1.8703 + 1.8704 + nsIFrame* parent = frame->GetParent(); 1.8705 + nsIContent* parentContent = parent ? parent->GetContent() : nullptr; 1.8706 + // If the parent frame is a leaf then the subsequent insert will fail to 1.8707 + // create a frame, so we need to recreate the parent content. This happens 1.8708 + // with native anonymous content from the editor. 1.8709 + if (parent && parent->IsLeaf() && parentContent && 1.8710 + parentContent != aContent) { 1.8711 + return RecreateFramesForContent(parentContent, aAsyncInsert); 1.8712 + } 1.8713 + } 1.8714 + 1.8715 + nsresult rv = NS_OK; 1.8716 + 1.8717 + if (frame && MaybeRecreateContainerForFrameRemoval(frame, &rv)) { 1.8718 + return rv; 1.8719 + } 1.8720 + 1.8721 + nsINode* containerNode = aContent->GetParentNode(); 1.8722 + // XXXbz how can containerNode be null here? 1.8723 + if (containerNode) { 1.8724 + // Before removing the frames associated with the content object, 1.8725 + // ask them to save their state onto a temporary state object. 1.8726 + CaptureStateForFramesOf(aContent, mTempFrameTreeState); 1.8727 + 1.8728 + // Need the nsIContent parent, which might be null here, since we need to 1.8729 + // pass it to ContentInserted and ContentRemoved. 1.8730 + nsCOMPtr<nsIContent> container = aContent->GetParent(); 1.8731 + 1.8732 + // Remove the frames associated with the content object. 1.8733 + bool didReconstruct; 1.8734 + rv = ContentRemoved(container, aContent, 1.8735 + aContent->IsRootOfAnonymousSubtree() ? 1.8736 + nullptr : 1.8737 + aContent->GetNextSibling(), 1.8738 + REMOVE_FOR_RECONSTRUCTION, &didReconstruct); 1.8739 + 1.8740 + if (NS_SUCCEEDED(rv) && !didReconstruct) { 1.8741 + // Now, recreate the frames associated with this content object. If 1.8742 + // ContentRemoved triggered reconstruction, then we don't need to do this 1.8743 + // because the frames will already have been built. 1.8744 + if (aAsyncInsert) { 1.8745 + RestyleManager()->PostRestyleEvent( 1.8746 + aContent->AsElement(), nsRestyleHint(0), nsChangeHint_ReconstructFrame); 1.8747 + } else { 1.8748 + rv = ContentInserted(container, aContent, mTempFrameTreeState, false); 1.8749 + } 1.8750 + } 1.8751 + } 1.8752 + 1.8753 + return rv; 1.8754 +} 1.8755 + 1.8756 +////////////////////////////////////////////////////////////////////// 1.8757 + 1.8758 +// Block frame construction code 1.8759 + 1.8760 +already_AddRefed<nsStyleContext> 1.8761 +nsCSSFrameConstructor::GetFirstLetterStyle(nsIContent* aContent, 1.8762 + nsStyleContext* aStyleContext) 1.8763 +{ 1.8764 + if (aContent) { 1.8765 + return mPresShell->StyleSet()-> 1.8766 + ResolvePseudoElementStyle(aContent->AsElement(), 1.8767 + nsCSSPseudoElements::ePseudo_firstLetter, 1.8768 + aStyleContext, 1.8769 + nullptr); 1.8770 + } 1.8771 + return nullptr; 1.8772 +} 1.8773 + 1.8774 +already_AddRefed<nsStyleContext> 1.8775 +nsCSSFrameConstructor::GetFirstLineStyle(nsIContent* aContent, 1.8776 + nsStyleContext* aStyleContext) 1.8777 +{ 1.8778 + if (aContent) { 1.8779 + return mPresShell->StyleSet()-> 1.8780 + ResolvePseudoElementStyle(aContent->AsElement(), 1.8781 + nsCSSPseudoElements::ePseudo_firstLine, 1.8782 + aStyleContext, 1.8783 + nullptr); 1.8784 + } 1.8785 + return nullptr; 1.8786 +} 1.8787 + 1.8788 +// Predicate to see if a given content (block element) has 1.8789 +// first-letter style applied to it. 1.8790 +bool 1.8791 +nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(nsIContent* aContent, 1.8792 + nsStyleContext* aStyleContext) 1.8793 +{ 1.8794 + return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext, 1.8795 + nsCSSPseudoElements::ePseudo_firstLetter, 1.8796 + mPresShell->GetPresContext()); 1.8797 +} 1.8798 + 1.8799 +bool 1.8800 +nsCSSFrameConstructor::HasFirstLetterStyle(nsIFrame* aBlockFrame) 1.8801 +{ 1.8802 + NS_PRECONDITION(aBlockFrame, "Need a frame"); 1.8803 + NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame), 1.8804 + "Not a block frame?"); 1.8805 + 1.8806 + return (aBlockFrame->GetStateBits() & NS_BLOCK_HAS_FIRST_LETTER_STYLE) != 0; 1.8807 +} 1.8808 + 1.8809 +bool 1.8810 +nsCSSFrameConstructor::ShouldHaveFirstLineStyle(nsIContent* aContent, 1.8811 + nsStyleContext* aStyleContext) 1.8812 +{ 1.8813 + bool hasFirstLine = 1.8814 + nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext, 1.8815 + nsCSSPseudoElements::ePseudo_firstLine, 1.8816 + mPresShell->GetPresContext()); 1.8817 + if (hasFirstLine) { 1.8818 + // But disable for fieldsets 1.8819 + int32_t namespaceID; 1.8820 + nsIAtom* tag = mDocument->BindingManager()->ResolveTag(aContent, 1.8821 + &namespaceID); 1.8822 + // This check must match the one in FindHTMLData. 1.8823 + hasFirstLine = tag != nsGkAtoms::fieldset || 1.8824 + namespaceID != kNameSpaceID_XHTML; 1.8825 + } 1.8826 + 1.8827 + return hasFirstLine; 1.8828 +} 1.8829 + 1.8830 +void 1.8831 +nsCSSFrameConstructor::ShouldHaveSpecialBlockStyle(nsIContent* aContent, 1.8832 + nsStyleContext* aStyleContext, 1.8833 + bool* aHaveFirstLetterStyle, 1.8834 + bool* aHaveFirstLineStyle) 1.8835 +{ 1.8836 + *aHaveFirstLetterStyle = 1.8837 + ShouldHaveFirstLetterStyle(aContent, aStyleContext); 1.8838 + *aHaveFirstLineStyle = 1.8839 + ShouldHaveFirstLineStyle(aContent, aStyleContext); 1.8840 +} 1.8841 + 1.8842 +/* static */ 1.8843 +const nsCSSFrameConstructor::PseudoParentData 1.8844 +nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = { 1.8845 + { // Cell 1.8846 + FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET | 1.8847 + FCDATA_USE_CHILD_ITEMS | 1.8848 + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow), 1.8849 + &nsCSSFrameConstructor::ConstructTableCell), 1.8850 + &nsCSSAnonBoxes::tableCell 1.8851 + }, 1.8852 + { // Row 1.8853 + FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET | 1.8854 + FCDATA_USE_CHILD_ITEMS | 1.8855 + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup), 1.8856 + &nsCSSFrameConstructor::ConstructTableRowOrRowGroup), 1.8857 + &nsCSSAnonBoxes::tableRow 1.8858 + }, 1.8859 + { // Row group 1.8860 + FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET | 1.8861 + FCDATA_USE_CHILD_ITEMS | 1.8862 + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), 1.8863 + &nsCSSFrameConstructor::ConstructTableRowOrRowGroup), 1.8864 + &nsCSSAnonBoxes::tableRowGroup 1.8865 + }, 1.8866 + { // Column group 1.8867 + FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_SKIP_FRAMESET | 1.8868 + FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_USE_CHILD_ITEMS | 1.8869 + FCDATA_SKIP_ABSPOS_PUSH | 1.8870 + FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable), 1.8871 + NS_NewTableColGroupFrame), 1.8872 + &nsCSSAnonBoxes::tableColGroup 1.8873 + }, 1.8874 + { // Table 1.8875 + FULL_CTOR_FCDATA(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS, 1.8876 + &nsCSSFrameConstructor::ConstructTable), 1.8877 + &nsCSSAnonBoxes::table 1.8878 + } 1.8879 +}; 1.8880 + 1.8881 +void 1.8882 +nsCSSFrameConstructor::CreateNeededAnonFlexItems( 1.8883 + nsFrameConstructorState& aState, 1.8884 + FrameConstructionItemList& aItems, 1.8885 + nsIFrame* aParentFrame) 1.8886 +{ 1.8887 + if (aItems.IsEmpty() || 1.8888 + aParentFrame->GetType() != nsGkAtoms::flexContainerFrame) { 1.8889 + return; 1.8890 + } 1.8891 + 1.8892 + FCItemIterator iter(aItems); 1.8893 + do { 1.8894 + // Advance iter past children that don't want to be wrapped 1.8895 + if (iter.SkipItemsThatDontNeedAnonFlexItem(aState)) { 1.8896 + // Hit the end of the items without finding any remaining children that 1.8897 + // need to be wrapped. We're finished! 1.8898 + return; 1.8899 + } 1.8900 + 1.8901 + // If our next potentially-wrappable child is whitespace, then see if 1.8902 + // there's anything wrappable immediately after it. If not, we just drop 1.8903 + // the whitespace and move on. (We're not supposed to create any anonymous 1.8904 + // flex items that _only_ contain whitespace). 1.8905 + // (BUT if this is generated content, then we don't give whitespace nodes 1.8906 + // any special treatment, because they're probably not really whitespace -- 1.8907 + // they're just temporarily empty, waiting for their generated text.) 1.8908 + // XXXdholbert If this node's generated text will *actually end up being 1.8909 + // entirely whitespace*, then we technically should still skip over it, per 1.8910 + // the flexbox spec. I'm not bothering with that at this point, since it's 1.8911 + // a pretty extreme edge case. 1.8912 + if (!aParentFrame->IsGeneratedContentFrame() && 1.8913 + iter.item().IsWhitespace(aState)) { 1.8914 + FCItemIterator afterWhitespaceIter(iter); 1.8915 + bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState); 1.8916 + bool nextChildNeedsAnonFlexItem = 1.8917 + !hitEnd && afterWhitespaceIter.item().NeedsAnonFlexItem(aState); 1.8918 + 1.8919 + if (!nextChildNeedsAnonFlexItem) { 1.8920 + // There's nothing after the whitespace that we need to wrap, so we 1.8921 + // just drop this run of whitespace. 1.8922 + iter.DeleteItemsTo(afterWhitespaceIter); 1.8923 + if (hitEnd) { 1.8924 + // Nothing left to do -- we're finished! 1.8925 + return; 1.8926 + } 1.8927 + // else, we have a next child and it does not want to be wrapped. So, 1.8928 + // we jump back to the beginning of the loop to skip over that child 1.8929 + // (and anything else non-wrappable after it) 1.8930 + NS_ABORT_IF_FALSE(!iter.IsDone() && 1.8931 + !iter.item().NeedsAnonFlexItem(aState), 1.8932 + "hitEnd and/or nextChildNeedsAnonFlexItem lied"); 1.8933 + continue; 1.8934 + } 1.8935 + } 1.8936 + 1.8937 + // Now |iter| points to the first child that needs to be wrapped in an 1.8938 + // anonymous flex item. Now we see how many children after it also want 1.8939 + // to be wrapped in an anonymous flex item. 1.8940 + FCItemIterator endIter(iter); // iterator to find the end of the group 1.8941 + endIter.SkipItemsThatNeedAnonFlexItem(aState); 1.8942 + 1.8943 + NS_ASSERTION(iter != endIter, 1.8944 + "Should've had at least one wrappable child to seek past"); 1.8945 + 1.8946 + // Now, we create the anonymous flex item to contain the children 1.8947 + // between |iter| and |endIter|. 1.8948 + nsIAtom* pseudoType = nsCSSAnonBoxes::anonymousFlexItem; 1.8949 + nsStyleContext* parentStyle = aParentFrame->StyleContext(); 1.8950 + nsIContent* parentContent = aParentFrame->GetContent(); 1.8951 + already_AddRefed<nsStyleContext> wrapperStyle = 1.8952 + mPresShell->StyleSet()->ResolveAnonymousBoxStyle(pseudoType, parentStyle); 1.8953 + 1.8954 + static const FrameConstructionData sBlockFormattingContextFCData = 1.8955 + FCDATA_DECL(FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS, 1.8956 + NS_NewBlockFormattingContext); 1.8957 + 1.8958 + FrameConstructionItem* newItem = 1.8959 + new FrameConstructionItem(&sBlockFormattingContextFCData, 1.8960 + // Use the content of our parent frame 1.8961 + parentContent, 1.8962 + // Lie about the tag; it doesn't matter anyway 1.8963 + pseudoType, 1.8964 + iter.item().mNameSpaceID, 1.8965 + // no pending binding 1.8966 + nullptr, 1.8967 + wrapperStyle, 1.8968 + true, nullptr); 1.8969 + 1.8970 + newItem->mIsAllInline = newItem->mHasInlineEnds = 1.8971 + newItem->mStyleContext->StyleDisplay()->IsInlineOutsideStyle(); 1.8972 + newItem->mIsBlock = !newItem->mIsAllInline; 1.8973 + 1.8974 + NS_ABORT_IF_FALSE(!newItem->mIsAllInline && newItem->mIsBlock, 1.8975 + "expecting anonymous flex items to be block-level " 1.8976 + "(this will make a difference when we encounter " 1.8977 + "'flex-align: baseline')"); 1.8978 + 1.8979 + // Anonymous flex items induce line boundaries around their 1.8980 + // contents. 1.8981 + newItem->mChildItems.SetLineBoundaryAtStart(true); 1.8982 + newItem->mChildItems.SetLineBoundaryAtEnd(true); 1.8983 + // The parent of the items in aItems is also the parent of the items 1.8984 + // in mChildItems 1.8985 + newItem->mChildItems.SetParentHasNoXBLChildren( 1.8986 + aItems.ParentHasNoXBLChildren()); 1.8987 + 1.8988 + // Eat up all items between |iter| and |endIter| and put them in our 1.8989 + // wrapper. This advances |iter| to point to |endIter|. 1.8990 + iter.AppendItemsToList(endIter, newItem->mChildItems); 1.8991 + 1.8992 + iter.InsertItem(newItem); 1.8993 + } while (!iter.IsDone()); 1.8994 +} 1.8995 + 1.8996 +/* 1.8997 + * This function works as follows: we walk through the child list (aItems) and 1.8998 + * find items that cannot have aParentFrame as their parent. We wrap 1.8999 + * continuous runs of such items into a FrameConstructionItem for a frame that 1.9000 + * gets them closer to their desired parents. For example, a run of non-row 1.9001 + * children of a row-group will get wrapped in a row. When we later construct 1.9002 + * the frame for this wrapper (in this case for the row), it'll be the correct 1.9003 + * parent for the cells in the set of items we wrapped or we'll wrap cells 1.9004 + * around everything else. At the end of this method, aItems is guaranteed to 1.9005 + * contain only items for frames that can be direct kids of aParentFrame. 1.9006 + */ 1.9007 +void 1.9008 +nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState& aState, 1.9009 + FrameConstructionItemList& aItems, 1.9010 + nsIFrame* aParentFrame) 1.9011 +{ 1.9012 + ParentType ourParentType = GetParentType(aParentFrame); 1.9013 + if (aItems.AllWantParentType(ourParentType)) { 1.9014 + // Nothing to do here 1.9015 + return; 1.9016 + } 1.9017 + 1.9018 + FCItemIterator iter(aItems); 1.9019 + do { 1.9020 + if (iter.SkipItemsWantingParentType(ourParentType)) { 1.9021 + // Nothing else to do here; we're finished 1.9022 + return; 1.9023 + } 1.9024 + 1.9025 + // Now we're pointing to the first child that wants a different parent 1.9026 + // type. 1.9027 + 1.9028 + // Now try to figure out what kids we can group together. We can generally 1.9029 + // group everything that has a different desired parent type from us. Two 1.9030 + // exceptions to this: 1.9031 + // 1) If our parent type is table, we can't group columns with anything 1.9032 + // else other than whitespace. 1.9033 + // 2) Whitespace that lies between two things we can group which both want 1.9034 + // a non-block parent should be dropped, even if we can't group them 1.9035 + // with each other and even if the whitespace wants a parent of 1.9036 + // ourParentType. Ends of the list count as things that don't want a 1.9037 + // block parent (so that for example we'll drop a whitespace-only list). 1.9038 + 1.9039 + FCItemIterator endIter(iter); /* iterator to find the end of the group */ 1.9040 + ParentType groupingParentType = endIter.item().DesiredParentType(); 1.9041 + if (aItems.AllWantParentType(groupingParentType) && 1.9042 + groupingParentType != eTypeBlock) { 1.9043 + // Just group them all and be done with it. We need the check for 1.9044 + // eTypeBlock here to catch the "all the items are whitespace" case 1.9045 + // described above. 1.9046 + endIter.SetToEnd(); 1.9047 + } else { 1.9048 + // Locate the end of the group. 1.9049 + 1.9050 + // Keep track of the type the previous item wanted, in case we have to 1.9051 + // deal with whitespace. Start it off with ourParentType, since that's 1.9052 + // the last thing |iter| would have skipped over. 1.9053 + ParentType prevParentType = ourParentType; 1.9054 + do { 1.9055 + /* Walk an iterator past any whitespace that we might be able to drop from the list */ 1.9056 + FCItemIterator spaceEndIter(endIter); 1.9057 + if (prevParentType != eTypeBlock && 1.9058 + !aParentFrame->IsGeneratedContentFrame() && 1.9059 + spaceEndIter.item().IsWhitespace(aState)) { 1.9060 + bool trailingSpaces = spaceEndIter.SkipWhitespace(aState); 1.9061 + 1.9062 + // We drop the whitespace if these are not trailing spaces and the next item 1.9063 + // does not want a block parent (see case 2 above) 1.9064 + // if these are trailing spaces and aParentFrame is a tabular container 1.9065 + // according to rule 1.3 of CSS 2.1 Sec 17.2.1. (Being a tabular container 1.9066 + // pretty much means ourParentType != eTypeBlock besides the eTypeColGroup case, 1.9067 + // which won't reach here.) 1.9068 + if ((trailingSpaces && ourParentType != eTypeBlock) || 1.9069 + (!trailingSpaces && spaceEndIter.item().DesiredParentType() != 1.9070 + eTypeBlock)) { 1.9071 + bool updateStart = (iter == endIter); 1.9072 + endIter.DeleteItemsTo(spaceEndIter); 1.9073 + NS_ASSERTION(trailingSpaces == endIter.IsDone(), "These should match"); 1.9074 + 1.9075 + if (updateStart) { 1.9076 + iter = endIter; 1.9077 + } 1.9078 + 1.9079 + if (trailingSpaces) { 1.9080 + break; /* Found group end */ 1.9081 + } 1.9082 + 1.9083 + if (updateStart) { 1.9084 + // Update groupingParentType, since it might have been eTypeBlock 1.9085 + // just because of the whitespace. 1.9086 + groupingParentType = iter.item().DesiredParentType(); 1.9087 + } 1.9088 + } 1.9089 + } 1.9090 + 1.9091 + // Now endIter points to a non-whitespace item or a non-droppable 1.9092 + // whitespace item. In the latter case, if this is the end of the group 1.9093 + // we'll traverse this whitespace again. But it'll all just be quick 1.9094 + // DesiredParentType() checks which will match ourParentType (that's 1.9095 + // what it means that this is the group end), so it's OK. 1.9096 + prevParentType = endIter.item().DesiredParentType(); 1.9097 + if (prevParentType == ourParentType) { 1.9098 + // End the group at endIter. 1.9099 + break; 1.9100 + } 1.9101 + 1.9102 + if (ourParentType == eTypeTable && 1.9103 + (prevParentType == eTypeColGroup) != 1.9104 + (groupingParentType == eTypeColGroup)) { 1.9105 + // Either we started with columns and now found something else, or vice 1.9106 + // versa. In any case, end the grouping. 1.9107 + break; 1.9108 + } 1.9109 + 1.9110 + // Include the whitespace we didn't drop (if any) in the group, since 1.9111 + // this is not the end of the group. Note that this doesn't change 1.9112 + // prevParentType, since if we didn't drop the whitespace then we ended 1.9113 + // at something that wants a block parent. 1.9114 + endIter = spaceEndIter; 1.9115 + 1.9116 + endIter.Next(); 1.9117 + } while (!endIter.IsDone()); 1.9118 + } 1.9119 + 1.9120 + if (iter == endIter) { 1.9121 + // Nothing to wrap here; just skipped some whitespace 1.9122 + continue; 1.9123 + } 1.9124 + 1.9125 + // Now group together all the items between iter and endIter. The right 1.9126 + // parent type to use depends on ourParentType. 1.9127 + ParentType wrapperType; 1.9128 + switch (ourParentType) { 1.9129 + case eTypeBlock: 1.9130 + wrapperType = eTypeTable; 1.9131 + break; 1.9132 + case eTypeRow: 1.9133 + // The parent type for a cell is eTypeBlock, since that's what a cell 1.9134 + // looks like to its kids. 1.9135 + wrapperType = eTypeBlock; 1.9136 + break; 1.9137 + case eTypeRowGroup: 1.9138 + wrapperType = eTypeRow; 1.9139 + break; 1.9140 + case eTypeTable: 1.9141 + // Either colgroup or rowgroup, depending on what we're grouping. 1.9142 + wrapperType = groupingParentType == eTypeColGroup ? 1.9143 + eTypeColGroup : eTypeRowGroup; 1.9144 + break; 1.9145 + default: 1.9146 + MOZ_CRASH("Colgroups should be suppresing non-col child items"); 1.9147 + } 1.9148 + 1.9149 + const PseudoParentData& pseudoData = sPseudoParentData[wrapperType]; 1.9150 + nsIAtom* pseudoType = *pseudoData.mPseudoType; 1.9151 + nsStyleContext* parentStyle = aParentFrame->StyleContext(); 1.9152 + nsIContent* parentContent = aParentFrame->GetContent(); 1.9153 + 1.9154 + if (pseudoType == nsCSSAnonBoxes::table && 1.9155 + parentStyle->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_INLINE) { 1.9156 + pseudoType = nsCSSAnonBoxes::inlineTable; 1.9157 + } 1.9158 + 1.9159 + already_AddRefed<nsStyleContext> wrapperStyle = 1.9160 + mPresShell->StyleSet()->ResolveAnonymousBoxStyle(pseudoType, parentStyle); 1.9161 + FrameConstructionItem* newItem = 1.9162 + new FrameConstructionItem(&pseudoData.mFCData, 1.9163 + // Use the content of our parent frame 1.9164 + parentContent, 1.9165 + // Lie about the tag; it doesn't matter anyway 1.9166 + pseudoType, 1.9167 + // The namespace does matter, however; it needs 1.9168 + // to match that of our first child item to 1.9169 + // match the old behavior 1.9170 + iter.item().mNameSpaceID, 1.9171 + // no pending binding 1.9172 + nullptr, 1.9173 + wrapperStyle, 1.9174 + true, nullptr); 1.9175 + 1.9176 + // Here we're cheating a tad... technically, table-internal items should be 1.9177 + // inline if aParentFrame is inline, but they'll get wrapped in an 1.9178 + // inline-table in the end, so it'll all work out. In any case, arguably 1.9179 + // we don't need to maintain this state at this point... but it's better 1.9180 + // to, I guess. 1.9181 + newItem->mIsAllInline = newItem->mHasInlineEnds = 1.9182 + newItem->mStyleContext->StyleDisplay()->IsInlineOutsideStyle(); 1.9183 + 1.9184 + // Table pseudo frames always induce line boundaries around their 1.9185 + // contents. 1.9186 + newItem->mChildItems.SetLineBoundaryAtStart(true); 1.9187 + newItem->mChildItems.SetLineBoundaryAtEnd(true); 1.9188 + // The parent of the items in aItems is also the parent of the items 1.9189 + // in mChildItems 1.9190 + newItem->mChildItems.SetParentHasNoXBLChildren( 1.9191 + aItems.ParentHasNoXBLChildren()); 1.9192 + 1.9193 + // Eat up all items between |iter| and |endIter| and put them in our wrapper 1.9194 + // Advances |iter| to point to |endIter|. 1.9195 + iter.AppendItemsToList(endIter, newItem->mChildItems); 1.9196 + 1.9197 + iter.InsertItem(newItem); 1.9198 + 1.9199 + // Now |iter| points to the item that was the first one we didn't wrap; 1.9200 + // loop and see whether we need to skip it or wrap it in something 1.9201 + // different. 1.9202 + } while (!iter.IsDone()); 1.9203 +} 1.9204 + 1.9205 +inline void 1.9206 +nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aState, 1.9207 + FrameConstructionItemList& aItems, 1.9208 + nsIFrame* aParentFrame, 1.9209 + nsFrameItems& aFrameItems) 1.9210 +{ 1.9211 + CreateNeededTablePseudos(aState, aItems, aParentFrame); 1.9212 + CreateNeededAnonFlexItems(aState, aItems, aParentFrame); 1.9213 + 1.9214 + aItems.SetTriedConstructingFrames(); 1.9215 + for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) { 1.9216 + NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame), 1.9217 + "Needed pseudos didn't get created; expect bad things"); 1.9218 + ConstructFramesFromItem(aState, iter, aParentFrame, aFrameItems); 1.9219 + } 1.9220 + 1.9221 + NS_ASSERTION(!aState.mHavePendingPopupgroup, 1.9222 + "Should have proccessed it by now"); 1.9223 +} 1.9224 + 1.9225 +void 1.9226 +nsCSSFrameConstructor::AddFCItemsForAnonymousContent( 1.9227 + nsFrameConstructorState& aState, 1.9228 + nsIFrame* aFrame, 1.9229 + nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonymousItems, 1.9230 + FrameConstructionItemList& aItemsToConstruct, 1.9231 + uint32_t aExtraFlags) 1.9232 +{ 1.9233 + for (uint32_t i = 0; i < aAnonymousItems.Length(); ++i) { 1.9234 + nsIContent* content = aAnonymousItems[i].mContent; 1.9235 +#ifdef DEBUG 1.9236 + nsIAnonymousContentCreator* creator = do_QueryFrame(aFrame); 1.9237 + NS_ASSERTION(!creator || !creator->CreateFrameFor(content), 1.9238 + "If you need to use CreateFrameFor, you need to call " 1.9239 + "CreateAnonymousFrames manually and not follow the standard " 1.9240 + "ProcessChildren() codepath for this frame"); 1.9241 +#endif 1.9242 + // Assert some things about this content 1.9243 + NS_ABORT_IF_FALSE(!(content->GetFlags() & 1.9244 + (NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME)), 1.9245 + "Should not be marked as needing frames"); 1.9246 + NS_ABORT_IF_FALSE(!content->IsElement() || 1.9247 + !(content->GetFlags() & ELEMENT_ALL_RESTYLE_FLAGS), 1.9248 + "Should have no pending restyle flags"); 1.9249 + NS_ABORT_IF_FALSE(!content->GetPrimaryFrame(), 1.9250 + "Should have no existing frame"); 1.9251 + NS_ABORT_IF_FALSE(!content->IsNodeOfType(nsINode::eCOMMENT) && 1.9252 + !content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION), 1.9253 + "Why is someone creating garbage anonymous content"); 1.9254 + 1.9255 + nsRefPtr<nsStyleContext> styleContext; 1.9256 + TreeMatchContext::AutoFlexItemStyleFixupSkipper 1.9257 + flexItemStyleFixupSkipper(aState.mTreeMatchContext); 1.9258 + if (aAnonymousItems[i].mStyleContext) { 1.9259 + styleContext = aAnonymousItems[i].mStyleContext.forget(); 1.9260 + } else { 1.9261 + styleContext = ResolveStyleContext(aFrame, content, &aState); 1.9262 + } 1.9263 + 1.9264 + nsTArray<nsIAnonymousContentCreator::ContentInfo>* anonChildren = nullptr; 1.9265 + if (!aAnonymousItems[i].mChildren.IsEmpty()) { 1.9266 + anonChildren = &aAnonymousItems[i].mChildren; 1.9267 + } 1.9268 + 1.9269 + uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK | 1.9270 + ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT | aExtraFlags; 1.9271 + 1.9272 + AddFrameConstructionItemsInternal(aState, content, aFrame, 1.9273 + content->Tag(), content->GetNameSpaceID(), 1.9274 + true, styleContext, flags, 1.9275 + anonChildren, aItemsToConstruct); 1.9276 + } 1.9277 +} 1.9278 + 1.9279 +void 1.9280 +nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState, 1.9281 + nsIContent* aContent, 1.9282 + nsStyleContext* aStyleContext, 1.9283 + nsIFrame* aFrame, 1.9284 + const bool aCanHaveGeneratedContent, 1.9285 + nsFrameItems& aFrameItems, 1.9286 + const bool aAllowBlockStyles, 1.9287 + PendingBinding* aPendingBinding, 1.9288 + nsIFrame* aPossiblyLeafFrame) 1.9289 +{ 1.9290 + NS_PRECONDITION(aFrame, "Must have parent frame here"); 1.9291 + NS_PRECONDITION(aFrame->GetContentInsertionFrame() == aFrame, 1.9292 + "Parent frame in ProcessChildren should be its own " 1.9293 + "content insertion frame"); 1.9294 + const uint32_t kMaxDepth = 2 * MAX_REFLOW_DEPTH; 1.9295 + static_assert(kMaxDepth <= UINT16_MAX, "mCurrentDepth type is too narrow"); 1.9296 + AutoRestore<uint16_t> savedDepth(mCurrentDepth); 1.9297 + if (mCurrentDepth != UINT16_MAX) { 1.9298 + ++mCurrentDepth; 1.9299 + } 1.9300 + 1.9301 + if (!aPossiblyLeafFrame) { 1.9302 + aPossiblyLeafFrame = aFrame; 1.9303 + } 1.9304 + 1.9305 + // XXXbz ideally, this would do all the pushing of various 1.9306 + // containing blocks as needed, so callers don't have to do it... 1.9307 + 1.9308 + bool haveFirstLetterStyle = false, haveFirstLineStyle = false; 1.9309 + if (aAllowBlockStyles) { 1.9310 + ShouldHaveSpecialBlockStyle(aContent, aStyleContext, &haveFirstLetterStyle, 1.9311 + &haveFirstLineStyle); 1.9312 + } 1.9313 + 1.9314 + // The logic here needs to match the logic in GetFloatContainingBlock() 1.9315 + nsFrameConstructorSaveState floatSaveState; 1.9316 + if (ShouldSuppressFloatingOfDescendants(aFrame)) { 1.9317 + aState.PushFloatContainingBlock(nullptr, floatSaveState); 1.9318 + } else if (aFrame->IsFloatContainingBlock()) { 1.9319 + aState.PushFloatContainingBlock(aFrame, floatSaveState); 1.9320 + } 1.9321 + 1.9322 + nsFrameConstructorState::PendingBindingAutoPusher pusher(aState, 1.9323 + aPendingBinding); 1.9324 + 1.9325 + FrameConstructionItemList itemsToConstruct; 1.9326 + 1.9327 + // If we have first-letter or first-line style then frames can get 1.9328 + // moved around so don't set these flags. 1.9329 + if (aAllowBlockStyles && !haveFirstLetterStyle && !haveFirstLineStyle) { 1.9330 + itemsToConstruct.SetLineBoundaryAtStart(true); 1.9331 + itemsToConstruct.SetLineBoundaryAtEnd(true); 1.9332 + } 1.9333 + 1.9334 + // Create any anonymous frames we need here. This must happen before the 1.9335 + // non-anonymous children are processed to ensure that popups are never 1.9336 + // constructed before the popupset. 1.9337 + nsAutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems; 1.9338 + GetAnonymousContent(aContent, aPossiblyLeafFrame, anonymousItems); 1.9339 +#ifdef DEBUG 1.9340 + for (uint32_t i = 0; i < anonymousItems.Length(); ++i) { 1.9341 + NS_ABORT_IF_FALSE(anonymousItems[i].mContent->IsRootOfAnonymousSubtree(), 1.9342 + "Content should know it's an anonymous subtree"); 1.9343 + } 1.9344 +#endif 1.9345 + AddFCItemsForAnonymousContent(aState, aFrame, anonymousItems, 1.9346 + itemsToConstruct); 1.9347 + 1.9348 + if (!aPossiblyLeafFrame->IsLeaf()) { 1.9349 + // :before/:after content should have the same style context parent 1.9350 + // as normal kids. 1.9351 + // Note that we don't use this style context for looking up things like 1.9352 + // special block styles because in some cases involving table pseudo-frames 1.9353 + // it has nothing to do with the parent frame's desired behavior. 1.9354 + nsStyleContext* styleContext; 1.9355 + 1.9356 + if (aCanHaveGeneratedContent) { 1.9357 + aFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT); 1.9358 + styleContext = 1.9359 + nsFrame::CorrectStyleParentFrame(aFrame, nullptr)->StyleContext(); 1.9360 + // Probe for generated content before 1.9361 + CreateGeneratedContentItem(aState, aFrame, aContent, styleContext, 1.9362 + nsCSSPseudoElements::ePseudo_before, 1.9363 + itemsToConstruct); 1.9364 + } 1.9365 + 1.9366 + const bool addChildItems = MOZ_LIKELY(mCurrentDepth < kMaxDepth); 1.9367 + if (!addChildItems) { 1.9368 + NS_WARNING("ProcessChildren max depth exceeded"); 1.9369 + } 1.9370 + 1.9371 + FlattenedChildIterator iter(aContent); 1.9372 + for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { 1.9373 + // Get the parent of the content and check if it is a XBL children element 1.9374 + // (if the content is a children element then parent != aContent because the 1.9375 + // FlattenedChildIterator will transitively iterate through <xbl:children> 1.9376 + // for default content). Push the children element as an ancestor here because 1.9377 + // it does not have a frame and would not otherwise be pushed as an ancestor. 1.9378 + nsIContent* parent = child->GetParent(); 1.9379 + MOZ_ASSERT(parent, "Parent must be non-null because we are iterating children."); 1.9380 + TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext); 1.9381 + if (parent != aContent && parent->IsElement()) { 1.9382 + if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) { 1.9383 + ancestorPusher.PushAncestorAndStyleScope(parent->AsElement()); 1.9384 + } else { 1.9385 + ancestorPusher.PushStyleScope(parent->AsElement()); 1.9386 + } 1.9387 + } 1.9388 + 1.9389 + // Frame construction item construction should not post 1.9390 + // restyles, so removing restyle flags here is safe. 1.9391 + if (child->IsElement()) { 1.9392 + child->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS); 1.9393 + } 1.9394 + if (addChildItems) { 1.9395 + AddFrameConstructionItems(aState, child, iter.XBLInvolved(), aFrame, 1.9396 + itemsToConstruct); 1.9397 + } else { 1.9398 + ClearLazyBits(child, child->GetNextSibling()); 1.9399 + } 1.9400 + } 1.9401 + itemsToConstruct.SetParentHasNoXBLChildren(!iter.XBLInvolved()); 1.9402 + 1.9403 + if (aCanHaveGeneratedContent) { 1.9404 + // Probe for generated content after 1.9405 + CreateGeneratedContentItem(aState, aFrame, aContent, styleContext, 1.9406 + nsCSSPseudoElements::ePseudo_after, 1.9407 + itemsToConstruct); 1.9408 + } 1.9409 + } else { 1.9410 + ClearLazyBits(aContent->GetFirstChild(), nullptr); 1.9411 + } 1.9412 + 1.9413 + ConstructFramesFromItemList(aState, itemsToConstruct, aFrame, aFrameItems); 1.9414 + 1.9415 + NS_ASSERTION(!aAllowBlockStyles || !aFrame->IsBoxFrame(), 1.9416 + "can't be both block and box"); 1.9417 + 1.9418 + if (haveFirstLetterStyle) { 1.9419 + WrapFramesInFirstLetterFrame(aContent, aFrame, aFrameItems); 1.9420 + } 1.9421 + if (haveFirstLineStyle) { 1.9422 + WrapFramesInFirstLineFrame(aState, aContent, aFrame, nullptr, 1.9423 + aFrameItems); 1.9424 + } 1.9425 + 1.9426 + // We might end up with first-line frames that change 1.9427 + // AnyKidsNeedBlockParent() without changing itemsToConstruct, but that 1.9428 + // should never happen for cases whan aFrame->IsBoxFrame(). 1.9429 + NS_ASSERTION(!haveFirstLineStyle || !aFrame->IsBoxFrame(), 1.9430 + "Shouldn't have first-line style if we're a box"); 1.9431 + NS_ASSERTION(!aFrame->IsBoxFrame() || 1.9432 + itemsToConstruct.AnyItemsNeedBlockParent() == 1.9433 + (AnyKidsNeedBlockParent(aFrameItems.FirstChild()) != nullptr), 1.9434 + "Something went awry in our block parent calculations"); 1.9435 + 1.9436 + if (aFrame->IsBoxFrame() && itemsToConstruct.AnyItemsNeedBlockParent()) { 1.9437 + // XXXbz we could do this on the FrameConstructionItemList level, 1.9438 + // no? And if we cared we could look through the item list 1.9439 + // instead of groveling through the framelist here.. 1.9440 + nsStyleContext *frameStyleContext = aFrame->StyleContext(); 1.9441 + // Report a warning for non-GC frames, for chrome: 1.9442 + if (!aFrame->IsGeneratedContentFrame() && 1.9443 + mPresShell->GetPresContext()->IsChrome()) { 1.9444 + nsIContent *badKid = AnyKidsNeedBlockParent(aFrameItems.FirstChild()); 1.9445 + nsDependentAtomString parentTag(aContent->Tag()), kidTag(badKid->Tag()); 1.9446 + const char16_t* params[] = { parentTag.get(), kidTag.get() }; 1.9447 + const nsStyleDisplay *display = frameStyleContext->StyleDisplay(); 1.9448 + const char *message = 1.9449 + (display->mDisplay == NS_STYLE_DISPLAY_INLINE_BOX) 1.9450 + ? "NeededToWrapXULInlineBox" : "NeededToWrapXUL"; 1.9451 + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, 1.9452 + NS_LITERAL_CSTRING("FrameConstructor"), 1.9453 + mDocument, 1.9454 + nsContentUtils::eXUL_PROPERTIES, 1.9455 + message, 1.9456 + params, ArrayLength(params)); 1.9457 + } 1.9458 + 1.9459 + nsRefPtr<nsStyleContext> blockSC = mPresShell->StyleSet()-> 1.9460 + ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozXULAnonymousBlock, 1.9461 + frameStyleContext); 1.9462 + nsIFrame *blockFrame = NS_NewBlockFrame(mPresShell, blockSC); 1.9463 + // We might, in theory, want to set NS_BLOCK_FLOAT_MGR and 1.9464 + // NS_BLOCK_MARGIN_ROOT, but I think it's a bad idea given that 1.9465 + // a real block placed here wouldn't get those set on it. 1.9466 + 1.9467 + InitAndRestoreFrame(aState, aContent, aFrame, blockFrame, false); 1.9468 + 1.9469 + NS_ASSERTION(!blockFrame->HasView(), "need to do view reparenting"); 1.9470 + ReparentFrames(this, blockFrame, aFrameItems); 1.9471 + 1.9472 + blockFrame->SetInitialChildList(kPrincipalList, aFrameItems); 1.9473 + NS_ASSERTION(aFrameItems.IsEmpty(), "How did that happen?"); 1.9474 + aFrameItems.Clear(); 1.9475 + aFrameItems.AddChild(blockFrame); 1.9476 + 1.9477 + aFrame->AddStateBits(NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK); 1.9478 + } 1.9479 +} 1.9480 + 1.9481 +//---------------------------------------------------------------------- 1.9482 + 1.9483 +// Support for :first-line style 1.9484 + 1.9485 +// Special routine to handle placing a list of frames into a block 1.9486 +// frame that has first-line style. The routine ensures that the first 1.9487 +// collection of inline frames end up in a first-line frame. 1.9488 +// NOTE: aState may have containing block information related to a 1.9489 +// different part of the frame tree than where the first line occurs. 1.9490 +// In particular aState may be set up for where ContentInserted or 1.9491 +// ContentAppended is inserting content, which may be some 1.9492 +// non-first-in-flow continuation of the block to which the first-line 1.9493 +// belongs. So this function needs to be careful about how it uses 1.9494 +// aState. 1.9495 +void 1.9496 +nsCSSFrameConstructor::WrapFramesInFirstLineFrame( 1.9497 + nsFrameConstructorState& aState, 1.9498 + nsIContent* aBlockContent, 1.9499 + nsIFrame* aBlockFrame, 1.9500 + nsIFrame* aLineFrame, 1.9501 + nsFrameItems& aFrameItems) 1.9502 +{ 1.9503 + // Find the part of aFrameItems that we want to put in the first-line 1.9504 + nsFrameList::FrameLinkEnumerator link(aFrameItems); 1.9505 + while (!link.AtEnd() && link.NextFrame()->IsInlineOutside()) { 1.9506 + link.Next(); 1.9507 + } 1.9508 + 1.9509 + nsFrameList firstLineChildren = aFrameItems.ExtractHead(link); 1.9510 + 1.9511 + if (firstLineChildren.IsEmpty()) { 1.9512 + // Nothing is supposed to go into the first-line; nothing to do 1.9513 + return; 1.9514 + } 1.9515 + 1.9516 + if (!aLineFrame) { 1.9517 + // Create line frame 1.9518 + nsStyleContext* parentStyle = 1.9519 + nsFrame::CorrectStyleParentFrame(aBlockFrame, 1.9520 + nsCSSPseudoElements::firstLine)-> 1.9521 + StyleContext(); 1.9522 + nsRefPtr<nsStyleContext> firstLineStyle = GetFirstLineStyle(aBlockContent, 1.9523 + parentStyle); 1.9524 + 1.9525 + aLineFrame = NS_NewFirstLineFrame(mPresShell, firstLineStyle); 1.9526 + 1.9527 + // Initialize the line frame 1.9528 + InitAndRestoreFrame(aState, aBlockContent, aBlockFrame, aLineFrame); 1.9529 + 1.9530 + // The lineFrame will be the block's first child; the rest of the 1.9531 + // frame list (after lastInlineFrame) will be the second and 1.9532 + // subsequent children; insert lineFrame into aFrameItems. 1.9533 + aFrameItems.InsertFrame(nullptr, nullptr, aLineFrame); 1.9534 + 1.9535 + NS_ASSERTION(aLineFrame->StyleContext() == firstLineStyle, 1.9536 + "Bogus style context on line frame"); 1.9537 + } 1.9538 + 1.9539 + // Give the inline frames to the lineFrame <b>after</b> reparenting them 1.9540 + ReparentFrames(this, aLineFrame, firstLineChildren); 1.9541 + if (aLineFrame->PrincipalChildList().IsEmpty() && 1.9542 + (aLineFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { 1.9543 + aLineFrame->SetInitialChildList(kPrincipalList, firstLineChildren); 1.9544 + } else { 1.9545 + AppendFrames(aLineFrame, kPrincipalList, firstLineChildren); 1.9546 + } 1.9547 +} 1.9548 + 1.9549 +// Special routine to handle appending a new frame to a block frame's 1.9550 +// child list. Takes care of placing the new frame into the right 1.9551 +// place when first-line style is present. 1.9552 +void 1.9553 +nsCSSFrameConstructor::AppendFirstLineFrames( 1.9554 + nsFrameConstructorState& aState, 1.9555 + nsIContent* aBlockContent, 1.9556 + nsIFrame* aBlockFrame, 1.9557 + nsFrameItems& aFrameItems) 1.9558 +{ 1.9559 + // It's possible that aBlockFrame needs to have a first-line frame 1.9560 + // created because it doesn't currently have any children. 1.9561 + const nsFrameList& blockKids = aBlockFrame->PrincipalChildList(); 1.9562 + if (blockKids.IsEmpty()) { 1.9563 + WrapFramesInFirstLineFrame(aState, aBlockContent, 1.9564 + aBlockFrame, nullptr, aFrameItems); 1.9565 + return; 1.9566 + } 1.9567 + 1.9568 + // Examine the last block child - if it's a first-line frame then 1.9569 + // appended frames need special treatment. 1.9570 + nsIFrame* lastBlockKid = blockKids.LastChild(); 1.9571 + if (lastBlockKid->GetType() != nsGkAtoms::lineFrame) { 1.9572 + // No first-line frame at the end of the list, therefore there is 1.9573 + // an intervening block between any first-line frame the frames 1.9574 + // we are appending. Therefore, we don't need any special 1.9575 + // treatment of the appended frames. 1.9576 + return; 1.9577 + } 1.9578 + 1.9579 + WrapFramesInFirstLineFrame(aState, aBlockContent, aBlockFrame, 1.9580 + lastBlockKid, aFrameItems); 1.9581 +} 1.9582 + 1.9583 +// Special routine to handle inserting a new frame into a block 1.9584 +// frame's child list. Takes care of placing the new frame into the 1.9585 +// right place when first-line style is present. 1.9586 +nsresult 1.9587 +nsCSSFrameConstructor::InsertFirstLineFrames( 1.9588 + nsFrameConstructorState& aState, 1.9589 + nsIContent* aContent, 1.9590 + nsIFrame* aBlockFrame, 1.9591 + nsIFrame** aParentFrame, 1.9592 + nsIFrame* aPrevSibling, 1.9593 + nsFrameItems& aFrameItems) 1.9594 +{ 1.9595 + nsresult rv = NS_OK; 1.9596 + // XXXbz If you make this method actually do something, check to 1.9597 + // make sure that the caller is passing what you expect. In 1.9598 + // particular, which content is aContent? And audit the rest of 1.9599 + // this code too; it makes bogus assumptions and may not build. 1.9600 +#if 0 1.9601 + nsIFrame* parentFrame = *aParentFrame; 1.9602 + nsIFrame* newFrame = aFrameItems.childList; 1.9603 + bool isInline = IsInlineOutside(newFrame); 1.9604 + 1.9605 + if (!aPrevSibling) { 1.9606 + // Insertion will become the first frame. Two cases: we either 1.9607 + // already have a first-line frame or we don't. 1.9608 + nsIFrame* firstBlockKid = aBlockFrame->GetFirstPrincipalChild(); 1.9609 + if (firstBlockKid->GetType() == nsGkAtoms::lineFrame) { 1.9610 + // We already have a first-line frame 1.9611 + nsIFrame* lineFrame = firstBlockKid; 1.9612 + 1.9613 + if (isInline) { 1.9614 + // Easy case: the new inline frame will go into the lineFrame. 1.9615 + ReparentFrame(this, lineFrame, newFrame); 1.9616 + InsertFrames(lineFrame, kPrincipalList, nullptr, newFrame); 1.9617 + 1.9618 + // Since the frame is going into the lineFrame, don't let it 1.9619 + // go into the block too. 1.9620 + aFrameItems.childList = nullptr; 1.9621 + aFrameItems.lastChild = nullptr; 1.9622 + } 1.9623 + else { 1.9624 + // Harder case: We are about to insert a block level element 1.9625 + // before the first-line frame. 1.9626 + // XXX need a method to steal away frames from the line-frame 1.9627 + } 1.9628 + } 1.9629 + else { 1.9630 + // We do not have a first-line frame 1.9631 + if (isInline) { 1.9632 + // We now need a first-line frame to contain the inline frame. 1.9633 + nsIFrame* lineFrame = NS_NewFirstLineFrame(firstLineStyle); 1.9634 + 1.9635 + if (NS_SUCCEEDED(rv)) { 1.9636 + // Lookup first-line style context 1.9637 + nsStyleContext* parentStyle = 1.9638 + nsFrame::CorrectStyleParentFrame(aBlockFrame, 1.9639 + nsCSSPseudoElements::firstLine)-> 1.9640 + StyleContext(); 1.9641 + nsRefPtr<nsStyleContext> firstLineStyle = 1.9642 + GetFirstLineStyle(aContent, parentStyle); 1.9643 + 1.9644 + // Initialize the line frame 1.9645 + InitAndRestoreFrame(aState, aContent, aBlockFrame, lineFrame); 1.9646 + 1.9647 + // Make sure the caller inserts the lineFrame into the 1.9648 + // blocks list of children. 1.9649 + aFrameItems.childList = lineFrame; 1.9650 + aFrameItems.lastChild = lineFrame; 1.9651 + 1.9652 + // Give the inline frames to the lineFrame <b>after</b> 1.9653 + // reparenting them 1.9654 + NS_ASSERTION(lineFrame->StyleContext() == firstLineStyle, 1.9655 + "Bogus style context on line frame"); 1.9656 + ReparentFrame(aPresContext, lineFrame, newFrame); 1.9657 + lineFrame->SetInitialChildList(kPrincipalList, newFrame); 1.9658 + } 1.9659 + } 1.9660 + else { 1.9661 + // Easy case: the regular insertion logic can insert the new 1.9662 + // frame because it's a block frame. 1.9663 + } 1.9664 + } 1.9665 + } 1.9666 + else { 1.9667 + // Insertion will not be the first frame. 1.9668 + nsIFrame* prevSiblingParent = aPrevSibling->GetParent(); 1.9669 + if (prevSiblingParent == aBlockFrame) { 1.9670 + // Easy case: The prev-siblings parent is the block 1.9671 + // frame. Therefore the prev-sibling is not currently in a 1.9672 + // line-frame. Therefore the new frame which is going after it, 1.9673 + // regardless of type, is not going into a line-frame. 1.9674 + } 1.9675 + else { 1.9676 + // If the prevSiblingParent is not the block-frame then it must 1.9677 + // be a line-frame (if it were a letter-frame, that logic would 1.9678 + // already have adjusted the prev-sibling to be the 1.9679 + // letter-frame). 1.9680 + if (isInline) { 1.9681 + // Easy case: the insertion can go where the caller thinks it 1.9682 + // should go (which is into prevSiblingParent). 1.9683 + } 1.9684 + else { 1.9685 + // Block elements don't end up in line-frames, therefore 1.9686 + // change the insertion point to aBlockFrame. However, there 1.9687 + // might be more inline elements following aPrevSibling that 1.9688 + // need to be pulled out of the line-frame and become children 1.9689 + // of the block. 1.9690 + nsIFrame* nextSibling = aPrevSibling->GetNextSibling(); 1.9691 + nsIFrame* nextLineFrame = prevSiblingParent->GetNextInFlow(); 1.9692 + if (nextSibling || nextLineFrame) { 1.9693 + // Oy. We have work to do. Create a list of the new frames 1.9694 + // that are going into the block by stripping them away from 1.9695 + // the line-frame(s). 1.9696 + if (nextSibling) { 1.9697 + nsLineFrame* lineFrame = (nsLineFrame*) prevSiblingParent; 1.9698 + nsFrameList tail = lineFrame->StealFramesAfter(aPrevSibling); 1.9699 + // XXX do something with 'tail' 1.9700 + } 1.9701 + 1.9702 + nsLineFrame* nextLineFrame = (nsLineFrame*) lineFrame; 1.9703 + for (;;) { 1.9704 + nextLineFrame = nextLineFrame->GetNextInFlow(); 1.9705 + if (!nextLineFrame) { 1.9706 + break; 1.9707 + } 1.9708 + nsIFrame* kids = nextLineFrame->GetFirstPrincipalChild(); 1.9709 + } 1.9710 + } 1.9711 + else { 1.9712 + // We got lucky: aPrevSibling was the last inline frame in 1.9713 + // the line-frame. 1.9714 + ReparentFrame(this, aBlockFrame, newFrame); 1.9715 + InsertFrames(aBlockFrame, kPrincipalList, 1.9716 + prevSiblingParent, newFrame); 1.9717 + aFrameItems.childList = nullptr; 1.9718 + aFrameItems.lastChild = nullptr; 1.9719 + } 1.9720 + } 1.9721 + } 1.9722 + } 1.9723 + 1.9724 +#endif 1.9725 + return rv; 1.9726 +} 1.9727 + 1.9728 +//---------------------------------------------------------------------- 1.9729 + 1.9730 +// First-letter support 1.9731 + 1.9732 +// Determine how many characters in the text fragment apply to the 1.9733 +// first letter 1.9734 +static int32_t 1.9735 +FirstLetterCount(const nsTextFragment* aFragment) 1.9736 +{ 1.9737 + int32_t count = 0; 1.9738 + int32_t firstLetterLength = 0; 1.9739 + 1.9740 + int32_t i, n = aFragment->GetLength(); 1.9741 + for (i = 0; i < n; i++) { 1.9742 + char16_t ch = aFragment->CharAt(i); 1.9743 + // FIXME: take content language into account when deciding whitespace. 1.9744 + if (dom::IsSpaceCharacter(ch)) { 1.9745 + if (firstLetterLength) { 1.9746 + break; 1.9747 + } 1.9748 + count++; 1.9749 + continue; 1.9750 + } 1.9751 + // XXX I18n 1.9752 + if ((ch == '\'') || (ch == '\"')) { 1.9753 + if (firstLetterLength) { 1.9754 + break; 1.9755 + } 1.9756 + // keep looping 1.9757 + firstLetterLength = 1; 1.9758 + } 1.9759 + else { 1.9760 + count++; 1.9761 + break; 1.9762 + } 1.9763 + } 1.9764 + 1.9765 + return count; 1.9766 +} 1.9767 + 1.9768 +static bool 1.9769 +NeedFirstLetterContinuation(nsIContent* aContent) 1.9770 +{ 1.9771 + NS_PRECONDITION(aContent, "null ptr"); 1.9772 + 1.9773 + bool result = false; 1.9774 + if (aContent) { 1.9775 + const nsTextFragment* frag = aContent->GetText(); 1.9776 + if (frag) { 1.9777 + int32_t flc = FirstLetterCount(frag); 1.9778 + int32_t tl = frag->GetLength(); 1.9779 + if (flc < tl) { 1.9780 + result = true; 1.9781 + } 1.9782 + } 1.9783 + } 1.9784 + return result; 1.9785 +} 1.9786 + 1.9787 +static bool IsFirstLetterContent(nsIContent* aContent) 1.9788 +{ 1.9789 + return aContent->TextLength() && 1.9790 + !aContent->TextIsOnlyWhitespace(); 1.9791 +} 1.9792 + 1.9793 +/** 1.9794 + * Create a letter frame, only make it a floating frame. 1.9795 + */ 1.9796 +void 1.9797 +nsCSSFrameConstructor::CreateFloatingLetterFrame( 1.9798 + nsFrameConstructorState& aState, 1.9799 + nsIFrame* aBlockFrame, 1.9800 + nsIContent* aTextContent, 1.9801 + nsIFrame* aTextFrame, 1.9802 + nsIContent* aBlockContent, 1.9803 + nsIFrame* aParentFrame, 1.9804 + nsStyleContext* aStyleContext, 1.9805 + nsFrameItems& aResult) 1.9806 +{ 1.9807 + // Create the first-letter-frame 1.9808 + nsIFrame* letterFrame; 1.9809 + nsStyleSet *styleSet = mPresShell->StyleSet(); 1.9810 + 1.9811 + letterFrame = NS_NewFirstLetterFrame(mPresShell, aStyleContext); 1.9812 + // We don't want to use a text content for a non-text frame (because we want 1.9813 + // its primary frame to be a text frame). So use its parent for the 1.9814 + // first-letter. 1.9815 + nsIContent* letterContent = aTextContent->GetParent(); 1.9816 + nsIFrame* containingBlock = aState.GetGeometricParent( 1.9817 + aStyleContext->StyleDisplay(), aParentFrame); 1.9818 + InitAndRestoreFrame(aState, letterContent, containingBlock, letterFrame); 1.9819 + 1.9820 + // Init the text frame to refer to the letter frame. Make sure we 1.9821 + // get a proper style context for it (the one passed in is for the 1.9822 + // letter frame and will have the float property set on it; the text 1.9823 + // frame shouldn't have that set). 1.9824 + nsRefPtr<nsStyleContext> textSC; 1.9825 + textSC = styleSet->ResolveStyleForNonElement(aStyleContext); 1.9826 + aTextFrame->SetStyleContextWithoutNotification(textSC); 1.9827 + InitAndRestoreFrame(aState, aTextContent, letterFrame, aTextFrame); 1.9828 + 1.9829 + // And then give the text frame to the letter frame 1.9830 + SetInitialSingleChild(letterFrame, aTextFrame); 1.9831 + 1.9832 + // See if we will need to continue the text frame (does it contain 1.9833 + // more than just the first-letter text or not?) If it does, then we 1.9834 + // create (in advance) a continuation frame for it. 1.9835 + nsIFrame* nextTextFrame = nullptr; 1.9836 + if (NeedFirstLetterContinuation(aTextContent)) { 1.9837 + // Create continuation 1.9838 + nextTextFrame = 1.9839 + CreateContinuingFrame(aState.mPresContext, aTextFrame, aParentFrame); 1.9840 + // Repair the continuations style context 1.9841 + nsStyleContext* parentStyleContext = aStyleContext->GetParent(); 1.9842 + if (parentStyleContext) { 1.9843 + nsRefPtr<nsStyleContext> newSC; 1.9844 + newSC = styleSet->ResolveStyleForNonElement(parentStyleContext); 1.9845 + nextTextFrame->SetStyleContext(newSC); 1.9846 + } 1.9847 + } 1.9848 + 1.9849 + NS_ASSERTION(aResult.IsEmpty(), "aResult should be an empty nsFrameItems!"); 1.9850 + // Put the new float before any of the floats in the block we're doing 1.9851 + // first-letter for, that is, before any floats whose parent is 1.9852 + // containingBlock. 1.9853 + nsFrameList::FrameLinkEnumerator link(aState.mFloatedItems); 1.9854 + while (!link.AtEnd() && link.NextFrame()->GetParent() != containingBlock) { 1.9855 + link.Next(); 1.9856 + } 1.9857 + 1.9858 + aState.AddChild(letterFrame, aResult, letterContent, aStyleContext, 1.9859 + aParentFrame, false, true, false, true, 1.9860 + link.PrevFrame()); 1.9861 + 1.9862 + if (nextTextFrame) { 1.9863 + aResult.AddChild(nextTextFrame); 1.9864 + } 1.9865 +} 1.9866 + 1.9867 +/** 1.9868 + * Create a new letter frame for aTextFrame. The letter frame will be 1.9869 + * a child of aParentFrame. 1.9870 + */ 1.9871 +void 1.9872 +nsCSSFrameConstructor::CreateLetterFrame(nsIFrame* aBlockFrame, 1.9873 + nsIFrame* aBlockContinuation, 1.9874 + nsIContent* aTextContent, 1.9875 + nsIFrame* aParentFrame, 1.9876 + nsFrameItems& aResult) 1.9877 +{ 1.9878 + NS_PRECONDITION(aTextContent->IsNodeOfType(nsINode::eTEXT), 1.9879 + "aTextContent isn't text"); 1.9880 + NS_ASSERTION(nsLayoutUtils::GetAsBlock(aBlockFrame), 1.9881 + "Not a block frame?"); 1.9882 + 1.9883 + // Get style context for the first-letter-frame 1.9884 + nsStyleContext* parentStyleContext = 1.9885 + nsFrame::CorrectStyleParentFrame(aParentFrame, 1.9886 + nsCSSPseudoElements::firstLetter)-> 1.9887 + StyleContext(); 1.9888 + 1.9889 + // Use content from containing block so that we can actually 1.9890 + // find a matching style rule. 1.9891 + nsIContent* blockContent = aBlockFrame->GetContent(); 1.9892 + 1.9893 + // Create first-letter style rule 1.9894 + nsRefPtr<nsStyleContext> sc = GetFirstLetterStyle(blockContent, 1.9895 + parentStyleContext); 1.9896 + if (sc) { 1.9897 + nsRefPtr<nsStyleContext> textSC; 1.9898 + textSC = mPresShell->StyleSet()->ResolveStyleForNonElement(sc); 1.9899 + 1.9900 + // Create a new text frame (the original one will be discarded) 1.9901 + // pass a temporary stylecontext, the correct one will be set 1.9902 + // later. Start off by unsetting the primary frame for 1.9903 + // aTextContent, so it's no longer pointing to the to-be-destroyed 1.9904 + // frame. 1.9905 + // XXXbz it would be really nice to destroy the old frame _first_, 1.9906 + // then create the new one, so we could avoid this hack. 1.9907 + aTextContent->SetPrimaryFrame(nullptr); 1.9908 + nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC); 1.9909 + 1.9910 + NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame), 1.9911 + "Containing block is confused"); 1.9912 + nsFrameConstructorState state(mPresShell, 1.9913 + GetAbsoluteContainingBlock(aParentFrame, FIXED_POS), 1.9914 + GetAbsoluteContainingBlock(aParentFrame, ABS_POS), 1.9915 + aBlockContinuation); 1.9916 + 1.9917 + // Create the right type of first-letter frame 1.9918 + const nsStyleDisplay* display = sc->StyleDisplay(); 1.9919 + if (display->IsFloatingStyle() && !aParentFrame->IsSVGText()) { 1.9920 + // Make a floating first-letter frame 1.9921 + CreateFloatingLetterFrame(state, aBlockFrame, aTextContent, textFrame, 1.9922 + blockContent, aParentFrame, sc, aResult); 1.9923 + } 1.9924 + else { 1.9925 + // Make an inflow first-letter frame 1.9926 + nsIFrame* letterFrame = NS_NewFirstLetterFrame(mPresShell, sc); 1.9927 + 1.9928 + // Initialize the first-letter-frame. We don't want to use a text 1.9929 + // content for a non-text frame (because we want its primary frame to 1.9930 + // be a text frame). So use its parent for the first-letter. 1.9931 + nsIContent* letterContent = aTextContent->GetParent(); 1.9932 + letterFrame->Init(letterContent, aParentFrame, nullptr); 1.9933 + 1.9934 + InitAndRestoreFrame(state, aTextContent, letterFrame, textFrame); 1.9935 + 1.9936 + SetInitialSingleChild(letterFrame, textFrame); 1.9937 + aResult.Clear(); 1.9938 + aResult.AddChild(letterFrame); 1.9939 + NS_ASSERTION(!aBlockFrame->GetPrevContinuation(), 1.9940 + "should have the first continuation here"); 1.9941 + aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD); 1.9942 + } 1.9943 + aTextContent->SetPrimaryFrame(textFrame); 1.9944 + } 1.9945 +} 1.9946 + 1.9947 +void 1.9948 +nsCSSFrameConstructor::WrapFramesInFirstLetterFrame( 1.9949 + nsIContent* aBlockContent, 1.9950 + nsIFrame* aBlockFrame, 1.9951 + nsFrameItems& aBlockFrames) 1.9952 +{ 1.9953 + aBlockFrame->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE); 1.9954 + 1.9955 + nsIFrame* parentFrame = nullptr; 1.9956 + nsIFrame* textFrame = nullptr; 1.9957 + nsIFrame* prevFrame = nullptr; 1.9958 + nsFrameItems letterFrames; 1.9959 + bool stopLooking = false; 1.9960 + WrapFramesInFirstLetterFrame(aBlockFrame, aBlockFrame, aBlockFrame, 1.9961 + aBlockFrames.FirstChild(), 1.9962 + &parentFrame, &textFrame, &prevFrame, 1.9963 + letterFrames, &stopLooking); 1.9964 + if (parentFrame) { 1.9965 + if (parentFrame == aBlockFrame) { 1.9966 + // Take textFrame out of the block's frame list and substitute the 1.9967 + // letter frame(s) instead. 1.9968 + aBlockFrames.DestroyFrame(textFrame); 1.9969 + aBlockFrames.InsertFrames(nullptr, prevFrame, letterFrames); 1.9970 + } 1.9971 + else { 1.9972 + // Take the old textFrame out of the inline parent's child list 1.9973 + RemoveFrame(kPrincipalList, textFrame); 1.9974 + 1.9975 + // Insert in the letter frame(s) 1.9976 + parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames); 1.9977 + } 1.9978 + } 1.9979 +} 1.9980 + 1.9981 +void 1.9982 +nsCSSFrameConstructor::WrapFramesInFirstLetterFrame( 1.9983 + nsIFrame* aBlockFrame, 1.9984 + nsIFrame* aBlockContinuation, 1.9985 + nsIFrame* aParentFrame, 1.9986 + nsIFrame* aParentFrameList, 1.9987 + nsIFrame** aModifiedParent, 1.9988 + nsIFrame** aTextFrame, 1.9989 + nsIFrame** aPrevFrame, 1.9990 + nsFrameItems& aLetterFrames, 1.9991 + bool* aStopLooking) 1.9992 +{ 1.9993 + nsIFrame* prevFrame = nullptr; 1.9994 + nsIFrame* frame = aParentFrameList; 1.9995 + 1.9996 + while (frame) { 1.9997 + nsIFrame* nextFrame = frame->GetNextSibling(); 1.9998 + 1.9999 + nsIAtom* frameType = frame->GetType(); 1.10000 + if (nsGkAtoms::textFrame == frameType) { 1.10001 + // Wrap up first-letter content in a letter frame 1.10002 + nsIContent* textContent = frame->GetContent(); 1.10003 + if (IsFirstLetterContent(textContent)) { 1.10004 + // Create letter frame to wrap up the text 1.10005 + CreateLetterFrame(aBlockFrame, aBlockContinuation, textContent, 1.10006 + aParentFrame, aLetterFrames); 1.10007 + 1.10008 + // Provide adjustment information for parent 1.10009 + *aModifiedParent = aParentFrame; 1.10010 + *aTextFrame = frame; 1.10011 + *aPrevFrame = prevFrame; 1.10012 + *aStopLooking = true; 1.10013 + return; 1.10014 + } 1.10015 + } 1.10016 + else if (IsInlineFrame(frame) && frameType != nsGkAtoms::brFrame) { 1.10017 + nsIFrame* kids = frame->GetFirstPrincipalChild(); 1.10018 + WrapFramesInFirstLetterFrame(aBlockFrame, aBlockContinuation, frame, 1.10019 + kids, aModifiedParent, aTextFrame, 1.10020 + aPrevFrame, aLetterFrames, aStopLooking); 1.10021 + if (*aStopLooking) { 1.10022 + return; 1.10023 + } 1.10024 + } 1.10025 + else { 1.10026 + // This will stop us looking to create more letter frames. For 1.10027 + // example, maybe the frame-type is "letterFrame" or 1.10028 + // "placeholderFrame". This keeps us from creating extra letter 1.10029 + // frames, and also prevents us from creating letter frames when 1.10030 + // the first real content child of a block is not text (e.g. an 1.10031 + // image, hr, etc.) 1.10032 + *aStopLooking = true; 1.10033 + break; 1.10034 + } 1.10035 + 1.10036 + prevFrame = frame; 1.10037 + frame = nextFrame; 1.10038 + } 1.10039 +} 1.10040 + 1.10041 +static nsIFrame* 1.10042 +FindFirstLetterFrame(nsIFrame* aFrame, nsIFrame::ChildListID aListID) 1.10043 +{ 1.10044 + nsFrameList list = aFrame->GetChildList(aListID); 1.10045 + for (nsFrameList::Enumerator e(list); !e.AtEnd(); e.Next()) { 1.10046 + if (nsGkAtoms::letterFrame == e.get()->GetType()) { 1.10047 + return e.get(); 1.10048 + } 1.10049 + } 1.10050 + return nullptr; 1.10051 +} 1.10052 + 1.10053 +nsresult 1.10054 +nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames( 1.10055 + nsPresContext* aPresContext, 1.10056 + nsIPresShell* aPresShell, 1.10057 + nsIFrame* aBlockFrame, 1.10058 + bool* aStopLooking) 1.10059 +{ 1.10060 + // Look for the first letter frame on the kFloatList, then kPushedFloatsList. 1.10061 + nsIFrame* floatFrame = 1.10062 + ::FindFirstLetterFrame(aBlockFrame, nsIFrame::kFloatList); 1.10063 + if (!floatFrame) { 1.10064 + floatFrame = 1.10065 + ::FindFirstLetterFrame(aBlockFrame, nsIFrame::kPushedFloatsList); 1.10066 + if (!floatFrame) { 1.10067 + return NS_OK; 1.10068 + } 1.10069 + } 1.10070 + 1.10071 + // Take the text frame away from the letter frame (so it isn't 1.10072 + // destroyed when we destroy the letter frame). 1.10073 + nsIFrame* textFrame = floatFrame->GetFirstPrincipalChild(); 1.10074 + if (!textFrame) { 1.10075 + return NS_OK; 1.10076 + } 1.10077 + 1.10078 + // Discover the placeholder frame for the letter frame 1.10079 + nsIFrame* parentFrame; 1.10080 + nsPlaceholderFrame* placeholderFrame = GetPlaceholderFrameFor(floatFrame); 1.10081 + 1.10082 + if (!placeholderFrame) { 1.10083 + // Somethings really wrong 1.10084 + return NS_OK; 1.10085 + } 1.10086 + parentFrame = placeholderFrame->GetParent(); 1.10087 + if (!parentFrame) { 1.10088 + // Somethings really wrong 1.10089 + return NS_OK; 1.10090 + } 1.10091 + 1.10092 + // Create a new text frame with the right style context that maps 1.10093 + // all of the content that was previously part of the letter frame 1.10094 + // (and probably continued elsewhere). 1.10095 + nsStyleContext* parentSC = parentFrame->StyleContext(); 1.10096 + nsIContent* textContent = textFrame->GetContent(); 1.10097 + if (!textContent) { 1.10098 + return NS_OK; 1.10099 + } 1.10100 + nsRefPtr<nsStyleContext> newSC; 1.10101 + newSC = aPresShell->StyleSet()->ResolveStyleForNonElement(parentSC); 1.10102 + nsIFrame* newTextFrame = NS_NewTextFrame(aPresShell, newSC); 1.10103 + newTextFrame->Init(textContent, parentFrame, nullptr); 1.10104 + 1.10105 + // Destroy the old text frame's continuations (the old text frame 1.10106 + // will be destroyed when its letter frame is destroyed). 1.10107 + nsIFrame* frameToDelete = textFrame->LastContinuation(); 1.10108 + while (frameToDelete != textFrame) { 1.10109 + nsIFrame* nextFrameToDelete = frameToDelete->GetPrevContinuation(); 1.10110 + RemoveFrame(kPrincipalList, frameToDelete); 1.10111 + frameToDelete = nextFrameToDelete; 1.10112 + } 1.10113 + 1.10114 + nsIFrame* prevSibling = placeholderFrame->GetPrevSibling(); 1.10115 + 1.10116 + // Now that everything is set... 1.10117 +#ifdef NOISY_FIRST_LETTER 1.10118 + printf("RemoveFloatingFirstLetterFrames: textContent=%p oldTextFrame=%p newTextFrame=%p\n", 1.10119 + textContent.get(), textFrame, newTextFrame); 1.10120 +#endif 1.10121 + 1.10122 + // Remove placeholder frame and the float 1.10123 + RemoveFrame(kPrincipalList, placeholderFrame); 1.10124 + 1.10125 + // Now that the old frames are gone, we can start pointing to our 1.10126 + // new primary frame. 1.10127 + textContent->SetPrimaryFrame(newTextFrame); 1.10128 + 1.10129 + // Wallpaper bug 822910. 1.10130 + bool offsetsNeedFixing = 1.10131 + prevSibling && prevSibling->GetType() == nsGkAtoms::textFrame; 1.10132 + if (offsetsNeedFixing) { 1.10133 + prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING); 1.10134 + } 1.10135 + 1.10136 + // Insert text frame in its place 1.10137 + nsFrameList textList(newTextFrame, newTextFrame); 1.10138 + InsertFrames(parentFrame, kPrincipalList, prevSibling, textList); 1.10139 + 1.10140 + if (offsetsNeedFixing) { 1.10141 + prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING); 1.10142 + } 1.10143 + 1.10144 + return NS_OK; 1.10145 +} 1.10146 + 1.10147 +nsresult 1.10148 +nsCSSFrameConstructor::RemoveFirstLetterFrames(nsPresContext* aPresContext, 1.10149 + nsIPresShell* aPresShell, 1.10150 + nsIFrame* aFrame, 1.10151 + nsIFrame* aBlockFrame, 1.10152 + bool* aStopLooking) 1.10153 +{ 1.10154 + nsIFrame* prevSibling = nullptr; 1.10155 + nsIFrame* kid = aFrame->GetFirstPrincipalChild(); 1.10156 + 1.10157 + while (kid) { 1.10158 + if (nsGkAtoms::letterFrame == kid->GetType()) { 1.10159 + // Bingo. Found it. First steal away the text frame. 1.10160 + nsIFrame* textFrame = kid->GetFirstPrincipalChild(); 1.10161 + if (!textFrame) { 1.10162 + break; 1.10163 + } 1.10164 + 1.10165 + // Create a new textframe 1.10166 + nsStyleContext* parentSC = aFrame->StyleContext(); 1.10167 + if (!parentSC) { 1.10168 + break; 1.10169 + } 1.10170 + nsIContent* textContent = textFrame->GetContent(); 1.10171 + if (!textContent) { 1.10172 + break; 1.10173 + } 1.10174 + nsRefPtr<nsStyleContext> newSC; 1.10175 + newSC = aPresShell->StyleSet()->ResolveStyleForNonElement(parentSC); 1.10176 + textFrame = NS_NewTextFrame(aPresShell, newSC); 1.10177 + textFrame->Init(textContent, aFrame, nullptr); 1.10178 + 1.10179 + // Next rip out the kid and replace it with the text frame 1.10180 + RemoveFrame(kPrincipalList, kid); 1.10181 + 1.10182 + // Now that the old frames are gone, we can start pointing to our 1.10183 + // new primary frame. 1.10184 + textContent->SetPrimaryFrame(textFrame); 1.10185 + 1.10186 + // Wallpaper bug 822910. 1.10187 + bool offsetsNeedFixing = 1.10188 + prevSibling && prevSibling->GetType() == nsGkAtoms::textFrame; 1.10189 + if (offsetsNeedFixing) { 1.10190 + prevSibling->AddStateBits(TEXT_OFFSETS_NEED_FIXING); 1.10191 + } 1.10192 + 1.10193 + // Insert text frame in its place 1.10194 + nsFrameList textList(textFrame, textFrame); 1.10195 + InsertFrames(aFrame, kPrincipalList, prevSibling, textList); 1.10196 + 1.10197 + if (offsetsNeedFixing) { 1.10198 + prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING); 1.10199 + } 1.10200 + 1.10201 + *aStopLooking = true; 1.10202 + NS_ASSERTION(!aBlockFrame->GetPrevContinuation(), 1.10203 + "should have the first continuation here"); 1.10204 + aBlockFrame->RemoveStateBits(NS_BLOCK_HAS_FIRST_LETTER_CHILD); 1.10205 + break; 1.10206 + } 1.10207 + else if (IsInlineFrame(kid)) { 1.10208 + // Look inside child inline frame for the letter frame 1.10209 + RemoveFirstLetterFrames(aPresContext, aPresShell, 1.10210 + kid, aBlockFrame, aStopLooking); 1.10211 + if (*aStopLooking) { 1.10212 + break; 1.10213 + } 1.10214 + } 1.10215 + prevSibling = kid; 1.10216 + kid = kid->GetNextSibling(); 1.10217 + } 1.10218 + 1.10219 + return NS_OK; 1.10220 +} 1.10221 + 1.10222 +nsresult 1.10223 +nsCSSFrameConstructor::RemoveLetterFrames(nsPresContext* aPresContext, 1.10224 + nsIPresShell* aPresShell, 1.10225 + nsIFrame* aBlockFrame) 1.10226 +{ 1.10227 + aBlockFrame = aBlockFrame->FirstContinuation(); 1.10228 + nsIFrame* continuation = aBlockFrame; 1.10229 + 1.10230 + bool stopLooking = false; 1.10231 + nsresult rv; 1.10232 + do { 1.10233 + rv = RemoveFloatingFirstLetterFrames(aPresContext, aPresShell, 1.10234 + continuation, &stopLooking); 1.10235 + if (NS_SUCCEEDED(rv) && !stopLooking) { 1.10236 + rv = RemoveFirstLetterFrames(aPresContext, aPresShell, 1.10237 + continuation, aBlockFrame, &stopLooking); 1.10238 + } 1.10239 + if (stopLooking) { 1.10240 + break; 1.10241 + } 1.10242 + continuation = continuation->GetNextContinuation(); 1.10243 + } while (continuation); 1.10244 + return rv; 1.10245 +} 1.10246 + 1.10247 +// Fixup the letter frame situation for the given block 1.10248 +void 1.10249 +nsCSSFrameConstructor::RecoverLetterFrames(nsIFrame* aBlockFrame) 1.10250 +{ 1.10251 + aBlockFrame = aBlockFrame->FirstContinuation(); 1.10252 + nsIFrame* continuation = aBlockFrame; 1.10253 + 1.10254 + nsIFrame* parentFrame = nullptr; 1.10255 + nsIFrame* textFrame = nullptr; 1.10256 + nsIFrame* prevFrame = nullptr; 1.10257 + nsFrameItems letterFrames; 1.10258 + bool stopLooking = false; 1.10259 + do { 1.10260 + // XXX shouldn't this bit be set already (bug 408493), assert instead? 1.10261 + continuation->AddStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE); 1.10262 + WrapFramesInFirstLetterFrame(aBlockFrame, continuation, continuation, 1.10263 + continuation->GetFirstPrincipalChild(), 1.10264 + &parentFrame, &textFrame, &prevFrame, 1.10265 + letterFrames, &stopLooking); 1.10266 + if (stopLooking) { 1.10267 + break; 1.10268 + } 1.10269 + continuation = continuation->GetNextContinuation(); 1.10270 + } while (continuation); 1.10271 + 1.10272 + if (parentFrame) { 1.10273 + // Take the old textFrame out of the parents child list 1.10274 + RemoveFrame(kPrincipalList, textFrame); 1.10275 + 1.10276 + // Insert in the letter frame(s) 1.10277 + parentFrame->InsertFrames(kPrincipalList, prevFrame, letterFrames); 1.10278 + } 1.10279 +} 1.10280 + 1.10281 +//---------------------------------------------------------------------- 1.10282 + 1.10283 +// listbox Widget Routines 1.10284 + 1.10285 +nsresult 1.10286 +nsCSSFrameConstructor::CreateListBoxContent(nsPresContext* aPresContext, 1.10287 + nsIFrame* aParentFrame, 1.10288 + nsIFrame* aPrevFrame, 1.10289 + nsIContent* aChild, 1.10290 + nsIFrame** aNewFrame, 1.10291 + bool aIsAppend, 1.10292 + bool aIsScrollbar, 1.10293 + nsILayoutHistoryState* aFrameState) 1.10294 +{ 1.10295 +#ifdef MOZ_XUL 1.10296 + nsresult rv = NS_OK; 1.10297 + 1.10298 + // Construct a new frame 1.10299 + if (nullptr != aParentFrame) { 1.10300 + nsFrameItems frameItems; 1.10301 + nsFrameConstructorState state(mPresShell, GetAbsoluteContainingBlock(aParentFrame, FIXED_POS), 1.10302 + GetAbsoluteContainingBlock(aParentFrame, ABS_POS), 1.10303 + GetFloatContainingBlock(aParentFrame), 1.10304 + mTempFrameTreeState); 1.10305 + 1.10306 + // If we ever initialize the ancestor filter on |state|, make sure 1.10307 + // to push the right parent! 1.10308 + 1.10309 + nsRefPtr<nsStyleContext> styleContext; 1.10310 + styleContext = ResolveStyleContext(aParentFrame, aChild, &state); 1.10311 + 1.10312 + // Pre-check for display "none" - only if we find that, do we create 1.10313 + // any frame at all 1.10314 + const nsStyleDisplay* display = styleContext->StyleDisplay(); 1.10315 + 1.10316 + if (NS_STYLE_DISPLAY_NONE == display->mDisplay) { 1.10317 + *aNewFrame = nullptr; 1.10318 + return NS_OK; 1.10319 + } 1.10320 + 1.10321 + BeginUpdate(); 1.10322 + 1.10323 + FrameConstructionItemList items; 1.10324 + AddFrameConstructionItemsInternal(state, aChild, aParentFrame, 1.10325 + aChild->Tag(), aChild->GetNameSpaceID(), 1.10326 + true, styleContext, 1.10327 + ITEM_ALLOW_XBL_BASE, nullptr, items); 1.10328 + ConstructFramesFromItemList(state, items, aParentFrame, frameItems); 1.10329 + 1.10330 + nsIFrame* newFrame = frameItems.FirstChild(); 1.10331 + *aNewFrame = newFrame; 1.10332 + 1.10333 + if (newFrame) { 1.10334 + // Notify the parent frame 1.10335 + if (aIsAppend) 1.10336 + rv = ((nsListBoxBodyFrame*)aParentFrame)->ListBoxAppendFrames(frameItems); 1.10337 + else 1.10338 + rv = ((nsListBoxBodyFrame*)aParentFrame)->ListBoxInsertFrames(aPrevFrame, frameItems); 1.10339 + } 1.10340 + 1.10341 + EndUpdate(); 1.10342 + 1.10343 +#ifdef ACCESSIBILITY 1.10344 + if (newFrame) { 1.10345 + nsAccessibilityService* accService = nsIPresShell::AccService(); 1.10346 + if (accService) { 1.10347 + accService->ContentRangeInserted(mPresShell, aChild->GetParent(), 1.10348 + aChild, aChild->GetNextSibling()); 1.10349 + } 1.10350 + } 1.10351 +#endif 1.10352 + } 1.10353 + 1.10354 + return rv; 1.10355 +#else 1.10356 + return NS_ERROR_FAILURE; 1.10357 +#endif 1.10358 +} 1.10359 + 1.10360 +//---------------------------------------- 1.10361 + 1.10362 +void 1.10363 +nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState& aState, 1.10364 + const nsStyleDisplay* aDisplay, 1.10365 + nsIContent* aContent, 1.10366 + nsIFrame* aParentFrame, 1.10367 + nsIFrame* aContentParentFrame, 1.10368 + nsStyleContext* aStyleContext, 1.10369 + nsIFrame** aNewFrame, 1.10370 + nsFrameItems& aFrameItems, 1.10371 + nsIFrame* aPositionedFrameForAbsPosContainer, 1.10372 + PendingBinding* aPendingBinding) 1.10373 +{ 1.10374 + // Create column wrapper if necessary 1.10375 + nsIFrame* blockFrame = *aNewFrame; 1.10376 + NS_ASSERTION(blockFrame->GetType() == nsGkAtoms::blockFrame, "not a block frame?"); 1.10377 + nsIFrame* parent = aParentFrame; 1.10378 + nsRefPtr<nsStyleContext> blockStyle = aStyleContext; 1.10379 + const nsStyleColumn* columns = aStyleContext->StyleColumn(); 1.10380 + 1.10381 + if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO 1.10382 + || columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) { 1.10383 + nsIFrame* columnSetFrame = nullptr; 1.10384 + columnSetFrame = 1.10385 + NS_NewColumnSetFrame(mPresShell, aStyleContext, nsFrameState(0)); 1.10386 + 1.10387 + InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetFrame); 1.10388 + blockStyle = mPresShell->StyleSet()-> 1.10389 + ResolveAnonymousBoxStyle(nsCSSAnonBoxes::columnContent, aStyleContext); 1.10390 + parent = columnSetFrame; 1.10391 + *aNewFrame = columnSetFrame; 1.10392 + 1.10393 + SetInitialSingleChild(columnSetFrame, blockFrame); 1.10394 + } 1.10395 + 1.10396 + blockFrame->SetStyleContextWithoutNotification(blockStyle); 1.10397 + InitAndRestoreFrame(aState, aContent, parent, blockFrame); 1.10398 + 1.10399 + aState.AddChild(*aNewFrame, aFrameItems, aContent, aStyleContext, 1.10400 + aContentParentFrame ? aContentParentFrame : 1.10401 + aParentFrame); 1.10402 + if (!mRootElementFrame) { 1.10403 + // The frame we're constructing will be the root element frame. 1.10404 + // Set mRootElementFrame before processing children. 1.10405 + mRootElementFrame = *aNewFrame; 1.10406 + } 1.10407 + 1.10408 + // We should make the outer frame be the absolute containing block, 1.10409 + // if one is required. We have to do this because absolute 1.10410 + // positioning must be computed with respect to the CSS dimensions 1.10411 + // of the element, which are the dimensions of the outer block. But 1.10412 + // we can't really do that because only blocks can have absolute 1.10413 + // children. So use the block and try to compensate with hacks 1.10414 + // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes. 1.10415 + nsFrameConstructorSaveState absoluteSaveState; 1.10416 + (*aNewFrame)->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); 1.10417 + if (aPositionedFrameForAbsPosContainer) { 1.10418 + // NS_ASSERTION(aRelPos, "should have made area frame for this"); 1.10419 + aState.PushAbsoluteContainingBlock(*aNewFrame, aPositionedFrameForAbsPosContainer, absoluteSaveState); 1.10420 + } 1.10421 + 1.10422 + // Process the child content 1.10423 + nsFrameItems childItems; 1.10424 + ProcessChildren(aState, aContent, aStyleContext, blockFrame, true, 1.10425 + childItems, true, aPendingBinding); 1.10426 + 1.10427 + // Set the frame's initial child list 1.10428 + blockFrame->SetInitialChildList(kPrincipalList, childItems); 1.10429 +} 1.10430 + 1.10431 +nsIFrame* 1.10432 +nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState, 1.10433 + FrameConstructionItem& aItem, 1.10434 + nsIFrame* aParentFrame, 1.10435 + const nsStyleDisplay* aDisplay, 1.10436 + nsFrameItems& aFrameItems) 1.10437 +{ 1.10438 + // If an inline frame has non-inline kids, then we chop up the child list 1.10439 + // into runs of blocks and runs of inlines, create anonymous block frames to 1.10440 + // contain the runs of blocks, inline frames with our style context for the 1.10441 + // runs of inlines, and put all these frames, in order, into aFrameItems. We 1.10442 + // return the the first one. The whole setup is called an {ib} 1.10443 + // split; in what follows "frames in the split" refers to the anonymous blocks 1.10444 + // and inlines that contain our children. 1.10445 + // 1.10446 + // {ib} splits maintain the following invariants: 1.10447 + // 1) All frames in the split have the NS_FRAME_PART_OF_IBSPLIT bit 1.10448 + // set. 1.10449 + // 2) Each frame in the split has the nsIFrame::IBSplitSibling 1.10450 + // property pointing to the next frame in the split, except for the last 1.10451 + // one, which does not have it set. 1.10452 + // 3) Each frame in the split has the nsIFrame::IBSplitPrevSibling 1.10453 + // property pointing to the previous frame in the split, except for the 1.10454 + // first one, which does not have it set. 1.10455 + // 4) The first and last frame in the split are always inlines. 1.10456 + // 1.10457 + // An invariant that is NOT maintained is that the wrappers are actually 1.10458 + // linked via GetNextSibling linkage. A simple example is an inline 1.10459 + // containing an inline that contains a block. The three parts of the inner 1.10460 + // inline end up with three different parents. 1.10461 + // 1.10462 + // For example, this HTML: 1.10463 + // <span> 1.10464 + // <div>a</div> 1.10465 + // <span> 1.10466 + // b 1.10467 + // <div>c</div> 1.10468 + // </span> 1.10469 + // d 1.10470 + // <div>e</div> 1.10471 + // f 1.10472 + // </span> 1.10473 + // Gives the following frame tree: 1.10474 + // 1.10475 + // Inline (outer span) 1.10476 + // Block (anonymous, outer span) 1.10477 + // Block (div) 1.10478 + // Text("a") 1.10479 + // Inline (outer span) 1.10480 + // Inline (inner span) 1.10481 + // Text("b") 1.10482 + // Block (anonymous, outer span) 1.10483 + // Block (anonymous, inner span) 1.10484 + // Block (div) 1.10485 + // Text("c") 1.10486 + // Inline (outer span) 1.10487 + // Inline (inner span) 1.10488 + // Text("d") 1.10489 + // Block (anonymous, outer span) 1.10490 + // Block (div) 1.10491 + // Text("e") 1.10492 + // Inline (outer span) 1.10493 + // Text("f") 1.10494 + 1.10495 + nsIContent* const content = aItem.mContent; 1.10496 + nsStyleContext* const styleContext = aItem.mStyleContext; 1.10497 + 1.10498 + bool positioned = 1.10499 + NS_STYLE_DISPLAY_INLINE == aDisplay->mDisplay && 1.10500 + aDisplay->IsRelativelyPositionedStyle() && 1.10501 + !aParentFrame->IsSVGText(); 1.10502 + 1.10503 + nsIFrame* newFrame = NS_NewInlineFrame(mPresShell, styleContext); 1.10504 + 1.10505 + // Initialize the frame 1.10506 + InitAndRestoreFrame(aState, content, aParentFrame, newFrame); 1.10507 + 1.10508 + // Inline frames can always have generated content 1.10509 + newFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT); 1.10510 + 1.10511 + nsFrameConstructorSaveState absoluteSaveState; // definition cannot be inside next block 1.10512 + // because the object's destructor is significant 1.10513 + // this is part of the fix for bug 42372 1.10514 + 1.10515 + newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); 1.10516 + if (positioned) { 1.10517 + // Relatively positioned frames becomes a container for child 1.10518 + // frames that are positioned 1.10519 + aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState); 1.10520 + } 1.10521 + 1.10522 + // Process the child content 1.10523 + nsFrameItems childItems; 1.10524 + ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame, childItems); 1.10525 + 1.10526 + nsFrameList::FrameLinkEnumerator firstBlockEnumerator(childItems); 1.10527 + if (!aItem.mIsAllInline) { 1.10528 + FindFirstBlock(firstBlockEnumerator); 1.10529 + } 1.10530 + 1.10531 + if (aItem.mIsAllInline || firstBlockEnumerator.AtEnd()) { 1.10532 + // This part is easy. We either already know we have no non-inline kids, 1.10533 + // or haven't found any when constructing actual frames (the latter can 1.10534 + // happen only if out-of-flows that we thought had no containing block 1.10535 + // acquired one when ancestor inline frames and {ib} splits got 1.10536 + // constructed). Just put all the kids into the single inline frame and 1.10537 + // bail. 1.10538 + newFrame->SetInitialChildList(kPrincipalList, childItems); 1.10539 + aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame); 1.10540 + return newFrame; 1.10541 + } 1.10542 + 1.10543 + // This inline frame contains several types of children. Therefore this frame 1.10544 + // has to be chopped into several pieces, as described above. 1.10545 + 1.10546 + // Grab the first inline's kids 1.10547 + nsFrameList firstInlineKids = childItems.ExtractHead(firstBlockEnumerator); 1.10548 + newFrame->SetInitialChildList(kPrincipalList, firstInlineKids); 1.10549 + 1.10550 + aFrameItems.AddChild(newFrame); 1.10551 + 1.10552 + CreateIBSiblings(aState, newFrame, positioned, childItems, aFrameItems); 1.10553 + 1.10554 + return newFrame; 1.10555 +} 1.10556 + 1.10557 +void 1.10558 +nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState, 1.10559 + nsIFrame* aInitialInline, 1.10560 + bool aIsPositioned, 1.10561 + nsFrameItems& aChildItems, 1.10562 + nsFrameItems& aSiblings) 1.10563 +{ 1.10564 + nsIContent* content = aInitialInline->GetContent(); 1.10565 + nsStyleContext* styleContext = aInitialInline->StyleContext(); 1.10566 + nsIFrame* parentFrame = aInitialInline->GetParent(); 1.10567 + 1.10568 + // Resolve the right style context for our anonymous blocks. 1.10569 + // The distinction in styles is needed because of CSS 2.1, section 1.10570 + // 9.2.1.1, which says: 1.10571 + // When such an inline box is affected by relative positioning, any 1.10572 + // resulting translation also affects the block-level box contained 1.10573 + // in the inline box. 1.10574 + nsRefPtr<nsStyleContext> blockSC = 1.10575 + mPresShell->StyleSet()-> 1.10576 + ResolveAnonymousBoxStyle(aIsPositioned ? 1.10577 + nsCSSAnonBoxes::mozAnonymousPositionedBlock : 1.10578 + nsCSSAnonBoxes::mozAnonymousBlock, 1.10579 + styleContext); 1.10580 + 1.10581 + nsIFrame* lastNewInline = aInitialInline->FirstContinuation(); 1.10582 + do { 1.10583 + // On entry to this loop aChildItems is not empty and the first frame in it 1.10584 + // is block-level. 1.10585 + NS_PRECONDITION(aChildItems.NotEmpty(), "Should have child items"); 1.10586 + NS_PRECONDITION(!aChildItems.FirstChild()->IsInlineOutside(), 1.10587 + "Must have list starting with block"); 1.10588 + 1.10589 + // The initial run of blocks belongs to an anonymous block that we create 1.10590 + // right now. The anonymous block will be the parent of these block 1.10591 + // children of the inline. 1.10592 + nsIFrame* blockFrame; 1.10593 + blockFrame = NS_NewBlockFrame(mPresShell, blockSC); 1.10594 + 1.10595 + InitAndRestoreFrame(aState, content, parentFrame, blockFrame, false); 1.10596 + 1.10597 + // Find the first non-block child which defines the end of our block kids 1.10598 + // and the start of our next inline's kids 1.10599 + nsFrameList::FrameLinkEnumerator firstNonBlock = 1.10600 + FindFirstNonBlock(aChildItems); 1.10601 + nsFrameList blockKids = aChildItems.ExtractHead(firstNonBlock); 1.10602 + 1.10603 + MoveChildrenTo(aState.mPresContext, aInitialInline, blockFrame, blockKids); 1.10604 + 1.10605 + SetFrameIsIBSplit(lastNewInline, blockFrame); 1.10606 + aSiblings.AddChild(blockFrame); 1.10607 + 1.10608 + // Now grab the initial inlines in aChildItems and put them into an inline 1.10609 + // frame 1.10610 + nsIFrame* inlineFrame = NS_NewInlineFrame(mPresShell, styleContext); 1.10611 + 1.10612 + InitAndRestoreFrame(aState, content, parentFrame, inlineFrame, false); 1.10613 + 1.10614 + inlineFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT | 1.10615 + NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); 1.10616 + if (aIsPositioned) { 1.10617 + inlineFrame->MarkAsAbsoluteContainingBlock(); 1.10618 + } 1.10619 + 1.10620 + if (aChildItems.NotEmpty()) { 1.10621 + nsFrameList::FrameLinkEnumerator firstBlock(aChildItems); 1.10622 + FindFirstBlock(firstBlock); 1.10623 + nsFrameList inlineKids = aChildItems.ExtractHead(firstBlock); 1.10624 + 1.10625 + MoveChildrenTo(aState.mPresContext, aInitialInline, inlineFrame, 1.10626 + inlineKids); 1.10627 + } 1.10628 + 1.10629 + SetFrameIsIBSplit(blockFrame, inlineFrame); 1.10630 + aSiblings.AddChild(inlineFrame); 1.10631 + lastNewInline = inlineFrame; 1.10632 + } while (aChildItems.NotEmpty()); 1.10633 + 1.10634 + SetFrameIsIBSplit(lastNewInline, nullptr); 1.10635 +} 1.10636 + 1.10637 +void 1.10638 +nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState, 1.10639 + FrameConstructionItem& aParentItem, 1.10640 + bool aItemIsWithinSVGText, 1.10641 + bool aItemAllowsTextPathChild) 1.10642 +{ 1.10643 + // XXXbz should we preallocate aParentItem.mChildItems to some sane 1.10644 + // length? Maybe even to parentContent->GetChildCount()? 1.10645 + nsFrameConstructorState::PendingBindingAutoPusher 1.10646 + pusher(aState, aParentItem.mPendingBinding); 1.10647 + 1.10648 + nsStyleContext* const parentStyleContext = aParentItem.mStyleContext; 1.10649 + nsIContent* const parentContent = aParentItem.mContent; 1.10650 + 1.10651 + TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext); 1.10652 + if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) { 1.10653 + ancestorPusher.PushAncestorAndStyleScope(parentContent->AsElement()); 1.10654 + } else { 1.10655 + ancestorPusher.PushStyleScope(parentContent->AsElement()); 1.10656 + } 1.10657 + 1.10658 + if (!aItemIsWithinSVGText) { 1.10659 + // Probe for generated content before 1.10660 + CreateGeneratedContentItem(aState, nullptr, parentContent, parentStyleContext, 1.10661 + nsCSSPseudoElements::ePseudo_before, 1.10662 + aParentItem.mChildItems); 1.10663 + } 1.10664 + 1.10665 + uint32_t flags = ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK; 1.10666 + if (aItemIsWithinSVGText) { 1.10667 + flags |= ITEM_IS_WITHIN_SVG_TEXT; 1.10668 + } 1.10669 + if (aItemAllowsTextPathChild && aParentItem.mIsForSVGAElement) { 1.10670 + flags |= ITEM_ALLOWS_TEXT_PATH_CHILD; 1.10671 + } 1.10672 + 1.10673 + if (!aParentItem.mAnonChildren.IsEmpty()) { 1.10674 + // Use the anon-children list instead of the content tree child list so 1.10675 + // that we use any special style context that should be associated with 1.10676 + // the children, and so that we won't try to construct grandchildren frame 1.10677 + // constructor items before the frame is available for their parent. 1.10678 + AddFCItemsForAnonymousContent(aState, nullptr, aParentItem.mAnonChildren, 1.10679 + aParentItem.mChildItems, flags); 1.10680 + } else { 1.10681 + // Use the content tree child list: 1.10682 + FlattenedChildIterator iter(parentContent); 1.10683 + for (nsIContent* content = iter.GetNextChild(); content; content = iter.GetNextChild()) { 1.10684 + // Get the parent of the content and check if it is a XBL children element 1.10685 + // (if the content is a children element then contentParent != parentContent because the 1.10686 + // FlattenedChildIterator will transitively iterate through <xbl:children> 1.10687 + // for default content). Push the children element as an ancestor here because 1.10688 + // it does not have a frame and would not otherwise be pushed as an ancestor. 1.10689 + nsIContent* contentParent = content->GetParent(); 1.10690 + MOZ_ASSERT(contentParent, "Parent must be non-null because we are iterating children."); 1.10691 + TreeMatchContext::AutoAncestorPusher insertionPointPusher(aState.mTreeMatchContext); 1.10692 + if (contentParent != parentContent && contentParent->IsElement()) { 1.10693 + if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) { 1.10694 + insertionPointPusher.PushAncestorAndStyleScope(contentParent->AsElement()); 1.10695 + } else { 1.10696 + insertionPointPusher.PushStyleScope(contentParent->AsElement()); 1.10697 + } 1.10698 + } 1.10699 + 1.10700 + // Manually check for comments/PIs, since we don't have a frame to pass to 1.10701 + // AddFrameConstructionItems. We know our parent is a non-replaced inline, 1.10702 + // so there is no need to do the NeedFrameFor check. 1.10703 + content->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME); 1.10704 + if (content->IsNodeOfType(nsINode::eCOMMENT) || 1.10705 + content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) { 1.10706 + continue; 1.10707 + } 1.10708 + if (content->IsElement()) { 1.10709 + // See comment explaining why we need to remove the "is possible 1.10710 + // restyle root" flags in AddFrameConstructionItems. But note 1.10711 + // that we can remove all restyle flags, just like in 1.10712 + // ProcessChildren and for the same reason. 1.10713 + content->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS); 1.10714 + } 1.10715 + 1.10716 + nsRefPtr<nsStyleContext> childContext = 1.10717 + ResolveStyleContext(parentStyleContext, content, &aState); 1.10718 + 1.10719 + AddFrameConstructionItemsInternal(aState, content, nullptr, content->Tag(), 1.10720 + content->GetNameSpaceID(), 1.10721 + iter.XBLInvolved(), childContext, 1.10722 + flags, nullptr, 1.10723 + aParentItem.mChildItems); 1.10724 + } 1.10725 + } 1.10726 + 1.10727 + if (!aItemIsWithinSVGText) { 1.10728 + // Probe for generated content after 1.10729 + CreateGeneratedContentItem(aState, nullptr, parentContent, parentStyleContext, 1.10730 + nsCSSPseudoElements::ePseudo_after, 1.10731 + aParentItem.mChildItems); 1.10732 + } 1.10733 + 1.10734 + aParentItem.mIsAllInline = aParentItem.mChildItems.AreAllItemsInline(); 1.10735 +} 1.10736 + 1.10737 +// return whether it's ok to append (in the AppendFrames sense) to 1.10738 +// aParentFrame if our nextSibling is aNextSibling. aParentFrame must 1.10739 +// be an ib-split inline. 1.10740 +static bool 1.10741 +IsSafeToAppendToIBSplitInline(nsIFrame* aParentFrame, nsIFrame* aNextSibling) 1.10742 +{ 1.10743 + NS_PRECONDITION(IsInlineFrame(aParentFrame), 1.10744 + "Must have an inline parent here"); 1.10745 + do { 1.10746 + NS_ASSERTION(IsFramePartOfIBSplit(aParentFrame), 1.10747 + "How is this not part of an ib-split?"); 1.10748 + if (aNextSibling || aParentFrame->GetNextContinuation() || 1.10749 + GetIBSplitSibling(aParentFrame)) { 1.10750 + return false; 1.10751 + } 1.10752 + 1.10753 + aNextSibling = aParentFrame->GetNextSibling(); 1.10754 + aParentFrame = aParentFrame->GetParent(); 1.10755 + } while (IsInlineFrame(aParentFrame)); 1.10756 + 1.10757 + return true; 1.10758 +} 1.10759 + 1.10760 +bool 1.10761 +nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, 1.10762 + nsIFrame* aContainingBlock, 1.10763 + nsIFrame* aFrame, 1.10764 + FrameConstructionItemList& aItems, 1.10765 + bool aIsAppend, 1.10766 + nsIFrame* aPrevSibling) 1.10767 +{ 1.10768 + if (aItems.IsEmpty()) { 1.10769 + return false; 1.10770 + } 1.10771 + 1.10772 + // Before we go and append the frames, we must check for several 1.10773 + // special situations. 1.10774 + 1.10775 + // Situation #1 is a XUL frame that contains frames that are required 1.10776 + // to be wrapped in blocks. 1.10777 + if (aFrame->IsBoxFrame() && 1.10778 + !(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) && 1.10779 + aItems.AnyItemsNeedBlockParent()) { 1.10780 + RecreateFramesForContent(aFrame->GetContent(), true); 1.10781 + return true; 1.10782 + } 1.10783 + 1.10784 + nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling); 1.10785 + 1.10786 + // Situation #2 is a flex container frame into which we're inserting new 1.10787 + // inline non-replaced children, adjacent to an existing anonymous flex item. 1.10788 + if (aFrame->GetType() == nsGkAtoms::flexContainerFrame) { 1.10789 + FCItemIterator iter(aItems); 1.10790 + 1.10791 + // Check if we're adding to-be-wrapped content right *after* an existing 1.10792 + // anonymous flex item (which would need to absorb this content). 1.10793 + if (aPrevSibling && IsAnonymousFlexItem(aPrevSibling) && 1.10794 + iter.item().NeedsAnonFlexItem(aState)) { 1.10795 + RecreateFramesForContent(aFrame->GetContent(), true); 1.10796 + return true; 1.10797 + } 1.10798 + 1.10799 + // Check if we're adding to-be-wrapped content right *before* an existing 1.10800 + // anonymous flex item (which would need to absorb this content). 1.10801 + if (nextSibling && IsAnonymousFlexItem(nextSibling)) { 1.10802 + // Jump to the last entry in the list 1.10803 + iter.SetToEnd(); 1.10804 + iter.Prev(); 1.10805 + if (iter.item().NeedsAnonFlexItem(aState)) { 1.10806 + RecreateFramesForContent(aFrame->GetContent(), true); 1.10807 + return true; 1.10808 + } 1.10809 + } 1.10810 + } 1.10811 + 1.10812 + // Situation #3 is an anonymous flex item that's getting new children who 1.10813 + // don't want to be wrapped. 1.10814 + if (IsAnonymousFlexItem(aFrame)) { 1.10815 + nsIFrame* flexContainerFrame = aFrame->GetParent(); 1.10816 + NS_ABORT_IF_FALSE(flexContainerFrame && 1.10817 + flexContainerFrame->GetType() == nsGkAtoms::flexContainerFrame, 1.10818 + "anonymous flex items should only exist as children " 1.10819 + "of flex container frames"); 1.10820 + 1.10821 + // We need to push a null float containing block to be sure that 1.10822 + // "NeedsAnonFlexItem" will know we're not honoring floats for this 1.10823 + // inserted content. (In particular, this is necessary in order for 1.10824 + // NeedsAnonFlexItem's "GetGeometricParent" call to return the correct 1.10825 + // result.) We're not honoring floats on this content because it has the 1.10826 + // _flex container_ as its parent in the content tree. 1.10827 + nsFrameConstructorSaveState floatSaveState; 1.10828 + aState.PushFloatContainingBlock(nullptr, floatSaveState); 1.10829 + 1.10830 + FCItemIterator iter(aItems); 1.10831 + // Skip over things that _do_ need an anonymous flex item, because 1.10832 + // they're perfectly happy to go here -- they won't cause a reframe. 1.10833 + if (!iter.SkipItemsThatNeedAnonFlexItem(aState)) { 1.10834 + // We hit something that _doesn't_ need an anonymous flex item! 1.10835 + // Rebuild the flex container to bust it out. 1.10836 + RecreateFramesForContent(flexContainerFrame->GetContent(), true); 1.10837 + return true; 1.10838 + } 1.10839 + 1.10840 + // If we get here, then everything in |aItems| needs to be wrapped in 1.10841 + // an anonymous flex item. That's where it's already going - good! 1.10842 + } 1.10843 + 1.10844 + // Situation #4 is a case when table pseudo-frames don't work out right 1.10845 + ParentType parentType = GetParentType(aFrame); 1.10846 + // If all the kids want a parent of the type that aFrame is, then we're all 1.10847 + // set to go. Indeed, there won't be any table pseudo-frames created between 1.10848 + // aFrame and the kids, so those won't need to be merged with any table 1.10849 + // pseudo-frames that might already be kids of aFrame. If aFrame itself is a 1.10850 + // table pseudo-frame, then all the kids in this list would have wanted a 1.10851 + // frame of that type wrapping them anyway, so putting them inside it is ok. 1.10852 + if (!aItems.AllWantParentType(parentType)) { 1.10853 + // Don't give up yet. If parentType is not eTypeBlock and the parent is 1.10854 + // not a generated content frame, then try filtering whitespace out of the 1.10855 + // list. 1.10856 + if (parentType != eTypeBlock && !aFrame->IsGeneratedContentFrame()) { 1.10857 + // For leading whitespace followed by a kid that wants our parent type, 1.10858 + // there are four cases: 1.10859 + // 1) We have a previous sibling which is not a table pseudo. That means 1.10860 + // that previous sibling wanted a (non-block) parent of the type we're 1.10861 + // looking at. Then the whitespace comes between two table-internal 1.10862 + // elements, so should be collapsed out. 1.10863 + // 2) We have a previous sibling which is a table pseudo. It might have 1.10864 + // kids who want this whitespace, so we need to reframe. 1.10865 + // 3) We have no previous sibling and our parent frame is not a table 1.10866 + // pseudo. That means that we'll be at the beginning of our actual 1.10867 + // non-block-type parent, and the whitespace is OK to collapse out. 1.10868 + // If something is ever inserted before us, it'll find our own parent 1.10869 + // as its parent and if it's something that would care about the 1.10870 + // whitespace it'll want a block parent, so it'll trigger a reframe at 1.10871 + // that point. 1.10872 + // 4) We have no previous sibling and our parent frame is a table pseudo. 1.10873 + // Need to reframe. 1.10874 + // All that is predicated on finding the correct previous sibling. We 1.10875 + // might have to walk backwards along continuations from aFrame to do so. 1.10876 + // 1.10877 + // It's always OK to drop whitespace between any two items that want a 1.10878 + // parent of type parentType. 1.10879 + // 1.10880 + // For trailing whitespace preceded by a kid that wants our parent type, 1.10881 + // there are four cases: 1.10882 + // 1) We have a next sibling which is not a table pseudo. That means 1.10883 + // that next sibling wanted a (non-block) parent of the type we're 1.10884 + // looking at. Then the whitespace comes between two table-internal 1.10885 + // elements, so should be collapsed out. 1.10886 + // 2) We have a next sibling which is a table pseudo. It might have 1.10887 + // kids who want this whitespace, so we need to reframe. 1.10888 + // 3) We have no next sibling and our parent frame is not a table 1.10889 + // pseudo. That means that we'll be at the end of our actual 1.10890 + // non-block-type parent, and the whitespace is OK to collapse out. 1.10891 + // If something is ever inserted after us, it'll find our own parent 1.10892 + // as its parent and if it's something that would care about the 1.10893 + // whitespace it'll want a block parent, so it'll trigger a reframe at 1.10894 + // that point. 1.10895 + // 4) We have no next sibling and our parent frame is a table pseudo. 1.10896 + // Need to reframe. 1.10897 + // All that is predicated on finding the correct next sibling. We might 1.10898 + // have to walk forward along continuations from aFrame to do so. That 1.10899 + // said, in the case when nextSibling is null at this point and aIsAppend 1.10900 + // is true, we know we're in case 3. Furthermore, in that case we don't 1.10901 + // even have to worry about the table pseudo situation; we know our 1.10902 + // parent is not a table pseudo there. 1.10903 + FCItemIterator iter(aItems); 1.10904 + FCItemIterator start(iter); 1.10905 + do { 1.10906 + if (iter.SkipItemsWantingParentType(parentType)) { 1.10907 + break; 1.10908 + } 1.10909 + 1.10910 + // iter points to an item that wants a different parent. If it's not 1.10911 + // whitespace, we're done; no more point scanning the list. 1.10912 + if (!iter.item().IsWhitespace(aState)) { 1.10913 + break; 1.10914 + } 1.10915 + 1.10916 + if (iter == start) { 1.10917 + // Leading whitespace. How to handle this depends on our 1.10918 + // previous sibling and aFrame. See the long comment above. 1.10919 + nsIFrame* prevSibling = aPrevSibling; 1.10920 + if (!prevSibling) { 1.10921 + // Try to find one after all 1.10922 + nsIFrame* parentPrevCont = aFrame->GetPrevContinuation(); 1.10923 + while (parentPrevCont) { 1.10924 + prevSibling = parentPrevCont->GetLastChild(kPrincipalList); 1.10925 + if (prevSibling) { 1.10926 + break; 1.10927 + } 1.10928 + parentPrevCont = parentPrevCont->GetPrevContinuation(); 1.10929 + } 1.10930 + }; 1.10931 + if (prevSibling) { 1.10932 + if (IsTablePseudo(prevSibling)) { 1.10933 + // need to reframe 1.10934 + break; 1.10935 + } 1.10936 + } else if (IsTablePseudo(aFrame)) { 1.10937 + // need to reframe 1.10938 + break; 1.10939 + } 1.10940 + } 1.10941 + 1.10942 + FCItemIterator spaceEndIter(iter); 1.10943 + // Advance spaceEndIter past any whitespace 1.10944 + bool trailingSpaces = spaceEndIter.SkipWhitespace(aState); 1.10945 + 1.10946 + bool okToDrop; 1.10947 + if (trailingSpaces) { 1.10948 + // Trailing whitespace. How to handle this depeds on aIsAppend, our 1.10949 + // next sibling and aFrame. See the long comment above. 1.10950 + okToDrop = aIsAppend && !nextSibling; 1.10951 + if (!okToDrop) { 1.10952 + if (!nextSibling) { 1.10953 + // Try to find one after all 1.10954 + nsIFrame* parentNextCont = aFrame->GetNextContinuation(); 1.10955 + while (parentNextCont) { 1.10956 + nextSibling = parentNextCont->GetFirstPrincipalChild(); 1.10957 + if (nextSibling) { 1.10958 + break; 1.10959 + } 1.10960 + parentNextCont = parentNextCont->GetNextContinuation(); 1.10961 + } 1.10962 + } 1.10963 + 1.10964 + okToDrop = (nextSibling && !IsTablePseudo(nextSibling)) || 1.10965 + (!nextSibling && !IsTablePseudo(aFrame)); 1.10966 + } 1.10967 +#ifdef DEBUG 1.10968 + else { 1.10969 + NS_ASSERTION(!IsTablePseudo(aFrame), "How did that happen?"); 1.10970 + } 1.10971 +#endif 1.10972 + } else { 1.10973 + okToDrop = (spaceEndIter.item().DesiredParentType() == parentType); 1.10974 + } 1.10975 + 1.10976 + if (okToDrop) { 1.10977 + iter.DeleteItemsTo(spaceEndIter); 1.10978 + } else { 1.10979 + // We're done: we don't want to drop the whitespace, and it has the 1.10980 + // wrong parent type. 1.10981 + break; 1.10982 + } 1.10983 + 1.10984 + // Now loop, since |iter| points to item right after the whitespace we 1.10985 + // removed. 1.10986 + } while (!iter.IsDone()); 1.10987 + } 1.10988 + 1.10989 + // We might be able to figure out some sort of optimizations here, but they 1.10990 + // would have to depend on having a correct aPrevSibling and a correct next 1.10991 + // sibling. For example, we can probably avoid reframing if none of 1.10992 + // aFrame, aPrevSibling, and next sibling are table pseudo-frames. But it 1.10993 + // doesn't seem worth it to worry about that for now, especially since we 1.10994 + // in fact do not have a reliable aPrevSibling, nor any next sibling, in 1.10995 + // this method. 1.10996 + 1.10997 + // aItems might have changed, so recheck the parent type thing. In fact, 1.10998 + // it might be empty, so recheck that too. 1.10999 + if (aItems.IsEmpty()) { 1.11000 + return false; 1.11001 + } 1.11002 + 1.11003 + if (!aItems.AllWantParentType(parentType)) { 1.11004 + // Reframing aFrame->GetContent() is good enough, since the content of 1.11005 + // table pseudo-frames is the ancestor content. 1.11006 + RecreateFramesForContent(aFrame->GetContent(), true); 1.11007 + return true; 1.11008 + } 1.11009 + } 1.11010 + 1.11011 + // Now we have several cases involving {ib} splits. Put them all in a 1.11012 + // do/while with breaks to take us to the "go and reconstruct" code. 1.11013 + do { 1.11014 + if (IsInlineFrame(aFrame)) { 1.11015 + if (aItems.AreAllItemsInline()) { 1.11016 + // We can just put the kids in. 1.11017 + return false; 1.11018 + } 1.11019 + 1.11020 + if (!IsFramePartOfIBSplit(aFrame)) { 1.11021 + // Need to go ahead and reconstruct. 1.11022 + break; 1.11023 + } 1.11024 + 1.11025 + // Now we're adding kids including some blocks to an inline part of an 1.11026 + // {ib} split. If we plan to call AppendFrames, and don't have a next 1.11027 + // sibling for the new frames, and our parent is the last continuation of 1.11028 + // the last part of the {ib} split, and the same is true of all our 1.11029 + // ancestor inlines (they have no following continuations and they're the 1.11030 + // last part of their {ib} splits and we'd be adding to the end for all 1.11031 + // of them), then AppendFrames will handle things for us. Bail out in 1.11032 + // that case. 1.11033 + if (aIsAppend && IsSafeToAppendToIBSplitInline(aFrame, nextSibling)) { 1.11034 + return false; 1.11035 + } 1.11036 + 1.11037 + // Need to reconstruct. 1.11038 + break; 1.11039 + } 1.11040 + 1.11041 + // Now we know we have a block parent. If it's not part of an 1.11042 + // ib-split, we're all set. 1.11043 + if (!IsFramePartOfIBSplit(aFrame)) { 1.11044 + return false; 1.11045 + } 1.11046 + 1.11047 + // We're adding some kids to a block part of an {ib} split. If all the 1.11048 + // kids are blocks, we don't need to reconstruct. 1.11049 + if (aItems.AreAllItemsBlock()) { 1.11050 + return false; 1.11051 + } 1.11052 + 1.11053 + // We might have some inline kids for this block. Just reconstruct. 1.11054 + break; 1.11055 + } while (0); 1.11056 + 1.11057 + // If we don't have a containing block, start with aFrame and look for one. 1.11058 + if (!aContainingBlock) { 1.11059 + aContainingBlock = aFrame; 1.11060 + } 1.11061 + 1.11062 + // To find the right block to reframe, just walk up the tree until we find a 1.11063 + // frame that is: 1.11064 + // 1) Not part of an IB split 1.11065 + // 2) Not a pseudo-frame 1.11066 + // 3) Not an inline frame 1.11067 + // We're guaranteed to find one, since nsStyleContext::ApplyStyleFixups 1.11068 + // enforces that the root is display:none, display:table, or display:block. 1.11069 + // Note that walking up "too far" is OK in terms of correctness, even if it 1.11070 + // might be a little inefficient. This is why we walk out of all 1.11071 + // pseudo-frames -- telling which ones are or are not OK to walk out of is 1.11072 + // too hard (and I suspect that we do in fact need to walk out of all of 1.11073 + // them). 1.11074 + while (IsFramePartOfIBSplit(aContainingBlock) || 1.11075 + aContainingBlock->IsInlineOutside() || 1.11076 + aContainingBlock->StyleContext()->GetPseudo()) { 1.11077 + aContainingBlock = aContainingBlock->GetParent(); 1.11078 + NS_ASSERTION(aContainingBlock, 1.11079 + "Must have non-inline, non-ib-split, non-pseudo frame as " 1.11080 + "root (or child of root, for a table root)!"); 1.11081 + } 1.11082 + 1.11083 + // Tell parent of the containing block to reformulate the 1.11084 + // entire block. This is painful and definitely not optimal 1.11085 + // but it will *always* get the right answer. 1.11086 + 1.11087 + nsIContent *blockContent = aContainingBlock->GetContent(); 1.11088 +#ifdef DEBUG 1.11089 + if (gNoisyContentUpdates) { 1.11090 + printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p\n", 1.11091 + static_cast<void*>(blockContent)); 1.11092 + } 1.11093 +#endif 1.11094 + RecreateFramesForContent(blockContent, true); 1.11095 + return true; 1.11096 +} 1.11097 + 1.11098 +nsresult 1.11099 +nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame) 1.11100 +{ 1.11101 + 1.11102 +#ifdef DEBUG 1.11103 + // ReframeContainingBlock is a NASTY routine, it causes terrible performance problems 1.11104 + // so I want to see when it is happening! Unfortunately, it is happening way to often because 1.11105 + // so much content on the web causes block-in-inline frame situations and we handle them 1.11106 + // very poorly 1.11107 + if (gNoisyContentUpdates) { 1.11108 + printf("nsCSSFrameConstructor::ReframeContainingBlock frame=%p\n", 1.11109 + static_cast<void*>(aFrame)); 1.11110 + } 1.11111 +#endif 1.11112 + 1.11113 + // XXXbz how exactly would we get here while isReflowing anyway? Should this 1.11114 + // whole test be ifdef DEBUG? 1.11115 + if (mPresShell->IsReflowLocked()) { 1.11116 + // don't ReframeContainingBlock, this will result in a crash 1.11117 + // if we remove a tree that's in reflow - see bug 121368 for testcase 1.11118 + NS_ERROR("Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a Reflow!!!"); 1.11119 + return NS_OK; 1.11120 + } 1.11121 + 1.11122 + // Get the first "normal" ancestor of the target frame. 1.11123 + nsIFrame* containingBlock = GetIBContainingBlockFor(aFrame); 1.11124 + if (containingBlock) { 1.11125 + // From here we look for the containing block in case the target 1.11126 + // frame is already a block (which can happen when an inline frame 1.11127 + // wraps some of its content in an anonymous block; see 1.11128 + // ConstructInline) 1.11129 + 1.11130 + // NOTE: We used to get the FloatContainingBlock here, but it was often wrong. 1.11131 + // GetIBContainingBlock works much better and provides the correct container in all cases 1.11132 + // so GetFloatContainingBlock(aFrame) has been removed 1.11133 + 1.11134 + // And get the containingBlock's content 1.11135 + nsCOMPtr<nsIContent> blockContent = containingBlock->GetContent(); 1.11136 + if (blockContent) { 1.11137 +#ifdef DEBUG 1.11138 + if (gNoisyContentUpdates) { 1.11139 + printf(" ==> blockContent=%p\n", static_cast<void*>(blockContent)); 1.11140 + } 1.11141 +#endif 1.11142 + return RecreateFramesForContent(blockContent, true); 1.11143 + } 1.11144 + } 1.11145 + 1.11146 + // If we get here, we're screwed! 1.11147 + return RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(), 1.11148 + true); 1.11149 +} 1.11150 + 1.11151 +nsresult 1.11152 +nsCSSFrameConstructor::GenerateChildFrames(nsIFrame* aFrame) 1.11153 +{ 1.11154 + { 1.11155 + nsAutoScriptBlocker scriptBlocker; 1.11156 + BeginUpdate(); 1.11157 + 1.11158 + nsFrameItems childItems; 1.11159 + nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr); 1.11160 + // We don't have a parent frame with a pending binding constructor here, 1.11161 + // so no need to worry about ordering of the kids' constructors with it. 1.11162 + // Pass null for the PendingBinding. 1.11163 + ProcessChildren(state, aFrame->GetContent(), aFrame->StyleContext(), 1.11164 + aFrame, false, childItems, false, 1.11165 + nullptr); 1.11166 + 1.11167 + aFrame->SetInitialChildList(kPrincipalList, childItems); 1.11168 + 1.11169 + EndUpdate(); 1.11170 + } 1.11171 + 1.11172 +#ifdef ACCESSIBILITY 1.11173 + nsAccessibilityService* accService = nsIPresShell::AccService(); 1.11174 + if (accService) { 1.11175 + nsIContent* container = aFrame->GetContent(); 1.11176 + nsIContent* child = container->GetFirstChild(); 1.11177 + if (child) { 1.11178 + accService->ContentRangeInserted(mPresShell, container, child, nullptr); 1.11179 + } 1.11180 + } 1.11181 +#endif 1.11182 + 1.11183 + // call XBL constructors after the frames are created 1.11184 + mPresShell->GetDocument()->BindingManager()->ProcessAttachedQueue(); 1.11185 + 1.11186 + return NS_OK; 1.11187 +} 1.11188 + 1.11189 +////////////////////////////////////////////////////////// 1.11190 +// nsCSSFrameConstructor::FrameConstructionItem methods // 1.11191 +////////////////////////////////////////////////////////// 1.11192 +bool 1.11193 +nsCSSFrameConstructor:: 1.11194 +FrameConstructionItem::IsWhitespace(nsFrameConstructorState& aState) const 1.11195 +{ 1.11196 + NS_PRECONDITION(aState.mCreatingExtraFrames || 1.11197 + !mContent->GetPrimaryFrame(), "How did that happen?"); 1.11198 + if (!mIsText) { 1.11199 + return false; 1.11200 + } 1.11201 + mContent->SetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE | 1.11202 + NS_REFRAME_IF_WHITESPACE); 1.11203 + return mContent->TextIsOnlyWhitespace(); 1.11204 +} 1.11205 + 1.11206 +////////////////////////////////////////////////////////////// 1.11207 +// nsCSSFrameConstructor::FrameConstructionItemList methods // 1.11208 +////////////////////////////////////////////////////////////// 1.11209 +void 1.11210 +nsCSSFrameConstructor::FrameConstructionItemList:: 1.11211 +AdjustCountsForItem(FrameConstructionItem* aItem, int32_t aDelta) 1.11212 +{ 1.11213 + NS_PRECONDITION(aDelta == 1 || aDelta == -1, "Unexpected delta"); 1.11214 + mItemCount += aDelta; 1.11215 + if (aItem->mIsAllInline) { 1.11216 + mInlineCount += aDelta; 1.11217 + } 1.11218 + if (aItem->mIsBlock) { 1.11219 + mBlockCount += aDelta; 1.11220 + } 1.11221 + if (aItem->mIsLineParticipant) { 1.11222 + mLineParticipantCount += aDelta; 1.11223 + } 1.11224 + mDesiredParentCounts[aItem->DesiredParentType()] += aDelta; 1.11225 +} 1.11226 + 1.11227 +//////////////////////////////////////////////////////////////////////// 1.11228 +// nsCSSFrameConstructor::FrameConstructionItemList::Iterator methods // 1.11229 +//////////////////////////////////////////////////////////////////////// 1.11230 +inline bool 1.11231 +nsCSSFrameConstructor::FrameConstructionItemList:: 1.11232 +Iterator::SkipItemsWantingParentType(ParentType aParentType) 1.11233 +{ 1.11234 + NS_PRECONDITION(!IsDone(), "Shouldn't be done yet"); 1.11235 + while (item().DesiredParentType() == aParentType) { 1.11236 + Next(); 1.11237 + if (IsDone()) { 1.11238 + return true; 1.11239 + } 1.11240 + } 1.11241 + return false; 1.11242 +} 1.11243 + 1.11244 +bool 1.11245 +nsCSSFrameConstructor::FrameConstructionItem:: 1.11246 + NeedsAnonFlexItem(const nsFrameConstructorState& aState) 1.11247 +{ 1.11248 + if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) { 1.11249 + // This will be an inline non-replaced box. 1.11250 + return true; 1.11251 + } 1.11252 + 1.11253 + if (!(mFCData->mBits & FCDATA_DISALLOW_OUT_OF_FLOW) && 1.11254 + aState.GetGeometricParent(mStyleContext->StyleDisplay(), nullptr)) { 1.11255 + // We're abspos or fixedpos, which means we'll spawn a placeholder which 1.11256 + // we'll need to wrap in an anonymous flex item. So, we just treat 1.11257 + // _this_ frame as if _it_ needs to be wrapped in an anonymous flex item, 1.11258 + // and then when we spawn the placeholder, it'll end up in the right spot. 1.11259 + return true; 1.11260 + } 1.11261 + 1.11262 + return false; 1.11263 +} 1.11264 + 1.11265 +inline bool 1.11266 +nsCSSFrameConstructor::FrameConstructionItemList:: 1.11267 +Iterator::SkipItemsThatNeedAnonFlexItem( 1.11268 + const nsFrameConstructorState& aState) 1.11269 +{ 1.11270 + NS_PRECONDITION(!IsDone(), "Shouldn't be done yet"); 1.11271 + while (item().NeedsAnonFlexItem(aState)) { 1.11272 + Next(); 1.11273 + if (IsDone()) { 1.11274 + return true; 1.11275 + } 1.11276 + } 1.11277 + return false; 1.11278 +} 1.11279 + 1.11280 +inline bool 1.11281 +nsCSSFrameConstructor::FrameConstructionItemList:: 1.11282 +Iterator::SkipItemsThatDontNeedAnonFlexItem( 1.11283 + const nsFrameConstructorState& aState) 1.11284 +{ 1.11285 + NS_PRECONDITION(!IsDone(), "Shouldn't be done yet"); 1.11286 + while (!(item().NeedsAnonFlexItem(aState))) { 1.11287 + Next(); 1.11288 + if (IsDone()) { 1.11289 + return true; 1.11290 + } 1.11291 + } 1.11292 + return false; 1.11293 +} 1.11294 + 1.11295 +inline bool 1.11296 +nsCSSFrameConstructor::FrameConstructionItemList:: 1.11297 +Iterator::SkipWhitespace(nsFrameConstructorState& aState) 1.11298 +{ 1.11299 + NS_PRECONDITION(!IsDone(), "Shouldn't be done yet"); 1.11300 + NS_PRECONDITION(item().IsWhitespace(aState), "Not pointing to whitespace?"); 1.11301 + do { 1.11302 + Next(); 1.11303 + if (IsDone()) { 1.11304 + return true; 1.11305 + } 1.11306 + } while (item().IsWhitespace(aState)); 1.11307 + 1.11308 + return false; 1.11309 +} 1.11310 + 1.11311 +void 1.11312 +nsCSSFrameConstructor::FrameConstructionItemList:: 1.11313 +Iterator::AppendItemToList(FrameConstructionItemList& aTargetList) 1.11314 +{ 1.11315 + NS_ASSERTION(&aTargetList != &mList, "Unexpected call"); 1.11316 + NS_PRECONDITION(!IsDone(), "should not be done"); 1.11317 + 1.11318 + FrameConstructionItem* item = ToItem(mCurrent); 1.11319 + Next(); 1.11320 + PR_REMOVE_LINK(item); 1.11321 + PR_APPEND_LINK(item, &aTargetList.mItems); 1.11322 + 1.11323 + mList.AdjustCountsForItem(item, -1); 1.11324 + aTargetList.AdjustCountsForItem(item, 1); 1.11325 +} 1.11326 + 1.11327 +void 1.11328 +nsCSSFrameConstructor::FrameConstructionItemList:: 1.11329 +Iterator::AppendItemsToList(const Iterator& aEnd, 1.11330 + FrameConstructionItemList& aTargetList) 1.11331 +{ 1.11332 + NS_ASSERTION(&aTargetList != &mList, "Unexpected call"); 1.11333 + NS_PRECONDITION(mEnd == aEnd.mEnd, "end iterator for some other list?"); 1.11334 + 1.11335 + // We can't just move our guts to the other list if it already has 1.11336 + // some information or if we're not moving our entire list. 1.11337 + if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty() || 1.11338 + !aTargetList.mUndisplayedItems.IsEmpty()) { 1.11339 + do { 1.11340 + AppendItemToList(aTargetList); 1.11341 + } while (*this != aEnd); 1.11342 + return; 1.11343 + } 1.11344 + 1.11345 + // move over the list of items 1.11346 + PR_INSERT_AFTER(&aTargetList.mItems, &mList.mItems); 1.11347 + // Need to init when we remove to makd ~FrameConstructionItemList work right. 1.11348 + PR_REMOVE_AND_INIT_LINK(&mList.mItems); 1.11349 + 1.11350 + // Copy over the various counters 1.11351 + aTargetList.mInlineCount = mList.mInlineCount; 1.11352 + aTargetList.mBlockCount = mList.mBlockCount; 1.11353 + aTargetList.mLineParticipantCount = mList.mLineParticipantCount; 1.11354 + aTargetList.mItemCount = mList.mItemCount; 1.11355 + memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts, 1.11356 + sizeof(aTargetList.mDesiredParentCounts)); 1.11357 + 1.11358 + // Swap out undisplayed item arrays, before we nuke the array on our end 1.11359 + aTargetList.mUndisplayedItems.SwapElements(mList.mUndisplayedItems); 1.11360 + 1.11361 + // reset mList 1.11362 + mList.~FrameConstructionItemList(); 1.11363 + new (&mList) FrameConstructionItemList(); 1.11364 + 1.11365 + // Point ourselves to aEnd, as advertised 1.11366 + mCurrent = mEnd = &mList.mItems; 1.11367 + NS_POSTCONDITION(*this == aEnd, "How did that happen?"); 1.11368 +} 1.11369 + 1.11370 +void 1.11371 +nsCSSFrameConstructor::FrameConstructionItemList:: 1.11372 +Iterator::InsertItem(FrameConstructionItem* aItem) 1.11373 +{ 1.11374 + // Just insert the item before us. There's no magic here. 1.11375 + PR_INSERT_BEFORE(aItem, mCurrent); 1.11376 + mList.AdjustCountsForItem(aItem, 1); 1.11377 + 1.11378 + NS_POSTCONDITION(PR_NEXT_LINK(aItem) == mCurrent, "How did that happen?"); 1.11379 +} 1.11380 + 1.11381 +void 1.11382 +nsCSSFrameConstructor::FrameConstructionItemList:: 1.11383 +Iterator::DeleteItemsTo(const Iterator& aEnd) 1.11384 +{ 1.11385 + NS_PRECONDITION(mEnd == aEnd.mEnd, "end iterator for some other list?"); 1.11386 + NS_PRECONDITION(*this != aEnd, "Shouldn't be at aEnd yet"); 1.11387 + 1.11388 + do { 1.11389 + NS_ASSERTION(!IsDone(), "Ran off end of list?"); 1.11390 + FrameConstructionItem* item = ToItem(mCurrent); 1.11391 + Next(); 1.11392 + PR_REMOVE_LINK(item); 1.11393 + mList.AdjustCountsForItem(item, -1); 1.11394 + delete item; 1.11395 + } while (*this != aEnd); 1.11396 +}