[filter-effects] What to do with errors in filters

I see from the SVG WG agenda for this week [1] that there is a push to get
the Filter Effects spec to Last Call Working Draft.  (Hooray!)

One of the items on that agenda is how to handle errors from <feImage> when
the specified image cannot be accessed; browsers currently differ in
implementations.

A wider issue is what to do with filters as a whole if there is an error.
For example, the use of "BackgroundImage" or "BackgroundAlpha" in SVG
filters in browsers which haven't implemented them.  Or the use of a named
input that doesn't match any of the result names from previous filter
primitives.

Currently, all implementations I've seen cause the filtered graphic to
disappear in these cases.

I'm not sure how it is implemented behind the scenes.  Maybe some
implementations treat the entire filter as in error, so it results in empty
rendering output; the graphic that referenced the filter is only rendered
to the temporary buffer.  Or, maybe implementations treat the invalid input
as a zero-sized graphic input that results in zero-sized graphic output, as
Max Vujovic discovers happens with invalid <feImage> references on Firefox
[2].

Regardless, the effect is difficult to debug and means that authors are
hesitant to use filters to enhance a graphic unless they are confident of
universal support for all its components.  There are very few situations
where the desired fallback behaviour would be to remove the filtered
graphic.

Within the discussion on <feImage>, Paul LeBeau [3] quoted the general SVG
error handling directive, ""The document shall be rendered up to, but not
including, the first element which has an error" [4]. Paul's interpretation
of how this should be applied to filters is that the filter primitive with
an error, and all subsequent primitives within the filter, is ignored, but
the filter as a whole is still applied.

I would add that if the filter as a whole is in error, it should simply be
ignored and the graphic drawn without the filter. But since that isn't what
is happening in implementations, some clearer error handling rules are
needed.

The error handling rules that currently exist (in the current draft spec
[5] or from CSS error handling) are as follows:

1) For CSS shorthand filter functions, an unsupported parameter value would
be a CSS syntax error, and the accepted CSS error handling rule would be to
ignore the entire property declaration.

E.g., if you used

.graphic {
  filter: blur(5px);
  filter: saturate(0.7) drop-shadow(5px 5px 10px 20px navy) contrast(2);
/* four lengths given to drop-shadow function that takes max three lengths
in current spec */
}

the drop-shadow declaration would be invalid, therefore that entire
property value would be invalid, and the blur filter would be applied
instead.

2) A CSS property declaration that references a URL, where that URL is
inaccessible or not of the correct content type, is still a valid property
declaration, so more explicit rules are required.  The current draft
specifically says that invalid URLs should be treated as `filter:none`
(i.e., the entire filter declaration is ignored and no filter applied).

E.g., if you used

.graphic {
  filter: blur(5px);
  filter: saturate(0.7) url(#foo) contrast(2);
/* where #foo either doesn't exist or isn't a filter */
}

then the graphic wouldn't have a filter applied.  In particular, it would
not fall back to the blur.  This is a run-time error, not a compile-time
error, so the CSS cascade has already washed away the previous property
declaration.

When this issue was previously discussed on the list [6], the options that
came up were

   - Don't apply any filter if a URL reference is invalid (current draft
   spec rule).
   - Treat an invalid URL reference as a "pass-through", essentially
   removing it from the list of filter components (so the above CSS would be
   the same as `filter: saturate(0.7)  contrast(2);`).
   - Treat an invalid URL reference as a block, but apply filters earlier
   in the list  (so the above CSS would be the same as
   `filter: saturate(0.7);`).

I can see arguments for all of the above options.  However, there are also
arguments in favour of consistency between CSS filter functions and SVG
composite filters, so you might want to keep that in mind while considering
options for SVG filter error handling.  That said, the situations are
somewhat different: errors from inaccessible URLs are often outside an
author's control, so you want a pretty fallback for the end user; in
contrast, errors within SVG markup can be fixed during debugging and
browser testing by the author, so error handling should support that.

For SVG filters, I would propose the following error handling rules in the
interest of reasonable fallbacks and easy debugging:

   - If a filter element is in error, treat all references to the filter as
   invalid URLs (and follow the error handling rule above, so that no filter
   is applied).
   - If a filter primitive (or primitive component) is in error, ignore
   that primitive and all subsequent primitives, so that the output of the
   filter as a whole is the result of the last non-error primitive.
   - If a valid filter element has no children, or if all its children are
   ignored because of errors, then return the source graphic that would be the
   default input to that filter, clipped to the filter effects region if
   appropriate.  In other words, treat it as if it contained a single,
   no-effect filter primitive with default input, such as
   <feMerge><feMergeNode/></feMerge>.
   (Note: This last rule might cause backwards compatibility issues.  The
   alternative would be to continue to treat empty but error-free filter
   elements as a "delete" filter.)

On the specific question of invalid source images for <feImage>, or invalid
values for `in` or `in2` attributes, there are a couple approaches that
could be reasonable:

   - Treat the filter primitive with invalid input as being in error, and
   apply the rules above.
   - Create a transparent black flood the same size as the primitive
   region, and use that to replace the invalid input or image.
   - Use the transparent black input for <feImage> (or even the browser
   broken-image icon, if you want to give feedback about what went wrong), but
   revert to default values for `in` and `in2`.
   (P.S. The default value for `in2` really should be explicitly stated
   somewhere in the spec; I think most implementations use the same defaults
   as for `in`, but I haven't tested carefully.)

This last behaviour seems to be what is currently recommended in the draft
spec for at least one specific type of invalid `in` or `in2` attributes:

If the value for result appears multiple times within a given filter
> element, then a reference to that result will use the closest preceding
> filter primitive with the given value for attribute result. Forward
> references to results are not allowed, and will be treated as if no result
> was specified.


That's not super-clear, but treating a forward reference "as if no result
was specified" for the input of a primitive, would mean to use the default
input (i.e., the output from the previous primitive or the SourceGraphic).
This is in contrast to the SVG1.1 spec, which says "forward references are
in error" [7] and therefore currently causes the
filter-in-error-graphic-disappears effect.

I don't have strong opinions on which of the three approaches to invalid
inputs should be used, although I would lean towards the transparent black
flood or the revert to default options.

I think that covers all the possibilities for error handling. I would be
interested to hear from those of you involved in implementing these
features whether any of the options above are preferred (or difficult) for
practical reasons.

Best,
Amelia BR


[1]: http://lists.w3.org/Archives/Public/www-svg/2014Nov/0027.html
[2]: http://lists.w3.org/Archives/Public/public-fx/2014OctDec/0040.html
[3]: http://lists.w3.org/Archives/Public/public-fx/2014OctDec/0038.html
[4]: http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing
[5]: http://dev.w3.org/fxtf/filters/
[6]: http://lists.w3.org/Archives/Public/public-fx/2013JulSep/0000.html
[7]: http://www.w3.org/TR/SVG11/filters.html#FilterPrimitiveInAttribute

Received on Wednesday, 12 November 2014 23:22:21 UTC