Add `FT_Glyph` support for OT-SVG glyphs.

* include/freetype/ftglyph.h (FT_SvgGlyphRec, FT_SvgGlyph): New structure.

* src/base/ftglyph.c: Include `otsvg.h`.
(ft_svg_glyph_init, ft_svg_glyph_done, ft_svg_glyph_copy,
ft_svg_glyph_transform, ft_svg_glyph_prepare): New function.
(ft_svg_glyph_class): New class.
(FT_New_Glyph, FT_Glyph_To_Bitmap): Updated to handle OT-SVG glyphs.
* src/base/ftglyph.h: Updated.
This commit is contained in:
Moazin Khatti 2021-12-25 19:55:58 -08:00 committed by Werner Lemberg
parent 5cf01aa2b2
commit 97c09a803e
3 changed files with 340 additions and 2 deletions

View File

@ -126,7 +126,7 @@ FT_BEGIN_HEADER
*
* @description:
* A handle to an object used to model a bitmap glyph image. This is a
* sub-class of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec.
* 'sub-class' of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec.
*/
typedef struct FT_BitmapGlyphRec_* FT_BitmapGlyph;
@ -142,7 +142,7 @@ FT_BEGIN_HEADER
*
* @fields:
* root ::
* The root @FT_Glyph fields.
* The root fields of @FT_Glyph.
*
* left ::
* The left-side bearing, i.e., the horizontal distance from the
@ -222,6 +222,92 @@ FT_BEGIN_HEADER
} FT_OutlineGlyphRec;
/**************************************************************************
*
* @type:
* FT_SvgGlyph
*
* @description:
* A handle to an object used to model an SVG glyph. This is a
* 'sub-class' of @FT_Glyph, and a pointer to @FT_SvgGlyphRec.
*
* @since:
* 2.12
*/
typedef struct FT_SvgGlyphRec_* FT_SvgGlyph;
/**************************************************************************
*
* @struct:
* FT_SvgGlyphRec
*
* @description:
* A structure used for OT-SVG glyphs. This is a 'sub-class' of
* @FT_GlyphRec.
*
* @fields:
* root ::
* The root @FT_GlyphRec fields.
*
* svg_document ::
* A pointer to the SVG document.
*
* svg_document_length ::
* The length of `svg_document`.
*
* glyph_index ::
* The index of the glyph to be rendered.
*
* metrics ::
* A metrics object storing the size information.
*
* units_per_EM ::
* The size of the EM square.
*
* start_glyph_id ::
* The first glyph ID in the glyph range covered by this document.
*
* end_glyph_id ::
* The last glyph ID in the glyph range covered by this document.
*
* transform ::
* A 2x2 transformation matrix to apply to the glyph while rendering
* it.
*
* delta ::
* Translation to apply to the glyph while rendering.
*
* @note:
* The Glyph Management API requires @FT_Glyph or its 'sub-class' to have
* all the information needed to completely define the glyph's rendering.
* Outline-based glyphs can directly apply transformations to the outline
* but this is not possible for an SVG document that hasn't been parsed.
* Therefore, the transformation is stored along with the document. In
* the absence of a 'ViewBox' or 'Width'/'Height' attribute, the size of
* the ViewPort should be assumed to be 'units_per_EM'.
*/
typedef struct FT_SvgGlyphRec_
{
FT_GlyphRec root;
FT_Byte* svg_document;
FT_ULong svg_document_length;
FT_UInt glyph_index;
FT_Size_Metrics metrics;
FT_UShort units_per_EM;
FT_UShort start_glyph_id;
FT_UShort end_glyph_id;
FT_Matrix transform;
FT_Vector delta;
} FT_SvgGlyphRec;
/**************************************************************************
*
* @function:

View File

@ -28,6 +28,7 @@ FT_BEGIN_HEADER
FT_DECLARE_GLYPH( ft_bitmap_glyph_class )
FT_DECLARE_GLYPH( ft_outline_glyph_class )
FT_DECLARE_GLYPH( ft_svg_glyph_class )
#ifdef FT_CONFIG_OPTION_MAC_FONTS

View File

@ -34,6 +34,7 @@
#include <freetype/ftoutln.h>
#include <freetype/ftbitmap.h>
#include <freetype/internal/ftobjs.h>
#include <freetype/otsvg.h>
#include "ftbase.h"
@ -277,6 +278,240 @@
)
#ifdef FT_CONFIG_OPTION_SVG
/*************************************************************************/
/*************************************************************************/
/**** ****/
/**** FT_SvgGlyph support ****/
/**** ****/
/*************************************************************************/
/*************************************************************************/
FT_CALLBACK_DEF( FT_Error )
ft_svg_glyph_init( FT_Glyph svg_glyph,
FT_GlyphSlot slot )
{
FT_ULong doc_length;
FT_SVG_Document document;
FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph;
FT_Error error = FT_Err_Ok;
FT_Memory memory = FT_GLYPH( glyph )->library->memory;
if ( slot->format != FT_GLYPH_FORMAT_SVG )
{
error = FT_THROW( Invalid_Glyph_Format );
goto Exit;
}
if ( slot->other == NULL )
{
error = FT_THROW( Invalid_Slot_Handle );
goto Exit;
}
document = (FT_SVG_Document)slot->other;
if ( document->svg_document_length == 0 )
{
error = FT_THROW( Invalid_Slot_Handle );
goto Exit;
}
/* allocate a new document */
doc_length = document->svg_document_length;
if ( FT_QALLOC( glyph->svg_document, doc_length ) )
goto Exit;
glyph->svg_document_length = doc_length;
glyph->glyph_index = slot->glyph_index;
glyph->metrics = document->metrics;
glyph->units_per_EM = document->units_per_EM;
glyph->start_glyph_id = document->start_glyph_id;
glyph->end_glyph_id = document->end_glyph_id;
glyph->transform = document->transform;
glyph->delta = document->delta;
/* copy the document into glyph */
FT_MEM_COPY( glyph->svg_document, document->svg_document, doc_length );
Exit:
return error;
}
FT_CALLBACK_DEF( void )
ft_svg_glyph_done( FT_Glyph svg_glyph )
{
FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph;
FT_Memory memory = svg_glyph->library->memory;
/* just free the memory */
FT_FREE( glyph->svg_document );
}
FT_CALLBACK_DEF( FT_Error )
ft_svg_glyph_copy( FT_Glyph svg_source,
FT_Glyph svg_target )
{
FT_SvgGlyph source = (FT_SvgGlyph)svg_source;
FT_SvgGlyph target = (FT_SvgGlyph)svg_target;
FT_Error error = FT_Err_Ok;
FT_Memory memory = FT_GLYPH( source )->library->memory;
if ( svg_source->format != FT_GLYPH_FORMAT_SVG )
{
error = FT_THROW( Invalid_Glyph_Format );
goto Exit;
}
if ( source->svg_document_length == 0 )
{
error = FT_THROW( Invalid_Slot_Handle );
goto Exit;
}
target->glyph_index = source->glyph_index;
target->svg_document_length = source->svg_document_length;
target->metrics = source->metrics;
target->units_per_EM = source->units_per_EM;
target->start_glyph_id = source->start_glyph_id;
target->end_glyph_id = source->end_glyph_id;
target->transform = source->transform;
target->delta = source->delta;
/* allocate space for the SVG document */
if ( FT_QALLOC( target->svg_document, target->svg_document_length ) )
goto Exit;
/* copy the document */
FT_MEM_COPY( target->svg_document,
source->svg_document,
target->svg_document_length );
Exit:
return error;
}
FT_CALLBACK_DEF( void )
ft_svg_glyph_transform( FT_Glyph svg_glyph,
const FT_Matrix* _matrix,
const FT_Vector* _delta )
{
FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph;
FT_Matrix* matrix = (FT_Matrix*)_matrix;
FT_Vector* delta = (FT_Vector*)_delta;
FT_Matrix tmp_matrix;
FT_Vector tmp_delta;
FT_Matrix a, b;
FT_Pos x, y;
if ( !matrix )
{
tmp_matrix.xx = 0x10000;
tmp_matrix.xy = 0;
tmp_matrix.yx = 0;
tmp_matrix.yy = 0x10000;
matrix = &tmp_matrix;
}
if ( !delta )
{
tmp_delta.x = 0;
tmp_delta.y = 0;
delta = &tmp_delta;
}
a = glyph->transform;
b = *matrix;
FT_Matrix_Multiply( &b, &a );
x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, glyph->delta.x ),
FT_MulFix( matrix->xy, glyph->delta.y ) ),
delta->x );
y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, glyph->delta.x ),
FT_MulFix( matrix->yy, glyph->delta.y ) ),
delta->y );
glyph->delta.x = x;
glyph->delta.y = y;
glyph->transform = a;
}
FT_CALLBACK_DEF( FT_Error )
ft_svg_glyph_prepare( FT_Glyph svg_glyph,
FT_GlyphSlot slot )
{
FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph;
FT_Error error = FT_Err_Ok;
FT_Memory memory = svg_glyph->library->memory;
FT_SVG_Document document;
if ( FT_NEW( document ) )
return error;
document->svg_document = glyph->svg_document;
document->svg_document_length = glyph->svg_document_length;
document->metrics = glyph->metrics;
document->units_per_EM = glyph->units_per_EM;
document->start_glyph_id = glyph->start_glyph_id;
document->end_glyph_id = glyph->end_glyph_id;
document->transform = glyph->transform;
document->delta = glyph->delta;
slot->format = FT_GLYPH_FORMAT_SVG;
slot->glyph_index = glyph->glyph_index;
slot->other = document;
return error;
}
FT_DEFINE_GLYPH(
ft_svg_glyph_class,
sizeof ( FT_SvgGlyphRec ),
FT_GLYPH_FORMAT_SVG,
ft_svg_glyph_init, /* FT_Glyph_InitFunc glyph_init */
ft_svg_glyph_done, /* FT_Glyph_DoneFunc glyph_done */
ft_svg_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */
ft_svg_glyph_transform, /* FT_Glyph_TransformFunc glyph_transform */
NULL, /* FT_Glyph_GetBBoxFunc glyph_bbox */
ft_svg_glyph_prepare /* FT_Glyph_PrepareFunc glyph_prepare */
)
#endif /* FT_CONFIG_OPTION_SVG */
/*************************************************************************/
/*************************************************************************/
/**** ****/
@ -377,6 +612,12 @@
else if ( format == FT_GLYPH_FORMAT_OUTLINE )
clazz = &ft_outline_glyph_class;
#ifdef FT_CONFIG_OPTION_SVG
/* if it is an SVG glyph */
else if ( format == FT_GLYPH_FORMAT_SVG )
clazz = &ft_svg_glyph_class;
#endif
else
{
/* try to find a renderer that supports the glyph image format */
@ -595,6 +836,16 @@
if ( !error )
error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode );
#ifdef FT_CONFIG_OPTION_SVG
if ( clazz == &ft_svg_glyph_class )
{
FT_Memory memory = library->memory;
FT_FREE( dummy.other );
}
#endif
#if 1
if ( !destroy && origin )
{