Coverage Report

Created: 2025-12-31 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/fapi_ft.c
Line
Count
Source
1
/* Copyright (C) 2001-2025 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/*
18
   GhostScript Font API plug-in that allows fonts to be rendered by FreeType.
19
   Started by Graham Asher, 6th June 2002.
20
 */
21
22
/* GhostScript headers. */
23
#include "stdio_.h"
24
#include "malloc_.h"
25
#include "write_t1.h"
26
#include "write_t2.h"
27
#include "math_.h"
28
#include "gserrors.h"
29
#include "gsmemory.h"
30
#include "gsmalloc.h"
31
#include "gxfixed.h"
32
#include "gdebug.h"
33
#include "gxbitmap.h"
34
#include "gsmchunk.h"
35
#include "gxfont.h"
36
#include "gxfont1.h"
37
38
#include "stream.h"
39
#include "gxiodev.h"            /* must come after stream.h */
40
41
#include "gsfname.h"
42
43
#include "gxfapi.h"
44
45
46
/* FreeType headers */
47
#include <ft2build.h>
48
#include FT_FREETYPE_H
49
#include FT_INCREMENTAL_H
50
#include FT_GLYPH_H
51
#include FT_SYSTEM_H
52
#include FT_MODULE_H
53
#include FT_TRIGONOMETRY_H
54
#include FT_BBOX_H
55
#include FT_OUTLINE_H
56
#include FT_IMAGE_H
57
#include FT_BITMAP_H
58
#include FT_TRUETYPE_DRIVER_H
59
#include FT_TRUETYPE_TABLES_H
60
#include FT_MULTIPLE_MASTERS_H
61
#include FT_TYPE1_TABLES_H
62
63
/* Note: structure definitions here start with FF_, which stands for 'FAPI FreeType". */
64
65
#define ft_emprintf(m,s) { outflush(m); emprintf(m, s); outflush(m); }
66
#define ft_emprintf1(m,s,d) { outflush(m); emprintf1(m, s, d); outflush(m); }
67
68
typedef struct ff_server_s
69
{
70
    gs_fapi_server fapi_server;
71
    FT_Library freetype_library;
72
    FT_OutlineGlyph outline_glyph;
73
    FT_BitmapGlyph bitmap_glyph;
74
    gs_memory_t *mem;
75
    FT_Memory ftmemory;
76
    struct FT_MemoryRec_ ftmemory_rec;
77
} ff_server;
78
79
80
81
typedef struct ff_face_s
82
{
83
    FT_Face ft_face;
84
85
    /* Currently in force scaling/transform for this face */
86
    FT_Matrix ft_transform;
87
    FT_F26Dot6 width, height;
88
    FT_UInt horz_res;
89
    FT_UInt vert_res;
90
91
    /* If non-null, the incremental interface object passed to FreeType. */
92
    FT_Incremental_InterfaceRec *ft_inc_int;
93
    /* If non-null, we're using a custom stream object for Freetype to read the font file */
94
    FT_Stream ftstrm;
95
    /* Non-null if font data is owned by this object. */
96
    unsigned char *font_data;
97
    int font_data_len;
98
    bool data_owned;
99
    ff_server *server;
100
} ff_face;
101
102
/* Here we define the struct FT_Incremental that is used as an opaque type
103
 * inside FreeType. This structure has to have the tag FT_IncrementalRec_
104
 * to be compatible with the functions defined in FT_Incremental_FuncsRec.
105
 */
106
typedef struct FT_IncrementalRec_
107
{
108
    gs_fapi_font *fapi_font;    /* The font. */
109
110
    /* If it is already in use glyph data is allocated on the heap. */
111
    unsigned char *glyph_data;  /* A one-shot buffer for glyph data. */
112
    size_t glyph_data_length;   /* Length in bytes of glyph_data. */
113
    bool glyph_data_in_use;     /* True if glyph_data is already in use. */
114
115
    FT_Incremental_MetricsRec glyph_metrics;    /* Incremental glyph metrics supplied by Ghostscript. */
116
    unsigned long glyph_metrics_index;  /* contains data for this glyph index unless it is 0xFFFFFFFF. */
117
    gs_fapi_metrics_type metrics_type;  /* determines whether metrics are replaced, added, etc. */
118
} FT_IncrementalRec;
119
120
121
static void
122
delete_inc_int(gs_fapi_server * a_server,
123
               FT_Incremental_InterfaceRec * a_inc_int);
124
125
static void
126
delete_inc_int_info(gs_fapi_server * a_server,
127
                    FT_IncrementalRec * a_inc_int_info);
128
129
static void *
130
FF_alloc(FT_Memory memory, long size)
131
210M
{
132
210M
    gs_memory_t *mem = (gs_memory_t *) memory->user;
133
134
210M
    return (gs_malloc(mem, size, 1, "FF_alloc"));
135
210M
}
136
137
static void *
138
    FF_realloc(FT_Memory memory, long cur_size, long new_size, void *block)
139
6.37M
{
140
6.37M
    gs_memory_t *mem = (gs_memory_t *) memory->user;
141
6.37M
    void *tmp;
142
143
6.37M
    if (cur_size == new_size) {
144
30.1k
        return (block);
145
30.1k
    }
146
147
6.33M
    tmp = gs_malloc(mem, new_size, 1, "FF_realloc");
148
6.33M
    if (tmp && block) {
149
6.33M
        memcpy(tmp, block, min(cur_size, new_size));
150
151
6.33M
        gs_free(mem, block, 0, 0, "FF_realloc");
152
6.33M
    }
153
154
6.33M
    return (tmp);
155
6.37M
}
156
157
static void
158
    FF_free(FT_Memory memory, void *block)
159
212M
{
160
212M
    gs_memory_t *mem = (gs_memory_t *) memory->user;
161
162
212M
    gs_free(mem, block, 0, 0, "FF_free");
163
212M
}
164
165
/* The following three functions are used in providing a custom stream
166
 * object to Freetype, so file access happens through Ghostscript's
167
 * file i/o. Most importantly, this gives Freetype direct access to
168
 * files in the romfs
169
 */
170
static FT_ULong
171
FF_stream_read(FT_Stream str, unsigned long offset, unsigned char *buffer,
172
               unsigned long count)
173
0
{
174
0
    stream *ps = (stream *) str->descriptor.pointer;
175
0
    unsigned int rlen = 0;
176
0
    int status = 0;
177
178
0
    if (sseek(ps, (gs_offset_t)offset) < 0)
179
0
        return_error(-1);
180
181
0
    if (count) {
182
0
        status = sgets(ps, buffer, count, &rlen);
183
184
0
        if (status < 0 && status != EOFC)
185
0
            return_error (-1);
186
0
    }
187
0
    return (rlen);
188
0
}
189
190
static void
191
FF_stream_close(FT_Stream str)
192
0
{
193
0
    stream *ps = (stream *) str->descriptor.pointer;
194
0
    gs_memory_t *mem = ps->memory;
195
196
0
    (void)sclose(ps);
197
0
    gs_free_object(mem, ps, "FF_stream_close");
198
0
}
199
200
extern const uint file_default_buffer_size;
201
202
static int
203
FF_open_read_stream(gs_memory_t * mem, char *fname, FT_Stream * fts)
204
0
{
205
0
    int code = 0;
206
0
    gs_parsed_file_name_t pfn;
207
0
    stream *ps = (stream *)NULL;
208
0
    gs_offset_t length;
209
0
    FT_Stream ftstrm = NULL;
210
211
0
    code = gs_parse_file_name(&pfn, (const char *)fname, strlen(fname), mem);
212
0
    if (code < 0) {
213
0
        goto error_out;
214
0
    }
215
216
0
    if (!pfn.fname) {
217
0
        code = gs_error_undefinedfilename;
218
0
        goto error_out;
219
0
    }
220
221
0
    if (pfn.iodev == NULL) {
222
0
        pfn.iodev = iodev_default(mem);
223
0
    }
224
225
0
    if (pfn.iodev) {
226
0
        gx_io_device *const iodev = pfn.iodev;
227
228
0
        iodev_proc_open_file((*open_file)) = iodev->procs.open_file;
229
230
0
        if (open_file) {
231
0
            code = open_file(iodev, pfn.fname, pfn.len, "r", &ps, mem);
232
0
            if (code < 0) {
233
0
                goto error_out;
234
0
            }
235
0
        }
236
0
        else {
237
0
            code =
238
0
                file_open_stream(pfn.fname, pfn.len, "r",
239
0
                                 file_default_buffer_size, &ps, pfn.iodev,
240
0
                                 pfn.iodev->procs.gp_fopen, mem);
241
0
            if (code < 0) {
242
0
                goto error_out;
243
0
            }
244
0
        }
245
0
    }
246
0
    else {
247
0
        goto error_out;
248
0
    }
249
250
0
    if ((code = savailable(ps, &length)) < 0) {
251
0
        goto error_out;
252
0
    }
253
254
0
    ftstrm = gs_malloc(mem, sizeof(FT_StreamRec), 1, "FF_open_read_stream");
255
0
    if (!ftstrm) {
256
0
        code = gs_error_VMerror;
257
0
        goto error_out;
258
0
    }
259
0
    memset(ftstrm, 0x00, sizeof(FT_StreamRec));
260
261
0
    ftstrm->descriptor.pointer = ps;
262
0
    ftstrm->read = FF_stream_read;
263
0
    ftstrm->close = FF_stream_close;
264
0
    ftstrm->size = (long)length;
265
0
    *fts = ftstrm;
266
267
0
  error_out:
268
0
    if (code < 0) {
269
0
        if (ps)
270
0
            (void)sclose(ps);
271
0
        if (ftstrm)
272
0
            gs_free(mem, ftstrm, 0, 0, "FF_open_read_stream");
273
0
    }
274
0
    return (code);
275
0
}
276
277
278
static ff_face *
279
new_face(gs_fapi_server * a_server, FT_Face a_ft_face,
280
         FT_Incremental_InterfaceRec * a_ft_inc_int, FT_Stream ftstrm,
281
         unsigned char *a_font_data, int a_font_data_len, bool data_owned)
282
1.29M
{
283
1.29M
    ff_server *s = (ff_server *) a_server;
284
285
1.29M
    ff_face *face = (ff_face *) FF_alloc(s->ftmemory, sizeof(ff_face));
286
287
1.29M
    if (face) {
288
1.29M
        face->ft_face = a_ft_face;
289
1.29M
        face->ft_inc_int = a_ft_inc_int;
290
1.29M
        face->font_data = a_font_data;
291
1.29M
        face->font_data_len = a_font_data_len;
292
1.29M
        face->data_owned = data_owned;
293
1.29M
        face->ftstrm = ftstrm;
294
1.29M
        face->server = (ff_server *) a_server;
295
1.29M
    }
296
1.29M
    return face;
297
1.29M
}
298
299
static void
300
delete_face(gs_fapi_server * a_server, ff_face * a_face)
301
1.29M
{
302
1.29M
    if (a_face) {
303
1.29M
        ff_server *s = (ff_server *) a_server;
304
1.29M
        if (a_face->ft_inc_int) {
305
1.27M
            FT_Incremental a_info = a_face->ft_inc_int->object;
306
307
1.27M
            if (a_info->glyph_data) {
308
756k
                gs_free(s->mem, a_info->glyph_data, 0, 0, "delete_face");
309
756k
            }
310
1.27M
            a_info->glyph_data = NULL;
311
1.27M
            a_info->glyph_data_length = 0;
312
1.27M
            delete_inc_int(a_server, a_face->ft_inc_int);
313
1.27M
            a_face->ft_inc_int = NULL;
314
1.27M
        }
315
1.29M
        FT_Done_Face(a_face->ft_face);
316
317
1.29M
        FF_free(s->ftmemory, a_face->ft_inc_int);
318
1.29M
        if (a_face->data_owned)
319
1.26M
            FF_free(s->ftmemory, a_face->font_data);
320
1.29M
        if (a_face->ftstrm) {
321
0
            FF_free(s->ftmemory, a_face->ftstrm);
322
0
        }
323
1.29M
        FF_free(s->ftmemory, a_face);
324
1.29M
    }
325
1.29M
}
326
327
static FT_IncrementalRec *
328
new_inc_int_info(gs_fapi_server * a_server, gs_fapi_font * a_fapi_font)
329
1.28M
{
330
1.28M
    ff_server *s = (ff_server *) a_server;
331
332
1.28M
    FT_IncrementalRec *info =
333
1.28M
        (FT_IncrementalRec *) FF_alloc(s->ftmemory,
334
1.28M
                                       sizeof(FT_IncrementalRec));
335
1.28M
    if (info) {
336
1.28M
        info->fapi_font = a_fapi_font;
337
1.28M
        info->glyph_data = NULL;
338
1.28M
        info->glyph_data_length = 0;
339
1.28M
        info->glyph_data_in_use = false;
340
1.28M
        info->glyph_metrics_index = 0xFFFFFFFF;
341
1.28M
        info->metrics_type = gs_fapi_metrics_notdef;
342
1.28M
    }
343
1.28M
    return info;
344
1.28M
}
345
346
static void
347
delete_inc_int_info(gs_fapi_server * a_server,
348
                    FT_IncrementalRec * a_inc_int_info)
349
1.28M
{
350
1.28M
    ff_server *s = (ff_server *) a_server;
351
352
1.28M
    if (a_inc_int_info) {
353
1.28M
        FF_free(s->ftmemory, a_inc_int_info->glyph_data);
354
1.28M
        FF_free(s->ftmemory, a_inc_int_info);
355
1.28M
    }
356
1.28M
}
357
358
static FT_Error
359
get_fapi_glyph_data(FT_Incremental a_info, FT_UInt a_index, FT_Data * a_data)
360
25.1M
{
361
25.1M
    gs_fapi_font *ff = a_info->fapi_font;
362
25.1M
    int length = 0;
363
25.1M
    ff_face *face = (ff_face *) ff->server_font_data;
364
25.1M
    gs_memory_t *mem = (gs_memory_t *) face->server->mem;
365
366
    /* Tell the FAPI interface that we need to decrypt the glyph data. */
367
25.1M
    ff->need_decrypt = true;
368
369
    /* If glyph_data is already in use (as will happen for composite glyphs)
370
     * create a new buffer on the heap.
371
     */
372
25.1M
    if (a_info->glyph_data_in_use) {
373
117k
        unsigned char *buffer = NULL;
374
375
117k
        length = ff->get_glyph(ff, a_index, NULL, 0);
376
117k
        if (length == gs_fapi_glyph_invalid_format
377
117k
            || length == gs_fapi_glyph_invalid_index)
378
0
            return FT_Err_Invalid_Glyph_Index;
379
380
117k
        buffer = gs_malloc(mem, length, 1, "get_fapi_glyph_data");
381
117k
        if (!buffer)
382
3.08k
            return FT_Err_Out_Of_Memory;
383
384
114k
        length = ff->get_glyph(ff, a_index, buffer, length);
385
114k
        if (length == gs_fapi_glyph_invalid_format) {
386
0
            gs_free((gs_memory_t *) mem, buffer, 0, 0,
387
0
                    "get_fapi_glyph_data");
388
0
            return FT_Err_Invalid_Glyph_Index;
389
0
        }
390
114k
        a_data->pointer = buffer;
391
114k
    }
392
25.0M
    else {
393
        /* Save ff->char_data, which is set to null by FAPI_FF_get_glyph as part of a hack to
394
         * make the deprecated Type 2 endchar ('seac') work, so that it can be restored
395
         * if we need to try again with a longer buffer.
396
         */
397
25.0M
        const void *saved_char_data = ff->char_data;
398
399
        /* Get as much of the glyph data as possible into the buffer */
400
25.0M
        length =
401
25.0M
            ff->get_glyph(ff, a_index, a_info->glyph_data,
402
25.0M
                          (ushort) a_info->glyph_data_length);
403
25.0M
        if (length == gs_fapi_glyph_invalid_format) {
404
0
            ff->char_data = saved_char_data;
405
0
            return FT_Err_Unknown_File_Format;
406
0
        }
407
408
25.0M
        if (length == gs_fapi_glyph_invalid_index) {
409
0
            ff->char_data = saved_char_data;
410
0
            return FT_Err_Invalid_Glyph_Index;
411
0
        }
412
413
        /* If the buffer was too small enlarge it and try again. */
414
25.0M
        if (length > a_info->glyph_data_length) {
415
1.70M
            if (a_info->glyph_data) {
416
944k
                gs_free((gs_memory_t *) mem,
417
944k
                        a_info->glyph_data, 0, 0, "get_fapi_glyph_data");
418
944k
            }
419
420
1.70M
            a_info->glyph_data =
421
1.70M
                gs_malloc(mem, length, 1, "get_fapi_glyph_data");
422
423
1.70M
            if (!a_info->glyph_data) {
424
1.76k
                a_info->glyph_data_length = 0;
425
1.76k
                return FT_Err_Out_Of_Memory;
426
1.76k
            }
427
1.70M
            a_info->glyph_data_length = length;
428
1.70M
            ff->char_data = saved_char_data;
429
1.70M
            length = ff->get_glyph(ff, a_index, a_info->glyph_data, length);
430
1.70M
            if (length == gs_fapi_glyph_invalid_format)
431
0
                return FT_Err_Unknown_File_Format;
432
1.70M
            if (length == gs_fapi_glyph_invalid_index)
433
0
                return FT_Err_Invalid_Glyph_Index;
434
1.70M
        }
435
436
        /* Set the returned pointer and length. */
437
24.9M
        a_data->pointer = a_info->glyph_data;
438
439
24.9M
        a_info->glyph_data_in_use = true;
440
24.9M
    }
441
442
25.1M
    a_data->length = length;
443
25.1M
    return 0;
444
25.1M
}
445
446
static void
447
free_fapi_glyph_data(FT_Incremental a_info, FT_Data * a_data)
448
25.1M
{
449
25.1M
    gs_fapi_font *ff = a_info->fapi_font;
450
25.1M
    ff_face *face = (ff_face *) ff->server_font_data;
451
25.1M
    gs_memory_t *mem = (gs_memory_t *) face->server->mem;
452
453
25.1M
    if (a_data->pointer == (const FT_Byte *)a_info->glyph_data)
454
24.9M
        a_info->glyph_data_in_use = false;
455
113k
    else
456
25.1M
        gs_free(mem, (FT_Byte *) a_data->pointer, 0, 0, "free_fapi_glyph_data");
457
25.1M
}
458
459
static FT_Error
460
get_fapi_glyph_metrics(FT_Incremental a_info, FT_UInt a_glyph_index,
461
                       FT_Bool bVertical,
462
                       FT_Incremental_MetricsRec * a_metrics)
463
27.0M
{
464
    /* FreeType will create synthetic vertical metrics, including a vertical
465
     * advance, if none is present. We don't want this, so if the font uses Truetype outlines
466
     * and the WMode is not 1 (vertical) we ignore the advance by setting it to 0
467
     */
468
27.0M
    if (bVertical && !a_info->fapi_font->is_type1)
469
2.08M
        a_metrics->advance = 0;
470
471
27.0M
    if (a_info->glyph_metrics_index == a_glyph_index) {
472
1.46M
        switch (a_info->metrics_type) {
473
1.46M
            case gs_fapi_metrics_add:
474
1.46M
                a_metrics->advance += a_info->glyph_metrics.advance;
475
1.46M
                break;
476
0
            case gs_fapi_metrics_replace_width:
477
0
                a_metrics->advance = a_info->glyph_metrics.advance;
478
0
                break;
479
0
            case gs_fapi_metrics_replace:
480
0
                *a_metrics = a_info->glyph_metrics;
481
                /* We are replacing the horizontal metrics, so the vertical must be 0 */
482
0
                a_metrics->advance_v = 0;
483
0
                break;
484
0
            default:
485
                /* This can't happen. */
486
0
                return FT_Err_Invalid_Argument;
487
1.46M
        }
488
1.46M
    }
489
27.0M
    return 0;
490
27.0M
}
491
492
static const FT_Incremental_FuncsRec TheFAPIIncrementalInterfaceFuncs = {
493
    get_fapi_glyph_data,
494
    free_fapi_glyph_data,
495
    get_fapi_glyph_metrics
496
};
497
498
static FT_Incremental_InterfaceRec *
499
new_inc_int(gs_fapi_server * a_server, gs_fapi_font * a_fapi_font)
500
1.28M
{
501
1.28M
    ff_server *s = (ff_server *) a_server;
502
503
1.28M
    FT_Incremental_InterfaceRec *i =
504
1.28M
        (FT_Incremental_InterfaceRec *) FF_alloc(s->ftmemory,
505
1.28M
                                                 sizeof
506
1.28M
                                                 (FT_Incremental_InterfaceRec));
507
1.28M
    if (i) {
508
1.28M
        i->funcs = &TheFAPIIncrementalInterfaceFuncs;
509
1.28M
        i->object = (FT_Incremental) new_inc_int_info(a_server, a_fapi_font);
510
511
1.28M
        if (!i->object) {
512
0
            FF_free(s->ftmemory, i);
513
0
            i = NULL;
514
0
        }
515
1.28M
    }
516
1.28M
    return i;
517
1.28M
}
518
519
static void
520
delete_inc_int(gs_fapi_server * a_server,
521
               FT_Incremental_InterfaceRec * a_inc_int)
522
1.28M
{
523
1.28M
    ff_server *s = (ff_server *) a_server;
524
525
1.28M
    if (a_inc_int) {
526
1.28M
        delete_inc_int_info(a_server, a_inc_int->object);
527
1.28M
        FF_free(s->ftmemory, a_inc_int);
528
1.28M
    }
529
1.28M
}
530
531
/* Convert FreeType error codes to GhostScript ones.
532
 * Very rudimentary because most don't correspond.
533
 */
534
static int
535
ft_to_gs_error(FT_Error a_error)
536
30.3M
{
537
30.3M
    if (a_error) {
538
346k
        if (a_error == FT_Err_Out_Of_Memory)
539
0
            return_error(gs_error_VMerror);
540
346k
        else
541
346k
            return_error(gs_error_unknownerror);
542
346k
    }
543
30.0M
    return 0;
544
30.3M
}
545
546
/* Load a glyph and optionally rasterize it. Return its metrics in a_metrics.
547
 * If a_bitmap is true convert the glyph to a bitmap.
548
 */
549
static gs_fapi_retcode
550
load_glyph(gs_fapi_server * a_server, gs_fapi_font * a_fapi_font,
551
           const gs_fapi_char_ref * a_char_ref, gs_fapi_metrics * a_metrics,
552
           FT_Glyph * a_glyph, bool a_bitmap, int max_bitmap)
553
27.0M
{
554
27.0M
    ff_server *s = (ff_server *) a_server;
555
27.0M
    FT_Error ft_error = 0;
556
27.0M
    FT_Error ft_error_fb = 1;
557
27.0M
    ff_face *face = (ff_face *) a_fapi_font->server_font_data;
558
27.0M
    FT_Face ft_face = face->ft_face;
559
27.0M
    int index = a_char_ref->char_codes[0];
560
27.0M
    FT_Long w;
561
27.0M
    FT_Long h;
562
27.0M
    FT_Long fflags;
563
27.0M
    FT_Int32 load_flags = 0;
564
27.0M
    FT_Vector  delta = {0,0};
565
566
    /* Save a_fapi_font->char_data, which is set to null by FAPI_FF_get_glyph as part of a hack to
567
     * make the deprecated Type 2 endchar ('seac') work, so that it can be restored
568
     * after the first call to FT_Load_Glyph.
569
     */
570
27.0M
    const void *saved_char_data = a_fapi_font->char_data;
571
27.0M
    const int saved_char_data_len = a_fapi_font->char_data_len;
572
573
27.0M
    if (s->bitmap_glyph) {
574
0
        FT_Bitmap_Done(s->freetype_library, &s->bitmap_glyph->bitmap);
575
0
        FF_free(s->ftmemory, s->bitmap_glyph);
576
0
        s->bitmap_glyph = NULL;
577
0
    }
578
27.0M
    if (s->outline_glyph) {
579
0
        FT_Outline_Done(s->freetype_library, &s->outline_glyph->outline);
580
0
        FF_free(s->ftmemory, s->outline_glyph);
581
0
        s->outline_glyph = NULL;
582
0
    }
583
584
27.0M
    if (!a_char_ref->is_glyph_index) {
585
23.3M
        if (ft_face->num_charmaps)
586
23.2M
            index = FT_Get_Char_Index(ft_face, index);
587
135k
        else {
588
            /* If there are no character maps and no glyph index, loading the glyph will still work
589
             * properly if both glyph data and metrics are supplied by the incremental interface.
590
             * In that case we use a dummy glyph index which will be passed
591
             * back to FAPI_FF_get_glyph by get_fapi_glyph_data.
592
             *
593
             * Type 1 fonts don't use the code and can appear to FreeType to have only one glyph,
594
             * so we have to set the index to 0.
595
             *
596
             * For other font types, FAPI_FF_get_glyph requires the character code
597
             * when getting data.
598
             */
599
135k
            if (a_fapi_font->is_type1)
600
0
                index = 0;
601
135k
            else
602
135k
                index = a_char_ref->char_codes[0];
603
135k
        }
604
23.3M
    }
605
3.71M
    else {
606
        /* This is a heuristic to try to avoid using the TTF notdef (empty rectangle), and replace it
607
           with a non-marking glyph instead. This is only required for fonts where we don't use the
608
           FT incremental interface - when we are using the incremental interface, we handle it in
609
           our own glyph lookup code.
610
         */
611
3.71M
        if (!a_fapi_font->is_cid && !face->ft_inc_int &&
612
0
            (index == 0 ||
613
0
            (a_char_ref->client_char_code != gs_no_char &&
614
0
            FT_Get_Char_Index(ft_face, a_char_ref->client_char_code) <= 0))) {
615
0
            int tmp_ind;
616
617
0
            if ((tmp_ind = FT_Get_Char_Index(ft_face, 32)) > 0) {
618
0
                index = tmp_ind;
619
0
            }
620
0
        }
621
3.71M
    }
622
    /* Refresh the pointer to the FAPI_font held by the incremental interface. */
623
27.0M
    if (face->ft_inc_int)
624
24.8M
        face->ft_inc_int->object->fapi_font = a_fapi_font;
625
626
    /* Store the overriding metrics if they have been supplied. */
627
27.0M
    if (face->ft_inc_int && a_char_ref->metrics_type != gs_fapi_metrics_notdef) {
628
629
1.46M
        FT_Incremental_MetricsRec *m = &face->ft_inc_int->object->glyph_metrics;
630
631
1.46M
        m->bearing_x = a_char_ref->sb_x >> 16;
632
1.46M
        m->bearing_y = a_char_ref->sb_y >> 16;
633
1.46M
        m->advance = a_char_ref->aw_x >> 16;
634
635
1.46M
        face->ft_inc_int->object->glyph_metrics_index = index;
636
637
        /* For most font types, the original metrics come directly from the font, and
638
           what we have here are customized (such as a Matrics dict in Postscript). We
639
           only want to use the width, in that case, because other metrics can mess up
640
           the hinting in Freetype. We'll apply custom lsb outselves, using the "delta"
641
           stuff below.
642
           The exception here is PCL/XL embedded TTF fonts, where the h/vmtx tables can
643
           be missing, and we *have* to use the explicit metrics from the PCL/XL glyph
644
           data. (NOTE: if those do not match the original font's metrics, again, the hinting
645
           can be distorted)
646
         */
647
1.46M
        if (a_char_ref->metrics_type == gs_fapi_metrics_replace && !a_fapi_font->is_mtx_skipped) {
648
0
            face->ft_inc_int->object->glyph_metrics_index = 0xFFFFFFFF;
649
0
            delta.x = FT_MulFix(a_char_ref->sb_x >> 16, ft_face->size->metrics.x_scale);
650
0
            delta.y = FT_MulFix(a_char_ref->sb_y >> 16, ft_face->size->metrics.y_scale);
651
0
            FT_Vector_Transform( &delta, &face->ft_transform);
652
0
        }
653
1.46M
        else {
654
1.46M
            face->ft_inc_int->object->metrics_type = a_char_ref->metrics_type;
655
1.46M
        }
656
1.46M
    }
657
25.5M
    else if (face->ft_inc_int)
658
        /* Make sure we don't leave this set to the last value, as we may then use inappropriate metrics values */
659
23.3M
        face->ft_inc_int->object->glyph_metrics_index = 0xFFFFFFFF;
660
661
    /* We have to load the glyph, scale it correctly, and render it if we need a bitmap. */
662
27.0M
    if (!ft_error) {
663
        /* We disable loading bitmaps because if we allow it then FreeType invents metrics for them, which messes up our glyph positioning */
664
        /* Also the bitmaps tend to look somewhat different (though more readable) than FreeType's rendering. By disabling them we */
665
        /* maintain consistency better.  (FT_LOAD_NO_BITMAP) */
666
27.0M
        a_fapi_font->char_data = saved_char_data;
667
27.0M
        if (!a_fapi_font->is_mtx_skipped && !a_fapi_font->is_type1) {
668
            /* grid_fit == 1 is the default - use font's native hints
669
             * with freetype, 1 & 3 are, in practice, the same.
670
             */
671
672
4.36M
            if (a_server->grid_fit == 0) {
673
0
                load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT;
674
0
            }
675
4.36M
            else if (a_server->grid_fit == 2) {
676
0
                load_flags = FT_LOAD_FORCE_AUTOHINT;
677
0
            }
678
4.36M
            load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_NO_BITMAP | FT_LOAD_LINEAR_DESIGN | FT_LOAD_PEDANTIC;
679
4.36M
        }
680
22.7M
        else {
681
            /* Current FreeType hinting for type 1 fonts is so poor we are actually better off without it (fewer files render incorrectly) (FT_LOAD_NO_HINTING) */
682
            /* We also need to disable hinting for XL format embedded truetypes */
683
22.7M
            load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_LINEAR_DESIGN;
684
22.7M
        }
685
686
27.0M
        ft_error = FT_Load_Glyph(ft_face, index, load_flags);
687
27.0M
        if (ft_error == FT_Err_Unknown_File_Format) {
688
0
            return index + 1;
689
0
        }
690
27.0M
    }
691
692
27.0M
    if (ft_error == FT_Err_Invalid_Argument
693
27.0M
        || ft_error == FT_Err_Invalid_Reference
694
26.8M
        || ft_error == FT_Err_Invalid_Glyph_Index
695
26.8M
        || ft_error == FT_Err_DEF_In_Glyf_Bytecode
696
26.8M
        || (ft_error >= FT_Err_Invalid_Opcode
697
1.00M
            && ft_error <= FT_Err_Too_Many_Instruction_Defs)) {
698
699
1.00M
        a_fapi_font->char_data = saved_char_data;
700
701
        /* We want to prevent hinting, even for a "tricky" font - it shouldn't matter for the notdef */
702
1.00M
        fflags = ft_face->face_flags;
703
1.00M
        ft_face->face_flags &= ~FT_FACE_FLAG_TRICKY;
704
1.00M
        load_flags |= FT_LOAD_NO_HINTING;
705
1.00M
        ft_error = FT_Load_Glyph(ft_face, index, load_flags);
706
707
1.00M
        ft_face->face_flags = fflags;
708
1.00M
    }
709
710
27.0M
    if (ft_error == FT_Err_Out_Of_Memory
711
27.0M
        || ft_error == FT_Err_Array_Too_Large) {
712
1.98k
        return (gs_error_VMerror);
713
1.98k
    }
714
715
    /* If FT gives us an error, try to fall back to the notdef - if that doesn't work, we'll throw an error over to Ghostscript */
716
27.0M
    if (ft_error) {
717
349k
        gs_string notdef_str;
718
719
349k
        notdef_str.data = (byte *)".notdef";
720
349k
        notdef_str.size = 7;
721
722
349k
        a_fapi_font->char_data = (void *)(&notdef_str);
723
349k
        a_fapi_font->char_data_len = 0;
724
725
        /* We want to prevent hinting, even for a "tricky" font - it shouldn't matter for the notdef */
726
349k
        fflags = ft_face->face_flags;
727
349k
        ft_face->face_flags &= ~FT_FACE_FLAG_TRICKY;
728
729
349k
        ft_error_fb = FT_Load_Glyph(ft_face, 0, load_flags);
730
731
349k
        ft_face->face_flags = fflags;
732
733
349k
        a_fapi_font->char_data = saved_char_data;
734
349k
        a_fapi_font->char_data_len = saved_char_data_len;
735
349k
    }
736
737
27.0M
    if ((!ft_error || !ft_error_fb) && (delta.x != 0 || delta.y != 0)) {
738
0
        FT_Outline_Translate( &ft_face->glyph->outline, delta.x, delta.y);
739
0
    }
740
741
    /* Previously we interpreted the glyph unscaled, and derived the metrics from that. Now we only interpret it
742
     * once, and work out the metrics from the scaled/hinted outline.
743
     */
744
27.0M
    if ((!ft_error || !ft_error_fb) && a_metrics) {
745
26.9M
        FT_Long hx;
746
26.9M
        FT_Long hy;
747
26.9M
        FT_Long vadv;
748
749
        /* In order to get the metrics in the form we need them, we have to remove the size scaling
750
         * the resolution scaling, and convert to points.
751
         */
752
26.9M
        hx = (FT_Long) (((double)ft_face->glyph->metrics.horiBearingX *
753
26.9M
                         ft_face->units_per_EM * 72.0) /
754
26.9M
                        ((double)face->width * face->horz_res))  + (a_fapi_font->is_mtx_skipped == 1 ? 0 : a_char_ref->sb_x >> 16);
755
26.9M
        hy = (FT_Long) (((double)ft_face->glyph->metrics.horiBearingY *
756
26.9M
                         ft_face->units_per_EM * 72.0) /
757
26.9M
                        ((double)face->height * face->vert_res)) + (a_fapi_font->is_mtx_skipped == 1 ? 0 : a_char_ref->sb_y >> 16);
758
759
26.9M
        w = (FT_Long) (((double)ft_face->glyph->metrics.width *
760
26.9M
                        ft_face->units_per_EM * 72.0) / ((double)face->width *
761
26.9M
                                                         face->horz_res));
762
26.9M
        h = (FT_Long) (((double)ft_face->glyph->metrics.height *
763
26.9M
                        ft_face->units_per_EM * 72.0) /
764
26.9M
                       ((double)face->height * face->vert_res));
765
766
        /* Ugly. FreeType creates verticla metrics for TT fonts, normally we override them in the
767
         * metrics callbacks, but those only work for incremental interface fonts, and TrueType fonts
768
         * loaded as CIDFont replacements are not incrementally handled. So here, if its a CIDFont, and
769
         * its not type 1 outlines, and its not a vertical mode fotn, ignore the advance.
770
         */
771
26.9M
        if (a_fapi_font->is_type1
772
4.26M
           || ((a_fapi_font->full_font_buf || a_fapi_font->font_file_path)
773
22.7M
           && a_fapi_font->is_vertical &&  FT_HAS_VERTICAL(ft_face))) {
774
775
22.7M
            vadv = ft_face->glyph->linearVertAdvance;
776
22.7M
        }
777
4.26M
        else {
778
4.26M
            vadv = 0;
779
4.26M
        }
780
781
26.9M
        a_metrics->bbox_x0 = hx;
782
26.9M
        a_metrics->bbox_y0 = hy - h;
783
26.9M
        a_metrics->bbox_x1 = a_metrics->bbox_x0 + w;
784
26.9M
        a_metrics->bbox_y1 = a_metrics->bbox_y0 + h;
785
26.9M
        a_metrics->escapement = ft_face->glyph->linearHoriAdvance;
786
26.9M
        a_metrics->v_escapement = vadv;
787
26.9M
        a_metrics->em_x = ft_face->units_per_EM;
788
26.9M
        a_metrics->em_y = ft_face->units_per_EM;
789
26.9M
    }
790
791
27.0M
    if ((!ft_error || !ft_error_fb)) {
792
793
26.9M
        FT_BBox cbox;
794
795
        /* compute the control box, and grid fit it - lifted from ft_raster1_render() */
796
26.9M
        FT_Outline_Get_CBox(&ft_face->glyph->outline, &cbox);
797
798
        /* These round operations are only to preserve behaviour compared to the 9.00 release
799
           which used the bitmap dimensions as calculated by Freetype.
800
           But FT_PIX_FLOOR/FT_PIX_CEIL aren't public.
801
         */
802
26.9M
        cbox.xMin = ((cbox.xMin) & ~63);        /* FT_PIX_FLOOR( cbox.xMin ) */
803
26.9M
        cbox.yMin = ((cbox.yMin) & ~63);
804
26.9M
        cbox.xMax = (((cbox.xMax) + 63) & ~63);
805
26.9M
        cbox.yMax = (((cbox.yMax) + 63) & ~63); /* FT_PIX_CEIL( cbox.yMax ) */
806
807
26.9M
        w = (FT_UInt) ((cbox.xMax - cbox.xMin) >> 6);
808
26.9M
        h = (FT_UInt) ((cbox.yMax - cbox.yMin) >> 6);
809
810
26.9M
        if (!a_fapi_font->metrics_only && a_bitmap == true && ft_face->glyph->format != FT_GLYPH_FORMAT_BITMAP
811
14.9M
            && ft_face->glyph->format != FT_GLYPH_FORMAT_COMPOSITE) {
812
14.9M
            if ((bitmap_raster(w) * h) < max_bitmap) {
813
7.85M
                FT_Render_Mode mode = FT_RENDER_MODE_MONO;
814
815
7.85M
                ft_error = FT_Render_Glyph(ft_face->glyph, mode);
816
7.85M
                if (ft_error != 0) {
817
28
                    (*a_glyph) = NULL;
818
28
                    return (gs_error_VMerror);
819
28
                }
820
7.85M
            }
821
7.13M
            else {
822
7.13M
                (*a_glyph) = NULL;
823
7.13M
                return (gs_error_VMerror);
824
7.13M
            }
825
14.9M
        }
826
26.9M
    }
827
828
19.9M
    if (!a_fapi_font->metrics_only) {
829
        /* The following works around the fact that at the scales we deal with
830
         * these values may not fit in a 16.16 fixed point value, and thus cause
831
         * freetype to error due to overflow - but we don't use these values
832
         * and neither does freetype, we can set them to zero and avoid the error
833
         */
834
18.4M
        ft_face->glyph->advance.x = ft_face->glyph->advance.y = 0;
835
18.4M
        if ((!ft_error || !ft_error_fb) && a_glyph) {
836
18.3M
            ft_error = FT_Get_Glyph(ft_face->glyph, a_glyph);
837
18.3M
        }
838
94.7k
        else {
839
94.7k
            if (ft_face->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
840
0
                FT_BitmapGlyph bmg;
841
842
0
                ft_error = FT_Get_Glyph(ft_face->glyph, (FT_Glyph *) & bmg);
843
0
                if (!ft_error) {
844
0
                    FT_Bitmap_Done(s->freetype_library, &bmg->bitmap);
845
0
                    FF_free(s->ftmemory, bmg);
846
0
                }
847
0
            }
848
94.7k
            else if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
849
84.5k
                FT_OutlineGlyph olg;
850
851
84.5k
                ft_error = FT_Get_Glyph(ft_face->glyph, (FT_Glyph *) & olg);
852
84.5k
                if (!ft_error) {
853
84.5k
                    FT_Outline_Done(s->freetype_library, &olg->outline);
854
84.5k
                    FF_free(s->ftmemory, olg);
855
84.5k
                }
856
84.5k
            }
857
94.7k
        }
858
18.4M
    }
859
860
19.9M
    if (ft_error == FT_Err_Too_Many_Hints) {
861
#ifdef DEBUG
862
        if (gs_debug_c('1')) {
863
            ft_emprintf1(a_fapi_font->memory,
864
                      "TrueType glyph %"PRId64" uses more instructions than the declared maximum in the font.",
865
                      a_char_ref->char_codes[0]);
866
867
            if (!ft_error_fb) {
868
                ft_emprintf(a_fapi_font->memory,
869
                         " Continuing, falling back to notdef\n\n");
870
            }
871
        }
872
#endif
873
0
        if (!ft_error_fb)
874
0
            ft_error = 0;
875
0
    }
876
19.9M
    if (ft_error == FT_Err_Invalid_Argument) {
877
#ifdef DEBUG
878
        if (gs_debug_c('1')) {
879
            ft_emprintf1(a_fapi_font->memory,
880
                      "TrueType parsing error in glyph %"PRId64" in the font.",
881
                      a_char_ref->char_codes[0]);
882
883
            if (!ft_error_fb) {
884
                ft_emprintf(a_fapi_font->memory,
885
                         " Continuing, falling back to notdef\n\n");
886
            }
887
        }
888
#endif
889
10.1k
        if (!ft_error_fb)
890
0
            ft_error = 0;
891
10.1k
    }
892
19.9M
    if (ft_error == FT_Err_Too_Many_Function_Defs) {
893
#ifdef DEBUG
894
        if (gs_debug_c('1')) {
895
            ft_emprintf1(a_fapi_font->memory,
896
                      "TrueType instruction error in glyph %"PRId64" in the font.",
897
                      a_char_ref->char_codes[0]);
898
899
            if (!ft_error_fb) {
900
                ft_emprintf(a_fapi_font->memory,
901
                         " Continuing, falling back to notdef\n\n");
902
            }
903
        }
904
#endif
905
0
        if (!ft_error_fb)
906
0
            ft_error = 0;
907
0
    }
908
19.9M
    if (ft_error == FT_Err_Invalid_Glyph_Index) {
909
#ifdef DEBUG
910
        if (gs_debug_c('1')) {
911
            ft_emprintf1(a_fapi_font->memory,
912
                      "FreeType is unable to find the glyph %"PRId64" in the font.",
913
                      a_char_ref->char_codes[0]);
914
915
            if (!ft_error_fb) {
916
                ft_emprintf(a_fapi_font->memory,
917
                         " Continuing, falling back to notdef\n\n");
918
            }
919
        }
920
#endif
921
0
        if (!ft_error_fb)
922
0
            ft_error = 0;
923
0
    }
924
19.9M
    return ft_to_gs_error(ft_error);
925
27.0M
}
926
927
/*
928
 * Ensure that the rasterizer is open.
929
 *
930
 * In the case of FreeType this means creating the FreeType library object.
931
 */
932
static gs_fapi_retcode
933
gs_fapi_ft_ensure_open(gs_fapi_server * a_server, const char * server_param,
934
                       int server_param_size)
935
1.30M
{
936
1.30M
    ff_server *s = (ff_server *) a_server;
937
1.30M
    FT_UInt tt_ins_version = TT_INTERPRETER_VERSION_35;
938
1.30M
    FT_Error ft_error;
939
940
1.30M
    if (s->freetype_library)
941
1.23M
        return 0;
942
943
    /* As we want FT to use our memory management, we cannot use the convenience of
944
     * FT_Init_FreeType(), we have to do each stage "manually"
945
     */
946
74.1k
    s->ftmemory->user = s->mem;
947
74.1k
    s->ftmemory->alloc = FF_alloc;
948
74.1k
    s->ftmemory->free = FF_free;
949
74.1k
    s->ftmemory->realloc = FF_realloc;
950
951
74.1k
    ft_error = FT_New_Library(s->ftmemory, &s->freetype_library);
952
74.1k
    if (ft_error)
953
0
        return ft_to_gs_error(ft_error);
954
955
74.1k
    FT_Add_Default_Modules(s->freetype_library);
956
74.1k
    FT_Property_Set( s->freetype_library, "truetype", "interpreter-version", &tt_ins_version);
957
958
74.1k
    return 0;
959
74.1k
}
960
961
#if 0                           /* Not currently used */
962
static void
963
transform_concat(FT_Matrix * a_A, const FT_Matrix * a_B)
964
{
965
    FT_Matrix result = *a_B;
966
967
    FT_Matrix_Multiply(a_A, &result);
968
    *a_A = result;
969
}
970
971
/* Create a transform representing an angle defined as a vector. */
972
static void
973
make_rotation(FT_Matrix * a_transform, const FT_Vector * a_vector)
974
{
975
    FT_Fixed length, cos, sin;
976
977
    if (a_vector->x >= 0 && a_vector->y == 0) {
978
        a_transform->xx = a_transform->yy = 65536;
979
        a_transform->xy = a_transform->yx = 0;
980
        return;
981
    }
982
983
    length = FT_Vector_Length((FT_Vector *) a_vector);
984
    cos = FT_DivFix(a_vector->x, length);
985
    sin = FT_DivFix(a_vector->y, length);
986
    a_transform->xx = a_transform->yy = cos;
987
    a_transform->xy = -sin;
988
    a_transform->yx = sin;
989
}
990
#endif /* Not currently used */
991
992
/* Divide a transformation into a scaling part and a rotation-and-shear part.
993
 * The scaling part is used for setting the pixel size for hinting.
994
 */
995
static void
996
transform_decompose(FT_Matrix * a_transform, FT_UInt * xresp, FT_UInt * yresp,
997
                    FT_Fixed * a_x_scale, FT_Fixed * a_y_scale, int units_per_EM)
998
4.26M
{
999
4.26M
    double scalex, scaley, fact = 1.0;
1000
4.26M
    double factx = 1.0, facty = 1.0;
1001
4.26M
    FT_Matrix ftscale_mat;
1002
4.26M
    FT_UInt xres;
1003
4.26M
    FT_UInt yres;
1004
    /* We have to account for units_per_EM as we fiddle with the scaling
1005
     * in order to avoid underflow (mostly in the TTF hinting code), but
1006
     * we also want to clamp to a lower value (512, admittedly arrived at
1007
     * via experimentation) in order to preserve the fidelity of the outlines.
1008
     */
1009
4.26M
    double upe = units_per_EM > 512 ? (float)units_per_EM : 512.0;
1010
1011
4.26M
    scalex = hypot((double)a_transform->xx, (double)a_transform->xy);
1012
4.26M
    scaley = hypot((double)a_transform->yx, (double)a_transform->yy);
1013
1014
    /* In addition to all the wrangling below, we have to make sure that
1015
     * that the contents of a_transform can also be understood by Freetype.
1016
     */
1017
4.26M
    if (scalex < 64.0 || scaley < 64.0) {
1018
8.21k
        factx = 64.0/scalex;
1019
8.21k
        facty = 64.0/scaley;
1020
1021
8.21k
        ftscale_mat.xx = (FT_Fixed)(a_transform->xx * factx);
1022
8.21k
        ftscale_mat.xy = (FT_Fixed)(a_transform->xy * facty);
1023
8.21k
        ftscale_mat.yx = (FT_Fixed)(a_transform->yx * factx);
1024
8.21k
        ftscale_mat.yy = (FT_Fixed)(a_transform->yy * facty);
1025
8.21k
        memcpy(a_transform, &ftscale_mat, sizeof(ftscale_mat));
1026
8.21k
        scalex = hypot((double)a_transform->xx, (double)a_transform->xy);
1027
8.21k
        scaley = hypot((double)a_transform->yx, (double)a_transform->yy);
1028
8.21k
    }
1029
1030
4.26M
    if (*xresp != *yresp) {
1031
        /* To get good results, we have to pull the implicit scaling from
1032
         * non-square resolutions, and apply it in the matrix. This means
1033
         * we get the correct "shearing" effect for rotated glyphs.
1034
         * The previous solution was only effective for for glyphs whose
1035
         * axes were coincident with the axes of the page.
1036
         */
1037
0
        bool use_x = true;
1038
1039
0
        if (*xresp < *yresp) {
1040
0
            use_x = false;
1041
0
        }
1042
1043
0
        ftscale_mat.xx =
1044
0
            (int)(((double)(*xresp) /
1045
0
                   ((double)(use_x ? (*xresp) : (*yresp)))) * 65536);
1046
0
        ftscale_mat.xy = ftscale_mat.yx = 0;
1047
0
        ftscale_mat.yy =
1048
0
            (int)(((double)(*yresp) /
1049
0
                   ((double)(use_x ? (*xresp) : (*yresp)))) * 65536);
1050
1051
0
        FT_Matrix_Multiply(&ftscale_mat, a_transform);
1052
1053
0
        xres = yres = (use_x ? (*xresp) : (*yresp));
1054
0
        xres = (FT_UInt)(xres / factx);
1055
0
        yres = (FT_UInt)(yres / facty);
1056
0
    }
1057
4.26M
    else {
1058
        /* Life is considerably easier when square resolutions are in use! */
1059
4.26M
        xres = (FT_UInt)(*xresp / factx);
1060
4.26M
        yres = (FT_UInt)(*yresp / facty);
1061
4.26M
    }
1062
1063
4.26M
    scalex *= 1.0 / 65536.0;
1064
4.26M
    scaley *= 1.0 / 65536.0;
1065
1066
4.26M
    if (scalex < scaley) {
1067
215k
        scaley = scalex;
1068
215k
    }
1069
4.05M
    else if (scalex > scaley) {
1070
90.4k
        scalex = scaley;
1071
90.4k
    }
1072
1073
    /* FT clamps the width and height to a lower limit of 1.0 units
1074
     * (note: as FT stores it in 64ths of a unit, that is 64)
1075
     * So if either the width or the height are <1.0 here, we scale
1076
     * the width and height appropriately, and then compensate using
1077
     * the "final" matrix for FT
1078
     */
1079
    /* We use 1 1/64th to calculate the scale, so that we *guarantee* the
1080
     * scalex/y we calculate will be >64 after rounding.
1081
     */
1082
1083
4.26M
    if (scalex < 1.0) {
1084
1.19M
        fact = 1.016 / scalex;
1085
1.19M
        scalex = scalex * fact;
1086
1.19M
        scaley = scaley * fact;
1087
1.19M
    }
1088
1089
    /* see above */
1090
4.26M
    if (scalex * xres < 2268.0 / 64.0) {
1091
5.07k
        fact = (2400.0 / 64.0) / (xres * scalex);
1092
5.07k
        scaley *= fact;
1093
5.07k
        scalex *= fact;
1094
5.07k
    }
1095
1096
    /* see above */
1097
4.26M
    fact = 1.0;
1098
12.0M
    while (scaley * yres > (double)upe * 72.0 && (xres > 0 && yres > 0)
1099
7.76M
           && (scalex > 0.0 && scaley > 0.0)) {
1100
7.76M
        if (scaley < yres) {
1101
2.57k
            xres >>= 1;
1102
2.57k
            yres >>= 1;
1103
2.57k
            fact *= 2.0;
1104
2.57k
        }
1105
7.76M
        else {
1106
7.76M
            scalex /= 1.25;
1107
7.76M
            scaley /= 1.25;
1108
7.76M
        }
1109
7.76M
    }
1110
1111
4.26M
    ftscale_mat.xx = (FT_Fixed) ((65536.0 / scalex) * fact);
1112
4.26M
    ftscale_mat.xy = 0;
1113
4.26M
    ftscale_mat.yx = 0;
1114
4.26M
    ftscale_mat.yy = (FT_Fixed) ((65536.0 / scaley) * fact);
1115
1116
4.26M
    FT_Matrix_Multiply(a_transform, &ftscale_mat);
1117
4.26M
    memcpy(a_transform, &ftscale_mat, sizeof(FT_Matrix));
1118
1119
4.26M
    *xresp = xres;
1120
4.26M
    *yresp = yres;
1121
    /* Return values ready scaled for FT */
1122
4.26M
    *a_x_scale = (FT_Fixed) (scalex * 64);
1123
4.26M
    *a_y_scale = (FT_Fixed) (scaley * 64);
1124
4.26M
}
1125
1126
/*
1127
 * Open a font and set its size.
1128
 */
1129
static gs_fapi_retcode
1130
gs_fapi_ft_get_scaled_font(gs_fapi_server * a_server, gs_fapi_font * a_font,
1131
                const gs_fapi_font_scale * a_font_scale,
1132
                const char *a_map, gs_fapi_descendant_code a_descendant_code)
1133
4.27M
{
1134
4.27M
    ff_server *s = (ff_server *) a_server;
1135
4.27M
    ff_face *face = (ff_face *) a_font->server_font_data;
1136
4.27M
    FT_Error ft_error = 0;
1137
4.27M
    int i, j, code;
1138
4.27M
    FT_CharMap cmap = NULL;
1139
4.27M
    bool data_owned = true;
1140
1141
4.27M
    if (s->bitmap_glyph) {
1142
0
        FT_Bitmap_Done(s->freetype_library, &s->bitmap_glyph->bitmap);
1143
0
        FF_free(s->ftmemory, s->bitmap_glyph);
1144
0
        s->bitmap_glyph = NULL;
1145
0
    }
1146
4.27M
    if (s->outline_glyph) {
1147
0
        FT_Outline_Done(s->freetype_library, &s->outline_glyph->outline);
1148
0
        FF_free(s->ftmemory, s->outline_glyph);
1149
0
        s->outline_glyph = NULL;
1150
0
    }
1151
1152
    /* dpf("gs_fapi_ft_get_scaled_font enter: is_type1=%d is_cid=%d font_file_path='%s' a_descendant_code=%d\n",
1153
       a_font->is_type1, a_font->is_cid, a_font->font_file_path ? a_font->font_file_path : "", a_descendant_code); */
1154
1155
    /* If this font is the top level font of an embedded CID type 0 font (font type 9)
1156
     * do nothing. See the comment in FAPI_prepare_font. The descendant fonts are
1157
     * passed in individually.
1158
     */
1159
4.27M
    if (a_font->is_cid && a_font->is_type1 && a_font->font_file_path == NULL
1160
10.7k
        && (a_descendant_code == gs_fapi_toplevel_begin
1161
8.08k
            || a_descendant_code == gs_fapi_toplevel_complete)) {
1162
        /* dpf("gs_fapi_ft_get_scaled_font return 0\n"); */
1163
5.19k
        return 0;
1164
5.19k
    }
1165
1166
    /* Create the face if it doesn't already exist. */
1167
4.27M
    if (!face) {
1168
1.29M
        FT_Face ft_face = NULL;
1169
1.29M
        FT_Parameter ft_param;
1170
1.29M
        FT_Incremental_InterfaceRec *ft_inc_int = NULL;
1171
1.29M
        unsigned char *own_font_data = NULL;
1172
1.29M
        int own_font_data_len = -1;
1173
1.29M
        FT_Stream ft_strm = NULL;
1174
1175
        /* dpf("gs_fapi_ft_get_scaled_font creating face\n"); */
1176
1177
1.29M
        if (a_font->full_font_buf) {
1178
1179
17.8k
            own_font_data =
1180
17.8k
                gs_malloc(((gs_memory_t *) (s->ftmemory->user)),
1181
17.8k
                          a_font->full_font_buf_len, 1,
1182
17.8k
                          "gs_fapi_ft_get_scaled_font - full font buf");
1183
17.8k
            if (!own_font_data) {
1184
0
                return_error(gs_error_VMerror);
1185
0
            }
1186
1187
17.8k
            own_font_data_len = a_font->full_font_buf_len;
1188
17.8k
            memcpy(own_font_data, a_font->full_font_buf,
1189
17.8k
                   a_font->full_font_buf_len);
1190
1191
17.8k
            ft_error =
1192
17.8k
                FT_New_Memory_Face(s->freetype_library,
1193
17.8k
                                   (const FT_Byte *)own_font_data,
1194
17.8k
                                   own_font_data_len, a_font->subfont,
1195
17.8k
                                   &ft_face);
1196
1197
17.8k
            if (ft_error) {
1198
1.16k
                gs_memory_t *mem = (gs_memory_t *) s->ftmemory->user;
1199
1.16k
                gs_free(mem, own_font_data, 0, 0, "gs_fapi_ft_get_scaled_font");
1200
1.16k
                return ft_to_gs_error(ft_error);
1201
1.16k
            }
1202
17.8k
        }
1203
        /* Load a typeface from a file. */
1204
1.28M
        else if (a_font->font_file_path) {
1205
0
            FT_Open_Args args;
1206
1207
0
            memset(&args, 0x00, sizeof(args));
1208
1209
0
            if ((code =
1210
0
                 FF_open_read_stream((gs_memory_t *) (s->ftmemory->user),
1211
0
                                     (char *)a_font->font_file_path,
1212
0
                                     &ft_strm)) < 0) {
1213
0
                return (code);
1214
0
            }
1215
1216
0
            args.flags = FT_OPEN_STREAM;
1217
0
            args.stream = ft_strm;
1218
1219
0
            ft_error =
1220
0
                FT_Open_Face(s->freetype_library, &args, a_font->subfont,
1221
0
                             &ft_face);
1222
0
            if (ft_error) {
1223
                /* in the event of an error, Freetype should cleanup the stream */
1224
                /* But not the ft container */
1225
0
                gs_memory_t *mem = (gs_memory_t *) s->ftmemory->user;
1226
0
                gs_free(mem, ft_strm, 0, 0, "gs_fapi_ft_get_scaled_font");
1227
0
                return ft_to_gs_error(ft_error);
1228
0
            }
1229
0
        }
1230
1231
        /* Load a typeface from a representation in GhostScript's memory. */
1232
1.28M
        else {
1233
1.28M
            FT_Open_Args open_args;
1234
1235
1.28M
            open_args.flags = FT_OPEN_MEMORY;
1236
1.28M
            open_args.stream = NULL;
1237
1238
1.28M
            if (a_font->is_type1) {
1239
1.24M
                long length;
1240
1.24M
                unsigned short type = 0;
1241
1242
1.24M
                code = a_font->get_word(a_font, gs_fapi_font_feature_FontType, 0, &type);
1243
1.24M
                if (code < 0) {
1244
0
                    return code;
1245
0
                }
1246
1247
                /* Tell the FAPI interface that we need to decrypt the /Subrs data. */
1248
1.24M
                a_font->need_decrypt = true;
1249
1250
                /*
1251
                   Serialise a type 1 font in PostScript source form, or
1252
                   a Type 2 font in binary form, so that FreeType can read it.
1253
                 */
1254
1.24M
                if (type == 1)
1255
1.23M
                    length = gs_fapi_serialize_type1_font(a_font, NULL, 0);
1256
16.3k
                else
1257
16.3k
                    length = gs_fapi_serialize_type2_font(a_font, NULL, 0);
1258
1259
1.24M
                open_args.memory_base = own_font_data =
1260
1.24M
                    FF_alloc(s->ftmemory, length);
1261
1.24M
                if (!open_args.memory_base)
1262
88
                    return_error(gs_error_VMerror);
1263
1.24M
                own_font_data_len = length;
1264
1.24M
                if (type == 1)
1265
1.23M
                    open_args.memory_size =
1266
1.23M
                        gs_fapi_serialize_type1_font(a_font, own_font_data, length);
1267
16.2k
                else
1268
16.2k
                    open_args.memory_size =
1269
16.2k
                        gs_fapi_serialize_type2_font(a_font, own_font_data, length);
1270
1271
1.24M
                if (open_args.memory_size != length)
1272
0
                    return_error(gs_error_unregistered);        /* Must not happen. */
1273
1274
1.24M
                ft_inc_int = new_inc_int(a_server, a_font);
1275
1.24M
                if (!ft_inc_int) {
1276
0
                    FF_free(s->ftmemory, own_font_data);
1277
0
                    return_error(gs_error_VMerror);
1278
0
                }
1279
1.24M
            }
1280
1281
            /* It must be type 42 (see code in FAPI_FF_get_glyph in zfapi.c). */
1282
31.2k
            else {
1283
                /* Get the length of the TrueType data. */
1284
1285
31.2k
                if (a_font->retrieve_tt_font != NULL) {
1286
31.1k
                    unsigned int ms;
1287
31.1k
                    code = a_font->retrieve_tt_font(a_font, (void **)&own_font_data, &ms);
1288
31.1k
                    if (code == 0) {
1289
31.1k
                        data_owned = false;
1290
31.1k
                        open_args.memory_base = own_font_data;
1291
31.1k
                        open_args.memory_size = own_font_data_len = ms;
1292
31.1k
                    }
1293
31.1k
                }
1294
39
                else
1295
39
                    code = gs_error_unregistered;
1296
1297
31.2k
                if (code < 0) {
1298
39
                    unsigned long lms;
1299
39
                    code = a_font->get_long(a_font, gs_fapi_font_feature_TT_size, 0, &lms);
1300
39
                    if (code < 0)
1301
0
                        return code;
1302
39
                    if (lms == 0)
1303
0
                        return_error(gs_error_invalidfont);
1304
1305
39
                    open_args.memory_size = (FT_Long)lms;
1306
1307
                    /* Load the TrueType data into a single buffer. */
1308
39
                    open_args.memory_base = own_font_data =
1309
39
                        FF_alloc(s->ftmemory, open_args.memory_size);
1310
39
                    if (!own_font_data)
1311
0
                        return_error(gs_error_VMerror);
1312
1313
39
                    own_font_data_len = open_args.memory_size;
1314
1315
39
                    code = a_font->serialize_tt_font(a_font, own_font_data,
1316
39
                                          open_args.memory_size);
1317
39
                    if (code < 0)
1318
34
                        return code;
1319
39
                }
1320
1321
                /* We always load incrementally. */
1322
31.1k
                ft_inc_int = new_inc_int(a_server, a_font);
1323
31.1k
                if (!ft_inc_int) {
1324
0
                    if (data_owned)
1325
0
                        FF_free(s->ftmemory, own_font_data);
1326
0
                    return_error(gs_error_VMerror);
1327
0
                }
1328
31.1k
            }
1329
1330
1.28M
            if (ft_inc_int) {
1331
1.28M
                open_args.flags =
1332
1.28M
                    (FT_UInt) (open_args.flags | FT_OPEN_PARAMS);
1333
1.28M
                ft_param.tag = FT_PARAM_TAG_INCREMENTAL;
1334
1.28M
                ft_param.data = ft_inc_int;
1335
1.28M
                open_args.num_params = 1;
1336
1.28M
                open_args.params = &ft_param;
1337
1.28M
            }
1338
1.28M
            ft_error =
1339
1.28M
                FT_Open_Face(s->freetype_library, &open_args, a_font->subfont,
1340
1.28M
                             &ft_face);
1341
1.28M
            if (ft_error) {
1342
3.17k
                delete_inc_int (a_server, ft_inc_int);
1343
3.17k
                if (data_owned)
1344
56
                    FF_free(s->ftmemory, own_font_data);
1345
3.17k
                return ft_to_gs_error(ft_error);
1346
3.17k
            }
1347
1.28M
        }
1348
1349
1.29M
        if (ft_face) {
1350
1.29M
            face =
1351
1.29M
                new_face(a_server, ft_face, ft_inc_int, ft_strm,
1352
1.29M
                         own_font_data, own_font_data_len, data_owned);
1353
1.29M
            if (!face) {
1354
0
                if (data_owned)
1355
0
                    FF_free(s->ftmemory, own_font_data);
1356
0
                FT_Done_Face(ft_face);
1357
0
                delete_inc_int(a_server, ft_inc_int);
1358
0
                return_error(gs_error_VMerror);
1359
0
            }
1360
1.29M
            a_font->server_font_data = face;
1361
1362
1.29M
            if (!a_font->is_type1) {
1363
124k
                for (i = 0; i < GS_FAPI_NUM_TTF_CMAP_REQ && !cmap; i++) {
1364
88.5k
                    if (a_font->ttf_cmap_req[i].platform_id > 0) {
1365
141k
                        for (j = 0; j < face->ft_face->num_charmaps; j++) {
1366
98.1k
                            if (FT_Get_CMap_Format(face->ft_face->charmaps[j]) >= 0
1367
93.2k
                             && face->ft_face->charmaps[j]->platform_id == a_font->ttf_cmap_req[i].platform_id
1368
36.8k
                             && face->ft_face->charmaps[j]->encoding_id == a_font->ttf_cmap_req[i].encoding_id) {
1369
1370
36.1k
                                cmap = face->ft_face->charmaps[j];
1371
36.1k
                                break;
1372
36.1k
                            }
1373
98.1k
                        }
1374
79.9k
                    }
1375
8.57k
                    else {
1376
8.57k
                        break;
1377
8.57k
                    }
1378
88.5k
                }
1379
44.7k
                if (cmap) {
1380
36.1k
                    (void)FT_Set_Charmap(face->ft_face, cmap);
1381
36.1k
                }
1382
8.57k
                else if (a_font->full_font_buf != NULL || a_font->font_file_path != NULL) {
1383
                    /* If we've passed a complete TTF to Freetype, but *haven't* requested a
1384
                     * specific cmap table above, try to use a Unicode one
1385
                     * If that doesn't work, just leave the default in place.
1386
                     */
1387
5.09k
                    (void)FT_Select_Charmap(face->ft_face, ft_encoding_unicode);
1388
5.09k
                }
1389
                /* For PDF, we have to know which cmap table actually was selected */
1390
44.7k
                if (face->ft_face->charmap != NULL) {
1391
36.8k
                    a_font->ttf_cmap_selected.platform_id = face->ft_face->charmap->platform_id;
1392
36.8k
                    a_font->ttf_cmap_selected.encoding_id = face->ft_face->charmap->encoding_id;
1393
36.8k
                }
1394
7.87k
                else {
1395
                    /* Just in case */
1396
7.87k
                    a_font->ttf_cmap_selected.platform_id = -1;
1397
7.87k
                    a_font->ttf_cmap_selected.encoding_id = -1;
1398
7.87k
                }
1399
44.7k
            }
1400
1.24M
            else {
1401
                /* Just in case */
1402
1.24M
                a_font->ttf_cmap_selected.platform_id = -1;
1403
1.24M
                a_font->ttf_cmap_selected.encoding_id = -1;
1404
1.24M
            }
1405
1.29M
        }
1406
0
        else
1407
0
            a_font->server_font_data = NULL;
1408
1.29M
    }
1409
1410
    /* Set the point size and transformation.
1411
     * The matrix is scaled by the shift specified in the server, 16,
1412
     * so we divide by 65536 when converting to a gs_matrix.
1413
     */
1414
4.26M
    if (face) {
1415
        /* Convert the GS transform into an FT transform.
1416
         * Ignore the translation elements because they contain very large values
1417
         * derived from the current transformation matrix and so are of no use.
1418
         */
1419
4.26M
        face->ft_transform.xx = a_font_scale->matrix[0];
1420
4.26M
        face->ft_transform.xy = a_font_scale->matrix[2];
1421
4.26M
        face->ft_transform.yx = a_font_scale->matrix[1];
1422
4.26M
        face->ft_transform.yy = a_font_scale->matrix[3];
1423
1424
4.26M
        face->horz_res = a_font_scale->HWResolution[0] >> 16;
1425
4.26M
        face->vert_res = a_font_scale->HWResolution[1] >> 16;
1426
1427
        /* Split the transform into scale factors and a rotation-and-shear
1428
         * transform.
1429
         */
1430
4.26M
        transform_decompose(&face->ft_transform, &face->horz_res,
1431
4.26M
                            &face->vert_res, &face->width, &face->height, face->ft_face->units_per_EM);
1432
1433
4.26M
        ft_error = FT_Set_Char_Size(face->ft_face, face->width, face->height,
1434
4.26M
                                    face->horz_res, face->vert_res);
1435
1436
4.26M
        if (ft_error) {
1437
            /* The code originally cleaned up the face data here, but the "top level"
1438
               font object still has references to the face data, and we've no way
1439
               to tell it it's gone. So we defer releasing the data until the garbage
1440
               collector collects the font object, and the font's finalize call will
1441
               free the data correctly for us.
1442
             */
1443
200
            return ft_to_gs_error(ft_error);
1444
200
        }
1445
1446
        /* Concatenate the transform to a reflection around (y=0) so that it
1447
         * produces a glyph that is upside down in FreeType terms, with its
1448
         * first row at the bottom. That is what GhostScript needs.
1449
         */
1450
1451
4.26M
        FT_Set_Transform(face->ft_face, &face->ft_transform, NULL);
1452
1453
4.26M
    }
1454
1455
    /* dpf("gs_fapi_ft_get_scaled_font return %d\n", a_font->server_font_data ? 0 : -1); */
1456
4.26M
    return a_font->server_font_data ? 0 : -1;
1457
4.26M
}
1458
1459
/*
1460
 * Return the name of a resource which maps names to character codes. Do this
1461
 * by setting a_decoding_id to point to a null-terminated string. The resource
1462
 * is in the 'decoding' directory in the directory named by /GenericResourceDir
1463
 * in lib/gs_res.ps.
1464
 */
1465
static gs_fapi_retcode
1466
gs_fapi_ft_get_decodingID(gs_fapi_server * a_server, gs_fapi_font * a_font,
1467
               const char **a_decoding_id)
1468
15.0k
{
1469
15.0k
    *a_decoding_id = "Unicode";
1470
15.0k
    return 0;
1471
15.0k
}
1472
1473
/*
1474
 * Get the font bounding box in font units.
1475
 */
1476
static gs_fapi_retcode
1477
gs_fapi_ft_get_font_bbox(gs_fapi_server * a_server, gs_fapi_font * a_font, int a_box[4], int unitsPerEm[2])
1478
1.13M
{
1479
1.13M
    ff_face *face = (ff_face *) a_font->server_font_data;
1480
1481
1.13M
    a_box[0] = face->ft_face->bbox.xMin;
1482
1.13M
    a_box[1] = face->ft_face->bbox.yMin;
1483
1.13M
    a_box[2] = face->ft_face->bbox.xMax;
1484
1.13M
    a_box[3] = face->ft_face->bbox.yMax;
1485
1486
1.13M
    unitsPerEm[0] = unitsPerEm[1] = face->ft_face->units_per_EM;
1487
1488
1.13M
    return 0;
1489
1.13M
}
1490
1491
/*
1492
 * Return a boolean value in a_proportional stating whether the font is proportional
1493
 * or fixed-width.
1494
 */
1495
static gs_fapi_retcode
1496
gs_fapi_ft_get_font_proportional_feature(gs_fapi_server * a_server,
1497
                              gs_fapi_font * a_font, bool * a_proportional)
1498
0
{
1499
0
    *a_proportional = true;
1500
0
    return 0;
1501
0
}
1502
1503
/* Convert the character name in a_char_ref.char_name to a character code or
1504
 * glyph index and put it in a_char_ref.char_code, setting
1505
 * a_char_ref.is_glyph_index as appropriate. If this is possible set a_result
1506
 * to true, otherwise set it to false.  The return value is a standard error
1507
 * return code.
1508
 */
1509
static gs_fapi_retcode
1510
gs_fapi_ft_can_retrieve_char_by_name(gs_fapi_server * a_server, gs_fapi_font * a_font,
1511
                          gs_fapi_char_ref * a_char_ref, bool * a_result)
1512
0
{
1513
0
    ff_face *face = (ff_face *) a_font->server_font_data;
1514
0
    char name[128];
1515
1516
0
    if (FT_HAS_GLYPH_NAMES(face->ft_face)
1517
0
        && a_char_ref->char_name_length < sizeof(name)) {
1518
0
        memcpy(name, a_char_ref->char_name, a_char_ref->char_name_length);
1519
0
        name[a_char_ref->char_name_length] = 0;
1520
0
        a_char_ref->char_codes[0] = FT_Get_Name_Index(face->ft_face, name);
1521
0
        *a_result = a_char_ref->char_codes[0] != 0;
1522
0
        if (*a_result)
1523
0
            a_char_ref->is_glyph_index = true;
1524
0
    }
1525
0
    else
1526
0
        *a_result = false;
1527
0
    return 0;
1528
0
}
1529
1530
/*
1531
 * Return non-zero if the metrics can be replaced.
1532
 */
1533
static gs_fapi_retcode
1534
gs_fapi_ft_can_replace_metrics(gs_fapi_server * a_server, gs_fapi_font * a_font,
1535
                    gs_fapi_char_ref * a_char_ref, int *a_result)
1536
19.9M
{
1537
    /* Replace metrics only if the metrics are supplied in font units. */
1538
19.9M
    *a_result = 1;
1539
19.9M
    return 0;
1540
19.9M
}
1541
1542
/*
1543
 * Retrieve the metrics of a_char_ref and put them in a_metrics.
1544
 */
1545
static gs_fapi_retcode
1546
gs_fapi_ft_get_char_width(gs_fapi_server * a_server, gs_fapi_font * a_font,
1547
               gs_fapi_char_ref * a_char_ref, gs_fapi_metrics * a_metrics)
1548
0
{
1549
0
    ff_server *s = (ff_server *) a_server;
1550
1551
0
    return load_glyph(a_server, a_font, a_char_ref, a_metrics,
1552
0
                      (FT_Glyph *) & s->outline_glyph,
1553
0
                      false, a_server->max_bitmap);
1554
0
}
1555
1556
static gs_fapi_retcode
1557
gs_fapi_ft_get_fontmatrix(gs_fapi_server * server, gs_matrix * m)
1558
36.7M
{
1559
36.7M
    m->xx = 1.0;
1560
36.7M
    m->xy = 0.0;
1561
36.7M
    m->yx = 0.0;
1562
36.7M
    m->yy = 1.0;
1563
36.7M
    m->tx = 0.0;
1564
36.7M
    m->ty = 0.0;
1565
36.7M
    return 0;
1566
36.7M
}
1567
1568
/*
1569
 * Rasterize the character a_char and return its metrics. Do not return the
1570
 * bitmap but store this. It can be retrieved by a subsequent call to
1571
 * gs_fapi_ft_get_char_raster.
1572
 */
1573
static gs_fapi_retcode
1574
gs_fapi_ft_get_char_raster_metrics(gs_fapi_server * a_server, gs_fapi_font * a_font,
1575
                        gs_fapi_char_ref * a_char_ref,
1576
                        gs_fapi_metrics * a_metrics)
1577
15.0M
{
1578
15.0M
    ff_server *s = (ff_server *) a_server;
1579
15.0M
    gs_fapi_retcode error =
1580
15.0M
        load_glyph(a_server, a_font, a_char_ref, a_metrics,
1581
15.0M
                   (FT_Glyph *) & s->bitmap_glyph, true,
1582
15.0M
                   a_server->max_bitmap);
1583
15.0M
    return error;
1584
15.0M
}
1585
1586
/*
1587
 * Return the bitmap created by the last call to gs_fapi_ft_get_char_raster_metrics.
1588
 */
1589
static gs_fapi_retcode
1590
gs_fapi_ft_get_char_raster(gs_fapi_server * a_server, gs_fapi_raster * a_raster)
1591
18.9M
{
1592
18.9M
    ff_server *s = (ff_server *) a_server;
1593
1594
18.9M
    if (!s->bitmap_glyph)
1595
11.1M
        return(gs_error_unregistered);
1596
7.85M
    a_raster->p = s->bitmap_glyph->bitmap.buffer;
1597
7.85M
    a_raster->width = s->bitmap_glyph->bitmap.width;
1598
7.85M
    a_raster->height = s->bitmap_glyph->bitmap.rows;
1599
7.85M
    a_raster->line_step = s->bitmap_glyph->bitmap.pitch;
1600
7.85M
    a_raster->orig_x = s->bitmap_glyph->left * 16;
1601
7.85M
    a_raster->orig_y = s->bitmap_glyph->top * 16;
1602
7.85M
    a_raster->left_indent = a_raster->top_indent = a_raster->black_height =
1603
7.85M
        a_raster->black_width = 0;
1604
7.85M
    return 0;
1605
18.9M
}
1606
1607
/*
1608
 * Create an outline for the character a_char and return its metrics. Do not
1609
 * return the outline but store this.
1610
 * It can be retrieved by a subsequent call to gs_fapi_ft_get_char_outline.
1611
 */
1612
static gs_fapi_retcode
1613
gs_fapi_ft_get_char_outline_metrics(gs_fapi_server * a_server, gs_fapi_font * a_font,
1614
                         gs_fapi_char_ref * a_char_ref,
1615
                         gs_fapi_metrics * a_metrics)
1616
11.9M
{
1617
11.9M
    ff_server *s = (ff_server *) a_server;
1618
1619
11.9M
    return load_glyph(a_server, a_font, a_char_ref, a_metrics,
1620
11.9M
                      (FT_Glyph *) & s->outline_glyph, false,
1621
11.9M
                      a_server->max_bitmap);
1622
11.9M
}
1623
1624
typedef struct FF_path_info_s
1625
{
1626
    gs_fapi_path *path;
1627
    int64_t x;
1628
    int64_t y;
1629
    FT_Vector currentp;
1630
} FF_path_info;
1631
1632
static inline int
1633
FF_points_equal(const FT_Vector *p1, const FT_Vector *p2)
1634
125M
{
1635
125M
    if (p1->x == p2->x && p1->y == p2->y)
1636
131k
        return 1;
1637
125M
    else
1638
125M
        return 0;
1639
125M
}
1640
1641
static int
1642
move_to(const FT_Vector * aTo, void *aObject)
1643
11.8M
{
1644
11.8M
    FF_path_info *p = (FF_path_info *) aObject;
1645
1646
11.8M
    p->currentp = *aTo;
1647
1648
    /* FAPI expects that co-ordinates will be as implied by frac_shift
1649
     * in our case 16.16 fixed precision. True for 'low level' FT
1650
     * routines (apparently), it isn't true for these routines where
1651
     * FT returns a 26.6 format. Rescale to 16.16 so that FAPI will
1652
     * be able to convert to GS co-ordinates properly.
1653
     */
1654
    /* FAPI now expects these coordinates in 32.32 */
1655
11.8M
    p->x = ((int64_t) aTo->x) << 26;
1656
11.8M
    p->y = ((int64_t) aTo->y) << 26;
1657
1658
11.8M
    return p->path->moveto(p->path, p->x, p->y) ? -1 : 0;
1659
11.8M
}
1660
1661
static int
1662
line_to(const FT_Vector * aTo, void *aObject)
1663
52.1M
{
1664
52.1M
    FF_path_info *p = (FF_path_info *) aObject;
1665
1666
52.1M
    if (!FF_points_equal(&p->currentp, aTo)) {
1667
52.1M
        p->currentp = *aTo;
1668
1669
        /* See move_to() above */
1670
52.1M
        p->x = ((int64_t) aTo->x) << 26;
1671
52.1M
        p->y = ((int64_t) aTo->y) << 26;
1672
1673
52.1M
        return p->path->lineto(p->path, p->x, p->y) ? -1 : 0;
1674
52.1M
    }
1675
74.7k
    return 0;
1676
52.1M
}
1677
1678
static int
1679
conic_to(const FT_Vector * aControl, const FT_Vector * aTo, void *aObject)
1680
16.5M
{
1681
16.5M
    FF_path_info *p = (FF_path_info *) aObject;
1682
16.5M
    double x, y, Controlx, Controly;
1683
16.5M
    int64_t Control1x, Control1y, Control2x, Control2y;
1684
16.5M
    double sx, sy;
1685
1686
16.5M
    if (!FF_points_equal(&p->currentp, aControl) ||
1687
13.1k
        !FF_points_equal(&p->currentp, aTo) ||
1688
16.4M
        !FF_points_equal(aControl, aTo)) {
1689
16.4M
        p->currentp = *aTo;
1690
1691
        /* More complicated than above, we need to do arithmetic on the
1692
         * co-ordinates, so we want them as floats and we will convert the
1693
         * result into 16.16 fixed precision for FAPI
1694
         *
1695
         * NB this code is funcitonally the same as the original, but I don't believe
1696
         * the comment (below) to be what the code is actually doing....
1697
         *
1698
         * NB2: the comment below was wrong, even though the code was correct(!!)
1699
         * The comment has now been amended.
1700
         *
1701
         * Convert a quadratic spline to a cubic. Do this by changing the three points
1702
         * A, B and C to A, 2/3(B,A), 2/3(B,C), C - that is, the two cubic control points are
1703
         * a third of the way from the single quadratic control point to the end points. This
1704
         * gives the same curve as the original quadratic.
1705
         */
1706
1707
16.4M
        sx = (double) (p->x >> 32);
1708
16.4M
        sy = (double) (p->y >> 32);
1709
1710
16.4M
        x = aTo->x / 64.0;
1711
16.4M
        p->x = ((int64_t) float2fixed(x)) << 24;
1712
16.4M
        y = aTo->y / 64.0;
1713
16.4M
        p->y = ((int64_t) float2fixed(y)) << 24;
1714
16.4M
        Controlx = aControl->x / 64.0;
1715
16.4M
        Controly = aControl->y / 64.0;
1716
1717
16.4M
        Control1x = ((int64_t) float2fixed((sx + Controlx * 2) / 3)) << 24;
1718
16.4M
        Control1y = ((int64_t) float2fixed((sy + Controly * 2) / 3)) << 24;
1719
16.4M
        Control2x = ((int64_t) float2fixed((x + Controlx * 2) / 3)) << 24;
1720
16.4M
        Control2y = ((int64_t) float2fixed((y + Controly * 2) / 3)) << 24;
1721
1722
16.4M
        return p->path->curveto(p->path, Control1x,
1723
16.4M
                                Control1y,
1724
16.4M
                                Control2x, Control2y, p->x, p->y) ? -1 : 0;
1725
16.4M
    }
1726
8.01k
    return 0;
1727
16.5M
}
1728
1729
static int
1730
cubic_to(const FT_Vector * aControl1, const FT_Vector * aControl2,
1731
         const FT_Vector * aTo, void *aObject)
1732
56.4M
{
1733
56.4M
    FF_path_info *p = (FF_path_info *) aObject;
1734
56.4M
    int64_t Control1x, Control1y, Control2x, Control2y;
1735
1736
56.4M
    if (!FF_points_equal(&p->currentp, aControl1) ||
1737
11.6k
        !FF_points_equal(&p->currentp, aControl2) ||
1738
4.91k
        !FF_points_equal(&p->currentp, aTo) ||
1739
2.82k
        !FF_points_equal(aControl1, aControl2) ||
1740
2.82k
        !FF_points_equal(aControl1, aTo) ||
1741
56.4M
        !FF_points_equal(aControl2, aTo)) {
1742
56.4M
        p->currentp = *aTo;
1743
1744
        /* See move_to() above */
1745
56.4M
        p->x = ((int64_t) aTo->x) << 26;
1746
56.4M
        p->y = ((int64_t) aTo->y) << 26;
1747
1748
56.4M
        Control1x = ((int64_t) aControl1->x) << 26;
1749
56.4M
        Control1y = ((int64_t) aControl1->y) << 26;
1750
56.4M
        Control2x = ((int64_t) aControl2->x) << 26;
1751
56.4M
        Control2y = ((int64_t) aControl2->y) << 26;
1752
56.4M
        return p->path->curveto(p->path, Control1x, Control1y, Control2x,
1753
56.4M
                                Control2y, p->x, p->y) ? -1 : 0;
1754
56.4M
    }
1755
2.82k
    return 0;
1756
56.4M
}
1757
1758
static const FT_Outline_Funcs TheFtOutlineFuncs = {
1759
    move_to,
1760
    line_to,
1761
    conic_to,
1762
    cubic_to,
1763
    0,
1764
    0
1765
};
1766
1767
/*
1768
 * Return the outline created by the last call to gs_fapi_ft_get_char_outline_metrics.
1769
 */
1770
static gs_fapi_retcode
1771
gs_fapi_ft_get_char_outline(gs_fapi_server * a_server, gs_fapi_path * a_path)
1772
10.4M
{
1773
10.4M
    ff_server *s = (ff_server *) a_server;
1774
10.4M
    FF_path_info p;
1775
10.4M
    FT_Error ft_error = 0;
1776
1777
10.4M
    p.path = a_path;
1778
10.4M
    p.x = 0;
1779
10.4M
    p.y = 0;
1780
    /* If we got an error during glyph creation, we can get
1781
     * here with s->outline_glyph == NULL
1782
     */
1783
10.4M
    if (s->outline_glyph) {
1784
10.4M
        ft_error =
1785
10.4M
            FT_Outline_Decompose(&s->outline_glyph->outline, &TheFtOutlineFuncs,
1786
10.4M
                                 &p);
1787
10.4M
    }
1788
199
    else {
1789
199
        a_path->moveto(a_path, 0, 0);
1790
199
    }
1791
1792
10.4M
    if (a_path->gs_error == 0)
1793
10.1M
        a_path->closepath(a_path);
1794
10.4M
    return ft_to_gs_error(ft_error);
1795
10.4M
}
1796
1797
static gs_fapi_retcode
1798
gs_fapi_ft_release_char_data(gs_fapi_server * a_server)
1799
19.9M
{
1800
19.9M
    ff_server *s = (ff_server *) a_server;
1801
1802
19.9M
    if (s->outline_glyph) {
1803
10.4M
        FT_Outline_Done(s->freetype_library, &s->outline_glyph->outline);
1804
10.4M
        FF_free(s->ftmemory, s->outline_glyph);
1805
10.4M
    }
1806
1807
19.9M
    if (s->bitmap_glyph) {
1808
7.85M
        FT_Bitmap_Done(s->freetype_library, &s->bitmap_glyph->bitmap);
1809
7.85M
        FF_free(s->ftmemory, s->bitmap_glyph);
1810
7.85M
    }
1811
1812
19.9M
    s->outline_glyph = NULL;
1813
19.9M
    s->bitmap_glyph = NULL;
1814
19.9M
    return 0;
1815
19.9M
}
1816
1817
static gs_fapi_retcode
1818
gs_fapi_ft_release_typeface(gs_fapi_server * a_server, void *a_server_font_data)
1819
1.29M
{
1820
1.29M
    ff_face *face = (ff_face *) a_server_font_data;
1821
1822
1.29M
    delete_face(a_server, face);
1823
1.29M
    return 0;
1824
1.29M
}
1825
1826
static gs_fapi_retcode
1827
gs_fapi_ft_check_cmap_for_GID(gs_fapi_server * server, uint * index)
1828
17.3M
{
1829
17.3M
    ff_face *face = (ff_face *) (server->ff.server_font_data);
1830
17.3M
    FT_Face ft_face = face->ft_face;
1831
1832
17.3M
    *index = FT_Get_Char_Index(ft_face, *index);
1833
17.3M
    return 0;
1834
17.3M
}
1835
1836
static gs_fapi_retcode
1837
gs_fapi_ft_set_mm_weight_vector(gs_fapi_server *server, gs_fapi_font *ff, float *wvector, int length)
1838
0
{
1839
#if defined(SHARE_FT) && SHARE_FT == 1 && \
1840
    FREETYPE_MAJOR <= 2 && FREETYPE_MINOR <= 9 && FREETYPE_PATCH <= 1
1841
1842
    return gs_error_invalidaccess;
1843
#else
1844
0
    ff_face *face = (ff_face *) ff->server_font_data;
1845
0
    FT_Fixed nwv[16] = {0};
1846
0
    FT_Fixed cwv[16] = {0};
1847
0
    FT_UInt len = 16;
1848
0
    int i;
1849
0
    bool setit = false;
1850
0
    FT_Error ft_error;
1851
0
    (void)server;
1852
1853
0
    ft_error = FT_Get_MM_WeightVector(face->ft_face, &len, cwv);
1854
0
    if (ft_error != 0) return_error(gs_error_invalidaccess);
1855
1856
0
    for (i = 0; i < length; i++) {
1857
0
        nwv[i] = (FT_Fixed)(wvector[i] * 65536.0);
1858
0
        if (nwv[i] != cwv[i]) {
1859
0
            setit = true;
1860
0
        }
1861
0
    }
1862
1863
0
    if (setit == true) {
1864
0
        ft_error = FT_Set_MM_WeightVector(face->ft_face, length, nwv);
1865
0
        if (ft_error != 0) return_error(gs_error_invalidaccess);
1866
0
    }
1867
1868
0
    return 0;
1869
0
#endif
1870
0
}
1871
1872
static void gs_fapi_freetype_destroy(gs_fapi_server ** serv);
1873
1874
static const gs_fapi_server_descriptor freetypedescriptor = {
1875
    (const char *)"FAPI",
1876
    (const char *)"FreeType",
1877
    gs_fapi_freetype_destroy
1878
};
1879
1880
static const gs_fapi_server freetypeserver = {
1881
    {&freetypedescriptor},
1882
    NULL,                       /* client_ctx_p */
1883
    16,                         /* frac_shift */
1884
    {gs_no_id},
1885
    {0},
1886
    0,
1887
    false,
1888
    false,
1889
    {1, 0, 0, 1, 0, 0},
1890
    1,
1891
    {1, 0, 0, 1, 0, 0},
1892
    gs_fapi_ft_ensure_open,
1893
    gs_fapi_ft_get_scaled_font,
1894
    gs_fapi_ft_get_decodingID,
1895
    gs_fapi_ft_get_font_bbox,
1896
    gs_fapi_ft_get_font_proportional_feature,
1897
    gs_fapi_ft_can_retrieve_char_by_name,
1898
    gs_fapi_ft_can_replace_metrics,
1899
    NULL,                       /* can_simulate_style */
1900
    gs_fapi_ft_get_fontmatrix,
1901
    gs_fapi_ft_get_char_width,
1902
    gs_fapi_ft_get_char_raster_metrics,
1903
    gs_fapi_ft_get_char_raster,
1904
    gs_fapi_ft_get_char_outline_metrics,
1905
    gs_fapi_ft_get_char_outline,
1906
    gs_fapi_ft_release_char_data,
1907
    gs_fapi_ft_release_typeface,
1908
    gs_fapi_ft_check_cmap_for_GID,
1909
    NULL,                        /* get_font_info */
1910
    gs_fapi_ft_set_mm_weight_vector,
1911
};
1912
1913
int gs_fapi_ft_init(gs_memory_t * mem, gs_fapi_server ** server);
1914
1915
int
1916
gs_fapi_ft_init(gs_memory_t * mem, gs_fapi_server ** server)
1917
182k
{
1918
182k
    ff_server *serv;
1919
182k
    int code = 0;
1920
182k
    gs_memory_t *cmem = mem->non_gc_memory;
1921
1922
182k
    code = gs_memory_chunk_wrap(&(cmem), mem);
1923
182k
    if (code != 0) {
1924
0
        return (code);
1925
0
    }
1926
1927
1928
182k
    serv = (ff_server *) gs_alloc_bytes_immovable(cmem, sizeof(ff_server), "gs_fapi_ft_init");
1929
182k
    if (!serv) {
1930
0
        gs_memory_chunk_release(cmem);
1931
0
        return_error(gs_error_VMerror);
1932
0
    }
1933
182k
    memset(serv, 0, sizeof(*serv));
1934
182k
    serv->mem = cmem;
1935
182k
    serv->fapi_server = freetypeserver;
1936
1937
182k
    serv->ftmemory = (FT_Memory) (&(serv->ftmemory_rec));
1938
1939
182k
    (*server) = (gs_fapi_server *) serv;
1940
182k
    return (0);
1941
182k
}
1942
1943
1944
void
1945
gs_fapi_freetype_destroy(gs_fapi_server ** serv)
1946
182k
{
1947
182k
    ff_server *server = (ff_server *) * serv;
1948
182k
    gs_memory_t *cmem = server->mem;
1949
1950
182k
    FT_Done_Glyph(&server->outline_glyph->root);
1951
182k
    FT_Done_Glyph(&server->bitmap_glyph->root);
1952
1953
    /* As with initialization: since we're supplying memory management to
1954
     * FT, we cannot just to use FT_Done_FreeType (), we have to use
1955
     * FT_Done_Library () and then discard the memory ourselves
1956
     */
1957
182k
    FT_Done_Library(server->freetype_library);
1958
182k
    gs_free(cmem, *serv, 0, 0, "gs_fapi_freetype_destroy: ff_server");
1959
    *serv = NULL;
1960
182k
    gs_memory_chunk_release(cmem);
1961
182k
}