[sfnt] Add API to retrieve 'COLR' v1 root paint (#59703).

* src/sfnt/ttcolr.c (BaseGlyphV1Record): New structure.
(tt_face_load_colr): Handle version 1 table header.
(find_base_glyph_v1_record): New auxiliary function.
(tt_face_get_colr_glyph_paint): New function to find the root
`FT_OpaquePaint` object for a given glyph ID.

* src/sfnt/ttcolr.h: Updated.
This commit is contained in:
Dominik Röttsches 2020-12-16 16:44:34 +02:00 committed by Werner Lemberg
parent 08dba4dc35
commit 9e422b67c8
3 changed files with 158 additions and 8 deletions

View File

@ -1,3 +1,15 @@
2020-12-16 Dominik Röttsches <drott@chromium.org>
[sfnt] Add API to retrieve 'COLR' v1 root paint (#59703).
* src/sfnt/ttcolr.c (BaseGlyphV1Record): New structure.
(tt_face_load_colr): Handle version 1 table header.
(find_base_glyph_v1_record): New auxiliary function.
(tt_face_get_colr_glyph_paint): New function to find the root
`FT_OpaquePaint` object for a given glyph ID.
* src/sfnt/ttcolr.h: Updated.
2020-12-16 Dominik Röttsches <drott@chromium.org>
Add new methods required for 'COLR' v1 to public API (#59703).

View File

@ -5,7 +5,7 @@
* TrueType and OpenType colored glyph layer support (body).
*
* Copyright (C) 2018-2020 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
* David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg.
*
* Originally written by Shao Yu Zhang <shaozhang@fb.com>.
*
@ -31,6 +31,7 @@
#include <freetype/internal/ftstream.h>
#include <freetype/tttags.h>
#include <freetype/ftcolor.h>
#include <freetype/config/integer-types.h>
#ifdef TT_CONFIG_OPTION_COLOR_LAYERS
@ -39,12 +40,16 @@
/* NOTE: These are the table sizes calculated through the specs. */
#define BASE_GLYPH_SIZE 6U
#define LAYER_SIZE 4U
#define COLR_HEADER_SIZE 14U
#define BASE_GLYPH_SIZE 6U
#define BASE_GLYPH_V1_RECORD_SIZE 6U
#define LAYER_V1_LIST_PAINT_OFFSET_SIZE 4U
#define LAYER_V1_LIST_NUM_LAYERS_SIZE 4U
#define COLOR_STOP_SIZE 6U
#define LAYER_SIZE 4U
#define COLR_HEADER_SIZE 14U
typedef struct BaseGlyphRecord_
typedef struct BaseGlyphRecord_
{
FT_UShort gid;
FT_UShort first_layer_index;
@ -53,7 +58,16 @@
} BaseGlyphRecord;
typedef struct Colr_
typedef struct BaseGlyphV1Record_
{
FT_UShort gid;
/* Offset from start of BaseGlyphV1List, i.e., from base_glyphs_v1. */
FT_ULong paint_offset;
} BaseGlyphV1Record;
typedef struct Colr_
{
FT_UShort version;
FT_UShort num_base_glyphs;
@ -62,7 +76,14 @@
FT_Byte* base_glyphs;
FT_Byte* layers;
/* The memory which backs up the `COLR' table. */
FT_ULong num_base_glyphs_v1;
/* Points at beginning of BaseGlyphV1List. */
FT_Byte* base_glyphs_v1;
FT_ULong num_layers_v1;
FT_Byte* layers_v1;
/* The memory that backs up the `COLR' table. */
void* table;
FT_ULong table_size;
@ -88,10 +109,14 @@
FT_Byte* table = NULL;
FT_Byte* p = NULL;
/* Needed for reading array lengths in referenced tables. */
FT_Byte* p1 = NULL;
Colr* colr = NULL;
FT_ULong base_glyph_offset, layer_offset;
FT_ULong base_glyphs_offset_v1, num_base_glyphs_v1;
FT_ULong layer_offset_v1, num_layers_v1;
FT_ULong table_size;
@ -115,7 +140,7 @@
goto NoColr;
colr->version = FT_NEXT_USHORT( p );
if ( colr->version != 0 )
if ( colr->version != 0 && colr->version != 1 )
goto InvalidTable;
colr->num_base_glyphs = FT_NEXT_USHORT( p );
@ -135,6 +160,35 @@
if ( colr->num_layers * LAYER_SIZE > table_size - layer_offset )
goto InvalidTable;
if ( colr->version == 1 )
{
base_glyphs_offset_v1 = FT_NEXT_ULONG( p );
if ( base_glyphs_offset_v1 >= table_size )
goto InvalidTable;
p1 = (FT_Byte*)( table + base_glyphs_offset_v1 );
num_base_glyphs_v1 = FT_PEEK_ULONG( p1 );
if ( num_base_glyphs_v1 * BASE_GLYPH_V1_RECORD_SIZE >
table_size - base_glyphs_offset_v1 )
goto InvalidTable;
colr->num_base_glyphs_v1 = num_base_glyphs_v1;
colr->base_glyphs_v1 = p1;
layer_offset_v1 = FT_NEXT_ULONG( p );
if ( !layer_offset_v1 || layer_offset_v1 >= table_size )
goto InvalidTable;
p1 = (FT_Byte*)( table + layer_offset_v1 );
num_layers_v1 = FT_PEEK_ULONG( p1 );
colr->num_layers_v1 = num_layers_v1;
colr->layers_v1 = p1;
}
colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset );
colr->layers = (FT_Byte*)( table + layer_offset );
colr->table = table;
@ -265,6 +319,85 @@
}
static FT_Bool
find_base_glyph_v1_record ( FT_Byte * base_glyph_begin,
FT_Int num_base_glyph,
FT_UInt glyph_id,
BaseGlyphV1Record *record )
{
FT_Int min = 0;
FT_Int max = num_base_glyph - 1;
while ( min <= max )
{
FT_Int mid = min + ( max - min ) / 2;
/*
* `base_glyph_begin` is the beginning of `BaseGlyphV1List`;
* skip `numBaseGlyphV1Records` by adding 4 to start binary search
* in the array of `BaseGlyphV1Record`.
*/
FT_Byte *p = base_glyph_begin + 4 + mid * BASE_GLYPH_V1_RECORD_SIZE;
FT_UShort gid = FT_NEXT_USHORT( p );
if ( gid < glyph_id )
min = mid + 1;
else if (gid > glyph_id )
max = mid - 1;
else
{
record->gid = gid;
record->paint_offset = FT_NEXT_ULONG ( p );
return 1;
}
}
return 0;
}
FT_LOCAL_DEF ( FT_Bool )
tt_face_get_colr_glyph_paint( TT_Face face,
FT_UInt base_glyph,
FT_OpaquePaint* opaque_paint )
{
Colr* colr = (Colr*)face->colr;
BaseGlyphV1Record base_glyph_v1_record;
FT_Byte* p;
if ( colr->version < 1 || !colr->num_base_glyphs_v1 ||
!colr->base_glyphs_v1 )
return 0;
if ( opaque_paint->p )
return 0;
if ( !find_base_glyph_v1_record( colr->base_glyphs_v1,
colr->num_base_glyphs_v1,
base_glyph,
&base_glyph_v1_record ) )
return 0;
if ( !base_glyph_v1_record.paint_offset ||
base_glyph_v1_record.paint_offset > colr->table_size )
return 0;
p = (FT_Byte*)( colr->base_glyphs_v1 +
base_glyph_v1_record.paint_offset );
if ( p >= ( (FT_Byte*)colr->table + colr->table_size ) )
return 0;
opaque_paint->p = p;
return 1;
}
FT_LOCAL_DEF( FT_Error )
tt_face_colr_blend_layer( TT_Face face,
FT_UInt color_index,

View File

@ -42,6 +42,11 @@ FT_BEGIN_HEADER
FT_UInt *acolor_index,
FT_LayerIterator* iterator );
FT_LOCAL( FT_Bool )
tt_face_get_colr_glyph_paint( TT_Face face,
FT_UInt base_glyph,
FT_OpaquePaint* paint );
FT_LOCAL( FT_Error )
tt_face_colr_blend_layer( TT_Face face,
FT_UInt color_index,