Skip to content

Commit

Permalink
[freetype] Implement rendering colored layer outlines
Browse files Browse the repository at this point in the history
COLR/CPAL tables extensions by Microsoft describes color fills
for outlines. This enables color emojis that can scale to any
size.
The spec is defined at:
https://www.microsoft.com/typography/otspec/colr.htm
https://www.microsoft.com/typography/otspec/cpal.htm

If the color palette does not exist or is invalid. The render
step rasterizes the outline instead. The current implementation
assumes foreground is black.

Enable this by defining the option TT_CONFIG_OPTION_COLOR_LAYERS
  • Loading branch information
ShaoYuZhang committed Nov 25, 2015
1 parent 4a15013 commit 27d9e6f
Show file tree
Hide file tree
Showing 17 changed files with 738 additions and 11 deletions.
9 changes: 9 additions & 0 deletions devel/ftoption.h
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,15 @@ FT_BEGIN_HEADER
#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS
/*************************************************************************/
/* */
/* Define TT_CONFIG_OPTION_COLOR_LAYERS if you want to support */
/* colored outline (COLR/CPAL table) in all formats using the */
/* SFNT module (namely TrueType & OpenType). */
/* */
#define TT_CONFIG_OPTION_COLOR_LAYERS
/*************************************************************************/
/* */
/* Define TT_CONFIG_OPTION_POSTSCRIPT_NAMES if you want to be able to */
Expand Down
9 changes: 9 additions & 0 deletions include/freetype/config/ftoption.h
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,15 @@ FT_BEGIN_HEADER
#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS
/*************************************************************************/
/* */
/* Define TT_CONFIG_OPTION_COLOR_LAYERS if you want to support */
/* colored outline (COLR/CPAL table) in all formats using the */
/* SFNT module (namely TrueType & OpenType). */
/* */
#define TT_CONFIG_OPTION_COLOR_LAYERS
/*************************************************************************/
/* */
/* Define TT_CONFIG_OPTION_POSTSCRIPT_NAMES if you want to be able to */
Expand Down
22 changes: 17 additions & 5 deletions include/freetype/freetype.h
Original file line number Diff line number Diff line change
Expand Up @@ -1573,6 +1573,16 @@ FT_BEGIN_HEADER
/* */
typedef struct FT_Slot_InternalRec_* FT_Slot_Internal;

/*************************************************************************/
/* */
/* <Type> */
/* FT_Colr_Internal */
/* */
/* <Description> */
/* An opaque handle to an `FT_Colr_InternalRec' structure, used to */
/* model color related private data of a given @FT_Face object. */
/* */
typedef struct FT_Colr_InternalRec_* FT_Colr_Internal;

/*************************************************************************/
/* */
Expand Down Expand Up @@ -1776,6 +1786,8 @@ FT_BEGIN_HEADER

FT_Slot_Internal internal;

FT_Colr_Internal color_layers;

} FT_GlyphSlotRec;


Expand Down Expand Up @@ -2737,11 +2749,11 @@ FT_BEGIN_HEADER
*
* FT_LOAD_COLOR ::
* This flag is used to request loading of color embedded-bitmap
* images. The resulting color bitmaps, if available, will have the
* @FT_PIXEL_MODE_BGRA format. When the flag is not used and color
* bitmaps are found, they will be converted to 256-level gray
* bitmaps transparently. Those bitmaps will be in the
* @FT_PIXEL_MODE_GRAY format.
* images or color outlines. The resulting color bitmaps, if
* available, will have the @FT_PIXEL_MODE_BGRA format. When
* the flag is not used and color bitmaps are found, they will
* be converted to 256-level gray bitmaps transparently.
* Those bitmaps will be in the @FT_PIXEL_MODE_GRAY format.
*
* FT_LOAD_COMPUTE_METRICS ::
* This flag sets computing glyph metrics without the use of bundled
Expand Down
12 changes: 12 additions & 0 deletions include/freetype/internal/ftobjs.h
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,18 @@ FT_BEGIN_HEADER

#endif

typedef struct FT_Glyph_LayerRec_
{
FT_UShort glyph_index;
FT_UShort color_index;
} FT_Glyph_LayerRec;

typedef struct FT_Colr_InternalRec_
{
FT_Glyph_LayerRec *layers;
FT_UShort num_layers;
FT_Int load_flags;
} FT_Colr_InternalRec;

/*************************************************************************/
/*************************************************************************/
Expand Down
80 changes: 80 additions & 0 deletions include/freetype/internal/sfnt.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,65 @@ FT_BEGIN_HEADER
FT_Short* abearing,
FT_UShort* aadvance );

/*************************************************************************/
/* */
/* <FuncType> */
/* TT_Load_Colr_Layer_Func */
/* */
/* <Description> */
/* Load the color layer data given a glyph index. */
/* */
/* <Input> */
/* face :: The target face object. */
/* idx :: The glyph index. */
/* */
/* */
/* <Output> */
/* layers :: The layer info with color index and glyph index. */
/* Free with FT_FREE() */
/* num_layers :: Number of layers */
/* */
/* <Return> */
/* FreeType error code. 0 means success. Returns an error if no */
/* color layer information exists for glyph index. */
/* */
typedef FT_Error
(*TT_Load_Colr_Layer_Func)( TT_Face face,
FT_Int idx,
FT_Glyph_LayerRec** layers,
FT_UShort* ret_num_layers );


/*************************************************************************/
/* */
/* <FuncType> */
/* TT_Blend_Colr_Func */
/* */
/* <Description> */
/* Blend the bitmap in newGlyph with color index dstSlot using the */
/* color specified by color_index. */
/* XXX: Handle foregound color */
/* */
/* <Input> */
/* face :: The target face object. */
/* color_index :: color_index from the COLR table */
/* base_glyph :: Slot to for bitmap to be merged into. Underlying */
/* bitmap maybe reallocated. */
/* new_glyph :: Slot to be incooperated into base_glyph. */
/* */
/* <Output> */
/* none */
/* */
/* <Return> */
/* FreeType error code. 0 means success. Returns an error if */
/* color_index is invalid or reallocation fails. */
/* */
typedef FT_Error
(*TT_Blend_Colr_Func)( TT_Face face,
FT_Int color_index,
FT_GlyphSlot base_glyph,
FT_GlyphSlot new_glyph );


/*************************************************************************/
/* */
Expand Down Expand Up @@ -585,6 +644,11 @@ FT_BEGIN_HEADER
TT_Set_SBit_Strike_Func set_sbit_strike;
TT_Load_Strike_Metrics_Func load_strike_metrics;

TT_Load_Table_Func load_colr;
TT_Free_Table_Func free_colr;
TT_Load_Colr_Layer_Func load_colr_layer;
TT_Blend_Colr_Func colr_blend;

TT_Get_Metrics_Func get_metrics;

TT_Get_Name_Func get_name;
Expand Down Expand Up @@ -627,6 +691,10 @@ FT_BEGIN_HEADER
free_eblc_, \
set_sbit_strike_, \
load_strike_metrics_, \
load_colr_, \
free_colr_, \
load_colr_layer_, \
colr_blend_, \
get_metrics_, \
get_name_ ) \
static const SFNT_Interface class_ = \
Expand Down Expand Up @@ -659,6 +727,10 @@ FT_BEGIN_HEADER
free_eblc_, \
set_sbit_strike_, \
load_strike_metrics_, \
load_colr_, \
free_colr_, \
load_colr_layer_, \
colr_blend_, \
get_metrics_, \
get_name_, \
};
Expand Down Expand Up @@ -696,6 +768,10 @@ FT_BEGIN_HEADER
load_hmtx_, \
load_eblc_, \
free_eblc_, \
load_colr_, \
free_colr_, \
load_colr_layer_, \
colr_blend_, \
set_sbit_strike_, \
load_strike_metrics_, \
get_metrics_, \
Expand Down Expand Up @@ -732,6 +808,10 @@ FT_BEGIN_HEADER
clazz->load_hmtx = load_hmtx_; \
clazz->load_eblc = load_eblc_; \
clazz->free_eblc = free_eblc_; \
clazz->load_colr = load_colr_; \
clazz->free_colr = free_colr_; \
clazz->load_colr_layer = load_colr_layer_; \
clazz->colr_blend_ = colr_blend_; \
clazz->set_sbit_strike = set_sbit_strike_; \
clazz->load_strike_metrics = load_strike_metrics_; \
clazz->get_metrics = get_metrics_; \
Expand Down
1 change: 1 addition & 0 deletions include/freetype/internal/tttypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,7 @@ FT_BEGIN_HEADER
TT_SbitTableType sbit_table_type;
FT_UInt sbit_num_strikes;

void* colr_and_cpal;
FT_Byte* kern_table;
FT_ULong kern_table_size;
FT_UInt num_kern_tables;
Expand Down
2 changes: 2 additions & 0 deletions include/freetype/tttags.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ FT_BEGIN_HEADER
#define TTAG_CID FT_MAKE_TAG( 'C', 'I', 'D', ' ' )
#define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' )
#define TTAG_cvar FT_MAKE_TAG( 'c', 'v', 'a', 'r' )
#define TTAG_COLR FT_MAKE_TAG( 'C', 'O', 'L', 'R' )
#define TTAG_CPAL FT_MAKE_TAG( 'C', 'P', 'A', 'L' )
#define TTAG_cvt FT_MAKE_TAG( 'c', 'v', 't', ' ' )
#define TTAG_DSIG FT_MAKE_TAG( 'D', 'S', 'I', 'G' )
#define TTAG_EBDT FT_MAKE_TAG( 'E', 'B', 'D', 'T' )
Expand Down
52 changes: 48 additions & 4 deletions src/base/ftobjs.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,14 @@
/* free bitmap buffer if needed */
ft_glyphslot_free_bitmap( slot );

/* free glyph color layers if needed */
if ( slot->color_layers )
{
FT_Colr_InternalRec *color_layers = slot->color_layers;
FT_FREE( color_layers->layers );
FT_FREE( slot->color_layers );
}

/* slot->internal might be NULL in out-of-memory situations */
if ( slot->internal )
{
Expand Down Expand Up @@ -4120,17 +4128,53 @@
FT_GlyphSlot slot,
FT_Render_Mode render_mode )
{
FT_Error error = FT_Err_Ok;
FT_Renderer renderer;


FT_Error error = FT_Err_Ok;
FT_Renderer renderer;
TT_Face ttface;
SFNT_Service sfnt;
FT_Int layer_idx;
FT_Int load_flags;
FT_Glyph_LayerRec *glyph_layers;

FT_Face face = slot->face;
/* if it is already a bitmap, no need to do anything */
switch ( slot->format )
{
case FT_GLYPH_FORMAT_BITMAP: /* already a bitmap, don't do anything */
break;

default:
if ( slot->color_layers != NULL )
{
error = FT_New_GlyphSlot( face, NULL );
ttface = (TT_Face)face;
sfnt = (SFNT_Service)ttface->sfnt;
if ( !error )
{
glyph_layers = slot->color_layers->layers;
for ( layer_idx = 0; layer_idx < slot->color_layers->num_layers; layer_idx++ )
{
load_flags = slot->color_layers->load_flags & ~FT_LOAD_COLOR;
error = FT_Load_Glyph( face, glyph_layers[layer_idx].glyph_index, load_flags );
if ( error )
break;

error = sfnt->colr_blend( ttface, glyph_layers[layer_idx].color_index,
slot, face->glyph );
if ( error )
break;
}
if ( !error )
slot->format = FT_GLYPH_FORMAT_BITMAP;
FT_Done_GlyphSlot( face->glyph );
}
if ( !error )
return error;

/* Failed to do the colored layer. Draw outline instead. */
slot->format = FT_GLYPH_FORMAT_OUTLINE;
}

{
FT_ListNode node = NULL;

Expand Down
1 change: 1 addition & 0 deletions src/sfnt/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ SubDir FT2_TOP $(FT2_SRC_DIR) sfnt ;
ttmtx
ttpost
ttsbit
ttcolr
;
}
else
Expand Down
1 change: 1 addition & 0 deletions src/sfnt/rules.mk
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ SFNT_DRV_SRC := $(SFNT_DIR)/ttload.c \
$(SFNT_DIR)/ttmtx.c \
$(SFNT_DIR)/ttcmap.c \
$(SFNT_DIR)/ttsbit.c \
$(SFNT_DIR)/ttcolr.c \
$(SFNT_DIR)/ttpost.c \
$(SFNT_DIR)/ttkern.c \
$(SFNT_DIR)/ttbdf.c \
Expand Down
15 changes: 15 additions & 0 deletions src/sfnt/sfdriver.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
#include "ttsbit.h"
#endif

#ifdef TT_CONFIG_OPTION_COLOR_LAYERS
#include "ttcolr.h"
#endif

#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
#include "ttpost.h"
#endif
Expand Down Expand Up @@ -451,6 +455,12 @@
#define PUT_EMBEDDED_BITMAPS( a ) NULL
#endif

#ifdef TT_CONFIG_OPTION_COLOR_LAYERS
#define PUT_COLOR_LAYERS( a ) a
#else
#define PUT_COLOR_LAYERS( a ) NULL
#endif

#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
#define PUT_PS_NAMES( a ) a
#else
Expand Down Expand Up @@ -505,6 +515,11 @@
PUT_EMBEDDED_BITMAPS( tt_face_set_sbit_strike ),
PUT_EMBEDDED_BITMAPS( tt_face_load_strike_metrics ),

PUT_COLOR_LAYERS( tt_face_load_colr ),
PUT_COLOR_LAYERS( tt_face_free_colr ),
PUT_COLOR_LAYERS( tt_face_load_colr_layers ),
PUT_COLOR_LAYERS( tt_face_colr_blend_layer ),

tt_face_get_metrics,

tt_face_get_name
Expand Down
4 changes: 4 additions & 0 deletions src/sfnt/sfnt.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
#include "ttsbit.c"
#endif

#ifdef TT_CONFIG_OPTION_COLOR_LAYERS
#include "ttcolr.c"
#endif

#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
#include "ttpost.c"
#endif
Expand Down
Loading

0 comments on commit 27d9e6f

Please sign in to comment.