freetype-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Git][freetype/freetype-demos][wl/freetype-demos-support-ot-svg-glyphs-n


From: Werner Lemberg (@wl)
Subject: [Git][freetype/freetype-demos][wl/freetype-demos-support-ot-svg-glyphs-new] Prototype SVG support.
Date: Thu, 20 Jan 2022 15:57:07 +0000

Werner Lemberg pushed to branch wl/freetype-demos-support-ot-svg-glyphs-new at FreeType / FreeType Demo Programs

Commits:

5 changed files:

Changes:

  • Makefile
    ... ... @@ -125,6 +125,16 @@ else
    125 125
         SRC_DIR := $(TOP_DIR_2)/src
    
    126 126
       endif
    
    127 127
     
    
    128
    +  ifeq ($(PLATFORM),unixdev)
    
    129
    +    # `FT_DEMO_CFLAGS` comes from FreeType's `configure` script (via
    
    130
    +    # `builds/unix/unix-cc.mk`), holding additional flags to compile the
    
    131
    +    # FreeType demo programs.
    
    132
    +    #
    
    133
    +    # For the pure `make` call (without using `configure`) we have to add
    
    134
    +    # all needed cflags manually.
    
    135
    +    FT_DEMO_CFLAGS := $(shell pkg-config --cflags librsvg-2.0)
    
    136
    +  endif
    
    137
    +
    
    128 138
       FT_INCLUDES := $(OBJ_BUILD) \
    
    129 139
                      $(DEVEL_DIR) \
    
    130 140
                      $(TOP_DIR)/include \
    
    ... ... @@ -133,7 +143,8 @@ else
    133 143
       COMPILE = $(CC) $(ANSIFLAGS) \
    
    134 144
                       $(INCLUDES:%=$I%) \
    
    135 145
                       $(CPPFLAGS) \
    
    136
    -                  $(CFLAGS)
    
    146
    +                  $(CFLAGS) \
    
    147
    +                  $(FT_DEMO_CFLAGS)
    
    137 148
     
    
    138 149
       # Enable C99 for gcc to avoid warnings.
    
    139 150
       # Note that clang++ aborts with an error if we use `-std=C99',
    
    ... ... @@ -164,17 +175,27 @@ else
    164 175
       LINK_ITEMS = $T$(subst /,$(COMPILER_SEP),$@ $<)
    
    165 176
     
    
    166 177
       ifeq ($(PLATFORM),unix)
    
    178
    +    # `LDFLAGS` comes from the `configure` script (via FreeType's
    
    179
    +    # `builds/unix/unix-cc.mk`), holding all linker flags necessary to
    
    180
    +    # link the FreeType library.
    
    181
    +    #
    
    182
    +    # `FT_DEMO_LDFLAGS` has been set in `unix-cc.mk`, too.
    
    167 183
         override CC = $(CCraw)
    
    168 184
         LINK_CMD    = $(LIBTOOL) --mode=link $(CC) \
    
    169 185
                       $(subst /,$(COMPILER_SEP),$(LDFLAGS))
    
    170
    -    LINK_LIBS   = $(subst /,$(COMPILER_SEP),$(FTLIB) $(EFENCE)) $(LIB_CLOCK_GETTIME)
    
    186
    +    LINK_LIBS   = $(subst /,$(COMPILER_SEP),$(FTLIB) $(EFENCE)) \
    
    187
    +                  $(FT_DEMO_LDFLAGS)
    
    171 188
       else
    
    172 189
         LINK_CMD = $(CC) $(subst /,$(COMPILER_SEP),$(LDFLAGS))
    
    173 190
         ifeq ($(PLATFORM),unixdev)
    
    174
    -      LINK_LIBS := $(subst /,$(COMPILER_SEP),$(FTLIB) $(EFENCE)) -lm -lrt -lz -lbz2 -lpthread
    
    191
    +      # For the pure `make` call (without using `configure`) we have to add
    
    192
    +      # all needed libraries manually.
    
    193
    +      LINK_LIBS := $(subst /,$(COMPILER_SEP),$(FTLIB) $(EFENCE)) \
    
    194
    +                   -lm -lrt -lz -lbz2 -lpthread
    
    175 195
           LINK_LIBS += $(shell pkg-config --libs libpng)
    
    176 196
           LINK_LIBS += $(shell pkg-config --libs harfbuzz)
    
    177 197
           LINK_LIBS += $(shell pkg-config --libs libbrotlidec)
    
    198
    +      LINK_LIBS += $(shell pkg-config --libs librsvg-2.0)
    
    178 199
         else
    
    179 200
           LINK_LIBS = $(subst /,$(COMPILER_SEP),$(FTLIB) $(EFENCE))
    
    180 201
         endif
    
    ... ... @@ -349,6 +370,7 @@ else
    349 370
       $(OBJ_DIR_2)/mlgetopt.$(SO): $(SRC_DIR)/mlgetopt.c
    
    350 371
       COMMON_OBJ := $(OBJ_DIR_2)/common.$(SO) \
    
    351 372
                     $(OBJ_DIR_2)/strbuf.$(SO) \
    
    373
    +                $(OBJ_DIR_2)/rsvg-port.$(SO) \
    
    352 374
                     $(OBJ_DIR_2)/output.$(SO) \
    
    353 375
                     $(OBJ_DIR_2)/md5.$(SO) \
    
    354 376
                     $(OBJ_DIR_2)/mlgetopt.$(SO)
    
    ... ... @@ -361,6 +383,9 @@ else
    361 383
     	  $(COMPILE) $(GRAPH_INCLUDES:%=$I%) \
    
    362 384
                          $T$(subst /,$(COMPILER_SEP),$@ $<)
    
    363 385
     
    
    386
    +  $(OBJ_DIR_2)/rsvg-port.$(SO): $(SRC_DIR)/rsvg-port.c $(SRC_DIR)/rsvg-port.h
    
    387
    +	  $(COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)
    
    388
    +
    
    364 389
       FTCOMMON_OBJ := $(OBJ_DIR_2)/ftcommon.$(SO) \
    
    365 390
                       $(OBJ_DIR_2)/ftpngout.$(SO)
    
    366 391
     
    

  • meson.build
    ... ... @@ -30,6 +30,10 @@ libfreetype2_dep = libfreetype2.get_variable('freetype_dep')
    30 30
     libpng_dep = dependency('libpng',
    
    31 31
       required: true)
    
    32 32
     
    
    33
    +librsvg_dep = dependency('librsvg-2.0',
    
    34
    +  required: true)
    
    35
    +
    
    36
    +
    
    33 37
     cc = meson.get_compiler('c')
    
    34 38
     
    
    35 39
     math_dep = cc.find_library('m',
    
    ... ... @@ -70,8 +74,10 @@ ftcommon_lib = static_library('ftcommon',
    70 74
         'src/ftcommon.c',
    
    71 75
         'src/ftcommon.h',
    
    72 76
         'src/ftpngout.c',
    
    77
    +    'src/rsvg-port.c',
    
    78
    +    'src/rsvg-port.h',
    
    73 79
       ],
    
    74
    -  dependencies: [libpng_dep, libfreetype2_dep],
    
    80
    +  dependencies: [libpng_dep, librsvg_dep, libfreetype2_dep],
    
    75 81
       include_directories: graph_include_dir,
    
    76 82
       link_with: [common_lib, graph_lib],
    
    77 83
     )
    

  • src/ftcommon.c
    ... ... @@ -27,6 +27,8 @@
    27 27
     
    
    28 28
     #include FT_BITMAP_H
    
    29 29
     #include FT_FONT_FORMATS_H
    
    30
    +#include FT_OTSVG_H
    
    31
    +
    
    30 32
     
    
    31 33
       /* error messages */
    
    32 34
     #undef FTERRORS_H_
    
    ... ... @@ -37,6 +39,7 @@
    37 39
     #include "common.h"
    
    38 40
     #include "strbuf.h"
    
    39 41
     #include "ftcommon.h"
    
    42
    +#include "rsvg-port.h"
    
    40 43
     
    
    41 44
     #include <stdio.h>
    
    42 45
     #include <stdlib.h>
    
    ... ... @@ -337,6 +340,12 @@
    337 340
       {
    
    338 341
         FTDemo_Handle*  handle;
    
    339 342
     
    
    343
    +    SVG_RendererHooks  hooks = {
    
    344
    +                         (SVG_Lib_Init_Func)rsvg_port_init,
    
    345
    +                         (SVG_Lib_Free_Func)rsvg_port_free,
    
    346
    +                         (SVG_Lib_Render_Func)rsvg_port_render,
    
    347
    +                         (SVG_Lib_Preset_Slot_Func)rsvg_port_preset_slot };
    
    348
    +
    
    340 349
     
    
    341 350
         handle = (FTDemo_Handle *)malloc( sizeof ( FTDemo_Handle ) );
    
    342 351
         if ( !handle )
    
    ... ... @@ -348,6 +357,9 @@
    348 357
         if ( error )
    
    349 358
           PanicZ( "could not initialize FreeType" );
    
    350 359
     
    
    360
    +    /* XXX error handling? */
    
    361
    +    FT_Property_Set( handle->library, "ot-svg", "svg_hooks", &hooks );
    
    362
    +
    
    351 363
         error = FTC_Manager_New( handle->library, 0, 0, 0,
    
    352 364
                                  my_face_requester, 0, &handle->cache_manager );
    
    353 365
         if ( error )
    
    ... ... @@ -1333,7 +1345,8 @@
    1333 1345
     
    
    1334 1346
         error = FT_Err_Ok;
    
    1335 1347
     
    
    1336
    -    if ( glyf->format == FT_GLYPH_FORMAT_OUTLINE )
    
    1348
    +    if ( glyf->format == FT_GLYPH_FORMAT_OUTLINE ||
    
    1349
    +         glyf->format == FT_GLYPH_FORMAT_SVG     )
    
    1337 1350
         {
    
    1338 1351
           FT_Render_Mode  render_mode;
    
    1339 1352
     
    

  • src/rsvg-port.c
    1
    +/****************************************************************************
    
    2
    + *
    
    3
    + * rsvg-port.c
    
    4
    + *
    
    5
    + *   Librsvg-based hook functions for OT-SVG rendering in FreeType
    
    6
    + *   (implementation).
    
    7
    + *
    
    8
    + * Copyright (C) 2022 by
    
    9
    + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
    
    10
    + *
    
    11
    + * This file is part of the FreeType project, and may only be used,
    
    12
    + * modified, and distributed under the terms of the FreeType project
    
    13
    + * license, LICENSE.TXT.  By continuing to use, modify, or distribute
    
    14
    + * this file you indicate that you have read the license and
    
    15
    + * understand and accept it fully.
    
    16
    + *
    
    17
    + */
    
    18
    +
    
    19
    +#include <cairo.h>
    
    20
    +#include <librsvg/rsvg.h>
    
    21
    +#include <stdlib.h>
    
    22
    +#include <math.h>
    
    23
    +
    
    24
    +#include <ft2build.h>
    
    25
    +#include <freetype/freetype.h>
    
    26
    +#include <freetype/ftbbox.h>
    
    27
    +#include <freetype/otsvg.h>
    
    28
    +
    
    29
    +#include "rsvg-port.h"
    
    30
    +
    
    31
    +
    
    32
    +  /*
    
    33
    +   * The init hook is called when the first OT-SVG glyph is rendered.  All
    
    34
    +   * we do is to allocate an internal state structure and set the pointer in
    
    35
    +   * `library->svg_renderer_state`.  This state structure becomes very
    
    36
    +   * useful to cache some of the results obtained by one hook function that
    
    37
    +   * the other one might use.
    
    38
    +   */
    
    39
    +  FT_Error
    
    40
    +  rsvg_port_init( FT_Pointer  *state )
    
    41
    +  {
    
    42
    +    /* allocate the memory upon initialization */
    
    43
    +    *state = malloc( sizeof( Rsvg_Port_StateRec ) ); /* XXX error handling */
    
    44
    +
    
    45
    +    return FT_Err_Ok;
    
    46
    +  }
    
    47
    +
    
    48
    +
    
    49
    +  /*
    
    50
    +   * Deallocate the state structure.
    
    51
    +   */
    
    52
    +  void
    
    53
    +  rsvg_port_free( FT_Pointer  *state )
    
    54
    +  {
    
    55
    +    free( *state );
    
    56
    +  }
    
    57
    +
    
    58
    +
    
    59
    +  /*
    
    60
    +   * The render hook.  The job of this hook is to simply render the glyph in
    
    61
    +   * the buffer that has been allocated on the FreeType side.  Here we
    
    62
    +   * simply use the recording surface by playing it back against the
    
    63
    +   * surface.
    
    64
    +   */
    
    65
    +  FT_Error
    
    66
    +  rsvg_port_render( FT_GlyphSlot  slot,
    
    67
    +                    FT_Pointer   *_state )
    
    68
    +  {
    
    69
    +    FT_Error  error = FT_Err_Ok;
    
    70
    +
    
    71
    +    Rsvg_Port_State   state;
    
    72
    +    cairo_status_t    status;
    
    73
    +    cairo_t          *cr;
    
    74
    +    cairo_surface_t  *surface;
    
    75
    +
    
    76
    +
    
    77
    +    state = *(Rsvg_Port_State*)_state;
    
    78
    +
    
    79
    +    /* Create an image surface to store the rendered image.  However,   */
    
    80
    +    /* don't allocate memory; instead use the space already provided in */
    
    81
    +    /* `slot->bitmap.buffer`.                                           */
    
    82
    +    surface = cairo_image_surface_create_for_data( slot->bitmap.buffer,
    
    83
    +                                                   CAIRO_FORMAT_ARGB32,
    
    84
    +                                                   (int)slot->bitmap.width,
    
    85
    +                                                   (int)slot->bitmap.rows,
    
    86
    +                                                   slot->bitmap.pitch );
    
    87
    +    status = cairo_surface_status( surface );
    
    88
    +
    
    89
    +    if ( status != CAIRO_STATUS_SUCCESS )
    
    90
    +    {
    
    91
    +      if ( status == CAIRO_STATUS_NO_MEMORY )
    
    92
    +        return FT_Err_Out_Of_Memory;
    
    93
    +      else
    
    94
    +        return FT_Err_Invalid_Outline;
    
    95
    +    }
    
    96
    +
    
    97
    +    cr     = cairo_create( surface );
    
    98
    +    status = cairo_status( cr );
    
    99
    +
    
    100
    +    if ( status != CAIRO_STATUS_SUCCESS )
    
    101
    +    {
    
    102
    +      if ( status == CAIRO_STATUS_NO_MEMORY )
    
    103
    +        return FT_Err_Out_Of_Memory;
    
    104
    +      else
    
    105
    +        return FT_Err_Invalid_Outline;
    
    106
    +    }
    
    107
    +
    
    108
    +    /* Set a translate transform that translates the points in such a way */
    
    109
    +    /* that we get a tight rendering with least redundant white spac.     */
    
    110
    +    cairo_translate( cr, -state->x, -state->y );
    
    111
    +
    
    112
    +    /* Replay from the recorded surface.  This saves us from parsing the */
    
    113
    +    /* document again and redoing what was already done in the preset    */
    
    114
    +    /* hook.                                                             */
    
    115
    +    cairo_set_source_surface( cr, state->rec_surface, 0.0, 0.0 );
    
    116
    +    cairo_paint( cr );
    
    117
    +
    
    118
    +    cairo_surface_flush( surface );
    
    119
    +
    
    120
    +    slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
    
    121
    +    slot->bitmap.num_grays  = 256;
    
    122
    +    slot->format            = FT_GLYPH_FORMAT_BITMAP;
    
    123
    +
    
    124
    +    /* Clean up everything. */
    
    125
    +    cairo_surface_destroy( surface );
    
    126
    +    cairo_destroy( cr );
    
    127
    +    cairo_surface_destroy( state->rec_surface );
    
    128
    +
    
    129
    +    return error;
    
    130
    +  }
    
    131
    +
    
    132
    +
    
    133
    +  /*
    
    134
    +   * This hook is called at two different locations.  Firstly, it is called
    
    135
    +   * when presetting the glyphslot when `FT_Load_Glyph` is called.
    
    136
    +   * Secondly, it is called right before the render hook is called.  When
    
    137
    +   * `cache` is false, it is the former, when `cache` is true, it is the
    
    138
    +   * latter.
    
    139
    +   *
    
    140
    +   * The job of this function is to preset the slot setting the width,
    
    141
    +   * height, pitch, `bitmap.left`, and `bitmap.top`.  These are all
    
    142
    +   * necessary for appropriate memory allocation, as well as ultimately
    
    143
    +   * compositing the glyph later on by client applications.
    
    144
    +   */
    
    145
    +  FT_Error
    
    146
    +  rsvg_port_preset_slot( FT_GlyphSlot  slot,
    
    147
    +                         FT_Bool       cache,
    
    148
    +                         FT_Pointer   *_state )
    
    149
    +  {
    
    150
    +    /* FreeType variables. */
    
    151
    +    FT_Error  error = FT_Err_Ok;
    
    152
    +
    
    153
    +    FT_SVG_Document  document = (FT_SVG_Document)slot->other;
    
    154
    +    FT_Size_Metrics  metrics  = document->metrics;
    
    155
    +
    
    156
    +    FT_UShort  units_per_EM   = document->units_per_EM;
    
    157
    +    FT_UShort  end_glyph_id   = document->end_glyph_id;
    
    158
    +    FT_UShort  start_glyph_id = document->start_glyph_id;
    
    159
    +
    
    160
    +    /* Librsvg variables. */
    
    161
    +    GError   *gerror = NULL;
    
    162
    +    gboolean  ret;
    
    163
    +
    
    164
    +    gboolean  out_has_width;
    
    165
    +    gboolean  out_has_height;
    
    166
    +    gboolean  out_has_viewbox;
    
    167
    +
    
    168
    +    RsvgHandle         *handle;
    
    169
    +    RsvgLength         out_width;
    
    170
    +    RsvgLength         out_height;
    
    171
    +    RsvgRectangle      out_viewbox;
    
    172
    +    RsvgDimensionData  dimension_svg;
    
    173
    +
    
    174
    +    cairo_t        *rec_cr;
    
    175
    +    cairo_matrix_t  transform_matrix;
    
    176
    +
    
    177
    +    /* Rendering port's state. */
    
    178
    +    Rsvg_Port_State     state;
    
    179
    +    Rsvg_Port_StateRec  state_dummy;
    
    180
    +
    
    181
    +    /* General variables. */
    
    182
    +    double  x, y;
    
    183
    +    double  xx, xy, yx, yy;
    
    184
    +    double  x0, y0;
    
    185
    +    double  width, height;
    
    186
    +    double  x_svg_to_out, y_svg_to_out;
    
    187
    +    double  tmpd;
    
    188
    +
    
    189
    +    float metrics_width, metrics_height;
    
    190
    +    float horiBearingX, horiBearingY;
    
    191
    +    float vertBearingX, vertBearingY;
    
    192
    +    float tmpf;
    
    193
    +
    
    194
    +
    
    195
    +    /* If `cache` is `TRUE` we store calculations in the actual port */
    
    196
    +    /* state variable, otherwise we just create a dummy variable and */
    
    197
    +    /* store there.  This saves us from too many 'if' statements.    */
    
    198
    +    if ( cache )
    
    199
    +      state = *(Rsvg_Port_State*)_state;
    
    200
    +    else
    
    201
    +      state = &state_dummy;
    
    202
    +
    
    203
    +    /* Form an `RsvgHandle` by loading the SVG document. */
    
    204
    +    handle = rsvg_handle_new_from_data( document->svg_document,
    
    205
    +                                        document->svg_document_length,
    
    206
    +                                        &gerror );
    
    207
    +    if ( handle == NULL )
    
    208
    +    {
    
    209
    +      error = FT_Err_Invalid_SVG_Document;
    
    210
    +      goto CleanLibrsvg;
    
    211
    +    }
    
    212
    +
    
    213
    +    /* Get attributes like `viewBox` and `width`/`height`. */
    
    214
    +    rsvg_handle_get_intrinsic_dimensions( handle,
    
    215
    +                                          &out_has_width,
    
    216
    +                                          &out_width,
    
    217
    +                                          &out_has_height,
    
    218
    +                                          &out_height,
    
    219
    +                                          &out_has_viewbox,
    
    220
    +                                          &out_viewbox );
    
    221
    +
    
    222
    +    /*
    
    223
    +     * Figure out the units in the EM square in the SVG document.  This is
    
    224
    +     * specified by the `ViewBox` or the `width`/`height` attributes, if
    
    225
    +     * present, otherwise it should be assumed that the units in the EM
    
    226
    +     * square are the same as in the TTF/CFF outlines.
    
    227
    +     *
    
    228
    +     * TODO: I'm not sure what the standard says about the situation if
    
    229
    +     * `ViewBox` as well as `width`/`height` are present; however, I've
    
    230
    +     * never seen that situation in real fonts.
    
    231
    +     */
    
    232
    +    if ( out_has_viewbox == TRUE )
    
    233
    +    {
    
    234
    +      dimension_svg.width  = (int)out_viewbox.width; /* XXX rounding? */
    
    235
    +      dimension_svg.height = (int)out_viewbox.height;
    
    236
    +    }
    
    237
    +    else if ( out_has_width == TRUE && out_has_height == TRUE )
    
    238
    +    {
    
    239
    +      dimension_svg.width  = (int)out_width.length; /* XXX rounding? */
    
    240
    +      dimension_svg.height = (int)out_height.length;
    
    241
    +    }
    
    242
    +    else
    
    243
    +    {
    
    244
    +      /* If neither `ViewBox` nor `width`/`height` are present, the */
    
    245
    +      /* `units_per_EM` in SVG coordinates must be the same as      */
    
    246
    +      /* `units_per_EM` of the TTF/CFF outlines.                    */
    
    247
    +      dimension_svg.width  = units_per_EM;
    
    248
    +      dimension_svg.height = units_per_EM;
    
    249
    +    }
    
    250
    +
    
    251
    +    /* Scale factors from SVG coordinates to the needed output size. */
    
    252
    +    x_svg_to_out = (float)metrics.x_ppem / dimension_svg.width;
    
    253
    +    y_svg_to_out = (float)metrics.y_ppem / dimension_svg.height;
    
    254
    +
    
    255
    +    /*
    
    256
    +     * Create a cairo recording surface.  This is done for two reasons.
    
    257
    +     * Firstly, it is required to get the bounding box of the final drawing
    
    258
    +     * so we can use an appropriate translate transform to get a tight
    
    259
    +     * rendering.  Secondly, if `cache` is true, we can save this surface
    
    260
    +     * and later replay it against an image surface for the final rendering.
    
    261
    +     * This saves us from loading and parsing the document again.
    
    262
    +     */
    
    263
    +    state->rec_surface =
    
    264
    +      cairo_recording_surface_create( CAIRO_CONTENT_COLOR_ALPHA, NULL );
    
    265
    +
    
    266
    +    rec_cr = cairo_create( state->rec_surface );
    
    267
    +
    
    268
    +    /*
    
    269
    +     * We need to take into account any transformations applied.  The end
    
    270
    +     * user who applied the transformation doesn't know the internal details
    
    271
    +     * of the SVG document.  Thus, we expect that the end user should just
    
    272
    +     * write the transformation as if the glyph is a traditional one.  We
    
    273
    +     * then do some maths on this to get the equivalent transformation in
    
    274
    +     * SVG coordinates.
    
    275
    +     */
    
    276
    +    xx =  (double)document->transform.xx / ( 1 << 16 );
    
    277
    +    xy = -(double)document->transform.xy / ( 1 << 16 );
    
    278
    +    yx = -(double)document->transform.yx / ( 1 << 16 );
    
    279
    +    yy =  (double)document->transform.yy / ( 1 << 16 );
    
    280
    +
    
    281
    +    x0 =  (double)document->delta.x / 64 *
    
    282
    +            dimension_svg.width / metrics.x_ppem;
    
    283
    +    y0 = -(double)document->delta.y / 64 *
    
    284
    +            dimension_svg.height / metrics.y_ppem;
    
    285
    +
    
    286
    +    /* Cairo stores both transformation and translation in one matrix. */
    
    287
    +    transform_matrix.xx = xx;
    
    288
    +    transform_matrix.yx = yx;
    
    289
    +    transform_matrix.xy = xy;
    
    290
    +    transform_matrix.yy = yy;
    
    291
    +    transform_matrix.x0 = x0;
    
    292
    +    transform_matrix.y0 = y0;
    
    293
    +
    
    294
    +    /* Set up a scale transformation to scale up the document to the */
    
    295
    +    /* required output size.                                         */
    
    296
    +    cairo_scale( rec_cr, x_svg_to_out, y_svg_to_out );
    
    297
    +    /* Set up a transformation matrix. */
    
    298
    +    cairo_transform( rec_cr, &transform_matrix );
    
    299
    +
    
    300
    +    /* If the document contains only one glyph, `start_glyph_id` and */
    
    301
    +    /* `end_glyph_id` have the same value.  Otherwise `end_glyph_id` */
    
    302
    +    /* is larger.                                                    */
    
    303
    +    if ( start_glyph_id == end_glyph_id )
    
    304
    +    {
    
    305
    +      /* Render the whole document to the recording surface. */
    
    306
    +      ret = rsvg_handle_render_cairo ( handle, rec_cr );
    
    307
    +      if ( ret == FALSE )
    
    308
    +      {
    
    309
    +        error = FT_Err_Invalid_SVG_Document;
    
    310
    +        goto CleanCairo;
    
    311
    +      }
    
    312
    +    }
    
    313
    +    else if ( start_glyph_id < end_glyph_id )
    
    314
    +    {
    
    315
    +      char  str[32] = "#glyph";
    
    316
    +
    
    317
    +
    
    318
    +      /* Render only the element with its ID equal to `glyph<ID>`. */
    
    319
    +      sprintf( str + 6, "%u", slot->glyph_index );
    
    320
    +      ret = rsvg_handle_render_cairo_sub( handle, rec_cr, str );
    
    321
    +      if ( ret == FALSE )
    
    322
    +      {
    
    323
    +        error = FT_Err_Invalid_SVG_Document;
    
    324
    +        goto CleanCairo;
    
    325
    +      }
    
    326
    +    }
    
    327
    +
    
    328
    +    /* Get the bounding box of the drawing. */
    
    329
    +    cairo_recording_surface_ink_extents( state->rec_surface, &x, &y,
    
    330
    +                                         &width, &height );
    
    331
    +
    
    332
    +    /* We store the bounding box's `x` and `y` values so that the render */
    
    333
    +    /* hook can apply a translation to get a tight rendering.            */
    
    334
    +    state->x = x;
    
    335
    +    state->y = y;
    
    336
    +
    
    337
    +    /* Preset the values. */
    
    338
    +    slot->bitmap_left = (FT_Int) state->x;  /* XXX rounding? */
    
    339
    +    slot->bitmap_top  = (FT_Int)-state->y;
    
    340
    +
    
    341
    +    /* Do conversion in two steps to avoid 'bad function cast' warning. */
    
    342
    +    tmpd               = ceil( height );
    
    343
    +    slot->bitmap.rows  = (unsigned int)tmpd;
    
    344
    +    tmpd               = ceil( width );
    
    345
    +    slot->bitmap.width = (unsigned int)tmpd;
    
    346
    +
    
    347
    +    slot->bitmap.pitch = (int)slot->bitmap.width * 4;
    
    348
    +
    
    349
    +    slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
    
    350
    +
    
    351
    +    /* Compute all the bearings and set them correctly.  The outline is */
    
    352
    +    /* scaled already, we just need to use the bounding box.            */
    
    353
    +    metrics_width  = (float)width;
    
    354
    +    metrics_height = (float)height;
    
    355
    +
    
    356
    +    horiBearingX = (float) state->x;
    
    357
    +    horiBearingY = (float)-state->y;
    
    358
    +
    
    359
    +    vertBearingX = slot->metrics.horiBearingX / 64.0f -
    
    360
    +                     slot->metrics.horiAdvance / 64.0f / 2;
    
    361
    +    vertBearingY = ( slot->metrics.vertAdvance / 64.0f -
    
    362
    +                       slot->metrics.height / 64.0f ) / 2; /* XXX parentheses correct? */
    
    363
    +
    
    364
    +    /* Do conversion in two steps to avoid 'bad function cast' warning. */
    
    365
    +    tmpf                 = roundf( metrics_width * 64 );
    
    366
    +    slot->metrics.width  = (FT_Pos)tmpf;
    
    367
    +    tmpf                 = roundf( metrics_height * 64 );
    
    368
    +    slot->metrics.height = (FT_Pos)tmpf;
    
    369
    +
    
    370
    +    slot->metrics.horiBearingX = (FT_Pos)( horiBearingX * 64 ); /* XXX rounding? */
    
    371
    +    slot->metrics.horiBearingY = (FT_Pos)( horiBearingY * 64 );
    
    372
    +    slot->metrics.vertBearingX = (FT_Pos)( vertBearingX * 64 );
    
    373
    +    slot->metrics.vertBearingY = (FT_Pos)( vertBearingY * 64 );
    
    374
    +
    
    375
    +    if ( slot->metrics.vertAdvance == 0 )
    
    376
    +      slot->metrics.vertAdvance = (FT_Pos)( metrics_height * 1.2 * 64 );
    
    377
    +
    
    378
    +    /* If a render call is to follow, just destroy the context for the */
    
    379
    +    /* recording surface since no more drawing will be done on it.     */
    
    380
    +    /* However, keep the surface itself for use by the render hook.    */
    
    381
    +    if ( cache == TRUE )
    
    382
    +    {
    
    383
    +      cairo_destroy( rec_cr );
    
    384
    +      goto CleanLibrsvg;
    
    385
    +    }
    
    386
    +
    
    387
    +    /* Destroy the recording surface as well as the context. */
    
    388
    +  CleanCairo:
    
    389
    +    cairo_surface_destroy( state->rec_surface );
    
    390
    +    cairo_destroy( rec_cr );
    
    391
    +
    
    392
    +  CleanLibrsvg:
    
    393
    +    /* Destroy the handle. */
    
    394
    +    g_object_unref( handle );
    
    395
    +
    
    396
    +    return error;
    
    397
    +  }
    
    398
    +
    
    399
    +
    
    400
    +/* End */

  • src/rsvg-port.h
    1
    +/****************************************************************************
    
    2
    + *
    
    3
    + * rsvg-port.h
    
    4
    + *
    
    5
    + *   Librsvg based hook functions for OT-SVG rendering in FreeType
    
    6
    + *   (headers).
    
    7
    + *
    
    8
    + * Copyright (C) 2022 by
    
    9
    + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
    
    10
    + *
    
    11
    + * This file is part of the FreeType project, and may only be used,
    
    12
    + * modified, and distributed under the terms of the FreeType project
    
    13
    + * license, LICENSE.TXT.  By continuing to use, modify, or distribute
    
    14
    + * this file you indicate that you have read the license and
    
    15
    + * understand and accept it fully.
    
    16
    + *
    
    17
    + */
    
    18
    +
    
    19
    +#ifndef RSVG_PORT_H
    
    20
    +#define RSVG_PORT_H
    
    21
    +
    
    22
    +#include <cairo.h>
    
    23
    +#include <librsvg/rsvg.h>
    
    24
    +#include <ft2build.h>
    
    25
    +#include <freetype/freetype.h>
    
    26
    +
    
    27
    +
    
    28
    +  /*
    
    29
    +   * Different hook functions can access persisting data by creating a state
    
    30
    +   * structure and putting its address in `library->svg_renderer_state`.
    
    31
    +   * Functions can then store and retrieve data from this structure.
    
    32
    +   */
    
    33
    +  typedef struct  Rsvg_Port_StateRec_
    
    34
    +  {
    
    35
    +    cairo_surface_t  *rec_surface;
    
    36
    +
    
    37
    +    double  x;
    
    38
    +    double  y;
    
    39
    +
    
    40
    +  } Rsvg_Port_StateRec;
    
    41
    +
    
    42
    +  typedef struct Rsvg_Port_StateRec_*  Rsvg_Port_State;
    
    43
    +
    
    44
    +
    
    45
    +  FT_Error
    
    46
    +  rsvg_port_init( FT_Pointer  *state );
    
    47
    +
    
    48
    +  void
    
    49
    +  rsvg_port_free( FT_Pointer  *state );
    
    50
    +
    
    51
    +  FT_Error
    
    52
    +  rsvg_port_render( FT_GlyphSlot  slot,
    
    53
    +                    FT_Pointer   *state );
    
    54
    +
    
    55
    +  FT_Error
    
    56
    +  rsvg_port_preset_slot( FT_GlyphSlot  slot,
    
    57
    +                         FT_Bool       cache,
    
    58
    +                         FT_Pointer   *state );
    
    59
    +
    
    60
    +#endif /* RSVG_PORT_H */
    
    61
    +
    
    62
    +
    
    63
    +/* End */


  • reply via email to

    [Prev in Thread] Current Thread [Next in Thread]