static already_AddRefed<nsStyleContext> CreateStyleContextForAnimationValue(nsCSSPropertyID aProperty, const StyleAnimationValue& aValue, nsStyleContext* aBaseStyleContext) { MOZ_ASSERT(aBaseStyleContext, "CreateStyleContextForAnimationValue needs to be called " "with a valid nsStyleContext"); RefPtr<AnimValuesStyleRule> styleRule = new AnimValuesStyleRule(); styleRule->AddValue(aProperty, aValue); nsCOMArray<nsIStyleRule> rules; rules.AppendObject(styleRule); MOZ_ASSERT(aBaseStyleContext->PresContext()->StyleSet()->IsGecko(), "ServoStyleSet should not use StyleAnimationValue for animations"); nsStyleSet* styleSet = aBaseStyleContext->PresContext()->StyleSet()->AsGecko(); RefPtr<nsStyleContext> styleContext = styleSet->ResolveStyleByAddingRules(aBaseStyleContext, rules); // We need to call StyleData to generate cached data for the style context. // Otherwise CalcStyleDifference returns no meaningful result. styleContext->StyleData(nsCSSProps::kSIDTable[aProperty]); return styleContext.forget(); }
RefPtr< PropertyLine<Vector2> > PropertyLineYamlReader::CreateVector2PropertyLineFromYamlNode( YamlNode * parentNode, const String & propertyName, RefPtr< PropertyLine<Vector2> > defaultPropertyLine /*= 0*/ ) { YamlNode * node = parentNode->Get(propertyName); if (!node)return defaultPropertyLine; if (node->GetType() == YamlNode::TYPE_STRING) { float32 v = node->AsFloat(); return RefPtr< PropertyLine<Vector2> >(new PropertyLineValue<Vector2>(Vector2(v, v))); }else if (node->GetType() == YamlNode::TYPE_ARRAY) { if (node->GetCount() == 2) { Vector2 res(1.0f, 1.0f); res = node->AsPoint(); return RefPtr< PropertyLine<Vector2> >(new PropertyLineValue<Vector2>(res)); } RefPtr< PropertyLineKeyframes<Vector2> > keyframes (new PropertyLineKeyframes<Vector2>()); for (int k = 0; k < node->GetCount() / 2; ++k) { YamlNode * time = node->Get(k * 2); YamlNode * value = node->Get(k * 2 + 1); if (time && value) { if (value->GetType() == YamlNode::TYPE_ARRAY) { keyframes->AddValue(time->AsFloat(), value->AsPoint()); } else { float32 v = value->AsFloat(); keyframes->AddValue(time->AsFloat(), Vector2(v, v)); } } } return keyframes; } return RefPtr< PropertyLine<Vector2> >(); }
RefPtr< PropertyLine<Color> > PropertyLineYamlReader::CreateColorPropertyLineFromYamlNode( YamlNode * parentNode, const String & propertyName, RefPtr< PropertyLine<Color> > defaultPropertyLine) { YamlNode * node = parentNode->Get(propertyName); if (!node)return defaultPropertyLine; if (node->GetType() == YamlNode::TYPE_ARRAY) { bool allString = true; for (int k = 0; k < node->GetCount(); ++k) if (node->Get(k)->GetType() != YamlNode::TYPE_STRING) allString = false; if (allString && node->GetCount() == 4) { return RefPtr< PropertyLine<Color> >(new PropertyLineValue<Color>(ColorFromYamlNode(node))); }else { RefPtr< PropertyLineKeyframes<Color> > keyframes (new PropertyLineKeyframes<Color>()); for (int k = 0; k < node->GetCount() / 2; ++k) { YamlNode * time = node->Get(k * 2); YamlNode * value = node->Get(k * 2 + 1); if (time && value) { if (value->GetType() == YamlNode::TYPE_ARRAY) { keyframes->AddValue(time->AsFloat(), ColorFromYamlNode(value)); } } } return keyframes; } } return RefPtr< PropertyLine<Color> >(); }
void KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule, nsCSSPropertyIDSet& aSetProperties) { ComputedTiming computedTiming = GetComputedTiming(); mProgressOnLastCompose = computedTiming.mProgress; // If the progress is null, we don't have fill data for the current // time so we shouldn't animate. if (computedTiming.mProgress.IsNull()) { return; } for (size_t propIdx = 0, propEnd = mProperties.Length(); propIdx != propEnd; ++propIdx) { const AnimationProperty& prop = mProperties[propIdx]; MOZ_ASSERT(prop.mSegments[0].mFromKey == 0.0, "incorrect first from key"); MOZ_ASSERT(prop.mSegments[prop.mSegments.Length() - 1].mToKey == 1.0, "incorrect last to key"); if (aSetProperties.HasProperty(prop.mProperty)) { // Animations are composed by EffectCompositor by iterating // from the last animation to first. For animations targetting the // same property, the later one wins. So if this property is already set, // we should not override it. continue; } if (!prop.mWinsInCascade) { // This isn't the winning declaration, so don't add it to style. // For transitions, this is important, because it's how we // implement the rule that CSS transitions don't run when a CSS // animation is running on the same property and element. For // animations, this is only skipping things that will otherwise be // overridden. continue; } aSetProperties.AddProperty(prop.mProperty); MOZ_ASSERT(prop.mSegments.Length() > 0, "property should not be in animations if it has no segments"); // FIXME: Maybe cache the current segment? const AnimationPropertySegment *segment = prop.mSegments.Elements(), *segmentEnd = segment + prop.mSegments.Length(); while (segment->mToKey <= computedTiming.mProgress.Value()) { MOZ_ASSERT(segment->mFromKey <= segment->mToKey, "incorrect keys"); if ((segment+1) == segmentEnd) { break; } ++segment; MOZ_ASSERT(segment->mFromKey == (segment-1)->mToKey, "incorrect keys"); } MOZ_ASSERT(segment->mFromKey <= segment->mToKey, "incorrect keys"); MOZ_ASSERT(segment >= prop.mSegments.Elements() && size_t(segment - prop.mSegments.Elements()) < prop.mSegments.Length(), "out of array bounds"); if (!aStyleRule) { // Allocate the style rule now that we know we have animation data. aStyleRule = new AnimValuesStyleRule(); } // Special handling for zero-length segments if (segment->mToKey == segment->mFromKey) { if (computedTiming.mProgress.Value() < 0) { aStyleRule->AddValue(prop.mProperty, segment->mFromValue); } else { aStyleRule->AddValue(prop.mProperty, segment->mToValue); } continue; } double positionInSegment = (computedTiming.mProgress.Value() - segment->mFromKey) / (segment->mToKey - segment->mFromKey); double valuePosition = ComputedTimingFunction::GetPortion(segment->mTimingFunction, positionInSegment, computedTiming.mBeforeFlag); MOZ_ASSERT(IsFinite(valuePosition), "Position value should be finite"); StyleAnimationValue val; if (StyleAnimationValue::Interpolate(prop.mProperty, segment->mFromValue, segment->mToValue, valuePosition, val)) { aStyleRule->AddValue(prop.mProperty, Move(val)); } else if (valuePosition < 0.5) { aStyleRule->AddValue(prop.mProperty, segment->mFromValue); } else { aStyleRule->AddValue(prop.mProperty, segment->mToValue); } } }
void KeyframeEffectReadOnly::ComposeStyle( RefPtr<AnimValuesStyleRule>& aStyleRule, const nsCSSPropertyIDSet& aPropertiesToSkip) { ComputedTiming computedTiming = GetComputedTiming(); mProgressOnLastCompose = computedTiming.mProgress; mCurrentIterationOnLastCompose = computedTiming.mCurrentIteration; // If the progress is null, we don't have fill data for the current // time so we shouldn't animate. if (computedTiming.mProgress.IsNull()) { return; } for (size_t propIdx = 0, propEnd = mProperties.Length(); propIdx != propEnd; ++propIdx) { const AnimationProperty& prop = mProperties[propIdx]; MOZ_ASSERT(prop.mSegments[0].mFromKey == 0.0, "incorrect first from key"); MOZ_ASSERT(prop.mSegments[prop.mSegments.Length() - 1].mToKey == 1.0, "incorrect last to key"); if (aPropertiesToSkip.HasProperty(prop.mProperty)) { continue; } MOZ_ASSERT(prop.mSegments.Length() > 0, "property should not be in animations if it has no segments"); // FIXME: Maybe cache the current segment? const AnimationPropertySegment *segment = prop.mSegments.Elements(), *segmentEnd = segment + prop.mSegments.Length(); while (segment->mToKey <= computedTiming.mProgress.Value()) { MOZ_ASSERT(segment->mFromKey <= segment->mToKey, "incorrect keys"); if ((segment+1) == segmentEnd) { break; } ++segment; MOZ_ASSERT(segment->mFromKey == (segment-1)->mToKey, "incorrect keys"); } MOZ_ASSERT(segment->mFromKey <= segment->mToKey, "incorrect keys"); MOZ_ASSERT(segment >= prop.mSegments.Elements() && size_t(segment - prop.mSegments.Elements()) < prop.mSegments.Length(), "out of array bounds"); if (!aStyleRule) { // Allocate the style rule now that we know we have animation data. aStyleRule = new AnimValuesStyleRule(); } StyleAnimationValue fromValue = segment->mFromValue; StyleAnimationValue toValue = segment->mToValue; // Iteration composition for accumulate if (mEffectOptions.mIterationComposite == IterationCompositeOperation::Accumulate && computedTiming.mCurrentIteration > 0) { const AnimationPropertySegment& lastSegment = prop.mSegments.LastElement(); // FIXME: Bug 1293492: Add a utility function to calculate both of // below StyleAnimationValues. DebugOnly<bool> accumulateResult = StyleAnimationValue::Accumulate(prop.mProperty, fromValue, lastSegment.mToValue, computedTiming.mCurrentIteration); // We can't check the accumulation result in case of filter property. // That's because some filter property can't accumulate, // e.g. 'contrast(2) brightness(2)' onto 'brightness(1) contrast(1)' // because of mismatch of the order. MOZ_ASSERT(accumulateResult || prop.mProperty == eCSSProperty_filter, "could not accumulate value"); accumulateResult = StyleAnimationValue::Accumulate(prop.mProperty, toValue, lastSegment.mToValue, computedTiming.mCurrentIteration); MOZ_ASSERT(accumulateResult || prop.mProperty == eCSSProperty_filter, "could not accumulate value"); } // Special handling for zero-length segments if (segment->mToKey == segment->mFromKey) { if (computedTiming.mProgress.Value() < 0) { aStyleRule->AddValue(prop.mProperty, Move(fromValue)); } else { aStyleRule->AddValue(prop.mProperty, Move(toValue)); } continue; } double positionInSegment = (computedTiming.mProgress.Value() - segment->mFromKey) / (segment->mToKey - segment->mFromKey); double valuePosition = ComputedTimingFunction::GetPortion(segment->mTimingFunction, positionInSegment, computedTiming.mBeforeFlag); MOZ_ASSERT(IsFinite(valuePosition), "Position value should be finite"); StyleAnimationValue val; if (StyleAnimationValue::Interpolate(prop.mProperty, fromValue, toValue, valuePosition, val)) { aStyleRule->AddValue(prop.mProperty, Move(val)); } else if (valuePosition < 0.5) { aStyleRule->AddValue(prop.mProperty, Move(fromValue)); } else { aStyleRule->AddValue(prop.mProperty, Move(toValue)); } } }
RefPtr< PropertyLine<Vector3> > PropertyLineYamlReader::CreateVector3PropertyLineFromYamlNode( YamlNode * parentNode, const String & propertyName, RefPtr< PropertyLine<Vector3> > defaultPropertyLine /*= 0*/ ) { YamlNode * node = parentNode->Get(propertyName); if (!node)return defaultPropertyLine; if (node->GetType() == YamlNode::TYPE_STRING) { if(propertyName == "emissionAngle") // for old emissionAngle compatibility { Vector3 res(0, 0, 0); float32 angle = DegToRad(node->AsFloat()); res.x = cosf(angle); res.y = sinf(angle); return RefPtr< PropertyLine<Vector3> >(new PropertyLineValue<Vector3>(res)); } float32 v = node->AsFloat(); return RefPtr< PropertyLine<Vector3> >(new PropertyLineValue<Vector3>(Vector3(v, v, v))); } else if (node->GetType() == YamlNode::TYPE_ARRAY) { if(node->GetCount() == 2) // for 2D forces compatibility { Vector3 res(node->AsVector2()); res.z = 0.0f; return RefPtr< PropertyLine<Vector3> >(new PropertyLineValue<Vector3>(res)); } if (node->GetCount() == 3 || node->GetCount() == 2) { Vector3 res(0.0f, 0.0f, 0.0f); res = node->AsVector3(); return RefPtr< PropertyLine<Vector3> >(new PropertyLineValue<Vector3>(res)); } RefPtr< PropertyLineKeyframes<Vector3> > keyframes (new PropertyLineKeyframes<Vector3>()); for (int k = 0; k < node->GetCount() / 2; ++k) { YamlNode * time = node->Get(k * 2); YamlNode * value = node->Get(k * 2 + 1); if (time && value) { if (value->GetType() == YamlNode::TYPE_ARRAY) { keyframes->AddValue(time->AsFloat(), value->AsVector3()); } else { Vector3 v = value->AsVector3(); if(propertyName == "emissionAngle") // for old emissionAngle compatibility { float32 angle = DegToRad(value->AsFloat()); v.x = cosf(angle); v.y = sinf(angle); v.z = 0.0f; } keyframes->AddValue(time->AsFloat(), v); } } } return keyframes; } return RefPtr< PropertyLine<Vector3> >(); }