1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/base/RestyleManager.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2965 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/** 1.10 + * Code responsible for managing style changes: tracking what style 1.11 + * changes need to happen, scheduling them, and doing them. 1.12 + */ 1.13 + 1.14 +#include "RestyleManager.h" 1.15 +#include "mozilla/EventStates.h" 1.16 +#include "nsLayoutUtils.h" 1.17 +#include "GeckoProfiler.h" 1.18 +#include "nsStyleChangeList.h" 1.19 +#include "nsRuleProcessorData.h" 1.20 +#include "nsStyleUtil.h" 1.21 +#include "nsCSSFrameConstructor.h" 1.22 +#include "nsSVGEffects.h" 1.23 +#include "nsCSSRendering.h" 1.24 +#include "nsAnimationManager.h" 1.25 +#include "nsTransitionManager.h" 1.26 +#include "nsViewManager.h" 1.27 +#include "nsRenderingContext.h" 1.28 +#include "nsSVGIntegrationUtils.h" 1.29 +#include "nsCSSAnonBoxes.h" 1.30 +#include "nsContainerFrame.h" 1.31 +#include "nsPlaceholderFrame.h" 1.32 +#include "nsBlockFrame.h" 1.33 +#include "nsViewportFrame.h" 1.34 +#include "SVGTextFrame.h" 1.35 +#include "StickyScrollContainer.h" 1.36 +#include "nsIRootBox.h" 1.37 +#include "nsIDOMMutationEvent.h" 1.38 +#include "nsContentUtils.h" 1.39 +#include "nsIFrameInlines.h" 1.40 +#include "ActiveLayerTracker.h" 1.41 +#include "nsDisplayList.h" 1.42 + 1.43 +#ifdef ACCESSIBILITY 1.44 +#include "nsAccessibilityService.h" 1.45 +#endif 1.46 + 1.47 +namespace mozilla { 1.48 + 1.49 +using namespace layers; 1.50 + 1.51 +RestyleManager::RestyleManager(nsPresContext* aPresContext) 1.52 + : mPresContext(aPresContext) 1.53 + , mRebuildAllStyleData(false) 1.54 + , mObservingRefreshDriver(false) 1.55 + , mInStyleRefresh(false) 1.56 + , mHoverGeneration(0) 1.57 + , mRebuildAllExtraHint(nsChangeHint(0)) 1.58 + , mAnimationGeneration(0) 1.59 + , mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE | 1.60 + ELEMENT_IS_POTENTIAL_RESTYLE_ROOT) 1.61 + , mPendingAnimationRestyles(ELEMENT_HAS_PENDING_ANIMATION_RESTYLE | 1.62 + ELEMENT_IS_POTENTIAL_ANIMATION_RESTYLE_ROOT) 1.63 +{ 1.64 + mPendingRestyles.Init(this); 1.65 + mPendingAnimationRestyles.Init(this); 1.66 +} 1.67 + 1.68 +void 1.69 +RestyleManager::NotifyDestroyingFrame(nsIFrame* aFrame) 1.70 +{ 1.71 + mOverflowChangedTracker.RemoveFrame(aFrame); 1.72 +} 1.73 + 1.74 +#ifdef DEBUG 1.75 + // To ensure that the functions below are only called within 1.76 + // |ApplyRenderingChangeToTree|. 1.77 +static bool gInApplyRenderingChangeToTree = false; 1.78 +#endif 1.79 + 1.80 +static void 1.81 +DoApplyRenderingChangeToTree(nsIFrame* aFrame, 1.82 + nsChangeHint aChange); 1.83 + 1.84 +/** 1.85 + * Sync views on aFrame and all of aFrame's descendants (following placeholders), 1.86 + * if aChange has nsChangeHint_SyncFrameView. 1.87 + * Calls DoApplyRenderingChangeToTree on all aFrame's out-of-flow descendants 1.88 + * (following placeholders), if aChange has nsChangeHint_RepaintFrame. 1.89 + * aFrame should be some combination of nsChangeHint_SyncFrameView and 1.90 + * nsChangeHint_RepaintFrame and nsChangeHint_UpdateOpacityLayer, nothing else. 1.91 +*/ 1.92 +static void 1.93 +SyncViewsAndInvalidateDescendants(nsIFrame* aFrame, 1.94 + nsChangeHint aChange) 1.95 +{ 1.96 + NS_PRECONDITION(gInApplyRenderingChangeToTree, 1.97 + "should only be called within ApplyRenderingChangeToTree"); 1.98 + NS_ASSERTION(aChange == (aChange & (nsChangeHint_RepaintFrame | 1.99 + nsChangeHint_SyncFrameView | 1.100 + nsChangeHint_UpdateOpacityLayer)), 1.101 + "Invalid change flag"); 1.102 + 1.103 + nsView* view = aFrame->GetView(); 1.104 + if (view) { 1.105 + if (aChange & nsChangeHint_SyncFrameView) { 1.106 + nsContainerFrame::SyncFrameViewProperties(aFrame->PresContext(), 1.107 + aFrame, nullptr, view); 1.108 + } 1.109 + } 1.110 + 1.111 + nsIFrame::ChildListIterator lists(aFrame); 1.112 + for (; !lists.IsDone(); lists.Next()) { 1.113 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.114 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.115 + nsIFrame* child = childFrames.get(); 1.116 + if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) { 1.117 + // only do frames that don't have placeholders 1.118 + if (nsGkAtoms::placeholderFrame == child->GetType()) { 1.119 + // do the out-of-flow frame and its continuations 1.120 + nsIFrame* outOfFlowFrame = 1.121 + nsPlaceholderFrame::GetRealFrameForPlaceholder(child); 1.122 + DoApplyRenderingChangeToTree(outOfFlowFrame, aChange); 1.123 + } else if (lists.CurrentID() == nsIFrame::kPopupList) { 1.124 + DoApplyRenderingChangeToTree(child, aChange); 1.125 + } else { // regular frame 1.126 + SyncViewsAndInvalidateDescendants(child, aChange); 1.127 + } 1.128 + } 1.129 + } 1.130 + } 1.131 +} 1.132 + 1.133 +/** 1.134 + * To handle nsChangeHint_ChildrenOnlyTransform we must iterate over the child 1.135 + * frames of the SVG frame concerned. This helper function is used to find that 1.136 + * SVG frame when we encounter nsChangeHint_ChildrenOnlyTransform to ensure 1.137 + * that we iterate over the intended children, since sometimes we end up 1.138 + * handling that hint while processing hints for one of the SVG frame's 1.139 + * ancestor frames. 1.140 + * 1.141 + * The reason that we sometimes end up trying to process the hint for an 1.142 + * ancestor of the SVG frame that the hint is intended for is due to the way we 1.143 + * process restyle events. ApplyRenderingChangeToTree adjusts the frame from 1.144 + * the restyled element's principle frame to one of its ancestor frames based 1.145 + * on what nsCSSRendering::FindBackground returns, since the background style 1.146 + * may have been propagated up to an ancestor frame. Processing hints using an 1.147 + * ancestor frame is fine in general, but nsChangeHint_ChildrenOnlyTransform is 1.148 + * a special case since it is intended to update the children of a specific 1.149 + * frame. 1.150 + */ 1.151 +static nsIFrame* 1.152 +GetFrameForChildrenOnlyTransformHint(nsIFrame *aFrame) 1.153 +{ 1.154 + if (aFrame->GetType() == nsGkAtoms::viewportFrame) { 1.155 + // This happens if the root-<svg> is fixed positioned, in which case we 1.156 + // can't use aFrame->GetContent() to find the primary frame, since 1.157 + // GetContent() returns nullptr for ViewportFrame. 1.158 + aFrame = aFrame->GetFirstPrincipalChild(); 1.159 + } 1.160 + // For an nsHTMLScrollFrame, this will get the SVG frame that has the 1.161 + // children-only transforms: 1.162 + aFrame = aFrame->GetContent()->GetPrimaryFrame(); 1.163 + if (aFrame->GetType() == nsGkAtoms::svgOuterSVGFrame) { 1.164 + aFrame = aFrame->GetFirstPrincipalChild(); 1.165 + NS_ABORT_IF_FALSE(aFrame->GetType() == nsGkAtoms::svgOuterSVGAnonChildFrame, 1.166 + "Where is the nsSVGOuterSVGFrame's anon child??"); 1.167 + } 1.168 + NS_ABORT_IF_FALSE(aFrame->IsFrameOfType(nsIFrame::eSVG | 1.169 + nsIFrame::eSVGContainer), 1.170 + "Children-only transforms only expected on SVG frames"); 1.171 + return aFrame; 1.172 +} 1.173 + 1.174 +static void 1.175 +DoApplyRenderingChangeToTree(nsIFrame* aFrame, 1.176 + nsChangeHint aChange) 1.177 +{ 1.178 + NS_PRECONDITION(gInApplyRenderingChangeToTree, 1.179 + "should only be called within ApplyRenderingChangeToTree"); 1.180 + 1.181 + for ( ; aFrame; aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame)) { 1.182 + // Invalidate and sync views on all descendant frames, following placeholders. 1.183 + // We don't need to update transforms in SyncViewsAndInvalidateDescendants, because 1.184 + // there can't be any out-of-flows or popups that need to be transformed; 1.185 + // all out-of-flow descendants of the transformed element must also be 1.186 + // descendants of the transformed frame. 1.187 + SyncViewsAndInvalidateDescendants(aFrame, 1.188 + nsChangeHint(aChange & (nsChangeHint_RepaintFrame | 1.189 + nsChangeHint_SyncFrameView | 1.190 + nsChangeHint_UpdateOpacityLayer))); 1.191 + // This must be set to true if the rendering change needs to 1.192 + // invalidate content. If it's false, a composite-only paint 1.193 + // (empty transaction) will be scheduled. 1.194 + bool needInvalidatingPaint = false; 1.195 + 1.196 + // if frame has view, will already be invalidated 1.197 + if (aChange & nsChangeHint_RepaintFrame) { 1.198 + // Note that this whole block will be skipped when painting is suppressed 1.199 + // (due to our caller ApplyRendingChangeToTree() discarding the 1.200 + // nsChangeHint_RepaintFrame hint). If you add handling for any other 1.201 + // hints within this block, be sure that they too should be ignored when 1.202 + // painting is suppressed. 1.203 + needInvalidatingPaint = true; 1.204 + aFrame->InvalidateFrameSubtree(); 1.205 + if (aChange & nsChangeHint_UpdateEffects && 1.206 + aFrame->IsFrameOfType(nsIFrame::eSVG) && 1.207 + !(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)) { 1.208 + // Need to update our overflow rects: 1.209 + nsSVGUtils::ScheduleReflowSVG(aFrame); 1.210 + } 1.211 + } 1.212 + if (aChange & nsChangeHint_UpdateTextPath) { 1.213 + if (aFrame->IsSVGText()) { 1.214 + // Invalidate and reflow the entire SVGTextFrame: 1.215 + NS_ASSERTION(aFrame->GetContent()->IsSVG(nsGkAtoms::textPath), 1.216 + "expected frame for a <textPath> element"); 1.217 + nsIFrame* text = nsLayoutUtils::GetClosestFrameOfType( 1.218 + aFrame, 1.219 + nsGkAtoms::svgTextFrame); 1.220 + NS_ASSERTION(text, "expected to find an ancestor SVGTextFrame"); 1.221 + static_cast<SVGTextFrame*>(text)->NotifyGlyphMetricsChange(); 1.222 + } else { 1.223 + NS_ABORT_IF_FALSE(false, "unexpected frame got " 1.224 + "nsChangeHint_UpdateTextPath"); 1.225 + } 1.226 + } 1.227 + if (aChange & nsChangeHint_UpdateOpacityLayer) { 1.228 + // FIXME/bug 796697: we can get away with empty transactions for 1.229 + // opacity updates in many cases. 1.230 + needInvalidatingPaint = true; 1.231 + 1.232 + ActiveLayerTracker::NotifyRestyle(aFrame, eCSSProperty_opacity); 1.233 + if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) { 1.234 + // SVG effects paints the opacity without using 1.235 + // nsDisplayOpacity. We need to invalidate manually. 1.236 + aFrame->InvalidateFrameSubtree(); 1.237 + } 1.238 + } 1.239 + if ((aChange & nsChangeHint_UpdateTransformLayer) && 1.240 + aFrame->IsTransformed()) { 1.241 + ActiveLayerTracker::NotifyRestyle(aFrame, eCSSProperty_transform); 1.242 + // If we're not already going to do an invalidating paint, see 1.243 + // if we can get away with only updating the transform on a 1.244 + // layer for this frame, and not scheduling an invalidating 1.245 + // paint. 1.246 + if (!needInvalidatingPaint) { 1.247 + Layer* layer; 1.248 + needInvalidatingPaint |= !aFrame->TryUpdateTransformOnly(&layer); 1.249 + 1.250 + if (!needInvalidatingPaint) { 1.251 + // Since we're not going to paint, we need to resend animation 1.252 + // data to the layer. 1.253 + MOZ_ASSERT(layer, "this can't happen if there's no layer"); 1.254 + nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(layer, 1.255 + nullptr, nullptr, aFrame, eCSSProperty_transform); 1.256 + } 1.257 + } 1.258 + } 1.259 + if (aChange & nsChangeHint_ChildrenOnlyTransform) { 1.260 + needInvalidatingPaint = true; 1.261 + nsIFrame* childFrame = 1.262 + GetFrameForChildrenOnlyTransformHint(aFrame)->GetFirstPrincipalChild(); 1.263 + for ( ; childFrame; childFrame = childFrame->GetNextSibling()) { 1.264 + ActiveLayerTracker::NotifyRestyle(childFrame, eCSSProperty_transform); 1.265 + } 1.266 + } 1.267 + aFrame->SchedulePaint(needInvalidatingPaint ? 1.268 + nsIFrame::PAINT_DEFAULT : 1.269 + nsIFrame::PAINT_COMPOSITE_ONLY); 1.270 + } 1.271 +} 1.272 + 1.273 +static void 1.274 +ApplyRenderingChangeToTree(nsPresContext* aPresContext, 1.275 + nsIFrame* aFrame, 1.276 + nsChangeHint aChange) 1.277 +{ 1.278 + // We check StyleDisplay()->HasTransform() in addition to checking 1.279 + // IsTransformed() since we can get here for some frames that don't support 1.280 + // CSS transforms. 1.281 + NS_ASSERTION(!(aChange & nsChangeHint_UpdateTransformLayer) || 1.282 + aFrame->IsTransformed() || 1.283 + aFrame->StyleDisplay()->HasTransformStyle(), 1.284 + "Unexpected UpdateTransformLayer hint"); 1.285 + 1.286 + nsIPresShell *shell = aPresContext->PresShell(); 1.287 + if (shell->IsPaintingSuppressed()) { 1.288 + // Don't allow synchronous rendering changes when painting is turned off. 1.289 + aChange = NS_SubtractHint(aChange, nsChangeHint_RepaintFrame); 1.290 + if (!aChange) { 1.291 + return; 1.292 + } 1.293 + } 1.294 + 1.295 + // If the frame's background is propagated to an ancestor, walk up to 1.296 + // that ancestor. 1.297 + nsStyleContext *bgSC; 1.298 + while (!nsCSSRendering::FindBackground(aFrame, &bgSC)) { 1.299 + aFrame = aFrame->GetParent(); 1.300 + NS_ASSERTION(aFrame, "root frame must paint"); 1.301 + } 1.302 + 1.303 + // Trigger rendering updates by damaging this frame and any 1.304 + // continuations of this frame. 1.305 + 1.306 + // XXX this needs to detect the need for a view due to an opacity change and deal with it... 1.307 + 1.308 +#ifdef DEBUG 1.309 + gInApplyRenderingChangeToTree = true; 1.310 +#endif 1.311 + DoApplyRenderingChangeToTree(aFrame, aChange); 1.312 +#ifdef DEBUG 1.313 + gInApplyRenderingChangeToTree = false; 1.314 +#endif 1.315 +} 1.316 + 1.317 +bool 1.318 +RestyleManager::RecomputePosition(nsIFrame* aFrame) 1.319 +{ 1.320 + // Don't process position changes on table frames, since we already handle 1.321 + // the dynamic position change on the outer table frame, and the reflow-based 1.322 + // fallback code path also ignores positions on inner table frames. 1.323 + if (aFrame->GetType() == nsGkAtoms::tableFrame) { 1.324 + return true; 1.325 + } 1.326 + 1.327 + const nsStyleDisplay* display = aFrame->StyleDisplay(); 1.328 + // Changes to the offsets of a non-positioned element can safely be ignored. 1.329 + if (display->mPosition == NS_STYLE_POSITION_STATIC) { 1.330 + return true; 1.331 + } 1.332 + 1.333 + // Don't process position changes on frames which have views or the ones which 1.334 + // have a view somewhere in their descendants, because the corresponding view 1.335 + // needs to be repositioned properly as well. 1.336 + if (aFrame->HasView() || 1.337 + (aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) { 1.338 + StyleChangeReflow(aFrame, nsChangeHint_NeedReflow); 1.339 + return false; 1.340 + } 1.341 + 1.342 + aFrame->SchedulePaint(); 1.343 + 1.344 + // For relative positioning, we can simply update the frame rect 1.345 + if (display->IsRelativelyPositionedStyle()) { 1.346 + if (display->IsInnerTableStyle()) { 1.347 + // We don't currently support relative positioning of inner table 1.348 + // elements (bug 35168). If we apply offsets to things we haven't 1.349 + // previously offset, we'll get confused. So bail. 1.350 + return true; 1.351 + } 1.352 + 1.353 + 1.354 + // Move the frame 1.355 + if (display->mPosition == NS_STYLE_POSITION_STICKY) { 1.356 + // Update sticky positioning for an entire element at once when 1.357 + // RecomputePosition is called with the first continuation in a chain. 1.358 + StickyScrollContainer::ComputeStickyOffsets(aFrame); 1.359 + StickyScrollContainer* ssc = 1.360 + StickyScrollContainer::GetStickyScrollContainerForFrame(aFrame); 1.361 + if (ssc) { 1.362 + ssc->PositionContinuations(aFrame); 1.363 + } 1.364 + } else { 1.365 + MOZ_ASSERT(NS_STYLE_POSITION_RELATIVE == display->mPosition, 1.366 + "Unexpected type of positioning"); 1.367 + for (nsIFrame *cont = aFrame; cont; 1.368 + cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) { 1.369 + nsIFrame* cb = cont->GetContainingBlock(); 1.370 + nsMargin newOffsets; 1.371 + const nsSize size = cb->GetContentRectRelativeToSelf().Size(); 1.372 + 1.373 + nsHTMLReflowState::ComputeRelativeOffsets( 1.374 + cb->StyleVisibility()->mDirection, 1.375 + cont, size.width, size.height, newOffsets); 1.376 + NS_ASSERTION(newOffsets.left == -newOffsets.right && 1.377 + newOffsets.top == -newOffsets.bottom, 1.378 + "ComputeRelativeOffsets should return valid results"); 1.379 + 1.380 + // nsHTMLReflowState::ApplyRelativePositioning would work here, but 1.381 + // since we've already checked mPosition and aren't changing the frame's 1.382 + // normal position, go ahead and add the offsets directly. 1.383 + cont->SetPosition(cont->GetNormalPosition() + 1.384 + nsPoint(newOffsets.left, newOffsets.top)); 1.385 + } 1.386 + } 1.387 + 1.388 + return true; 1.389 + } 1.390 + 1.391 + // For the absolute positioning case, set up a fake HTML reflow state for 1.392 + // the frame, and then get the offsets and size from it. If the frame's size 1.393 + // doesn't need to change, we can simply update the frame position. Otherwise 1.394 + // we fall back to a reflow. 1.395 + nsRefPtr<nsRenderingContext> rc = 1.396 + aFrame->PresContext()->PresShell()->CreateReferenceRenderingContext(); 1.397 + 1.398 + // Construct a bogus parent reflow state so that there's a usable 1.399 + // containing block reflow state. 1.400 + nsIFrame* parentFrame = aFrame->GetParent(); 1.401 + nsSize parentSize = parentFrame->GetSize(); 1.402 + 1.403 + nsFrameState savedState = parentFrame->GetStateBits(); 1.404 + nsHTMLReflowState parentReflowState(aFrame->PresContext(), parentFrame, 1.405 + rc, parentSize); 1.406 + parentFrame->RemoveStateBits(~nsFrameState(0)); 1.407 + parentFrame->AddStateBits(savedState); 1.408 + 1.409 + NS_WARN_IF_FALSE(parentSize.width != NS_INTRINSICSIZE && 1.410 + parentSize.height != NS_INTRINSICSIZE, 1.411 + "parentSize should be valid"); 1.412 + parentReflowState.SetComputedWidth(std::max(parentSize.width, 0)); 1.413 + parentReflowState.SetComputedHeight(std::max(parentSize.height, 0)); 1.414 + parentReflowState.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0); 1.415 + 1.416 + parentReflowState.ComputedPhysicalPadding() = parentFrame->GetUsedPadding(); 1.417 + parentReflowState.ComputedPhysicalBorderPadding() = 1.418 + parentFrame->GetUsedBorderAndPadding(); 1.419 + nsSize availSize(parentSize.width, NS_INTRINSICSIZE); 1.420 + 1.421 + ViewportFrame* viewport = do_QueryFrame(parentFrame); 1.422 + nsSize cbSize = viewport ? 1.423 + viewport->AdjustReflowStateAsContainingBlock(&parentReflowState).Size() 1.424 + : aFrame->GetContainingBlock()->GetSize(); 1.425 + const nsMargin& parentBorder = 1.426 + parentReflowState.mStyleBorder->GetComputedBorder(); 1.427 + cbSize -= nsSize(parentBorder.LeftRight(), parentBorder.TopBottom()); 1.428 + nsHTMLReflowState reflowState(aFrame->PresContext(), parentReflowState, 1.429 + aFrame, availSize, cbSize.width, 1.430 + cbSize.height); 1.431 + nsSize computedSize(reflowState.ComputedWidth(), reflowState.ComputedHeight()); 1.432 + computedSize.width += reflowState.ComputedPhysicalBorderPadding().LeftRight(); 1.433 + if (computedSize.height != NS_INTRINSICSIZE) { 1.434 + computedSize.height += reflowState.ComputedPhysicalBorderPadding().TopBottom(); 1.435 + } 1.436 + nsSize size = aFrame->GetSize(); 1.437 + // The RecomputePosition hint is not used if any offset changed between auto 1.438 + // and non-auto. If computedSize.height == NS_INTRINSICSIZE then the new 1.439 + // element height will be its intrinsic height, and since 'top' and 'bottom''s 1.440 + // auto-ness hasn't changed, the old height must also be its intrinsic 1.441 + // height, which we can assume hasn't changed (or reflow would have 1.442 + // been triggered). 1.443 + if (computedSize.width == size.width && 1.444 + (computedSize.height == NS_INTRINSICSIZE || computedSize.height == size.height)) { 1.445 + // If we're solving for 'left' or 'top', then compute it here, in order to 1.446 + // match the reflow code path. 1.447 + if (NS_AUTOOFFSET == reflowState.ComputedPhysicalOffsets().left) { 1.448 + reflowState.ComputedPhysicalOffsets().left = cbSize.width - 1.449 + reflowState.ComputedPhysicalOffsets().right - 1.450 + reflowState.ComputedPhysicalMargin().right - 1.451 + size.width - 1.452 + reflowState.ComputedPhysicalMargin().left; 1.453 + } 1.454 + 1.455 + if (NS_AUTOOFFSET == reflowState.ComputedPhysicalOffsets().top) { 1.456 + reflowState.ComputedPhysicalOffsets().top = cbSize.height - 1.457 + reflowState.ComputedPhysicalOffsets().bottom - 1.458 + reflowState.ComputedPhysicalMargin().bottom - 1.459 + size.height - 1.460 + reflowState.ComputedPhysicalMargin().top; 1.461 + } 1.462 + 1.463 + // Move the frame 1.464 + nsPoint pos(parentBorder.left + reflowState.ComputedPhysicalOffsets().left + 1.465 + reflowState.ComputedPhysicalMargin().left, 1.466 + parentBorder.top + reflowState.ComputedPhysicalOffsets().top + 1.467 + reflowState.ComputedPhysicalMargin().top); 1.468 + aFrame->SetPosition(pos); 1.469 + 1.470 + return true; 1.471 + } 1.472 + 1.473 + // Fall back to a reflow 1.474 + StyleChangeReflow(aFrame, nsChangeHint_NeedReflow); 1.475 + return false; 1.476 +} 1.477 + 1.478 +nsresult 1.479 +RestyleManager::StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint) 1.480 +{ 1.481 + nsIPresShell::IntrinsicDirty dirtyType; 1.482 + if (aHint & nsChangeHint_ClearDescendantIntrinsics) { 1.483 + NS_ASSERTION(aHint & nsChangeHint_ClearAncestorIntrinsics, 1.484 + "Please read the comments in nsChangeHint.h"); 1.485 + dirtyType = nsIPresShell::eStyleChange; 1.486 + } else if (aHint & nsChangeHint_ClearAncestorIntrinsics) { 1.487 + dirtyType = nsIPresShell::eTreeChange; 1.488 + } else { 1.489 + dirtyType = nsIPresShell::eResize; 1.490 + } 1.491 + 1.492 + nsFrameState dirtyBits; 1.493 + if (aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) { 1.494 + dirtyBits = nsFrameState(0); 1.495 + } else if (aHint & nsChangeHint_NeedDirtyReflow) { 1.496 + dirtyBits = NS_FRAME_IS_DIRTY; 1.497 + } else { 1.498 + dirtyBits = NS_FRAME_HAS_DIRTY_CHILDREN; 1.499 + } 1.500 + 1.501 + // If we're not going to clear any intrinsic sizes on the frames, and 1.502 + // there are no dirty bits to set, then there's nothing to do. 1.503 + if (dirtyType == nsIPresShell::eResize && !dirtyBits) 1.504 + return NS_OK; 1.505 + 1.506 + do { 1.507 + mPresContext->PresShell()->FrameNeedsReflow(aFrame, dirtyType, dirtyBits); 1.508 + aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame); 1.509 + } while (aFrame); 1.510 + 1.511 + return NS_OK; 1.512 +} 1.513 + 1.514 +NS_DECLARE_FRAME_PROPERTY(ChangeListProperty, nullptr) 1.515 + 1.516 +/** 1.517 + * Return true if aFrame's subtree has placeholders for out-of-flow content 1.518 + * whose 'position' style's bit in aPositionMask is set. 1.519 + */ 1.520 +static bool 1.521 +FrameHasPositionedPlaceholderDescendants(nsIFrame* aFrame, uint32_t aPositionMask) 1.522 +{ 1.523 + const nsIFrame::ChildListIDs skip(nsIFrame::kAbsoluteList | 1.524 + nsIFrame::kFixedList); 1.525 + for (nsIFrame::ChildListIterator lists(aFrame); !lists.IsDone(); lists.Next()) { 1.526 + if (!skip.Contains(lists.CurrentID())) { 1.527 + for (nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.528 + !childFrames.AtEnd(); childFrames.Next()) { 1.529 + nsIFrame* f = childFrames.get(); 1.530 + if (f->GetType() == nsGkAtoms::placeholderFrame) { 1.531 + nsIFrame* outOfFlow = nsPlaceholderFrame::GetRealFrameForPlaceholder(f); 1.532 + // If SVG text frames could appear here, they could confuse us since 1.533 + // they ignore their position style ... but they can't. 1.534 + NS_ASSERTION(!outOfFlow->IsSVGText(), 1.535 + "SVG text frames can't be out of flow"); 1.536 + if (aPositionMask & (1 << outOfFlow->StyleDisplay()->mPosition)) { 1.537 + return true; 1.538 + } 1.539 + } 1.540 + if (FrameHasPositionedPlaceholderDescendants(f, aPositionMask)) { 1.541 + return true; 1.542 + } 1.543 + } 1.544 + } 1.545 + } 1.546 + return false; 1.547 +} 1.548 + 1.549 +static bool 1.550 +NeedToReframeForAddingOrRemovingTransform(nsIFrame* aFrame) 1.551 +{ 1.552 + static_assert(0 <= NS_STYLE_POSITION_ABSOLUTE && 1.553 + NS_STYLE_POSITION_ABSOLUTE < 32, "Style constant out of range"); 1.554 + static_assert(0 <= NS_STYLE_POSITION_FIXED && 1.555 + NS_STYLE_POSITION_FIXED < 32, "Style constant out of range"); 1.556 + 1.557 + uint32_t positionMask; 1.558 + // Don't call aFrame->IsPositioned here, since that returns true if 1.559 + // the frame already has a transform, and we want to ignore that here 1.560 + if (aFrame->IsAbsolutelyPositioned() || 1.561 + aFrame->IsRelativelyPositioned()) { 1.562 + // This frame is a container for abs-pos descendants whether or not it 1.563 + // has a transform. 1.564 + // So abs-pos descendants are no problem; we only need to reframe if 1.565 + // we have fixed-pos descendants. 1.566 + positionMask = 1 << NS_STYLE_POSITION_FIXED; 1.567 + } else { 1.568 + // This frame may not be a container for abs-pos descendants already. 1.569 + // So reframe if we have abs-pos or fixed-pos descendants. 1.570 + positionMask = (1 << NS_STYLE_POSITION_FIXED) | 1.571 + (1 << NS_STYLE_POSITION_ABSOLUTE); 1.572 + } 1.573 + for (nsIFrame* f = aFrame; f; 1.574 + f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) { 1.575 + if (FrameHasPositionedPlaceholderDescendants(f, positionMask)) { 1.576 + return true; 1.577 + } 1.578 + } 1.579 + return false; 1.580 +} 1.581 + 1.582 +nsresult 1.583 +RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList) 1.584 +{ 1.585 + NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), 1.586 + "Someone forgot a script blocker"); 1.587 + int32_t count = aChangeList.Count(); 1.588 + if (!count) 1.589 + return NS_OK; 1.590 + 1.591 + PROFILER_LABEL("CSS", "ProcessRestyledFrames"); 1.592 + 1.593 + // Make sure to not rebuild quote or counter lists while we're 1.594 + // processing restyles 1.595 + FrameConstructor()->BeginUpdate(); 1.596 + 1.597 + FramePropertyTable* propTable = mPresContext->PropertyTable(); 1.598 + 1.599 + // Mark frames so that we skip frames that die along the way, bug 123049. 1.600 + // A frame can be in the list multiple times with different hints. Further 1.601 + // optmization is possible if nsStyleChangeList::AppendChange could coalesce 1.602 + int32_t index = count; 1.603 + 1.604 + while (0 <= --index) { 1.605 + const nsStyleChangeData* changeData; 1.606 + aChangeList.ChangeAt(index, &changeData); 1.607 + if (changeData->mFrame) { 1.608 + propTable->Set(changeData->mFrame, ChangeListProperty(), 1.609 + NS_INT32_TO_PTR(1)); 1.610 + } 1.611 + } 1.612 + 1.613 + index = count; 1.614 + 1.615 + bool didUpdateCursor = false; 1.616 + 1.617 + while (0 <= --index) { 1.618 + nsIFrame* frame; 1.619 + nsIContent* content; 1.620 + bool didReflowThisFrame = false; 1.621 + nsChangeHint hint; 1.622 + aChangeList.ChangeAt(index, frame, content, hint); 1.623 + 1.624 + NS_ASSERTION(!(hint & nsChangeHint_AllReflowHints) || 1.625 + (hint & nsChangeHint_NeedReflow), 1.626 + "Reflow hint bits set without actually asking for a reflow"); 1.627 + 1.628 + // skip any frame that has been destroyed due to a ripple effect 1.629 + if (frame && !propTable->Get(frame, ChangeListProperty())) { 1.630 + continue; 1.631 + } 1.632 + 1.633 + if (frame && frame->GetContent() != content) { 1.634 + // XXXbz this is due to image maps messing with the primary frame of 1.635 + // <area>s. See bug 135040. Remove this block once that's fixed. 1.636 + frame = nullptr; 1.637 + if (!(hint & nsChangeHint_ReconstructFrame)) { 1.638 + continue; 1.639 + } 1.640 + } 1.641 + 1.642 + if ((hint & nsChangeHint_AddOrRemoveTransform) && frame && 1.643 + !(hint & nsChangeHint_ReconstructFrame)) { 1.644 + if (NeedToReframeForAddingOrRemovingTransform(frame) || 1.645 + frame->GetType() == nsGkAtoms::fieldSetFrame || 1.646 + frame->GetContentInsertionFrame() != frame) { 1.647 + // The frame has positioned children that need to be reparented, or 1.648 + // it can't easily be converted to/from being an abs-pos container correctly. 1.649 + NS_UpdateHint(hint, nsChangeHint_ReconstructFrame); 1.650 + } else { 1.651 + for (nsIFrame *cont = frame; cont; 1.652 + cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) { 1.653 + // Normally frame construction would set state bits as needed, 1.654 + // but we're not going to reconstruct the frame so we need to set them. 1.655 + // It's because we need to set this state on each affected frame 1.656 + // that we can't coalesce nsChangeHint_AddOrRemoveTransform hints up 1.657 + // to ancestors (i.e. it can't be an inherited change hint). 1.658 + if (cont->IsPositioned()) { 1.659 + // If a transform has been added, we'll be taking this path, 1.660 + // but we may be taking this path even if a transform has been 1.661 + // removed. It's OK to add the bit even if it's not needed. 1.662 + cont->AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED); 1.663 + if (!cont->IsAbsoluteContainer() && 1.664 + (cont->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) { 1.665 + cont->MarkAsAbsoluteContainingBlock(); 1.666 + } 1.667 + } else { 1.668 + // Don't remove NS_FRAME_MAY_BE_TRANSFORMED since it may still by 1.669 + // transformed by other means. It's OK to have the bit even if it's 1.670 + // not needed. 1.671 + if (cont->IsAbsoluteContainer()) { 1.672 + cont->MarkAsNotAbsoluteContainingBlock(); 1.673 + } 1.674 + } 1.675 + } 1.676 + } 1.677 + } 1.678 + if (hint & nsChangeHint_ReconstructFrame) { 1.679 + // If we ever start passing true here, be careful of restyles 1.680 + // that involve a reframe and animations. In particular, if the 1.681 + // restyle we're processing here is an animation restyle, but 1.682 + // the style resolution we will do for the frame construction 1.683 + // happens async when we're not in an animation restyle already, 1.684 + // problems could arise. 1.685 + FrameConstructor()->RecreateFramesForContent(content, false); 1.686 + } else { 1.687 + NS_ASSERTION(frame, "This shouldn't happen"); 1.688 + 1.689 + if ((frame->GetStateBits() & NS_FRAME_SVG_LAYOUT) && 1.690 + (frame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) { 1.691 + // frame does not maintain overflow rects, so avoid calling 1.692 + // FinishAndStoreOverflow on it: 1.693 + hint = NS_SubtractHint(hint, 1.694 + NS_CombineHint(nsChangeHint_UpdateOverflow, 1.695 + NS_CombineHint(nsChangeHint_ChildrenOnlyTransform, 1.696 + nsChangeHint_UpdatePostTransformOverflow))); 1.697 + } 1.698 + 1.699 + if (!(frame->GetStateBits() & NS_FRAME_MAY_BE_TRANSFORMED)) { 1.700 + // Frame can not be transformed, and thus a change in transform will 1.701 + // have no effect and we should not use the 1.702 + // nsChangeHint_UpdatePostTransformOverflow hint. 1.703 + hint = NS_SubtractHint(hint, nsChangeHint_UpdatePostTransformOverflow); 1.704 + } 1.705 + 1.706 + if (hint & nsChangeHint_UpdateEffects) { 1.707 + for (nsIFrame *cont = frame; cont; 1.708 + cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) { 1.709 + nsSVGEffects::UpdateEffects(cont); 1.710 + } 1.711 + } 1.712 + if (hint & nsChangeHint_NeedReflow) { 1.713 + StyleChangeReflow(frame, hint); 1.714 + didReflowThisFrame = true; 1.715 + } 1.716 + if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView | 1.717 + nsChangeHint_UpdateOpacityLayer | nsChangeHint_UpdateTransformLayer | 1.718 + nsChangeHint_ChildrenOnlyTransform)) { 1.719 + ApplyRenderingChangeToTree(mPresContext, frame, hint); 1.720 + } 1.721 + if ((hint & nsChangeHint_RecomputePosition) && !didReflowThisFrame) { 1.722 + ActiveLayerTracker::NotifyOffsetRestyle(frame); 1.723 + // It is possible for this to fall back to a reflow 1.724 + if (!RecomputePosition(frame)) { 1.725 + didReflowThisFrame = true; 1.726 + } 1.727 + } 1.728 + NS_ASSERTION(!(hint & nsChangeHint_ChildrenOnlyTransform) || 1.729 + (hint & nsChangeHint_UpdateOverflow), 1.730 + "nsChangeHint_UpdateOverflow should be passed too"); 1.731 + if (!didReflowThisFrame && 1.732 + (hint & (nsChangeHint_UpdateOverflow | 1.733 + nsChangeHint_UpdatePostTransformOverflow))) { 1.734 + OverflowChangedTracker::ChangeKind changeKind; 1.735 + if (hint & nsChangeHint_ChildrenOnlyTransform) { 1.736 + // The overflow areas of the child frames need to be updated: 1.737 + nsIFrame* hintFrame = GetFrameForChildrenOnlyTransformHint(frame); 1.738 + nsIFrame* childFrame = hintFrame->GetFirstPrincipalChild(); 1.739 + NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame), 1.740 + "SVG frames should not have continuations " 1.741 + "or ib-split siblings"); 1.742 + NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(hintFrame), 1.743 + "SVG frames should not have continuations " 1.744 + "or ib-split siblings"); 1.745 + for ( ; childFrame; childFrame = childFrame->GetNextSibling()) { 1.746 + NS_ABORT_IF_FALSE(childFrame->IsFrameOfType(nsIFrame::eSVG), 1.747 + "Not expecting non-SVG children"); 1.748 + // If |childFrame| is dirty or has dirty children, we don't bother 1.749 + // updating overflows since that will happen when it's reflowed. 1.750 + if (!(childFrame->GetStateBits() & 1.751 + (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) { 1.752 + mOverflowChangedTracker.AddFrame(childFrame, 1.753 + OverflowChangedTracker::CHILDREN_AND_PARENT_CHANGED); 1.754 + } 1.755 + NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(childFrame), 1.756 + "SVG frames should not have continuations " 1.757 + "or ib-split siblings"); 1.758 + NS_ASSERTION(childFrame->GetParent() == hintFrame, 1.759 + "SVG child frame not expected to have different parent"); 1.760 + } 1.761 + } 1.762 + // If |frame| is dirty or has dirty children, we don't bother updating 1.763 + // overflows since that will happen when it's reflowed. 1.764 + if (!(frame->GetStateBits() & 1.765 + (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) { 1.766 + // If we have both nsChangeHint_UpdateOverflow and 1.767 + // nsChangeHint_UpdatePostTransformOverflow, CHILDREN_AND_PARENT_CHANGED 1.768 + // is selected as it is stronger. 1.769 + if (hint & nsChangeHint_UpdateOverflow) { 1.770 + changeKind = OverflowChangedTracker::CHILDREN_AND_PARENT_CHANGED; 1.771 + } else { 1.772 + changeKind = OverflowChangedTracker::TRANSFORM_CHANGED; 1.773 + } 1.774 + for (nsIFrame *cont = frame; cont; cont = 1.775 + nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) { 1.776 + mOverflowChangedTracker.AddFrame(cont, changeKind); 1.777 + } 1.778 + } 1.779 + } 1.780 + if ((hint & nsChangeHint_UpdateCursor) && !didUpdateCursor) { 1.781 + mPresContext->PresShell()->SynthesizeMouseMove(false); 1.782 + didUpdateCursor = true; 1.783 + } 1.784 + } 1.785 + } 1.786 + 1.787 + FrameConstructor()->EndUpdate(); 1.788 + 1.789 + // cleanup references and verify the style tree. Note that the latter needs 1.790 + // to happen once we've processed the whole list, since until then the tree 1.791 + // is not in fact in a consistent state. 1.792 + index = count; 1.793 + while (0 <= --index) { 1.794 + const nsStyleChangeData* changeData; 1.795 + aChangeList.ChangeAt(index, &changeData); 1.796 + if (changeData->mFrame) { 1.797 + propTable->Delete(changeData->mFrame, ChangeListProperty()); 1.798 + } 1.799 + 1.800 +#ifdef DEBUG 1.801 + // reget frame from content since it may have been regenerated... 1.802 + if (changeData->mContent) { 1.803 + if (!nsAnimationManager::ContentOrAncestorHasAnimation(changeData->mContent) && 1.804 + !nsTransitionManager::ContentOrAncestorHasTransition(changeData->mContent)) { 1.805 + nsIFrame* frame = changeData->mContent->GetPrimaryFrame(); 1.806 + if (frame) { 1.807 + DebugVerifyStyleTree(frame); 1.808 + } 1.809 + } 1.810 + } else if (!changeData->mFrame || 1.811 + changeData->mFrame->GetType() != nsGkAtoms::viewportFrame) { 1.812 + NS_WARNING("Unable to test style tree integrity -- no content node " 1.813 + "(and not a viewport frame)"); 1.814 + } 1.815 +#endif 1.816 + } 1.817 + 1.818 + aChangeList.Clear(); 1.819 + return NS_OK; 1.820 +} 1.821 + 1.822 +void 1.823 +RestyleManager::RestyleElement(Element* aElement, 1.824 + nsIFrame* aPrimaryFrame, 1.825 + nsChangeHint aMinHint, 1.826 + RestyleTracker& aRestyleTracker, 1.827 + bool aRestyleDescendants) 1.828 +{ 1.829 + NS_ASSERTION(aPrimaryFrame == aElement->GetPrimaryFrame(), 1.830 + "frame/content mismatch"); 1.831 + if (aPrimaryFrame && aPrimaryFrame->GetContent() != aElement) { 1.832 + // XXXbz this is due to image maps messing with the primary frame pointer 1.833 + // of <area>s. See bug 135040. We can remove this block once that's fixed. 1.834 + aPrimaryFrame = nullptr; 1.835 + } 1.836 + NS_ASSERTION(!aPrimaryFrame || aPrimaryFrame->GetContent() == aElement, 1.837 + "frame/content mismatch"); 1.838 + 1.839 + // If we're restyling the root element and there are 'rem' units in 1.840 + // use, handle dynamic changes to the definition of a 'rem' here. 1.841 + if (mPresContext->UsesRootEMUnits() && aPrimaryFrame) { 1.842 + nsStyleContext *oldContext = aPrimaryFrame->StyleContext(); 1.843 + if (!oldContext->GetParent()) { // check that we're the root element 1.844 + nsRefPtr<nsStyleContext> newContext = mPresContext->StyleSet()-> 1.845 + ResolveStyleFor(aElement, nullptr /* == oldContext->GetParent() */); 1.846 + if (oldContext->StyleFont()->mFont.size != 1.847 + newContext->StyleFont()->mFont.size) { 1.848 + // The basis for 'rem' units has changed. 1.849 + newContext = nullptr; 1.850 + DoRebuildAllStyleData(aRestyleTracker, nsChangeHint(0)); 1.851 + if (aMinHint == 0) { 1.852 + return; 1.853 + } 1.854 + aPrimaryFrame = aElement->GetPrimaryFrame(); 1.855 + } 1.856 + } 1.857 + } 1.858 + 1.859 + if (aMinHint & nsChangeHint_ReconstructFrame) { 1.860 + FrameConstructor()->RecreateFramesForContent(aElement, false); 1.861 + } else if (aPrimaryFrame) { 1.862 + nsStyleChangeList changeList; 1.863 + ComputeStyleChangeFor(aPrimaryFrame, &changeList, aMinHint, 1.864 + aRestyleTracker, aRestyleDescendants); 1.865 + ProcessRestyledFrames(changeList); 1.866 + } else { 1.867 + // no frames, reconstruct for content 1.868 + FrameConstructor()->MaybeRecreateFramesForElement(aElement); 1.869 + } 1.870 +} 1.871 + 1.872 +static inline dom::Element* 1.873 +ElementForStyleContext(nsIContent* aParentContent, 1.874 + nsIFrame* aFrame, 1.875 + nsCSSPseudoElements::Type aPseudoType); 1.876 + 1.877 +// Forwarded nsIDocumentObserver method, to handle restyling (and 1.878 +// passing the notification to the frame). 1.879 +nsresult 1.880 +RestyleManager::ContentStateChanged(nsIContent* aContent, 1.881 + EventStates aStateMask) 1.882 +{ 1.883 + // XXXbz it would be good if this function only took Elements, but 1.884 + // we'd have to make ESM guarantee that usefully. 1.885 + if (!aContent->IsElement()) { 1.886 + return NS_OK; 1.887 + } 1.888 + 1.889 + Element* aElement = aContent->AsElement(); 1.890 + 1.891 + nsStyleSet* styleSet = mPresContext->StyleSet(); 1.892 + NS_ASSERTION(styleSet, "couldn't get style set"); 1.893 + 1.894 + nsChangeHint hint = NS_STYLE_HINT_NONE; 1.895 + // Any change to a content state that affects which frames we construct 1.896 + // must lead to a frame reconstruct here if we already have a frame. 1.897 + // Note that we never decide through non-CSS means to not create frames 1.898 + // based on content states, so if we already don't have a frame we don't 1.899 + // need to force a reframe -- if it's needed, the HasStateDependentStyle 1.900 + // call will handle things. 1.901 + nsIFrame* primaryFrame = aElement->GetPrimaryFrame(); 1.902 + nsCSSPseudoElements::Type pseudoType = 1.903 + nsCSSPseudoElements::ePseudo_NotPseudoElement; 1.904 + if (primaryFrame) { 1.905 + // If it's generated content, ignore LOADING/etc state changes on it. 1.906 + if (!primaryFrame->IsGeneratedContentFrame() && 1.907 + aStateMask.HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN | 1.908 + NS_EVENT_STATE_USERDISABLED | 1.909 + NS_EVENT_STATE_SUPPRESSED | 1.910 + NS_EVENT_STATE_LOADING)) { 1.911 + hint = nsChangeHint_ReconstructFrame; 1.912 + } else { 1.913 + uint8_t app = primaryFrame->StyleDisplay()->mAppearance; 1.914 + if (app) { 1.915 + nsITheme *theme = mPresContext->GetTheme(); 1.916 + if (theme && theme->ThemeSupportsWidget(mPresContext, 1.917 + primaryFrame, app)) { 1.918 + bool repaint = false; 1.919 + theme->WidgetStateChanged(primaryFrame, app, nullptr, &repaint); 1.920 + if (repaint) { 1.921 + NS_UpdateHint(hint, nsChangeHint_RepaintFrame); 1.922 + } 1.923 + } 1.924 + } 1.925 + } 1.926 + 1.927 + pseudoType = primaryFrame->StyleContext()->GetPseudoType(); 1.928 + 1.929 + primaryFrame->ContentStatesChanged(aStateMask); 1.930 + } 1.931 + 1.932 + 1.933 + nsRestyleHint rshint; 1.934 + 1.935 + if (pseudoType >= nsCSSPseudoElements::ePseudo_PseudoElementCount) { 1.936 + rshint = styleSet->HasStateDependentStyle(mPresContext, aElement, 1.937 + aStateMask); 1.938 + } else if (nsCSSPseudoElements::PseudoElementSupportsUserActionState( 1.939 + pseudoType)) { 1.940 + // If aElement is a pseudo-element, we want to check to see whether there 1.941 + // are any state-dependent rules applying to that pseudo. 1.942 + Element* ancestor = ElementForStyleContext(nullptr, primaryFrame, 1.943 + pseudoType); 1.944 + rshint = styleSet->HasStateDependentStyle(mPresContext, ancestor, 1.945 + pseudoType, aElement, 1.946 + aStateMask); 1.947 + } else { 1.948 + rshint = nsRestyleHint(0); 1.949 + } 1.950 + 1.951 + if (aStateMask.HasState(NS_EVENT_STATE_HOVER) && rshint != 0) { 1.952 + ++mHoverGeneration; 1.953 + } 1.954 + 1.955 + if (aStateMask.HasState(NS_EVENT_STATE_VISITED)) { 1.956 + // Exposing information to the page about whether the link is 1.957 + // visited or not isn't really something we can worry about here. 1.958 + // FIXME: We could probably do this a bit better. 1.959 + NS_UpdateHint(hint, nsChangeHint_RepaintFrame); 1.960 + } 1.961 + 1.962 + PostRestyleEvent(aElement, rshint, hint); 1.963 + return NS_OK; 1.964 +} 1.965 + 1.966 +// Forwarded nsIMutationObserver method, to handle restyling. 1.967 +void 1.968 +RestyleManager::AttributeWillChange(Element* aElement, 1.969 + int32_t aNameSpaceID, 1.970 + nsIAtom* aAttribute, 1.971 + int32_t aModType) 1.972 +{ 1.973 + nsRestyleHint rshint = 1.974 + mPresContext->StyleSet()->HasAttributeDependentStyle(mPresContext, 1.975 + aElement, 1.976 + aAttribute, 1.977 + aModType, 1.978 + false); 1.979 + PostRestyleEvent(aElement, rshint, NS_STYLE_HINT_NONE); 1.980 +} 1.981 + 1.982 +// Forwarded nsIMutationObserver method, to handle restyling (and 1.983 +// passing the notification to the frame). 1.984 +void 1.985 +RestyleManager::AttributeChanged(Element* aElement, 1.986 + int32_t aNameSpaceID, 1.987 + nsIAtom* aAttribute, 1.988 + int32_t aModType) 1.989 +{ 1.990 + // Hold onto the PresShell to prevent ourselves from being destroyed. 1.991 + // XXXbz how, exactly, would this attribute change cause us to be 1.992 + // destroyed from inside this function? 1.993 + nsCOMPtr<nsIPresShell> shell = mPresContext->GetPresShell(); 1.994 + 1.995 + // Get the frame associated with the content which is the highest in the frame tree 1.996 + nsIFrame* primaryFrame = aElement->GetPrimaryFrame(); 1.997 + 1.998 +#if 0 1.999 + NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, 1.1000 + ("RestyleManager::AttributeChanged: content=%p[%s] frame=%p", 1.1001 + aContent, ContentTag(aElement, 0), frame)); 1.1002 +#endif 1.1003 + 1.1004 + // the style tag has its own interpretation based on aHint 1.1005 + nsChangeHint hint = aElement->GetAttributeChangeHint(aAttribute, aModType); 1.1006 + 1.1007 + bool reframe = (hint & nsChangeHint_ReconstructFrame) != 0; 1.1008 + 1.1009 +#ifdef MOZ_XUL 1.1010 + // The following listbox widget trap prevents offscreen listbox widget 1.1011 + // content from being removed and re-inserted (which is what would 1.1012 + // happen otherwise). 1.1013 + if (!primaryFrame && !reframe) { 1.1014 + int32_t namespaceID; 1.1015 + nsIAtom* tag = mPresContext->Document()->BindingManager()-> 1.1016 + ResolveTag(aElement, &namespaceID); 1.1017 + 1.1018 + if (namespaceID == kNameSpaceID_XUL && 1.1019 + (tag == nsGkAtoms::listitem || 1.1020 + tag == nsGkAtoms::listcell)) 1.1021 + return; 1.1022 + } 1.1023 + 1.1024 + if (aAttribute == nsGkAtoms::tooltiptext || 1.1025 + aAttribute == nsGkAtoms::tooltip) 1.1026 + { 1.1027 + nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresContext->GetPresShell()); 1.1028 + if (rootBox) { 1.1029 + if (aModType == nsIDOMMutationEvent::REMOVAL) 1.1030 + rootBox->RemoveTooltipSupport(aElement); 1.1031 + if (aModType == nsIDOMMutationEvent::ADDITION) 1.1032 + rootBox->AddTooltipSupport(aElement); 1.1033 + } 1.1034 + } 1.1035 + 1.1036 +#endif // MOZ_XUL 1.1037 + 1.1038 + if (primaryFrame) { 1.1039 + // See if we have appearance information for a theme. 1.1040 + const nsStyleDisplay* disp = primaryFrame->StyleDisplay(); 1.1041 + if (disp->mAppearance) { 1.1042 + nsITheme *theme = mPresContext->GetTheme(); 1.1043 + if (theme && theme->ThemeSupportsWidget(mPresContext, primaryFrame, disp->mAppearance)) { 1.1044 + bool repaint = false; 1.1045 + theme->WidgetStateChanged(primaryFrame, disp->mAppearance, aAttribute, &repaint); 1.1046 + if (repaint) 1.1047 + NS_UpdateHint(hint, nsChangeHint_RepaintFrame); 1.1048 + } 1.1049 + } 1.1050 + 1.1051 + // let the frame deal with it now, so we don't have to deal later 1.1052 + primaryFrame->AttributeChanged(aNameSpaceID, aAttribute, aModType); 1.1053 + // XXXwaterson should probably check for IB split siblings 1.1054 + // here, and propagate the AttributeChanged notification to 1.1055 + // them, as well. Currently, inline frames don't do anything on 1.1056 + // this notification, so it's not that big a deal. 1.1057 + } 1.1058 + 1.1059 + // See if we can optimize away the style re-resolution -- must be called after 1.1060 + // the frame's AttributeChanged() in case it does something that affects the style 1.1061 + nsRestyleHint rshint = 1.1062 + mPresContext->StyleSet()->HasAttributeDependentStyle(mPresContext, 1.1063 + aElement, 1.1064 + aAttribute, 1.1065 + aModType, 1.1066 + true); 1.1067 + 1.1068 + PostRestyleEvent(aElement, rshint, hint); 1.1069 +} 1.1070 + 1.1071 +void 1.1072 +RestyleManager::RestyleForEmptyChange(Element* aContainer) 1.1073 +{ 1.1074 + // In some cases (:empty + E, :empty ~ E), a change if the content of 1.1075 + // an element requires restyling its parent's siblings. 1.1076 + nsRestyleHint hint = eRestyle_Subtree; 1.1077 + nsIContent* grandparent = aContainer->GetParent(); 1.1078 + if (grandparent && 1.1079 + (grandparent->GetFlags() & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS)) { 1.1080 + hint = nsRestyleHint(hint | eRestyle_LaterSiblings); 1.1081 + } 1.1082 + PostRestyleEvent(aContainer, hint, NS_STYLE_HINT_NONE); 1.1083 +} 1.1084 + 1.1085 +void 1.1086 +RestyleManager::RestyleForAppend(Element* aContainer, 1.1087 + nsIContent* aFirstNewContent) 1.1088 +{ 1.1089 + NS_ASSERTION(aContainer, "must have container for append"); 1.1090 +#ifdef DEBUG 1.1091 + { 1.1092 + for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) { 1.1093 + NS_ASSERTION(!cur->IsRootOfAnonymousSubtree(), 1.1094 + "anonymous nodes should not be in child lists"); 1.1095 + } 1.1096 + } 1.1097 +#endif 1.1098 + uint32_t selectorFlags = 1.1099 + aContainer->GetFlags() & (NODE_ALL_SELECTOR_FLAGS & 1.1100 + ~NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS); 1.1101 + if (selectorFlags == 0) 1.1102 + return; 1.1103 + 1.1104 + if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) { 1.1105 + // see whether we need to restyle the container 1.1106 + bool wasEmpty = true; // :empty or :-moz-only-whitespace 1.1107 + for (nsIContent* cur = aContainer->GetFirstChild(); 1.1108 + cur != aFirstNewContent; 1.1109 + cur = cur->GetNextSibling()) { 1.1110 + // We don't know whether we're testing :empty or :-moz-only-whitespace, 1.1111 + // so be conservative and assume :-moz-only-whitespace (i.e., make 1.1112 + // IsSignificantChild less likely to be true, and thus make us more 1.1113 + // likely to restyle). 1.1114 + if (nsStyleUtil::IsSignificantChild(cur, true, false)) { 1.1115 + wasEmpty = false; 1.1116 + break; 1.1117 + } 1.1118 + } 1.1119 + if (wasEmpty) { 1.1120 + RestyleForEmptyChange(aContainer); 1.1121 + return; 1.1122 + } 1.1123 + } 1.1124 + 1.1125 + if (selectorFlags & NODE_HAS_SLOW_SELECTOR) { 1.1126 + PostRestyleEvent(aContainer, eRestyle_Subtree, NS_STYLE_HINT_NONE); 1.1127 + // Restyling the container is the most we can do here, so we're done. 1.1128 + return; 1.1129 + } 1.1130 + 1.1131 + if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) { 1.1132 + // restyle the last element child before this node 1.1133 + for (nsIContent* cur = aFirstNewContent->GetPreviousSibling(); 1.1134 + cur; 1.1135 + cur = cur->GetPreviousSibling()) { 1.1136 + if (cur->IsElement()) { 1.1137 + PostRestyleEvent(cur->AsElement(), eRestyle_Subtree, NS_STYLE_HINT_NONE); 1.1138 + break; 1.1139 + } 1.1140 + } 1.1141 + } 1.1142 +} 1.1143 + 1.1144 +// Needed since we can't use PostRestyleEvent on non-elements (with 1.1145 +// eRestyle_LaterSiblings or nsRestyleHint(eRestyle_Subtree | 1.1146 +// eRestyle_LaterSiblings) as appropriate). 1.1147 +static void 1.1148 +RestyleSiblingsStartingWith(RestyleManager* aRestyleManager, 1.1149 + nsIContent* aStartingSibling /* may be null */) 1.1150 +{ 1.1151 + for (nsIContent *sibling = aStartingSibling; sibling; 1.1152 + sibling = sibling->GetNextSibling()) { 1.1153 + if (sibling->IsElement()) { 1.1154 + aRestyleManager-> 1.1155 + PostRestyleEvent(sibling->AsElement(), 1.1156 + nsRestyleHint(eRestyle_Subtree | eRestyle_LaterSiblings), 1.1157 + NS_STYLE_HINT_NONE); 1.1158 + break; 1.1159 + } 1.1160 + } 1.1161 +} 1.1162 + 1.1163 +// Restyling for a ContentInserted or CharacterDataChanged notification. 1.1164 +// This could be used for ContentRemoved as well if we got the 1.1165 +// notification before the removal happened (and sometimes 1.1166 +// CharacterDataChanged is more like a removal than an addition). 1.1167 +// The comments are written and variables are named in terms of it being 1.1168 +// a ContentInserted notification. 1.1169 +void 1.1170 +RestyleManager::RestyleForInsertOrChange(Element* aContainer, 1.1171 + nsIContent* aChild) 1.1172 +{ 1.1173 + NS_ASSERTION(!aChild->IsRootOfAnonymousSubtree(), 1.1174 + "anonymous nodes should not be in child lists"); 1.1175 + uint32_t selectorFlags = 1.1176 + aContainer ? (aContainer->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0; 1.1177 + if (selectorFlags == 0) 1.1178 + return; 1.1179 + 1.1180 + if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) { 1.1181 + // see whether we need to restyle the container 1.1182 + bool wasEmpty = true; // :empty or :-moz-only-whitespace 1.1183 + for (nsIContent* child = aContainer->GetFirstChild(); 1.1184 + child; 1.1185 + child = child->GetNextSibling()) { 1.1186 + if (child == aChild) 1.1187 + continue; 1.1188 + // We don't know whether we're testing :empty or :-moz-only-whitespace, 1.1189 + // so be conservative and assume :-moz-only-whitespace (i.e., make 1.1190 + // IsSignificantChild less likely to be true, and thus make us more 1.1191 + // likely to restyle). 1.1192 + if (nsStyleUtil::IsSignificantChild(child, true, false)) { 1.1193 + wasEmpty = false; 1.1194 + break; 1.1195 + } 1.1196 + } 1.1197 + if (wasEmpty) { 1.1198 + RestyleForEmptyChange(aContainer); 1.1199 + return; 1.1200 + } 1.1201 + } 1.1202 + 1.1203 + if (selectorFlags & NODE_HAS_SLOW_SELECTOR) { 1.1204 + PostRestyleEvent(aContainer, eRestyle_Subtree, NS_STYLE_HINT_NONE); 1.1205 + // Restyling the container is the most we can do here, so we're done. 1.1206 + return; 1.1207 + } 1.1208 + 1.1209 + if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) { 1.1210 + // Restyle all later siblings. 1.1211 + RestyleSiblingsStartingWith(this, aChild->GetNextSibling()); 1.1212 + } 1.1213 + 1.1214 + if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) { 1.1215 + // restyle the previously-first element child if it is after this node 1.1216 + bool passedChild = false; 1.1217 + for (nsIContent* content = aContainer->GetFirstChild(); 1.1218 + content; 1.1219 + content = content->GetNextSibling()) { 1.1220 + if (content == aChild) { 1.1221 + passedChild = true; 1.1222 + continue; 1.1223 + } 1.1224 + if (content->IsElement()) { 1.1225 + if (passedChild) { 1.1226 + PostRestyleEvent(content->AsElement(), eRestyle_Subtree, 1.1227 + NS_STYLE_HINT_NONE); 1.1228 + } 1.1229 + break; 1.1230 + } 1.1231 + } 1.1232 + // restyle the previously-last element child if it is before this node 1.1233 + passedChild = false; 1.1234 + for (nsIContent* content = aContainer->GetLastChild(); 1.1235 + content; 1.1236 + content = content->GetPreviousSibling()) { 1.1237 + if (content == aChild) { 1.1238 + passedChild = true; 1.1239 + continue; 1.1240 + } 1.1241 + if (content->IsElement()) { 1.1242 + if (passedChild) { 1.1243 + PostRestyleEvent(content->AsElement(), eRestyle_Subtree, 1.1244 + NS_STYLE_HINT_NONE); 1.1245 + } 1.1246 + break; 1.1247 + } 1.1248 + } 1.1249 + } 1.1250 +} 1.1251 + 1.1252 +void 1.1253 +RestyleManager::RestyleForRemove(Element* aContainer, 1.1254 + nsIContent* aOldChild, 1.1255 + nsIContent* aFollowingSibling) 1.1256 +{ 1.1257 + if (aOldChild->IsRootOfAnonymousSubtree()) { 1.1258 + // This should be an assert, but this is called incorrectly in 1.1259 + // nsHTMLEditor::DeleteRefToAnonymousNode and the assertions were clogging 1.1260 + // up the logs. Make it an assert again when that's fixed. 1.1261 + NS_WARNING("anonymous nodes should not be in child lists (bug 439258)"); 1.1262 + } 1.1263 + uint32_t selectorFlags = 1.1264 + aContainer ? (aContainer->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0; 1.1265 + if (selectorFlags == 0) 1.1266 + return; 1.1267 + 1.1268 + if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) { 1.1269 + // see whether we need to restyle the container 1.1270 + bool isEmpty = true; // :empty or :-moz-only-whitespace 1.1271 + for (nsIContent* child = aContainer->GetFirstChild(); 1.1272 + child; 1.1273 + child = child->GetNextSibling()) { 1.1274 + // We don't know whether we're testing :empty or :-moz-only-whitespace, 1.1275 + // so be conservative and assume :-moz-only-whitespace (i.e., make 1.1276 + // IsSignificantChild less likely to be true, and thus make us more 1.1277 + // likely to restyle). 1.1278 + if (nsStyleUtil::IsSignificantChild(child, true, false)) { 1.1279 + isEmpty = false; 1.1280 + break; 1.1281 + } 1.1282 + } 1.1283 + if (isEmpty) { 1.1284 + RestyleForEmptyChange(aContainer); 1.1285 + return; 1.1286 + } 1.1287 + } 1.1288 + 1.1289 + if (selectorFlags & NODE_HAS_SLOW_SELECTOR) { 1.1290 + PostRestyleEvent(aContainer, eRestyle_Subtree, NS_STYLE_HINT_NONE); 1.1291 + // Restyling the container is the most we can do here, so we're done. 1.1292 + return; 1.1293 + } 1.1294 + 1.1295 + if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) { 1.1296 + // Restyle all later siblings. 1.1297 + RestyleSiblingsStartingWith(this, aFollowingSibling); 1.1298 + } 1.1299 + 1.1300 + if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) { 1.1301 + // restyle the now-first element child if it was after aOldChild 1.1302 + bool reachedFollowingSibling = false; 1.1303 + for (nsIContent* content = aContainer->GetFirstChild(); 1.1304 + content; 1.1305 + content = content->GetNextSibling()) { 1.1306 + if (content == aFollowingSibling) { 1.1307 + reachedFollowingSibling = true; 1.1308 + // do NOT continue here; we might want to restyle this node 1.1309 + } 1.1310 + if (content->IsElement()) { 1.1311 + if (reachedFollowingSibling) { 1.1312 + PostRestyleEvent(content->AsElement(), eRestyle_Subtree, 1.1313 + NS_STYLE_HINT_NONE); 1.1314 + } 1.1315 + break; 1.1316 + } 1.1317 + } 1.1318 + // restyle the now-last element child if it was before aOldChild 1.1319 + reachedFollowingSibling = (aFollowingSibling == nullptr); 1.1320 + for (nsIContent* content = aContainer->GetLastChild(); 1.1321 + content; 1.1322 + content = content->GetPreviousSibling()) { 1.1323 + if (content->IsElement()) { 1.1324 + if (reachedFollowingSibling) { 1.1325 + PostRestyleEvent(content->AsElement(), eRestyle_Subtree, NS_STYLE_HINT_NONE); 1.1326 + } 1.1327 + break; 1.1328 + } 1.1329 + if (content == aFollowingSibling) { 1.1330 + reachedFollowingSibling = true; 1.1331 + } 1.1332 + } 1.1333 + } 1.1334 +} 1.1335 + 1.1336 +void 1.1337 +RestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint) 1.1338 +{ 1.1339 + NS_ASSERTION(!(aExtraHint & nsChangeHint_ReconstructFrame), 1.1340 + "Should not reconstruct the root of the frame tree. " 1.1341 + "Use ReconstructDocElementHierarchy instead."); 1.1342 + 1.1343 + mRebuildAllStyleData = false; 1.1344 + NS_UpdateHint(aExtraHint, mRebuildAllExtraHint); 1.1345 + mRebuildAllExtraHint = nsChangeHint(0); 1.1346 + 1.1347 + nsIPresShell* presShell = mPresContext->GetPresShell(); 1.1348 + if (!presShell || !presShell->GetRootFrame()) 1.1349 + return; 1.1350 + 1.1351 + // Make sure that the viewmanager will outlive the presshell 1.1352 + nsRefPtr<nsViewManager> vm = presShell->GetViewManager(); 1.1353 + 1.1354 + // Processing the style changes could cause a flush that propagates to 1.1355 + // the parent frame and thus destroys the pres shell. 1.1356 + nsCOMPtr<nsIPresShell> kungFuDeathGrip(presShell); 1.1357 + 1.1358 + // We may reconstruct frames below and hence process anything that is in the 1.1359 + // tree. We don't want to get notified to process those items again after. 1.1360 + presShell->GetDocument()->FlushPendingNotifications(Flush_ContentAndNotify); 1.1361 + 1.1362 + nsAutoScriptBlocker scriptBlocker; 1.1363 + 1.1364 + mPresContext->SetProcessingRestyles(true); 1.1365 + 1.1366 + DoRebuildAllStyleData(mPendingRestyles, aExtraHint); 1.1367 + 1.1368 + mPresContext->SetProcessingRestyles(false); 1.1369 + 1.1370 + // Make sure that we process any pending animation restyles from the 1.1371 + // above style change. Note that we can *almost* implement the above 1.1372 + // by just posting a style change -- except we really need to restyle 1.1373 + // the root frame rather than the root element's primary frame. 1.1374 + ProcessPendingRestyles(); 1.1375 +} 1.1376 + 1.1377 +void 1.1378 +RestyleManager::DoRebuildAllStyleData(RestyleTracker& aRestyleTracker, 1.1379 + nsChangeHint aExtraHint) 1.1380 +{ 1.1381 + // Tell the style set to get the old rule tree out of the way 1.1382 + // so we can recalculate while maintaining rule tree immutability 1.1383 + nsresult rv = mPresContext->StyleSet()->BeginReconstruct(); 1.1384 + if (NS_FAILED(rv)) { 1.1385 + return; 1.1386 + } 1.1387 + 1.1388 + // Recalculate all of the style contexts for the document 1.1389 + // Note that we can ignore the return value of ComputeStyleChangeFor 1.1390 + // because we never need to reframe the root frame 1.1391 + // XXX This could be made faster by not rerunning rule matching 1.1392 + // (but note that nsPresShell::SetPreferenceStyleRules currently depends 1.1393 + // on us re-running rule matching here 1.1394 + nsStyleChangeList changeList; 1.1395 + // XXX Does it matter that we're passing aExtraHint to the real root 1.1396 + // frame and not the root node's primary frame? 1.1397 + // Note: The restyle tracker we pass in here doesn't matter. 1.1398 + ComputeStyleChangeFor(mPresContext->PresShell()->GetRootFrame(), 1.1399 + &changeList, aExtraHint, 1.1400 + aRestyleTracker, true); 1.1401 + // Process the required changes 1.1402 + ProcessRestyledFrames(changeList); 1.1403 + FlushOverflowChangedTracker(); 1.1404 + 1.1405 + // Tell the style set it's safe to destroy the old rule tree. We 1.1406 + // must do this after the ProcessRestyledFrames call in case the 1.1407 + // change list has frame reconstructs in it (since frames to be 1.1408 + // reconstructed will still have their old style context pointers 1.1409 + // until they are destroyed). 1.1410 + mPresContext->StyleSet()->EndReconstruct(); 1.1411 +} 1.1412 + 1.1413 +void 1.1414 +RestyleManager::ProcessPendingRestyles() 1.1415 +{ 1.1416 + NS_PRECONDITION(mPresContext->Document(), "No document? Pshaw!"); 1.1417 + NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(), 1.1418 + "Missing a script blocker!"); 1.1419 + 1.1420 + // First do any queued-up frame creation. (We should really 1.1421 + // merge this into the rest of the process, though; see bug 827239.) 1.1422 + mPresContext->FrameConstructor()->CreateNeededFrames(); 1.1423 + 1.1424 + // Process non-animation restyles... 1.1425 + NS_ABORT_IF_FALSE(!mPresContext->IsProcessingRestyles(), 1.1426 + "Nesting calls to ProcessPendingRestyles?"); 1.1427 + mPresContext->SetProcessingRestyles(true); 1.1428 + 1.1429 + // Before we process any restyles, we need to ensure that style 1.1430 + // resulting from any throttled animations (animations that we're 1.1431 + // running entirely on the compositor thread) is up-to-date, so that 1.1432 + // if any style changes we cause trigger transitions, we have the 1.1433 + // correct old style for starting the transition. 1.1434 + if (nsLayoutUtils::AreAsyncAnimationsEnabled() && 1.1435 + mPendingRestyles.Count() > 0) { 1.1436 + ++mAnimationGeneration; 1.1437 + mPresContext->TransitionManager()->UpdateAllThrottledStyles(); 1.1438 + } 1.1439 + 1.1440 + mPendingRestyles.ProcessRestyles(); 1.1441 + 1.1442 +#ifdef DEBUG 1.1443 + uint32_t oldPendingRestyleCount = mPendingRestyles.Count(); 1.1444 +#endif 1.1445 + 1.1446 + // ...and then process animation restyles. This needs to happen 1.1447 + // second because we need to start animations that resulted from the 1.1448 + // first set of restyles (e.g., CSS transitions with negative 1.1449 + // transition-delay), and because we need to immediately 1.1450 + // restyle-with-animation any just-restyled elements that are 1.1451 + // mid-transition (since processing the non-animation restyle ignores 1.1452 + // the running transition so it can check for a new change on the same 1.1453 + // property, and then posts an immediate animation style change). 1.1454 + mPresContext->SetProcessingAnimationStyleChange(true); 1.1455 + mPendingAnimationRestyles.ProcessRestyles(); 1.1456 + mPresContext->SetProcessingAnimationStyleChange(false); 1.1457 + 1.1458 + mPresContext->SetProcessingRestyles(false); 1.1459 + NS_POSTCONDITION(mPendingRestyles.Count() == oldPendingRestyleCount, 1.1460 + "We should not have posted new non-animation restyles while " 1.1461 + "processing animation restyles"); 1.1462 + 1.1463 + if (mRebuildAllStyleData) { 1.1464 + // We probably wasted a lot of work up above, but this seems safest 1.1465 + // and it should be rarely used. 1.1466 + // This might add us as a refresh observer again; that's ok. 1.1467 + RebuildAllStyleData(nsChangeHint(0)); 1.1468 + } 1.1469 +} 1.1470 + 1.1471 +void 1.1472 +RestyleManager::BeginProcessingRestyles() 1.1473 +{ 1.1474 + // Make sure to not rebuild quote or counter lists while we're 1.1475 + // processing restyles 1.1476 + mPresContext->FrameConstructor()->BeginUpdate(); 1.1477 + 1.1478 + mInStyleRefresh = true; 1.1479 +} 1.1480 + 1.1481 +void 1.1482 +RestyleManager::EndProcessingRestyles() 1.1483 +{ 1.1484 + FlushOverflowChangedTracker(); 1.1485 + 1.1486 + // Set mInStyleRefresh to false now, since the EndUpdate call might 1.1487 + // add more restyles. 1.1488 + mInStyleRefresh = false; 1.1489 + 1.1490 + mPresContext->FrameConstructor()->EndUpdate(); 1.1491 + 1.1492 +#ifdef DEBUG 1.1493 + mPresContext->PresShell()->VerifyStyleTree(); 1.1494 +#endif 1.1495 +} 1.1496 + 1.1497 +void 1.1498 +RestyleManager::PostRestyleEventCommon(Element* aElement, 1.1499 + nsRestyleHint aRestyleHint, 1.1500 + nsChangeHint aMinChangeHint, 1.1501 + bool aForAnimation) 1.1502 +{ 1.1503 + if (MOZ_UNLIKELY(mPresContext->PresShell()->IsDestroying())) { 1.1504 + return; 1.1505 + } 1.1506 + 1.1507 + if (aRestyleHint == 0 && !aMinChangeHint) { 1.1508 + // Nothing to do here 1.1509 + return; 1.1510 + } 1.1511 + 1.1512 + RestyleTracker& tracker = 1.1513 + aForAnimation ? mPendingAnimationRestyles : mPendingRestyles; 1.1514 + tracker.AddPendingRestyle(aElement, aRestyleHint, aMinChangeHint); 1.1515 + 1.1516 + PostRestyleEventInternal(false); 1.1517 +} 1.1518 + 1.1519 +void 1.1520 +RestyleManager::PostRestyleEventInternal(bool aForLazyConstruction) 1.1521 +{ 1.1522 + // Make sure we're not in a style refresh; if we are, we still have 1.1523 + // a call to ProcessPendingRestyles coming and there's no need to 1.1524 + // add ourselves as a refresh observer until then. 1.1525 + bool inRefresh = !aForLazyConstruction && mInStyleRefresh; 1.1526 + nsIPresShell* presShell = mPresContext->PresShell(); 1.1527 + if (!mObservingRefreshDriver && !inRefresh) { 1.1528 + mObservingRefreshDriver = mPresContext->RefreshDriver()-> 1.1529 + AddStyleFlushObserver(presShell); 1.1530 + } 1.1531 + 1.1532 + // Unconditionally flag our document as needing a flush. The other 1.1533 + // option here would be a dedicated boolean to track whether we need 1.1534 + // to do so (set here and unset in ProcessPendingRestyles). 1.1535 + presShell->GetDocument()->SetNeedStyleFlush(); 1.1536 +} 1.1537 + 1.1538 +void 1.1539 +RestyleManager::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint) 1.1540 +{ 1.1541 + NS_ASSERTION(!(aExtraHint & nsChangeHint_ReconstructFrame), 1.1542 + "Should not reconstruct the root of the frame tree. " 1.1543 + "Use ReconstructDocElementHierarchy instead."); 1.1544 + 1.1545 + mRebuildAllStyleData = true; 1.1546 + NS_UpdateHint(mRebuildAllExtraHint, aExtraHint); 1.1547 + 1.1548 + // Get a restyle event posted if necessary 1.1549 + PostRestyleEventInternal(false); 1.1550 +} 1.1551 + 1.1552 +#ifdef DEBUG 1.1553 +static void 1.1554 +DumpContext(nsIFrame* aFrame, nsStyleContext* aContext) 1.1555 +{ 1.1556 + if (aFrame) { 1.1557 + fputs("frame: ", stdout); 1.1558 + nsAutoString name; 1.1559 + aFrame->GetFrameName(name); 1.1560 + fputs(NS_LossyConvertUTF16toASCII(name).get(), stdout); 1.1561 + fprintf(stdout, " (%p)", static_cast<void*>(aFrame)); 1.1562 + } 1.1563 + if (aContext) { 1.1564 + fprintf(stdout, " style: %p ", static_cast<void*>(aContext)); 1.1565 + 1.1566 + nsIAtom* pseudoTag = aContext->GetPseudo(); 1.1567 + if (pseudoTag) { 1.1568 + nsAutoString buffer; 1.1569 + pseudoTag->ToString(buffer); 1.1570 + fputs(NS_LossyConvertUTF16toASCII(buffer).get(), stdout); 1.1571 + fputs(" ", stdout); 1.1572 + } 1.1573 + fputs("{}\n", stdout); 1.1574 + } 1.1575 +} 1.1576 + 1.1577 +static void 1.1578 +VerifySameTree(nsStyleContext* aContext1, nsStyleContext* aContext2) 1.1579 +{ 1.1580 + nsStyleContext* top1 = aContext1; 1.1581 + nsStyleContext* top2 = aContext2; 1.1582 + nsStyleContext* parent; 1.1583 + for (;;) { 1.1584 + parent = top1->GetParent(); 1.1585 + if (!parent) 1.1586 + break; 1.1587 + top1 = parent; 1.1588 + } 1.1589 + for (;;) { 1.1590 + parent = top2->GetParent(); 1.1591 + if (!parent) 1.1592 + break; 1.1593 + top2 = parent; 1.1594 + } 1.1595 + NS_ASSERTION(top1 == top2, 1.1596 + "Style contexts are not in the same style context tree"); 1.1597 +} 1.1598 + 1.1599 +static void 1.1600 +VerifyContextParent(nsPresContext* aPresContext, nsIFrame* aFrame, 1.1601 + nsStyleContext* aContext, nsStyleContext* aParentContext) 1.1602 +{ 1.1603 + // get the contexts not provided 1.1604 + if (!aContext) { 1.1605 + aContext = aFrame->StyleContext(); 1.1606 + } 1.1607 + 1.1608 + if (!aParentContext) { 1.1609 + // Get the correct parent context from the frame 1.1610 + // - if the frame is a placeholder, we get the out of flow frame's context 1.1611 + // as the parent context instead of asking the frame 1.1612 + 1.1613 + // get the parent context from the frame (indirectly) 1.1614 + nsIFrame* providerFrame = aFrame->GetParentStyleContextFrame(); 1.1615 + if (providerFrame) 1.1616 + aParentContext = providerFrame->StyleContext(); 1.1617 + // aParentContext could still be null 1.1618 + } 1.1619 + 1.1620 + NS_ASSERTION(aContext, "Failure to get required contexts"); 1.1621 + nsStyleContext* actualParentContext = aContext->GetParent(); 1.1622 + 1.1623 + if (aParentContext) { 1.1624 + if (aParentContext != actualParentContext) { 1.1625 + DumpContext(aFrame, aContext); 1.1626 + if (aContext == aParentContext) { 1.1627 + NS_ERROR("Using parent's style context"); 1.1628 + } 1.1629 + else { 1.1630 + NS_ERROR("Wrong parent style context"); 1.1631 + fputs("Wrong parent style context: ", stdout); 1.1632 + DumpContext(nullptr, actualParentContext); 1.1633 + fputs("should be using: ", stdout); 1.1634 + DumpContext(nullptr, aParentContext); 1.1635 + VerifySameTree(actualParentContext, aParentContext); 1.1636 + fputs("\n", stdout); 1.1637 + } 1.1638 + } 1.1639 + 1.1640 + } 1.1641 + else { 1.1642 + if (actualParentContext) { 1.1643 + NS_ERROR("Have parent context and shouldn't"); 1.1644 + DumpContext(aFrame, aContext); 1.1645 + fputs("Has parent context: ", stdout); 1.1646 + DumpContext(nullptr, actualParentContext); 1.1647 + fputs("Should be null\n\n", stdout); 1.1648 + } 1.1649 + } 1.1650 + 1.1651 + nsStyleContext* childStyleIfVisited = aContext->GetStyleIfVisited(); 1.1652 + // Either childStyleIfVisited has aContext->GetParent()->GetStyleIfVisited() 1.1653 + // as the parent or it has a different rulenode from aContext _and_ has 1.1654 + // aContext->GetParent() as the parent. 1.1655 + if (childStyleIfVisited && 1.1656 + !((childStyleIfVisited->RuleNode() != aContext->RuleNode() && 1.1657 + childStyleIfVisited->GetParent() == aContext->GetParent()) || 1.1658 + childStyleIfVisited->GetParent() == 1.1659 + aContext->GetParent()->GetStyleIfVisited())) { 1.1660 + NS_ERROR("Visited style has wrong parent"); 1.1661 + DumpContext(aFrame, aContext); 1.1662 + fputs("\n", stdout); 1.1663 + } 1.1664 +} 1.1665 + 1.1666 +static void 1.1667 +VerifyStyleTree(nsPresContext* aPresContext, nsIFrame* aFrame, 1.1668 + nsStyleContext* aParentContext) 1.1669 +{ 1.1670 + nsStyleContext* context = aFrame->StyleContext(); 1.1671 + VerifyContextParent(aPresContext, aFrame, context, nullptr); 1.1672 + 1.1673 + nsIFrame::ChildListIterator lists(aFrame); 1.1674 + for (; !lists.IsDone(); lists.Next()) { 1.1675 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.1676 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.1677 + nsIFrame* child = childFrames.get(); 1.1678 + if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) { 1.1679 + // only do frames that are in flow 1.1680 + if (nsGkAtoms::placeholderFrame == child->GetType()) { 1.1681 + // placeholder: first recurse and verify the out of flow frame, 1.1682 + // then verify the placeholder's context 1.1683 + nsIFrame* outOfFlowFrame = 1.1684 + nsPlaceholderFrame::GetRealFrameForPlaceholder(child); 1.1685 + 1.1686 + // recurse to out of flow frame, letting the parent context get resolved 1.1687 + do { 1.1688 + VerifyStyleTree(aPresContext, outOfFlowFrame, nullptr); 1.1689 + } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation())); 1.1690 + 1.1691 + // verify placeholder using the parent frame's context as 1.1692 + // parent context 1.1693 + VerifyContextParent(aPresContext, child, nullptr, nullptr); 1.1694 + } 1.1695 + else { // regular frame 1.1696 + VerifyStyleTree(aPresContext, child, nullptr); 1.1697 + } 1.1698 + } 1.1699 + } 1.1700 + } 1.1701 + 1.1702 + // do additional contexts 1.1703 + int32_t contextIndex = 0; 1.1704 + for (nsStyleContext* extraContext; 1.1705 + (extraContext = aFrame->GetAdditionalStyleContext(contextIndex)); 1.1706 + ++contextIndex) { 1.1707 + VerifyContextParent(aPresContext, aFrame, extraContext, context); 1.1708 + } 1.1709 +} 1.1710 + 1.1711 +void 1.1712 +RestyleManager::DebugVerifyStyleTree(nsIFrame* aFrame) 1.1713 +{ 1.1714 + if (aFrame) { 1.1715 + nsStyleContext* context = aFrame->StyleContext(); 1.1716 + nsStyleContext* parentContext = context->GetParent(); 1.1717 + VerifyStyleTree(mPresContext, aFrame, parentContext); 1.1718 + } 1.1719 +} 1.1720 + 1.1721 +#endif // DEBUG 1.1722 + 1.1723 +// aContent must be the content for the frame in question, which may be 1.1724 +// :before/:after content 1.1725 +static void 1.1726 +TryStartingTransition(nsPresContext *aPresContext, nsIContent *aContent, 1.1727 + nsStyleContext *aOldStyleContext, 1.1728 + nsRefPtr<nsStyleContext> *aNewStyleContext /* inout */) 1.1729 +{ 1.1730 + if (!aContent || !aContent->IsElement()) { 1.1731 + return; 1.1732 + } 1.1733 + 1.1734 + // Notify the transition manager, and if it starts a transition, 1.1735 + // it will give us back a transition-covering style rule which 1.1736 + // we'll use to get *another* style context. We want to ignore 1.1737 + // any already-running transitions, but cover up any that we're 1.1738 + // currently starting with their start value so we don't start 1.1739 + // them again for descendants that inherit that value. 1.1740 + nsCOMPtr<nsIStyleRule> coverRule = 1.1741 + aPresContext->TransitionManager()->StyleContextChanged( 1.1742 + aContent->AsElement(), aOldStyleContext, *aNewStyleContext); 1.1743 + if (coverRule) { 1.1744 + nsCOMArray<nsIStyleRule> rules; 1.1745 + rules.AppendObject(coverRule); 1.1746 + *aNewStyleContext = aPresContext->StyleSet()-> 1.1747 + ResolveStyleByAddingRules(*aNewStyleContext, rules); 1.1748 + } 1.1749 +} 1.1750 + 1.1751 +static inline dom::Element* 1.1752 +ElementForStyleContext(nsIContent* aParentContent, 1.1753 + nsIFrame* aFrame, 1.1754 + nsCSSPseudoElements::Type aPseudoType) 1.1755 +{ 1.1756 + // We don't expect XUL tree stuff here. 1.1757 + NS_PRECONDITION(aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement || 1.1758 + aPseudoType == nsCSSPseudoElements::ePseudo_AnonBox || 1.1759 + aPseudoType < nsCSSPseudoElements::ePseudo_PseudoElementCount, 1.1760 + "Unexpected pseudo"); 1.1761 + // XXX see the comments about the various element confusion in 1.1762 + // ElementRestyler::Restyle. 1.1763 + if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) { 1.1764 + return aFrame->GetContent()->AsElement(); 1.1765 + } 1.1766 + 1.1767 + if (aPseudoType == nsCSSPseudoElements::ePseudo_AnonBox) { 1.1768 + return nullptr; 1.1769 + } 1.1770 + 1.1771 + if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLetter) { 1.1772 + NS_ASSERTION(aFrame->GetType() == nsGkAtoms::letterFrame, 1.1773 + "firstLetter pseudoTag without a nsFirstLetterFrame"); 1.1774 + nsBlockFrame* block = nsBlockFrame::GetNearestAncestorBlock(aFrame); 1.1775 + return block->GetContent()->AsElement(); 1.1776 + } 1.1777 + 1.1778 + if (aPseudoType == nsCSSPseudoElements::ePseudo_mozColorSwatch) { 1.1779 + MOZ_ASSERT(aFrame->GetParent() && 1.1780 + aFrame->GetParent()->GetParent(), 1.1781 + "Color swatch frame should have a parent & grandparent"); 1.1782 + 1.1783 + nsIFrame* grandparentFrame = aFrame->GetParent()->GetParent(); 1.1784 + MOZ_ASSERT(grandparentFrame->GetType() == nsGkAtoms::colorControlFrame, 1.1785 + "Color swatch's grandparent should be nsColorControlFrame"); 1.1786 + 1.1787 + return grandparentFrame->GetContent()->AsElement(); 1.1788 + } 1.1789 + 1.1790 + if (aPseudoType == nsCSSPseudoElements::ePseudo_mozNumberText || 1.1791 + aPseudoType == nsCSSPseudoElements::ePseudo_mozNumberWrapper || 1.1792 + aPseudoType == nsCSSPseudoElements::ePseudo_mozNumberSpinBox || 1.1793 + aPseudoType == nsCSSPseudoElements::ePseudo_mozNumberSpinUp || 1.1794 + aPseudoType == nsCSSPseudoElements::ePseudo_mozNumberSpinDown) { 1.1795 + // Get content for nearest nsNumberControlFrame: 1.1796 + nsIFrame* f = aFrame->GetParent(); 1.1797 + MOZ_ASSERT(f); 1.1798 + while (f->GetType() != nsGkAtoms::numberControlFrame) { 1.1799 + f = f->GetParent(); 1.1800 + MOZ_ASSERT(f); 1.1801 + } 1.1802 + return f->GetContent()->AsElement(); 1.1803 + } 1.1804 + 1.1805 + if (aParentContent) { 1.1806 + return aParentContent->AsElement(); 1.1807 + } 1.1808 + 1.1809 + MOZ_ASSERT(aFrame->GetContent()->GetParent(), 1.1810 + "should not have got here for the root element"); 1.1811 + return aFrame->GetContent()->GetParent()->AsElement(); 1.1812 +} 1.1813 + 1.1814 +/** 1.1815 + * FIXME: Temporary. Should merge with following function. 1.1816 + */ 1.1817 +static nsIFrame* 1.1818 +GetPrevContinuationWithPossiblySameStyle(nsIFrame* aFrame) 1.1819 +{ 1.1820 + // Account for {ib} splits when looking for "prevContinuation". In 1.1821 + // particular, for the first-continuation of a part of an {ib} split 1.1822 + // we want to use the previous ib-split sibling of the previous 1.1823 + // ib-split sibling of aFrame, which should have the same style 1.1824 + // context as aFrame itself. In particular, if aFrame is the first 1.1825 + // continuation of an inline part of a block-in-inline split then its 1.1826 + // previous ib-split sibling is a block, and the previous ib-split 1.1827 + // sibling of _that_ is an inline, just like aFrame. Similarly, if 1.1828 + // aFrame is the first continuation of a block part of an 1.1829 + // block-in-inline split (a block-in-inline wrapper block), then its 1.1830 + // previous ib-split sibling is an inline and the previous ib-split 1.1831 + // sibling of that is either another block-in-inline wrapper block box 1.1832 + // or null. 1.1833 + nsIFrame *prevContinuation = aFrame->GetPrevContinuation(); 1.1834 + if (!prevContinuation && 1.1835 + (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) { 1.1836 + // We're the first continuation, so we can just get the frame 1.1837 + // property directly 1.1838 + prevContinuation = static_cast<nsIFrame*>( 1.1839 + aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling())); 1.1840 + if (prevContinuation) { 1.1841 + prevContinuation = static_cast<nsIFrame*>( 1.1842 + prevContinuation->Properties().Get(nsIFrame::IBSplitPrevSibling())); 1.1843 + } 1.1844 + } 1.1845 + 1.1846 + NS_ASSERTION(!prevContinuation || 1.1847 + prevContinuation->GetContent() == aFrame->GetContent(), 1.1848 + "unexpected content mismatch"); 1.1849 + 1.1850 + return prevContinuation; 1.1851 +} 1.1852 + 1.1853 +/** 1.1854 + * Get the previous continuation or similar ib-split sibling (assuming 1.1855 + * block/inline alternation), conditionally on it having the same style. 1.1856 + * This assumes that we're not between resolving the two (i.e., that 1.1857 + * they're both already resolved. 1.1858 + */ 1.1859 +static nsIFrame* 1.1860 +GetPrevContinuationWithSameStyle(nsIFrame* aFrame) 1.1861 +{ 1.1862 + nsIFrame* prevContinuation = GetPrevContinuationWithPossiblySameStyle(aFrame); 1.1863 + if (!prevContinuation) { 1.1864 + return nullptr; 1.1865 + } 1.1866 + 1.1867 + nsStyleContext* prevStyle = prevContinuation->StyleContext(); 1.1868 + nsStyleContext* selfStyle = aFrame->StyleContext(); 1.1869 + if (prevStyle != selfStyle) { 1.1870 + NS_ASSERTION(prevStyle->GetPseudo() != selfStyle->GetPseudo() || 1.1871 + prevStyle->GetParent() != selfStyle->GetParent(), 1.1872 + "continuations should have the same style context"); 1.1873 + prevContinuation = nullptr; 1.1874 + } 1.1875 + return prevContinuation; 1.1876 +} 1.1877 + 1.1878 +/** 1.1879 + * Get the next continuation or similar ib-split sibling (assuming 1.1880 + * block/inline alternation), conditionally on it having the same style. 1.1881 + * 1.1882 + * Since this is used when deciding to copy the new style context, it 1.1883 + * takes as an argument the old style context to check if the style is 1.1884 + * the same. When it is used in other contexts (i.e., where the next 1.1885 + * continuation would already have the new style context), the current 1.1886 + * style context should be passed. 1.1887 + */ 1.1888 +static nsIFrame* 1.1889 +GetNextContinuationWithSameStyle(nsIFrame* aFrame, 1.1890 + nsStyleContext* aOldStyleContext) 1.1891 +{ 1.1892 + // See GetPrevContinuationWithSameStyle about {ib} splits. 1.1893 + 1.1894 + nsIFrame *nextContinuation = aFrame->GetNextContinuation(); 1.1895 + if (!nextContinuation && 1.1896 + (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) { 1.1897 + // We're the last continuation, so we have to hop back to the first 1.1898 + // before getting the frame property 1.1899 + nextContinuation = static_cast<nsIFrame*>(aFrame->FirstContinuation()-> 1.1900 + Properties().Get(nsIFrame::IBSplitSibling())); 1.1901 + if (nextContinuation) { 1.1902 + nextContinuation = static_cast<nsIFrame*>( 1.1903 + nextContinuation->Properties().Get(nsIFrame::IBSplitSibling())); 1.1904 + } 1.1905 + } 1.1906 + 1.1907 + if (!nextContinuation) { 1.1908 + return nullptr; 1.1909 + } 1.1910 + 1.1911 + NS_ASSERTION(nextContinuation->GetContent() == aFrame->GetContent(), 1.1912 + "unexpected content mismatch"); 1.1913 + 1.1914 + nsStyleContext* nextStyle = nextContinuation->StyleContext(); 1.1915 + if (nextStyle != aOldStyleContext) { 1.1916 + NS_ASSERTION(aOldStyleContext->GetPseudo() != nextStyle->GetPseudo() || 1.1917 + aOldStyleContext->GetParent() != nextStyle->GetParent(), 1.1918 + "continuations should have the same style context"); 1.1919 + nextContinuation = nullptr; 1.1920 + } 1.1921 + return nextContinuation; 1.1922 +} 1.1923 + 1.1924 +nsresult 1.1925 +RestyleManager::ReparentStyleContext(nsIFrame* aFrame) 1.1926 +{ 1.1927 + if (nsGkAtoms::placeholderFrame == aFrame->GetType()) { 1.1928 + // Also reparent the out-of-flow and all its continuations. 1.1929 + nsIFrame* outOfFlow = 1.1930 + nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame); 1.1931 + NS_ASSERTION(outOfFlow, "no out-of-flow frame"); 1.1932 + do { 1.1933 + ReparentStyleContext(outOfFlow); 1.1934 + } while ((outOfFlow = outOfFlow->GetNextContinuation())); 1.1935 + } 1.1936 + 1.1937 + // DO NOT verify the style tree before reparenting. The frame 1.1938 + // tree has already been changed, so this check would just fail. 1.1939 + nsStyleContext* oldContext = aFrame->StyleContext(); 1.1940 + 1.1941 + nsRefPtr<nsStyleContext> newContext; 1.1942 + nsIFrame* providerFrame = aFrame->GetParentStyleContextFrame(); 1.1943 + bool isChild = providerFrame && providerFrame->GetParent() == aFrame; 1.1944 + nsStyleContext* newParentContext = nullptr; 1.1945 + nsIFrame* providerChild = nullptr; 1.1946 + if (isChild) { 1.1947 + ReparentStyleContext(providerFrame); 1.1948 + newParentContext = providerFrame->StyleContext(); 1.1949 + providerChild = providerFrame; 1.1950 + } else if (providerFrame) { 1.1951 + newParentContext = providerFrame->StyleContext(); 1.1952 + } else { 1.1953 + NS_NOTREACHED("Reparenting something that has no usable parent? " 1.1954 + "Shouldn't happen!"); 1.1955 + } 1.1956 + // XXX need to do something here to produce the correct style context for 1.1957 + // an IB split whose first inline part is inside a first-line frame. 1.1958 + // Currently the first IB anonymous block's style context takes the first 1.1959 + // part's style context as parent, which is wrong since first-line style 1.1960 + // should not apply to the anonymous block. 1.1961 + 1.1962 +#ifdef DEBUG 1.1963 + { 1.1964 + // Check that our assumption that continuations of the same 1.1965 + // pseudo-type and with the same style context parent have the 1.1966 + // same style context is valid before the reresolution. (We need 1.1967 + // to check the pseudo-type and style context parent because of 1.1968 + // :first-letter and :first-line, where we create styled and 1.1969 + // unstyled letter/line frames distinguished by pseudo-type, and 1.1970 + // then need to distinguish their descendants based on having 1.1971 + // different parents.) 1.1972 + nsIFrame *nextContinuation = aFrame->GetNextContinuation(); 1.1973 + if (nextContinuation) { 1.1974 + nsStyleContext *nextContinuationContext = 1.1975 + nextContinuation->StyleContext(); 1.1976 + NS_ASSERTION(oldContext == nextContinuationContext || 1.1977 + oldContext->GetPseudo() != 1.1978 + nextContinuationContext->GetPseudo() || 1.1979 + oldContext->GetParent() != 1.1980 + nextContinuationContext->GetParent(), 1.1981 + "continuations should have the same style context"); 1.1982 + } 1.1983 + } 1.1984 +#endif 1.1985 + 1.1986 + nsIFrame *prevContinuation = 1.1987 + GetPrevContinuationWithPossiblySameStyle(aFrame); 1.1988 + nsStyleContext *prevContinuationContext; 1.1989 + bool copyFromContinuation = 1.1990 + prevContinuation && 1.1991 + (prevContinuationContext = prevContinuation->StyleContext()) 1.1992 + ->GetPseudo() == oldContext->GetPseudo() && 1.1993 + prevContinuationContext->GetParent() == newParentContext; 1.1994 + if (copyFromContinuation) { 1.1995 + // Just use the style context from the frame's previous 1.1996 + // continuation (see assertion about aFrame->GetNextContinuation() 1.1997 + // above, which we would have previously hit for aFrame's previous 1.1998 + // continuation). 1.1999 + newContext = prevContinuationContext; 1.2000 + } else { 1.2001 + nsIFrame* parentFrame = aFrame->GetParent(); 1.2002 + Element* element = 1.2003 + ElementForStyleContext(parentFrame ? parentFrame->GetContent() : nullptr, 1.2004 + aFrame, 1.2005 + oldContext->GetPseudoType()); 1.2006 + newContext = mPresContext->StyleSet()-> 1.2007 + ReparentStyleContext(oldContext, newParentContext, element); 1.2008 + } 1.2009 + 1.2010 + if (newContext) { 1.2011 + if (newContext != oldContext) { 1.2012 + // We probably don't want to initiate transitions from 1.2013 + // ReparentStyleContext, since we call it during frame 1.2014 + // construction rather than in response to dynamic changes. 1.2015 + // Also see the comment at the start of 1.2016 + // nsTransitionManager::ConsiderStartingTransition. 1.2017 +#if 0 1.2018 + if (!copyFromContinuation) { 1.2019 + TryStartingTransition(mPresContext, aFrame->GetContent(), 1.2020 + oldContext, &newContext); 1.2021 + } 1.2022 +#endif 1.2023 + 1.2024 + // Make sure to call CalcStyleDifference so that the new context ends 1.2025 + // up resolving all the structs the old context resolved. 1.2026 + if (!copyFromContinuation) { 1.2027 + DebugOnly<nsChangeHint> styleChange = 1.2028 + oldContext->CalcStyleDifference(newContext, nsChangeHint(0)); 1.2029 + // The style change is always 0 because we have the same rulenode and 1.2030 + // CalcStyleDifference optimizes us away. That's OK, though: 1.2031 + // reparenting should never trigger a frame reconstruct, and whenever 1.2032 + // it's happening we already plan to reflow and repaint the frames. 1.2033 + NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame), 1.2034 + "Our frame tree is likely to be bogus!"); 1.2035 + } 1.2036 + 1.2037 + aFrame->SetStyleContext(newContext); 1.2038 + 1.2039 + nsIFrame::ChildListIterator lists(aFrame); 1.2040 + for (; !lists.IsDone(); lists.Next()) { 1.2041 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.2042 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.2043 + nsIFrame* child = childFrames.get(); 1.2044 + // only do frames that are in flow 1.2045 + if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && 1.2046 + child != providerChild) { 1.2047 +#ifdef DEBUG 1.2048 + if (nsGkAtoms::placeholderFrame == child->GetType()) { 1.2049 + nsIFrame* outOfFlowFrame = 1.2050 + nsPlaceholderFrame::GetRealFrameForPlaceholder(child); 1.2051 + NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame"); 1.2052 + 1.2053 + NS_ASSERTION(outOfFlowFrame != providerChild, 1.2054 + "Out of flow provider?"); 1.2055 + } 1.2056 +#endif 1.2057 + ReparentStyleContext(child); 1.2058 + } 1.2059 + } 1.2060 + } 1.2061 + 1.2062 + // If this frame is part of an IB split, then the style context of 1.2063 + // the next part of the split might be a child of our style context. 1.2064 + // Reparent its style context just in case one of our ancestors 1.2065 + // (split or not) hasn't done so already). It's not a problem to 1.2066 + // reparent the same frame twice because the "if (newContext != 1.2067 + // oldContext)" check will prevent us from redoing work. 1.2068 + if ((aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) && 1.2069 + !aFrame->GetPrevContinuation()) { 1.2070 + nsIFrame* sib = static_cast<nsIFrame*> 1.2071 + (aFrame->Properties().Get(nsIFrame::IBSplitSibling())); 1.2072 + if (sib) { 1.2073 + ReparentStyleContext(sib); 1.2074 + } 1.2075 + } 1.2076 + 1.2077 + // do additional contexts 1.2078 + int32_t contextIndex = 0; 1.2079 + for (nsStyleContext* oldExtraContext; 1.2080 + (oldExtraContext = aFrame->GetAdditionalStyleContext(contextIndex)); 1.2081 + ++contextIndex) { 1.2082 + nsRefPtr<nsStyleContext> newExtraContext; 1.2083 + newExtraContext = mPresContext->StyleSet()-> 1.2084 + ReparentStyleContext(oldExtraContext, 1.2085 + newContext, nullptr); 1.2086 + if (newExtraContext) { 1.2087 + if (newExtraContext != oldExtraContext) { 1.2088 + // Make sure to call CalcStyleDifference so that the new 1.2089 + // context ends up resolving all the structs the old context 1.2090 + // resolved. 1.2091 + DebugOnly<nsChangeHint> styleChange = 1.2092 + oldExtraContext->CalcStyleDifference(newExtraContext, 1.2093 + nsChangeHint(0)); 1.2094 + // The style change is always 0 because we have the same 1.2095 + // rulenode and CalcStyleDifference optimizes us away. That's 1.2096 + // OK, though: reparenting should never trigger a frame 1.2097 + // reconstruct, and whenever it's happening we already plan to 1.2098 + // reflow and repaint the frames. 1.2099 + NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame), 1.2100 + "Our frame tree is likely to be bogus!"); 1.2101 + } 1.2102 + 1.2103 + aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext); 1.2104 + } 1.2105 + } 1.2106 +#ifdef DEBUG 1.2107 + VerifyStyleTree(mPresContext, aFrame, newParentContext); 1.2108 +#endif 1.2109 + } 1.2110 + } 1.2111 + 1.2112 + return NS_OK; 1.2113 +} 1.2114 + 1.2115 +ElementRestyler::ElementRestyler(nsPresContext* aPresContext, 1.2116 + nsIFrame* aFrame, 1.2117 + nsStyleChangeList* aChangeList, 1.2118 + nsChangeHint aHintsHandledByAncestors, 1.2119 + RestyleTracker& aRestyleTracker, 1.2120 + TreeMatchContext& aTreeMatchContext, 1.2121 + nsTArray<nsIContent*>& 1.2122 + aVisibleKidsOfHiddenElement) 1.2123 + : mPresContext(aPresContext) 1.2124 + , mFrame(aFrame) 1.2125 + , mParentContent(nullptr) 1.2126 + // XXXldb Why does it make sense to use aParentContent? (See 1.2127 + // comment above assertion at start of ElementRestyler::Restyle.) 1.2128 + , mContent(mFrame->GetContent() ? mFrame->GetContent() : mParentContent) 1.2129 + , mChangeList(aChangeList) 1.2130 + , mHintsHandled(NS_SubtractHint(aHintsHandledByAncestors, 1.2131 + NS_HintsNotHandledForDescendantsIn(aHintsHandledByAncestors))) 1.2132 + , mParentFrameHintsNotHandledForDescendants(nsChangeHint(0)) 1.2133 + , mHintsNotHandledForDescendants(nsChangeHint(0)) 1.2134 + , mRestyleTracker(aRestyleTracker) 1.2135 + , mTreeMatchContext(aTreeMatchContext) 1.2136 + , mResolvedChild(nullptr) 1.2137 +#ifdef ACCESSIBILITY 1.2138 + , mDesiredA11yNotifications(eSendAllNotifications) 1.2139 + , mKidsDesiredA11yNotifications(mDesiredA11yNotifications) 1.2140 + , mOurA11yNotification(eDontNotify) 1.2141 + , mVisibleKidsOfHiddenElement(aVisibleKidsOfHiddenElement) 1.2142 +#endif 1.2143 +{ 1.2144 +} 1.2145 + 1.2146 +ElementRestyler::ElementRestyler(const ElementRestyler& aParentRestyler, 1.2147 + nsIFrame* aFrame, 1.2148 + uint32_t aConstructorFlags) 1.2149 + : mPresContext(aParentRestyler.mPresContext) 1.2150 + , mFrame(aFrame) 1.2151 + , mParentContent(aParentRestyler.mContent) 1.2152 + // XXXldb Why does it make sense to use aParentContent? (See 1.2153 + // comment above assertion at start of ElementRestyler::Restyle.) 1.2154 + , mContent(mFrame->GetContent() ? mFrame->GetContent() : mParentContent) 1.2155 + , mChangeList(aParentRestyler.mChangeList) 1.2156 + , mHintsHandled(NS_SubtractHint(aParentRestyler.mHintsHandled, 1.2157 + NS_HintsNotHandledForDescendantsIn(aParentRestyler.mHintsHandled))) 1.2158 + , mParentFrameHintsNotHandledForDescendants( 1.2159 + aParentRestyler.mHintsNotHandledForDescendants) 1.2160 + , mHintsNotHandledForDescendants(nsChangeHint(0)) 1.2161 + , mRestyleTracker(aParentRestyler.mRestyleTracker) 1.2162 + , mTreeMatchContext(aParentRestyler.mTreeMatchContext) 1.2163 + , mResolvedChild(nullptr) 1.2164 +#ifdef ACCESSIBILITY 1.2165 + , mDesiredA11yNotifications(aParentRestyler.mKidsDesiredA11yNotifications) 1.2166 + , mKidsDesiredA11yNotifications(mDesiredA11yNotifications) 1.2167 + , mOurA11yNotification(eDontNotify) 1.2168 + , mVisibleKidsOfHiddenElement(aParentRestyler.mVisibleKidsOfHiddenElement) 1.2169 +#endif 1.2170 +{ 1.2171 + if (aConstructorFlags & FOR_OUT_OF_FLOW_CHILD) { 1.2172 + // Note that the out-of-flow may not be a geometric descendant of 1.2173 + // the frame where we started the reresolve. Therefore, even if 1.2174 + // mHintsHandled already includes nsChangeHint_AllReflowHints we 1.2175 + // don't want to pass that on to the out-of-flow reresolve, since 1.2176 + // that can lead to the out-of-flow not getting reflowed when it 1.2177 + // should be (eg a reresolve starting at <body> that involves 1.2178 + // reflowing the <body> would miss reflowing fixed-pos nodes that 1.2179 + // also need reflow). In the cases when the out-of-flow _is_ a 1.2180 + // geometric descendant of a frame we already have a reflow hint 1.2181 + // for, reflow coalescing should keep us from doing the work twice. 1.2182 + mHintsHandled = NS_SubtractHint(mHintsHandled, nsChangeHint_AllReflowHints); 1.2183 + } 1.2184 +} 1.2185 + 1.2186 +ElementRestyler::ElementRestyler(ParentContextFromChildFrame, 1.2187 + const ElementRestyler& aParentRestyler, 1.2188 + nsIFrame* aFrame) 1.2189 + : mPresContext(aParentRestyler.mPresContext) 1.2190 + , mFrame(aFrame) 1.2191 + , mParentContent(aParentRestyler.mParentContent) 1.2192 + // XXXldb Why does it make sense to use aParentContent? (See 1.2193 + // comment above assertion at start of ElementRestyler::Restyle.) 1.2194 + , mContent(mFrame->GetContent() ? mFrame->GetContent() : mParentContent) 1.2195 + , mChangeList(aParentRestyler.mChangeList) 1.2196 + , mHintsHandled(NS_SubtractHint(aParentRestyler.mHintsHandled, 1.2197 + NS_HintsNotHandledForDescendantsIn(aParentRestyler.mHintsHandled))) 1.2198 + , mParentFrameHintsNotHandledForDescendants( 1.2199 + // assume the worst 1.2200 + nsChangeHint_Hints_NotHandledForDescendants) 1.2201 + , mHintsNotHandledForDescendants(nsChangeHint(0)) 1.2202 + , mRestyleTracker(aParentRestyler.mRestyleTracker) 1.2203 + , mTreeMatchContext(aParentRestyler.mTreeMatchContext) 1.2204 + , mResolvedChild(nullptr) 1.2205 +#ifdef ACCESSIBILITY 1.2206 + , mDesiredA11yNotifications(aParentRestyler.mDesiredA11yNotifications) 1.2207 + , mKidsDesiredA11yNotifications(mDesiredA11yNotifications) 1.2208 + , mOurA11yNotification(eDontNotify) 1.2209 + , mVisibleKidsOfHiddenElement(aParentRestyler.mVisibleKidsOfHiddenElement) 1.2210 +#endif 1.2211 +{ 1.2212 +} 1.2213 + 1.2214 +void 1.2215 +ElementRestyler::CaptureChange(nsStyleContext* aOldContext, 1.2216 + nsStyleContext* aNewContext, 1.2217 + nsChangeHint aChangeToAssume) 1.2218 +{ 1.2219 + // Check some invariants about replacing one style context with another. 1.2220 + NS_ASSERTION(aOldContext->GetPseudo() == aNewContext->GetPseudo(), 1.2221 + "old and new style contexts should have the same pseudo"); 1.2222 + NS_ASSERTION(aOldContext->GetPseudoType() == aNewContext->GetPseudoType(), 1.2223 + "old and new style contexts should have the same pseudo"); 1.2224 + 1.2225 + nsChangeHint ourChange = aOldContext->CalcStyleDifference(aNewContext, 1.2226 + mParentFrameHintsNotHandledForDescendants); 1.2227 + NS_ASSERTION(!(ourChange & nsChangeHint_AllReflowHints) || 1.2228 + (ourChange & nsChangeHint_NeedReflow), 1.2229 + "Reflow hint bits set without actually asking for a reflow"); 1.2230 + 1.2231 + // nsChangeHint_UpdateEffects is inherited, but it can be set due to changes 1.2232 + // in inherited properties (fill and stroke). Avoid propagating it into 1.2233 + // text nodes. 1.2234 + if ((ourChange & nsChangeHint_UpdateEffects) && 1.2235 + mContent && !mContent->IsElement()) { 1.2236 + ourChange = NS_SubtractHint(ourChange, nsChangeHint_UpdateEffects); 1.2237 + } 1.2238 + 1.2239 + NS_UpdateHint(ourChange, aChangeToAssume); 1.2240 + if (NS_UpdateHint(mHintsHandled, ourChange)) { 1.2241 + if (!(ourChange & nsChangeHint_ReconstructFrame) || mContent) { 1.2242 + mChangeList->AppendChange(mFrame, mContent, ourChange); 1.2243 + } 1.2244 + } 1.2245 + NS_UpdateHint(mHintsNotHandledForDescendants, 1.2246 + NS_HintsNotHandledForDescendantsIn(ourChange)); 1.2247 +} 1.2248 + 1.2249 +/** 1.2250 + * Recompute style for mFrame (which should not have a prev continuation 1.2251 + * with the same style), all of its next continuations with the same 1.2252 + * style, and all ib-split siblings of the same type (either block or 1.2253 + * inline, skipping the intermediates of the other type) and accumulate 1.2254 + * changes into mChangeList given that mHintsHandled is already accumulated 1.2255 + * for an ancestor. 1.2256 + * mParentContent is the content node used to resolve the parent style 1.2257 + * context. This means that, for pseudo-elements, it is the content 1.2258 + * that should be used for selector matching (rather than the fake 1.2259 + * content node attached to the frame). 1.2260 + */ 1.2261 +void 1.2262 +ElementRestyler::Restyle(nsRestyleHint aRestyleHint) 1.2263 +{ 1.2264 + // It would be nice if we could make stronger assertions here; they 1.2265 + // would let us simplify the ?: expressions below setting |content| 1.2266 + // and |pseudoContent| in sensible ways as well as making what 1.2267 + // |content| and |pseudoContent| mean, and their relationship to 1.2268 + // |mFrame->GetContent()|, make more sense. However, we can't, 1.2269 + // because of frame trees like the one in 1.2270 + // https://bugzilla.mozilla.org/show_bug.cgi?id=472353#c14 . Once we 1.2271 + // fix bug 242277 we should be able to make this make more sense. 1.2272 + NS_ASSERTION(mFrame->GetContent() || !mParentContent || 1.2273 + !mParentContent->GetParent(), 1.2274 + "frame must have content (unless at the top of the tree)"); 1.2275 + 1.2276 + NS_ASSERTION(!GetPrevContinuationWithSameStyle(mFrame), 1.2277 + "should not be trying to restyle this frame separately"); 1.2278 + 1.2279 + if (mContent && mContent->IsElement()) { 1.2280 + mContent->OwnerDoc()->FlushPendingLinkUpdates(); 1.2281 + RestyleTracker::RestyleData restyleData; 1.2282 + if (mRestyleTracker.GetRestyleData(mContent->AsElement(), &restyleData)) { 1.2283 + if (NS_UpdateHint(mHintsHandled, restyleData.mChangeHint)) { 1.2284 + mChangeList->AppendChange(mFrame, mContent, restyleData.mChangeHint); 1.2285 + } 1.2286 + aRestyleHint = nsRestyleHint(aRestyleHint | restyleData.mRestyleHint); 1.2287 + } 1.2288 + } 1.2289 + 1.2290 + nsRestyleHint childRestyleHint = aRestyleHint; 1.2291 + 1.2292 + if (childRestyleHint == eRestyle_Self) { 1.2293 + childRestyleHint = nsRestyleHint(0); 1.2294 + } 1.2295 + 1.2296 + { 1.2297 + nsRefPtr<nsStyleContext> oldContext = mFrame->StyleContext(); 1.2298 + 1.2299 + // TEMPORARY (until bug 918064): Call RestyleSelf for each 1.2300 + // continuation or block-in-inline sibling. 1.2301 + 1.2302 + for (nsIFrame* f = mFrame; f; 1.2303 + f = GetNextContinuationWithSameStyle(f, oldContext)) { 1.2304 + RestyleSelf(f, aRestyleHint); 1.2305 + } 1.2306 + } 1.2307 + 1.2308 + RestyleChildren(childRestyleHint); 1.2309 +} 1.2310 + 1.2311 +void 1.2312 +ElementRestyler::RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint) 1.2313 +{ 1.2314 + // XXXldb get new context from prev-in-flow if possible, to avoid 1.2315 + // duplication. (Or should we just let |GetContext| handle that?) 1.2316 + // Getting the hint would be nice too, but that's harder. 1.2317 + 1.2318 + // XXXbryner we may be able to avoid some of the refcounting goop here. 1.2319 + // We do need a reference to oldContext for the lifetime of this function, and it's possible 1.2320 + // that the frame has the last reference to it, so AddRef it here. 1.2321 + 1.2322 + nsChangeHint assumeDifferenceHint = NS_STYLE_HINT_NONE; 1.2323 + nsRefPtr<nsStyleContext> oldContext = aSelf->StyleContext(); 1.2324 + nsStyleSet* styleSet = mPresContext->StyleSet(); 1.2325 + 1.2326 +#ifdef ACCESSIBILITY 1.2327 + mWasFrameVisible = nsIPresShell::IsAccessibilityActive() ? 1.2328 + oldContext->StyleVisibility()->IsVisible() : false; 1.2329 +#endif 1.2330 + 1.2331 + nsIAtom* const pseudoTag = oldContext->GetPseudo(); 1.2332 + const nsCSSPseudoElements::Type pseudoType = oldContext->GetPseudoType(); 1.2333 + 1.2334 + nsStyleContext* parentContext; 1.2335 + // Get the frame providing the parent style context. If it is a 1.2336 + // child, then resolve the provider first. 1.2337 + nsIFrame* providerFrame = aSelf->GetParentStyleContextFrame(); 1.2338 + bool isChild = providerFrame && providerFrame->GetParent() == aSelf; 1.2339 + if (!isChild) { 1.2340 + if (providerFrame) 1.2341 + parentContext = providerFrame->StyleContext(); 1.2342 + else 1.2343 + parentContext = nullptr; 1.2344 + } 1.2345 + else { 1.2346 + MOZ_ASSERT(providerFrame->GetContent() == aSelf->GetContent(), 1.2347 + "Postcondition for GetParentStyleContextFrame() violated. " 1.2348 + "That means we need to add the current element to the " 1.2349 + "ancestor filter."); 1.2350 + 1.2351 + // resolve the provider here (before aSelf below). 1.2352 + 1.2353 + // assumeDifferenceHint forces the parent's change to be also 1.2354 + // applied to this frame, no matter what 1.2355 + // nsStyleContext::CalcStyleDifference says. CalcStyleDifference 1.2356 + // can't be trusted because it assumes any changes to the parent 1.2357 + // style context provider will be automatically propagated to 1.2358 + // the frame(s) with child style contexts. 1.2359 + 1.2360 + ElementRestyler providerRestyler(PARENT_CONTEXT_FROM_CHILD_FRAME, 1.2361 + *this, providerFrame); 1.2362 + providerRestyler.Restyle(aRestyleHint); 1.2363 + assumeDifferenceHint = providerRestyler.HintsHandledForFrame(); 1.2364 + 1.2365 + // The provider's new context becomes the parent context of 1.2366 + // aSelf's context. 1.2367 + parentContext = providerFrame->StyleContext(); 1.2368 + // Set |mResolvedChild| so we don't bother resolving the 1.2369 + // provider again. 1.2370 + mResolvedChild = providerFrame; 1.2371 + } 1.2372 + 1.2373 + if (providerFrame != aSelf->GetParent()) { 1.2374 + // We don't actually know what the parent style context's 1.2375 + // non-inherited hints were, so assume the worst. 1.2376 + mParentFrameHintsNotHandledForDescendants = 1.2377 + nsChangeHint_Hints_NotHandledForDescendants; 1.2378 + } 1.2379 + 1.2380 + // do primary context 1.2381 + nsRefPtr<nsStyleContext> newContext; 1.2382 + nsIFrame *prevContinuation = 1.2383 + GetPrevContinuationWithPossiblySameStyle(aSelf); 1.2384 + nsStyleContext *prevContinuationContext; 1.2385 + bool copyFromContinuation = 1.2386 + prevContinuation && 1.2387 + (prevContinuationContext = prevContinuation->StyleContext()) 1.2388 + ->GetPseudo() == oldContext->GetPseudo() && 1.2389 + prevContinuationContext->GetParent() == parentContext; 1.2390 + if (copyFromContinuation) { 1.2391 + // Just use the style context from the frame's previous 1.2392 + // continuation. 1.2393 + newContext = prevContinuationContext; 1.2394 + } 1.2395 + else if (pseudoTag == nsCSSAnonBoxes::mozNonElement) { 1.2396 + NS_ASSERTION(aSelf->GetContent(), 1.2397 + "non pseudo-element frame without content node"); 1.2398 + newContext = styleSet->ResolveStyleForNonElement(parentContext); 1.2399 + } 1.2400 + else if (!aRestyleHint && !prevContinuation) { 1.2401 + // Unfortunately, if prevContinuation is non-null then we may have 1.2402 + // already stolen the restyle tracker entry for this element while 1.2403 + // processing prevContinuation. So we don't know whether aRestyleHint 1.2404 + // should really be 0 here or whether it should be eRestyle_Self. Be 1.2405 + // pessimistic and force an actual reresolve in that situation. The good 1.2406 + // news is that in the common case when prevContinuation is non-null we 1.2407 + // just used prevContinuationContext anyway and aren't reaching this code 1.2408 + // to start with. 1.2409 + newContext = 1.2410 + styleSet->ReparentStyleContext(oldContext, parentContext, 1.2411 + ElementForStyleContext(mParentContent, 1.2412 + aSelf, pseudoType)); 1.2413 + } else if (pseudoType == nsCSSPseudoElements::ePseudo_AnonBox) { 1.2414 + newContext = styleSet->ResolveAnonymousBoxStyle(pseudoTag, 1.2415 + parentContext); 1.2416 + } 1.2417 + else { 1.2418 + Element* element = ElementForStyleContext(mParentContent, aSelf, pseudoType); 1.2419 + if (pseudoTag) { 1.2420 + if (pseudoTag == nsCSSPseudoElements::before || 1.2421 + pseudoTag == nsCSSPseudoElements::after) { 1.2422 + // XXX what other pseudos do we need to treat like this? 1.2423 + newContext = styleSet->ProbePseudoElementStyle(element, 1.2424 + pseudoType, 1.2425 + parentContext, 1.2426 + mTreeMatchContext); 1.2427 + if (!newContext) { 1.2428 + // This pseudo should no longer exist; gotta reframe 1.2429 + NS_UpdateHint(mHintsHandled, nsChangeHint_ReconstructFrame); 1.2430 + mChangeList->AppendChange(aSelf, element, 1.2431 + nsChangeHint_ReconstructFrame); 1.2432 + // We're reframing anyway; just keep the same context 1.2433 + newContext = oldContext; 1.2434 + } 1.2435 + } else { 1.2436 + // Don't expect XUL tree stuff here, since it needs a comparator and 1.2437 + // all. 1.2438 + NS_ASSERTION(pseudoType < 1.2439 + nsCSSPseudoElements::ePseudo_PseudoElementCount, 1.2440 + "Unexpected pseudo type"); 1.2441 + Element* pseudoElement = 1.2442 + nsCSSPseudoElements::PseudoElementSupportsStyleAttribute(pseudoType) || 1.2443 + nsCSSPseudoElements::PseudoElementSupportsUserActionState(pseudoType) ? 1.2444 + aSelf->GetContent()->AsElement() : nullptr; 1.2445 + MOZ_ASSERT(element != pseudoElement); 1.2446 + newContext = styleSet->ResolvePseudoElementStyle(element, 1.2447 + pseudoType, 1.2448 + parentContext, 1.2449 + pseudoElement); 1.2450 + } 1.2451 + } 1.2452 + else { 1.2453 + NS_ASSERTION(aSelf->GetContent(), 1.2454 + "non pseudo-element frame without content node"); 1.2455 + // Skip flex-item style fixup for anonymous subtrees: 1.2456 + TreeMatchContext::AutoFlexItemStyleFixupSkipper 1.2457 + flexFixupSkipper(mTreeMatchContext, 1.2458 + element->IsRootOfNativeAnonymousSubtree()); 1.2459 + newContext = styleSet->ResolveStyleFor(element, parentContext, 1.2460 + mTreeMatchContext); 1.2461 + } 1.2462 + } 1.2463 + 1.2464 + MOZ_ASSERT(newContext); 1.2465 + 1.2466 + if (!parentContext) { 1.2467 + if (oldContext->RuleNode() == newContext->RuleNode() && 1.2468 + oldContext->IsLinkContext() == newContext->IsLinkContext() && 1.2469 + oldContext->RelevantLinkVisited() == 1.2470 + newContext->RelevantLinkVisited()) { 1.2471 + // We're the root of the style context tree and the new style 1.2472 + // context returned has the same rule node. This means that 1.2473 + // we can use FindChildWithRules to keep a lot of the old 1.2474 + // style contexts around. However, we need to start from the 1.2475 + // same root. 1.2476 + newContext = oldContext; 1.2477 + } 1.2478 + } 1.2479 + 1.2480 + if (newContext != oldContext) { 1.2481 + if (!copyFromContinuation) { 1.2482 + TryStartingTransition(mPresContext, aSelf->GetContent(), 1.2483 + oldContext, &newContext); 1.2484 + 1.2485 + CaptureChange(oldContext, newContext, assumeDifferenceHint); 1.2486 + } 1.2487 + 1.2488 + if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) { 1.2489 + // If the frame gets regenerated, let it keep its old context, 1.2490 + // which is important to maintain various invariants about 1.2491 + // frame types matching their style contexts. 1.2492 + // Note that this check even makes sense if we didn't call 1.2493 + // CaptureChange because of copyFromContinuation being true, 1.2494 + // since we'll have copied the existing context from the 1.2495 + // previous continuation, so newContext == oldContext. 1.2496 + aSelf->SetStyleContext(newContext); 1.2497 + } 1.2498 + } 1.2499 + oldContext = nullptr; 1.2500 + 1.2501 + // do additional contexts 1.2502 + // XXXbz might be able to avoid selector matching here in some 1.2503 + // cases; won't worry about it for now. 1.2504 + int32_t contextIndex = 0; 1.2505 + for (nsStyleContext* oldExtraContext; 1.2506 + (oldExtraContext = aSelf->GetAdditionalStyleContext(contextIndex)); 1.2507 + ++contextIndex) { 1.2508 + nsRefPtr<nsStyleContext> newExtraContext; 1.2509 + nsIAtom* const extraPseudoTag = oldExtraContext->GetPseudo(); 1.2510 + const nsCSSPseudoElements::Type extraPseudoType = 1.2511 + oldExtraContext->GetPseudoType(); 1.2512 + NS_ASSERTION(extraPseudoTag && 1.2513 + extraPseudoTag != nsCSSAnonBoxes::mozNonElement, 1.2514 + "extra style context is not pseudo element"); 1.2515 + if (extraPseudoType == nsCSSPseudoElements::ePseudo_AnonBox) { 1.2516 + newExtraContext = styleSet->ResolveAnonymousBoxStyle(extraPseudoTag, 1.2517 + newContext); 1.2518 + } 1.2519 + else { 1.2520 + // Don't expect XUL tree stuff here, since it needs a comparator and 1.2521 + // all. 1.2522 + NS_ASSERTION(extraPseudoType < 1.2523 + nsCSSPseudoElements::ePseudo_PseudoElementCount, 1.2524 + "Unexpected type"); 1.2525 + newExtraContext = styleSet->ResolvePseudoElementStyle(mContent->AsElement(), 1.2526 + extraPseudoType, 1.2527 + newContext, 1.2528 + nullptr); 1.2529 + } 1.2530 + 1.2531 + MOZ_ASSERT(newExtraContext); 1.2532 + 1.2533 + if (oldExtraContext != newExtraContext) { 1.2534 + CaptureChange(oldExtraContext, newExtraContext, assumeDifferenceHint); 1.2535 + if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) { 1.2536 + aSelf->SetAdditionalStyleContext(contextIndex, newExtraContext); 1.2537 + } 1.2538 + } 1.2539 + } 1.2540 +} 1.2541 + 1.2542 +void 1.2543 +ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint) 1.2544 +{ 1.2545 + RestyleUndisplayedChildren(aChildRestyleHint); 1.2546 + 1.2547 + // Check whether we might need to create a new ::before frame. 1.2548 + // There's no need to do this if we're planning to reframe already 1.2549 + // or if we're not forcing restyles on kids. 1.2550 + // It's also important to check mHintsHandled since we use 1.2551 + // mFrame->StyleContext(), which is out of date if mHintsHandled has a 1.2552 + // ReconstructFrame hint. Using an out of date style context could 1.2553 + // trigger assertions about mismatched rule trees. 1.2554 + if (!(mHintsHandled & nsChangeHint_ReconstructFrame) && 1.2555 + aChildRestyleHint) { 1.2556 + RestyleBeforePseudo(); 1.2557 + } 1.2558 + 1.2559 + // There is no need to waste time crawling into a frame's children 1.2560 + // on a frame change. The act of reconstructing frames will force 1.2561 + // new style contexts to be resolved on all of this frame's 1.2562 + // descendants anyway, so we want to avoid wasting time processing 1.2563 + // style contexts that we're just going to throw away anyway. - dwh 1.2564 + // It's also important to check mHintsHandled since reresolving the 1.2565 + // kids would use mFrame->StyleContext(), which is out of date if 1.2566 + // mHintsHandled has a ReconstructFrame hint; doing this could trigger 1.2567 + // assertions about mismatched rule trees. 1.2568 + nsIFrame *lastContinuation; 1.2569 + if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) { 1.2570 + InitializeAccessibilityNotifications(); 1.2571 + 1.2572 + for (nsIFrame* f = mFrame; f; 1.2573 + f = GetNextContinuationWithSameStyle(f, f->StyleContext())) { 1.2574 + lastContinuation = f; 1.2575 + RestyleContentChildren(f, aChildRestyleHint); 1.2576 + } 1.2577 + 1.2578 + SendAccessibilityNotifications(); 1.2579 + } 1.2580 + 1.2581 + // Check whether we might need to create a new ::after frame. 1.2582 + // See comments above regarding :before. 1.2583 + if (!(mHintsHandled & nsChangeHint_ReconstructFrame) && 1.2584 + aChildRestyleHint) { 1.2585 + RestyleAfterPseudo(lastContinuation); 1.2586 + } 1.2587 +} 1.2588 + 1.2589 +void 1.2590 +ElementRestyler::RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint) 1.2591 +{ 1.2592 + // When the root element is display:none, we still construct *some* 1.2593 + // frames that have the root element as their mContent, down to the 1.2594 + // DocElementContainingBlock. 1.2595 + bool checkUndisplayed; 1.2596 + nsIContent* undisplayedParent; 1.2597 + nsCSSFrameConstructor* frameConstructor = mPresContext->FrameConstructor(); 1.2598 + if (mFrame->StyleContext()->GetPseudo()) { 1.2599 + checkUndisplayed = mFrame == frameConstructor-> 1.2600 + GetDocElementContainingBlock(); 1.2601 + undisplayedParent = nullptr; 1.2602 + } else { 1.2603 + checkUndisplayed = !!mFrame->GetContent(); 1.2604 + undisplayedParent = mFrame->GetContent(); 1.2605 + } 1.2606 + if (checkUndisplayed && 1.2607 + // No need to do this if we're planning to reframe already. 1.2608 + // It's also important to check mHintsHandled since we use 1.2609 + // mFrame->StyleContext(), which is out of date if mHintsHandled 1.2610 + // has a ReconstructFrame hint. Using an out of date style 1.2611 + // context could trigger assertions about mismatched rule trees. 1.2612 + !(mHintsHandled & nsChangeHint_ReconstructFrame)) { 1.2613 + UndisplayedNode* undisplayed = 1.2614 + frameConstructor->GetAllUndisplayedContentIn(undisplayedParent); 1.2615 + TreeMatchContext::AutoAncestorPusher pusher(mTreeMatchContext); 1.2616 + if (undisplayed) { 1.2617 + pusher.PushAncestorAndStyleScope(undisplayedParent); 1.2618 + } 1.2619 + for (; undisplayed; undisplayed = undisplayed->mNext) { 1.2620 + NS_ASSERTION(undisplayedParent || 1.2621 + undisplayed->mContent == 1.2622 + mPresContext->Document()->GetRootElement(), 1.2623 + "undisplayed node child of null must be root"); 1.2624 + NS_ASSERTION(!undisplayed->mStyle->GetPseudo(), 1.2625 + "Shouldn't have random pseudo style contexts in the " 1.2626 + "undisplayed map"); 1.2627 + 1.2628 + // Get the parent of the undisplayed content and check if it is a XBL 1.2629 + // children element. Push the children element as an ancestor here because it does 1.2630 + // not have a frame and would not otherwise be pushed as an ancestor. 1.2631 + nsIContent* parent = undisplayed->mContent->GetParent(); 1.2632 + TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext); 1.2633 + if (parent && nsContentUtils::IsContentInsertionPoint(parent)) { 1.2634 + insertionPointPusher.PushAncestorAndStyleScope(parent); 1.2635 + } 1.2636 + 1.2637 + nsRestyleHint thisChildHint = aChildRestyleHint; 1.2638 + RestyleTracker::RestyleData undisplayedRestyleData; 1.2639 + if (mRestyleTracker.GetRestyleData(undisplayed->mContent->AsElement(), 1.2640 + &undisplayedRestyleData)) { 1.2641 + thisChildHint = 1.2642 + nsRestyleHint(thisChildHint | undisplayedRestyleData.mRestyleHint); 1.2643 + } 1.2644 + nsRefPtr<nsStyleContext> undisplayedContext; 1.2645 + nsStyleSet* styleSet = mPresContext->StyleSet(); 1.2646 + if (thisChildHint) { 1.2647 + undisplayedContext = 1.2648 + styleSet->ResolveStyleFor(undisplayed->mContent->AsElement(), 1.2649 + mFrame->StyleContext(), 1.2650 + mTreeMatchContext); 1.2651 + } else { 1.2652 + undisplayedContext = 1.2653 + styleSet->ReparentStyleContext(undisplayed->mStyle, 1.2654 + mFrame->StyleContext(), 1.2655 + undisplayed->mContent->AsElement()); 1.2656 + } 1.2657 + const nsStyleDisplay* display = undisplayedContext->StyleDisplay(); 1.2658 + if (display->mDisplay != NS_STYLE_DISPLAY_NONE) { 1.2659 + NS_ASSERTION(undisplayed->mContent, 1.2660 + "Must have undisplayed content"); 1.2661 + mChangeList->AppendChange(nullptr, undisplayed->mContent, 1.2662 + NS_STYLE_HINT_FRAMECHANGE); 1.2663 + // The node should be removed from the undisplayed map when 1.2664 + // we reframe it. 1.2665 + } else { 1.2666 + // update the undisplayed node with the new context 1.2667 + undisplayed->mStyle = undisplayedContext; 1.2668 + } 1.2669 + } 1.2670 + } 1.2671 +} 1.2672 + 1.2673 +void 1.2674 +ElementRestyler::RestyleBeforePseudo() 1.2675 +{ 1.2676 + // Make sure not to do this for pseudo-frames or frames that 1.2677 + // can't have generated content. 1.2678 + if (!mFrame->StyleContext()->GetPseudo() && 1.2679 + ((mFrame->GetStateBits() & NS_FRAME_MAY_HAVE_GENERATED_CONTENT) || 1.2680 + // Our content insertion frame might have gotten flagged 1.2681 + (mFrame->GetContentInsertionFrame()->GetStateBits() & 1.2682 + NS_FRAME_MAY_HAVE_GENERATED_CONTENT))) { 1.2683 + // Check for a new :before pseudo and an existing :before 1.2684 + // frame, but only if the frame is the first continuation. 1.2685 + nsIFrame* prevContinuation = mFrame->GetPrevContinuation(); 1.2686 + if (!prevContinuation) { 1.2687 + // Checking for a :before frame is cheaper than getting the 1.2688 + // :before style context. 1.2689 + if (!nsLayoutUtils::GetBeforeFrame(mFrame) && 1.2690 + nsLayoutUtils::HasPseudoStyle(mFrame->GetContent(), 1.2691 + mFrame->StyleContext(), 1.2692 + nsCSSPseudoElements::ePseudo_before, 1.2693 + mPresContext)) { 1.2694 + // Have to create the new :before frame 1.2695 + NS_UpdateHint(mHintsHandled, nsChangeHint_ReconstructFrame); 1.2696 + mChangeList->AppendChange(mFrame, mContent, 1.2697 + nsChangeHint_ReconstructFrame); 1.2698 + } 1.2699 + } 1.2700 + } 1.2701 +} 1.2702 + 1.2703 +/** 1.2704 + * aFrame is the last continuation or block-in-inline sibling that this 1.2705 + * ElementRestyler is restyling. 1.2706 + */ 1.2707 +void 1.2708 +ElementRestyler::RestyleAfterPseudo(nsIFrame* aFrame) 1.2709 +{ 1.2710 + // Make sure not to do this for pseudo-frames or frames that 1.2711 + // can't have generated content. 1.2712 + if (!aFrame->StyleContext()->GetPseudo() && 1.2713 + ((aFrame->GetStateBits() & NS_FRAME_MAY_HAVE_GENERATED_CONTENT) || 1.2714 + // Our content insertion frame might have gotten flagged 1.2715 + (aFrame->GetContentInsertionFrame()->GetStateBits() & 1.2716 + NS_FRAME_MAY_HAVE_GENERATED_CONTENT))) { 1.2717 + // Check for new :after content, but only if the frame is the 1.2718 + // last continuation. 1.2719 + nsIFrame* nextContinuation = aFrame->GetNextContinuation(); 1.2720 + 1.2721 + if (!nextContinuation) { 1.2722 + // Getting the :after frame is more expensive than getting the pseudo 1.2723 + // context, so get the pseudo context first. 1.2724 + if (nsLayoutUtils::HasPseudoStyle(aFrame->GetContent(), 1.2725 + aFrame->StyleContext(), 1.2726 + nsCSSPseudoElements::ePseudo_after, 1.2727 + mPresContext) && 1.2728 + !nsLayoutUtils::GetAfterFrame(aFrame)) { 1.2729 + // have to create the new :after frame 1.2730 + NS_UpdateHint(mHintsHandled, nsChangeHint_ReconstructFrame); 1.2731 + mChangeList->AppendChange(aFrame, mContent, 1.2732 + nsChangeHint_ReconstructFrame); 1.2733 + } 1.2734 + } 1.2735 + } 1.2736 +} 1.2737 + 1.2738 +void 1.2739 +ElementRestyler::InitializeAccessibilityNotifications() 1.2740 +{ 1.2741 +#ifdef ACCESSIBILITY 1.2742 + // Notify a11y for primary frame only if it's a root frame of visibility 1.2743 + // changes or its parent frame was hidden while it stays visible and 1.2744 + // it is not inside a {ib} split or is the first frame of {ib} split. 1.2745 + if (nsIPresShell::IsAccessibilityActive() && 1.2746 + !mFrame->GetPrevContinuation() && 1.2747 + !mFrame->FrameIsNonFirstInIBSplit()) { 1.2748 + if (mDesiredA11yNotifications == eSendAllNotifications) { 1.2749 + bool isFrameVisible = mFrame->StyleVisibility()->IsVisible(); 1.2750 + if (isFrameVisible != mWasFrameVisible) { 1.2751 + if (isFrameVisible) { 1.2752 + // Notify a11y the element (perhaps with its children) was shown. 1.2753 + // We don't fall into this case if this element gets or stays shown 1.2754 + // while its parent becomes hidden. 1.2755 + mKidsDesiredA11yNotifications = eSkipNotifications; 1.2756 + mOurA11yNotification = eNotifyShown; 1.2757 + } else { 1.2758 + // The element is being hidden; its children may stay visible, or 1.2759 + // become visible after being hidden previously. If we'll find 1.2760 + // visible children then we should notify a11y about that as if 1.2761 + // they were inserted into tree. Notify a11y this element was 1.2762 + // hidden. 1.2763 + mKidsDesiredA11yNotifications = eNotifyIfShown; 1.2764 + mOurA11yNotification = eNotifyHidden; 1.2765 + } 1.2766 + } 1.2767 + } else if (mDesiredA11yNotifications == eNotifyIfShown && 1.2768 + mFrame->StyleVisibility()->IsVisible()) { 1.2769 + // Notify a11y that element stayed visible while its parent was 1.2770 + // hidden. 1.2771 + mVisibleKidsOfHiddenElement.AppendElement(mFrame->GetContent()); 1.2772 + mKidsDesiredA11yNotifications = eSkipNotifications; 1.2773 + } 1.2774 + } 1.2775 +#endif 1.2776 +} 1.2777 + 1.2778 +void 1.2779 +ElementRestyler::RestyleContentChildren(nsIFrame* aParent, 1.2780 + nsRestyleHint aChildRestyleHint) 1.2781 +{ 1.2782 + nsIFrame::ChildListIterator lists(aParent); 1.2783 + TreeMatchContext::AutoAncestorPusher ancestorPusher(mTreeMatchContext); 1.2784 + if (!lists.IsDone()) { 1.2785 + ancestorPusher.PushAncestorAndStyleScope(mContent); 1.2786 + } 1.2787 + for (; !lists.IsDone(); lists.Next()) { 1.2788 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.2789 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.2790 + nsIFrame* child = childFrames.get(); 1.2791 + // Out-of-flows are reached through their placeholders. Continuations 1.2792 + // and block-in-inline splits are reached through those chains. 1.2793 + if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && 1.2794 + !GetPrevContinuationWithSameStyle(child)) { 1.2795 + // Get the parent of the child frame's content and check if it 1.2796 + // is a XBL children element. Push the children element as an 1.2797 + // ancestor here because it does not have a frame and would not 1.2798 + // otherwise be pushed as an ancestor. 1.2799 + 1.2800 + // Check if the frame has a content because |child| may be a 1.2801 + // nsPageFrame that does not have a content. 1.2802 + nsIContent* parent = child->GetContent() ? child->GetContent()->GetParent() : nullptr; 1.2803 + TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext); 1.2804 + if (parent && nsContentUtils::IsContentInsertionPoint(parent)) { 1.2805 + insertionPointPusher.PushAncestorAndStyleScope(parent); 1.2806 + } 1.2807 + 1.2808 + // only do frames that are in flow 1.2809 + if (nsGkAtoms::placeholderFrame == child->GetType()) { // placeholder 1.2810 + // get out of flow frame and recur there 1.2811 + nsIFrame* outOfFlowFrame = 1.2812 + nsPlaceholderFrame::GetRealFrameForPlaceholder(child); 1.2813 + NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame"); 1.2814 + NS_ASSERTION(outOfFlowFrame != mResolvedChild, 1.2815 + "out-of-flow frame not a true descendant"); 1.2816 + 1.2817 + // |nsFrame::GetParentStyleContextFrame| checks being out 1.2818 + // of flow so that this works correctly. 1.2819 + do { 1.2820 + if (GetPrevContinuationWithSameStyle(outOfFlowFrame)) { 1.2821 + // Later continuations are likely restyled as a result of 1.2822 + // the restyling of the previous continuation. 1.2823 + // (Currently that's always true, but it's likely to 1.2824 + // change if we implement overflow:fragments or similar.) 1.2825 + continue; 1.2826 + } 1.2827 + ElementRestyler oofRestyler(*this, outOfFlowFrame, 1.2828 + FOR_OUT_OF_FLOW_CHILD); 1.2829 + oofRestyler.Restyle(aChildRestyleHint); 1.2830 + } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation())); 1.2831 + 1.2832 + // reresolve placeholder's context under the same parent 1.2833 + // as the out-of-flow frame 1.2834 + ElementRestyler phRestyler(*this, child, 0); 1.2835 + phRestyler.Restyle(aChildRestyleHint); 1.2836 + } 1.2837 + else { // regular child frame 1.2838 + if (child != mResolvedChild) { 1.2839 + ElementRestyler childRestyler(*this, child, 0); 1.2840 + childRestyler.Restyle(aChildRestyleHint); 1.2841 + } 1.2842 + } 1.2843 + } 1.2844 + } 1.2845 + } 1.2846 + // XXX need to do overflow frames??? 1.2847 +} 1.2848 + 1.2849 +void 1.2850 +ElementRestyler::SendAccessibilityNotifications() 1.2851 +{ 1.2852 +#ifdef ACCESSIBILITY 1.2853 + // Send notifications about visibility changes. 1.2854 + if (mOurA11yNotification == eNotifyShown) { 1.2855 + nsAccessibilityService* accService = nsIPresShell::AccService(); 1.2856 + if (accService) { 1.2857 + nsIPresShell* presShell = mFrame->PresContext()->GetPresShell(); 1.2858 + nsIContent* content = mFrame->GetContent(); 1.2859 + 1.2860 + accService->ContentRangeInserted(presShell, content->GetParent(), 1.2861 + content, 1.2862 + content->GetNextSibling()); 1.2863 + } 1.2864 + } else if (mOurA11yNotification == eNotifyHidden) { 1.2865 + nsAccessibilityService* accService = nsIPresShell::AccService(); 1.2866 + if (accService) { 1.2867 + nsIPresShell* presShell = mFrame->PresContext()->GetPresShell(); 1.2868 + nsIContent* content = mFrame->GetContent(); 1.2869 + accService->ContentRemoved(presShell, content->GetParent(), content); 1.2870 + 1.2871 + // Process children staying shown. 1.2872 + uint32_t visibleContentCount = mVisibleKidsOfHiddenElement.Length(); 1.2873 + for (uint32_t idx = 0; idx < visibleContentCount; idx++) { 1.2874 + nsIContent* childContent = mVisibleKidsOfHiddenElement[idx]; 1.2875 + accService->ContentRangeInserted(presShell, childContent->GetParent(), 1.2876 + childContent, 1.2877 + childContent->GetNextSibling()); 1.2878 + } 1.2879 + mVisibleKidsOfHiddenElement.Clear(); 1.2880 + } 1.2881 + } 1.2882 +#endif 1.2883 +} 1.2884 + 1.2885 +static inline nsIFrame* 1.2886 +GetNextBlockInInlineSibling(FramePropertyTable* aPropTable, nsIFrame* aFrame) 1.2887 +{ 1.2888 + NS_ASSERTION(!aFrame->GetPrevContinuation(), 1.2889 + "must start with the first continuation"); 1.2890 + // Might we have ib-split siblings? 1.2891 + if (!(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) { 1.2892 + // nothing more to do here 1.2893 + return nullptr; 1.2894 + } 1.2895 + 1.2896 + return static_cast<nsIFrame*> 1.2897 + (aPropTable->Get(aFrame, nsIFrame::IBSplitSibling())); 1.2898 +} 1.2899 + 1.2900 +void 1.2901 +RestyleManager::ComputeStyleChangeFor(nsIFrame* aFrame, 1.2902 + nsStyleChangeList* aChangeList, 1.2903 + nsChangeHint aMinChange, 1.2904 + RestyleTracker& aRestyleTracker, 1.2905 + bool aRestyleDescendants) 1.2906 +{ 1.2907 + PROFILER_LABEL("CSS", "ComputeStyleChangeFor"); 1.2908 + 1.2909 + nsIContent *content = aFrame->GetContent(); 1.2910 + if (aMinChange) { 1.2911 + aChangeList->AppendChange(aFrame, content, aMinChange); 1.2912 + } 1.2913 + 1.2914 + NS_ASSERTION(!aFrame->GetPrevContinuation(), 1.2915 + "must start with the first continuation"); 1.2916 + 1.2917 + // We want to start with this frame and walk all its next-in-flows, 1.2918 + // as well as all its ib-split siblings and their next-in-flows, 1.2919 + // reresolving style on all the frames we encounter in this walk that 1.2920 + // we didn't reach already. In the normal case, this will mean only 1.2921 + // restyling the first two block-in-inline splits and no 1.2922 + // continuations, and skipping everything else. However, when we have 1.2923 + // a style change targeted at an element inside a context where styles 1.2924 + // vary between continuations (e.g., a style change on an element that 1.2925 + // extends from inside a styled ::first-line to outside of that first 1.2926 + // line), we might restyle more than that. 1.2927 + 1.2928 + FramePropertyTable* propTable = mPresContext->PropertyTable(); 1.2929 + 1.2930 + TreeMatchContext treeMatchContext(true, 1.2931 + nsRuleWalker::eRelevantLinkUnvisited, 1.2932 + mPresContext->Document()); 1.2933 + nsIContent *parent = content ? content->GetParent() : nullptr; 1.2934 + Element *parentElement = 1.2935 + parent && parent->IsElement() ? parent->AsElement() : nullptr; 1.2936 + treeMatchContext.InitAncestors(parentElement); 1.2937 + nsTArray<nsIContent*> visibleKidsOfHiddenElement; 1.2938 + for (nsIFrame* ibSibling = aFrame; ibSibling; 1.2939 + ibSibling = GetNextBlockInInlineSibling(propTable, ibSibling)) { 1.2940 + // Outer loop over ib-split siblings 1.2941 + for (nsIFrame* cont = ibSibling; cont; cont = cont->GetNextContinuation()) { 1.2942 + if (GetPrevContinuationWithSameStyle(cont)) { 1.2943 + // We already handled this element when dealing with its earlier 1.2944 + // continuation. 1.2945 + continue; 1.2946 + } 1.2947 + 1.2948 + // Inner loop over next-in-flows of the current frame 1.2949 + ElementRestyler restyler(mPresContext, cont, aChangeList, 1.2950 + aMinChange, aRestyleTracker, 1.2951 + treeMatchContext, 1.2952 + visibleKidsOfHiddenElement); 1.2953 + 1.2954 + restyler.Restyle(aRestyleDescendants ? eRestyle_Subtree : eRestyle_Self); 1.2955 + 1.2956 + if (restyler.HintsHandledForFrame() & nsChangeHint_ReconstructFrame) { 1.2957 + // If it's going to cause a framechange, then don't bother 1.2958 + // with the continuations or ib-split siblings since they'll be 1.2959 + // clobbered by the frame reconstruct anyway. 1.2960 + NS_ASSERTION(!cont->GetPrevContinuation(), 1.2961 + "continuing frame had more severe impact than first-in-flow"); 1.2962 + return; 1.2963 + } 1.2964 + } 1.2965 + } 1.2966 +} 1.2967 + 1.2968 +} // namespace mozilla