Name

    CHROMIUM_path_rendering

Name Strings

    GL_CHROMIUM_path_rendering

Version

    Last Modifed Date: August 14, 2014

Dependencies

    OpenGL ES 3.0 is required.

Overview

    This extensions implements path rendering using
    OpenGL API.

New Tokens

    Accepted by the <matrixMode> parameter of MatrixLoadfCHROMIUM and
    MatrixLoadIdentityCHROMIUM:
    PATH_MODELVIEW_CHROMIUM                           0x1700
    PATH_PROJECTION_CHROMIUM                          0x1701

    Accepted in elements of the <commands> array parameter of
    PathCommandsCHROMIUM:
    CLOSE_PATH_CHROMIUM                               0x00
    MOVE_TO_CHROMIUM                                  0x02
    LINE_TO_CHROMIUM                                  0x04
    QUADRATIC_CURVE_TO_CHROMIUM                       0x0A
    CUBIC_CURVE_TO_CHROMIUM                           0x0C
    CONIC_CURVE_TO_CHROMIUM                           0x1A

    Accepted by the <pname> parameter of GetIntegerv,
    GetFloatv:
    PATH_MODELVIEW_MATRIX_CHROMIUM                    0x0BA6
    PATH_PROJECTION_MATRIX_CHROMIUM                   0x0BA7

    Accepted by the <pname> parameter of PathParameter{if}CHROMIUM:
    PATH_STROKE_WIDTH_CHROMIUM                        0x9075
    PATH_END_CAPS_CHROMIUM                            0x9076
    PATH_JOIN_STYLE_CHROMIUM                          0x9079
    PATH_MITER_LIMIT_CHROMIUM                         0x907a
    PATH_STROKE_BOUND_CHROMIUM                        0x9086

    Accepted by the <value> parameter of PathParameter{if}CHROMIUM:
    FLAT_CHROMIUM                                     0x1D00
    SQUARE_CHROMIUM                                   0x90a3
    ROUND_CHROMIUM                                    0x90a4
    BEVEL_CHROMIUM                                    0x90A6
    MITER_REVERT_CHROMIUM                             0x90A7

    Accepted by the <fillMode> parameter of StencilFillPathCHROMIUM
    StencilFillPathInstancedCHROMIUM and
    StencilThenCoverFillPathInstancedCHROMIUM:
    COUNT_UP_CHROMIUM                                 0x9088
    COUNT_DOWN_CHROMIUM                               0x9089

    Accepted by the <coverMode> parameter of CoverFillPathCHROMIUM,
    CoverStrokePath, StencilThenCoverFillPathCHROMIUM and
    StencilThenCoverStrokePathCHROMIUM:
    CONVEX_HULL_CHROMIUM                              0x908B
    BOUNDING_BOX_CHROMIUM                             0x908D

    Accepted by the <coverMode> parameter of CoverFillPathInstancedCHROMIUM,
    CoverStrokePathInstanced, StencilThenCoverFillPathInstancedCHROMIUM and
    StencilThenCoverStrokePathInstancedCHROMIUM:
    CONVEX_HULL_CHROMIUM                              see above
    BOUNDING_BOX_CHROMIUM                             see above
    BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM           0x909C

    Accepted by the <genMode> parameter of ProgramPathFragmentInputGen:
    EYE_LINEAR_CHROMIUM                               0x2400
    OBJECT_LINEAR_CHROMIUM                            0x2401
    CONSTANT_CHROMIUM                                 0x8576

    Accepted by the <transformType> parameter of
    StencilFillPathInstancedCHROMIUM, StencilStrokePathInstancedCHROMIUM,
    CoverFillPathInstancedCHROMIUM, CoverStrokePathInstancedCHROMIUM,
    StencilThenCoverFillPathInstancedCHROMIUM and
    StencilThenCoverStrokePathInstancedCHROMIUM:
    TRANSLATE_X_CHROMIUM                              0x908E
    TRANSLATE_Y_CHROMIUM                              0x908F
    TRANSLATE_2D_CHROMIUM                             0x9090
    TRANSLATE_3D_CHROMIUM                             0x9091
    AFFINE_2D_CHROMIUM                                0x9092
    AFFINE_3D_CHROMIUM                                0x9094
    TRANSPOSE_AFFINE_2D_CHROMIUM                      0x9096
    TRANSPOSE_AFFINE_3D_CHROMIUM                      0x9098

New Procedures and Functions

    void MatrixLoadfCHROMIUM(enum matrixMode, float* matrix)

    Takes a pointer to a 4x4 matrix stored in column-major order as 16
    consecutive ﬂoating-point values. The matrixMode specifies which
    matrix, PATH_MODELVIEW_CHROMIUM or PATH_PROJECTION_CHROMIUM is used.

    The funcition specifies either modelview or projection matrix
    to be used with path rendering API calls.

    void MatrixLoadIdentityCHROMIUM(enum matrixMode)

    Effectively calls MatrixLoadf with the identity matrix.

    uint GenPathsCHROMIUM(sizei range)

    Returns an integer /n/ such that names /n/, ..., /n+range-1/ are
    previously unused (i.e. there are /range/ previously unused path object
    names starting at /n/).  These names are marked as used, for the
    purposes of subsequent GenPathsCHROMIUM only, but they do not acquire
    path object state until each particular name is used to specify
    a path object.

    Returns 0 if no new path name was marked as used. Reasons for this
    include lack of free path names or range being 0 or a GL error
    was generated.

    INVALID_VALUE error is generated if range is negative.

    INVALID_OPERATION error is generated if range does not fit in
    32-bit uint.

    void DeletePathsCHROMIUM(uint path, sizei range)

    Deletes a path object where /path/ contains /range/ names of path objects to
    be delete. After a path object is deleted, its name is again unused.
    Unused names in /paths/ are silently ignored.

    INVALID_VALUE error is generated if /range/ is negative.

    INVALID_OPERATION error is generated if /range/ does not
    fit in 32-bit uint.

    INVALID_OPERATION error is generated if /path/ + /range/ does not fit
    32-bit uint.

    boolean IsPathCHROMIUM(uint path);

    The query returns TRUE if /path/ is the name of a path object.  If path is
    not the name of a path object, or if an error condition occurs,
    IsPathCHROMIUM returns FALSE.  A name retuned by GenPathsCHROMIUM, but
    without a path specified for it yet, is not the name of a path object.

    void PathCommandsCHROMIUM(uint path, sizei numCommands,
                        const ubyte* commands, sizei numCoords,
                        enum coordType, const GLvoid* coords)

    Specifies a path object commands for /path/ where /numCommands/
    indicates the number of path commands, read from the array
    /commands/, with which to initialize that path's command sequence.
    The type of the coordinates read from the /coords/ array is
    determined by the /coordType/ parameter which must be one of BYTE,
    UNSIGNED_BYTE, SHORT, UNSIGNED_SHORT, or FLOAT, otherwise the
    INVALID_ENUM error is generated.  These path commands reference
    coordinates read sequentially from the /coords/ array.

    The /numCommands/ elements of the /commands/ array must be tokens
    in Table 5.pathCommands.  The command sequence matches
    the element order of the /commands/ array.  Each command references
    a number of coordinates specified by "Coordinate count" column of
    Table 5.pathCommands, starting with the first (zero) element of
    the /coords/ array and advancing by the coordinate count for each
    command.  If any of these /numCommands/ command values are not
    listed in the "Token" column of Table
    5.pathCommands, the INVALID_ENUM error is generated.

    The INVALID_OPERATION error is generated if /numCoords/ does not
    equal the number of coordinates referenced by the command sequence
    specified by /numCommands/ and /commands/ (so /numCoords/ provides a
    sanity check that the /coords/ array is being interpreted properly).
    The error INVALID_VALUE is generated if either /numCommands/ or
    /numCoords/ is negative.

    The error INVALID_OPERATION is generated if /path/ is
    not an existing path object.

    The error INVALID_OPERATION is generated if
    /numCommands/ + (size of /coordType/ data type) * /numCoords/
    does not fit in 32-bit uint.

    If the PathCommandsCHROMIUM command results in an error, the path object
    named /path/ is not changed; if there is no error, the prior contents
    of /path/, if /path/ was an existent path object, are lost and the
    path object name /path/ becomes used.

    void PathParameterfCHROMIUM(uint path, enum pname, float value)
    void PathParameteriCHROMIUM(uint path, enum pname, int value)

    The commands specify the value of path parameters for the specified path
    object named /path/.  The error INVALID_OPERATION is generated if /path/ is
    not an existing path object.

    Each parameter has a single (scalar) value.

    /pname/ must be one of the tokens in the "Name" column of
    Table 5.pathParameters.
    The required values or range of each allowed parameter name token
    is listed in Table 5.pathParameter's "Required Values/Range" column.

    For values of /pname/ listed in Table 5.pathsParameters, the specified
    parameter is specified by /value/ when /value/ is a float or int,
    or if /value/ is a pointer to a float or int, accessed through that
    pointer.  The error INVALID_VALUE is generated if the specified
    value is negative for parameters required to be non-negative in
    Table 5.pathParameters.

    The error INVALID_VALUE is generated if the specified parameter value
    is not within the require range for parameters typed float or integer.
    The error INVALID_ENUM is generated if the specified parameter value
    is not one of the listed tokens for parameters typed enum.

    void PathStencilFuncCHROMIUM(enum func, int ref, uint mask)

    Configures the stencil function, stencil reference value, and stencil read
    mask to be used by the StencilFillPathCHROMIUM and StencilStrokePathCHROMIUM
    commands described subsequently. The parameters accept the same values
    allowed by the StencilFunc command.

    void StencilFillPathCHROMIUM(uint path, enum fillMode, uint mask)

    The function transforms into window space the outline of the path object
    named /path/ based on the current modelview, projection and viewport,
    transforms (ignoring any vertex and/or geometry shader or program that might
    be active/enabled) and then updates the stencil values of all /accessible
    samples/ (explained below) in the framebuffer.  Each sample's stencil buffer
    value is updated based on the winding number of that sample with respect to
    the transformed outline of the path object with any non-closed subpath
    forced closed and the specified /fillMode/.

    If /path/ does not name an existing path object, the command does
    nothing (and no error is generated).

    If the path's command sequence specifies unclosed subpaths (so not
    contours) due to MOVE_TO_CHROMIUM commands, such subpaths are trivially
    closed by connecting with a line segment the initial and terminal
    control points of each such path command subsequence.

    Transformation of a path's outline works by taking all positions on the
    path's outline in 2D path space (x,y) and constructing an object space
    position (x,y,0,1) that is then used similar to as with the (xo,yo,zo,wo)
    position in section 2.12 ("Fixed-Function Vertex Transformation") of OpenGL
    3.2 (unabridged) Specification (Special Functions) to compute corresponding
    eye-space coordinates (xe,ye,ze,we) and clip-space coordinates
    (xc,yc,zc,wc).  A path outline's clip-space coordinates are further
    transformed into window space similar to as described in section 2.16
    ("Coordinate Transformations").  This process provides a mapping 2D path
    coordinates to 2D window coordinates.  The resulting 2D window coordinates
    are undefined if any of the transformations involved are singular or may be
    inaccurate if any of the transformations (or their combination) are
    ill-conditioned.

    The winding number for a sample with respect to the path outline,
    transformed into window space, is computed by counting the (signed)
    number of revolutions around the sample point when traversing each
    (trivially closed if necessary) contour once in the transformed path.
    This traversal is performed in the order of the path's command
    sequence.  Starting from an initially zero winding count, each
    counterclockwise revolution when the front face mode is CCW (or
    clockwise revolution when the front face mode is CW) around the sample
    point increments the winding count by one; while each clockwise
    revolution when the front face mode is CCW (or counterclockwise
    revolution when the front face mode is CW) around the sample point
    decrements the winding count by one.

    The /mask/ parameter controls what subset of stencil bits are affected
    by the command.

    The /fillMode/ parameter must be one of INVERT, COUNT_UP_CHROMIUM
    or COUNT_DOWN_CHROMIUM; otherwise the INVALID_ENUM error
    is generated.  INVERT inverts the bits set in the effective /mask/
    value for each sample's stencil value if the winding number for the
    given sample is odd.  COUNT_UP_CHROMIUM adds with modulo n arithmetic the
    winding number of each sample with the sample's prior stencil buffer
    value; the result of this addition is written into the sample's
    stencil value but the bits of the stencil value not set in the
    effective /mask/ value are left unchanged.  COUNT_DOWN_CHROMIUM subtracts
    with modulo /n/ arithmetic the winding number of each sample with the
    sample's prior stencil buffer value; the result of this subtraction is
    written into the sample's stencil value but the bits of the stencil
    value not set in the effective /mask/ value are left unchanged.

    The value of /n/ for the modulo /n/ arithmetic used by COUNT_UP_CHROMIUM
    and COUNT_DOWN_CHROMIUM is the effective /mask/+1.  The error INVALID_VALUE
    is generated if /fillMode/ is COUNT_UP_CHROMIUM or COUNT_DOWN_CHROMIUM and
    the effective /mask/+1 is not an integer power of two.

    ACCESSIBLE SAMPLES WITH RESPECT TO A TRANSFORMED PATH

    The accessible samples of a transformed path that are updated are
    the samples that remain after discarding the following samples:

        *   Any sample that would be clipped similar to as specified in section
            2.22 ("Primitive Clipping") of OpenGL 3.2 (unabridged) Specification
            (Special Functions) because its corresponding position in clip space
            (xc,yc,zc,wc) or (xe,ye,ze,we) would be clipped by the clip volume
            or enabled client-defined clip planes.

        *   Any sample that would fail the pixel ownership test (section
            4.1.1) if rasterized.

        *   Any sample that would fail the scissor test (section 4.1.2)
            if SCISSOR_TEST is enabled.

    And for the StencilFillPathCHROMIUM and StencilStrokePathCHROMIUM commands
    (so not applicable to the CoverFillPathCHROMIUM and CoverStrokePathCHROMIUM
    commands):
        *   Any sample that would fail the (implicitly enabled) stencil test
            with the stencil function configured based on the path stencil
            function state configured by PathStencilFuncCHROMIUM.  In the case
            of the StencilFillPathCHROMIUM and StencilStrokePathCHROMIUM
            commands and their instanced versions, the effective stencil read
            mask for the stencil mask is treated as the value of
            PATH_STENCIL_VALUE_MASK bit-wise ANDed with the bit-invert of the
            effective /mask/ parameter value; otherwise, for the cover commands,
            the stencil test operates normally.  In the case the stencil test
            fails during a path stencil operation, the stencil fail operation is
            ignored and the pixel's stencil value is left undisturbed (as if the
            stencil operation was KEEP).

        *   The state of the face culling (CULL_FACE) enable is ignored.

    void StencilStrokePathCHROMIUM(uint path, int reference, uint mask)

    Transforms into window space the stroked region of the path object named
    /path/ based on the current modelview, projection and viewport transforms
    (ignoring any vertex and/or geometry shader or program that might be
    active/enabled) and then updates the stencil values of a subset of the
    accessible samples (see above) in the framebuffer.

    If /path/ does not name an existing path object, the command does
    nothing (and no error is generated).

    The path object's specified stroke width (in path space) determines
    the width of the path's stroked region.

    The stroke of a transformed path's outline
    is the region of window space defined by the union of:

        *   Sweeping an orthogonal centered line segment of the (above
            determined) effective stroke width along each path segment
            in the path's transformed outline.

        *   End cap regions (explained below) appended to the initial
            and terminal control points of non-closed command sequences
            in the path.  For a sequence of commands that form a closed
            contour, the end cap regions are ignored.

        *   Join style regions (explained below) between connected path
            segments meet.

    Any accessible samples within the union of these three regions are
    considered within the path object's stroke.

    If the stroke width is zero, each of the regions in the union will
    be empty and there are no accessible samples within the stroke.

    The /mask/ parameter controls what subset of stencil bits are affected
    by the command.

    A sample's stencil bits that are set in the effective /mask/ value
    are updated with the specified stencil /reference/ value if the
    sample is accessible (as specified above) and within the stroke of
    the transformed path's outline.

    Every path object has an end caps parameter
    PATH_END_CAPS_CHROMIUM) that is one of FLAT_CHROMIUM,
    SQUARE_CHROMIUM or ROUND_CHROMIUM. This parameter defines the
    initial and terminal caps type. There are no samples within a
    FLAT_CHROMIUM cap.  The SQUARE_CHROMIUM cap extends centered and
    tangent to the given end (initial or terminal) of the subpath for
    half the effective stroke width; in other words, a square cap is a
    half-square that kisses watertightly the end of a subpath.  The
    ROUND_CHROMIUM cap appends a semi-circle, centered and tangent,
    with the diameter of the effective stroke width to the given end
    (initial or terminal) of the subpath; in other words, a round cap
    is a semi-circle that kisses watertightly the end of a subpath.

    Every path object has a join style that is one of BEVEL_CHROMIUM,
    ROUND_CHROMIUM or MITER_REVERT_CHROMIUM.  Each path object also has a miter
    limit value.  The BEVEL_CHROMIUM join style inserts a triangle with two
    vertices at the outside corners where two connected path segments join and a
    third vertex at the common end point shared by the two path segments.  The
    ROUND_CHROMIUM join style inserts a wedge-shaped portion of a circle
    centered at the common end point shared by the two path segments; the radius
    of the circle is half the effective stroke width. The MITER_REVERT_CHROMIUM
    join style inserts a quadrilateral with two opposite vertices at the outside
    corners where the two connected path segments join and two opposite vertices
    with one on the path's junction between the two joining path segments and
    the other at the common end point shared by the two path segments.  However,
    the MITER_REVERT_CHROMIUM join style behaves as the BEVEL_CHROMIUM style if
    the sine of half the angle between the two joined segments is less than the
    path object's PATH_STROKE_WIDTH value divided by the path's
    PATH_MITER_LIMIT_CHROMIUM value.

    Every path object has a stroke approximation bound parameter
    (PATH_STROKE_BOUND_CHROMIUM) that is a floating-point value /sab/ clamped
    between 0.0 and 1.0 and set and queried with the PATH_STROKE_BOUND_CHROMIUM
    path parameter.  Exact determination of samples swept an orthogonal
    centered line segment along cubic Bezier segments and rational
    quadratic Bezier curves (so non-circular partial elliptical arcs) is
    intractable for real-time rendering so an approximation is required;
    /sab/ intuitively bounds the approximation error as a percentage of
    the path object's stroke width.  Specifically, this path parameter
    requests the implementation to stencil any samples within /sweep/
    object space units of the exact sweep of the path's cubic Bezier
    segments or partial elliptical arcs to be sampled by the stroke where

      sweep = ((1-sab)*sw)/2

    where /sw/ is the path object's stroke width.  The initial value
    of /sab/ when a path is created is 0.2.  In practical terms, this
    initial value means the stencil sample positions coverage within 80%
    (100%-20%) of the stroke width of cubic and rational quadratic stroke
    segments should be sampled.


    void CoverFillPathCHROMIUM(uint path, enum coverMode)

    The command transforms into window space the outline of the path object
    named /path/ based on the current modelview, projection and viewport
    transforms (ignoring any vertex and/or geometry shader or program that might
    be active/enabled) and rasterizes a subset of the accessible samples in the
    framebuffer guaranteed to include all samples that would have a net
    stencil value change if StencilFillPathCHROMIUM were issued with the same
    modelview, projection, and viewport state.  During this rasterization, the
    stencil test operates normally and as configured; the expectation is the
    stencil test will be used to discard samples not determined "covered" by a
    prior StencilFillPathCHROMIUM command.

    If /path/ does not name an existing path object, the command does
    nothing (and no error is generated).

    /coverMode/ must be one of CONVEX_HULL_CHROMIUM or BOUNDING_BOX_CHROMIUM.
    Otherwise, INVALID_ENUM error is generated.

    The subset of accessible pixels that are rasterized are within a bounding
    box (expected to be reasonably tight) surrounding all the samples guaranteed
    to be rasterized by CoverFillPathCHROMIUM.  The bounding box must be
    orthogonally aligned to the path space coordinate system.  (The area of the
    bounding box in path space is guaranteed to be greater than or equal the
    area of the convex hull in path space.) Each rasterized sample will be
    rasterized once and exactly once.

    While samples with a net stencil change /must/ be rasterized,
    implementations are explicitly allowed to vary in the rasterization
    of samples for which StencilFillPathCHROMIUM would /not/ change sample's
    net stencil value.  This means implementations are allowed to (and,
    in fact, are expected to) conservatively "exceed" the region strictly
    stenciled by the path object.

    CoverFillPathCHROMIUM /requires/ the following rasterization invariance:
    calling CoverFillPathCHROMIUM for the same (unchanged) path object with
    fixed (unchanged) modelview, projection, and viewport transform state
    with the same (unchanged) set of accessible samples will rasterize
    the exact same set of samples with identical interpolated values
    for respective fragment/sample locations.

    void CoverStrokePathCHROMIUM(uint path, enum coverMode)

    The command operates in the same manner as CoverFillPathCHROMIUM except the
    region guaranteed to be rasterized is, rather than the region within
    /path/'s filled outline, instead the region within the /path/'s stroked
    region as determined by StencilStrokePathCHROMIUM.  During this
    rasterization, the stencil test operates normally and as configured; the
    expectation is the stencil test will be used to discard samples not
    determined "covered" by a prior StencilStrokePathCHROMIUM command.

    If /path/ does not name an existing path object, the command does
    nothing (and no error is generated).

    /coverMode/ must be one of CONVEX_HULL_CHROMIUM or BOUNDING_BOX_CHROMIUM.
    Otherwise, INVALID_ENUM error is generated.

    Analogous to the rasterization guarantee of CoverFillPathCHROMIUM with
    respect to StencilFillPathCHROMIUM, CoverStrokePathCHROMIUM guarantees that
    all samples rasterized by StencilStrokePathCHROMIUM, given the same
    transforms and accessible pixels and stroke width, will also be rasterized
    by the corresponding CoverStrokePathCHROMIUM.

    CoverStrokePathCHROMIUM /requires/ the following rasterization invariance:
    calling CoverStrokePathCHROMIUM for the same (unchanged) path object with
    fixed (unchanged) modelview, projection, and viewport transform state and
    with the same (unchanged) set of accessible samples will rasterize the exact
    same set of samples with identical interpolated values for respective
    fragment/sample locations.

    void StencilThenCoverFillPathCHROMIUM(uint path, enum fillMode, uint mask, enum coverMode)

    The command is equivalent to the two commands

        StencilFillPathCHROMIUM(path, fillMode, mask);
        CoverFillPathCHROMIUM(path, coverMode);

    unless either command would generate an error; for any such error
    other than OUT_OF_MEMORY, only that error is generated.

    void StencilThenCoverStrokePathCHROMIUM(uint path, int reference, uint mask, enum coverMode)

    The command is equivalent to the two commands

        StencilStrokePathCHROMIUM(path, reference, mask);
        CoverStrokePathCHROMIUM(path, coverMode);

    unless either command would generate an error; for any such error
    other than OUT_OF_MEMORY, only that error is generated.

    void StencilFillPathInstancedCHROMIUM(sizei numPaths,
                                          enum pathNameType,
                                          const void *paths,
                                          uint pathBase,
                                          enum fillMode, uint mask,
                                          enum transformType,
                                          const float *transformValues);

    The command stencils a sequence of filled paths.

    The /numPaths/ has to be >= 0. Otherwise INVALID_VALUE error is
    generated.

    The /numPaths/ has to fit in 32-bit uint. Otherwise
    INVALID_OPERATION is generated.

    The /pathNameType/ determines the type of elements of the /paths/
    array and must be one of UNSIGNED_BYTE, BYTE, UNSIGNED_SHORT, SHORT,
    UNSIGNED_INT or INT. Otherwise INVALID_ENUM error is generated.

    The /pathBase/ is an offset added to the /numPaths/ path names read
    from the /paths/ array. Each result is 2's complement integer and it
    is cast to uint path name..

    The /transformType/ must be one of NONE, TRANSLATE_X_CHROMIUM,
    TRANSLATE_Y_CHROMIUM, TRANSLATE_2D_CHROMIUM, TRANSLATE_3D_CHROMIUM,
    AFFINE_2D_CHROMIUM, AFFINE_3D_CHROMIUM, TRANSPOSE_AFFINE_2D_CHROMIUM, or
    TRANSPOSE_AFFINE_3D_CHROMIUM. Otherwise INVALID_ENUM error is generated.

    The /fillMode/ and /mask/ are validated identically to the same-named
    parameters of StencilFillPathCHROMIUM.

    The /numPaths/ * (size of /pathNameType/ data type) + /numPaths/ *
    (size of float) * (component count of /transformType/)  must fit to
    32-bit uint. Otherwise INVALID_OPERATION is generated.

    The StencilFillPathInstancedCHROMIUM command is equivalent to:

        float dm[16];
        GetFloatv(PATH_MODELVIEW_MATRIX, dm);
        const float *v = transformValues;
        for (int i = 0; i<numPaths; i++) {
          if (!applyPathTransform(dm, transformType, &v)) {
            return;
          }
          uint pathName;
          if (!getPathName(pathNameType, &paths, pathBase, &pathName)) {
            return;
          }
          if (IsPathCHROMIUM(pathName)) {
            StencilFillPathCHROMIUM(pathName, fillMode, mask);
          }
        }
        glMatrixLoadfCHROMIUM(PATH_MODELVIEW_CHROMIUM, dm);

    assuming these helper functions for applyPathTransform and
    getPathName:

        bool applyPathTransform(const float dm[], enum transformType, const float** v)
        {
          float m[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
 
          switch (transformType) {
          case NONE:
            break;
          case TRANSLATE_X_CHROMIUM:
            m[12] = (*v)[0];
            *v += 1;
            break;
          case TRANSLATE_Y_CHROMIUM:
            m[13] = (*v)[0];
            *v += 1;
            break;
          case TRANSLATE_2D_CHROMIUM:
            m[12] = (*v)[0];
            m[13] = (*v)[1];
            *v += 2;
            break;
          case TRANSLATE_3D_CHROMIUM:
            m[12] = (*v)[0];
            m[13] = (*v)[1];
            m[14] = (*v)[2];
            *v += 3;
            break;
          case AFFINE_2D_CHROMIUM:
            m[0] =(*v)[0]; m[4] =(*v)[2]; m[8] =0; m[12]=(*v)[4];
            m[1] =(*v)[1]; m[5] =(*v)[3]; m[9] =0; m[13]=(*v)[5];
            m[2] =0   ;    m[6] =0;       m[10]=1; m[14]=0;
            m[3] =0;       m[7] =0;       m[11]=0; m[15]=1;
            *v += 6;
            break;
          case TRANSPOSE_AFFINE_2D_CHROMIUM:
            m[0] =(*v)[0]; m[4] =(*v)[1]; m[8] =0; m[12]=(*v)[2];
            m[1] =(*v)[3]; m[5] =(*v)[4]; m[9] =0; m[13]=(*v)[5];
            m[2] =0;       m[6] =0;       m[10]=1; m[14]=0;
            m[3] =0;       m[7] =0;       m[11]=0; m[15]=1;
            *v += 6;
            break;
          case AFFINE_3D_CHROMIUM:
            m[0] =(*v)[0]; m[4] =(*v)[3]; m[8] =(*v)[6]; m[12]=(*v)[9];
            m[1] =(*v)[1]; m[5] =(*v)[4]; m[9] =(*v)[7]; m[13]=(*v)[10];
            m[2] =(*v)[2]; m[6] =(*v)[5]; m[10]=(*v)[8]; m[14]=(*v)[11];
            m[3] =0;       m[7] =0;       m[11]=1;       m[15]=0;
            *v += 12;
            break;
          case TRANSPOSE_AFFINE_3D_CHROMIUM:
            m[0] =(*v)[0]; m[4] =(*v)[1]; m[8] =(*v)[2];  m[12]=(*v)[3];
            m[1] =(*v)[4]; m[5] =(*v)[5]; m[9] =(*v)[6];  m[13]=(*v)[7];
            m[2] =(*v)[8]; m[6] =(*v)[9]; m[10]=(*v)[10]; m[14]=(*v)[11];
            m[3] =0;       m[7] =0;       m[11]=1;        m[15]=0;
            *v += 12;
            break;
          default:
            setError(INVALID_ENUM);
            return FALSE;
          }
          multiplyMatrix(dm, m, m);  // Multiplies dm and m and stores result to m.
          glMatrixLoadfCHROMIUM(PATH_MODELVIEW_CHROMIUM, m);
          return TRUE;
        }

        bool getPathName(enum pathNameType, const void** paths,
                         uint pathBase, uint* pathName)
        {
          switch (pathNameType) {
          case BYTE:
            {
              const byte *p = (const byte*)*paths;
              *pathName = pathBase + p[0];
              *paths = p+1;
              break;
            }
          case UNSIGNED_BYTE:
            {
              const ubyte *p = (const ubyte*)*paths;
              *pathName = pathBase + p[0];
              *paths = p+1;
              break;
            }
          case SHORT:
            {
              const short *p = (const short*)*paths;
              *pathName = pathBase + p[0];
              *paths = p+1;
              break;
            }
          case UNSIGNED_SHORT:
            {
              const ushort *p = (const ushort*)*paths;
              *pathName = pathBase + p[0];
              *paths = p+1;
              break;
            }
          case INT:
            {
              const int *p = (const int*)*paths;
              *pathName = pathBase + p[0];
              *paths = p+1;
              break;
            }
          case UNSIGNED_INT:
            {
              const uint *p = (const uint*)*paths;
              *pathName = pathBase + p[0];
              *paths = p+1;
              break;
            }
          default:
            setError(INVALID_ENUM);
            return FALSE;
        }
        return TRUE;
    }


    void StencilStrokePathInstancedCHROMIUM(sizei numPaths,
                                            enum pathNameType,
                                            const void *paths,
                                            uint pathBase,
                                            int reference, uint mask,
                                            enum transformType,
                                            const float *transformValues);

    The command stencils a sequence of stroked paths.

    The command verifies /numPaths/, /pathNameType/ and
    /transformType/ similarly to StencilFillPathInstancedCHROMIUM.

    The command is equivalent to:

        float dm[16];
        GetFloatv(PATH_MODELVIEW_MATRIX, dm);
        const float *v = transformValues;
        for (int i = 0; i<numPaths; i++) {
          if (!applyPathTransform(dm, transformType, &v)) {
            return;
          }
          uint pathName;
          if (!getPathName(pathNameType, &paths, pathBase, &pathName)) {
            return;
          }
          if (IsPathCHROMIUM(pathName)) {
            StencilStrokePathCHROMIUM(pathName, reference, mask);
          }
        }
        glMatrixLoadfCHROMIUM(PATH_MODELVIEW_CHROMIUM, dm);

    assume the helper functions for applyPathTransform and
    getPathName defined above.

    void CoverFillPathInstancedCHROMIUM(sizei numPaths,
                                        enum pathNameType,
                                        const void *paths,
                                        uint pathBase,
                                        enum coverMode,
                                        enum transformType,
                                        const float *transformValues);

    The command covers a sequence of filled paths.

    The command verifies /numPaths/, /pathNameType/ and
    /transformType/ similarly to StencilFillPathInstancedCHROMIUM.

    The command is equivalent to:

        if (coverMode == BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM) {
          renderBoundingBox(FALSE,
                            numPaths,
                            pathNameType,
                            paths,
                            pathBase,
                            transformType, transformValues);
        } else if (coverMode == CONVEX_HULL_CHROMIUM || coverMode == BOUNDING_BOX_CHROMIUM) {
          float dm[16];
          GetFloatv(PATH_MODELVIEW_MATRIX, dm);
          const float *v = transformValues;
          for (int i = 0; i<numPaths; i++) {
            if (!applyPathTransform(dm, transformType, &v)) {
              return;
            }
            uint pathName;
            if (!getPathName(pathNameType, &paths, pathBase, &pathName)) {
              return;
            }
            if (IsPathCHROMIUM(pathName)) {
              CoverFillPathCHROMIUM(pathName, coverMode);
            }
          }
          glMatrixLoadfCHROMIUM(PATH_MODELVIEW_CHROMIUM, dm);
        } else {
          setError(INVALID_ENUM);
        }


    assuming these helper functions for applyPathTransform and
    getPathName defined above as well as:

        void renderBoundingBox(bool shouldRenderStroke,
                               sizei numPaths,
                               enum pathNameType,
                               const uint *paths,
                               uint pathBase,
                               enum transformType,
                               const float *transformValues)
        {
          boolean hasBounds = FALSE;
          float boundsUnion[4], bounds[4];

          const float *v = transformValues;
          for (int i = 0; i<numPaths; i++) {
            uint pathName;
            if (!getPathName(pathNameType, paths, pathBase, &pathName)) {
              return;
            }
            if (IsPathCHROMIUM(pathName)) {
              GetPathBoundingBox(pathName, shouldRenderStroke, bounds);
              switch (transformType) {
              case NONE:
                break;
              case TRANSLATE_X_CHROMIUM:
                bounds[0] += v[0];
                bounds[2] += v[0];
                v += 1;
                break;
              case TRANSLATE_Y_CHROMIUM:
                bounds[1] += v[0];
                bounds[3] += v[0];
                v += 1;
                break;
              case TRANSLATE_2D_CHROMIUM:
                bounds[0] += v[0];
                bounds[1] += v[1];
                bounds[2] += v[0];
                bounds[3] += v[1];
                v += 2;
                break;
              case TRANSLATE_3D_CHROMIUM: // ignores v[2]
                bounds[0] += v[0];
                bounds[1] += v[1];
                bounds[2] += v[0];
                bounds[3] += v[1];
                v += 3;
                break;
              case AFFINE_2D_CHROMIUM:
                bounds[0] = bounds[0]*v[0] + bounds[0]*v[2] + v[4];
                bounds[1] = bounds[1]*v[1] + bounds[1]*v[3] + v[5];
                bounds[2] = bounds[2]*v[0] + bounds[2]*v[2] + v[4];
                bounds[3] = bounds[3]*v[1] + bounds[3]*v[3] + v[5];
                v += 6;
                break;
              case TRANSPOSE_AFFINE_2D_CHROMIUM:
                bounds[0] = bounds[0]*v[0] + bounds[0]*v[1] + v[2];
                bounds[1] = bounds[1]*v[3] + bounds[1]*v[4] + v[5];
                bounds[2] = bounds[2]*v[0] + bounds[2]*v[1] + v[2];
                bounds[3] = bounds[3]*v[3] + bounds[3]*v[4] + v[5];
                v += 6;
                break;
              case AFFINE_3D_CHROMIUM:  // ignores v[2], v[5], v[6..8], v[11]
                bounds[0] = bounds[0]*v[0] + bounds[0]*v[3] + v[9];
                bounds[1] = bounds[1]*v[1] + bounds[1]*v[4] + v[10];
                bounds[2] = bounds[2]*v[0] + bounds[2]*v[3] + v[9];
                bounds[3] = bounds[3]*v[1] + bounds[3]*v[4] + v[10];
                v += 12;
                break;
              case TRANSPOSE_AFFINE_3D_CHROMIUM:  // ignores v[2], v[6], v[8..11]
                bounds[0] = bounds[0]*v[0] + bounds[0]*v[1] + v[3];
                bounds[1] = bounds[1]*v[4] + bounds[1]*v[5] + v[7];
                bounds[2] = bounds[2]*v[0] + bounds[2]*v[1] + v[3];
                bounds[3] = bounds[3]*v[4] + bounds[3]*v[5] + v[7];
                v += 12;
                break;
              default:
                setError(INVALID_ENUM);
                return;
              }
              if (bounds[0] > bounds[2]) {
                float t = bounds[2];
                bounds[2] = bounds[0];
                bounds[0] = t;
              }
              if (bounds[1] > bounds[3]) {
                float t = bounds[3];
                bounds[3] = bounds[1];
                bounds[1] = t;
              }
              if (hasBounds) {
                if (bounds[0] < boundsUnion[0]) {
                  boundsUnion[0] = bounds[0];
                }
                if (bounds[1] < boundsUnion[1]) {
                  boundsUnion[1] = bounds[1];
                }
                if (bounds[2] > boundsUnion[2]) {
                  boundsUnion[2] = bounds[2];
                }
                if (bounds[3] > boundsUnion[3]) {
                  boundsUnion[3] = bounds[3];
                }
              } else {
                for (int i=0; i<4; i++) {
                  boundsUnion[i] = bounds[i];
                }
                hasBounds = TRUE;
              }
            }
          }
          if (hasBounds) {
             Rectf(boundsUnion[0], boundsUnion[1], boundsUnion[2], boundsUnion[3]);
          }
        }

    Where helper GetPathBoundingBox returns bounding box for the path with or without
    stroking, and Rectf renders a rectangle.

    /coverMode/ must be one of CONVEX_HULL_CHROMIUM or BOUNDING_BOX_CHROMIUM or
    BOUNDING_BOX_OF_BOUNDING_BOXES. Otherwise, INVALID_ENUM error is generated.

    void CoverStrokePathInstancedCHROMIUM(sizei numPaths,
                                          enum pathNameType,
                                          const void *paths,
                                          uint pathBase,
                                          enum coverMode,
                                          enum transformType,
                                          const float *transformValues);

    The command covers a sequence of stroked paths.

    The command verifies /numPaths/, /pathNameType/ and
    /transformType/ similarly to StencilFillPathInstancedCHROMIUM.

    The command is equivalent to:

        if (coverage == BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM) {
          renderBoundingBox(TRUE,
                            numPaths,
                            pathNameType, paths,
                            pathBase,
                            transformType, transformValues);
        } else if (coverMode == CONVEX_HULL_CHROMIUM || coverMode == BOUNDING_BOX_CHROMIUM) {
          float dm[16];
          GetFloatv(PATH_MODELVIEW_MATRIX, dm);
          const float *v = transformValues;
          for (int i = 0; i<numPaths; i++) {
            if (!applyPathTransform(dm, transformType, &v)) {
              return;
            }
            uint pathName;
            if (!getPathName(pathNameType, &paths, pathBase, &pathName)) {
              return;
            }
            if (IsPathCHROMIUM(pathName)) {
              CoverStrokePathCHROMIUM(pathName, coverMode);
            }
          }
          glMatrixLoadfCHROMIUM(PATH_MODELVIEW_CHROMIUM, dm);
        } else {
          setError(INVALID_ENUM);
        }

    assuming these helper functions defined above.

    /coverMode/ must be one of CONVEX_HULL_CHROMIUM or BOUNDING_BOX_CHROMIUM or
    BOUNDING_BOX_OF_BOUNDING_BOXES. Otherwise, INVALID_ENUM error is generated.


    void StencilThenCoverFillPathInstancedCHROMIUM(sizei numPaths,
                                                   enum pathNameType,
                                                   const void *paths,
                                                   uint pathBase,
                                                   enum coverMode,
                                                   enum fillMode,
                                                   uint mask,
                                                   enum transformType,
                                                   const float *transformValues);

    The command is equivalent to the two commands

        StencilFillPathInstancedCHROMIUM(numPaths
                                         paths,
                                         pathBase,
                                         fillMode,
                                         mask,
                                         transformType,
                                         transformValues);
        CoverFillPathInstancedCHROMIUM(numPaths,
                                       paths,
                                       pathBase,
                                       coverMode,
                                       fillMode,
                                       mask,
                                       transformType,
                                       transformValues);

    unless either command would generate an error; for any such error
    other than OUT_OF_MEMORY, only that error is generated.


    void StencilThenCoverStrokePathInstancedCHROMIUM(sizei numPaths,
                                                     enum pathNameType,
                                                     const void *paths,
                                                     uint pathBase,
                                                     enum coverMode,
                                                     int reference,
                                                     uint mask,
                                                     enum transformType,
                                                     const float *transformValues);

    The command is equivalent to the two commands

        StencilStrokePathInstancedCHROMIUM(numPaths,
                                           pathNameType,
                                           paths,
                                           pathBase,
                                           reference,
                                           mask,
                                           transformType,
                                           transformValues);
        CoverStrokePathInstancedCHROMIUM(numPaths,
                                         pathNameType,
                                         paths,
                                         pathBase,
                                         coverMode,
                                         transformType,
                                         transformValues);

    unless either command would generate an error; for any such error
    other than OUT_OF_MEMORY, only that error is generated.

    void BindFragmentInputLocationCHROMIUM(uint program, int location,
                                           const char* name);

    The call specifes that the fragment shader input varying named
    /name/ in program /program/ should be bound to uniform location
    /location/ when the program is next linked.  If /name/ was bound
    previously, its assigned binding is replaced with /location/. The
    /name/ must be a null terminated string. The error INVALID_VALUE
    is generated if /location/ is equal or greater than

    MAX_VARYING_VECTORS * 4

    or less than 0. BindFragmentInputLocation has no effect until the
    program is linked. In particular, it doesn't modify the bindings of active
    uniforms variables in a program that has already been linked.

    The error INVALID_OPERATION is generated if /program/ is not name for a
    program object.

    The error INVALID_OPERATION is generated if name starts with the reserved
    "gl_" prefix.

    When a program is linked, any active uniforms without a binding specified
    through BindFragmentInputLocation will be automatically be bound to
    locations by the GL. Such bindings can not be queried.

    BindFragmentInputLocation may be issued before any shader objects are
    attached to a program object. Hence it is allowed to bind any name (except
    a name starting with "gl_") to an index, including a name that is never used
    as a varying in the fragment shader object. Assigned bindings for varying
    variables that do not exist or are not active are ignored. Using such bindings
    behaves as if passed location was -1.

    It is possible for an application to bind more than one fragment
    input name to the same location.  This is referred to as aliasing.
    This will only work if only one of the aliased fragment inputs is
    active in the executable program, or if no path through the shader
    consumes more than one fragment input of a set of fragment inputs
    aliased to the same location.  If two statically used fragment
    inputs in a program are bound to the name location, link must
    fail.

    void ProgramPathFragmentInputGenCHROMIUM(uint program,
                                             int location,
                                             enum genMode,
                                             int components,
                                             const float *coeffs);

    The command controls how a user-defined (non-built-in) fragment input of
    a GLSL program object is computed for fragment shading operations that occur
    as a result of CoverFillPathCHROMIUM or CoverStrokePathCHROMIUM.

    /program/ names a GLSL program object. If /program/ has not been
    successfully linked, the error INVALID_OPERATION is generated.

    The given fragment input generation state is loaded into the fragment
    input variable location identified by /location/. This location
    is a value bound with BindFragmentInputLocation.

    If the value of location is -1, the ProgramPathFragmentInputGenCHROMIUM
    command will silently ignore the command, and the program's path fragment
    input generation state will not be changed.

    If any of the following conditions occur, an INVALID_OPERATION error is
    generated by the ProgramPathFragmentInputGenCHROMIUM, and no state is
    changed:

        * if the size indicated in the /components/ of the
          ProgramPathFragmentInputGenCHROMIUM command used does not match the
          size of the fragment input scalar or vector declared in the
          shader,

        * if the fragment input declared in the shader is not
          single-precision floating-point scalar or vector, or

        * if no fragment input variable with a location of /location/
          exists in the program object named by /program/ and location
          is not -1, or

        * if the fragment input declared in the shader is a built-in
          variables (i.e. prefixed by "gl_").

    When covering paths, fragment input variables are interpolated at
    each shaded fragment based on the corresponding fragment input
    generation state specified by ProgramPathFragmentInputGenCHROMIUM for
    each respective fragment input.

    The /genMode/, /components/, and /coeffs/ parameters are used to
    generate the fragment input variable values. This is described in
    subsection FRAGMENT INPUT GENERATION FOR PATH COVER COMMANDS.

    When covering paths, if a fragment input variable has not had its
    path fragment input generation state successfully generated, it as
    if the values of this variable are always initialized to zero when
    the fragment shader is executing.

    FRAGMENT INPUT GENERATION FOR PATH COVER COMMANDS

    The /genMode/, /components/, and /coeffs/ parameters of
    ProgramPathFragmentInputGenCHROMIUM control how fragment inputs are computed
    for fragment shading operations that occur as a result of
    CoverFillPathCHROMIUM and CoverStrokePathCHROMIUM and their StencilThenCover
    and instanced variants.

    /genMode/ must be one of NONE, OBJECT_LINEAR_CHROMIUM, EYE_LINEAR_CHROMIUM
    or CONSTANT_CHROMIUM; otherwise INVALID_ENUM is generated.

    NONE means that the fragment input is not generated. OBJECT_LINEAR_CHROMIUM
    means that the specified input is generated from a linear combination of the
    2D path coordinates (x,y). EYE_LINEAR_CHROMIUM means the specified input is
    generated from a linear combination of path's 2D coordinates transformed in
    eye space, with (xe, ye, ze, we) calculated as in section 2.12
    ("Fixed-Function Vertex Transformation") of OpenGL 3.2 (unabridged)
    Specification (Special Functions). CONSTANT_CHROMIUM means that the
    specified input is set to corresponding constant value.

    /components/ must be 0 if /genMode/ is NONE or for other allowed /genMode/
    values must be one of 1, 2, 3, or 4; otherwise INVALID_VALUE is generated.
    /components/ determines how many fragment input components, how many
    coefficients read from the /coeffs/ array, and the linear equations used to
    generate the s, t, r, and q coordinates of the fragment input specified by
    /location/.

    In the following equations, coeffs[i] is the /i/th element (base zero) of
    the /coeffs/ array; x, y, z, and w are determined by the /genMode/.

    When /genMode/ is EYE_LINEAR_CHROMIUM, xcoeffs[i] is the /i/th element (base
    zero) of a /xcoeffs/ array generated by multiplying each respective vector
    of four elements of coeffs by the current inverse modelview matrix when
    ProgramPathFragmentInputGen is called.

        xcoeffs[0..3]   = coeffs[0..3]   * MV^-1
        xcoeffs[4..7]   = coeffs[4..7]   * MV^-1
        xcoeffs[8..11]  = coeffs[8..11]  * MV^-1
        xcoeffs[12..15] = coeffs[12..12] * MV^-1

    [[ NOTATION:

       xxx[0..3] is a vector form from xxx[0], xxx[1], xxx[2], and xxx[3]

       MV^-1 is the inverse of the current PATH_MODELVIEW_CHROMIUM matrix when
       ProgramPathFragmentInputGenCHROMIUM happens.

    ]]

    If the /components/ is 0, no values from the /coeffs/ array are
    accessed and the s, t, r, and q coordinates of a covered fragment's
    fragment input for /location/ are computed:

        s = 0
        t = 0
        r = 0
        q = 0

    If the /components/ is 1 and /genMode/ is OBJECT_LINEAR_CHROMIUM
    3 values from the /coeffs/ array are
    accessed and the s, t, r, and q coordinates of a covered fragment's
    fragment input for /location/ are computed:

        s = coeffs[0] * x + coeffs[1] * y + coeffs[2]
        t = 0
        r = 0
        q = 0

    Alternatively if the /genMode/ is EYE_LINEAR_CHROMIUM, then 4 values are
    accessed and the fragment input for /location/ are
    computed:

        s = xcoeffs[0] * xe + xcoeffs[1] * ye + xcoeffs[2] * ze + xcoeffs[3] * we
        t = 0
        r = 0
        q = 0

    Alternatively if the /genMode/ is CONSTANT_CHROMIUM, then:

        s = xcoeffs[0]
        t = 0
        r = 0
        q = 0

    If the /components/ is 2 and /genMode/ is OBJECT_LINEAR_CHROMIUM,
    6 values from the /coeffs/ array are accessed and the
    s, t, r, and q coordinates of a covered fragment's fragment input
    coordinates are computed:

        s = coeffs[0] * x + coeffs[1] * y + coeffs[2]
        t = coeffs[3] * x + coeffs[4] * y + coeffs[5]
        r = 0
        q = 0

    Alternatively if the /genMode/ is EYE_LINEAR_CHROMIUM, then 8 values are
    accessed and the fragment input coordinates are computed:

        s = xcoeffs[0] * xe + xcoeffs[1] * ye + xcoeffs[2] * ze + xcoeffs[3] * we
        t = xcoeffs[4] * xe + xcoeffs[5] * ye + xcoeffs[6] * ze + xcoeffs[7] * we
        r = 0
        q = 0

    Alternatively if the /genMode/ is CONSTANT_CHROMIUM, then:

        s = xcoeffs[0]
        t = xcoeffs[1]
        r = 0
        q = 0

    If the /components/ is 3 and /genMode/ is OBJECT_LINEAR_CHROMIUM 9 values
    from the /coeffs/ array are accessed and the s, t, r, and q coordinates of a
    covered fragment's fragment input coordinates for /location/ are computed:

        s = coeffs[0] * x + coeffs[1] * y + coeffs[2]
        t = coeffs[3] * x + coeffs[4] * y + coeffs[5]
        r = coeffs[6] * x + coeffs[7] * y + coeffs[8]
        q = 0

    Alternatively if the /genMode/ is CONSTANT_CHROMIUM, then:

        s = xcoeffs[0]
        t = xcoeffs[1]
        r = xcoeffs[2]
        q = 0

    Alternatively if the /genMode/ is EYE_LINEAR_CHROMIUM, then 12 values are
    accessed and the fragment input coodinates for /location/ are computed:

        s = xcoeffs[0] * xe + xcoeffs[1] * ye + xcoeffs[2]  * ze + xcoeffs[3]  * we
        t = xcoeffs[4] * xe + xcoeffs[5] * ye + xcoeffs[6]  * ze + xcoeffs[7]  * we
        r = xcoeffs[8] * xe + xcoeffs[9] * ye + xcoeffs[10] * ze + xcoeffs[11] * we
        q = 0

    If the /components/ is 4 and /genMode/ is OBJECT_LINEAR_CHROMIUM,
    12 values from the /coeffs/ array are accessed and the
    s, t, r, and q coordinates of a covered fragment's fragment input
    coordinates  for /location/ are computed:

        s = coeffs[0] * x + coeffs[1]  * y + coeffs[2]
        t = coeffs[3] * x + coeffs[4]  * y + coeffs[5]
        r = coeffs[6] * x + coeffs[7]  * y + coeffs[8]
        q = coeffs[9] * x + coeffs[10] * y + coeffs[11]

    Alternatively if the /genMode/ is EYE_LINEAR_CHROMIUM, then 16 values are
    accessed and the fragment input coordinates for /location/ are
    computed:

        s = xcoeffs[0]  * xe + xcoeffs[1]  * ye + xcoeffs[2]  * ze + xcoeffs[3]  * we
        t = xcoeffs[4]  * xe + xcoeffs[5]  * ye + xcoeffs[6]  * ze + xcoeffs[7]  * we
        r = xcoeffs[8]  * xe + xcoeffs[9]  * ye + xcoeffs[10] * ze + xcoeffs[11] * we
        q = xcoeffs[12] * xe + xcoeffs[13] * ye + xcoeffs[14] * ze + xcoeffs[15] * we

    Alternatively if the /genMode/ is CONSTANT_CHROMIUM, then:

        s = xcoeffs[0]
        t = xcoeffs[1]
        r = xcoeffs[2]
        q = xcoeffs[3]

    The initial mode is NONE and the coefficients are all initially zero.

    PATH COVERING RASTERIZATION DETAILS

    The GL processes fragments rasterized by path cover commands in
    much the same manner as fragments generated by conventional polygon
    rasterization.  However path rendering /ignores/ the following
    operations:

        *  Interpolation of per-vertex data (section 3.6.1).  Path
           primitives have neither conventional vertices nor per-vertex
           data.  Instead fragments generate interpolated per-fragment
           colors, texture coordinate sets, as a
           linear function of object-space or eye-space path coordinate's
           or using the current color or texture coordinate set state
           directly.

    Depth offset (section 3.6.2) and polygon multisample rasterization
    (3.6.3) do apply to path covering.

    Front and back face determination (explained in section 3.6.1 for
    polygons) operates somewhat differently for transformed paths than
    polygons.  The path's convex hull or bounding box
    (depending on the /coverMode/) is specified to wind counterclockwise
    in object space, though the transformation of the convex hull into
    window space could reverse this winding.  Whether the GL's front face
    state is CW or CCW (as set by the FrontFace command) determines
    if the path is front facing or not.  Because the specific vertices
    that belong to the covering geometry are implementation-dependent,
    when the signed area of the covering geometry (computed with equation
    3.6) is sufficiently near zero, the facingness of the path in such
    situations is ill-defined.

    The determination of whether a path transformed into window space is
    front facing or not affects face culling if enabled (section 3.6.1),
    the gl_FrontFacing built-in variable (section 3.9.2), and separate
    (two-sided) stencil testing (section 4.1.4).

Errors

    None.

New State

    Get Value                       Type   Get Command  Initial  Description
    -----------------------------  -----  ------------ -------- -------------------
    PATH_MODELVIEW_MATRIX_CHROMIUM  16xR   GetFloatv    all 0's  Current modelview
                                                                 matrix for path rendering
    PATH_PROJECTION_MATRIX_CHROMIUM 16xR   GetFloatv    all 0's  Current projection
                                                                 matrix for path rendering
    PATH_STENCIL_FUNC_CHROMIUM      Z8     GetIntegerv  ALWAYS   path stenciling function
    PATH_STENCIL_REF_CHROMIUM       Z+     GetIntegerv  0        path stenciling
                                                                 reference value
    PATH_STENCIL_VALUE_MASK_CHROMIUM                             path stencil read
                                    Z+     GetIntegerv  1's      mask

Tables
    Table 5.pathCommands: Path Commands

                                                       Coordinate
    Token                       Description            count
    ==========================  =====================  ==========
    MOVE_TO_CHROMIUM            Absolute move          2
                                current point
    --------------------------  ---------------------  ----------
    CLOSE_PATH_CHROMIUM         Close path             0
    --------------------------  ---------------------  ----------
    LINE_TO_CHROMIUM            Absolute line          2
    --------------------------  ---------------------  ----------
    QUADRATIC_CURVE_TO_CHROMIUM Absolute quadratic     4
    --------------------------  ---------------------  ----------
    CUBIC_CURVE_TO_CHROMIUM     Absolute cubic         6
                                Bezier segment
    --------------------------  ---------------------  ----------
    CONIC_CURVE_TO_CHROMIUM     Absolute conic         5
                                (rational Bezier)
                                segment


    Table 5.pathParameters
    Name                             Type     Required Values or Range
    -------------------------------  -------  -----------------------------------------------
    PATH_STROKE_WIDTH_CHROMIUM       float    non-negative
    PATH_END_CAPS_CHROMIUM           enum     FLAT, SQUARE_CHROMIUM, ROUND_CHROMIUM
    PATH_JOIN_STYLE_CHROMIUM         enum     MITER_REVERT_CHROMIUM, BEVEL_CHROMIUM, ROUND_CHROMIUM
    PATH_MITER_LIMIT_CHROMIUM        float    non-negative
    PATH_STROKE_BOUND_CHROMIUM       float    will be clamped to [0, 1.0], initially 0.2 (20%)


Issues

   1.   Should there be a distinct stencil function state for path
        stenciling?

        RESOLVED:  YES.  glPathStencilFunc sets the state.  How the
        stencil state needs to be configured for path covering is
        different than how the stencil function is configured typically
        for path stenciling.

        For example, stencil covering might use
        StencilFunc(NOT_EQUAL,0,~0) while path stenciling would
        use ALWAYS for the path stenciling stencil test.

        However there are other situations such as path clipping where it
        is useful to have the path stencil function configured differently
        such as PathStencilFunc(NOT_EQUAL, 0x00, 0x80) or other
        similar path clipping test.

   2.   Since Cover*Path* skips the vertex shader, what does it mean exactly
        wrt a fully linked program? What happens to the fragment shader's input
        varyings that are not filled by the vertex shader + rasterizer?

        It is possible that input varyings from a shader may not be written
        as output varyings of a preceding shader.  In this case, the unwritten
        input varying values are set to constant zeros.

   3.   What is the defined behavior when stroking if PATH_STROKE_WIDTH is
        zero?

        There will not be any samples within the stroke. I.e. the stroke does
        not produce any visible results.

   4.   How do you define a program that's valid to use with these calls.

        There is no change with respect to validity of the programs. All
        programs that are valid before this extension are valid after.
        All programs that are invalid before this extension is invalid
        after.

   5.   Can same programs be used to render regular GL primitives as well
        as in covering paths?

        Yes.

   6.  How is the fragment shader called when covering paths, and with
       which values for the inputs?

        gl_FragCoord: Interpolated coordinate of the path coverage.

        gl_FrontFacing:
         * Paths wind by default counterclockwise
         * Window space transform can reverse this winding
         * GL front face state CW/CCW selects whether the variable is true
           or false

        user-defined varyings: constant zeros.

Revision History

    14/8/2014    Documented the extension
