[sfnt] Provide optional root transform for 'COLR' v1 glyph graph.
* include/freetype/freetype.h (FT_Get_Color_Glyph_Paint): Additional function argument root_transform to control whether root transform should be returned. (FT_OpaquePaint): Additional tracking field to denote whether root transform is to be returned. * include/freetype/internal/sfnt.h (TT_Get_Color_Glyph_Paint_Func): Propagate additional argument. * src/base/ftobjs.c (FT_Get_Color_Glyph_Paint): Ditto. * src/sfnt/ttcolr.c (tt_face_get_colr_glyph_paint): Return root transform reflecting the size and tranform configured on FT_Face. (read_paint): Initialize and track status of insert_root_transform flag.
This commit is contained in:
parent
cc90307d71
commit
64f01bfedd
18
ChangeLog
18
ChangeLog
@ -1,3 +1,21 @@
|
||||
2021-02-09 Dominik Röttsches <drott@chromium.org>
|
||||
|
||||
[sfnt] Provide optional root transform for 'COLR' v1 glyph graph.
|
||||
|
||||
* include/freetype/freetype.h (FT_Get_Color_Glyph_Paint):
|
||||
Additional function argument `root_transform` to control whether
|
||||
root transform should be returned.
|
||||
(FT_OpaquePaint): Additional tracking field to denote whether
|
||||
root transform is to be returned.
|
||||
* include/freetype/internal/sfnt.h
|
||||
(TT_Get_Color_Glyph_Paint_Func): Propagate additional argument.
|
||||
* src/base/ftobjs.c (FT_Get_Color_Glyph_Paint): Ditto.
|
||||
* src/sfnt/ttcolr.c (tt_face_get_colr_glyph_paint): Return root
|
||||
transform reflecting the size and tranform configured on
|
||||
`FT_Face`.
|
||||
(read_paint): Initialize and track status of insert_root_transform
|
||||
flag.
|
||||
|
||||
2021-02-09 Xavier Claessens <xavier.claessens@collabora.com>
|
||||
|
||||
* meson.build: s/freetype2_dep/freetype_dep/.
|
||||
|
@ -4479,11 +4479,15 @@ FT_BEGIN_HEADER
|
||||
* p ::
|
||||
* An internal offset to a Paint table, needs to be set to NULL before
|
||||
* passing this struct as an argument to @FT_Get_Paint.
|
||||
*
|
||||
* insert_root_transform ::
|
||||
* An internal boolean to track whether an initial root transform is
|
||||
* to be provided. Do not set this value.
|
||||
*/
|
||||
typedef struct FT_Opaque_Paint_
|
||||
{
|
||||
FT_Byte* p;
|
||||
|
||||
FT_Bool insert_root_transform;
|
||||
} FT_OpaquePaint;
|
||||
|
||||
|
||||
@ -4879,6 +4883,33 @@ FT_BEGIN_HEADER
|
||||
} FT_COLR_Paint;
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @enum:
|
||||
* FT_Color_Root_Transform
|
||||
*
|
||||
* @description:
|
||||
* An enumeration to specify whether @FT_Get_Color_Glyph_Paint is to
|
||||
* return a root transform to configure the client's graphics context
|
||||
* matrix.
|
||||
*
|
||||
* @values:
|
||||
* FT_COLOR_INCLUDE_ROOT_TRANSFORM ::
|
||||
* Do include the root transform as the initial @FT_COLR_Paint object.
|
||||
*
|
||||
* FT_COLOR_NO_ROOT_TRANSFORM ::
|
||||
* Do not output an initial root transform.
|
||||
*/
|
||||
typedef enum FT_Color_Root_Transform_
|
||||
{
|
||||
FT_COLOR_INCLUDE_ROOT_TRANSFORM,
|
||||
FT_COLOR_NO_ROOT_TRANSFORM,
|
||||
|
||||
FT_COLOR_ROOT_TRANSFORM_MAX
|
||||
|
||||
} FT_Color_Root_Transform;
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @function:
|
||||
@ -4898,6 +4929,26 @@ FT_BEGIN_HEADER
|
||||
* function and specifying a glyph ID, one retrieves the root paint
|
||||
* table for this glyph ID.
|
||||
*
|
||||
* This function allows control whether an initial root transform is
|
||||
* returned to configure scaling, transform, and translation correctly
|
||||
* on the client's graphics context. The initial root transform is
|
||||
* computed and returned according to the values configured for @FT_Size
|
||||
* and @FT_Set_Transform on the @FT_Face object, see below for details
|
||||
* of the `root_transform` parameter. This has implications for a
|
||||
* client 'COLR' v1 implementation: When this function returns an
|
||||
* initially computed root transform, at the time of executing the
|
||||
* @FT_Paint_Glyph operation, the contours should be retrieved using
|
||||
* @FT_Load_Glyph at unscaled, untransformed size. This is because the
|
||||
* root transform applied to the graphics context will take care of
|
||||
* correct scaling.
|
||||
*
|
||||
* Alternatively, to allow hinting of contours, at the time of executing
|
||||
* @FT_Load_Glyph, the current graphics context transformation matrix
|
||||
* can be decomposed into a scaling matrix and a remainder, and
|
||||
* @FT_Load_Glyph can be used to retrieve the contours at scaled size.
|
||||
* Care must then be taken to blit or clip to the graphics context with
|
||||
* taking this remainder transformation into account.
|
||||
*
|
||||
* @input:
|
||||
* face ::
|
||||
* A handle to the parent face object.
|
||||
@ -4905,6 +4956,28 @@ FT_BEGIN_HEADER
|
||||
* base_glyph ::
|
||||
* The glyph index for which to retrieve the root paint table.
|
||||
*
|
||||
* root_transform ::
|
||||
* Specifies whether an initially computed root is returned by
|
||||
* @FT_Paint_Transformed to account for the activated size (see
|
||||
* @FT_Activate_Size) and the configured transform and translate (see
|
||||
* @FT_Set_Translate).
|
||||
*
|
||||
* This root transform is returned before nodes of the glyph graph of
|
||||
* the font are returned. Subsequent @FT_COLR_Paint structures
|
||||
* contain unscaled and untransformed values. The inserted root
|
||||
* transform enables the client application to apply an initial
|
||||
* transform to its graphics context. When executing subsequent
|
||||
* FT_COLR_Paint operations, values from @FT_COLR_Paint operations
|
||||
* will ultimately be correctly scaled because of the root transform
|
||||
* applied to the graphics context. Use
|
||||
* @FT_COLOR_INCLUDE_ROOT_TRANSFORM to include the root transform, use
|
||||
* @FT_COLOR_NO_ROOT_TRANSFORM to not include it. The latter may be
|
||||
* useful when traversing the 'COLR' v1 glyph graph and reaching a
|
||||
* @FT_PaintColrGlyph. When recursing into @FT_PaintColrGlyph and
|
||||
* painting that inline, no additional root transform is needed as it
|
||||
* has already been applied to the graphics context at the beginning
|
||||
* of drawing this glyph.
|
||||
*
|
||||
* @output:
|
||||
* paint ::
|
||||
* The @FT_OpaquePaint object that references the actual paint table.
|
||||
@ -4918,9 +4991,10 @@ FT_BEGIN_HEADER
|
||||
* error, value~0 is returned also.
|
||||
*/
|
||||
FT_EXPORT( FT_Bool )
|
||||
FT_Get_Color_Glyph_Paint( FT_Face face,
|
||||
FT_UInt base_glyph,
|
||||
FT_OpaquePaint* paint );
|
||||
FT_Get_Color_Glyph_Paint( FT_Face face,
|
||||
FT_UInt base_glyph,
|
||||
FT_Color_Root_Transform root_transform,
|
||||
FT_OpaquePaint* paint );
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -549,9 +549,10 @@ FT_BEGIN_HEADER
|
||||
* error, value~0 is returned also.
|
||||
*/
|
||||
typedef FT_Bool
|
||||
( *TT_Get_Color_Glyph_Paint_Func )( TT_Face face,
|
||||
FT_UInt base_glyph,
|
||||
FT_OpaquePaint *paint );
|
||||
( *TT_Get_Color_Glyph_Paint_Func )( TT_Face face,
|
||||
FT_UInt base_glyph,
|
||||
FT_Color_Root_Transform root_transform,
|
||||
FT_OpaquePaint *paint );
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -5571,9 +5571,10 @@
|
||||
/* documentation is in freetype.h */
|
||||
|
||||
FT_EXPORT_DEF ( FT_Bool )
|
||||
FT_Get_Color_Glyph_Paint( FT_Face face,
|
||||
FT_UInt base_glyph,
|
||||
FT_OpaquePaint* paint )
|
||||
FT_Get_Color_Glyph_Paint( FT_Face face,
|
||||
FT_UInt base_glyph,
|
||||
FT_Color_Root_Transform root_transform,
|
||||
FT_OpaquePaint* paint )
|
||||
{
|
||||
TT_Face ttface;
|
||||
SFNT_Service sfnt;
|
||||
@ -5589,7 +5590,10 @@
|
||||
sfnt = (SFNT_Service)ttface->sfnt;
|
||||
|
||||
if ( sfnt->get_colr_layer )
|
||||
return sfnt->get_colr_glyph_paint( ttface, base_glyph, paint );
|
||||
return sfnt->get_colr_glyph_paint( ttface,
|
||||
base_glyph,
|
||||
root_transform,
|
||||
paint );
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
@ -396,8 +396,9 @@
|
||||
if ( paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
|
||||
return 0;
|
||||
|
||||
apaint->u.glyph.paint.p = paint_p;
|
||||
apaint->u.glyph.glyphID = FT_NEXT_USHORT( p );
|
||||
apaint->u.glyph.paint.p = paint_p;
|
||||
apaint->u.glyph.paint.insert_root_transform = 0;
|
||||
apaint->u.glyph.glyphID = FT_NEXT_USHORT( p );
|
||||
}
|
||||
|
||||
else if ( apaint->format == FT_COLR_PAINTFORMAT_SOLID )
|
||||
@ -475,7 +476,8 @@
|
||||
if ( paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
|
||||
return 0;
|
||||
|
||||
apaint->u.transformed.paint.p = paint_p;
|
||||
apaint->u.transformed.paint.p = paint_p;
|
||||
apaint->u.transformed.paint.insert_root_transform = 0;
|
||||
|
||||
/* skip VarIdx entries */
|
||||
apaint->u.transformed.affine.xx = FT_NEXT_LONG( p );
|
||||
@ -506,7 +508,8 @@
|
||||
if ( paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
|
||||
return 0;
|
||||
|
||||
apaint->u.translate.paint.p = paint_p;
|
||||
apaint->u.translate.paint.p = paint_p;
|
||||
apaint->u.translate.paint.insert_root_transform = 0;
|
||||
|
||||
/* skip VarIdx entries */
|
||||
apaint->u.translate.dx = FT_NEXT_LONG( p );
|
||||
@ -529,7 +532,8 @@
|
||||
if ( paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
|
||||
return 0;
|
||||
|
||||
apaint->u.rotate.paint.p = paint_p;
|
||||
apaint->u.rotate.paint.p = paint_p;
|
||||
apaint->u.rotate.paint.insert_root_transform = 0;
|
||||
|
||||
/* skip VarIdx entries */
|
||||
apaint->u.rotate.angle = FT_NEXT_LONG( p );
|
||||
@ -555,7 +559,8 @@
|
||||
if ( paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
|
||||
return 0;
|
||||
|
||||
apaint->u.skew.paint.p = paint_p;
|
||||
apaint->u.skew.paint.p = paint_p;
|
||||
apaint->u.skew.paint.insert_root_transform = 0;
|
||||
|
||||
/* skip VarIdx entries */
|
||||
apaint->u.skew.x_skew_angle = FT_NEXT_LONG( p );
|
||||
@ -588,7 +593,10 @@
|
||||
if ( source_paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
|
||||
return 0;
|
||||
|
||||
apaint->u.composite.source_paint.p = source_paint_p;
|
||||
apaint->u.composite.source_paint.p =
|
||||
source_paint_p;
|
||||
apaint->u.composite.source_paint.insert_root_transform =
|
||||
0;
|
||||
|
||||
composite_mode = FT_NEXT_BYTE( p );
|
||||
if ( composite_mode >= FT_COLR_COMPOSITE_MAX )
|
||||
@ -604,7 +612,10 @@
|
||||
if ( backdrop_paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
|
||||
return 0;
|
||||
|
||||
apaint->u.composite.backdrop_paint.p = backdrop_paint_p;
|
||||
apaint->u.composite.backdrop_paint.p =
|
||||
backdrop_paint_p;
|
||||
apaint->u.composite.backdrop_paint.insert_root_transform =
|
||||
0;
|
||||
}
|
||||
|
||||
else if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_GLYPH )
|
||||
@ -655,17 +666,16 @@
|
||||
|
||||
|
||||
FT_LOCAL_DEF ( FT_Bool )
|
||||
tt_face_get_colr_glyph_paint( TT_Face face,
|
||||
FT_UInt base_glyph,
|
||||
FT_OpaquePaint* opaque_paint )
|
||||
tt_face_get_colr_glyph_paint( TT_Face face,
|
||||
FT_UInt base_glyph,
|
||||
FT_Color_Root_Transform root_transform,
|
||||
FT_OpaquePaint* opaque_paint )
|
||||
{
|
||||
Colr* colr = (Colr*)face->colr;
|
||||
|
||||
Colr* colr = (Colr*)face->colr;
|
||||
BaseGlyphV1Record base_glyph_v1_record;
|
||||
FT_Byte* p;
|
||||
|
||||
|
||||
if ( !colr )
|
||||
if ( !colr || !colr->table )
|
||||
return 0;
|
||||
|
||||
if ( colr->version < 1 || !colr->num_base_glyphs_v1 ||
|
||||
@ -692,6 +702,11 @@
|
||||
|
||||
opaque_paint->p = p;
|
||||
|
||||
if ( root_transform == FT_COLOR_INCLUDE_ROOT_TRANSFORM )
|
||||
opaque_paint->insert_root_transform = 1;
|
||||
else
|
||||
opaque_paint->insert_root_transform = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -737,8 +752,12 @@
|
||||
colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ) )
|
||||
return 0;
|
||||
|
||||
paint_offset = FT_NEXT_ULONG( p );
|
||||
opaque_paint->p = (FT_Byte*)( colr->layers_v1 + paint_offset );
|
||||
paint_offset =
|
||||
FT_NEXT_ULONG( p );
|
||||
opaque_paint->insert_root_transform =
|
||||
0;
|
||||
opaque_paint->p =
|
||||
(FT_Byte*)( colr->layers_v1 + paint_offset );
|
||||
|
||||
iterator->p = p;
|
||||
|
||||
@ -794,21 +813,74 @@
|
||||
FT_OpaquePaint opaque_paint,
|
||||
FT_COLR_Paint* paint )
|
||||
{
|
||||
Colr* colr = (Colr*)face->colr;
|
||||
Colr* colr = (Colr*)face->colr;
|
||||
FT_OpaquePaint next_paint;
|
||||
FT_Matrix ft_root_scale;
|
||||
|
||||
FT_Byte* p;
|
||||
|
||||
|
||||
if ( !colr )
|
||||
if ( !colr || !colr->base_glyphs_v1 || !colr->table )
|
||||
return 0;
|
||||
|
||||
if ( opaque_paint.p < (FT_Byte*)colr->table ||
|
||||
opaque_paint.p >= ( (FT_Byte*)colr->table + colr->table_size ) )
|
||||
return 0;
|
||||
if ( opaque_paint.insert_root_transform )
|
||||
{
|
||||
/* 'COLR' v1 glyph information is returned in unscaled coordinates,
|
||||
* i.e., `FT_Size` is not applied or multiplied into the values. When
|
||||
* client applications draw color glyphs, they can request to include
|
||||
* a top-level transform, which includes the active `x_scale` and
|
||||
* `y_scale` information for scaling the glyph, as well the additional
|
||||
* transform and translate configured through `FT_Set_Transform`.
|
||||
* This allows client applications to apply this top-level transform
|
||||
* to the graphics context first and only once, then have gradient and
|
||||
* contour scaling applied correctly when performing the additional
|
||||
* drawing operations for subsequenct paints. Prepare this initial
|
||||
* transform here.
|
||||
*/
|
||||
paint->format = FT_COLR_PAINTFORMAT_TRANSFORMED;
|
||||
|
||||
p = opaque_paint.p;
|
||||
next_paint.p = opaque_paint.p;
|
||||
next_paint.insert_root_transform = 0;
|
||||
paint->u.transformed.paint = next_paint;
|
||||
|
||||
return read_paint( colr, p, paint );
|
||||
/* `x_scale` and `y_scale` are in 26.6 format, representing the scale
|
||||
* factor to get from font units to requested size. However, expected
|
||||
* return values are in 16.16, so we shift accordingly with rounding.
|
||||
*/
|
||||
ft_root_scale.xx = ( face->root.size->metrics.x_scale + 32 ) >> 6;
|
||||
ft_root_scale.xy = 0;
|
||||
ft_root_scale.yx = 0;
|
||||
ft_root_scale.yy = ( face->root.size->metrics.y_scale + 32 ) >> 6;
|
||||
|
||||
if ( face->root.internal->transform_flags & 1 )
|
||||
FT_Matrix_Multiply( &face->root.internal->transform_matrix,
|
||||
&ft_root_scale );
|
||||
|
||||
paint->u.transformed.affine.xx = ft_root_scale.xx;
|
||||
paint->u.transformed.affine.xy = ft_root_scale.xy;
|
||||
paint->u.transformed.affine.yx = ft_root_scale.yx;
|
||||
paint->u.transformed.affine.yy = ft_root_scale.yy;
|
||||
|
||||
/* The translation is specified in 26.6 format and, according to the
|
||||
* documentation of `FT_Set_Translate`, is performed on the character
|
||||
* size given in the last call to `FT_Set_Char_Size`. The
|
||||
* 'PaintTransformed' paint table's `FT_Affine23` format expects
|
||||
* values in 16.16 format, thus we need to shift by 10 bits.
|
||||
*/
|
||||
if ( face->root.internal->transform_flags & 2 )
|
||||
{
|
||||
paint->u.transformed.affine.dx =
|
||||
face->root.internal->transform_delta.x << 10;
|
||||
paint->u.transformed.affine.dy =
|
||||
face->root.internal->transform_delta.y << 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
paint->u.transformed.affine.dx = 0;
|
||||
paint->u.transformed.affine.dy = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return read_paint( colr, opaque_paint.p, paint );
|
||||
}
|
||||
|
||||
|
||||
|
@ -43,9 +43,10 @@ FT_BEGIN_HEADER
|
||||
FT_LayerIterator* iterator );
|
||||
|
||||
FT_LOCAL( FT_Bool )
|
||||
tt_face_get_colr_glyph_paint( TT_Face face,
|
||||
FT_UInt base_glyph,
|
||||
FT_OpaquePaint* paint );
|
||||
tt_face_get_colr_glyph_paint( TT_Face face,
|
||||
FT_UInt base_glyph,
|
||||
FT_Color_Root_Transform root_transform,
|
||||
FT_OpaquePaint* paint );
|
||||
|
||||
FT_LOCAL ( FT_Bool )
|
||||
tt_face_get_paint_layers( TT_Face face,
|
||||
|
Loading…
Reference in New Issue
Block a user