From 7f411fdfb89be4c83d8e1ec71e3bb41ddb22e383 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Gravel Date: Wed, 19 Jul 2023 14:30:16 -0400 Subject: [PATCH 01/15] Add a layer and filter interface in the 2D canvas This adds new beginLayer and endLayer functions to open and close layers in the canvas. While layers are active, draw calls operate on a separate texture that gets composited to the parent output bitmap when the layer is closed. An optional filter can be specified in beginLayer, allowing effects to be applied to the layer's texture when it's composited its parent. Tests: https://github.com/web-platform-tests/wpt/tree/master/html/canvas/element/layers https://github.com/web-platform-tests/wpt/tree/master/html/canvas/offscreen/layers Fixes #8476 --- source | 629 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 614 insertions(+), 15 deletions(-) diff --git a/source b/source index c09d97c6242..250a00e1338 100644 --- a/source +++ b/source @@ -4455,6 +4455,8 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
  • SVG title element
  • SVG use element
  • SVG text-rendering property
  • +
  • core attribute
  • +
  • presentation attribute
  • @@ -4466,6 +4468,9 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute @@ -64923,6 +64928,9 @@ callback BlobCallback = undefined (Blob? blob); when invoked, must run these steps:

      +
    1. If layer-count is not zero, then throw an + "InvalidStateError" DOMException.

    2. +
    3. If this canvas element's bitmap's origin-clean flag is set to false, then throw a "SecurityError" DOMException.

      @@ -64951,6 +64959,9 @@ callback BlobCallback = undefined (Blob? blob); quality) method, when invoked, must run these steps:

        +
      1. If layer-count is not zero, then throw an + "InvalidStateError" DOMException.

      2. +
      3. If this canvas element's bitmap's origin-clean flag is set to false, then throw a "SecurityError" DOMException.

      4. @@ -65050,6 +65061,7 @@ interface CanvasRenderingContext2D { CanvasRenderingContext2DSettings getContextAttributes(); }; CanvasRenderingContext2D includes CanvasState; +CanvasRenderingContext2D includes CanvasLayers; CanvasRenderingContext2D includes CanvasTransform; CanvasRenderingContext2D includes CanvasCompositing; CanvasRenderingContext2D includes CanvasImageSmoothing; @@ -65074,6 +65086,19 @@ interface mixin CanvasState { boolean isContextLost(); // return whether context is lost }; +typedef record<DOMString, any> CanvasFilterPrimitive; +typedef (CanvasFilterPrimitive or sequence<CanvasFilterPrimitive>) CanvasFilterInput; + +dictionary BeginLayerOptions { + CanvasFilterInput? filter = null; +}; + +interface mixin CanvasLayers { + // layers + undefined beginLayer(optional BeginLayerOptions options = {}); + undefined endLayer(); +}; + interface mixin CanvasTransform { // transformations (default transform is the identity matrix) undefined scale(unrestricted double x, unrestricted double y); @@ -65360,6 +65385,16 @@ interface Path2D {

        A CanvasRenderingContext2D object has an output bitmap that is initialized when the object is created.

        + The CanvasRenderingContext2D output bitmap can be replaced and restored + by calls to beginLayer and endLayer, with the drawing state stack + keeping track of all active nested output bitmaps. The + CanvasRenderingContext2D object has a layer-count integer that is initially set to zero, + keeping track of the number of opened nested layers. To access the content of the context's + output bitmap, the steps for reading the context output bitmap must be + used. +

        The output bitmap has an origin-clean flag, which can be set to true or false. Initially, when one of these bitmaps is created, its cases, this will be more memory efficient.

        The bitmap of a canvas element is the one bitmap that's pretty much always going - to be needed in practice. The output bitmap of a rendering context, when it has one, - is always just an alias to a canvas element's bitmap.

        + to be needed in practice. The top level output bitmap of a rendering context, when it + has one, is always just an alias to a canvas element's bitmap. When layers are + opened, implementations must behave as if draw calls operate on a separate output + bitmap that gets composited to the parent output bitmap when the layer is + closed. If the canvas element's bitmap needs to be presented while layers are opened, + layers are automatically closed, so that their content gets drawn to the context's output + bitmap. The drawing state stack is then restored, reopening all pending + layers before the script execution could resume.

        Additional bitmaps are sometimes needed, e.g. to enable fast drawing when the canvas is being painted at a different size than its natural size, @@ -65652,8 +65693,9 @@ context.fillRect(100,0,50,50); // only this square remains

        The canvas state
        -

        Objects that implement the CanvasState interface maintain a stack of drawing - states. Drawing states consist of:

        +

        Objects that implement the CanvasState interface maintain a stack of drawing states. + Drawing states consist of:

        • The current transformation @@ -65691,10 +65733,13 @@ context.fillRect(100,0,50,50); // only this square remains data-x="dom-context-2d-imageSmoothingQuality">imageSmoothingQuality.

        • The current dash list.

        • + +
        • An optional canvas layer state.

        -

        The rendering context's bitmaps are not part of the drawing state, as they - depend on whether and how the rendering context is bound to a canvas element.

        +

        The rendering context's bitmaps are not part of the drawing state + (with the exception of layer's parentOutputBitmap), as they depend on whether and how + the rendering context is bound to a canvas element.

        Objects that implement the CanvasState mixin have a context lost boolean, that is initialized to false @@ -65709,8 +65754,8 @@ context.fillRect(100,0,50,50); // only this square remains

        Pops the top state on the stack, restoring the context to that state.

        context.reset()
        -

        Resets the rendering context, which includes the backing buffer, the drawing state stack, - path, and styles.

        +

        Resets the rendering context, which includes the backing buffer, the drawing state + stack, path, and styles.

        context.isContextLost()

        Returns true if the rendering context was lost. Context loss can occur due to driver @@ -65721,11 +65766,26 @@ context.fillRect(100,0,50,50); // only this square remains

        The save() method - steps are to push a copy of the current drawing state onto the drawing state stack.

        + steps are to push a copy of the current drawing state onto the + drawing state stack.

        The restore() - method steps are to pop the top entry in the drawing state stack, and reset the drawing state it - describes. If there is no saved state, then the method must do nothing.

        + method steps are:

        + +
          +
        1. If the drawing state stack is empty, + return.

        2. + +
        3. If the canvas layer state at the top of the drawing state stack + is not null, throw an "InvalidStateError" + DOMException.

        4. + +
        5. Let previousDrawingStates be the result of popping the drawing state stack.

        6. + +
        7. Set all current drawing states to the values they have + in previousDrawingStates.

        8. +

        The reset() method steps are to reset the rendering context to its default state.

        @@ -65737,7 +65797,10 @@ context.fillRect(100,0,50,50); // only this square remains
      5. Empty the list of subpaths in context's current default path.

      6. -
      7. Clear the context's drawing state stack.

      8. +
      9. Clear the context's drawing state stack.

      10. + +
      11. Set the context's layer-count to + zero.

      12. Reset everything that drawing state consists of to their initial values.

      13. @@ -65749,6 +65812,521 @@ context.fillRect(100,0,50,50); // only this square remains
        +
        Layers
        + +

        Objects that implement the CanvasLayers mixin have methods (defined in this + section) for managing output bitmap layers.

        + +

        Layers are opened and closed using beginLayer + and endLayer. When a layer is opened, the context + output bitmap is aliased to that layer's output bitmap, such that all + draw calls performed while the layer is active will effectively render onto the layer's + output bitmap. When endLayer is called, + the layer's output bitmap gets rendered to the parent's output bitmap + using the filter specified in beginLayer.

        + +
        + +

        The drawing state stack keeps track of opened layers by holding canvas layer + state structs containing the following items:

        + +
          +
        • parentOutputBitmap, the layer's parent + output bitmap.
        • + +
        • xmlFilterList, the layer's XML filter list.
        • +
        + +
        + +

        The layer rendering states are the subset of the drawing states that are applied to a layer's + output bitmap when it's drawn to its parent output bitmap. The + layer rendering states are:

        +
          +
        • The current global alpha and + compositing and blending + operator.
        • + +
        • The current values of the following attributes: + shadowOffsetX, + shadowOffsetY, + shadowBlur, + shadowColor
        • +
        + +
        +

        Because the layer rendering states are applied on the layer's output, + they cannot also be applied to the layer's content, or else, they would be applied twice. These + states are therefore set to their default value when opening a layer.

        + +

        The transformation matrix and imageSmoothingEnabled are not part of + the layer rendering states because if the layer's output was to be transformed or + smoothed, it would require resampling of the layer's output bitmap, lowering picture + quality for every layer nesting levels. It's better to transform and smooth the innermost layer + content and draw pixels directly to their final coordinate.

        + +

        Filters specified via context.filter are not part of the layer rendering + states and are therefore not applied on the layer's output bitmap. The preferred way to + specify filters is to use beginLayer. Using + context.filter is inefficient because it + requires each individual draw call to be wrapped in a layer. It's better to make this cost + explicit by using beginLayer.

        + +

        The clipping region is the only state that gets applied to both the layer content + and the layer's output bitmap. As such, it's treated as a special case and is not + included in the layer rendering states.

        +
        + +

        CanvasFilterInput is used for describing SVG filters using JavaScript. A + CanvasFilterInput object can be converted to an equivalent XML filter list. An XML filter list is a list of + XML element data for filters that fully describes an SVG filter network.

        + +
        +
        context.beginLayer([ { [ filter: filterInput ] } + ])
        +

        Pushes the current state onto the stack and starts a new layer. While a layer is active, + all draw calls are performed on a separate surface, which will later be drawn as a whole to the + canvas (or parent layer) when the layer is closed.

        + +

        If the filter member is + specified, the filter effect is applied to the layer's resulting texture as it's drawn to the + parent output bitmap.

        + +

        Filters are specified as a single CanvasFilterPrimitive, or a list of + CanvasFilterPrimitive to chain filter effects. CanvasFilterPrimitive + objects have a name property, whose value is one of the supported + filter names, and additional properties corresponding to the settings of the filter. These + latter properties are the same as the XML attribute names when using the corresponding SVG + filter.

        + +
        context.endLayer()
        +

        Pops the top state on the stack, restores the context to that state and draws the layer's + resulting texture to the parent surface (the canvas or the parent layer). The layer's filter, if specified, gets applied, + along with the global rendering states as they were when beginLayer was called.

        +
        + +
        + +

        The beginLayer() method steps are:

        +
          +
        1. Let settings be the result of converting options to the dictionary type + BeginLayerOptions. (This can throw an exception.)

        2. + +
        3. Let currentOutputBitmap be the context's current + output bitmap

        4. + +
        5. Let layerOutputBitmap be a newly created output bitmap, + initialized with the same size and color space + as `currentOutputBitmap` and with an origin-clean flag set to true.

        6. + +
        7. Let xmlFilter be the result of running the steps for building an XML filter list + given settings["filter"].

        8. + +
        9. Let layerState be a new canvas layer state object, initialized + with currentOutputBitmap and xmlFilter.

        10. + +
        11. Run the steps of the save method. + +

        12. Reset the context's layer rendering states to their default value.

        13. + +
        14. Set the canvas layer state at the top of the drawing state stack + to layerState.

        15. + +
        16. Set the context's current output bitmap to + layerOutputBitmap

        17. + +
        18. Increment layer-count by one.

        19. +
        + +

        The endLayer() method steps are:

        +
          +
        1. If the drawing state stack is empty, then + throw an "InvalidStateError" DOMException.

        2. + +
        3. Let layerState be the canvas layer state at the top of the + drawing state stack.

        4. + +
        5. If layerState is null, throw an "InvalidStateError" + DOMException.

        6. + +
        7. Let layerOutputBitmap be the context's current + output bitmap

        8. + +
        9. Let parentOutputBitmap be + layerState["parentOutputBitmap"]

        10. + +
        11. If layerOutputBitmap is marked as not origin-clean, then set the origin-clean flag of parentOutputBitmap + to false.

        12. + +
        13. Set the context's current output bitmap to + parentOutputBitmap

        14. + +
        15. Let filteredLayerOutputBitmap be the result of applying + layerState["xmlFilterList"] to layerOutputBitmap using the + steps to apply an XML filter list.

        16. + +
        17. Let parentDrawingStates be the result of popping the drawing state stack.

        18. + +
        19. Reset all context drawing states to their default + values, then set the current layer rendering states and the clipping + region to the values stored in parentDrawingState.

        20. + +
        21. Draw filteredLayerOutputBitmap onto the context's current + output bitmap using the steps outlined in the drawing model.

        22. + +
        23. Set all current drawing states to the values they have + in parentDrawingStates.

        24. + +
        25. Decrement layer-count by one.

        26. +
        + +
        + +

        For legacy reasons, calling restore() + when the drawing state stack is empty is a no-op. The addition of the layer API + however introduced several new potential pitfalls. For instance, scripts like context.save(); context.endLayer(); or context.beginLayer(); + context.restore(); are problematic. They are symptomatic of web page bugs and user agents + cannot silently fix these bugs on behalf of the page (e.g. did the page intend to call + endLayer() instead of restore(), or is there a missing save()?) For that reason, invalid API sequences involving + layers throw exceptions to make the issue clear to web developers.

        + +
        + +

        The steps for building an XML + filter list require the following definitions:

        + +

        The supported filter names are + "colorMatrix", + "componentTransfer", + "convolveMatrix", + "dropShadow" and + "gaussianBlur". + +

        The XML element data for filters is a struct, with the following items:

        + +
          +
        • A string name

        • + +
        • An ordered map of strings to strings attributes

        • + +
        • A list of XML element data for filters children

        • +
        + +

        To get the IDL type for a canvas filter attribute attrName:

        + +
          +
        1. Let type be the type listed for attrName in Filter + Effects.

        2. + +
        3. If type is "false | true", then return boolean.

        4. + +
        5. If type is "list of <number>s", then return sequence<double>.

        6. + +
        7. If type is "<number>", then return double.

        8. + +
        9. If type is "<integer>", then return long long.

        10. + +
        11. If type is "<number-optional-number>", then + return (double or sequence<double>).

        12. + +
        13. Return DOMString.

        14. +
        + +

        To generate an XML value from a key, + value pair: + +

          +
        1. Let type be the result of getting the IDL type for a canvas filter + attribute for key.

        2. + +
        3. Let idlValue be the result of converting value to type.

        4. + +
        5. If type is (double or sequence<double>), + value is a sequence<double> and value doesn't have two elements, + throw a TypeError exception.

        6. + +
        7. Let xmlValue be the result of converting idlValue to an ECMAScript value, and + then converting that result to a DOMString.

        8. + +
        9. Return xmlValue.

        10. +
        + +

        The steps for building an + XML filter list given + filters are:

        + +
          +
        1. Let xmlFilters be an empty list.

        2. + +
        3. If filters is null, then set filters to « ».

        4. + +
        5. If filters is a CanvasFilterPrimitive, then set filters + to « filters ».

        6. + +
        7. +

          For each filterDict of filters:

          + +
            +
          1. If filterDict["name"] does not exist, then throw a TypeError exception.

          2. + +
          3. Let filterName be the value of filterDict["name"].

          4. + +
          5. If filterName is not one of supported filter names, then + continue.

          6. + +
          7. Let xmlName be the concatenation of "fe", the first + code unit of filterName converted to ASCII uppercase, + and all code units of filterName after the first + one.

          8. + +
          9. Let xmlFilter be a new XML element data for filters whose name is xmlName, whose attributes is an empty ordered map, and whose children is an empty list.

          10. + +
          11. Append xmlFilter to + xmlFilters.

          12. + +
          13. +

            For each keyvalue of + filterDict:

            + +
              +
            1. +

              If any of the following are true:

              + +
                +
              • key is not the local name of an attribute listed for the filter + primitive given by xmlName

              • + +
              • key is the local name of a core attribute

              • + +
              • key is the local name of a presentation attribute other + than "flood-color" and "flood-opacity"

              • + +
              • key is the local name of a filter primitive + attribute

              • + +
              • key contains U+003A (:)

              • +
              + +

              then continue.

              +
            2. + +
            3. +

              If key is one of "funcR", "funcG", "funcB", "funcA":

              + +
                +
              1. Set value to the result of + converting value to record<DOMString, + any>.

              2. + +
              3. Let xmlTransferName be the concatenation of "fe", + the first code unit of key converted to ASCII + uppercase, and all code units of key + after the first one.

              4. + +
              5. Let transferFunction be a new XML element data for filters + whose name is xmlTransferName, whose + attributes is an empty ordered map, and whose + children is an empty list.

              6. + +
              7. +

                For each transferNametransferValue of value:

                + +
                  +
                1. Let transferFunctionValue be the result of generating an XML value from transferName + and transferValue.

                2. + +
                3. Set transferFunction's attributes[transferName] to + transferFunctionValue.

                4. +
                +
              8. + +
              9. Append transferFunction to xmlFilter's children.

              10. +
              +
            4. + +
            5. +

              Otherwise:

              + +
                +
              1. Let attrXMLValue be the result of generating an XML value from key and + value.

              2. + +
              3. Set xmlFilter's attributes[key] to + attrXMLValue.

              4. +
              +
            6. +
            +
          14. +
          +
        8. + +
        9. return xmlFilters
        10. +
        + +

        The steps to apply an XML filter list to an image given an XML filter list filters are:

        +
          +
        1. Let image be the source image

        2. + +
        3. +

          For each filter of filters:

          +
            +
          1. Let svgFilter be an SVG filter, obtained by mapping each attributes of the filter XML filter list to the SVG equivalent.

          2. + +
          3. Render image using svgFilter, creating + filteredImage

          4. + +
          5. Let image be an alias to filteredImage

          6. +
          +
        4. + +
        5. Return image.

        6. +
        + +
        + +
        +

        The following example will create a layer with a colorMatrix + filter that swaps the green and red channels, then blurs the result by 5 pixels:

        + +
        // canvas is a reference to a <canvas> element
        +const context = canvas.getContext('2d');
        +context.beginLayer({filter: [
        +  {
        +    name: 'colorMatrix',
        +    type: 'matrix',
        +    values: [
        +      0, 1, 0, 0, 0,
        +      1, 0, 0, 0, 0,
        +      0, 0, 1, 0, 0,
        +      0, 0, 0, 1, 0
        +    ],
        +  },
        +  {
        +    name: 'gaussianBlur',
        +    stdDeviation: 5,
        +  }
        +]});
        +
        + +

        Currently, CanvasFilterInputs can only be linear sequences of + filters. Full filter graphs are a planned expansion of this feature.

        + +
        + +

        Before any operations could access the canvas element's bitmap pixels, the + drawing state stack must be flushed so that all pending layers are closed and + rendered to their parent output bitmap all the way to the canvas + element's bitmap. The steps for flushing the drawing state stack are:

        + +
          +
        1. Save the context's current drawing state in the drawing state + stack by running the save() method + steps.

        2. + +
        3. Let stackBackup be an empty list.

        4. + +
        5. While the drawing state stack is not empty:

        6. + +
            +
          1. Prepend the drawing state at the top of + the drawing state stack to stackBackup.

          2. + +
          3. If the canvas layer state at the top of the drawing state stack + is not empty, run the endLayer() method + steps.

          4. + +
          5. Otherwise, run the restore() method + steps.

          6. +
          + +
        7. return stackBackup.

        8. +
        + +

        Given stackBackup which was returned when flushing the drawing state + stack, the drawing state stack can be restored to the state it was before it + was flushed by running the steps for restoring the drawing state stack:

        + +
          +
        1. For each stateEntry of + stateBackup:

        2. + +
            +
          1. Push stateEntry onto the drawing state + stack.

          2. +
          + +
        3. Restore the context's current drawing state by running the restore() method steps.

        4. +
        + +

        The steps for reading the context output bitmap are:

        + +
          +
        1. Let drawingStateStackBackup be the result of flushing the drawing state + stack.

        2. + +
        3. Let resultBitmap be a reference on the context output + bitmap.

        4. + +
        5. Run the steps for restoring the drawing state stack, given + drawingStateStackBackup.

        6. + +
        7. Return resultBitmap.

        8. +
        + +
        +
        Line styles
        @@ -68124,9 +68702,15 @@ try {
        HTMLCanvasElement
        OffscreenCanvas
        -

        If image has either a horizontal dimension or a vertical dimension - equal to zero, then throw an "InvalidStateError" - DOMException.

        +
        +

        If the rendering context associated with image has a layer-count different than zero, then throw an + "InvalidStateError" DOMException.

        + +

        If image has either a horizontal dimension or a vertical dimension + equal to zero, then throw an "InvalidStateError" + DOMException.

        +
        ImageBitmap
        VideoFrame
        @@ -69714,6 +70298,9 @@ try {
      14. If either the sw or sh arguments are zero, then throw an "IndexSizeError" DOMException.

      15. +
      16. If layer-count is not zero, then throw an + "InvalidStateError" DOMException.

      17. +
      18. If the CanvasRenderingContext2D's origin-clean flag is set to false, then throw a "SecurityError" DOMException.

      19. @@ -69861,6 +70448,9 @@ try {
      20. If IsDetachedBuffer(buffer) is true, then throw an "InvalidStateError" DOMException.

      21. +
      22. If layer-count is not zero, then throw an + "InvalidStateError" DOMException.

      23. +
      24. If dirtyWidth is negative, then let dirtyX be dirtyX+dirtyWidth, and let dirtyWidth be equal @@ -71209,6 +71799,13 @@ interface OffscreenCanvas : EventTarget { internal slot is set to true, then return a promise rejected with an "InvalidStateError" DOMException.

      25. +
      26. If this OffscreenCanvas object's context mode is 2d and the rendering context's layer-count is not zero, then return a promise + rejected with an "InvalidStateError" + DOMException.

        +
      27. If this OffscreenCanvas object's context mode is 2d and the rendering context's OffscreenCanvasRenderingContext2D { }; OffscreenCanvasRenderingContext2D includes CanvasState; +OffscreenCanvasRenderingContext2D includes CanvasLayers; OffscreenCanvasRenderingContext2D includes CanvasTransform; OffscreenCanvasRenderingContext2D includes CanvasCompositing; OffscreenCanvasRenderingContext2D includes CanvasImageSmoothing; @@ -145644,6 +146242,7 @@ INSERT INTERFACES HERE Jasper St. Pierre, Jatinder Mann, Jay Henry Kao, + Jean-Philippe Gravel, Jean-Yves Avenard, Jed Hartman, Jeff Balogh, From aa10da3363e68a4aa34ed5e83dd6b919b510ee99 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Gravel Date: Mon, 6 Nov 2023 23:59:58 -0500 Subject: [PATCH 02/15] Added CCS filter, fixed unclosed layers and replied to review comments This update addresses 3 main things: - Support for CSS filter strings was added to the beginLayer API - Unclosed layers are now never rasterized when the canvas is presented to the user. Instead, the content of the layer is preserved and will be rasterized in a later frame, if/when the layer is closed. - Replied to the first round of review comments. --- source | 534 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 276 insertions(+), 258 deletions(-) diff --git a/source b/source index 250a00e1338..22bcb483947 100644 --- a/source +++ b/source @@ -4469,8 +4469,8 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute

        • <filter-value-list>
        • filter primitive attribute
        • -
        • flood-color property
        • -
        • flood-opacity property
        • +
        • 'flood-color' property
        • +
        • 'flood-opacity' property
      28. @@ -64928,8 +64928,9 @@ callback BlobCallback = undefined (Blob? blob); when invoked, must run these steps:

          -
        1. If layer-count is not zero, then throw an - "InvalidStateError" DOMException.

        2. +
        3. If the rendering context associated with this canvas element has a layer count different than zero, then throw an + "InvalidStateError" DOMException.

        4. If this canvas element's bitmap's origin-clean flag is set to false, then throw a @@ -64959,8 +64960,9 @@ callback BlobCallback = undefined (Blob? blob); quality) method, when invoked, must run these steps:

            -
          1. If layer-count is not zero, then throw an - "InvalidStateError" DOMException.

          2. +
          3. If the rendering context associated with this canvas element has a layer count different than zero, then throw an + "InvalidStateError" DOMException.

          4. If this canvas element's bitmap's origin-clean flag is set to false, then throw a @@ -65087,7 +65089,7 @@ interface mixin CanvasState { }; typedef record<DOMString, any> CanvasFilterPrimitive; -typedef (CanvasFilterPrimitive or sequence<CanvasFilterPrimitive>) CanvasFilterInput; +typedef (DOMString or CanvasFilterPrimitive or sequence<CanvasFilterPrimitive>) CanvasFilterInput; dictionary BeginLayerOptions { CanvasFilterInput? filter = null; @@ -65382,22 +65384,25 @@ interface Path2D {

            -

            A CanvasRenderingContext2D object has an output bitmap that - is initialized when the object is created.

            +

            A CanvasRenderingContext2D object has a top level output bitmap and a + current output bitmap which both originally refer to the same output bitmap + that is initialized when the CanvasRenderingContext2D is created. The + top level output bitmap is the bitmap that gets presented to the user in the update the + rendering step of the event loop. The current output bitmap is + the bitmap to which most CanvasRenderingContext2D operations are drawing.

            - The CanvasRenderingContext2D output bitmap can be replaced and restored - by calls to beginLayer and endLayer, with the drawing state stack +

            The CanvasRenderingContext2D's current output bitmap can be replaced + and restored by calls to beginLayer and endLayer, with the drawing state stack keeping track of all active nested output bitmaps. The CanvasRenderingContext2D object has a layer-count integer that is initially set to zero, - keeping track of the number of opened nested layers. To access the content of the context's - output bitmap, the steps for reading the context output bitmap must be - used. + data-x="concept-canvas-layer-count">layer count integer that is initially set to zero, + keeping track of the number of opened nested layers.

            -

            The output bitmap has an The output bitmap objects have an origin-clean flag, which can be set to true or false. - Initially, when one of these bitmaps is created, its origin-clean flag must be set to true.

            The CanvasRenderingContext2D object also has an Path2D { always results in opaque black pixels, every fourth byte from getImageData() is always 255, the putImageData() method effectively ignores every - fourth byte in its input, and so on. However, the alpha component of styles and images drawn - onto the canvas are still honoured up to the point where they would impact the output - bitmap's alpha channel; for instance, drawing a 50% transparent white square on a freshly - created output bitmap with its alpha set - to false will result in a fully-opaque gray square.

            + fourth byte in its input, and so on. However, the alpha component of styles, images and layers + drawn onto the canvas are still honoured up to the point where they would impact the top + level output bitmap's alpha channel; for instance, drawing a 50% transparent white square + on a freshly created top level output bitmap with its alpha set to false will result in a fully-opaque gray + square.

            The CanvasRenderingContext2D object also has a desynchronized boolean. When a @@ -65447,9 +65453,9 @@ interface Path2D { may optimize the canvas for readback operations.

            On most devices the user agent needs to decide whether to store the canvas's - output bitmap on the GPU (this is also called "hardware accelerated"), or on the CPU - (also called "software"). Most rendering operations are more performant for accelerated canvases, - with the major exception being readback with output bitmaps on the GPU (this is also called "hardware + accelerated"), or on the CPU (also called "software"). Most rendering operations are more + performant for accelerated canvases, with the major exception being readback with getImageData(), toDataURL(), or toBlob(). CanvasRenderingContext2D objects with @@ -65461,7 +65467,7 @@ interface Path2D { data-x="concept-canvas-color-space">color space setting of type PredefinedColorSpace. The CanvasRenderingContext2D object's color space indicates the color space for the - output bitmap.

            + context's output bitmaps.

            The getContextAttributes() method @@ -65481,9 +65487,10 @@ interface Path2D { Cartesian surface whose origin (0,0) is at the top left corner, with the coordinate space having x values increasing when going right, and y values increasing when going down. The x-coordinate of the right-most edge is equal to the width of the rendering - context's output bitmap in CSS pixels; similarly, the - y-coordinate of the bottom-most edge is equal to the height of the rendering context's - output bitmap in CSS pixels.

            + context's top level output bitmap in CSS pixels; + similarly, the y-coordinate of the bottom-most edge is equal to the height of the + rendering context's top level output bitmap in CSS + pixels.

            The size of the coordinate space does not necessarily represent the size of the actual bitmaps that the user agent will use internally or during rendering. On high-definition displays, for @@ -65494,13 +65501,13 @@ interface Path2D {

            Using CSS pixels to describe the size of a rendering context's - output bitmap does not mean that when rendered the canvas will cover an equivalent - area in CSS pixels. CSS pixels are reused - for ease of integration with CSS features, such as text layout.

            + top level output bitmap does not mean that when rendered the canvas will cover an + equivalent area in CSS pixels. CSS pixels + are reused for ease of integration with CSS features, such as text layout.

            In other words, the canvas element below's rendering context has a 200x200 - output bitmap (which internally uses CSS pixels as a - unit for ease of integration with CSS) and is rendered as 100x100 CSS + top level output bitmap (which internally uses CSS pixels + as a unit for ease of integration with CSS) and is rendered as 100x100 CSS pixels:

            <canvas width=200 height=200 style=width:100px;height:100px>
            @@ -65521,8 +65528,9 @@ interface Path2D {
          5. Initialize context's canvas attribute to point to target.

          6. -
          7. Set context's output bitmap to the same bitmap as - target's bitmap (so that they are shared).

          8. +
          9. Set context's top level output bitmap and current output + bitmap to the same bitmap as target's bitmap (so that they are + shared).

          10. Set bitmap dimensions to the numeric values of target's Path2D {

            1. Reset the rendering context to its default state.

            2. -
            3. Resize the output bitmap to the new width and +

            4. Resize the top level output bitmap to the new width and height.

            5. Let canvas be the canvas element to which the rendering @@ -65669,7 +65677,7 @@ context.fillRect(100,0,50,50); // only this square remains -

              The output bitmap, when it is not directly displayed by the user agent, +

              The top level output bitmap, when it is not directly displayed by the user agent, implementations can, instead of updating this bitmap, merely remember the sequence of drawing operations that have been applied to it until such time as the bitmap's actual data is needed (for example because of a call to drawImage(), or @@ -65677,14 +65685,14 @@ context.fillRect(100,0,50,50); // only this square remains cases, this will be more memory efficient.

              The bitmap of a canvas element is the one bitmap that's pretty much always going - to be needed in practice. The top level output bitmap of a rendering context, when it + to be needed in practice. The top level output bitmap of a rendering context, when it has one, is always just an alias to a canvas element's bitmap. When layers are - opened, implementations must behave as if draw calls operate on a separate output - bitmap that gets composited to the parent output bitmap when the layer is - closed. If the canvas element's bitmap needs to be presented while layers are opened, - layers are automatically closed, so that their content gets drawn to the context's output - bitmap. The drawing state stack is then restored, reopening all pending - layers before the script execution could resume.

              + opened, draw calls operate on a separate current output bitmap that gets composited + to the parent output bitmap when the layer is closed. If the canvas + element's bitmap needs to be presented to the user + while layers are opened, the top level output bitmap is used, meaning that the + content of unclosed layers will not be presented. They will be presented in a later frame, if and + when the layers are closed.

              Additional bitmaps are sometimes needed, e.g. to enable fast drawing when the canvas is being painted at a different size than its natural size, @@ -65694,8 +65702,8 @@ context.fillRect(100,0,50,50); // only this square remains

              The canvas state

              Objects that implement the CanvasState interface maintain a stack of drawing states. - Drawing states consist of:

              + data-x="drawing state stack">stack of drawing states. Drawing states consist of:

              • The current transformation @@ -65734,11 +65742,11 @@ context.fillRect(100,0,50,50); // only this square remains

              • The current dash list.

              • -
              • An optional canvas layer state.

              • +
              • An optional canvas layer state, defaults to null if not specified.

              The rendering context's bitmaps are not part of the drawing state - (with the exception of layer's parentOutputBitmap), as they depend on whether and how + (with the exception of layer's parent output bitmap), as they depend on whether and how the rendering context is bound to a canvas element.

              Objects that implement the CanvasState mixin have a

              The save() method - steps are to push a copy of the current drawing state onto the + steps are to push a copy of the current drawing state onto this's drawing state stack.

              The restore() method steps are:

                -
              1. If the drawing state stack is empty, - return.

              2. +
              3. If this's drawing state stack is + empty, then return.

              4. -
              5. If the canvas layer state at the top of the drawing state stack - is not null, throw an "InvalidStateError" +

              6. If this's drawing state stack's last item's canvas layer + state is not null, then throw an "InvalidStateError" DOMException.

              7. Let previousDrawingStates be the result of popping the drawing state stack.

              8. -
              9. Set all current drawing states to the values they have - in previousDrawingStates.

              10. +
              11. Set all of this's current drawing states + to the values they have in previousDrawingStates.

              The reset() @@ -65793,14 +65801,20 @@ context.fillRect(100,0,50,50); // only this square remains

              To reset the rendering context to its default state:

                -
              1. Clear canvas's bitmap to transparent black.

              2. +
              3. Clear this's drawing state stack.

              4. -
              5. Empty the list of subpaths in context's current default path.

              6. +
              7. Set this's current output bitmap to be a reference to + this's top level output bitmap.

              8. -
              9. Clear the context's drawing state stack.

              10. +
              11. Set this's top level output bitmap's origin-clean flag to true.

              12. -
              13. Set the context's layer-count to - zero.

              14. +
              15. Set this's layer count to + zero.

              16. + +
              17. Clear canvas's bitmap to transparent black.

              18. + +
              19. Empty the list of subpaths in context's current default path.

              20. Reset everything that drawing state consists of to their initial values.

              21. @@ -65815,16 +65829,17 @@ context.fillRect(100,0,50,50); // only this square remains
                Layers

                Objects that implement the CanvasLayers mixin have methods (defined in this - section) for managing output bitmap layers.

                + section) for managing a stack of output bitmaps.

                -

                Layers are opened and closed using beginLayer - and endLayer. When a layer is opened, the context - output bitmap is aliased to that layer's output bitmap, such that all - draw calls performed while the layer is active will effectively render onto the layer's - output bitmap. When endLayer is called, - the layer's output bitmap gets rendered to the parent's output bitmap - using the filter specified in beginLayer.

                +

                Layers are opened and closed using beginLayer + and endLayer. When a layer is opened, the context's + current output bitmap is aliased to that layer's output bitmap, such + that all draw calls performed while the layer is active will effectively render onto the layer's + output bitmap. When endLayer is called, + the layer's output bitmap gets filtered using the filter specified in beginLayer and composited in the parent's + output bitmap using the layer rendering states.

                @@ -65833,11 +65848,11 @@ context.fillRect(100,0,50,50); // only this square remains data-x="struct item">items:

                  -
                • parentOutputBitmap, the layer's parent +
                • parent output bitmap, the layer's parent output bitmap.
                • -
                • xmlFilterList, the layer's XML filter list.
                • +
                • resolved layer filter, the layer's resolved filter.
                @@ -65847,6 +65862,8 @@ context.fillRect(100,0,50,50); // only this square remains output bitmap when it's drawn to its parent output bitmap. The layer rendering states are:

                  +
                • The current clipping region.
                • +
                • The current global alpha and compositing and blending operator.
                • @@ -65870,30 +65887,27 @@ context.fillRect(100,0,50,50); // only this square remains quality for every layer nesting levels. It's better to transform and smooth the innermost layer content and draw pixels directly to their final coordinate.

                  -

                  Filters specified via context.filter are not part of the layer rendering - states and are therefore not applied on the layer's output bitmap. The preferred way to - specify filters is to use beginLayer. Using - context.filter is inefficient because it - requires each individual draw call to be wrapped in a layer. It's better to make this cost - explicit by using beginLayer.

                  - -

                  The clipping region is the only state that gets applied to both the layer content - and the layer's output bitmap. As such, it's treated as a special case and is not - included in the layer rendering states.

                  +

                  Filters specified via context.filter are not part + of the layer rendering states and are therefore not applied on the layer's + output bitmap. The preferred way to specify filters is to use beginLayer. Using context.filter is inefficient because it requires each + individual draw call to be wrapped in a layer. It's better to make this cost explicit by using + beginLayer.

              -

              CanvasFilterInput is used for describing SVG filters using JavaScript. A - CanvasFilterInput object can be converted to an equivalent XML filter list. An XML filter list is a list of +

              CanvasFilterInput is used for describing CSS or SVG filters using JavaScript. A + CanvasFilterInput can either be a CSS filter string or an object that can be + converted to an equivalent XML filter list. + An XML filter list is a list of XML element data for filters that fully describes an SVG filter network.

              context.beginLayer([ { [ filter: filterInput ] } - ])
              + data-x="dom-context-2d-beginLayer">beginLayer() +
              context.beginLayer({ filter })

              Pushes the current state onto the stack and starts a new layer. While a layer is active, all draw calls are performed on a separate surface, which will later be drawn as a whole to the canvas (or parent layer) when the layer is closed.

              @@ -65902,104 +65916,112 @@ context.fillRect(100,0,50,50); // only this square remains specified, the filter effect is applied to the layer's resulting texture as it's drawn to the parent output bitmap.

              -

              Filters are specified as a single CanvasFilterPrimitive, or a list of - CanvasFilterPrimitive to chain filter effects. CanvasFilterPrimitive - objects have a name property, whose value is one of the supported - filter names, and additional properties corresponding to the settings of the filter. These - latter properties are the same as the XML attribute names when using the corresponding SVG - filter.

              +

              Filters are specified as either be the string "none", as a string + parseable as a <filter-value-list>, as a single + CanvasFilterPrimitive or as an array of CanvasFilterPrimitives (to + chain filter effects).

              + +

              CanvasFilterPrimitive objects have a name property, whose + value is one of the supported filter names, and additional properties corresponding + to the settings of the filter. These latter properties are the same as the XML attribute names + when using the corresponding SVG filter.

              context.endLayer()
              -

              Pops the top state on the stack, restores the context to that state and draws the layer's +

              Pops the top state off the stack, restores the context to that state and draws the layer's resulting texture to the parent surface (the canvas or the parent layer). The layer's filter, if specified, gets applied, - along with the global rendering states as they were when beginLayer was called.

              + along with the global rendering states as they were when beginLayer was called.

              The beginLayer() method steps are:

              + data-x="dom-context-2d-beginLayer">beginLayer(options) method steps + are:

                -
              1. Let settings be the result of converting options to the dictionary type - BeginLayerOptions. (This can throw an exception.)

              2. - -
              3. Let currentOutputBitmap be the context's current - output bitmap

              4. +
              5. Let currentOutputBitmap be this's + current output bitmap.

              6. Let layerOutputBitmap be a newly created output bitmap, - initialized with the same size and color space - as `currentOutputBitmap` and with an origin-clean flag set to true.

              7. + initialized with an origin-clean flag set to + true.

                -
              8. Let xmlFilter be the result of running the steps for building an XML filter list - given settings["filter"].

              9. +
              10. Let resolvedLayerFilter be the result of running the steps for resolving the layer filter + given options["filter"].

              11. Let layerState be a new canvas layer state object, initialized - with currentOutputBitmap and xmlFilter.

              12. + with parent output bitmap set to currentOutputBitmap and resolved + layer filter set to resolvedLayerFilter.

                -
              13. Run the steps of the save method. +

                Push a copy of the current drawing state onto this's + drawing state stack.

                -
              14. Reset the context's layer rendering states to their default value.

              15. +
              16. Reset this's layer rendering states to their default + value.

              17. -
              18. Set the canvas layer state at the top of the drawing state stack - to layerState.

              19. +
              20. Set this's drawing state stack's last item's canvas layer + state to layerState.

              21. -
              22. Set the context's current output bitmap to +

              23. Set this's current output bitmap to layerOutputBitmap

              24. -
              25. Increment layer-count by one.

              26. +
              27. Increment this's layer count + by one.

              The endLayer() method steps are:

                -
              1. If the drawing state stack is empty, then - throw an "InvalidStateError" DOMException.

              2. +
              3. If this's drawing state stack is + empty, then throw an "InvalidStateError" + DOMException.

              4. -
              5. Let layerState be the canvas layer state at the top of the - drawing state stack.

              6. +
              7. Let layerState be this's drawing state stack's last + item's canvas layer state.

              8. If layerState is null, throw an "InvalidStateError" DOMException.

              9. -
              10. Let layerOutputBitmap be the context's current - output bitmap

              11. +
              12. Let layerOutputBitmap be this's current output + bitmap

              13. Let parentOutputBitmap be - layerState["parentOutputBitmap"]

              14. + layerState's parent output bitmap

              15. If layerOutputBitmap is marked as not origin-clean, then set the origin-clean flag of parentOutputBitmap to false.

              16. -
              17. Set the context's current output bitmap to +

              18. Set this's current output bitmap to parentOutputBitmap

              19. -
              20. Let filteredLayerOutputBitmap be the result of applying - layerState["xmlFilterList"] to layerOutputBitmap using the - steps to apply an XML filter list.

              21. +
              22. Let filteredLayerOutputBitmap be the result of running the steps to apply + a resolved layer filter to layerOutputBitmap given + layerState's resolved layer filter.

              23. Let parentDrawingStates be the result of popping the drawing state stack.

              24. + data-x="stack pop">popping this's drawing state stack.

                + +
              25. Reset all of this's drawing states to + their default values.

              26. -
              27. Reset all context drawing states to their default - values, then set the current layer rendering states and the clipping - region to the values stored in parentDrawingState.

              28. +
              29. Set this's layer rendering states to the values stored in + parentDrawingState.

              30. -
              31. Draw filteredLayerOutputBitmap onto the context's current - output bitmap using the steps outlined in the drawing model.

              32. +
              33. Draw filteredLayerOutputBitmap onto this's current output + bitmap using the steps outlined in the drawing model.

              34. -
              35. Set all current drawing states to the values they have - in parentDrawingStates.

              36. +
              37. Set this's drawing states that are not + layer rendering states to the values they have in + parentDrawingStates.

              38. -
              39. Decrement layer-count by one.

              40. +
              41. Decrement this's layer count + by one.

              @@ -66017,6 +66039,42 @@ context.fillRect(100,0,50,50); // only this square remains
              +

              A resolved filter can either be the string + "none", a string parseable as a <filter-value-list> or + an XML filter list.

              + +

              The steps for resolving a layer + filter given a CanvasFilterInput filter are:

              + +
                +
              1. +

                If filter is a string, then:

                +
                  +
                1. If filter is "none", then return "none".

                2. + +
                3. Let parsedValue be the result of parsing filter as a + <filter-value-list>.

                4. + +
                5. If parsedValue is failure, then return "none".

                6. + +
                7. If any property-independent style sheet syntax like 'inherit' or 'initial' is present + in parsedValue, then return "none".

                8. + +
                9. If parsedValue references filters externally-defined in documents that + are not currently loaded, return "none".

                10. + +
                11. Return parsedValue.

                12. +
                +
              2. + +
              3. Otherwise, return the results of running the steps for building an XML filter list + given filter.

              4. +
              +

              The steps for building an XML filter list require the following definitions:

              @@ -66139,7 +66197,7 @@ context.fillRect(100,0,50,50); // only this square remains
            6. key is the local name of a core attribute

            7. key is the local name of a presentation attribute other - than "flood-color" and "flood-opacity"

            8. + than 'flood-color' and 'flood-opacity'

            9. key is the local name of a filter primitive attribute

            10. @@ -66210,11 +66268,30 @@ context.fillRect(100,0,50,50); // only this square remains
            11. return xmlFilters
            -

            The steps to apply an XML filter list to an image given an XML filter list filters are:

            +

            The steps to apply a resolved layer filter to an image given a resolvedFilter are:

              -
            1. Let image be the source image

            2. +
            3. +

              If filter is a string, then:

              +
                +
              1. If resolvedFilter is "none", return + image.

              2. + +
              3. Let filteredImage be the result of applying the resolvedFilter + <filter-value-list> to image in the same manner as SVG + would.

              4. +
              +
            4. + +
            5. Else, let filteredImage be the result of running the steps to apply an + XML filter list on image given resolvedFilter.

            6. + +
            7. Return filteredImage.

            8. +
            +

            The steps to apply an XML filter list, given an image and an XML filter list filters are:

            +
            1. For each filter of filters:

                @@ -66223,9 +66300,9 @@ context.fillRect(100,0,50,50); // only this square remains data-x="concept-canvas-xml-filter-list">XML filter list to the SVG equivalent.

              1. Render image using svgFilter, creating - filteredImage

              2. + filteredImage.

                -
              3. Let image be an alias to filteredImage

              4. +
              5. Set image to filteredImage

            2. @@ -66261,72 +66338,6 @@ context.beginLayer({filter: [

              Currently, CanvasFilterInputs can only be linear sequences of filters. Full filter graphs are a planned expansion of this feature.

              -
              - -

              Before any operations could access the canvas element's bitmap pixels, the - drawing state stack must be flushed so that all pending layers are closed and - rendered to their parent output bitmap all the way to the canvas - element's bitmap. The steps for flushing the drawing state stack are:

              - -
                -
              1. Save the context's current drawing state in the drawing state - stack by running the save() method - steps.

              2. - -
              3. Let stackBackup be an empty list.

              4. - -
              5. While the drawing state stack is not empty:

              6. - -
                  -
                1. Prepend the drawing state at the top of - the drawing state stack to stackBackup.

                2. - -
                3. If the canvas layer state at the top of the drawing state stack - is not empty, run the endLayer() method - steps.

                4. - -
                5. Otherwise, run the restore() method - steps.

                6. -
                - -
              7. return stackBackup.

              8. -
              - -

              Given stackBackup which was returned when flushing the drawing state - stack, the drawing state stack can be restored to the state it was before it - was flushed by running the steps for restoring the drawing state stack:

              - -
                -
              1. For each stateEntry of - stateBackup:

              2. - -
                  -
                1. Push stateEntry onto the drawing state - stack.

                2. -
                - -
              3. Restore the context's current drawing state by running the restore() method steps.

              4. -
              - -

              The steps for reading the context output bitmap are:

              - -
                -
              1. Let drawingStateStackBackup be the result of flushing the drawing state - stack.

              2. - -
              3. Let resultBitmap be a reference on the context output - bitmap.

              4. - -
              5. Run the steps for restoring the drawing state stack, given - drawingStateStackBackup.

              6. - -
              7. Return resultBitmap.

              8. -
              - -
              -
              Line styles
              @@ -68704,7 +68715,7 @@ try {
              OffscreenCanvas

              If the rendering context associated with image has a layer-count different than zero, then throw an + data-x="concept-canvas-layer-count">layer count different than zero, then throw an "InvalidStateError" DOMException.

              If image has either a horizontal dimension or a vertical dimension @@ -68888,8 +68899,8 @@ try {

            3. If the given value is a CanvasPattern object that is marked as not origin-clean, then set - this's origin-clean flag to - false.

            4. + this's current output bitmap's origin-clean flag to false.

            5. Set this's fill style to the given value.

            6. @@ -68934,8 +68945,8 @@ try {
            7. If the given value is a CanvasPattern object that is marked as not origin-clean, then set - this's origin-clean flag to - false.

            8. + this's current output bitmap's origin-clean flag to false.

            9. Set this's stroke style to the given value.

            10. @@ -70019,16 +70030,16 @@ try {

              If not specified, the dw and dh arguments must default to the values of sw and sh, interpreted such that one CSS pixel - in the image is treated as one unit in the output bitmap's coordinate space. If the - sx, sy, sw, and sh arguments are omitted, then they - must default to 0, 0, the image's natural width in image pixels, and the image's - natural height in image pixels, respectively. If the image has no natural - dimensions, then the concrete object size must be used instead, as determined - using the CSS "Concrete Object - Size Resolution" algorithm, with the specified size having neither a definite width - nor height, nor any additional constraints, the object's natural properties being those of the - image argument, and the default object size being the size of the - output bitmap. CSSIMAGES

              + in the image is treated as one unit in the current output bitmap's coordinate + space. If the sx, sy, sw, and sh arguments are + omitted, then they must default to 0, 0, the image's natural width in image pixels, + and the image's natural height in image pixels, respectively. If the image has no + natural dimensions, then the concrete object size must be used instead, as + determined using the CSS "Concrete + Object Size Resolution" algorithm, with the specified size having neither a definite + width nor height, nor any additional constraints, the object's natural properties being those of + the image argument, and the default object size being the size of the + current output bitmap. CSSIMAGES

              The source rectangle is the rectangle whose corners are the four points (sx, sy), (sx+sw, sy), (sx+sw, sy+sh), (sx, sy+sh).

              @@ -70040,9 +70051,9 @@ try { to the source image and the destination rectangle must be clipped in the same proportion.

              When the destination rectangle is outside the destination image (the - output bitmap), the pixels that land outside the output bitmap are - discarded, as if the destination was an infinite canvas whose rendering was clipped to the - dimensions of the output bitmap.

              + current output bitmap), the pixels that land outside the current output + bitmap are discarded, as if the destination was an infinite canvas whose rendering was + clipped to the dimensions of the current output bitmap.

            11. If one of the sw or sh arguments is zero, then return. Nothing is @@ -70050,7 +70061,7 @@ try {

            12. Paint the region of the image argument specified by the source rectangle - on the region of the rendering context's output bitmap specified by the + on the region of the rendering context's current output bitmap specified by the destination rectangle, after applying the current transformation matrix to the destination rectangle.

              @@ -70102,7 +70113,7 @@ try {
            13. If image is not origin-clean, then set the - CanvasRenderingContext2D's CanvasRenderingContext2D's current output bitmap's origin-clean flag to false.

            @@ -70298,10 +70309,11 @@ try {
          11. If either the sw or sh arguments are zero, then throw an "IndexSizeError" DOMException.

          12. -
          13. If layer-count is not zero, then throw an - "InvalidStateError" DOMException.

          14. +
          15. If this's layer count is not + zero, then throw an "InvalidStateError" + DOMException.

          16. -
          17. If the CanvasRenderingContext2D's

            If this's top level output bitmap's origin-clean flag is set to false, then throw a "SecurityError" DOMException.

          18. @@ -70320,14 +70332,14 @@ try { sy+sh).

          19. Set the pixel values of imageData to be the pixels of this's - output bitmap in the area specified by the source rectangle in the bitmap's - coordinate space units, converted from this's top level output bitmap in the area specified by the source rectangle in the + bitmap's coordinate space units, converted from this's color space to imageData's colorSpace using 'relative-colorimetric' rendering intent.

          20. Set the pixels values of imageData for areas of the source rectangle that are - outside of the output bitmap to transparent black.

          21. + outside of the top level output bitmap to transparent black.

          22. Return imageData.

          @@ -70430,9 +70442,9 @@ try {

          The putImageData() method writes data from - ImageData structures back to the rendering context's output bitmap. Its - arguments are: imagedata, dx, dy, dirtyX, - dirtyY, dirtyWidth, and dirtyHeight.

          + ImageData structures back to this's top level output + bitmap. Its arguments are: imagedata, dx, dy, + dirtyX, dirtyY, dirtyWidth, and dirtyHeight.

          When the last four arguments to this method are omitted, they must be assumed to have the values 0, 0, the width member of the imagedata structure, and the height @@ -70448,8 +70460,9 @@ try {

        5. If IsDetachedBuffer(buffer) is true, then throw an "InvalidStateError" DOMException.

        6. -
        7. If layer-count is not zero, then throw an - "InvalidStateError" DOMException.

        8. +
        9. If this's layer count is not + zero, then throw an "InvalidStateError" + DOMException.

        10. If dirtyWidth is negative, then let dirtyX be imagedata data structure's Canvas Pixel ArrayBuffer to the pixel with coordinate (dx+x, dy+y) - in the rendering context's output bitmap.

        11. + in this's top level output bitmap.

        Due to the lossy nature of converting between color spaces and converting to and @@ -70668,9 +70681,9 @@ console.log(pixels.data[2]);

        The global alpha value gives an alpha value - that is applied to shapes and images before they are composited onto the output bitmap. - The value ranges from 0.0 (fully transparent) to 1.0 (no additional transparency). It must - initially have the value 1.0.

        + that is applied to shapes and images before they are composited onto the current output + bitmap. The value ranges from 0.0 (fully transparent) to 1.0 (no additional transparency). + It must initially have the value 1.0.

        The globalAlpha getter steps are to return @@ -70687,7 +70700,7 @@ console.log(pixels.data[2]);

      The current compositing and blending operator value controls how shapes and images - are drawn onto the output bitmap, once they have had the current output bitmap, once they have had the global alpha and the current transformation matrix applied. Initially, it must be set to "source-over".

      @@ -70965,7 +70978,7 @@ console.log(pixels.data[2]); one canvas coordinate space unit. Filter coordinates are not affected by the current transformation matrix. The current transformation matrix affects only the input to the filter. Filters are applied in the - output bitmap's coordinate space.

      + current output bitmap's coordinate space.

      @@ -71035,16 +71048,15 @@ console.log(pixels.data[2]); using the current shadow styles, creating image C.

    4. When shadows are drawn, composite C within the - clipping region over the current output bitmap using the current + clipping region over the current output bitmap using the current compositing and blending operator.

    5. -
    6. Composite B within the clipping region over the current - output bitmap using the current compositing and blending - operator.

    7. +
    8. Composite B within the clipping region over the current + output bitmap using the current compositing and blending operator.

    -

    When compositing onto the output bitmap, pixels that would fall outside of the - output bitmap must be discarded.

    +

    When compositing onto the current output bitmap, pixels that would fall outside of + the current output bitmap must be discarded.

    @@ -71802,7 +71814,7 @@ interface OffscreenCanvas : EventTarget {
  • If this OffscreenCanvas object's context mode is 2d and the rendering context's layer-count is not zero, then return a promise + data-x="concept-canvas-layer-count">layer count is not zero, then return a promise rejected with an "InvalidStateError" DOMException.

    @@ -71866,6 +71878,12 @@ interface OffscreenCanvas : EventTarget { data-x="offscreencanvas-context-none">none, then throw an "InvalidStateError" DOMException.

  • +
  • If this OffscreenCanvas object's context mode is 2d and the rendering context's layer count is not zero, then throw an + "InvalidStateError" DOMException.

  • +
  • Let image be a newly created ImageBitmap object that references the same underlying bitmap data as this OffscreenCanvas object's bitmap.

  • From 9d4d816a10560a6cfb9db3001a65f89fd1ad0de9 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Thu, 9 Nov 2023 14:51:27 +0900 Subject: [PATCH 03/15] Fix syntax --- source | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source b/source index 22bcb483947..87c3e715325 100644 --- a/source +++ b/source @@ -66102,7 +66102,7 @@ context.fillRect(100,0,50,50); // only this square remains
    1. Let type be the type listed for attrName in Filter - Effects.

    2. + Effects. FILTERS

    3. If type is "false | true", then return boolean.

    4. @@ -66192,7 +66192,7 @@ context.fillRect(100,0,50,50); // only this square remains
      • key is not the local name of an attribute listed for the filter - primitive given by xmlName

      • + primitive given by xmlName FILTERS

      • key is the local name of a core attribute

      • From 5caa39a63da1d47e3c78578ee445811c758dd087 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Gravel Date: Thu, 9 Nov 2023 10:48:29 -0500 Subject: [PATCH 04/15] Fixed editorial issues --- source | 62 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/source b/source index 87c3e715325..c0ffaaa9a8d 100644 --- a/source +++ b/source @@ -65092,7 +65092,7 @@ typedef record<DOMString, any> CanvasFilterPrimitive; typedef (DOMString or CanvasFilterPrimitive or sequence<CanvasFilterPrimitive>) CanvasFilterInput; dictionary BeginLayerOptions { - CanvasFilterInput? filter = null; + CanvasFilterInput? filter; }; interface mixin CanvasLayers { @@ -65390,11 +65390,11 @@ interface Path2D { top level output bitmap is the bitmap that gets presented to the user in the update the rendering step of the event loop. The current output bitmap is - the bitmap to which most CanvasRenderingContext2D operations are drawing.

        + the bitmap to which most CanvasRenderingContext2D operations are drawing.

        The CanvasRenderingContext2D's current output bitmap can be replaced - and restored by calls to beginLayer and endLayer, with the drawing state stack + and restored by calls to beginLayer() and endLayer(), with the drawing state stack keeping track of all active nested output bitmaps. The CanvasRenderingContext2D object has a layer count integer that is initially set to zero, @@ -65402,7 +65402,7 @@ interface Path2D {

        The output bitmap objects have an origin-clean flag, which can be set to true or false. - Initially, when one of these bitmaps are created, their origin-clean flag must be set to true.

        The CanvasRenderingContext2D object also has an Path2D { always results in opaque black pixels, every fourth byte from getImageData() is always 255, the putImageData() method effectively ignores every - fourth byte in its input, and so on. However, the alpha component of styles, images and layers - drawn onto the canvas are still honoured up to the point where they would impact the top + fourth byte in its input, and so on. However, the alpha component of styles, images, and layers + drawn onto the canvas are still honored up to the point where they would impact the top level output bitmap's alpha channel; for instance, drawing a 50% transparent white square on a freshly created top level output bitmap with its alpha set to false will result in a fully-opaque gray @@ -65801,18 +65801,18 @@ context.fillRect(100,0,50,50); // only this square remains

        To reset the rendering context to its default state:

          -
        1. Clear this's drawing state stack.

        2. +
        3. Clear this's drawing state stack.

        4. -
        5. Set this's current output bitmap to be a reference to - this's top level output bitmap.

        6. +
        7. Set this's current output bitmap to be a reference to + this's top level output bitmap.

        8. -
        9. Set this's top level output bitmap's origin-clean flag to true.

        10. +
        11. Set this's top level output bitmap's origin-clean flag to true.

        12. -
        13. Set this's layer count to - zero.

        14. +
        15. Set this's layer count to + zero.

        16. -
        17. Clear canvas's bitmap to transparent black.

        18. +
        19. Clear canvas's bitmap to transparent black.

        20. Empty the list of subpaths in context's current default path.

        21. @@ -65831,14 +65831,14 @@ context.fillRect(100,0,50,50); // only this square remains

          Objects that implement the CanvasLayers mixin have methods (defined in this section) for managing a stack of output bitmaps.

          -

          Layers are opened and closed using beginLayer - and endLayer. When a layer is opened, the context's +

          Layers are opened and closed using beginLayer() + and endLayer(). When a layer is opened, the context's current output bitmap is aliased to that layer's output bitmap, such that all draw calls performed while the layer is active will effectively render onto the layer's - output bitmap. When endLayer is called, - the layer's output bitmap gets filtered using the output bitmap. When endLayer() is + called, the layer's output bitmap gets filtered using the filter specified in beginLayer and composited in the parent's + data-x="dom-context-2d-beginLayer">beginLayer() and composited in the parent's output bitmap using the layer rendering states.

          @@ -65890,10 +65890,10 @@ context.fillRect(100,0,50,50); // only this square remains

          Filters specified via context.filter are not part of the layer rendering states and are therefore not applied on the layer's output bitmap. The preferred way to specify filters is to use beginLayer. Using beginLayer(). Using context.filter is inefficient because it requires each individual draw call to be wrapped in a layer. It's better to make this cost explicit by using - beginLayer.

          + beginLayer().

          CanvasFilterInput is used for describing CSS or SVG filters using JavaScript. A @@ -65932,7 +65932,7 @@ context.fillRect(100,0,50,50); // only this square remains resulting texture to the parent surface (the canvas or the parent layer). The layer's filter, if specified, gets applied, along with the global rendering states as they were when beginLayer was called.

          + data-x="dom-context-2d-beginLayer">beginLayer() was called.

          @@ -65957,8 +65957,8 @@ context.fillRect(100,0,50,50); // only this square remains with parent output bitmap set to currentOutputBitmap and resolved layer filter set to resolvedLayerFilter.

          -

          Push a copy of the current drawing state onto this's - drawing state stack.

          +
        22. Push a copy of the current drawing state onto this's + drawing state stack.

        23. Reset this's layer rendering states to their default value.

        24. @@ -65967,7 +65967,7 @@ context.fillRect(100,0,50,50); // only this square remains state to layerState.

        25. Set this's current output bitmap to - layerOutputBitmap

        26. + layerOutputBitmap.

        27. Increment this's layer count by one.

        28. @@ -65987,10 +65987,10 @@ context.fillRect(100,0,50,50); // only this square remains DOMException.

        29. Let layerOutputBitmap be this's current output - bitmap

        30. + bitmap.

        31. Let parentOutputBitmap be - layerState's parent output bitmap

        32. + layerState's parent output bitmap.

        33. If layerOutputBitmap is marked as not origin-clean, then set the to false.

        34. Set this's current output bitmap to - parentOutputBitmap

        35. + parentOutputBitmap.

        36. Let filteredLayerOutputBitmap be the result of running the steps to apply a resolved layer filter to layerOutputBitmap given @@ -66040,7 +66040,7 @@ context.fillRect(100,0,50,50); // only this square remains

          A resolved filter can either be the string - "none", a string parseable as a <filter-value-list> or + "none", a string parseable as a <filter-value-list>, or an XML filter list.

          The steps for resolving a layer @@ -66265,7 +66265,7 @@ context.fillRect(100,0,50,50); // only this square remains

        -
      • return xmlFilters
      • +
      • Return xmlFilters.

    The steps to apply a resolved layer filter to an image given a Date: Fri, 31 May 2024 16:29:52 -0400 Subject: [PATCH 05/15] Remove XML CanvasFilter from initial layer spec This will be moved to a separate pull request. --- source | 317 +++++---------------------------------------------------- 1 file changed, 25 insertions(+), 292 deletions(-) diff --git a/source b/source index c0ffaaa9a8d..f3351e13209 100644 --- a/source +++ b/source @@ -65088,8 +65088,7 @@ interface mixin CanvasState { boolean isContextLost(); // return whether context is lost }; -typedef record<DOMString, any> CanvasFilterPrimitive; -typedef (DOMString or CanvasFilterPrimitive or sequence<CanvasFilterPrimitive>) CanvasFilterInput; +typedef DOMString CanvasFilterInput; dictionary BeginLayerOptions { CanvasFilterInput? filter; @@ -65896,11 +65895,9 @@ context.fillRect(100,0,50,50); // only this square remains beginLayer().

    -

    CanvasFilterInput is used for describing CSS or SVG filters using JavaScript. A - CanvasFilterInput can either be a CSS filter string or an object that can be - converted to an equivalent XML filter list. - An XML filter list is a list of - XML element data for filters that fully describes an SVG filter network.

    +

    CanvasFilterInput is used to describe the layer's filter. A + CanvasFilterInput can either be the string "none" or as a + string parseable as a <filter-value-list>.

    context. specified, the filter effect is applied to the layer's resulting texture as it's drawn to the parent output bitmap.

    -

    Filters are specified as either be the string "none", as a string - parseable as a <filter-value-list>, as a single - CanvasFilterPrimitive or as an array of CanvasFilterPrimitives (to - chain filter effects).

    - -

    CanvasFilterPrimitive objects have a name property, whose - value is one of the supported filter names, and additional properties corresponding - to the settings of the filter. These latter properties are the same as the XML attribute names - when using the corresponding SVG filter.

    +

    Filters are specified as either the string "none", or as a CSS filter + string.

    context.endLayer()
    @@ -66040,304 +66030,47 @@ context.fillRect(100,0,50,50); // only this square remains

    A resolved filter can either be the string - "none", a string parseable as a <filter-value-list>, or - an XML filter list.

    + "none", or a string parseable as a + <filter-value-list>.

    The steps for resolving a layer filter given a CanvasFilterInput filter are:

      -
    1. -

      If filter is a string, then:

      -
        -
      1. If filter is "none", then return "none".

      2. - -
      3. Let parsedValue be the result of parsing filter as a - <filter-value-list>.

      4. - -
      5. If parsedValue is failure, then return "none".

      6. - -
      7. If any property-independent style sheet syntax like 'inherit' or 'initial' is present - in parsedValue, then return "none".

      8. - -
      9. If parsedValue references filters externally-defined in documents that - are not currently loaded, return "none".

      10. - -
      11. Return parsedValue.

      12. -
      -
    2. - -
    3. Otherwise, return the results of running the steps for building an XML filter list - given filter.

    4. -
    - -

    The steps for building an XML - filter list require the following definitions:

    - -

    The supported filter names are - "colorMatrix", - "componentTransfer", - "convolveMatrix", - "dropShadow" and - "gaussianBlur". - -

    The XML element data for filters is a struct, with the following items:

    - -
      -
    • A string name

    • - -
    • An ordered map of strings to strings attributes

    • - -
    • A list of XML element data for filters children

    • -
    - -

    To get the IDL type for a canvas filter attribute attrName:

    - -
      -
    1. Let type be the type listed for attrName in Filter - Effects. FILTERS

    2. - -
    3. If type is "false | true", then return boolean.

    4. - -
    5. If type is "list of <number>s", then return sequence<double>.

    6. - -
    7. If type is "<number>", then return double.

    8. - -
    9. If type is "<integer>", then return long long.

    10. - -
    11. If type is "<number-optional-number>", then - return (double or sequence<double>).

    12. - -
    13. Return DOMString.

    14. -
    - -

    To generate an XML value from a key, - value pair: - -

      -
    1. Let type be the result of getting the IDL type for a canvas filter - attribute for key.

    2. - -
    3. Let idlValue be the result of converting value to type.

    4. - -
    5. If type is (double or sequence<double>), - value is a sequence<double> and value doesn't have two elements, - throw a TypeError exception.

    6. - -
    7. Let xmlValue be the result of converting idlValue to an ECMAScript value, and - then converting that result to a DOMString.

    8. - -
    9. Return xmlValue.

    10. -
    - -

    The steps for building an - XML filter list given - filters are:

    - -
      -
    1. Let xmlFilters be an empty list.

    2. - -
    3. If filters is null, then set filters to « ».

    4. - -
    5. If filters is a CanvasFilterPrimitive, then set filters - to « filters ».

    6. - -
    7. -

      For each filterDict of filters:

      - -
        -
      1. If filterDict["name"] does not exist, then throw a TypeError exception.

      2. - -
      3. Let filterName be the value of filterDict["name"].

      4. - -
      5. If filterName is not one of supported filter names, then - continue.

      6. - -
      7. Let xmlName be the concatenation of "fe", the first - code unit of filterName converted to ASCII uppercase, - and all code units of filterName after the first - one.

      8. - -
      9. Let xmlFilter be a new XML element data for filters whose name is xmlName, whose attributes is an empty ordered map, and whose children is an empty list.

      10. - -
      11. Append xmlFilter to - xmlFilters.

      12. - -
      13. -

        For each keyvalue of - filterDict:

        - -
          -
        1. -

          If any of the following are true:

          - -
            -
          • key is not the local name of an attribute listed for the filter - primitive given by xmlName FILTERS

          • - -
          • key is the local name of a core attribute

          • - -
          • key is the local name of a presentation attribute other - than 'flood-color' and 'flood-opacity'

          • - -
          • key is the local name of a filter primitive - attribute

          • - -
          • key contains U+003A (:)

          • -
          - -

          then continue.

          -
        2. - -
        3. -

          If key is one of "funcR", "funcG", "funcB", "funcA":

          - -
            -
          1. Set value to the result of - converting value to record<DOMString, - any>.

          2. - -
          3. Let xmlTransferName be the concatenation of "fe", - the first code unit of key converted to ASCII - uppercase, and all code units of key - after the first one.

          4. - -
          5. Let transferFunction be a new XML element data for filters - whose name is xmlTransferName, whose - attributes is an empty ordered map, and whose - children is an empty list.

          6. - -
          7. -

            For each transferNametransferValue of value:

            - -
              -
            1. Let transferFunctionValue be the result of generating an XML value from transferName - and transferValue.

            2. +
            3. If filter is "none", then return "none".

            4. -
            5. Set transferFunction's attributes[transferName] to - transferFunctionValue.

            6. -
            -
          8. +
          9. Let parsedValue be the result of parsing filter as a + <filter-value-list>.

          10. -
          11. Append transferFunction to xmlFilter's children.

          12. -
          -
        4. +
        5. If parsedValue is failure, then return "none".

        6. -
        7. -

          Otherwise:

          +
        8. If any property-independent style sheet syntax like 'inherit' or 'initial' is present + in parsedValue, then return "none".

        9. -
            -
          1. Let attrXMLValue be the result of generating an XML value from key and - value.

          2. +
          3. If parsedValue references filters externally-defined in documents that + are not currently loaded, return "none".

          4. -
          5. Set xmlFilter's attributes[key] to - attrXMLValue.

          6. -
          - -
        -
      14. -
      -
    8. - -
    9. Return xmlFilters.
    10. +
    11. Return parsedValue.

    The steps to apply a resolved layer filter to an image given a resolvedFilter are:

      -
    1. -

      If filter is a string, then:

      -
        -
      1. If resolvedFilter is "none", return - image.

      2. +
      3. If resolvedFilter is "none", return + image.

      4. -
      5. Let filteredImage be the result of applying the resolvedFilter - <filter-value-list> to image in the same manner as SVG - would.

      6. -
      -
    2. - -
    3. Else, let filteredImage be the result of running the steps to apply an - XML filter list on image given resolvedFilter.

    4. +
    5. Let filteredImage be the result of applying the resolvedFilter + <filter-value-list> to image in the same manner as SVG + would.

    6. Return filteredImage.

    -

    The steps to apply an XML filter list, given an image and an XML filter list filters are:

    -
      -
    1. -

      For each filter of filters:

      -
        -
      1. Let svgFilter be an SVG filter, obtained by mapping each attributes of the filter XML filter list to the SVG equivalent.

      2. - -
      3. Render image using svgFilter, creating - filteredImage.

      4. - -
      5. Set image to filteredImage

      6. -
      -
    2. - -
    3. Return image.

    4. -
    -
    -
    -

    The following example will create a layer with a colorMatrix - filter that swaps the green and red channels, then blurs the result by 5 pixels:

    - -
    // canvas is a reference to a <canvas> element
    -const context = canvas.getContext('2d');
    -context.beginLayer({filter: [
    -  {
    -    name: 'colorMatrix',
    -    type: 'matrix',
    -    values: [
    -      0, 1, 0, 0, 0,
    -      1, 0, 0, 0, 0,
    -      0, 0, 1, 0, 0,
    -      0, 0, 0, 1, 0
    -    ],
    -  },
    -  {
    -    name: 'gaussianBlur',
    -    stdDeviation: 5,
    -  }
    -]});
    -
    - -

    Currently, CanvasFilterInputs can only be linear sequences of - filters. Full filter graphs are a planned expansion of this feature.

    -
    Line styles
    From 9dafd05c4ffbcd4f6906fc5011bfcce2cb5db064 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Gravel Date: Fri, 16 Aug 2024 12:26:06 -0400 Subject: [PATCH 06/15] Add ctx.filter to the layer rendering states With this change, the context filters now applies to the layer's output bitmap and is resetted to "none" when entering layers. --- source | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/source b/source index f3351e13209..c5f44e5de3e 100644 --- a/source +++ b/source @@ -65863,9 +65863,9 @@ context.fillRect(100,0,50,50); // only this square remains
    • The current clipping region.
    • -
    • The current global alpha and - compositing and blending - operator.
    • +
    • The current filter, global alpha, and compositing and blending operator.
    • The current values of the following attributes: shadowOffsetX, @@ -65997,19 +65997,9 @@ context.fillRect(100,0,50,50); // only this square remains
    • Let parentDrawingStates be the result of popping this's drawing state stack.

    • -
    • Reset all of this's drawing states to - their default values.

    • - -
    • Set this's layer rendering states to the values stored in - parentDrawingState.

    • - -
    • Draw filteredLayerOutputBitmap onto this's current output +

    • Draw filteredlayerOutputBitmap onto this's current output bitmap using the steps outlined in the drawing model.

    • -
    • Set this's drawing states that are not - layer rendering states to the values they have in - parentDrawingStates.

    • -
    • Decrement this's layer count by one.

    • From 809c6500f47a87d915ace4f95d7778cebe4d2547 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Gravel Date: Fri, 16 Aug 2024 12:39:57 -0400 Subject: [PATCH 07/15] Remove BeginLayerOptions This removes the filter argument of the beginLayer API. BeginLayerOptions can possibliy be added to the specification as a follow-up. --- source | 106 +++++---------------------------------------------------- 1 file changed, 9 insertions(+), 97 deletions(-) diff --git a/source b/source index c5f44e5de3e..255e03525b2 100644 --- a/source +++ b/source @@ -65088,15 +65088,9 @@ interface mixin CanvasState { boolean isContextLost(); // return whether context is lost }; -typedef DOMString CanvasFilterInput; - -dictionary BeginLayerOptions { - CanvasFilterInput? filter; -}; - interface mixin CanvasLayers { // layers - undefined beginLayer(optional BeginLayerOptions options = {}); + undefined beginLayer(); undefined endLayer(); }; @@ -65835,23 +65829,18 @@ context.fillRect(100,0,50,50); // only this square remains current output bitmap is aliased to that layer's output bitmap, such that all draw calls performed while the layer is active will effectively render onto the layer's output bitmap. When endLayer() is - called, the layer's output bitmap gets filtered using the filter specified in beginLayer() and composited in the parent's - output bitmap using the layer rendering states.

      + called, the layer's output bitmap gets composited in the parent's output + bitmap using the layer rendering states.

      The drawing state stack keeps track of opened layers by holding canvas layer state structs containing the following items:

      + data-x="struct item">item:

      • parent output bitmap, the layer's parent output bitmap.
      • - -
      • resolved layer filter, the layer's resolved filter.
      @@ -65885,44 +65874,21 @@ context.fillRect(100,0,50,50); // only this square remains smoothed, it would require resampling of the layer's output bitmap, lowering picture quality for every layer nesting levels. It's better to transform and smooth the innermost layer content and draw pixels directly to their final coordinate.

      - -

      Filters specified via context.filter are not part - of the layer rendering states and are therefore not applied on the layer's - output bitmap. The preferred way to specify filters is to use beginLayer(). Using context.filter is inefficient because it requires each - individual draw call to be wrapped in a layer. It's better to make this cost explicit by using - beginLayer().

      -

      CanvasFilterInput is used to describe the layer's filter. A - CanvasFilterInput can either be the string "none" or as a - string parseable as a <filter-value-list>.

      -
      context.beginLayer()
      -
      context.beginLayer({ filter })

      Pushes the current state onto the stack and starts a new layer. While a layer is active, all draw calls are performed on a separate surface, which will later be drawn as a whole to the canvas (or parent layer) when the layer is closed.

      -

      If the filter member is - specified, the filter effect is applied to the layer's resulting texture as it's drawn to the - parent output bitmap.

      - -

      Filters are specified as either the string "none", or as a CSS filter - string.

      -
      context.endLayer()

      Pops the top state off the stack, restores the context to that state and draws the layer's - resulting texture to the parent surface (the canvas or the parent layer). The layer's filter, if specified, gets applied, - along with the global rendering states as they were when beginLayer() was called.

      + resulting texture to the parent surface (the canvas or the parent layer) using the global + rendering states as they were when beginLayer() + was called.

      @@ -65938,14 +65904,8 @@ context.fillRect(100,0,50,50); // only this square remains initialized with an origin-clean flag set to true.

      -
    • Let resolvedLayerFilter be the result of running the steps for resolving the layer filter - given options["filter"].

    • -
    • Let layerState be a new canvas layer state object, initialized - with parent output bitmap set to currentOutputBitmap and resolved - layer filter set to resolvedLayerFilter.

    • + with parent output bitmap set to currentOutputBitmap.

    • Push a copy of the current drawing state onto this's drawing state stack.

    • @@ -65990,14 +65950,10 @@ context.fillRect(100,0,50,50); // only this square remains
    • Set this's current output bitmap to parentOutputBitmap.

    • -
    • Let filteredLayerOutputBitmap be the result of running the steps to apply - a resolved layer filter to layerOutputBitmap given - layerState's resolved layer filter.

    • -
    • Let parentDrawingStates be the result of popping this's drawing state stack.

    • -
    • Draw filteredlayerOutputBitmap onto this's current output +

    • Draw layerOutputBitmap onto this's current output bitmap using the steps outlined in the drawing model.

    • Decrement this's layer count @@ -66017,50 +65973,6 @@ context.fillRect(100,0,50,50); // only this square remains data-x="dom-context-2d-save">save()?) For that reason, invalid API sequences involving layers throw exceptions to make the issue clear to web developers.

      -
      - -

      A resolved filter can either be the string - "none", or a string parseable as a - <filter-value-list>.

      - -

      The steps for resolving a layer - filter given a CanvasFilterInput filter are:

      - -
        -
      1. If filter is "none", then return "none".

      2. - -
      3. Let parsedValue be the result of parsing filter as a - <filter-value-list>.

      4. - -
      5. If parsedValue is failure, then return "none".

      6. - -
      7. If any property-independent style sheet syntax like 'inherit' or 'initial' is present - in parsedValue, then return "none".

      8. - -
      9. If parsedValue references filters externally-defined in documents that - are not currently loaded, return "none".

      10. - -
      11. Return parsedValue.

      12. -
      - -

      The steps to apply a resolved layer filter to an image given a resolvedFilter are:

      -
        -
      1. If resolvedFilter is "none", return - image.

      2. - -
      3. Let filteredImage be the result of applying the resolvedFilter - <filter-value-list> to image in the same manner as SVG - would.

      4. - -
      5. Return filteredImage.

      6. -
      - -
      -
      Line styles
      From 1630ffaf0d819ac0b9fa360f7f905c9d09035ac7 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Gravel Date: Tue, 10 Sep 2024 14:11:10 -0400 Subject: [PATCH 08/15] Clarify what type of bitmaps are used across the canvas spec The HTMLCanvasElement's bitmap was linkified to clarify to which bitmap each uses of the word "bitmap" refers to (either the element's bitmap, the context's top level output bitmap or the context's current output bitmap). --- source | 162 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 89 insertions(+), 73 deletions(-) diff --git a/source b/source index 255e03525b2..d5f1d21aa9f 100644 --- a/source +++ b/source @@ -64502,8 +64502,9 @@ callback BlobCallback = undefined (Blob? blob);
      Uses HTMLCanvasElement.
      -

      The canvas element provides scripts with a resolution-dependent bitmap canvas, - which can be used for rendering graphs, game graphics, art, or other visual images on the fly.

      +

      The canvas element provides scripts with a resolution-dependent bitmap canvas, which can be used for rendering graphs, game graphics, + art, or other visual images on the fly.

      Authors should not use the canvas element in a document when a more suitable element is available. For example, it is inappropriate to use a canvas element to @@ -64513,23 +64514,25 @@ callback BlobCallback = undefined (Blob? blob);

      When authors use the canvas element, they must also provide content that, when presented to the user, conveys essentially the same function or purpose as the - canvas's bitmap. This content may be placed as content of the canvas - element. The contents of the canvas element, if any, are the element's fallback - content.

      + canvas's bitmap. This content may be placed as + content of the canvas element. The contents of the canvas element, if + any, are the element's fallback content.


      In interactive visual media, if scripting is enabled for the canvas element, and if support for canvas elements has been enabled, then the canvas element represents embedded content - consisting of a dynamically created image, the element's bitmap.

      + consisting of a dynamically created image, the element's + bitmap.

      In non-interactive, static, visual media, if the canvas element has been previously associated with a rendering context (e.g. if the page was viewed in an interactive visual medium and is now being printed, or if some script that ran during the page layout process painted on the element), then the canvas element represents - embedded content with the element's current bitmap and size. Otherwise, the element - represents its fallback content instead.

      + embedded content with the element's current + bitmap and size. Otherwise, the element represents its fallback content + instead.

      In non-visual media, and in visual media if scripting is disabled for the canvas element or if support for canvas elements @@ -64552,16 +64555,16 @@ callback BlobCallback = undefined (Blob? blob);


      -

      The canvas element has two attributes to control the size of the element's bitmap: - width and height. These attributes, - when specified, must have values that are valid - non-negative integers. The rules for parsing non-negative - integers must be used to obtain their numeric - values. If an attribute is missing, or if parsing its value returns an error, then the - default value must be used instead. The width - attribute defaults to 300, and the height attribute - defaults to 150.

      +

      The canvas element has two attributes to control the size of the element's bitmap: width and height. These attributes, when specified, must have + values that are valid non-negative integers. + The rules for parsing non-negative integers must be used to obtain their numeric values. If an attribute is missing, or + if parsing its value returns an error, then the default value must be used instead. The + width attribute defaults to 300, and the height attribute defaults to 150.

      When setting the value of the width or height attribute, if the BlobCallback = undefined (Blob? blob);

      The natural dimensions of the canvas element when it represents embedded content are equal to the dimensions of the - element's bitmap.

      + element's bitmap.

      The user agent must use a square pixel density consisting of one pixel of image data per - coordinate space unit for the bitmaps of a canvas and its rendering contexts.

      + coordinate space unit for the bitmaps of a canvas + and its rendering contexts.

      A canvas element can be sized arbitrarily by a style sheet, its - bitmap is then subject to the 'object-fit' CSS property.

      + bitmap is then subject to the 'object-fit' CSS + property.


      -

      The bitmaps of canvas elements, the bitmaps of ImageBitmap objects, - as well as some of the bitmaps of rendering contexts, such as those described in the sections on - the CanvasRenderingContext2D and ImageBitmapRenderingContext objects - below, have an origin-clean flag, which can be - set to true or false. Initially, when the canvas element or ImageBitmap +

      The bitmaps of canvas elements, the bitmaps of + ImageBitmap objects, as well as some of the bitmaps of rendering contexts, such as + those described in the sections on the CanvasRenderingContext2D and + ImageBitmapRenderingContext objects below, have an origin-clean flag, which can be set to true or false. + Initially, when the canvas element or ImageBitmap object is created, its bitmap's origin-clean flag must be set to true.

      @@ -64606,13 +64612,13 @@ callback BlobCallback = undefined (Blob? blob);

      When its canvas context mode is none, a canvas element has no rendering context, - and its bitmap must be transparent black with a natural width equal - to the numeric value of the element's width attribute and a natural height equal to - the numeric value of the element's height attribute, those values being interpreted in CSS pixels, and being updated as the attributes are set, changed, or - removed.

      + and its bitmap must be transparent black with a + natural width equal to the numeric value + of the element's width attribute and a natural + height equal to the numeric value of the + element's height attribute, those values being + interpreted in CSS pixels, and being updated as the attributes are set, + changed, or removed.

      When its canvas context mode is placeholder, a canvas element has no @@ -64622,7 +64628,8 @@ callback BlobCallback = undefined (Blob? blob);

      When a canvas element represents embedded content, it provides a paint source whose width is the element's natural width, whose height - is the element's natural height, and whose appearance is the element's bitmap.

      + is the element's natural height, and whose appearance is the element's bitmap.

      Whenever the width and height content attributes are set, removed, changed, or @@ -64932,13 +64939,13 @@ callback BlobCallback = undefined (Blob? blob); data-x="concept-canvas-layer-count">layer count different than zero, then throw an "InvalidStateError" DOMException.

      -
    • If this canvas element's bitmap's

      If this canvas element's bitmap's origin-clean flag is set to false, then throw a "SecurityError" DOMException.

      -
    • If this canvas element's bitmap has no pixels (i.e. either its horizontal - dimension or its vertical dimension is zero) then return the string "data:,". (This is the shortest canvas element's bitmap has no + pixels (i.e. either its horizontal dimension or its vertical dimension is zero) then return the + string "data:,". (This is the shortest data: URL; it represents the empty string in a text/plain resource.)

    • @@ -64964,15 +64971,16 @@ callback BlobCallback = undefined (Blob? blob); data-x="concept-canvas-layer-count">layer count different than zero, then throw an "InvalidStateError" DOMException.

      -
    • If this canvas element's bitmap's

      If this canvas element's bitmap's origin-clean flag is set to false, then throw a "SecurityError" DOMException.

    • Let result be null.

    • -
    • If this canvas element's bitmap has pixels (i.e., neither its horizontal - dimension nor its vertical dimension is zero), then set result to a copy of this - canvas element's bitmap. +

    • If this canvas element's bitmap has + pixels (i.e., neither its horizontal dimension nor its vertical dimension is zero), then set + result to a copy of this canvas element's + bitmap.

    • Run these steps in parallel:

      @@ -65380,8 +65388,9 @@ interface Path2D {

      A CanvasRenderingContext2D object has a top level output bitmap and a current output bitmap which both originally refer to the same output bitmap that is initialized when the CanvasRenderingContext2D is created. The - top level output bitmap is the bitmap that gets presented to the user in the update the + top level output bitmap is an alias for the canvas element's bitmap and is the bitmap that gets + presented to the user in the update the rendering step of the event loop. The current output bitmap is the bitmap to which most CanvasRenderingContext2D operations are drawing.

      @@ -65522,8 +65531,8 @@ interface Path2D { attribute to point to target.

    • Set context's top level output bitmap and current output - bitmap to the same bitmap as target's bitmap (so that they are - shared).

    • + bitmap to the same bitmap as target's + bitmap (so that they are shared).

    • Set bitmap dimensions to the numeric values of target's the createImageBitmap() factory method). In many cases, this will be more memory efficient.

      -

      The bitmap of a canvas element is the one bitmap that's pretty much always going - to be needed in practice. The top level output bitmap of a rendering context, when it - has one, is always just an alias to a canvas element's bitmap. When layers are - opened, draw calls operate on a separate current output bitmap that gets composited - to the parent output bitmap when the layer is closed. If the canvas - element's bitmap needs to be presented to the user - while layers are opened, the top level output bitmap is used, meaning that the - content of unclosed layers will not be presented. They will be presented in a later frame, if and - when the layers are closed.

      +

      The bitmap of a canvas element is the one + bitmap that's pretty much always going to be needed in practice. The top level output + bitmap of a rendering context, when it has one, is always just an alias to a + canvas element's bitmap. When layers are opened, + draw calls operate on a separate current output bitmap that gets composited to the + parent output bitmap when the layer is closed. If the canvas element's bitmap needs to be presented to the user while layers are opened, the + top level output bitmap is used, meaning that the content of unclosed layers will not + be presented. They will be presented in a later frame, if and when the layers are closed.

      Additional bitmaps are sometimes needed, e.g. to enable fast drawing when the canvas is being painted at a different size than its natural size, @@ -65799,14 +65809,14 @@ context.fillRect(100,0,50,50); // only this square remains

    • Set this's current output bitmap to be a reference to this's top level output bitmap.

    • +
    • Clear the top level output bitmap to transparent black.

    • +
    • Set this's top level output bitmap's origin-clean flag to true.

    • Set this's layer count to zero.

    • -
    • Clear canvas's bitmap to transparent black.

    • -
    • Empty the list of subpaths in context's current default path.

    • Reset everything that drawing state consists of to their initial @@ -68389,7 +68399,7 @@ try { (i.e., after any aspect-ratio correction has been applied).

      When a CanvasImageSource object represents an HTMLCanvasElement, the - element's bitmap must be used as the source image.

      + element's bitmap must be used as the source image.

      When a CanvasImageSource object represents an element that is being rendered and that element has been resized, the original image data of the source image @@ -68897,9 +68907,10 @@ try {

      Drawing rectangles to the bitmap

      Objects that implement the CanvasRect interface provide the following methods for - immediately drawing rectangles to the bitmap. The methods each take four arguments; the first two - give the x and y coordinates of the top left of the rectangle, and the - second two give the width w and height h of the rectangle, respectively.

      + immediately drawing rectangles to the current output bitmap. The methods each take + four arguments; the first two give the x and y coordinates of the top left + of the rectangle, and the second two give the width w and height h of the + rectangle, respectively.

      @@ -68919,18 +68930,19 @@ try {
      context.clearRect(x, y, w, h)
      -

      Clears all pixels on the bitmap in the given rectangle to transparent - black.

      +

      Clears all pixels on the current output bitmap in the given rectangle to + transparent black.

      context.fillRect(x, y, w, h)
      -

      Paints the given rectangle onto the bitmap, using the current fill style.

      +

      Paints the given rectangle onto the current output bitmap, using the current + fill style.

      context.strokeRect(x, y, w, h)
      -

      Paints the box that outlines the given rectangle onto the bitmap, using the current stroke - style.

      +

      Paints the box that outlines the given rectangle onto the current output bitmap, + using the current stroke style.

      @@ -69800,7 +69812,7 @@ try {
      imagedata = context.getImageData(sx, sy, sw, sh [, settings])

      Returns an ImageData object containing the image data for the given rectangle of - the bitmap. The color space of the returned object is the top level output bitmap. The color space of the returned object is the color space of context unless overridden by settings.

      @@ -69822,8 +69834,9 @@ try {
      context.putImageData(imagedata, dx, dy [, dirtyX, dirtyY, dirtyWidth, dirtyHeight ])
      -

      Paints the data from the given ImageData object onto the bitmap. If a dirty - rectangle is provided, only the pixels from that rectangle are painted.

      +

      Paints the data from the given ImageData object onto the top level output + bitmap. If a dirty rectangle is provided, only the pixels from that rectangle are + painted.

      The globalAlpha and globalCompositeOperation properties, as @@ -69840,7 +69853,7 @@ try {

      Objects that implement the CanvasImageData interface provide the following methods - for reading and writing pixel data to the bitmap.

      + for reading and writing pixel data to the top level output bitmap.

      The new ImageData(sw, sh, settings) constructor steps are:

      @@ -71013,7 +71026,8 @@ dictionary ImageBitmapRenderingContextSettings {
    • Set context's output bitmap to the same - bitmap as target's bitmap (so that they are shared).

    • + bitmap as target's bitmap (so that they are + shared).

    • Run the steps to set an ImageBitmapRenderingContext's output bitmap with context.

    • @@ -71591,7 +71605,8 @@ interface OffscreenCanvasRenderingContext2D {

      An OffscreenCanvasRenderingContext2D object has a bitmap that is initialized when the object is - created.

      + created. This bitmap plays the same role as + CanvasRenderingContext2D's top level output bitmap.

      The bitmap has an origin-clean flag, which can be set to true or @@ -71654,7 +71669,8 @@ interface OffscreenCanvasRenderingContext2D { created bitmap with the dimensions specified by the width and height attributes of target, and set - target's bitmap to the same bitmap (so that they are shared).

      + target's bitmap to the same bitmap (so that they + are shared).

    • If context's alpha flag is set to true, initialize all the pixels of context's Date: Mon, 23 Sep 2024 15:35:12 -0400 Subject: [PATCH 09/15] Add the current transform to the layer rendering states This means that when entering a layer, the current transform now is reset to the identity matrix. setTransform and getTransform are now local to the current layer, meaning that calling setTransform sets a matrix relative to the parent layer. --- source | 229 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 145 insertions(+), 84 deletions(-) diff --git a/source b/source index d5f1d21aa9f..c0f788035f1 100644 --- a/source +++ b/source @@ -65709,7 +65709,7 @@ context.fillRect(100,0,50,50); // only this square remains data-x="drawing state">Drawing states consist of:

        -
      • The current transformation +

      • The current transformation matrix and parents transformation matrix.

      • The current clipping region.

      • @@ -65749,8 +65749,9 @@ context.fillRect(100,0,50,50); // only this square remains

      The rendering context's bitmaps are not part of the drawing state - (with the exception of layer's parent output bitmap), as they depend on whether and how - the rendering context is bound to a canvas element.

      + (with the exception of layer's parent output bitmap held in the canvas layer + state), as they depend on whether and how the rendering context is bound to a + canvas element.

      Objects that implement the CanvasState mixin have a context lost boolean, that is initialized to false @@ -65759,10 +65760,11 @@ context.fillRect(100,0,50,50); // only this square remains

      context.save()
      -

      Pushes the current state onto the stack.

      +

      Pushes the current state onto the stack.

      context.restore()
      -

      Pops the top state on the stack, restoring the context to that state.

      +

      Pops the top state on the stack, restoring the context to + that state.

      context.reset()

      Resets the rendering context, which includes the backing buffer, the drawing state @@ -65849,8 +65851,7 @@ context.fillRect(100,0,50,50); // only this square remains data-x="struct item">item:

        -
      • parent output bitmap, the layer's parent - output bitmap.
      • +
      • parent output bitmap, the layer's parent output bitmap.
    • @@ -65860,6 +65861,8 @@ context.fillRect(100,0,50,50); // only this square remains output bitmap when it's drawn to its parent output bitmap. The layer rendering states are:

        +
      • The current transformation matrix.
      • +
      • The current clipping region.
      • The current filter,
      -

      Because the layer rendering states are applied on the layer's output, - they cannot also be applied to the layer's content, or else, they would be applied twice. These - states are therefore set to their default value when opening a layer.

      - -

      The transformation matrix and imageSmoothingEnabled are not part of - the layer rendering states because if the layer's output was to be transformed or - smoothed, it would require resampling of the layer's output bitmap, lowering picture - quality for every layer nesting levels. It's better to transform and smooth the innermost layer - content and draw pixels directly to their final coordinate.

      +

      Because the layer rendering states are applied on the layer's output, + they cannot also be applied to the layer's content, or else, they would be applied twice. These + states are therefore set to their default value when opening a layer.

      + +

      The current transformation matrix can conceptually be considered as applying + to the layer's output, as if the layer's output bitmap was transformed by the + parent's current transformation matrix and then drawn to the parent's output + bitmap when the layer is closed. In practice however, the current transformation + matrix doesn't need to be applied on the layer's output since shapes and images are always + drawn using the total transformation matrix, in particular those drawn using the + current default path, which is always pre-transformed.

      + +

      imageSmoothingEnabled is not part + of the layer rendering states because layers's output + bitmaps are not resampled when drawn to their parent output bitmap. If they + were resampled, the picture quality would lower for every nested layer subject to a non-identity + transform. Instead, pixels are drawn in layers at the exact coordinates they'll have in the + top level output bitmap, thus making sure that layers's pixels have a one-to-one + correspondance with their parent's.

      @@ -65917,8 +65929,8 @@ context.fillRect(100,0,50,50); // only this square remains
    • Let layerState be a new canvas layer state object, initialized with parent output bitmap set to currentOutputBitmap.

    • -
    • Push a copy of the current drawing state onto this's - drawing state stack.

    • +
    • Push a copy of the current drawing state + onto this's drawing state stack.

    • Reset this's layer rendering states to their default value.

    • @@ -65929,6 +65941,9 @@ context.fillRect(100,0,50,50); // only this square remains
    • Set this's current output bitmap to layerOutputBitmap.

    • +
    • Set this's parents transformation matrix to total transformation + matrix.

    • +
    • Increment this's layer count by one.

    • @@ -65963,6 +65978,9 @@ context.fillRect(100,0,50,50); // only this square remains
    • Let parentDrawingStates be the result of popping this's drawing state stack.

    • +
    • Set all of this's current drawing states + to the values they have in parentDrawingStates.

    • +
    • Draw layerOutputBitmap onto this's current output bitmap using the steps outlined in the drawing model.

    • @@ -65972,16 +65990,25 @@ context.fillRect(100,0,50,50); // only this square remains -

      For legacy reasons, calling restore() - when the drawing state stack is empty is a no-op. The addition of the layer API - however introduced several new potential pitfalls. For instance, scripts like context.save(); context.endLayer(); or context.beginLayer(); - context.restore(); are problematic. They are symptomatic of web page bugs and user agents - cannot silently fix these bugs on behalf of the page (e.g. did the page intend to call - endLayer() instead of restore(), or is there a missing save()?) For that reason, invalid API sequences involving - layers throw exceptions to make the issue clear to web developers.

      +
      +

      As described in the drawing model, shapes and images are subjected to the + total transformation matrix and are therefore written to layers at the final pixel + position they'll have in the top level output bitmap. Thus, when layers are closed, + pixels from the layer's output bitmap have a one to one correspondence with the + pixels in the parent's output bitmap and can therefore be directly drawn to the + parent without further transforms or resampling.

      + +

      For legacy reasons, calling restore() when the + drawing state stack is empty is a no-op. The addition of the layer API however + introduced several new potential pitfalls. For instance, scripts like context.save(); context.endLayer(); or context.beginLayer(); + context.restore(); are problematic. They are symptomatic of web page bugs and user agents + cannot silently fix these bugs on behalf of the page (e.g. did the page intend to call + endLayer() instead of restore(), or is there a missing save()?) For that reason, invalid API sequences involving + layers throw exceptions to make the issue clear to web developers.

      +
      Line styles
      @@ -67563,9 +67590,8 @@ try {

      For objects implementing the CanvasDrawPath and CanvasTransform interfaces, the points passed to the methods, and the resulting lines added to current - default path by these methods, must be transformed according to the current transformation matrix before being added to - the path.

      + default path by these methods, must be transformed according to the total + transformation matrix before being added to the path.

      The moveTo(x, y) method, when invoked, must run these steps:

      @@ -67665,9 +67691,8 @@ try { DOMException.

    • Let the point (x0, y0) be the last point in the subpath, transformed - by the inverse of the current transformation - matrix (so that it is in the same coordinate system as the points passed to the - method).

    • + by the inverse of the total transformation matrix (so that it is in the same + coordinate system as the points passed to the method).

    • If the point (x0, y0) is equal to the point (x1, y1), or if the point (x1, y1) is equal to the point @@ -68041,14 +68066,26 @@ try { -

      Transformations
      +
      Transformations

      Objects that implement the CanvasTransform interface have a current - transformation matrix, as well as methods (described in this section) to manipulate it. When - an object implementing the CanvasTransform interface is created, its transformation - matrix must be initialized to the identity matrix.

      - -

      The current transformation matrix is applied to coordinates when creating the + transformation matrix, a parents transformation matrix and a total + transformation matrix, as well as methods (described in this section) to manipulate the + current transformation matrix. The current transformation matrix + corresponds to the transformation local to the current layer. The parents transformation + matrix is the multiplication of the transforms of all the ancestors of the current layer. + The total transformation matrix encompases all transforms mapping drawn shapes and + images to the top level output bitmap and is always equals to the results of + multiplying the parents transformation matrix with the current transformation + matrix.

      + +

      When an object implementing the CanvasTransform interface is created, its + current transformation matrix and parents transformation matrix must be + initialized to the identity matrix. For objects not implementing the CanvasLayers + interface, the parents transformation matrix is always equal to the identity + matrix.

      + +

      The total transformation matrix is applied to coordinates when creating the current default path, and when painting text, shapes, and Path2D objects, on objects implementing the CanvasTransform interface.

      @@ -68692,8 +68729,8 @@ try {

      Linear gradients must be rendered such that all points on a line perpendicular to the line that crosses the start and end points have the color at the point where those two lines cross (with the colors coming from the interpolation and extrapolation described - above). The points in the linear gradient must be transformed as described by the current transformation matrix when rendering.

      + above). The points in the linear gradient must be transformed as described by the total + transformation matrix when rendering.

      If x0 = x1 and y0 = y1, then the linear @@ -68739,8 +68776,8 @@ try { of the first offset, the part of the cone after the end circle (1.0) using the color of the last offset, and areas outside the cone untouched by the gradient (transparent black).

      -

      The resulting radial gradient must then be transformed as described by the current transformation matrix when rendering.

      +

      The resulting radial gradient must then be transformed as described by the total + transformation matrix when rendering.

      The createConicGradient(startAngle, @@ -68882,8 +68919,8 @@ try {

    • Transform the resulting bitmap according to the pattern's transformation matrix.

    • -
    • Transform the resulting bitmap again, this time according to the current transformation matrix.

    • +
    • Transform the resulting bitmap again, this time according to the total + transformation matrix.

    • Replace any part of the image outside the area in which the pattern is to be rendered with transparent black.

    • @@ -68914,10 +68951,12 @@ try {
      -

      The current transformation matrix must be - applied to the following four coordinates, which form the path that must then be closed to get the - specified rectangle: (x, y), (x+w, y), (x+w, y+h), (x, y+h).

      +

      The total transformation matrix must be applied to the following four + coordinates, which form the path that must then be closed to get the specified rectangle: (x, y), (x+w, + y), (x+w, + y+h), (x, + y+h).

      Shapes are painted without affecting the current default path, and are subject to the clipping region, and, with the exception of .

    • -

      Paint the shapes given in glyphs, as transformed by the current transformation matrix, with each CSS pixel in the coordinate space of glyphs mapped to one - coordinate space unit.

      +

      Paint the shapes given in glyphs, as transformed by the total + transformation matrix, with each CSS pixel in the coordinate + space of glyphs mapped to one coordinate space unit.

      For fillText(), this's fill style must be applied to the @@ -69308,13 +69346,12 @@ try { Path2D object, or the current default path otherwise.

      When the intended path is a Path2D object, the coordinates and lines - of its subpaths must be transformed according to the current transformation matrix on the object - implementing the CanvasTransform interface when used by these methods (without - affecting the Path2D object itself). When the intended path is the current - default path, it is not affected by the transform. (This is because transformations - already affect the current default path when it is constructed, so applying it when - it is painted as well would result in a double transformation.)

      + of its subpaths must be transformed according to the total transformation matrix on + the object implementing the CanvasTransform interface when used by these methods + (without affecting the Path2D object itself). When the intended path is the + current default path, it is not affected by the transform. (This is because + transformations already affect the current default path when it is constructed, so + applying it when it is painted as well would result in a double transformation.)

      The fill(fillRule) method steps are to run the @@ -69414,7 +69451,7 @@ try {

    • If x or y are infinite or NaN, then return false.

    • If the point given by the x and y coordinates, when treated as - coordinates in the canvas coordinate space unaffected by the current transformation, is inside + coordinates in the canvas coordinate space unaffected by transformations, is inside the intended path for path as determined by the fill rule indicated by fillRule, then return true. Open subpaths must be implicitly closed when computing the area inside the path, without affecting the actual subpaths. Points on the path @@ -69443,7 +69480,7 @@ try {

    • If x or y are infinite or NaN, then return false.

    • If the point given by the x and y coordinates, when treated as - coordinates in the canvas coordinate space unaffected by the current transformation, is inside + coordinates in the canvas coordinate space unaffected by transformations, is inside the path that results from tracing the intended path for path, using the nonzero winding rule, and using @@ -69597,7 +69634,8 @@ try { data-x="concept-CanvasFillStrokeStyles-stroke-style">stroke style, or any of the members in the CanvasPathDrawingStyles, CanvasTextDrawingStyles interfaces, but should be subject to the clipping region. (The effect of - transformations is described above and varies based on which path is being used.)

      + transformations is described above and varies based on which path is being + used.)

    • Inform the user that the focus is at the location given by the @@ -69709,8 +69747,8 @@ try {

    • Paint the region of the image argument specified by the source rectangle on the region of the rendering context's current output bitmap specified by the - destination rectangle, after applying the current - transformation matrix to the destination rectangle.

      + destination rectangle, after applying the total transformation matrix to the + destination rectangle.

      The image data must be processed in the original direction, even if the dimensions given are negative. -

      The top level output bitmap, when it is not directly displayed by the user agent, +

      The top-level output bitmap, when it is not directly displayed by the user agent, implementations can, instead of updating this bitmap, merely remember the sequence of drawing operations that have been applied to it until such time as the bitmap's actual data is needed (for example because of a call to drawImage(), or @@ -65682,14 +65682,14 @@ context.fillRect(100,0,50,50); // only this square remains cases, this will be more memory efficient.

      The bitmap of a canvas element is the one - bitmap that's pretty much always going to be needed in practice. The top level output + bitmap that's pretty much always going to be needed in practice. The top-level output bitmap of a rendering context, when it has one, is always just an alias to a canvas element's bitmap. When layers are opened, draw calls operate on a separate current output bitmap that gets composited to the parent output bitmap when the layer is closed. If the canvas element's bitmap needs to be presented to the user while layers are opened, the - top level output bitmap is used, meaning that the content of unclosed layers will not + top-level output bitmap is used, meaning that the content of unclosed layers will not be presented. They will be presented in a later frame, if and when the layers are closed.

      Additional bitmaps are sometimes needed, e.g. to enable fast drawing when the canvas is being @@ -65700,8 +65700,8 @@ context.fillRect(100,0,50,50); // only this square remains

      The canvas state

      Objects that implement the CanvasState interface maintain a stack of drawing states, which is a stack of drawing - states. A drawing state consists of:

      + state stack">stack of drawing states, which is a stack of drawing states. A drawing state consists of:

      • A layer transformation matrix and parents transformation @@ -65746,17 +65746,17 @@ context.fillRect(100,0,50,50); // only this square remains

        The drawing state stack is initialized to an empty stack when the context is created. The context owns and uses a current instance of all the states in drawing state. The drawing state - stack is used to backup and restore the context's drawing states by storing + stack is used to backup and restore the context's drawing state by storing copies of the context's states.

        -

        Instead of the context owning a unique current instance of the drawing - states and initializing the drawing state stack to an empty stack - at context creation, implementation could equivalenty initialize the drawing state - stack with an initial drawing state item and - have the context use the drawing state stack's last item as the context's current - drawing state. In that case, drawing state would hold the context's - current output bitmap instead of canvas layer state having a - parent output bitmap.

        +

        Instead of the context owning a unique current drawing state instance + and initializing the drawing state stack to an empty stack at context + creation, implementations could equivalenty initialize the drawing state stack with + an initial drawing state item and have the context + use the drawing state stack's last item as the context's current drawing + state. In that case, drawing state would hold the context's current + output bitmap instead of canvas layer state having a parent output + bitmap.

        Objects that implement the CanvasState mixin have a context lost boolean, that is initialized to false @@ -65784,8 +65784,8 @@ context.fillRect(100,0,50,50); // only this square remains

        The save() method - steps are to push a copy of the this's current - drawing states onto this's drawing state stack.

        + steps are to push a copy of this's current + drawing state onto this's drawing state stack.

        The restore() method steps are:

        @@ -65798,11 +65798,11 @@ context.fillRect(100,0,50,50); // only this square remains state is not null, then throw an "InvalidStateError" DOMException.

      • -
      • Let previousDrawingStates be the result of

        Let previousDrawingState be the result of popping the drawing state stack.

      • -
      • Set all of this's current drawing states to the values they have - in previousDrawingStates.

      • +
      • Set this's current drawing state to + previousDrawingState.

      • The reset() @@ -65811,22 +65811,24 @@ context.fillRect(100,0,50,50); // only this square remains

        To reset the rendering context to its default state:

          -
        1. Clear this's drawing state stack.

        2. +
        3. Empty this's drawing state + stack.

        4. -
        5. Set this's current output bitmap to be a reference to - this's top level output bitmap.

        6. +
        7. Set this's current output bitmap to a reference of + this's top-level output bitmap.

        8. -
        9. Clear the top level output bitmap to transparent black.

        10. +
        11. Clear the top-level output bitmap to transparent black.

        12. -
        13. Set this's top level output bitmap's

          Set this's top-level output bitmap's origin-clean flag to true.

        14. Set this's layer count to - zero.

        15. + 0.

        16. Empty the list of subpaths in context's current default path.

        17. -
        18. Reset this's drawing states to their initial values.

        19. +
        20. Reset the items in this's drawing + state to their initial values.

        The bitmaps are not resampled when drawn to their parent output bitmap. If they were resampled, the picture quality would lower for every nested layer subject to a non-identity transform. Instead, pixels are drawn in layers at the exact coordinates they'll have in the - top level output bitmap, thus making sure that layers's pixels have a one-to-one + top-level output bitmap, thus making sure that layers's pixels have a one-to-one correspondance with their parent's.

    • @@ -65920,8 +65922,7 @@ context.fillRect(100,0,50,50); // only this square remains

      The beginLayer(options) method steps - are:

      + data-x="dom-context-2d-beginLayer">beginLayer() method steps are:

      1. Let currentOutputBitmap be this's @@ -65935,7 +65936,7 @@ context.fillRect(100,0,50,50); // only this square remains with parent output bitmap set to currentOutputBitmap.

      2. Push a copy of this's current drawing - states onto this's drawing state stack.

      3. + state onto this's drawing state stack.

      4. Reset this's layer rendering states to their default value.

      5. @@ -65984,8 +65985,8 @@ context.fillRect(100,0,50,50); // only this square remains
      6. Let parentDrawingStates be the result of popping this's drawing state stack.

      7. -
      8. Set all of this's current drawing states to the values they have - in parentDrawingStates.

      9. +
      10. Set this's current drawing state to + parentDrawingStates.

      11. Draw layerOutputBitmap onto this's current output bitmap using the steps outlined in the drawing model.

      12. @@ -65999,7 +66000,7 @@ context.fillRect(100,0,50,50); // only this square remains

        As described in the drawing model, shapes and images are subjected to the total transformation matrix and are therefore written to layers at the final pixel - position they'll have in the top level output bitmap. Thus, when layers are closed, + position they'll have in the top-level output bitmap. Thus, when layers are closed, pixels from the layer's output bitmap have a one to one correspondence with the pixels in the parent's output bitmap and can therefore be directly drawn to the parent without further transforms or resampling.

        @@ -68081,7 +68082,7 @@ try { corresponds to the transformation local to the current layer. The parents transformation matrix is the multiplication of the transforms of all the ancestors of the current layer. The total transformation matrix encompases all transforms mapping drawn shapes and - images to the top level output bitmap and is always equals to the results of + images to the top-level output bitmap and is always equals to the results of multiplying the parents transformation matrix with the layer transformation matrix.

        @@ -68402,9 +68403,9 @@ try {
        HTMLCanvasElement
        OffscreenCanvas
        -

        If this image's rendering context's layer count different than zero, then throw an - "InvalidStateError" DOMException.

        +

        If image's rendering context's layer + count is not 0, then throw an "InvalidStateError" + DOMException.

        If image has either a horizontal dimension or a vertical dimension equal to zero, then throw an "InvalidStateError" @@ -69856,7 +69857,7 @@ try {

        imagedata = context.getImageData(sx, sy, sw, sh [, settings])

        Returns an ImageData object containing the image data for the given rectangle of - the top level output bitmap. The color space of the returned object is the top-level output bitmap. The color space of the returned object is the color space of context unless overridden by settings.

        @@ -69878,7 +69879,7 @@ try {
        context.putImageData(imagedata, dx, dy [, dirtyX, dirtyY, dirtyWidth, dirtyHeight ])
        -

        Paints the data from the given ImageData object onto the top level output +

        Paints the data from the given ImageData object onto the top-level output bitmap. If a dirty rectangle is provided, only the pixels from that rectangle are painted.

        @@ -69897,7 +69898,7 @@ try {

        Objects that implement the CanvasImageData interface provide the following methods - for reading and writing pixel data to the top level output bitmap.

        + for reading and writing pixel data to the top-level output bitmap.

        The new ImageData(sw, sh, settings) constructor steps are:

        @@ -70002,10 +70003,10 @@ try { "IndexSizeError" DOMException.

      13. If this's layer count is not - zero, then throw an "InvalidStateError" + 0, then throw an "InvalidStateError" DOMException.

      14. -
      15. If this's top level output bitmap's

        If this's top-level output bitmap's origin-clean flag is set to false, then throw a "SecurityError" DOMException.

      16. @@ -70024,14 +70025,14 @@ try { sy+sh).

      17. Set the pixel values of imageData to be the pixels of this's - top level output bitmap in the area specified by the source rectangle in the + top-level output bitmap in the area specified by the source rectangle in the bitmap's coordinate space units, converted from this's color space to imageData's colorSpace using 'relative-colorimetric' rendering intent.

      18. Set the pixels values of imageData for areas of the source rectangle that are - outside of the top level output bitmap to transparent black.

      19. + outside of the top-level output bitmap to transparent black.

      20. Return imageData.

      @@ -70134,7 +70135,7 @@ try {

      The putImageData() method writes data from - ImageData structures back to this's top level output + ImageData structures back to this's top-level output bitmap. Its arguments are: imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, and dirtyHeight.

      @@ -70153,7 +70154,7 @@ try { "InvalidStateError" DOMException.

    • If this's layer count is not - zero, then throw an "InvalidStateError" + 0, then throw an "InvalidStateError" DOMException.

    • @@ -70200,7 +70201,7 @@ try { the imagedata data structure's Canvas Pixel ArrayBuffer to the pixel with coordinate (dx+x, dy+y) - in this's top level output bitmap.

    • + in this's top-level output bitmap.

      Due to the lossy nature of converting between color spaces and converting to and @@ -70756,7 +70757,7 @@ console.log(pixels.data[2]); the current output bitmap must be discarded.

      To apply a shadow or filter on an image A in layer coordinate space, user - agents must follow these steps (or act as if they do):

      + agents must follow these steps:

      1. Let inverseParentsTransform be the result of inverting the parents @@ -71530,7 +71531,7 @@ interface OffscreenCanvas : EventTarget {

      2. If this OffscreenCanvas object's context mode is 2d and the rendering context's layer count is not zero, then return a promise + data-x="concept-canvas-layer-count">layer count is not 0, then return a promise rejected with an "InvalidStateError" DOMException.

        @@ -71597,7 +71598,7 @@ interface OffscreenCanvas : EventTarget {
      3. If this OffscreenCanvas object's context mode is 2d and the rendering context's layer count is not zero, then throw an + data-x="concept-canvas-layer-count">layer count is not 0, then throw an "InvalidStateError" DOMException.

      4. Let image be a newly created ImageBitmap object that references @@ -71673,7 +71674,7 @@ interface OffscreenCanvasRenderingContext2D {

        An OffscreenCanvasRenderingContext2D object has a bitmap that is initialized when the object is created. This bitmap plays the same role as - CanvasRenderingContext2D's top level output bitmap.

        + CanvasRenderingContext2D's top-level output bitmap.

        The bitmap has an origin-clean flag, which can be set to true or