Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-40312

Context2d clipping region is not reset by save/restore

    XMLWordPrintable

Details

    • 38d37b13a3aae54ef0480150247d96ac9da0247a

    Description

      From the W3C specification for Canvas 2D Context (which the Qt module is intending to implement) (http://www.w3.org/TR/2dcontext/):

      2 The canvas state

      Each context maintains a stack of drawing states. Drawing states consist of:

      The current transformation matrix.
      The current clipping region.
      The current values of the following attributes: strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation, font, textAlign, textBaseline.

      [...]

      The save() method must push a copy of the current drawing state onto the drawing state stack.

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

      So, I should be able to:
      1. Save the state with no clipping region (implicit clipping region of entire canvas rectangle)
      2. Define a path
      3. Set it as the clipping region with clip()
      4. Define a new path, and fill or stroke it with the rendering being clipped by the clipping region.
      5. Restore the state to having no clipping region
      6. Perform other drawing operations with no clipping (or different clipping, if I set up a new region).

      As it is implemented now, Context2d::save and ::restore() will not restore the original clipping region, as shown in the snippet to follow.

      When I run the snippet, I should see the left half of the canvas with a red rectangle clipped by the half-circle, and the right half of the canvas with a blue rectangle not clipped at all. Instead, the blue rectangle is still being clipped by the half-circle and is thus not visible at all, because it does not overlap the half-circle.

      Yes, I could avoid this problem by drawing the blue rectangle first, but obviously this is only a minimal example to demonstrate the problem and not a real use case (in which I might want to carry out many operations with many different clipping areas).

      import QtQuick 2.1
      
      Item {
        id: root
        width:  300
        height: 300
        
        Canvas {
          id: canvas
          anchors.fill: parent
          contextType: "2d"
          
          onPaint: {
            context.save()
              context.beginPath()
              context.arc(0, height/2, width/2, 0, 2*Math.PI, false)
              context.clip()
              
              context.beginPath()
              context.rect(0, 0, width/2, height)
              context.fillStyle = "red"
              context.fill()
            context.restore()
            
            context.save()
              context.beginPath()
              context.rect(width/2, 0, width/2, height)
              context.fillStyle = "blue"
              context.fill()
            context.restore()
          }
        }
      }
      

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            fischerm Matt Fischer
            jemc Joe Eli McIlvain
            Votes:
            1 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes