From 9df8c7dd27df66c79327babf7c011cc145c95563 Mon Sep 17 00:00:00 2001 From: Moazin Khatti Date: Sat, 10 Aug 2019 23:36:42 +0500 Subject: [PATCH] Adds OT-SVG glyph support to FT Glyph Management API. * include/freetype/ftglyph.h: Adds `FT_SvgGlyph' and `FT_SvgGlyphRec'. * src/base/ftglyph.c: Adds glyph class `ft_svg_glyph_class' and its methods. (FT_New_Glyph) Adds code to set the class of OT-SVG glyphs. (FT_Glyph_To_Bitmap) Adds code to free memory allocated for `FT_SVG_Document' in `dummy.other'. --- include/freetype/ftglyph.h | 70 ++++++++++++++++ src/base/ftglyph.c | 167 +++++++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+) diff --git a/include/freetype/ftglyph.h b/include/freetype/ftglyph.h index fedab8491..b29751e04 100644 --- a/include/freetype/ftglyph.h +++ b/include/freetype/ftglyph.h @@ -223,6 +223,76 @@ FT_BEGIN_HEADER } FT_OutlineGlyphRec; + /************************************************************************** + * + * @type: + * FT_SvgGlyph + * + * @description: + * A handle to an object used to model an SVG glyph image. This is a + * sub-class of @FT_Glyph, and a pointer to @FT_SvgGlyphRec. + */ + typedef struct FT_SvgGlyphRec_* FT_SvgGlyph; + + /************************************************************************** + * + * @struct: + * FT_SvgGlyphRec + * + * @description: + * A structure used for SVG glyph images. This really 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 the 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 starting glyph ID for the glyph range that this document has. + * + * end_glyph_id :: + * The ending glyph ID for the glyph range that this document has. + * + * @note: + * `metrics` and `units_per_EM` might look like repetitions since both + * fields are stored in face objects. However, the Glyph Management API + * requires an `FT_Glyph` to store all the information that completely + * describes a glyph. Outline glyphs are themselves scaled thus they + * don't need this information. However, SVG documents do. The field of + * `units_per_EM` is needed because the SVG is to be scaled in case its + * viewbox size differs from `units_per_EM`. For more info, refer to + * the section _Coordinate Systems and Glyph Metrics_ of the OpenType + * SVG specs. + */ + 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; + /* TODO: (OT-SVG) Maybe put a transformation matrix here */ + } FT_SvgGlyphRec; + + /************************************************************************** * * @function: diff --git a/src/base/ftglyph.c b/src/base/ftglyph.c index e6b132790..fa60ea1e7 100644 --- a/src/base/ftglyph.c +++ b/src/base/ftglyph.c @@ -35,6 +35,7 @@ #include FT_OUTLINE_H #include FT_BITMAP_H #include FT_INTERNAL_OBJECTS_H +#include FT_OTSVG_H /************************************************************************** @@ -275,6 +276,157 @@ ft_outline_glyph_prepare /* FT_Glyph_PrepareFunc glyph_prepare */ ) +#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; + glyph->svg_document = memory->alloc( memory, doc_length ); + 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; + /* 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 */ + memory->free( memory, 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 ); + return error; + } + + if ( source->svg_document_length == 0 ) + { + error = FT_THROW( Invalid_Slot_Handle ); + return error; + } + + + 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; + + /* allocate space for the svg document */ + target->svg_document = memory->alloc( memory, + target->svg_document_length ); + + /* copy the stuff */ + FT_MEM_COPY( target->svg_document, + source->svg_document, + target->svg_document_length ); + + return error; + } + + 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; + + 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 */ + NULL, /* FT_Glyph_TransformFunc glyph_transform */ + NULL, /* FT_Glyph_GetBBoxFunc glyph_bbox */ + ft_svg_glyph_prepare /* FT_Glyph_PrepareFunc glyph_prepare */ + ) + +#endif /*************************************************************************/ /*************************************************************************/ @@ -376,6 +528,12 @@ else if ( format == FT_GLYPH_FORMAT_OUTLINE ) clazz = &ft_outline_glyph_class; +#ifdef FT_CONFIG_OPTION_SVG + /* if it is a 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 */ @@ -592,7 +750,16 @@ /* prepare dummy slot for rendering */ error = clazz->glyph_prepare( glyph, &dummy ); 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 )