Bug 607537 - SVG SMIL: Support paint servers an animation values; r=dholbert,dbaron; a=roc

This commit is contained in:
Brian Birtles 2010-12-29 10:31:14 +09:00
parent a798fe031c
commit 98d103fe8b
5 changed files with 129 additions and 9 deletions

View File

@ -85,9 +85,6 @@ var _fromByTestLists =
paint: [
// The "none" keyword & URI values aren't addiditve, so the animations in
// these testcases are expected to have no effect.
// XXXdholbert Of course, we don't support animation between URI values yet
// (bug 520487), so the testcases that use URIs currently have no effect
// for that reason, too.
new AnimTestcaseFromBy("none", "none", { noEffect: 1 }),
new AnimTestcaseFromBy("url(#gradA)", "url(#gradB)", { noEffect: 1 }),
new AnimTestcaseFromBy("url(#gradA)", "url(#gradB) red", { noEffect: 1 }),

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="300" height="400" fill="lime"/>
</svg>

After

Width:  |  Height:  |  Size: 107 B

View File

@ -0,0 +1,86 @@
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="lime">
<stop offset="0.0" stop-color="lime"/>
</linearGradient>
<linearGradient id="red">
<stop offset="0.0" stop-color="red"/>
</linearGradient>
</defs>
<!-- 1. Set paint server -->
<rect x="0" y="0" width="100" height="100" fill="red">
<set attributeName="fill" to="url(#lime)"/>
</rect>
<!-- 2. Get paint server. We're looking for a code path that will fetch the
base value, fail to replace it, and end up setting the animation
value as the fetched base value.
To-animation requires fetching the base value so we use that, plus
invalid animation values so that we won't replace the base value. -->
<rect x="100" y="0" width="100" height="100" fill="url(#lime)">
<animate attributeName="fill" to="pikapikaglittergold"/>
</rect>
<!-- 3. "Interpolate" paint servers. We should fall back to discrete mode
which should mean that 150s into a 3-valued animation of 400s duration
we're in the middle value since each value will get about 133s each.
-->
<rect x="200" y="0" width="100" height="100" fill="red">
<animate attributeName="fill" values="orange; url(#lime); purple"
begin="-150s" dur="400s"/>
</rect>
<!-- By addition tests: In the following cases we'll go to calculate our
animation function values but since they're by-animation we'll try to do
some addition which should fail since addition with paint servers isn't
supported and hence the animation should not be applied. -->
<!-- 4. Check by-addition behaves (1): by: paint server -->
<rect x="0" y="100" width="100" height="100" fill="lime">
<animate attributeName="fill" from="#f00" by="url(#red)"/>
</rect>
<!-- 5. Check by-addition behaves (2): from: paint server -->
<rect x="100" y="100" width="100" height="100" fill="lime">
<animate attributeName="fill" from="url(#red)" by="#f00"/>
</rect>
<!-- 6. Check by-addition behaves (3): from-by paint server -->
<rect x="200" y="100" width="100" height="100" fill="#0f0">
<animate attributeName="fill" from="url(#red)" by="url(#red)"/>
</rect>
<!-- 7. Check that by-addition without a paint server is ok though.
(Since the animation has indefinite simple duration we'll never get past
the first value which is is lime green.) -->
<rect x="0" y="200" width="100" height="100" fill="red">
<animate attributeName="fill" from="#0f0" by="#00f" dur="indefinite"/>
</rect>
<!-- 8. Sandwich addition test. In the following cases we should be able to
calculate the animation function ok, but we'll fail to add it to the
underlying values (since paint servers can't be added) and just set the
value instead. (SMIL 3 12.6.3 says, "[The additive] attribute is
ignored if the target attribute does not support additive animation.")
-->
<rect x="100" y="200" width="100" height="100" fill="red">
<animate attributeName="fill" values="url(#lime)" additive="sum"/>
</rect>
<!-- 9. Check paced animation fails expectedly. The operation is as with case
3 and we should fall back to discrete mode -->
<rect x="200" y="200" width="100" height="100" fill="red">
<animate attributeName="fill" values="#0f1; url(#lime); #00f"
begin="-150s" dur="400s" calcMode="paced"/>
</rect>
<!-- 10. Fallback color - specified color -->
<rect x="0" y="300" width="100" height="100" fill="red">
<set attributeName="fill" to="url(#nonexistant) lime"/>
</rect>
<!-- 11. Fallback color - currentColor -->
<g color="lime">
<rect x="100" y="300" width="100" height="100" fill="red">
<set attributeName="fill" to="url(#nonexistant) currentColor"/>
</rect>
</g>
<!-- 12. Fallback color - none -->
<rect x="200" y="300" width="100" height="100" fill="lime"/>
<rect x="200" y="300" width="100" height="100" fill="red">
<set attributeName="fill" to="url(#nonexistant) none"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -130,6 +130,9 @@ fails == anim-fillcolor-1.svg anim-standard-ref.svg # bug 436296
== anim-pattern-href-01.svg lime.svg
asserts(9) == anim-use-href-01.svg lime.svg # the asserts here are bug 563481
# animate with some paint server values
== anim-paintserver-1.svg anim-paintserver-1-ref.svg
# animate where the base value is non-interpolatable but will be replaced anyway
== anim-fill-overpaintserver-1.svg lime.svg
== anim-fill-overpaintserver-2.svg lime.svg

View File

@ -245,6 +245,16 @@ SetCalcValue(const nsStyleCoord::Calc* aCalc, nsCSSValue& aValue)
aValue.SetArrayValue(arr, eCSSUnit_Calc);
}
static already_AddRefed<nsStringBuffer>
GetURIAsUtf16StringBuffer(nsIURI* aUri)
{
nsCAutoString utf8String;
nsresult rv = aUri->GetSpec(utf8String);
NS_ENSURE_SUCCESS(rv, nsnull);
return nsCSSValue::BufferFromString(NS_ConvertUTF8toUTF16(utf8String));
}
// CLASS METHODS
// -------------
@ -362,7 +372,8 @@ nsStyleAnimation::ComputeDistance(nsCSSProperty aProperty,
pair2->mXValue.GetUnit());
unit[1] = GetCommonUnit(aProperty, pair1->mYValue.GetUnit(),
pair2->mYValue.GetUnit());
if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null) {
if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null ||
unit[0] == eCSSUnit_URL) {
return PR_FALSE;
}
@ -1457,7 +1468,8 @@ nsStyleAnimation::AddWeighted(nsCSSProperty aProperty,
pair2->mXValue.GetUnit());
unit[1] = GetCommonUnit(aProperty, pair1->mYValue.GetUnit(),
pair2->mYValue.GetUnit());
if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null) {
if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null ||
unit[0] == eCSSUnit_URL) {
return PR_FALSE;
}
@ -2608,16 +2620,35 @@ nsStyleAnimation::ExtractComputedValue(nsCSSProperty aProperty,
case eStyleAnimType_PaintServer: {
const nsStyleSVGPaint &paint = *static_cast<const nsStyleSVGPaint*>(
StyleDataAtOffset(styleStruct, ssOffset));
// FIXME: At some point in the future, we should animate gradients.
if (paint.mType == eStyleSVGPaintType_Color) {
aComputedValue.SetColorValue(paint.mPaint.mColor);
return PR_TRUE;
}
if (paint.mType == eStyleSVGPaintType_None) {
aComputedValue.SetNoneValue();
if (paint.mType == eStyleSVGPaintType_Server) {
if (!paint.mPaint.mPaintServer) {
NS_WARNING("Null paint server");
return PR_FALSE;
}
nsAutoPtr<nsCSSValuePair> pair(new nsCSSValuePair);
nsRefPtr<nsStringBuffer> uriAsStringBuffer =
GetURIAsUtf16StringBuffer(paint.mPaint.mPaintServer);
NS_ENSURE_TRUE(!!uriAsStringBuffer, PR_FALSE);
nsIDocument* doc = aStyleContext->PresContext()->Document();
nsRefPtr<nsCSSValue::URL> url =
new nsCSSValue::URL(paint.mPaint.mPaintServer,
uriAsStringBuffer,
doc->GetDocumentURI(),
doc->NodePrincipal());
pair->mXValue.SetURLValue(url);
pair->mYValue.SetColorValue(paint.mFallbackColor);
aComputedValue.SetAndAdoptCSSValuePairValue(pair.forget(),
eUnit_CSSValuePair);
return PR_TRUE;
}
return PR_FALSE;
NS_ABORT_IF_FALSE(paint.mType == eStyleSVGPaintType_None,
"Unexpected SVG paint type");
aComputedValue.SetNoneValue();
return PR_TRUE;
}
case eStyleAnimType_Shadow: {
const nsCSSShadowArray *shadowArray =