The current canvas filters proposal [1] allows using SVG reference filters
defined in external documents (e.g. “url(file.svg#filter)”). Since the
external document needs to be loaded before the filter can be applied,
there’s a delay between setting the context’s filter attribute to such a
filter and actually having the filter apply to drawing operations. So
authors can’t predict when the filter will start getting applied. For

var canvas = document.getElementById(“canvas”);
var ctx = canvas.getContext(“2d”);
ctx.filter = “url(file.svg#blur)”
ctx.font = “48px serif”
ctx.strokeText(“Hello world”, 50, 100);

Unless file.svg happens to already be loaded, it won’t be loaded in time
for the call to strokeText. After some unpredictable delay, the document
will finish loading and the filter will start being applied to future draw

Another problem is switching between filters defined in separate documents
within the same animation frame. Continuing the previous example:

ctx.filter = “url(file2.svg#dropShadow)”
ctx.strokeText(“Hello again”, 50, 200);
ctx.filter = “url(file.svg#blur)”
ctx.strokeText(“Canvas”, 50, 300);

As soon as the filter property’s value is changed, documents that the
previous value referred to may get unloaded. So after switching back to
“url(file.svg#blur)” there might be another delay before the filter is
useable again.

To address these problems, I’d like to propose adding a createFilter
method. This takes a string (a filter value) and returns a promise. If the
filter fails to load, the promise is rejected. Otherwise, once the filter
finishes loading, the promise resolves to a CanvasFilter instance that acts
as an opaque handle to the filter. The filter is guaranteed to remain
loaded as long as the handle has references. A CanvasFilter can be directly
used as a filter attribute value. That is, the filter attribute is now
defined as:
  attribute (DOMString or CanvasFilter) filter;

For example:
var filters = [];
var promises = [];
promises[0] = ctx.createFilter(“url(file.svg#blur)”);
promises[1] = ctx.createFilter(“url(file2.svg#dropShadow)”);
Promise.all(promises).then(function(values) {
  filters = values;
  // Filters can now be used without any delay.
  ctx.filter = filters[0];
  ctx.strokeText(“Canvas”, 50, 400);
  ctx.filter = filters[1];
  ctx.strokeText(“Filters”, 50, 100);
  ctx.filter = filters[0];
  ctx.strokeText(“SVG”, 50, 200);
// Once we no longer need these filters, release them.
filters = [];



Reply via email to