// static void nsSMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID, Element* aTargetElement, const nsAString& aString, nsSMILValue& aValue, bool* aIsContextSensitive) { MOZ_ASSERT(aValue.IsNull(), "Outparam should be null-typed"); nsPresContext* presContext = GetPresContextForElement(aTargetElement); if (!presContext) { NS_WARNING("Not parsing animation value; unable to get PresContext"); return; } nsIDocument* doc = aTargetElement->GetUncomposedDoc(); if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr, doc->NodePrincipal(), doc->GetDocumentURI(), 0, aString, nullptr)) { return; } RefPtr<nsStyleContext> styleContext = nsComputedDOMStyle::GetStyleContext(aTargetElement, nullptr, presContext->PresShell()); if (!styleContext) { return; } if (styleContext->IsServo()) { ServoAnimationValues parsedValues = ValueFromStringHelper(aPropID, aTargetElement, presContext, styleContext, aString); if (aIsContextSensitive) { // FIXME: Bug 1358955 - detect context-sensitive values and set this value // appropriately. *aIsContextSensitive = false; } if (!parsedValues.IsEmpty()) { sSingleton.Init(aValue); aValue.mU.mPtr = new ValueWrapper(aPropID, Move(parsedValues)); } return; } StyleAnimationValue parsedValue; if (ValueFromStringHelper(aPropID, aTargetElement, presContext, styleContext->AsGecko(), aString, parsedValue, aIsContextSensitive)) { sSingleton.Init(aValue); aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue); } }
void nsTransitionManager::StyleContextChanged(dom::Element *aElement, GeckoStyleContext* aOldStyleContext, RefPtr<GeckoStyleContext>* aNewStyleContext /* inout */) { GeckoStyleContext* newStyleContext = *aNewStyleContext; NS_PRECONDITION(aOldStyleContext->GetPseudo() == newStyleContext->GetPseudo(), "pseudo type mismatch"); if (mInAnimationOnlyStyleUpdate) { // If we're doing an animation-only style update, return, since the // purpose of an animation-only style update is to update only the // animation styles so that we don't consider style changes // resulting from changes in the animation time for starting a // transition. return; } if (!mPresContext->IsDynamic()) { // For print or print preview, ignore transitions. return; } if (aOldStyleContext->HasPseudoElementData() != newStyleContext->HasPseudoElementData()) { // If the old style context and new style context differ in terms of // whether they're inside ::first-letter, ::first-line, or similar, // bail. We can't hit this codepath for normal style changes // involving moving frames around the boundaries of these // pseudo-elements since we don't call StyleContextChanged from // ReparentStyleContext. However, we can hit this codepath during // the handling of transitions that start across reframes. // // While there isn't an easy *perfect* way to handle this case, err // on the side of missing some transitions that we ought to have // rather than having bogus transitions that we shouldn't. // // We could consider changing this handling, although it's worth // thinking about whether the code below could do anything weird in // this case. return; } // NOTE: Things in this function (and ConsiderInitiatingTransition) // should never call PeekStyleData because we don't preserve gotten // structs across reframes. // Return sooner (before the startedAny check below) for the most // common case: no transitions specified or running. const nsStyleDisplay* disp = newStyleContext->StyleDisplay(); CSSPseudoElementType pseudoType = newStyleContext->GetPseudoType(); if (pseudoType != CSSPseudoElementType::NotPseudo) { if (pseudoType != CSSPseudoElementType::before && pseudoType != CSSPseudoElementType::after) { return; } NS_ASSERTION((pseudoType == CSSPseudoElementType::before && aElement->IsGeneratedContentContainerForBefore()) || (pseudoType == CSSPseudoElementType::after && aElement->IsGeneratedContentContainerForAfter()), "Unexpected aElement coming through"); // Else the element we want to use from now on is the element the // :before or :after is attached to. aElement = aElement->GetParent()->AsElement(); } CSSTransitionCollection* collection = CSSTransitionCollection::GetAnimationCollection(aElement, pseudoType); if (!collection && disp->mTransitionPropertyCount == 1 && disp->GetTransitionCombinedDuration(0) <= 0.0f) { return; } MOZ_ASSERT(mPresContext->RestyleManager()->IsGecko(), "ServoRestyleManager should not use nsTransitionManager " "for transitions"); if (collection && collection->mCheckGeneration == mPresContext->RestyleManager()->GetAnimationGeneration()) { // When we start a new transition, we immediately post a restyle. // If the animation generation on the collection is current, that // means *this* is that restyle, since we bump the animation // generation on the restyle manager whenever there's a real style // change (i.e., one where mInAnimationOnlyStyleUpdate isn't true, // which causes us to return above). Thus we shouldn't do anything. return; } if (newStyleContext->GetParent() && newStyleContext->GetParent()->HasPseudoElementData()) { // Ignore transitions on things that inherit properties from // pseudo-elements. // FIXME (Bug 522599): Add tests for this. return; } NS_WARNING_ASSERTION( !mPresContext->EffectCompositor()->HasThrottledStyleUpdates(), "throttled animations not up to date"); // Compute what the css-transitions spec calls the "after-change // style", which is the new style without any data from transitions, // but still inheriting from data that contains transitions that are // not stopping or starting right now. RefPtr<GeckoStyleContext> afterChangeStyle; if (collection) { MOZ_ASSERT(mPresContext->StyleSet()->IsGecko(), "ServoStyleSets should not use nsTransitionManager " "for transitions"); nsStyleSet* styleSet = mPresContext->StyleSet()->AsGecko(); afterChangeStyle = styleSet->ResolveStyleByRemovingAnimation(aElement, newStyleContext, eRestyle_CSSTransitions); } else { afterChangeStyle = newStyleContext; } nsAutoAnimationMutationBatch mb(aElement->OwnerDoc()); DebugOnly<bool> startedAny = false; // We don't have to update transitions if display:none, although we will // cancel them after restyling. if (!afterChangeStyle->IsInDisplayNoneSubtree()) { startedAny = DoUpdateTransitions(*disp, aElement, afterChangeStyle->GetPseudoType(), collection, aOldStyleContext->AsGecko(), afterChangeStyle->AsGecko()); } MOZ_ASSERT(!startedAny || collection, "must have element transitions if we started any transitions"); EffectCompositor::CascadeLevel cascadeLevel = EffectCompositor::CascadeLevel::Transitions; if (collection) { collection->UpdateCheckGeneration(mPresContext); mPresContext->EffectCompositor()->MaybeUpdateAnimationRule(aElement, pseudoType, cascadeLevel, newStyleContext); } // We want to replace the new style context with the after-change style. *aNewStyleContext = afterChangeStyle; if (collection) { // Since we have transition styles, we have to undo this replacement. // The check of collection->mCheckGeneration against the restyle // manager's GetAnimationGeneration() will ensure that we don't go // through the rest of this function again when we do. mPresContext->EffectCompositor()->PostRestyleForAnimation(aElement, pseudoType, cascadeLevel); } }