Compare commits

...

7 Commits

Author SHA1 Message Date
Moazin Khatti 503977f55c Adds transformation support for OT-SVG glyphs.
* include/freetype/ftglyph.h: Adds `transform' and `delta' fields
to `FT_SvgGlyphRed'.

* include/freetype/otsvg.h: Adds `transform' and `delta' fields to
`FT_SVG_Document'.

* src/base/ftglyph.c: Creates method `ft_svg_glyph_transform' and
modifies existing functions for the new fields.

* src/sfnt/ttsvg.c: (tt_face_load_svg_doc) Set `transform' to unity
and `delta' to zero by default.

* src/svg/ftsvg.c: Adds `ft_svg_transform'.
2019-08-17 23:42:27 +05:00
Moazin Khatti 9df8c7dd27 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'.
2019-08-17 22:47:37 +05:00
Moazin Khatti 1d9364ca89 [cache] Consider `FT_GLYPH_FORMAT_SVG' a valid format. 2019-08-10 23:32:25 +05:00
Moazin Khatti 865bba38d2 [svg] Creates new module for rendering OT-SVG glyphs.
For rendering OT-SVG glyphs, a new renderer module `ot-svg' is
created. The module holds hooks to an external library which are
used for rendering. The hooks can be set via module properties.
Also enabled bitmap presetting of OT-SVG glyphs at loading stage.

* include/freetype/fterrdef.h: Adds two errors, namely,
`Missing_SVG_Hooks' and `Invalid_SVG_Document'.

* include/freetype/internal/ftobjs.h: Adds `svg_renderer_state' to
`FT_LibraryRec' to let external libraries store state.

* include/freetype/internal/fttrace.h: Adds entry for `ot-svg'.

* modules.cfg: Ditto.

* include/freetype/internal/internal.h: Adds
`FT_INTERNAL_SVG_INTERFACE_H' for `svginterface.h'.

* include/freetype/internal/svginterface.h: Internal header file
to contain the interface of `ot-svg' module. Just exposes the
preset function.

* include/freetype/otsvg.h: Adds functypes for the four hooks and
a structure to hold them.

* src/base/ftobjs.c: (ft_glyphslot_preset_bitmap) Enable proper
presetting of OT-SVG glyphs by using `ot-svg' renderer.
(ft_add_renderer) Set `renderer->render' for `ot-svg' module.

* src/svg/ftsvg.h: Declaration for `ot-svg' module.

* src/svg/ftsvg.c: Module definition of `ot-svg' and its functions.

* src/svg/svg.c: Single source file of `ot-svg' module.

* src/svg/svgtypes.c: Defines `SVG_Renderer'.

* src/svg/rules.mk: Compilation rules for `ot-svg' module.

* src/svg/module.mk: Module definition of `ot-svg'.
2019-08-10 19:11:37 +05:00
Moazin Khatti ce64d9cbf1 Adds the functionality to load SVG documents.
SVG document corresponding to a glyphID is fetched and stored
in an `FT_SVG_Document' structure which is referenced in the
glyphslot.

* include/freetype/config/ftheader.h: Adds `FT_OTSVG_H'.

* include/freetype/ftimage.h: Adds `FT_GLYPH_FORMAT_SVG'.

* include/freetype/internal/ftobjs.h: Adds `FT_GLYPH_OWN_GZIP_SVG'.

* include/freetype/internal/sfnt.h: Adds `load_svg_doc' and its
function type `TT_Load_Svg_Doc_Func'.

* include/freetype/otsvg.h: Adds `FT_SVG_Document' and its struct.

* src/base/ftobjs.c: Adds code to allocate and free memory for
`FT_SVG_Document' in `slot->other'.

* src/cff/cffgload.c: Adds code to load SVG glyph if it's present.

* src/truetype/ttgload.c: Ditto.

* src/sfnt/sfdriver.c: Adds `tt_face_load_svg_doc'.

* src/sfnt/ttsvg.h: Ditto.

* src/sfnt/ttsvg.c: Adds implementation of `tt_face_load_svg_doc'
and its helper functions.
2019-08-10 16:11:07 +05:00
Moazin Khatti 92eeba75c4 [sfnt] Adds the functionality to load `SVG' table.
Adds code to load the SVG table data into an `svg'
structure and set the flag `FT_FACE_FLAG_SVG'.

* include/freetype/freetype.h: Adds `FT_FACE_FLAG_SVG'.

* include/freetype/internal/sfnt.h: Adds the fields
`load_svg' and `free_svg' to `SFNT_Interface'.

* include/freetype/internal/tttypes.h: Adds a void
pointer field `svg' to hold info from `SVG' table.

* include/freetype/internal/tttags.h: Adds the tag
`TTAG_SVG'.

* src/sfnt/ttsvg.c: Writes the functions
`tt_face_load_svg' and `tt_face_free_svg'

* src/sfnt/ttsvg.h: Writes header declarations for
`tt_face_load_svg' and `tt_face_free_svg'.

* src/sfnt/sfdriver.c: Adds the functions
`tt_face_load_svg' and `tt_face_free_svg' to
`sfnt_interface'.

* src/sfnt/sfnt.c: Includes `ttsvg.c'.

* src/sfnt/sfobjs.c: (sfnt_load_face) Adds code to
load `svg' table struct. (sfnt_done_face) Adds code
to free `svg' table struct.
2019-08-05 22:48:16 +05:00
Moazin Khatti 91e6a7b65f Adds `FT_CONFIG_OPTION_SVG' to allow toggling of OT-SVG support. 2019-08-05 16:12:17 +05:00
31 changed files with 1628 additions and 8 deletions

View File

@ -547,6 +547,19 @@
#define FT_BITMAP_H <freetype/ftbitmap.h>
/**************************************************************************
*
* @macro:
* FT_OTSVG_H
*
* @description:
* A macro used in `#include` statements to name the file containing the
* API of OT-SVG support related things.
*
*/
#define FT_OTSVG_H <freetype/otsvg.h>
/**************************************************************************
*
* @macro:

View File

@ -493,6 +493,15 @@ FT_BEGIN_HEADER
#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS
/**************************************************************************
*
* OpenType SVG Glyph Support
*
* If this macro is set, OpenType SVG glyphs will be supported.
*/
#define FT_CONFIG_OPTION_SVG
/**************************************************************************
*
* Error Strings

View File

@ -141,6 +141,7 @@ FT_BEGIN_HEADER
* FT_FACE_FLAG_GLYPH_NAMES
* FT_FACE_FLAG_EXTERNAL_STREAM
* FT_FACE_FLAG_HINTER
* FT_FACE_FLAG_SVG
*
* FT_HAS_HORIZONTAL
* FT_HAS_VERTICAL
@ -1167,6 +1168,10 @@ FT_BEGIN_HEADER
* table only if the native TrueType hinting engine (with the bytecode
* interpreter) is available and active.
*
* FT_FACE_FLAG_SVG ::
* The font file has an SVG table. The presence of an SVG table
* indicate the presence of OT-SVG glyphs.
*
* FT_FACE_FLAG_CID_KEYED ::
* The face is CID-keyed. In that case, the face is not accessed by
* glyph indices but by CID values. For subsetted CID-keyed fonts this
@ -1223,6 +1228,7 @@ FT_BEGIN_HEADER
#define FT_FACE_FLAG_TRICKY ( 1L << 13 )
#define FT_FACE_FLAG_COLOR ( 1L << 14 )
#define FT_FACE_FLAG_VARIATION ( 1L << 15 )
#define FT_FACE_FLAG_SVG ( 1L << 16 )
/**************************************************************************

View File

@ -101,6 +101,8 @@
"too many hints" )
FT_ERRORDEF_( Invalid_Pixel_Size, 0x17,
"invalid pixel size" )
FT_ERRORDEF_( Invalid_SVG_Document, 0x18,
"invalid SVG document" )
/* handle errors */
@ -234,6 +236,8 @@
"found FDEF or IDEF opcode in glyf bytecode" )
FT_ERRORDEF_( Missing_Bitmap, 0x9D,
"missing bitmap in strike" )
FT_ERRORDEF_( Missing_SVG_Hooks, 0x9E,
"hooks have not been set" )
/* CFF, CID, and Type 1 errors */

View File

@ -223,6 +223,83 @@ 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.
*
* transform ::
* Transformation matrix to apply on the glyph while rendering.
*
* delta ::
* Translation to apply on the glyph while rendering.
*
* @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;
FT_Matrix transform;
FT_Vector delta;
} FT_SvgGlyphRec;
/**************************************************************************
*
* @function:

View File

@ -732,6 +732,9 @@ FT_BEGIN_HEADER
* contours. Some Type~1 fonts, like those in the Hershey family,
* contain glyphs in this format. These are described as @FT_Outline,
* but FreeType isn't currently capable of rendering them correctly.
*
* FT_GLYPH_FORMAT_SVG ::
* The glyph is represented by an SVG document in the SVG table.
*/
typedef enum FT_Glyph_Format_
{
@ -740,7 +743,8 @@ FT_BEGIN_HEADER
FT_IMAGE_TAG( FT_GLYPH_FORMAT_COMPOSITE, 'c', 'o', 'm', 'p' ),
FT_IMAGE_TAG( FT_GLYPH_FORMAT_BITMAP, 'b', 'i', 't', 's' ),
FT_IMAGE_TAG( FT_GLYPH_FORMAT_OUTLINE, 'o', 'u', 't', 'l' ),
FT_IMAGE_TAG( FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't' )
FT_IMAGE_TAG( FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't' ),
FT_IMAGE_TAG( FT_GLYPH_FORMAT_SVG, 's', 'v', 'g', ' ' )
} FT_Glyph_Format;
@ -752,6 +756,7 @@ FT_BEGIN_HEADER
#define ft_glyph_format_bitmap FT_GLYPH_FORMAT_BITMAP
#define ft_glyph_format_outline FT_GLYPH_FORMAT_OUTLINE
#define ft_glyph_format_plotter FT_GLYPH_FORMAT_PLOTTER
#define ft_glyph_format_svg FT_GLYPH_FORMAT_SVG
/*************************************************************************/

View File

@ -418,7 +418,8 @@ FT_BEGIN_HEADER
* initializing the glyph slot.
*/
#define FT_GLYPH_OWN_BITMAP 0x1U
#define FT_GLYPH_OWN_BITMAP 0x1U
#define FT_GLYPH_OWN_GZIP_SVG 0x2U
typedef struct FT_Slot_InternalRec_
{
@ -889,6 +890,10 @@ FT_BEGIN_HEADER
* created. @FT_Reference_Library increments this counter, and
* @FT_Done_Library only destroys a library if the counter is~1,
* otherwise it simply decrements it.
*
* svg_renderer_state ::
* A pointer to a state object that will have the state of the SVG
* Renderer. This will be totally managed by the renderer.
*/
typedef struct FT_LibraryRec_
{
@ -916,6 +921,9 @@ FT_BEGIN_HEADER
FT_Int refcount;
#ifdef FT_CONFIG_OPTION_SVG
void* svg_renderer_state;
#endif
} FT_LibraryRec;

View File

@ -39,6 +39,7 @@ FT_TRACE_DEF( mm ) /* MM interface (ftmm.c) */
FT_TRACE_DEF( psprops ) /* PS driver properties (ftpsprop.c) */
FT_TRACE_DEF( raccess ) /* resource fork accessor (ftrfork.c) */
FT_TRACE_DEF( raster ) /* monochrome rasterizer (ftraster.c) */
FT_TRACE_DEF( otsvg ) /* ot-svg renderer (ftsvg.c) */
FT_TRACE_DEF( smooth ) /* anti-aliasing raster (ftgrays.c) */
FT_TRACE_DEF( synth ) /* bold/slant synthesizer (ftsynth.c) */

View File

@ -37,6 +37,7 @@
#define FT_INTERNAL_SERVICE_H <freetype/internal/ftserv.h>
#define FT_INTERNAL_RFORK_H <freetype/internal/ftrfork.h>
#define FT_INTERNAL_VALIDATE_H <freetype/internal/ftvalid.h>
#define FT_INTERNAL_SVG_INTERFACE_H <freetype/internal/svginterface.h>
#define FT_INTERNAL_TRUETYPE_TYPES_H <freetype/internal/tttypes.h>
#define FT_INTERNAL_TYPE1_TYPES_H <freetype/internal/t1types.h>

View File

@ -312,6 +312,31 @@ FT_BEGIN_HEADER
TT_SBit_MetricsRec *ametrics );
/**************************************************************************
*
* @functype:
* TT_Load_Svg_Doc_Func
*
* @description:
* Scans the SVG documents list to find the document containing the glyph
* that has the id "glyph<glyph_index>".
*
* @input:
* glyph ::
* The glyph slot from which pointers to SVG documents list will be
* grabbed. The results will be stored back in the slot too.
*
* glyph_index ::
* The index of the glyph that is to be looked up.
*
* @return:
* FreeType error code. 0 means success.
*/
typedef FT_Error
(*TT_Load_Svg_Doc_Func)( FT_GlyphSlot glyph,
FT_UInt glyph_index );
/**************************************************************************
*
* @functype:
@ -778,6 +803,11 @@ FT_BEGIN_HEADER
TT_Get_Name_Func get_name;
TT_Get_Name_ID_Func get_name_id;
/* OpenType SVG support */
TT_Load_Table_Func load_svg;
TT_Free_Table_Func free_svg;
TT_Load_Svg_Doc_Func load_svg_doc;
} SFNT_Interface;
@ -824,7 +854,10 @@ FT_BEGIN_HEADER
colr_blend_, \
get_metrics_, \
get_name_, \
get_name_id_ ) \
get_name_id_, \
load_svg_, \
free_svg_, \
load_svg_doc_ ) \
static const SFNT_Interface class_ = \
{ \
goto_table_, \
@ -864,7 +897,10 @@ FT_BEGIN_HEADER
colr_blend_, \
get_metrics_, \
get_name_, \
get_name_id_ \
get_name_id_, \
load_svg_, \
free_svg_, \
load_svg_doc_ \
};

View File

@ -0,0 +1,42 @@
/****************************************************************************
*
* svginterface.h
*
* Exposes the interface of ot-svg module
*
* Copyright (C) 1996-2019 by
* David Turner, Robert Wilhelm, Werner Lemberg and Moazin Khatti.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef SVGINTERFACE_H
#define SVGINTERFACE_H
#include <ft2build.h>
#include FT_OTSVG_H
FT_BEGIN_HEADER
typedef FT_Error
(*Preset_Bitmap_Func)( FT_Module module,
FT_GlyphSlot slot,
FT_Bool cache );
typedef struct SVG_Interface_
{
Preset_Bitmap_Func preset_slot;
} SVG_Interface;
typedef SVG_Interface* SVG_Service;
FT_END_HEADER
#endif

View File

@ -1645,6 +1645,9 @@ FT_BEGIN_HEADER
void* cpal;
void* colr;
/* OpenType SVG glyph support */
void* svg;
} TT_FaceRec;

189
include/freetype/otsvg.h Normal file
View File

@ -0,0 +1,189 @@
/****************************************************************************
*
* otsvg.h
*
* Interface for OT-SVG support related things (specification).
*
* Copyright (C) 2004-2019 by
* David Turner, Robert Wilhelm, Werner Lemberg and Moazin Khatti.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef FTSVG_RENDERER_H_
#define FTSVG_RENDERER_H_
#include <ft2build.h>
#include FT_FREETYPE_H
#ifdef FREETYPE_H
#error "freetype.h of FreeType 1 has been loaded!"
#error "Please fix the directory search order for header files"
#error "so that freetype.h of FreeType 2 is found first."
#endif
FT_BEGIN_HEADER
/**************************************************************************
*
* @functype:
* SVG_Lib_Init_Func
*
* @description:
* A callback used to initiate the SVG Rendering port
*
* @input:
* library ::
* A instance of library. This is required to initialize the
* renderer's state which will be held in the library.
*
* @return:
* FreeType error code. 0 means success.
*/
typedef FT_Error
(*SVG_Lib_Init_Func)( FT_Library library );
/**************************************************************************
*
* @functype:
* SVG_Lib_Free_Func
*
* @description:
* A callback used to free the SVG Rendering port. Calling this callback
* shall do all cleanups that the SVG Rendering port wants to do.
*
* @input:
* library ::
* A instance of library. This is required to free the renderer's
* state which will be held in the library.
*/
typedef void
(*SVG_Lib_Free_Func)( FT_Library library );
/**************************************************************************
*
* @functype:
* SVG_Lib_Render_Func
*
* @description:
* A callback used to render the glyph loaded in the slot.
*
* @input:
* slot ::
* The whole glyph slot object.
*
* @return:
* FreeType error code. 0 means success.
*/
typedef FT_Error
(*SVG_Lib_Render_Func)( FT_GlyphSlot slot );
/**************************************************************************
*
* @functype:
* SVG_Lib_Preset_Slot_Func
*
* @description:
* A callback used to preset the glyphslot.
*
* @input:
* slot ::
* The glyph slot which has the SVG document loaded.
*
* @return:
* FreeType error code. 0 means success.
*/
typedef FT_Error
(*SVG_Lib_Preset_Slot_Func)( FT_GlyphSlot slot, FT_Bool cache);
typedef struct SVG_RendererHooks_
{
/* Api Hooks for OT-SVG Rendering */
SVG_Lib_Init_Func init_svg;
SVG_Lib_Free_Func free_svg;
SVG_Lib_Render_Func render_svg;
SVG_Lib_Preset_Slot_Func preset_slot;
} SVG_RendererHooks;
/**************************************************************************
*
* @struct:
* FT_SVG_DocumentRec_
*
* @description:
* A structure that models one SVG document.
*
* @fields:
* svg_document ::
* A pointer to the SVG document string.
*
* svg_document_length ::
* The length of the SVG document string.
*
* 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.
*
* transform ::
* Transformation matrix to apply on the glyph while rendering.
*
* delta ::
* Translation to apply on the glyph while rendering.
*
* @note:
* `metrics` and `units_per_EM` might look like repetitions since both
* fields are stored in face object, but they are not; When the slot is
* passed down to a renderer, the renderer can only access the `metrics`
* and `units_per_EM` by `slot->face`. However, when `FT_Glyph_To_Bitmap`
* sets up a dummy object, it has no way to set a `face` object. Thus,
* metrics information and units_per_EM (which is necessary for OT-SVG)
* has to be stored separately.
*/
typedef struct FT_SVG_DocumentRec_
{
FT_Byte* svg_document;
FT_ULong svg_document_length;
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_SVG_DocumentRec;
/**************************************************************************
*
* @type:
* FT_SVG_Document
*
* @description:
* A handle to a FT_SVG_DocumentRec object.
*/
typedef struct FT_SVG_DocumentRec_* FT_SVG_Document;
FT_END_HEADER
#endif

View File

@ -96,6 +96,7 @@ FT_BEGIN_HEADER
#define TTAG_sbix FT_MAKE_TAG( 's', 'b', 'i', 'x' )
#define TTAG_sfnt FT_MAKE_TAG( 's', 'f', 'n', 't' )
#define TTAG_SING FT_MAKE_TAG( 'S', 'I', 'N', 'G' )
#define TTAG_SVG FT_MAKE_TAG( 'S', 'V', 'G', ' ' )
#define TTAG_trak FT_MAKE_TAG( 't', 'r', 'a', 'k' )
#define TTAG_true FT_MAKE_TAG( 't', 'r', 'u', 'e' )
#define TTAG_ttc FT_MAKE_TAG( 't', 't', 'c', ' ' )

View File

@ -99,6 +99,9 @@ RASTER_MODULES += raster
# Anti-aliasing rasterizer.
RASTER_MODULES += smooth
# OT-SVG
RASTER_MODULES += svg
####
#### auxiliary modules

View File

@ -35,6 +35,7 @@
#include FT_OUTLINE_H
#include FT_BITMAP_H
#include FT_INTERNAL_OBJECTS_H
#include FT_OTSVG_H
/**************************************************************************
@ -275,6 +276,212 @@
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;
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 */
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;
target->transform = source->transform;
target->delta = source->delta;
/* 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( 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 = _matrix;
FT_Vector* delta = _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
/*************************************************************************/
/*************************************************************************/
@ -376,6 +583,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 +805,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 )

View File

@ -28,6 +28,7 @@
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_SFNT_H /* for SFNT_Load_Table_Func */
#include FT_INTERNAL_POSTSCRIPT_AUX_H /* for PS_Driver */
#include FT_INTERNAL_SVG_INTERFACE_H
#include FT_TRUETYPE_TABLES_H
#include FT_TRUETYPE_TAGS_H
@ -40,6 +41,7 @@
#include FT_SERVICE_TT_CMAP_H
#include FT_SERVICE_KERNING_H
#include FT_SERVICE_TRUETYPE_ENGINE_H
#include FT_OTSVG_H
#include FT_DRIVER_H
@ -317,6 +319,17 @@
if ( !error && clazz->init_slot )
error = clazz->init_slot( slot );
#ifdef FT_CONFIG_OPTION_SVG
/* check if SVG table exists allocate the space in slot->other */
if ( slot->face->face_flags & FT_FACE_FLAG_SVG )
{
FT_SVG_Document document;
if ( FT_NEW( document ) )
goto Exit;
slot->other = document;
}
#endif
Exit:
return error;
}
@ -351,6 +364,7 @@
{
FT_Outline* outline = &slot->outline;
FT_Bitmap* bitmap = &slot->bitmap;
FT_Module module;
FT_Pixel_Mode pixel_mode;
@ -362,7 +376,19 @@
if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
{
if ( slot->format == FT_GLYPH_FORMAT_SVG )
{
SVG_Service svg_service;
module = FT_Get_Module(slot->library, "ot-svg" );
svg_service = (SVG_Service)module->clazz->module_interface;
return svg_service->preset_slot( module, slot, FALSE );
}
else
return 1;
return 1;
}
if ( origin )
{
@ -551,7 +577,23 @@
slot->subglyphs = NULL;
slot->control_data = NULL;
slot->control_len = 0;
#ifndef FT_CONFIG_OPTION_SVG
slot->other = NULL;
#else
if ( !( slot->face->face_flags & FT_FACE_FLAG_SVG ) )
slot->other = NULL;
else
{
if ( slot->internal->flags & FT_GLYPH_OWN_GZIP_SVG )
{
FT_Memory memory = slot->face->memory;
FT_SVG_Document doc = (FT_SVG_Document)slot->other;
FT_FREE( doc->svg_document );
slot->internal->load_flags &= ~FT_GLYPH_OWN_GZIP_SVG;
}
}
#endif
slot->format = FT_GLYPH_FORMAT_NONE;
slot->linearHoriAdvance = 0;
@ -569,6 +611,20 @@
FT_Memory memory = driver->root.memory;
#ifdef FT_CONFIG_OPTION_SVG
if ( slot->face->face_flags & FT_FACE_FLAG_SVG )
{
/* free memory in case svg was there */
if ( slot->internal->flags & FT_GLYPH_OWN_GZIP_SVG )
{
FT_SVG_Document doc = (FT_SVG_Document)slot->other;
FT_FREE( doc->svg_document );
slot->internal->flags &= ~FT_GLYPH_OWN_GZIP_SVG;
}
FT_FREE( slot->other );
}
#endif
if ( clazz->done_slot )
clazz->done_slot( slot );
@ -587,6 +643,7 @@
FT_FREE( slot->internal );
}
}
@ -4403,6 +4460,13 @@
render->render = clazz->render_glyph;
}
#ifdef FT_CONFIG_OPTION_SVG
if ( clazz->glyph_format == FT_GLYPH_FORMAT_SVG )
{
render->render = clazz->render_glyph;
}
#endif
/* add to list */
node->data = module;
FT_List_Add( &library->renderers, node );
@ -4538,7 +4602,6 @@
{
case FT_GLYPH_FORMAT_BITMAP: /* already a bitmap, don't do anything */
break;
default:
if ( slot->internal->load_flags & FT_LOAD_COLOR )
{
@ -5546,5 +5609,4 @@
return 0;
}
/* END */

View File

@ -177,7 +177,8 @@
if ( !error )
{
if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP ||
face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
face->glyph->format == FT_GLYPH_FORMAT_OUTLINE ||
face->glyph->format == FT_GLYPH_FORMAT_SVG )
{
/* ok, copy it */
FT_Glyph glyph;

View File

@ -347,6 +347,53 @@
if ( load_flags & FT_LOAD_SBITS_ONLY )
return FT_THROW( Invalid_Argument );
#ifdef FT_CONFIG_OPTION_SVG
/* check for OT-SVG */
if ( ( load_flags & FT_LOAD_COLOR ) &&
( ((TT_Face)glyph->root.face)->svg ) )
{
SFNT_Service sfnt;
FT_Short leftBearing;
FT_Short topBearing;
FT_UShort advanceX;
FT_UShort advanceY;
if ( ( size->root.metrics.x_ppem < 1 ||
size->root.metrics.y_ppem < 1 ) )
{
error = FT_THROW( Invalid_Size_Handle );
return error;
}
FT_TRACE3(( "Attemping to load SVG glyph\n" ));
sfnt = (SFNT_Service)((TT_Face)glyph->root.face)->sfnt;
error = sfnt->load_svg_doc( (FT_GlyphSlot)glyph, glyph_index );
if( error == FT_Err_Ok )
{
FT_TRACE3(( "Successfully loaded SVG glyph\n" ));
glyph->root.format = FT_GLYPH_FORMAT_SVG;
sfnt->get_metrics( face,
FALSE,
glyph_index,
&leftBearing,
&advanceX );
sfnt->get_metrics( face,
TRUE,
glyph_index,
&topBearing,
&advanceY );
advanceX *= ((float)glyph->root.face->size->metrics.x_ppem)/
((float)glyph->root.face->units_per_EM) * 64.0;
advanceY *= ((float)glyph->root.face->size->metrics.y_ppem)/
((float)glyph->root.face->units_per_EM) * 64.0;
glyph->root.metrics.horiAdvance = advanceX;
glyph->root.metrics.vertAdvance = advanceY;
return error;
}
FT_TRACE3(( "Failed to load SVG glyph\n" ));
}
#endif
/* if we have a CID subfont, use its matrix (which has already */
/* been multiplied with the root matrix) */

View File

@ -37,6 +37,10 @@
#include "ttcpal.h"
#endif
#ifdef FT_CONFIG_OPTION_SVG
#include "ttsvg.h"
#endif
#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
#include "ttpost.h"
#endif
@ -1208,6 +1212,12 @@
#define PUT_EMBEDDED_BITMAPS( a ) NULL
#endif
#ifdef FT_CONFIG_OPTION_SVG
#define PUT_SVG_SUPPORT( a ) a
#else
#define PUT_SVG_SUPPORT( a ) NULL
#endif
#ifdef TT_CONFIG_OPTION_COLOR_LAYERS
#define PUT_COLOR_LAYERS( a ) a
#else
@ -1294,7 +1304,14 @@
tt_face_get_metrics, /* TT_Get_Metrics_Func get_metrics */
tt_face_get_name, /* TT_Get_Name_Func get_name */
sfnt_get_name_id /* TT_Get_Name_ID_Func get_name_id */
sfnt_get_name_id, /* TT_Get_Name_ID_Func get_name_id */
PUT_SVG_SUPPORT( tt_face_load_svg ),
/* TT_Load_Table_Func load_svg */
PUT_SVG_SUPPORT( tt_face_free_svg ),
/* TT_Free_Table_Func free_svg */
PUT_SVG_SUPPORT( tt_face_load_svg_doc )
/* TT_Load_Svg_Doc_Func load_svg_doc */
)

View File

@ -27,6 +27,7 @@
#include "ttcmap.c"
#include "ttcolr.c"
#include "ttcpal.c"
#include "ttsvg.c"
#include "ttkern.c"
#include "ttload.c"

View File

@ -953,6 +953,11 @@
LOAD_( colr );
}
#ifdef FT_CONFIG_OPTION_SVG
if ( sfnt->load_svg )
LOAD_( svg );
#endif
/* consider the pclt, kerning, and gasp tables as optional */
LOAD_( pclt );
LOAD_( gasp );
@ -1372,6 +1377,12 @@
sfnt->free_cpal( face );
sfnt->free_colr( face );
}
#ifdef FT_CONFIG_OPTION_SVG
/* free svg data */
if ( sfnt->free_svg )
sfnt->free_svg( face );
#endif
}
#ifdef TT_CONFIG_OPTION_BDF

343
src/sfnt/ttsvg.c Normal file
View File

@ -0,0 +1,343 @@
/****************************************************************************
*
* ttsvg.c
*
* OpenType SVG Color (specification).
*
* Copyright (C) 2018-2019 by
* David Turner, Robert Wilhelm, Werner Lemberg and Moazin Khatti.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/**************************************************************************
*
* `SVG' table specification:
*
* https://docs.microsoft.com/en-us/typography/opentype/spec/svg
*
*/
#include <ft2build.h>
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_OBJECTS_H
#include FT_TRUETYPE_TAGS_H
#include FT_GZIP_H
#include FT_OTSVG_H
#ifdef FT_CONFIG_OPTION_SVG
#include "ttsvg.h"
typedef struct Svg_
{
FT_UShort version; /* Table version (starting at 0) */
FT_UShort num_entries; /* Number of SVG document records */
/* Pointer to the starting of SVG Document List */
FT_Byte* svg_doc_list;
void* table; /* Memory that backs up SVG */
FT_ULong table_size;
} Svg;
FT_LOCAL_DEF( FT_Error )
tt_face_load_svg( TT_Face face,
FT_Stream stream )
{
FT_Error error;
FT_Memory memory = face->root.memory;
FT_ULong table_size;
FT_Byte* table = NULL;
FT_Byte* p = NULL;
Svg* svg = NULL;
FT_ULong offsetToSVGDocumentList;
error = face->goto_table( face, TTAG_SVG, stream, &table_size );
if( error )
goto NoSVG;
if( FT_FRAME_EXTRACT( table_size, table ))
goto NoSVG;
/* Allocate the memory for the Svg object */
if( FT_NEW( svg ) )
goto NoSVG;
p = table;
svg->version = FT_NEXT_USHORT( p );
offsetToSVGDocumentList = FT_NEXT_ULONG( p );
if( offsetToSVGDocumentList == 0 )
goto InvalidTable;
svg->svg_doc_list = (FT_Byte*)( table + offsetToSVGDocumentList );
p = svg->svg_doc_list;
svg->num_entries = FT_NEXT_USHORT( p );
FT_TRACE3(( "version: %d\n", svg->version ));
FT_TRACE3(( "num entiries: %d\n", svg->num_entries ));
svg->table = table;
svg->table_size = table_size;
face->svg = svg;
face->root.face_flags |= FT_FACE_FLAG_SVG;
return FT_Err_Ok;
InvalidTable:
error = FT_THROW( Invalid_Table );
NoSVG:
FT_FRAME_RELEASE( table );
FT_FREE( svg );
face->svg = NULL;
return error;
}
FT_LOCAL_DEF( void )
tt_face_free_svg( TT_Face face )
{
FT_Memory memory = face->root.memory;
FT_Stream stream = face->root.stream;
Svg* svg = (Svg*) face->svg;
if( svg )
{
FT_FRAME_RELEASE( svg->table );
FT_FREE( svg );
}
}
typedef struct Svg_doc_
{
FT_UShort start_glyph_id;
FT_UShort end_glyph_id;
FT_ULong offset;
FT_ULong length;
} Svg_doc;
static Svg_doc
extract_svg_doc( FT_Byte* stream )
{
Svg_doc doc;
doc.start_glyph_id = FT_NEXT_USHORT( stream );
doc.end_glyph_id = FT_NEXT_USHORT( stream );
doc.offset = FT_NEXT_ULONG( stream );
doc.length = FT_NEXT_ULONG( stream );
return doc;
}
static FT_Int
compare_svg_doc( Svg_doc doc,
FT_UInt glyph_index )
{
if ( glyph_index < doc.start_glyph_id )
return -1;
else if ( glyph_index > doc.end_glyph_id )
return 1;
else
return 0;
}
static FT_Error
find_doc( FT_Byte* stream,
FT_UShort num_entries,
FT_UInt glyph_index,
FT_ULong *doc_offset,
FT_ULong *doc_length,
FT_UShort *start_glyph,
FT_UShort *end_glyph )
{
FT_Error error;
Svg_doc start_doc;
Svg_doc mid_doc;
Svg_doc end_doc;
FT_Bool found = FALSE;
FT_UInt i = 0;
FT_UInt start_index = 0;
FT_UInt end_index = num_entries - 1;
FT_Int comp_res;
/* search algo */
if ( num_entries == 0 )
{
error = FT_THROW( Invalid_Table );
return error;
}
FT_TRACE6(( "--- binary search glyph id: %d ---\n", glyph_index ));
start_doc = extract_svg_doc( stream + start_index * 12 );
end_doc = extract_svg_doc( stream + end_index * 12 );
FT_TRACE6(( "--- start glyph ---\n" ));
FT_TRACE6(( "start_id: %d\n", start_doc.start_glyph_id ));
FT_TRACE6(( "end_id: %d\n", start_doc.end_glyph_id ));
FT_TRACE6(( "--- end glyph ---\n" ));
FT_TRACE6(( "start_id: %d\n", end_doc.start_glyph_id ));
FT_TRACE6(( "end_id: %d\n", end_doc.end_glyph_id ));
if ( ( compare_svg_doc( start_doc, glyph_index ) == -1 ) ||
( compare_svg_doc( end_doc, glyph_index ) == 1 ) )
{
error = FT_THROW( Invalid_Glyph_Index );
return error;
}
while ( start_index <= end_index )
{
i = ( start_index + end_index ) / 2;
mid_doc = extract_svg_doc( stream + i * 12 );
FT_TRACE6(( "--- current glyph ---\n" ));
FT_TRACE6(( "start_id: %d\n", mid_doc.start_glyph_id ));
FT_TRACE6(( "end_id: %d\n", mid_doc.end_glyph_id ));
comp_res = compare_svg_doc( mid_doc, glyph_index );
if ( comp_res == 1 )
{
start_index = i + 1;
start_doc = extract_svg_doc( stream + start_index * 4 );
FT_TRACE6(( "RIGHT\n" ));
}
else if ( comp_res == -1 )
{
end_index = i - 1;
end_doc = extract_svg_doc( stream + end_index * 4 );
FT_TRACE6(( "LEFT\n" ));
}
else
{
found = TRUE;
FT_TRACE5(( "FOUND\n" ));
break;
}
}
FT_TRACE5(( "--- binary search end ---\n" ));
/* search algo end */
if ( found != TRUE )
{
FT_TRACE5(( "NOT FOUND\n" ));
error = FT_THROW( Invalid_Glyph_Index );
}
else
{
*doc_offset = mid_doc.offset;
*doc_length = mid_doc.length;
*start_glyph = mid_doc.start_glyph_id;
*end_glyph = mid_doc.end_glyph_id;
error = FT_Err_Ok;
}
return error;
}
FT_LOCAL_DEF( FT_Error )
tt_face_load_svg_doc( FT_GlyphSlot glyph,
FT_UInt glyph_index )
{
FT_Byte* doc_list; /* Pointer to the Svg Document List */
FT_UShort num_entries; /* Total no of entires in doc list */
FT_ULong doc_offset;
FT_ULong doc_length;
FT_UShort start_glyph_id;
FT_UShort end_glyph_id;
FT_ULong uncomp_size;
FT_Byte* uncomp_buffer;
FT_Error error = FT_Err_Ok;
TT_Face face = (TT_Face)glyph->face;
FT_Memory memory = face->root.memory;
Svg* svg = face->svg;
FT_SVG_Document svg_document = glyph->other;
FT_ASSERT( !( svg == NULL ) );
doc_list = svg->svg_doc_list;
num_entries = FT_NEXT_USHORT( doc_list );
error = find_doc( doc_list, num_entries, glyph_index,
&doc_offset, &doc_length,
&start_glyph_id, &end_glyph_id );
if ( error != FT_Err_Ok )
goto Exit;
doc_list = svg->svg_doc_list; /* Reset to so we can use it again */
doc_list = (FT_Byte*)( doc_list + doc_offset );
if( ( doc_list[0] == 0x1F ) && ( doc_list[1] == 0x8B )
&& ( doc_list[2] == 0x08 ) )
{
/* get the size of the orignal document. This helps in alotting the
* buffer to accomodate the uncompressed version. The last 4 bytes
* of the compressed document are equal to orignal_size modulo 2^32.
* Since SVG docs will be lesser in size then 2^32, we can use this
* accurately. The four bytes are stored in little-endian format.
*/
FT_TRACE4(( "SVG document found is GZIP compressed\n" ));
uncomp_size = (FT_ULong)doc_list[doc_length - 1] << 24 |
(FT_ULong)doc_list[doc_length - 2] << 16 |
(FT_ULong)doc_list[doc_length - 3] << 8 |
(FT_ULong)doc_list[doc_length - 4];
uncomp_buffer = (FT_Byte*) memory->alloc( memory, uncomp_size );
error = FT_Gzip_Uncompress( memory, uncomp_buffer, &uncomp_size,
doc_list, doc_length );
if ( error != FT_Err_Ok )
{
memory->free( memory, uncomp_buffer );
error = FT_THROW( Invalid_Table );
goto Exit;
}
glyph->internal->flags |= FT_GLYPH_OWN_GZIP_SVG;
doc_list = uncomp_buffer;
doc_length = uncomp_size;
}
svg_document->svg_document = doc_list;
svg_document->svg_document_length = doc_length;
svg_document->metrics = glyph->face->size->metrics;
svg_document->units_per_EM = glyph->face->units_per_EM;
svg_document->start_glyph_id = start_glyph_id;
svg_document->end_glyph_id = end_glyph_id;
svg_document->transform.xx = 0x10000;
svg_document->transform.xy = 0;
svg_document->transform.yx = 0;
svg_document->transform.yy = 0x10000;
svg_document->delta.x = 0;
svg_document->delta.y = 0;
FT_TRACE5(( "start_glyph_id: %d\n", start_glyph_id ));
FT_TRACE5(( "end_glyph_id: %d\n", end_glyph_id ));
FT_TRACE5(( "svg_document:\n%.*s\n", doc_length, doc_list ));
glyph->other = svg_document;
Exit:
return error;
}
#else /* !FT_CONFIG_OPTION_SVG */
/* ANSI C doesn't like empty source files */
typedef int _tt_svg_dummy;
#endif /* !FT_CONFIG_OPTION_SVG */

39
src/sfnt/ttsvg.h Normal file
View File

@ -0,0 +1,39 @@
/****************************************************************************
*
* ttsvg.h
*
* OpenType SVG Color (specification).
*
* Copyright (C) 2018-2019 by
* David Turner, Robert Wilhelm, Werner Lemberg and Moazin Khatti.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef __TTSVG_H__
#define __TTSVG_H__
#include <ft2build.h>
FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
tt_face_load_svg( TT_Face face,
FT_Stream stream );
FT_LOCAL( void )
tt_face_free_svg( TT_Face face );
FT_LOCAL( FT_Error )
tt_face_load_svg_doc( FT_GlyphSlot glyph,
FT_UInt glyph_index );
FT_END_HEADER
#endif /* __TTSVG_H__ */
/* END */

259
src/svg/ftsvg.c Normal file
View File

@ -0,0 +1,259 @@
/****************************************************************************
*
* ftsvg.c
*
* The FreeType svg renderer interface (body).
*
* Copyright (C) 1996-2019 by
* David Turner, Robert Wilhelm, Werner Lemberg and Moazin Khatti.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <ft2build.h>
#include FT_INTERNAL_DEBUG_H
#include FT_SERVICE_PROPERTIES_H
#include FT_OTSVG_H
#include FT_INTERNAL_SVG_INTERFACE_H
#include FT_BBOX_H
#include <stdio.h>
#include "ftsvg.h"
#undef FT_COMPONENT
#define FT_COMPONENT otsvg
#ifdef FT_CONFIG_OPTION_SVG
/* ft_svg_init */
static FT_Error
ft_svg_init( SVG_Renderer svg_module )
{
FT_Error error = FT_Err_Ok;
svg_module->loaded = FALSE;
svg_module->hooks_set = FALSE;
return error;
}
static void
ft_svg_done( SVG_Renderer svg_module )
{
FT_Library library = svg_module->root.root.library;
if ( svg_module->loaded == TRUE &&
svg_module->hooks_set == TRUE )
svg_module->hooks.free_svg( library );
svg_module->loaded = FALSE;
}
static FT_Error
ft_svg_preset_slot( FT_Module module,
FT_GlyphSlot slot,
FT_Bool cache )
{
SVG_Renderer svg_renderer = (SVG_Renderer)module;
SVG_RendererHooks hooks = svg_renderer->hooks;
if ( svg_renderer->hooks_set == FALSE )
{
FT_TRACE1(( "Hooks are NOT set. Can't render OT-SVG glyphs\n" ));
return FT_THROW( Missing_SVG_Hooks );
}
return hooks.preset_slot( slot, cache );
}
static FT_Error
ft_svg_render( FT_Renderer renderer,
FT_GlyphSlot slot,
FT_Render_Mode mode,
const FT_Vector* origin )
{
SVG_Renderer svg_renderer = (SVG_Renderer)renderer;
FT_Library library = renderer->root.library;
FT_Memory memory = library->memory;
FT_Error error;
FT_ULong size_image_buffer;
SVG_RendererHooks hooks = svg_renderer->hooks;
if ( svg_renderer->hooks_set == FALSE )
{
FT_TRACE1(( "Hooks are NOT set. Can't render OT-SVG glyphs\n" ));
return FT_THROW( Missing_SVG_Hooks );
}
if ( svg_renderer->loaded == FALSE )
{
FT_TRACE3(( "ft_svg_render: first rendering, calling init hook\n" ));
error = hooks.init_svg( library );
svg_renderer->loaded = TRUE;
}
ft_svg_preset_slot( (FT_Module)renderer, slot, TRUE);
size_image_buffer = slot->bitmap.pitch * slot->bitmap.rows;
FT_MEM_ALLOC( slot->bitmap.buffer, size_image_buffer);
if ( error )
return error;
return hooks.render_svg( slot );
}
static const SVG_Interface svg_interface = {
(Preset_Bitmap_Func)ft_svg_preset_slot
};
static FT_Error
ft_svg_property_set( FT_Module module,
const char* property_name,
const void* value,
FT_Bool value_is_string )
{
FT_Error error = FT_Err_Ok;
SVG_Renderer renderer = (SVG_Renderer)module;
if ( !ft_strcmp( property_name, "svg_hooks" ) )
{
SVG_RendererHooks* hooks = (SVG_RendererHooks*)value;
renderer->hooks = *hooks;
renderer->hooks_set = TRUE;
}
else
{
error = FT_THROW( Missing_Property );
}
return error;
}
static FT_Error
ft_svg_property_get( FT_Module module,
const char* property_name,
const void* value )
{
FT_Error error = FT_Err_Ok;
SVG_Renderer renderer = (SVG_Renderer)module;
if ( !ft_strcmp( property_name, "svg_hooks" ) )
{
SVG_RendererHooks* hooks = (SVG_RendererHooks*)value;
*hooks = renderer->hooks;
}
else
{
error = FT_THROW( Missing_Property );
}
return error;
}
FT_DEFINE_SERVICE_PROPERTIESREC(
ft_svg_service_properties,
(FT_Properties_SetFunc)ft_svg_property_set, /* set_property */
(FT_Properties_GetFunc)ft_svg_property_get /* get_property */
)
FT_DEFINE_SERVICEDESCREC1(
ft_svg_services,
FT_SERVICE_ID_PROPERTIES, &ft_svg_service_properties )
FT_CALLBACK_DEF( FT_Module_Interface )
ft_svg_get_interface( FT_Module module,
const char* ft_svg_interface )
{
FT_Module_Interface result;
result = ft_service_list_lookup( ft_svg_services, ft_svg_interface );
if ( result )
return result;
return 0;
}
static FT_Error
ft_svg_transform( FT_Renderer renderer,
FT_GlyphSlot slot,
const FT_Matrix* _matrix,
const FT_Vector* _delta )
{
FT_SVG_Document doc = (FT_SVG_Document)slot->other;
FT_Matrix* matrix = _matrix;
FT_Vector* delta = _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;
}
a = doc->transform;
b = *matrix;
FT_Matrix_Multiply( &b, &a );
x = ADD_LONG(ADD_LONG(
FT_MulFix(matrix->xx, doc->delta.x),
FT_MulFix(matrix->xy, doc->delta.y)),
delta->x);
y = ADD_LONG(ADD_LONG(
FT_MulFix(matrix->yx, doc->delta.x),
FT_MulFix(matrix->yy, doc->delta.y)),
delta->y);
doc->delta.x = x;
doc->delta.y = y;
doc->transform = a;
return FT_Err_Ok;
}
#endif
#ifdef FT_CONFIG_OPTION_SVG
#define PUT_SVG_MODULE( a ) a
#define SVG_GLYPH_FORMAT FT_GLYPH_FORMAT_SVG
#else
#define PUT_SVG_MODULE( a ) NULL
#define SVG_GLYPH_FORMAT FT_GLYPH_FORMAT_NONE
#endif
FT_DEFINE_RENDERER(
ft_svg_renderer_class,
FT_MODULE_RENDERER,
sizeof( SVG_RendererRec ),
"ot-svg",
0x10000L,
0x20000L,
(const void*)&svg_interface, /* module specific interface */
(FT_Module_Constructor)PUT_SVG_MODULE( ft_svg_init ), /* module_init */
(FT_Module_Destructor)PUT_SVG_MODULE( ft_svg_done ), /* module_done */
PUT_SVG_MODULE( ft_svg_get_interface ), /* get_interface */
SVG_GLYPH_FORMAT,
(FT_Renderer_RenderFunc)PUT_SVG_MODULE( ft_svg_render ),
(FT_Renderer_TransformFunc)PUT_SVG_MODULE( ft_svg_transform ),
NULL,
NULL,
NULL
)

32
src/svg/ftsvg.h Normal file
View File

@ -0,0 +1,32 @@
/****************************************************************************
*
* ftsvg.h
*
* The FreeType svg renderer interface (specification).
*
* Copyright (C) 1996-2019 by
* David Turner, Robert Wilhelm, Werner Lemberg and Moazin Khatti.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef FTSVG_H_
#define FTSVG_H_
#include <ft2build.h>
#include FT_RENDER_H
FT_BEGIN_HEADER
FT_DECLARE_RENDERER( ft_svg_renderer_class )
FT_END_HEADER
#endif /* FTSVG_H_ */
/* END */

23
src/svg/module.mk Normal file
View File

@ -0,0 +1,23 @@
#
# FreeType 2 svg renderer module definition
#
# Copyright (C) 1996-2019 by
# David Turner, Robert Wilhelm, Werner Lemberg and Moazin Khatti.
#
# This file is part of the FreeType project, and may only be used, modified,
# and distributed under the terms of the FreeType project license,
# LICENSE.TXT. By continuing to use, modify, or distribute this file you
# indicate that you have read the license and understand and accept it
# fully.
FTMODULE_H_COMMANDS += SVG_MODULE
define SVG_MODULE
$(OPEN_DRIVER) FT_Renderer_Class, ft_svg_renderer_class $(CLOSE_DRIVER)
$(ECHO_DRIVER)svg $(ECHO_DRIVER_DESC)svg renderer module$(ECHO_DRIVER_DONE)
endef
# EOF

69
src/svg/rules.mk Normal file
View File

@ -0,0 +1,69 @@
#
# FreeType 2 svg renderer module build rules
#
# Copyright (C) 1996-2019 by
# David Turner, Robert Wilhelm, Werner Lemberg and Moazin Khatti.
#
# This file is part of the FreeType project, and may only be used, modified,
# and distributed under the terms of the FreeType project license,
# LICENSE.TXT. By continuing to use, modify, or distribute this file you
# indicate that you have read the license and understand and accept it
# fully.
# svg renderer driver directory
#
SVG_DIR := $(SRC_DIR)/svg
# compilation flags for the driver
#
SVG_COMPILE := $(CC) $(ANSIFLAGS) \
$I$(subst /,$(COMPILER_SEP),$(SVG_DIR)) \
$(INCLUDE_FLAGS) \
$(FT_CFLAGS)
# svg renderer sources (i.e., C files)
#
SVG_DRV_SRC := $(SVG_DIR)/ftsvg.c \
$(SVG_DIR)/svgtypes.c
# svg renderer headers
#
SVG_DRV_H := $(SVG_DIR)/ftsvg.h
# svg renderer object(s)
#
# SVG_DRV_OBJ_M is used during `multi' builds.
# SVG_DRV_OBJ_S is used during `single' builds.
#
SVG_DRV_OBJ_M := $(SVG_DRV_SRC:$(SVG_DIR)/%.c=$(OBJ_DIR)/%.$O)
SVG_DRV_OBJ_S := $(OBJ_DIR)/svg.$O
# svg renderer source file for single build
#
SVG_DRV_SRC_S := $(SVG_DIR)/svg.c
# svg renderer - single object
#
$(SVG_DRV_OBJ_S): $(SVG_DRV_SRC_S) $(SVG_DRV_SRC) \
$(FREETYPE_H) $(SVG_DRV_H)
$(SVG_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(SVG_DRV_SRC_S))
# svg renderer - multiple objects
#
$(OBJ_DIR)/%.$O: $(SVG_DIR)/%.c $(FREETYPE_H) $(SVG_DRV_H)
$(SVG_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)
# update main driver object lists
#
DRV_OBJS_S += $(SVG_DRV_OBJ_S)
DRV_OBJS_M += $(SVG_DRV_OBJ_M)
# EOF

25
src/svg/svg.c Normal file
View File

@ -0,0 +1,25 @@
/****************************************************************************
*
* svg.c
*
* FreeType svg renderer module component (body only).
*
* Copyright (C) 1996-2019 by
* David Turner, Robert Wilhelm, Werner Lemberg and Moazin Khatti.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#define FT_MAKE_OPTION_SINGLE_OBJECT
#include <ft2build.h>
#include "svgtypes.c"
#include "ftsvg.c"
/* END */

32
src/svg/svgtypes.c Normal file
View File

@ -0,0 +1,32 @@
/****************************************************************************
*
* svgtypes.h
*
* The FreeType svg renderer internal types (specification).
*
* Copyright (C) 1996-2019 by
* David Turner, Robert Wilhelm, Werner Lemberg and Moazin Khatti.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <ft2build.h>
#include FT_INTERNAL_OBJECTS_H
#include FT_RENDER_H
#include FT_OTSVG_H
typedef struct SVG_RendererRec_
{
FT_RendererRec root; /* This inherits FT_RendererRec */
FT_Bool loaded;
FT_Bool hooks_set;
SVG_RendererHooks hooks; /* Holds out hooks to the outside library */
} SVG_RendererRec;
typedef struct SVG_RendererRec_* SVG_Renderer;

View File

@ -2907,6 +2907,45 @@
goto Exit;
}
#ifdef FT_CONFIG_OPTION_SVG
/* check for OT-SVG */
if ( ( load_flags & FT_LOAD_COLOR ) && ( ((TT_Face)glyph->face)->svg ) )
{
SFNT_Service sfnt;
FT_Short leftBearing;
FT_Short topBearing;
FT_UShort advanceX;
FT_UShort advanceY;
FT_TRACE3(( "Attemping to load SVG glyph\n" ));
sfnt = (SFNT_Service)((TT_Face)glyph->face)->sfnt;
error = sfnt->load_svg_doc( glyph, glyph_index );
if( error == FT_Err_Ok )
{
FT_TRACE3(( "Successfully loaded SVG glyph\n" ));
glyph->format = FT_GLYPH_FORMAT_SVG;
sfnt->get_metrics( (TT_Face)glyph->face,
FALSE,
glyph_index,
&leftBearing,
&advanceX );
sfnt->get_metrics( (TT_Face)glyph->face,
TRUE,
glyph_index,
&topBearing,
&advanceY );
advanceX *= ((float)glyph->face->size->metrics.x_ppem)/
((float)glyph->face->units_per_EM) * 64.0;
advanceY *= ((float)glyph->face->size->metrics.y_ppem)/
((float)glyph->face->units_per_EM) * 64.0;
glyph->metrics.horiAdvance = advanceX;
glyph->metrics.vertAdvance = advanceY;
return error;
}
FT_TRACE3(( "Failed to load SVG glyph\n" ));
}
#endif
if ( load_flags & FT_LOAD_SBITS_ONLY )
{
error = FT_THROW( Invalid_Argument );