Coverage Report

Created: 2026-10-28 08:05

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-2026 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
221M
{
132
221M
    gs_memory_t *mem = (gs_memory_t *) memory->user;
133
134
221M
    return (gs_malloc(mem, size, 1, "FF_alloc"));
135
221M
}
136
137
static void *
138
    FF_realloc(FT_Memory memory, long cur_size, long new_size, void *block)
139
10.2M
{
140
10.2M
    gs_memory_t *mem = (gs_memory_t *) memory->user;
141
10.2M
    void *tmp;
142
143
10.2M
    if (cur_size == new_size) {
144
2.87M
        return (block);
145
2.87M
    }
146
147
7.41M
    tmp = gs_malloc(mem, new_size, 1, "FF_realloc");
148
7.41M
    if (tmp && block) {
149
7.41M
        memcpy(tmp, block, min(cur_size, new_size));
150
151
7.41M
        gs_free(mem, block, 0, 0, "FF_realloc");
152
7.41M
    }
153
154
7.41M
    return (tmp);
155
10.2M
}
156
157
static void
158
    FF_free(FT_Memory memory, void *block)
159
229M
{
160
229M
    gs_memory_t *mem = (gs_memory_t *) memory->user;
161
162
229M
    gs_free(mem, block, 0, 0, "FF_free");
163
229M
}
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
151M
{
174
151M
    stream *ps = (stream *) str->descriptor.pointer;
175
151M
    unsigned int rlen = 0;
176
151M
    int status = 0;
177
178
151M
    if (sseek(ps, (gs_offset_t)offset) < 0)
179
0
        return_error(-1);
180
181
151M
    if (count) {
182
91.9M
        status = sgets(ps, buffer, count, &rlen);
183
184
91.9M
        if (status < 0 && status != EOFC)
185
0
            return_error (-1);
186
91.9M
    }
187
151M
    return (rlen);
188
151M
}
189
190
static void
191
FF_stream_close(FT_Stream str)
192
2.00M
{
193
2.00M
    stream *ps = (stream *) str->descriptor.pointer;
194
2.00M
    gs_memory_t *mem = ps->memory;
195
196
2.00M
    (void)sclose(ps);
197
2.00M
    gs_free_object(mem, ps, "FF_stream_close");
198
2.00M
}
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
2.00M
{
205
2.00M
    int code = 0;
206
2.00M
    gs_parsed_file_name_t pfn;
207
2.00M
    stream *ps = (stream *)NULL;
208
2.00M
    gs_offset_t length;
209
2.00M
    FT_Stream ftstrm = NULL;
210
211
2.00M
    code = gs_parse_file_name(&pfn, (const char *)fname, strlen(fname), mem);
212
2.00M
    if (code < 0) {
213
0
        goto error_out;
214
0
    }
215
216
2.00M
    if (!pfn.fname) {
217
0
        code = gs_error_undefinedfilename;
218
0
        goto error_out;
219
0
    }
220
221
2.00M
    if (pfn.iodev == NULL) {
222
0
        pfn.iodev = iodev_default(mem);
223
0
    }
224
225
2.00M
    if (pfn.iodev) {
226
2.00M
        gx_io_device *const iodev = pfn.iodev;
227
228
2.00M
        iodev_proc_open_file((*open_file)) = iodev->procs.open_file;
229
230
2.00M
        if (open_file) {
231
2.00M
            code = open_file(iodev, pfn.fname, pfn.len, "r", &ps, mem);
232
2.00M
            if (code < 0) {
233
0
                goto error_out;
234
0
            }
235
2.00M
        }
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
2.00M
    }
246
0
    else {
247
0
        goto error_out;
248
0
    }
249
250
2.00M
    if ((code = savailable(ps, &length)) < 0) {
251
0
        goto error_out;
252
0
    }
253
254
2.00M
    ftstrm = gs_malloc(mem, sizeof(FT_StreamRec), 1, "FF_open_read_stream");
255
2.00M
    if (!ftstrm) {
256
0
        code = gs_error_VMerror;
257
0
        goto error_out;
258
0
    }
259
2.00M
    memset(ftstrm, 0x00, sizeof(FT_StreamRec));
260
261
2.00M
    ftstrm->descriptor.pointer = ps;
262
2.00M
    ftstrm->read = FF_stream_read;
263
2.00M
    ftstrm->close = FF_stream_close;
264
2.00M
    ftstrm->size = (long)length;
265
2.00M
    *fts = ftstrm;
266
267
2.00M
  error_out:
268
2.00M
    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
2.00M
    return (code);
275
2.00M
}
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
2.64M
{
283
2.64M
    ff_server *s = (ff_server *) a_server;
284
285
2.64M
    ff_face *face = (ff_face *) FF_alloc(s->ftmemory, sizeof(ff_face));
286
287
2.64M
    if (face) {
288
2.64M
        face->ft_face = a_ft_face;
289
2.64M
        face->ft_inc_int = a_ft_inc_int;
290
2.64M
        face->font_data = a_font_data;
291
2.64M
        face->font_data_len = a_font_data_len;
292
2.64M
        face->data_owned = data_owned;
293
2.64M
        face->ftstrm = ftstrm;
294
2.64M
        face->server = (ff_server *) a_server;
295
2.64M
    }
296
2.64M
    return face;
297
2.64M
}
298
299
static void
300
delete_face(gs_fapi_server * a_server, ff_face * a_face)
301
2.64M
{
302
2.64M
    if (a_face) {
303
2.64M
        ff_server *s = (ff_server *) a_server;
304
2.64M
        if (a_face->ft_inc_int) {
305
623k
            FT_Incremental a_info = a_face->ft_inc_int->object;
306
307
623k
            if (a_info->glyph_data) {
308
371k
                gs_free(s->mem, a_info->glyph_data, 0, 0, "delete_face");
309
371k
            }
310
623k
            a_info->glyph_data = NULL;
311
623k
            a_info->glyph_data_length = 0;
312
623k
            delete_inc_int(a_server, a_face->ft_inc_int);
313
623k
            a_face->ft_inc_int = NULL;
314
623k
        }
315
2.64M
        FT_Done_Face(a_face->ft_face);
316
317
2.64M
        FF_free(s->ftmemory, a_face->ft_inc_int);
318
2.64M
        if (a_face->data_owned)
319
2.62M
            FF_free(s->ftmemory, a_face->font_data);
320
2.64M
        if (a_face->ftstrm) {
321
2.00M
            FF_free(s->ftmemory, a_face->ftstrm);
322
2.00M
        }
323
2.64M
        FF_free(s->ftmemory, a_face);
324
2.64M
    }
325
2.64M
}
326
327
static FT_IncrementalRec *
328
new_inc_int_info(gs_fapi_server * a_server, gs_fapi_font * a_fapi_font)
329
625k
{
330
625k
    ff_server *s = (ff_server *) a_server;
331
332
625k
    FT_IncrementalRec *info =
333
625k
        (FT_IncrementalRec *) FF_alloc(s->ftmemory,
334
625k
                                       sizeof(FT_IncrementalRec));
335
625k
    if (info) {
336
625k
        info->fapi_font = a_fapi_font;
337
625k
        info->glyph_data = NULL;
338
625k
        info->glyph_data_length = 0;
339
625k
        info->glyph_data_in_use = false;
340
625k
        info->glyph_metrics_index = 0xFFFFFFFF;
341
625k
        info->metrics_type = gs_fapi_metrics_notdef;
342
625k
    }
343
625k
    return info;
344
625k
}
345
346
static void
347
delete_inc_int_info(gs_fapi_server * a_server,
348
                    FT_IncrementalRec * a_inc_int_info)
349
625k
{
350
625k
    ff_server *s = (ff_server *) a_server;
351
352
625k
    if (a_inc_int_info) {
353
625k
        FF_free(s->ftmemory, a_inc_int_info->glyph_data);
354
625k
        FF_free(s->ftmemory, a_inc_int_info);
355
625k
    }
356
625k
}
357
358
static FT_Error
359
get_fapi_glyph_data(FT_Incremental a_info, FT_UInt a_index, FT_Data * a_data)
360
11.0M
{
361
11.0M
    gs_fapi_font *ff = a_info->fapi_font;
362
11.0M
    int length = 0;
363
11.0M
    ff_face *face = (ff_face *) ff->server_font_data;
364
11.0M
    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
11.0M
    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
11.0M
    if (a_info->glyph_data_in_use) {
373
28.7k
        unsigned char *buffer = NULL;
374
375
28.7k
        length = ff->get_glyph(ff, a_index, NULL, 0);
376
28.7k
        if (length == gs_fapi_glyph_invalid_format
377
28.7k
            || length == gs_fapi_glyph_invalid_index)
378
0
            return FT_Err_Invalid_Glyph_Index;
379
380
28.7k
        buffer = gs_malloc(mem, length, 1, "get_fapi_glyph_data");
381
28.7k
        if (!buffer)
382
1.25k
            return FT_Err_Out_Of_Memory;
383
384
27.5k
        length = ff->get_glyph(ff, a_index, buffer, length);
385
27.5k
        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
27.5k
        a_data->pointer = buffer;
391
27.5k
    }
392
11.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
11.0M
        const void *saved_char_data = ff->char_data;
398
399
        /* Get as much of the glyph data as possible into the buffer */
400
11.0M
        length =
401
11.0M
            ff->get_glyph(ff, a_index, a_info->glyph_data,
402
11.0M
                          (ushort) a_info->glyph_data_length);
403
11.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
11.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
11.0M
        if (length > a_info->glyph_data_length) {
415
894k
            if (a_info->glyph_data) {
416
521k
                gs_free((gs_memory_t *) mem,
417
521k
                        a_info->glyph_data, 0, 0, "get_fapi_glyph_data");
418
521k
            }
419
420
894k
            a_info->glyph_data =
421
894k
                gs_malloc(mem, length, 1, "get_fapi_glyph_data");
422
423
894k
            if (!a_info->glyph_data) {
424
1.42k
                a_info->glyph_data_length = 0;
425
1.42k
                return FT_Err_Out_Of_Memory;
426
1.42k
            }
427
893k
            a_info->glyph_data_length = length;
428
893k
            ff->char_data = saved_char_data;
429
893k
            length = ff->get_glyph(ff, a_index, a_info->glyph_data, length);
430
893k
            if (length == gs_fapi_glyph_invalid_format)
431
0
                return FT_Err_Unknown_File_Format;
432
893k
            if (length == gs_fapi_glyph_invalid_index)
433
0
                return FT_Err_Invalid_Glyph_Index;
434
893k
        }
435
436
        /* Set the returned pointer and length. */
437
11.0M
        a_data->pointer = a_info->glyph_data;
438
439
11.0M
        a_info->glyph_data_in_use = true;
440
11.0M
    }
441
442
11.0M
    a_data->length = length;
443
11.0M
    return 0;
444
11.0M
}
445
446
static void
447
free_fapi_glyph_data(FT_Incremental a_info, FT_Data * a_data)
448
11.0M
{
449
11.0M
    gs_fapi_font *ff = a_info->fapi_font;
450
11.0M
    ff_face *face = (ff_face *) ff->server_font_data;
451
11.0M
    gs_memory_t *mem = (gs_memory_t *) face->server->mem;
452
453
11.0M
    if (a_data->pointer == (const FT_Byte *)a_info->glyph_data)
454
11.0M
        a_info->glyph_data_in_use = false;
455
27.5k
    else
456
11.0M
        gs_free(mem, (FT_Byte *) a_data->pointer, 0, 0, "free_fapi_glyph_data");
457
11.0M
}
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
11.9M
{
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
11.9M
    if (bVertical && !a_info->fapi_font->is_type1)
469
902k
        a_metrics->advance = 0;
470
471
11.9M
    if (a_info->glyph_metrics_index == a_glyph_index) {
472
484k
        switch (a_info->metrics_type) {
473
484k
            case gs_fapi_metrics_add:
474
484k
                a_metrics->advance += a_info->glyph_metrics.advance;
475
484k
                break;
476
0
            case gs_fapi_metrics_replace_width:
477
0
                a_metrics->advance = a_info->glyph_metrics.advance;
478
0
                break;
479
1
            case gs_fapi_metrics_replace:
480
1
                *a_metrics = a_info->glyph_metrics;
481
                /* We are replacing the horizontal metrics, so the vertical must be 0 */
482
1
                a_metrics->advance_v = 0;
483
1
                break;
484
0
            default:
485
                /* This can't happen. */
486
0
                return FT_Err_Invalid_Argument;
487
484k
        }
488
484k
    }
489
11.9M
    return 0;
490
11.9M
}
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
625k
{
501
625k
    ff_server *s = (ff_server *) a_server;
502
503
625k
    FT_Incremental_InterfaceRec *i =
504
625k
        (FT_Incremental_InterfaceRec *) FF_alloc(s->ftmemory,
505
625k
                                                 sizeof
506
625k
                                                 (FT_Incremental_InterfaceRec));
507
625k
    if (i) {
508
625k
        i->funcs = &TheFAPIIncrementalInterfaceFuncs;
509
625k
        i->object = (FT_Incremental) new_inc_int_info(a_server, a_fapi_font);
510
511
625k
        if (!i->object) {
512
0
            FF_free(s->ftmemory, i);
513
0
            i = NULL;
514
0
        }
515
625k
    }
516
625k
    return i;
517
625k
}
518
519
static void
520
delete_inc_int(gs_fapi_server * a_server,
521
               FT_Incremental_InterfaceRec * a_inc_int)
522
625k
{
523
625k
    ff_server *s = (ff_server *) a_server;
524
525
625k
    if (a_inc_int) {
526
625k
        delete_inc_int_info(a_server, a_inc_int->object);
527
625k
        FF_free(s->ftmemory, a_inc_int);
528
625k
    }
529
625k
}
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
17.1M
{
537
17.1M
    if (a_error) {
538
239k
        if (a_error == FT_Err_Out_Of_Memory)
539
0
            return_error(gs_error_VMerror);
540
239k
        else
541
239k
            return_error(gs_error_unknownerror);
542
239k
    }
543
16.9M
    return 0;
544
17.1M
}
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
15.6M
{
554
15.6M
    ff_server *s = (ff_server *) a_server;
555
15.6M
    FT_Error ft_error = 0;
556
15.6M
    FT_Error ft_error_fb = 1;
557
15.6M
    ff_face *face = (ff_face *) a_fapi_font->server_font_data;
558
15.6M
    FT_Face ft_face = face->ft_face;
559
15.6M
    int index = a_char_ref->char_codes[0];
560
15.6M
    FT_Long w;
561
15.6M
    FT_Long h;
562
15.6M
    FT_Long fflags;
563
15.6M
    FT_Int32 load_flags = 0;
564
15.6M
    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
15.6M
    const void *saved_char_data = a_fapi_font->char_data;
571
15.6M
    const int saved_char_data_len = a_fapi_font->char_data_len;
572
573
15.6M
    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
15.6M
    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
15.6M
    if (!a_char_ref->is_glyph_index) {
585
10.4M
        if (ft_face->num_charmaps)
586
10.4M
            index = FT_Get_Char_Index(ft_face, index);
587
63.0k
        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
63.0k
            if (a_fapi_font->is_type1)
600
0
                index = 0;
601
63.0k
            else
602
63.0k
                index = a_char_ref->char_codes[0];
603
63.0k
        }
604
10.4M
    }
605
5.19M
    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
5.19M
        if (!a_fapi_font->is_cid && !face->ft_inc_int &&
612
3.61M
            (index == 0 ||
613
3.61M
            (a_char_ref->client_char_code != gs_no_char &&
614
3.61M
            FT_Get_Char_Index(ft_face, a_char_ref->client_char_code) <= 0))) {
615
75.0k
            int tmp_ind;
616
617
75.0k
            if ((tmp_ind = FT_Get_Char_Index(ft_face, 32)) > 0) {
618
0
                index = tmp_ind;
619
0
            }
620
75.0k
        }
621
5.19M
    }
622
    /* Refresh the pointer to the FAPI_font held by the incremental interface. */
623
15.6M
    if (face->ft_inc_int)
624
10.9M
        face->ft_inc_int->object->fapi_font = a_fapi_font;
625
626
    /* Store the overriding metrics if they have been supplied. */
627
15.6M
    if (face->ft_inc_int && a_char_ref->metrics_type != gs_fapi_metrics_notdef) {
628
629
485k
        FT_Incremental_MetricsRec *m = &face->ft_inc_int->object->glyph_metrics;
630
631
485k
        m->bearing_x = a_char_ref->sb_x >> 16;
632
485k
        m->bearing_y = a_char_ref->sb_y >> 16;
633
485k
        m->advance = a_char_ref->aw_x >> 16;
634
635
485k
        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
485k
        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
485k
        else {
654
485k
            face->ft_inc_int->object->metrics_type = a_char_ref->metrics_type;
655
485k
        }
656
485k
    }
657
15.1M
    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
10.4M
        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
15.6M
    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
15.6M
        a_fapi_font->char_data = saved_char_data;
667
15.6M
        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
5.62M
            if (a_server->grid_fit == 0) {
673
0
                load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT;
674
0
            }
675
5.62M
            else if (a_server->grid_fit == 2) {
676
0
                load_flags = FT_LOAD_FORCE_AUTOHINT;
677
0
            }
678
5.62M
            load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_NO_BITMAP | FT_LOAD_LINEAR_DESIGN | FT_LOAD_PEDANTIC;
679
5.62M
        }
680
10.0M
        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
10.0M
            load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_LINEAR_DESIGN;
684
10.0M
        }
685
686
15.6M
        ft_error = FT_Load_Glyph(ft_face, index, load_flags);
687
15.6M
        if (ft_error == FT_Err_Unknown_File_Format) {
688
0
            return index + 1;
689
0
        }
690
15.6M
    }
691
692
15.6M
    if (ft_error == FT_Err_Invalid_Argument
693
15.6M
        || ft_error == FT_Err_Invalid_Reference
694
15.5M
        || ft_error == FT_Err_Invalid_Glyph_Index
695
15.5M
        || ft_error == FT_Err_DEF_In_Glyf_Bytecode
696
15.5M
        || (ft_error >= FT_Err_Invalid_Opcode
697
567k
            && ft_error <= FT_Err_Too_Many_Instruction_Defs)) {
698
699
567k
        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
567k
        fflags = ft_face->face_flags;
703
567k
        ft_face->face_flags &= ~FT_FACE_FLAG_TRICKY;
704
567k
        load_flags |= FT_LOAD_NO_HINTING;
705
567k
        ft_error = FT_Load_Glyph(ft_face, index, load_flags);
706
707
567k
        ft_face->face_flags = fflags;
708
567k
    }
709
710
15.6M
    if (ft_error == FT_Err_Out_Of_Memory
711
15.6M
        || ft_error == FT_Err_Array_Too_Large) {
712
1.53k
        return (gs_error_VMerror);
713
1.53k
    }
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
15.6M
    if (ft_error) {
717
157k
        gs_string notdef_str;
718
719
157k
        notdef_str.data = (byte *)".notdef";
720
157k
        notdef_str.size = 7;
721
722
157k
        a_fapi_font->char_data = (void *)(&notdef_str);
723
157k
        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
157k
        fflags = ft_face->face_flags;
727
157k
        ft_face->face_flags &= ~FT_FACE_FLAG_TRICKY;
728
729
157k
        ft_error_fb = FT_Load_Glyph(ft_face, 0, load_flags);
730
731
157k
        ft_face->face_flags = fflags;
732
733
157k
        a_fapi_font->char_data = saved_char_data;
734
157k
        a_fapi_font->char_data_len = saved_char_data_len;
735
157k
    }
736
737
15.6M
    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
15.6M
    if ((!ft_error || !ft_error_fb) && a_metrics) {
745
15.6M
        FT_Long hx;
746
15.6M
        FT_Long hy;
747
15.6M
        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
15.6M
        hx = (FT_Long) (((double)ft_face->glyph->metrics.horiBearingX *
753
15.6M
                         ft_face->units_per_EM * 72.0) /
754
15.6M
                        ((double)face->width * face->horz_res))  + (a_fapi_font->is_mtx_skipped == 1 ? 0 : a_char_ref->sb_x >> 16);
755
15.6M
        hy = (FT_Long) (((double)ft_face->glyph->metrics.horiBearingY *
756
15.6M
                         ft_face->units_per_EM * 72.0) /
757
15.6M
                        ((double)face->height * face->vert_res)) + (a_fapi_font->is_mtx_skipped == 1 ? 0 : a_char_ref->sb_y >> 16);
758
759
15.6M
        w = (FT_Long) (((double)ft_face->glyph->metrics.width *
760
15.6M
                        ft_face->units_per_EM * 72.0) / ((double)face->width *
761
15.6M
                                                         face->horz_res));
762
15.6M
        h = (FT_Long) (((double)ft_face->glyph->metrics.height *
763
15.6M
                        ft_face->units_per_EM * 72.0) /
764
15.6M
                       ((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
15.6M
        if (a_fapi_font->is_type1
772
5.60M
           || ((a_fapi_font->full_font_buf || a_fapi_font->font_file_path)
773
10.0M
           && a_fapi_font->is_vertical &&  FT_HAS_VERTICAL(ft_face))) {
774
775
10.0M
            vadv = ft_face->glyph->linearVertAdvance;
776
10.0M
        }
777
5.60M
        else {
778
5.60M
            vadv = 0;
779
5.60M
        }
780
781
15.6M
        a_metrics->bbox_x0 = hx;
782
15.6M
        a_metrics->bbox_y0 = hy - h;
783
15.6M
        a_metrics->bbox_x1 = a_metrics->bbox_x0 + w;
784
15.6M
        a_metrics->bbox_y1 = a_metrics->bbox_y0 + h;
785
15.6M
        a_metrics->escapement = ft_face->glyph->linearHoriAdvance;
786
15.6M
        a_metrics->v_escapement = vadv;
787
15.6M
        a_metrics->em_x = ft_face->units_per_EM;
788
15.6M
        a_metrics->em_y = ft_face->units_per_EM;
789
15.6M
    }
790
791
15.6M
    if ((!ft_error || !ft_error_fb)) {
792
793
15.6M
        FT_BBox cbox;
794
795
        /* compute the control box, and grid fit it - lifted from ft_raster1_render() */
796
15.6M
        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
15.6M
        cbox.xMin = ((cbox.xMin) & ~63);        /* FT_PIX_FLOOR( cbox.xMin ) */
803
15.6M
        cbox.yMin = ((cbox.yMin) & ~63);
804
15.6M
        cbox.xMax = (((cbox.xMax) + 63) & ~63);
805
15.6M
        cbox.yMax = (((cbox.yMax) + 63) & ~63); /* FT_PIX_CEIL( cbox.yMax ) */
806
807
15.6M
        w = (FT_UInt) ((cbox.xMax - cbox.xMin) >> 6);
808
15.6M
        h = (FT_UInt) ((cbox.yMax - cbox.yMin) >> 6);
809
810
15.6M
        if (!a_fapi_font->metrics_only && a_bitmap == true && ft_face->glyph->format != FT_GLYPH_FORMAT_BITMAP
811
8.69M
            && ft_face->glyph->format != FT_GLYPH_FORMAT_COMPOSITE) {
812
8.69M
            if ((bitmap_raster(w) * h) < max_bitmap) {
813
5.78M
                FT_Render_Mode mode = FT_RENDER_MODE_MONO;
814
5.78M
                FT_UInt save_x_ppem = ft_face->glyph->face->size->metrics.x_ppem;
815
5.78M
                FT_UInt save_y_ppem = ft_face->glyph->face->size->metrics.y_ppem;
816
817
                /* Workaround so we have more control over size of the glyph that freetype will render for us */
818
5.78M
                if (a_fapi_font->is_type1) {
819
3.58M
                    ft_face->glyph->face->size->metrics.x_ppem = ft_face->glyph->face->size->metrics.y_ppem = 1000;
820
3.58M
                }
821
2.20M
                else {
822
2.20M
                    ft_face->glyph->face->size->metrics.x_ppem = ft_face->glyph->face->size->metrics.y_ppem = 2048;
823
2.20M
                }
824
5.78M
                ft_error = FT_Render_Glyph(ft_face->glyph, mode);
825
826
5.78M
                ft_face->glyph->face->size->metrics.x_ppem = save_x_ppem;
827
5.78M
                ft_face->glyph->face->size->metrics.y_ppem = save_y_ppem;
828
829
5.78M
                if (ft_error != 0) {
830
96
                    (*a_glyph) = NULL;
831
96
                    return (gs_error_VMerror);
832
96
                }
833
5.78M
            }
834
2.91M
            else {
835
2.91M
                (*a_glyph) = NULL;
836
2.91M
                return (gs_error_VMerror);
837
2.91M
            }
838
8.69M
        }
839
15.6M
    }
840
841
12.7M
    if (!a_fapi_font->metrics_only) {
842
        /* The following works around the fact that at the scales we deal with
843
         * these values may not fit in a 16.16 fixed point value, and thus cause
844
         * freetype to error due to overflow - but we don't use these values
845
         * and neither does freetype, we can set them to zero and avoid the error
846
         */
847
10.1M
        ft_face->glyph->advance.x = ft_face->glyph->advance.y = 0;
848
10.1M
        if ((!ft_error || !ft_error_fb) && a_glyph) {
849
10.1M
            ft_error = FT_Get_Glyph(ft_face->glyph, a_glyph);
850
10.1M
        }
851
10.9k
        else {
852
10.9k
            if (ft_face->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
853
0
                FT_BitmapGlyph bmg;
854
855
0
                ft_error = FT_Get_Glyph(ft_face->glyph, (FT_Glyph *) & bmg);
856
0
                if (!ft_error) {
857
0
                    FT_Bitmap_Done(s->freetype_library, &bmg->bitmap);
858
0
                    FF_free(s->ftmemory, bmg);
859
0
                }
860
0
            }
861
10.9k
            else if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
862
0
                FT_OutlineGlyph olg;
863
864
0
                ft_error = FT_Get_Glyph(ft_face->glyph, (FT_Glyph *) & olg);
865
0
                if (!ft_error) {
866
0
                    FT_Outline_Done(s->freetype_library, &olg->outline);
867
0
                    FF_free(s->ftmemory, olg);
868
0
                }
869
0
            }
870
10.9k
        }
871
10.1M
    }
872
873
12.7M
    if (ft_error == FT_Err_Too_Many_Hints) {
874
#ifdef DEBUG
875
        if (gs_debug_c('1')) {
876
            ft_emprintf1(a_fapi_font->memory,
877
                      "TrueType glyph %"PRId64" uses more instructions than the declared maximum in the font.",
878
                      a_char_ref->char_codes[0]);
879
880
            if (!ft_error_fb) {
881
                ft_emprintf(a_fapi_font->memory,
882
                         " Continuing, falling back to notdef\n\n");
883
            }
884
        }
885
#endif
886
253
        if (!ft_error_fb)
887
0
            ft_error = 0;
888
253
    }
889
12.7M
    if (ft_error == FT_Err_Invalid_Argument) {
890
#ifdef DEBUG
891
        if (gs_debug_c('1')) {
892
            ft_emprintf1(a_fapi_font->memory,
893
                      "TrueType parsing error in glyph %"PRId64" in the font.",
894
                      a_char_ref->char_codes[0]);
895
896
            if (!ft_error_fb) {
897
                ft_emprintf(a_fapi_font->memory,
898
                         " Continuing, falling back to notdef\n\n");
899
            }
900
        }
901
#endif
902
3.37k
        if (!ft_error_fb)
903
0
            ft_error = 0;
904
3.37k
    }
905
12.7M
    if (ft_error == FT_Err_Too_Many_Function_Defs) {
906
#ifdef DEBUG
907
        if (gs_debug_c('1')) {
908
            ft_emprintf1(a_fapi_font->memory,
909
                      "TrueType instruction error in glyph %"PRId64" in the font.",
910
                      a_char_ref->char_codes[0]);
911
912
            if (!ft_error_fb) {
913
                ft_emprintf(a_fapi_font->memory,
914
                         " Continuing, falling back to notdef\n\n");
915
            }
916
        }
917
#endif
918
0
        if (!ft_error_fb)
919
0
            ft_error = 0;
920
0
    }
921
12.7M
    if (ft_error == FT_Err_Invalid_Glyph_Index) {
922
#ifdef DEBUG
923
        if (gs_debug_c('1')) {
924
            ft_emprintf1(a_fapi_font->memory,
925
                      "FreeType is unable to find the glyph %"PRId64" in the font.",
926
                      a_char_ref->char_codes[0]);
927
928
            if (!ft_error_fb) {
929
                ft_emprintf(a_fapi_font->memory,
930
                         " Continuing, falling back to notdef\n\n");
931
            }
932
        }
933
#endif
934
0
        if (!ft_error_fb)
935
0
            ft_error = 0;
936
0
    }
937
12.7M
    return ft_to_gs_error(ft_error);
938
15.6M
}
939
940
/*
941
 * Ensure that the rasterizer is open.
942
 *
943
 * In the case of FreeType this means creating the FreeType library object.
944
 */
945
static gs_fapi_retcode
946
gs_fapi_ft_ensure_open(gs_fapi_server * a_server, const char * server_param,
947
                       int server_param_size)
948
2.64M
{
949
2.64M
    ff_server *s = (ff_server *) a_server;
950
2.64M
    FT_UInt tt_ins_version = TT_INTERPRETER_VERSION_35;
951
2.64M
    FT_Error ft_error;
952
953
2.64M
    if (s->freetype_library)
954
2.57M
        return 0;
955
956
    /* As we want FT to use our memory management, we cannot use the convenience of
957
     * FT_Init_FreeType(), we have to do each stage "manually"
958
     */
959
72.1k
    s->ftmemory->user = s->mem;
960
72.1k
    s->ftmemory->alloc = FF_alloc;
961
72.1k
    s->ftmemory->free = FF_free;
962
72.1k
    s->ftmemory->realloc = FF_realloc;
963
964
72.1k
    ft_error = FT_New_Library(s->ftmemory, &s->freetype_library);
965
72.1k
    if (ft_error)
966
0
        return ft_to_gs_error(ft_error);
967
968
72.1k
    FT_Add_Default_Modules(s->freetype_library);
969
72.1k
    FT_Property_Set( s->freetype_library, "truetype", "interpreter-version", &tt_ins_version);
970
971
72.1k
    return 0;
972
72.1k
}
973
974
#if 0                           /* Not currently used */
975
static void
976
transform_concat(FT_Matrix * a_A, const FT_Matrix * a_B)
977
{
978
    FT_Matrix result = *a_B;
979
980
    FT_Matrix_Multiply(a_A, &result);
981
    *a_A = result;
982
}
983
984
/* Create a transform representing an angle defined as a vector. */
985
static void
986
make_rotation(FT_Matrix * a_transform, const FT_Vector * a_vector)
987
{
988
    FT_Fixed length, cos, sin;
989
990
    if (a_vector->x >= 0 && a_vector->y == 0) {
991
        a_transform->xx = a_transform->yy = 65536;
992
        a_transform->xy = a_transform->yx = 0;
993
        return;
994
    }
995
996
    length = FT_Vector_Length((FT_Vector *) a_vector);
997
    cos = FT_DivFix(a_vector->x, length);
998
    sin = FT_DivFix(a_vector->y, length);
999
    a_transform->xx = a_transform->yy = cos;
1000
    a_transform->xy = -sin;
1001
    a_transform->yx = sin;
1002
}
1003
#endif /* Not currently used */
1004
1005
/* Divide a transformation into a scaling part and a rotation-and-shear part.
1006
 * The scaling part is used for setting the pixel size for hinting.
1007
 */
1008
static void
1009
transform_decompose(FT_Matrix * a_transform, FT_UInt * xresp, FT_UInt * yresp,
1010
                    FT_Fixed * a_x_scale, FT_Fixed * a_y_scale, int units_per_EM)
1011
9.04M
{
1012
9.04M
    double scalex, scaley, fact = 1.0;
1013
9.04M
    double factx = 1.0, facty = 1.0;
1014
9.04M
    FT_Matrix ftscale_mat;
1015
9.04M
    FT_UInt xres;
1016
9.04M
    FT_UInt yres;
1017
    /* We have to account for units_per_EM as we fiddle with the scaling
1018
     * in order to avoid underflow (mostly in the TTF hinting code), but
1019
     * we also want to clamp to a lower value (512, admittedly arrived at
1020
     * via experimentation) in order to preserve the fidelity of the outlines.
1021
     */
1022
9.04M
    double upe = units_per_EM > 512 ? (float)units_per_EM : 512.0;
1023
1024
9.04M
    scalex = hypot((double)a_transform->xx, (double)a_transform->xy);
1025
9.04M
    scaley = hypot((double)a_transform->yx, (double)a_transform->yy);
1026
1027
    /* In addition to all the wrangling below, we have to make sure that
1028
     * that the contents of a_transform can also be understood by Freetype.
1029
     */
1030
9.04M
    if (scalex < 64.0 || scaley < 64.0) {
1031
5.84k
        factx = 64.0/scalex;
1032
5.84k
        facty = 64.0/scaley;
1033
1034
5.84k
        ftscale_mat.xx = (FT_Fixed)(a_transform->xx * factx);
1035
5.84k
        ftscale_mat.xy = (FT_Fixed)(a_transform->xy * facty);
1036
5.84k
        ftscale_mat.yx = (FT_Fixed)(a_transform->yx * factx);
1037
5.84k
        ftscale_mat.yy = (FT_Fixed)(a_transform->yy * facty);
1038
5.84k
        memcpy(a_transform, &ftscale_mat, sizeof(ftscale_mat));
1039
5.84k
        scalex = hypot((double)a_transform->xx, (double)a_transform->xy);
1040
5.84k
        scaley = hypot((double)a_transform->yx, (double)a_transform->yy);
1041
5.84k
    }
1042
1043
9.04M
    if (*xresp != *yresp) {
1044
        /* To get good results, we have to pull the implicit scaling from
1045
         * non-square resolutions, and apply it in the matrix. This means
1046
         * we get the correct "shearing" effect for rotated glyphs.
1047
         * The previous solution was only effective for for glyphs whose
1048
         * axes were coincident with the axes of the page.
1049
         */
1050
0
        bool use_x = true;
1051
1052
0
        if (*xresp < *yresp) {
1053
0
            use_x = false;
1054
0
        }
1055
1056
0
        ftscale_mat.xx =
1057
0
            (int)(((double)(*xresp) /
1058
0
                   ((double)(use_x ? (*xresp) : (*yresp)))) * 65536);
1059
0
        ftscale_mat.xy = ftscale_mat.yx = 0;
1060
0
        ftscale_mat.yy =
1061
0
            (int)(((double)(*yresp) /
1062
0
                   ((double)(use_x ? (*xresp) : (*yresp)))) * 65536);
1063
1064
0
        FT_Matrix_Multiply(&ftscale_mat, a_transform);
1065
1066
0
        xres = yres = (use_x ? (*xresp) : (*yresp));
1067
0
        xres = (FT_UInt)(xres / factx);
1068
0
        yres = (FT_UInt)(yres / facty);
1069
0
    }
1070
9.04M
    else {
1071
        /* Life is considerably easier when square resolutions are in use! */
1072
9.04M
        xres = (FT_UInt)(*xresp / factx);
1073
9.04M
        yres = (FT_UInt)(*yresp / facty);
1074
9.04M
    }
1075
1076
9.04M
    scalex *= 1.0 / 65536.0;
1077
9.04M
    scaley *= 1.0 / 65536.0;
1078
1079
9.04M
    if (scalex < scaley) {
1080
89.4k
        scaley = scalex;
1081
89.4k
    }
1082
8.95M
    else if (scalex > scaley) {
1083
49.5k
        scalex = scaley;
1084
49.5k
    }
1085
1086
    /* FT clamps the width and height to a lower limit of 1.0 units
1087
     * (note: as FT stores it in 64ths of a unit, that is 64)
1088
     * So if either the width or the height are <1.0 here, we scale
1089
     * the width and height appropriately, and then compensate using
1090
     * the "final" matrix for FT
1091
     */
1092
    /* We use 1 1/64th to calculate the scale, so that we *guarantee* the
1093
     * scalex/y we calculate will be >64 after rounding.
1094
     */
1095
1096
9.04M
    if (scalex < 1.0) {
1097
554k
        fact = 1.016 / scalex;
1098
554k
        scalex = scalex * fact;
1099
554k
        scaley = scaley * fact;
1100
554k
    }
1101
1102
    /* see above */
1103
9.04M
    if (scalex * xres < 2268.0 / 64.0) {
1104
3.11k
        fact = (2400.0 / 64.0) / (xres * scalex);
1105
3.11k
        scaley *= fact;
1106
3.11k
        scalex *= fact;
1107
3.11k
    }
1108
1109
    /* see above */
1110
9.04M
    fact = 1.0;
1111
12.8M
    while (scaley * yres > (double)upe * 72.0 && (xres > 0 && yres > 0)
1112
3.80M
           && (scalex > 0.0 && scaley > 0.0)) {
1113
3.80M
        if (scaley < yres) {
1114
2.36k
            xres >>= 1;
1115
2.36k
            yres >>= 1;
1116
2.36k
            fact *= 2.0;
1117
2.36k
        }
1118
3.80M
        else {
1119
3.80M
            scalex /= 1.25;
1120
3.80M
            scaley /= 1.25;
1121
3.80M
        }
1122
3.80M
    }
1123
1124
9.04M
    ftscale_mat.xx = (FT_Fixed) ((65536.0 / scalex) * fact);
1125
9.04M
    ftscale_mat.xy = 0;
1126
9.04M
    ftscale_mat.yx = 0;
1127
9.04M
    ftscale_mat.yy = (FT_Fixed) ((65536.0 / scaley) * fact);
1128
1129
9.04M
    FT_Matrix_Multiply(a_transform, &ftscale_mat);
1130
9.04M
    memcpy(a_transform, &ftscale_mat, sizeof(FT_Matrix));
1131
1132
9.04M
    *xresp = xres;
1133
9.04M
    *yresp = yres;
1134
    /* Return values ready scaled for FT */
1135
9.04M
    *a_x_scale = (FT_Fixed) (scalex * 64);
1136
9.04M
    *a_y_scale = (FT_Fixed) (scaley * 64);
1137
9.04M
}
1138
1139
/*
1140
 * Open a font and set its size.
1141
 */
1142
static gs_fapi_retcode
1143
gs_fapi_ft_get_scaled_font(gs_fapi_server * a_server, gs_fapi_font * a_font,
1144
                const gs_fapi_font_scale * a_font_scale,
1145
                const char *a_map, gs_fapi_descendant_code a_descendant_code)
1146
9.04M
{
1147
9.04M
    ff_server *s = (ff_server *) a_server;
1148
9.04M
    ff_face *face = (ff_face *) a_font->server_font_data;
1149
9.04M
    FT_Error ft_error = 0;
1150
9.04M
    int i, j, code;
1151
9.04M
    FT_CharMap cmap = NULL;
1152
9.04M
    bool data_owned = true;
1153
1154
9.04M
    if (s->bitmap_glyph) {
1155
0
        FT_Bitmap_Done(s->freetype_library, &s->bitmap_glyph->bitmap);
1156
0
        FF_free(s->ftmemory, s->bitmap_glyph);
1157
0
        s->bitmap_glyph = NULL;
1158
0
    }
1159
9.04M
    if (s->outline_glyph) {
1160
0
        FT_Outline_Done(s->freetype_library, &s->outline_glyph->outline);
1161
0
        FF_free(s->ftmemory, s->outline_glyph);
1162
0
        s->outline_glyph = NULL;
1163
0
    }
1164
1165
    /* dpf("gs_fapi_ft_get_scaled_font enter: is_type1=%d is_cid=%d font_file_path='%s' a_descendant_code=%d\n",
1166
       a_font->is_type1, a_font->is_cid, a_font->font_file_path ? a_font->font_file_path : "", a_descendant_code); */
1167
1168
    /* If this font is the top level font of an embedded CID type 0 font (font type 9)
1169
     * do nothing. See the comment in FAPI_prepare_font. The descendant fonts are
1170
     * passed in individually.
1171
     */
1172
9.04M
    if (a_font->is_cid && a_font->is_type1 && a_font->font_file_path == NULL
1173
6.44k
        && (a_descendant_code == gs_fapi_toplevel_begin
1174
4.91k
            || a_descendant_code == gs_fapi_toplevel_complete)) {
1175
        /* dpf("gs_fapi_ft_get_scaled_font return 0\n"); */
1176
3.02k
        return 0;
1177
3.02k
    }
1178
1179
    /* Create the face if it doesn't already exist. */
1180
9.04M
    if (!face) {
1181
2.64M
        FT_Face ft_face = NULL;
1182
2.64M
        FT_Parameter ft_param;
1183
2.64M
        FT_Incremental_InterfaceRec *ft_inc_int = NULL;
1184
2.64M
        unsigned char *own_font_data = NULL;
1185
2.64M
        int own_font_data_len = -1;
1186
2.64M
        FT_Stream ft_strm = NULL;
1187
1188
        /* dpf("gs_fapi_ft_get_scaled_font creating face\n"); */
1189
1190
2.64M
        if (a_font->full_font_buf) {
1191
1192
12.6k
            own_font_data =
1193
12.6k
                gs_malloc(((gs_memory_t *) (s->ftmemory->user)),
1194
12.6k
                          a_font->full_font_buf_len, 1,
1195
12.6k
                          "gs_fapi_ft_get_scaled_font - full font buf");
1196
12.6k
            if (!own_font_data) {
1197
0
                return_error(gs_error_VMerror);
1198
0
            }
1199
1200
12.6k
            own_font_data_len = a_font->full_font_buf_len;
1201
12.6k
            memcpy(own_font_data, a_font->full_font_buf,
1202
12.6k
                   a_font->full_font_buf_len);
1203
1204
12.6k
            ft_error =
1205
12.6k
                FT_New_Memory_Face(s->freetype_library,
1206
12.6k
                                   (const FT_Byte *)own_font_data,
1207
12.6k
                                   own_font_data_len, a_font->subfont,
1208
12.6k
                                   &ft_face);
1209
1210
12.6k
            if (ft_error) {
1211
870
                gs_memory_t *mem = (gs_memory_t *) s->ftmemory->user;
1212
870
                gs_free(mem, own_font_data, 0, 0, "gs_fapi_ft_get_scaled_font");
1213
870
                return ft_to_gs_error(ft_error);
1214
870
            }
1215
12.6k
        }
1216
        /* Load a typeface from a file. */
1217
2.63M
        else if (a_font->font_file_path) {
1218
2.00M
            FT_Open_Args args;
1219
1220
2.00M
            memset(&args, 0x00, sizeof(args));
1221
1222
2.00M
            if ((code =
1223
2.00M
                 FF_open_read_stream((gs_memory_t *) (s->ftmemory->user),
1224
2.00M
                                     (char *)a_font->font_file_path,
1225
2.00M
                                     &ft_strm)) < 0) {
1226
0
                return (code);
1227
0
            }
1228
1229
2.00M
            args.flags = FT_OPEN_STREAM;
1230
2.00M
            args.stream = ft_strm;
1231
1232
2.00M
            ft_error =
1233
2.00M
                FT_Open_Face(s->freetype_library, &args, a_font->subfont,
1234
2.00M
                             &ft_face);
1235
2.00M
            if (ft_error) {
1236
                /* in the event of an error, Freetype should cleanup the stream */
1237
                /* But not the ft container */
1238
0
                gs_memory_t *mem = (gs_memory_t *) s->ftmemory->user;
1239
0
                gs_free(mem, ft_strm, 0, 0, "gs_fapi_ft_get_scaled_font");
1240
0
                return ft_to_gs_error(ft_error);
1241
0
            }
1242
2.00M
        }
1243
1244
        /* Load a typeface from a representation in GhostScript's memory. */
1245
625k
        else {
1246
625k
            FT_Open_Args open_args;
1247
1248
625k
            open_args.flags = FT_OPEN_MEMORY;
1249
625k
            open_args.stream = NULL;
1250
1251
625k
            if (a_font->is_type1) {
1252
603k
                long length;
1253
603k
                unsigned short type = 0;
1254
1255
603k
                code = a_font->get_word(a_font, gs_fapi_font_feature_FontType, 0, &type);
1256
603k
                if (code < 0) {
1257
0
                    return code;
1258
0
                }
1259
1260
                /* Tell the FAPI interface that we need to decrypt the /Subrs data. */
1261
603k
                a_font->need_decrypt = true;
1262
1263
                /*
1264
                   Serialise a type 1 font in PostScript source form, or
1265
                   a Type 2 font in binary form, so that FreeType can read it.
1266
                 */
1267
603k
                if (type == 1)
1268
593k
                    length = gs_fapi_serialize_type1_font(a_font, NULL, 0);
1269
10.3k
                else
1270
10.3k
                    length = gs_fapi_serialize_type2_font(a_font, NULL, 0);
1271
1272
603k
                open_args.memory_base = own_font_data =
1273
603k
                    FF_alloc(s->ftmemory, length);
1274
603k
                if (!open_args.memory_base)
1275
62
                    return_error(gs_error_VMerror);
1276
603k
                own_font_data_len = length;
1277
603k
                if (type == 1)
1278
593k
                    open_args.memory_size =
1279
593k
                        gs_fapi_serialize_type1_font(a_font, own_font_data, length);
1280
10.2k
                else
1281
10.2k
                    open_args.memory_size =
1282
10.2k
                        gs_fapi_serialize_type2_font(a_font, own_font_data, length);
1283
1284
603k
                if (open_args.memory_size != length)
1285
0
                    return_error(gs_error_unregistered);        /* Must not happen. */
1286
1287
603k
                ft_inc_int = new_inc_int(a_server, a_font);
1288
603k
                if (!ft_inc_int) {
1289
0
                    FF_free(s->ftmemory, own_font_data);
1290
0
                    return_error(gs_error_VMerror);
1291
0
                }
1292
603k
            }
1293
1294
            /* It must be type 42 (see code in FAPI_FF_get_glyph in zfapi.c). */
1295
21.6k
            else {
1296
                /* Get the length of the TrueType data. */
1297
1298
21.6k
                if (a_font->retrieve_tt_font != NULL) {
1299
21.4k
                    unsigned int ms;
1300
21.4k
                    code = a_font->retrieve_tt_font(a_font, (void **)&own_font_data, &ms);
1301
21.4k
                    if (code == 0) {
1302
21.4k
                        data_owned = false;
1303
21.4k
                        open_args.memory_base = own_font_data;
1304
21.4k
                        open_args.memory_size = own_font_data_len = ms;
1305
21.4k
                    }
1306
21.4k
                }
1307
163
                else
1308
163
                    code = gs_error_unregistered;
1309
1310
21.6k
                if (code < 0) {
1311
163
                    unsigned long lms;
1312
163
                    code = a_font->get_long(a_font, gs_fapi_font_feature_TT_size, 0, &lms);
1313
163
                    if (code < 0)
1314
0
                        return code;
1315
163
                    if (lms == 0)
1316
0
                        return_error(gs_error_invalidfont);
1317
1318
163
                    open_args.memory_size = (FT_Long)lms;
1319
1320
                    /* Load the TrueType data into a single buffer. */
1321
163
                    open_args.memory_base = own_font_data =
1322
163
                        FF_alloc(s->ftmemory, open_args.memory_size);
1323
163
                    if (!own_font_data)
1324
0
                        return_error(gs_error_VMerror);
1325
1326
163
                    own_font_data_len = open_args.memory_size;
1327
1328
163
                    code = a_font->serialize_tt_font(a_font, own_font_data,
1329
163
                                          open_args.memory_size);
1330
163
                    if (code < 0) {
1331
28
                        FF_free(s->ftmemory, own_font_data);
1332
28
                        return code;
1333
28
                    }
1334
163
                }
1335
1336
                /* We always load incrementally. */
1337
21.5k
                ft_inc_int = new_inc_int(a_server, a_font);
1338
21.5k
                if (!ft_inc_int) {
1339
0
                    if (data_owned)
1340
0
                        FF_free(s->ftmemory, own_font_data);
1341
0
                    return_error(gs_error_VMerror);
1342
0
                }
1343
21.5k
            }
1344
1345
625k
            if (ft_inc_int) {
1346
625k
                open_args.flags =
1347
625k
                    (FT_UInt) (open_args.flags | FT_OPEN_PARAMS);
1348
625k
                ft_param.tag = FT_PARAM_TAG_INCREMENTAL;
1349
625k
                ft_param.data = ft_inc_int;
1350
625k
                open_args.num_params = 1;
1351
625k
                open_args.params = &ft_param;
1352
625k
            }
1353
625k
            ft_error =
1354
625k
                FT_Open_Face(s->freetype_library, &open_args, a_font->subfont,
1355
625k
                             &ft_face);
1356
625k
            if (ft_error) {
1357
2.12k
                delete_inc_int (a_server, ft_inc_int);
1358
2.12k
                if (data_owned)
1359
72
                    FF_free(s->ftmemory, own_font_data);
1360
2.12k
                return ft_to_gs_error(ft_error);
1361
2.12k
            }
1362
625k
        }
1363
1364
2.64M
        if (ft_face) {
1365
2.64M
            face =
1366
2.64M
                new_face(a_server, ft_face, ft_inc_int, ft_strm,
1367
2.64M
                         own_font_data, own_font_data_len, data_owned);
1368
2.64M
            if (!face) {
1369
0
                if (data_owned)
1370
0
                    FF_free(s->ftmemory, own_font_data);
1371
0
                FT_Done_Face(ft_face);
1372
0
                delete_inc_int(a_server, ft_inc_int);
1373
0
                return_error(gs_error_VMerror);
1374
0
            }
1375
2.64M
            a_font->server_font_data = face;
1376
1377
2.64M
            if (!a_font->is_type1) {
1378
6.10M
                for (i = 0; i < GS_FAPI_NUM_TTF_CMAP_REQ && !cmap; i++) {
1379
4.13M
                    if (a_font->ttf_cmap_req[i].platform_id > 0) {
1380
13.9M
                        for (j = 0; j < face->ft_face->num_charmaps; j++) {
1381
11.9M
                            if (FT_Get_CMap_Format(face->ft_face->charmaps[j]) >= 0
1382
11.9M
                             && face->ft_face->charmaps[j]->platform_id == a_font->ttf_cmap_req[i].platform_id
1383
4.03M
                             && face->ft_face->charmaps[j]->encoding_id == a_font->ttf_cmap_req[i].encoding_id) {
1384
1385
1.97M
                                cmap = face->ft_face->charmaps[j];
1386
1.97M
                                break;
1387
1.97M
                            }
1388
11.9M
                        }
1389
4.06M
                    }
1390
64.9k
                    else {
1391
64.9k
                        break;
1392
64.9k
                    }
1393
4.13M
                }
1394
2.03M
                if (cmap) {
1395
1.97M
                    (void)FT_Set_Charmap(face->ft_face, cmap);
1396
1.97M
                }
1397
64.9k
                else if (a_font->full_font_buf != NULL || a_font->font_file_path != NULL) {
1398
                    /* If we've passed a complete TTF to Freetype, but *haven't* requested a
1399
                     * specific cmap table above, try to use a Unicode one
1400
                     * If that doesn't work, just leave the default in place.
1401
                     */
1402
62.4k
                    (void)FT_Select_Charmap(face->ft_face, ft_encoding_unicode);
1403
62.4k
                }
1404
                /* For PDF, we have to know which cmap table actually was selected */
1405
2.03M
                if (face->ft_face->charmap != NULL) {
1406
1.97M
                    a_font->ttf_cmap_selected.platform_id = face->ft_face->charmap->platform_id;
1407
1.97M
                    a_font->ttf_cmap_selected.encoding_id = face->ft_face->charmap->encoding_id;
1408
1.97M
                }
1409
64.3k
                else {
1410
                    /* Just in case */
1411
64.3k
                    a_font->ttf_cmap_selected.platform_id = -1;
1412
64.3k
                    a_font->ttf_cmap_selected.encoding_id = -1;
1413
64.3k
                }
1414
2.03M
            }
1415
603k
            else {
1416
                /* Just in case */
1417
603k
                a_font->ttf_cmap_selected.platform_id = -1;
1418
603k
                a_font->ttf_cmap_selected.encoding_id = -1;
1419
603k
            }
1420
2.64M
        }
1421
0
        else
1422
0
            a_font->server_font_data = NULL;
1423
2.64M
    }
1424
1425
    /* Set the point size and transformation.
1426
     * The matrix is scaled by the shift specified in the server, 16,
1427
     * so we divide by 65536 when converting to a gs_matrix.
1428
     */
1429
9.04M
    if (face) {
1430
        /* Convert the GS transform into an FT transform.
1431
         * Ignore the translation elements because they contain very large values
1432
         * derived from the current transformation matrix and so are of no use.
1433
         */
1434
9.04M
        face->ft_transform.xx = a_font_scale->matrix[0];
1435
9.04M
        face->ft_transform.xy = a_font_scale->matrix[2];
1436
9.04M
        face->ft_transform.yx = a_font_scale->matrix[1];
1437
9.04M
        face->ft_transform.yy = a_font_scale->matrix[3];
1438
1439
9.04M
        face->horz_res = a_font_scale->HWResolution[0] >> 16;
1440
9.04M
        face->vert_res = a_font_scale->HWResolution[1] >> 16;
1441
1442
        /* Split the transform into scale factors and a rotation-and-shear
1443
         * transform.
1444
         */
1445
9.04M
        transform_decompose(&face->ft_transform, &face->horz_res,
1446
9.04M
                            &face->vert_res, &face->width, &face->height, face->ft_face->units_per_EM);
1447
1448
        /* At small scales, we can end up with x_ppem or y_ppem in the FT metrics rounding down to zero,
1449
           which causes an FT_Err_Invalid_PPem error.
1450
           If such happens, gradually up the respective resolutions until the rounding no longer drops to zero.
1451
         */
1452
9.04M
        while ((ft_error = FT_Set_Char_Size(face->ft_face, face->width, face->height,
1453
9.04M
                                    face->horz_res, face->vert_res)) == FT_Err_Invalid_PPem) {
1454
1455
102
            if (face->ft_face->size->metrics.x_ppem == 0)
1456
102
                face->horz_res++;
1457
0
            else if (face->ft_face->size->metrics.y_ppem == 0)
1458
0
                face->vert_res++;
1459
0
            else
1460
0
                break;
1461
102
        }
1462
1463
9.04M
        if (ft_error) {
1464
            /* The code originally cleaned up the face data here, but the "top level"
1465
               font object still has references to the face data, and we've no way
1466
               to tell it it's gone. So we defer releasing the data until the garbage
1467
               collector collects the font object, and the font's finalize call will
1468
               free the data correctly for us.
1469
             */
1470
209
            return ft_to_gs_error(ft_error);
1471
209
        }
1472
1473
        /* Concatenate the transform to a reflection around (y=0) so that it
1474
         * produces a glyph that is upside down in FreeType terms, with its
1475
         * first row at the bottom. That is what GhostScript needs.
1476
         */
1477
1478
9.04M
        FT_Set_Transform(face->ft_face, &face->ft_transform, NULL);
1479
1480
9.04M
    }
1481
1482
    /* dpf("gs_fapi_ft_get_scaled_font return %d\n", a_font->server_font_data ? 0 : -1); */
1483
9.04M
    return a_font->server_font_data ? 0 : -1;
1484
9.04M
}
1485
1486
/*
1487
 * Return the name of a resource which maps names to character codes. Do this
1488
 * by setting a_decoding_id to point to a null-terminated string. The resource
1489
 * is in the 'decoding' directory in the directory named by /GenericResourceDir
1490
 * in lib/gs_res.ps.
1491
 */
1492
static gs_fapi_retcode
1493
gs_fapi_ft_get_decodingID(gs_fapi_server * a_server, gs_fapi_font * a_font,
1494
               const char **a_decoding_id)
1495
10.1k
{
1496
10.1k
    *a_decoding_id = "Unicode";
1497
10.1k
    return 0;
1498
10.1k
}
1499
1500
/*
1501
 * Get the font bounding box in font units.
1502
 */
1503
static gs_fapi_retcode
1504
gs_fapi_ft_get_font_bbox(gs_fapi_server * a_server, gs_fapi_font * a_font, int a_box[4], int unitsPerEm[2])
1505
2.56M
{
1506
2.56M
    ff_face *face = (ff_face *) a_font->server_font_data;
1507
1508
2.56M
    a_box[0] = face->ft_face->bbox.xMin;
1509
2.56M
    a_box[1] = face->ft_face->bbox.yMin;
1510
2.56M
    a_box[2] = face->ft_face->bbox.xMax;
1511
2.56M
    a_box[3] = face->ft_face->bbox.yMax;
1512
1513
2.56M
    unitsPerEm[0] = unitsPerEm[1] = face->ft_face->units_per_EM;
1514
1515
2.56M
    return 0;
1516
2.56M
}
1517
1518
/*
1519
 * Return a boolean value in a_proportional stating whether the font is proportional
1520
 * or fixed-width.
1521
 */
1522
static gs_fapi_retcode
1523
gs_fapi_ft_get_font_proportional_feature(gs_fapi_server * a_server,
1524
                              gs_fapi_font * a_font, bool * a_proportional)
1525
0
{
1526
0
    *a_proportional = true;
1527
0
    return 0;
1528
0
}
1529
1530
/* Convert the character name in a_char_ref.char_name to a character code or
1531
 * glyph index and put it in a_char_ref.char_code, setting
1532
 * a_char_ref.is_glyph_index as appropriate. If this is possible set a_result
1533
 * to true, otherwise set it to false.  The return value is a standard error
1534
 * return code.
1535
 */
1536
static gs_fapi_retcode
1537
gs_fapi_ft_can_retrieve_char_by_name(gs_fapi_server * a_server, gs_fapi_font * a_font,
1538
                          gs_fapi_char_ref * a_char_ref, bool * a_result)
1539
0
{
1540
0
    ff_face *face = (ff_face *) a_font->server_font_data;
1541
0
    char name[128];
1542
1543
0
    if (FT_HAS_GLYPH_NAMES(face->ft_face)
1544
0
        && a_char_ref->char_name_length < sizeof(name)) {
1545
0
        memcpy(name, a_char_ref->char_name, a_char_ref->char_name_length);
1546
0
        name[a_char_ref->char_name_length] = 0;
1547
0
        a_char_ref->char_codes[0] = FT_Get_Name_Index(face->ft_face, name);
1548
0
        *a_result = a_char_ref->char_codes[0] != 0;
1549
0
        if (*a_result)
1550
0
            a_char_ref->is_glyph_index = true;
1551
0
    }
1552
0
    else
1553
0
        *a_result = false;
1554
0
    return 0;
1555
0
}
1556
1557
/*
1558
 * Return non-zero if the metrics can be replaced.
1559
 */
1560
static gs_fapi_retcode
1561
gs_fapi_ft_can_replace_metrics(gs_fapi_server * a_server, gs_fapi_font * a_font,
1562
                    gs_fapi_char_ref * a_char_ref, int *a_result)
1563
12.7M
{
1564
    /* Replace metrics only if the metrics are supplied in font units. */
1565
12.7M
    *a_result = 1;
1566
12.7M
    return 0;
1567
12.7M
}
1568
1569
/*
1570
 * Retrieve the metrics of a_char_ref and put them in a_metrics.
1571
 */
1572
static gs_fapi_retcode
1573
gs_fapi_ft_get_char_width(gs_fapi_server * a_server, gs_fapi_font * a_font,
1574
               gs_fapi_char_ref * a_char_ref, gs_fapi_metrics * a_metrics)
1575
0
{
1576
0
    ff_server *s = (ff_server *) a_server;
1577
1578
0
    return load_glyph(a_server, a_font, a_char_ref, a_metrics,
1579
0
                      (FT_Glyph *) & s->outline_glyph,
1580
0
                      false, a_server->max_bitmap);
1581
0
}
1582
1583
static gs_fapi_retcode
1584
gs_fapi_ft_get_fontmatrix(gs_fapi_server * server, gs_matrix * m)
1585
23.8M
{
1586
23.8M
    m->xx = 1.0;
1587
23.8M
    m->xy = 0.0;
1588
23.8M
    m->yx = 0.0;
1589
23.8M
    m->yy = 1.0;
1590
23.8M
    m->tx = 0.0;
1591
23.8M
    m->ty = 0.0;
1592
23.8M
    return 0;
1593
23.8M
}
1594
1595
/*
1596
 * Rasterize the character a_char and return its metrics. Do not return the
1597
 * bitmap but store this. It can be retrieved by a subsequent call to
1598
 * gs_fapi_ft_get_char_raster.
1599
 */
1600
static gs_fapi_retcode
1601
gs_fapi_ft_get_char_raster_metrics(gs_fapi_server * a_server, gs_fapi_font * a_font,
1602
                        gs_fapi_char_ref * a_char_ref,
1603
                        gs_fapi_metrics * a_metrics)
1604
8.71M
{
1605
8.71M
    ff_server *s = (ff_server *) a_server;
1606
8.71M
    gs_fapi_retcode error =
1607
8.71M
        load_glyph(a_server, a_font, a_char_ref, a_metrics,
1608
8.71M
                   (FT_Glyph *) & s->bitmap_glyph, true,
1609
8.71M
                   a_server->max_bitmap);
1610
8.71M
    return error;
1611
8.71M
}
1612
1613
/*
1614
 * Return the bitmap created by the last call to gs_fapi_ft_get_char_raster_metrics.
1615
 */
1616
static gs_fapi_retcode
1617
gs_fapi_ft_get_char_raster(gs_fapi_server * a_server, gs_fapi_raster * a_raster)
1618
10.1M
{
1619
10.1M
    ff_server *s = (ff_server *) a_server;
1620
1621
10.1M
    if (!s->bitmap_glyph)
1622
4.34M
        return(gs_error_unregistered);
1623
5.78M
    a_raster->p = s->bitmap_glyph->bitmap.buffer;
1624
5.78M
    a_raster->width = s->bitmap_glyph->bitmap.width;
1625
5.78M
    a_raster->height = s->bitmap_glyph->bitmap.rows;
1626
5.78M
    a_raster->line_step = s->bitmap_glyph->bitmap.pitch;
1627
5.78M
    a_raster->orig_x = s->bitmap_glyph->left * 16;
1628
5.78M
    a_raster->orig_y = s->bitmap_glyph->top * 16;
1629
5.78M
    a_raster->left_indent = a_raster->top_indent = a_raster->black_height =
1630
5.78M
        a_raster->black_width = 0;
1631
5.78M
    return 0;
1632
10.1M
}
1633
1634
/*
1635
 * Create an outline for the character a_char and return its metrics. Do not
1636
 * return the outline but store this.
1637
 * It can be retrieved by a subsequent call to gs_fapi_ft_get_char_outline.
1638
 */
1639
static gs_fapi_retcode
1640
gs_fapi_ft_get_char_outline_metrics(gs_fapi_server * a_server, gs_fapi_font * a_font,
1641
                         gs_fapi_char_ref * a_char_ref,
1642
                         gs_fapi_metrics * a_metrics)
1643
6.96M
{
1644
6.96M
    ff_server *s = (ff_server *) a_server;
1645
1646
6.96M
    return load_glyph(a_server, a_font, a_char_ref, a_metrics,
1647
6.96M
                      (FT_Glyph *) & s->outline_glyph, false,
1648
6.96M
                      a_server->max_bitmap);
1649
6.96M
}
1650
1651
typedef struct FF_path_info_s
1652
{
1653
    gs_fapi_path *path;
1654
    int64_t x;
1655
    int64_t y;
1656
    FT_Vector currentp;
1657
} FF_path_info;
1658
1659
static inline int
1660
FF_points_equal(const FT_Vector *p1, const FT_Vector *p2)
1661
52.3M
{
1662
52.3M
    if (p1->x == p2->x && p1->y == p2->y)
1663
64.6k
        return 1;
1664
52.2M
    else
1665
52.2M
        return 0;
1666
52.3M
}
1667
1668
static int
1669
move_to(const FT_Vector * aTo, void *aObject)
1670
4.95M
{
1671
4.95M
    FF_path_info *p = (FF_path_info *) aObject;
1672
1673
4.95M
    p->currentp = *aTo;
1674
1675
    /* FAPI expects that co-ordinates will be as implied by frac_shift
1676
     * in our case 16.16 fixed precision. True for 'low level' FT
1677
     * routines (apparently), it isn't true for these routines where
1678
     * FT returns a 26.6 format. Rescale to 16.16 so that FAPI will
1679
     * be able to convert to GS co-ordinates properly.
1680
     */
1681
    /* FAPI now expects these coordinates in 32.32 */
1682
4.95M
    p->x = ((int64_t) aTo->x) << 26;
1683
4.95M
    p->y = ((int64_t) aTo->y) << 26;
1684
1685
4.95M
    return p->path->moveto(p->path, p->x, p->y) ? -1 : 0;
1686
4.95M
}
1687
1688
static int
1689
line_to(const FT_Vector * aTo, void *aObject)
1690
21.9M
{
1691
21.9M
    FF_path_info *p = (FF_path_info *) aObject;
1692
1693
21.9M
    if (!FF_points_equal(&p->currentp, aTo)) {
1694
21.9M
        p->currentp = *aTo;
1695
1696
        /* See move_to() above */
1697
21.9M
        p->x = ((int64_t) aTo->x) << 26;
1698
21.9M
        p->y = ((int64_t) aTo->y) << 26;
1699
1700
21.9M
        return p->path->lineto(p->path, p->x, p->y) ? -1 : 0;
1701
21.9M
    }
1702
24.1k
    return 0;
1703
21.9M
}
1704
1705
static int
1706
conic_to(const FT_Vector * aControl, const FT_Vector * aTo, void *aObject)
1707
7.20M
{
1708
7.20M
    FF_path_info *p = (FF_path_info *) aObject;
1709
7.20M
    double x, y, Controlx, Controly;
1710
7.20M
    int64_t Control1x, Control1y, Control2x, Control2y;
1711
7.20M
    double sx, sy;
1712
1713
7.20M
    if (!FF_points_equal(&p->currentp, aControl) ||
1714
10.6k
        !FF_points_equal(&p->currentp, aTo) ||
1715
7.19M
        !FF_points_equal(aControl, aTo)) {
1716
7.19M
        p->currentp = *aTo;
1717
1718
        /* More complicated than above, we need to do arithmetic on the
1719
         * co-ordinates, so we want them as floats and we will convert the
1720
         * result into 16.16 fixed precision for FAPI
1721
         *
1722
         * NB this code is funcitonally the same as the original, but I don't believe
1723
         * the comment (below) to be what the code is actually doing....
1724
         *
1725
         * NB2: the comment below was wrong, even though the code was correct(!!)
1726
         * The comment has now been amended.
1727
         *
1728
         * Convert a quadratic spline to a cubic. Do this by changing the three points
1729
         * A, B and C to A, 2/3(B,A), 2/3(B,C), C - that is, the two cubic control points are
1730
         * a third of the way from the single quadratic control point to the end points. This
1731
         * gives the same curve as the original quadratic.
1732
         */
1733
1734
7.19M
        sx = (double) (p->x >> 32);
1735
7.19M
        sy = (double) (p->y >> 32);
1736
1737
7.19M
        x = aTo->x / 64.0;
1738
7.19M
        p->x = ((int64_t) float2fixed(x)) << 24;
1739
7.19M
        y = aTo->y / 64.0;
1740
7.19M
        p->y = ((int64_t) float2fixed(y)) << 24;
1741
7.19M
        Controlx = aControl->x / 64.0;
1742
7.19M
        Controly = aControl->y / 64.0;
1743
1744
7.19M
        Control1x = ((int64_t) float2fixed((sx + Controlx * 2) / 3)) << 24;
1745
7.19M
        Control1y = ((int64_t) float2fixed((sy + Controly * 2) / 3)) << 24;
1746
7.19M
        Control2x = ((int64_t) float2fixed((x + Controlx * 2) / 3)) << 24;
1747
7.19M
        Control2y = ((int64_t) float2fixed((y + Controly * 2) / 3)) << 24;
1748
1749
7.19M
        return p->path->curveto(p->path, Control1x,
1750
7.19M
                                Control1y,
1751
7.19M
                                Control2x, Control2y, p->x, p->y) ? -1 : 0;
1752
7.19M
    }
1753
6.98k
    return 0;
1754
7.20M
}
1755
1756
static int
1757
cubic_to(const FT_Vector * aControl1, const FT_Vector * aControl2,
1758
         const FT_Vector * aTo, void *aObject)
1759
23.1M
{
1760
23.1M
    FF_path_info *p = (FF_path_info *) aObject;
1761
23.1M
    int64_t Control1x, Control1y, Control2x, Control2y;
1762
1763
23.1M
    if (!FF_points_equal(&p->currentp, aControl1) ||
1764
6.13k
        !FF_points_equal(&p->currentp, aControl2) ||
1765
2.85k
        !FF_points_equal(&p->currentp, aTo) ||
1766
1.72k
        !FF_points_equal(aControl1, aControl2) ||
1767
1.72k
        !FF_points_equal(aControl1, aTo) ||
1768
23.1M
        !FF_points_equal(aControl2, aTo)) {
1769
23.1M
        p->currentp = *aTo;
1770
1771
        /* See move_to() above */
1772
23.1M
        p->x = ((int64_t) aTo->x) << 26;
1773
23.1M
        p->y = ((int64_t) aTo->y) << 26;
1774
1775
23.1M
        Control1x = ((int64_t) aControl1->x) << 26;
1776
23.1M
        Control1y = ((int64_t) aControl1->y) << 26;
1777
23.1M
        Control2x = ((int64_t) aControl2->x) << 26;
1778
23.1M
        Control2y = ((int64_t) aControl2->y) << 26;
1779
23.1M
        return p->path->curveto(p->path, Control1x, Control1y, Control2x,
1780
23.1M
                                Control2y, p->x, p->y) ? -1 : 0;
1781
23.1M
    }
1782
1.72k
    return 0;
1783
23.1M
}
1784
1785
static const FT_Outline_Funcs TheFtOutlineFuncs = {
1786
    move_to,
1787
    line_to,
1788
    conic_to,
1789
    cubic_to,
1790
    0,
1791
    0
1792
};
1793
1794
/*
1795
 * Return the outline created by the last call to gs_fapi_ft_get_char_outline_metrics.
1796
 */
1797
static gs_fapi_retcode
1798
gs_fapi_ft_get_char_outline(gs_fapi_server * a_server, gs_fapi_path * a_path)
1799
4.38M
{
1800
4.38M
    ff_server *s = (ff_server *) a_server;
1801
4.38M
    FF_path_info p;
1802
4.38M
    FT_Error ft_error = 0;
1803
1804
4.38M
    p.path = a_path;
1805
4.38M
    p.x = 0;
1806
4.38M
    p.y = 0;
1807
    /* If we got an error during glyph creation, we can get
1808
     * here with s->outline_glyph == NULL
1809
     */
1810
4.38M
    if (s->outline_glyph) {
1811
4.38M
        ft_error =
1812
4.38M
            FT_Outline_Decompose(&s->outline_glyph->outline, &TheFtOutlineFuncs,
1813
4.38M
                                 &p);
1814
4.38M
    }
1815
0
    else {
1816
0
        a_path->moveto(a_path, 0, 0);
1817
0
    }
1818
1819
4.38M
    if (a_path->gs_error == 0)
1820
4.15M
        a_path->closepath(a_path);
1821
4.38M
    return ft_to_gs_error(ft_error);
1822
4.38M
}
1823
1824
static gs_fapi_retcode
1825
gs_fapi_ft_release_char_data(gs_fapi_server * a_server)
1826
12.7M
{
1827
12.7M
    ff_server *s = (ff_server *) a_server;
1828
1829
12.7M
    if (s->outline_glyph) {
1830
4.39M
        FT_Outline_Done(s->freetype_library, &s->outline_glyph->outline);
1831
4.39M
        FF_free(s->ftmemory, s->outline_glyph);
1832
4.39M
    }
1833
1834
12.7M
    if (s->bitmap_glyph) {
1835
5.78M
        FT_Bitmap_Done(s->freetype_library, &s->bitmap_glyph->bitmap);
1836
5.78M
        FF_free(s->ftmemory, s->bitmap_glyph);
1837
5.78M
    }
1838
1839
12.7M
    s->outline_glyph = NULL;
1840
12.7M
    s->bitmap_glyph = NULL;
1841
12.7M
    return 0;
1842
12.7M
}
1843
1844
static gs_fapi_retcode
1845
gs_fapi_ft_release_typeface(gs_fapi_server * a_server, void *a_server_font_data)
1846
2.64M
{
1847
2.64M
    ff_face *face = (ff_face *) a_server_font_data;
1848
1849
2.64M
    delete_face(a_server, face);
1850
2.64M
    return 0;
1851
2.64M
}
1852
1853
static gs_fapi_retcode
1854
gs_fapi_ft_check_cmap_for_GID(gs_fapi_server * server, uint * index)
1855
10.0M
{
1856
10.0M
    ff_face *face = (ff_face *) (server->ff.server_font_data);
1857
10.0M
    FT_Face ft_face = face->ft_face;
1858
1859
10.0M
    *index = FT_Get_Char_Index(ft_face, *index);
1860
10.0M
    return 0;
1861
10.0M
}
1862
1863
static gs_fapi_retcode
1864
gs_fapi_ft_set_mm_weight_vector(gs_fapi_server *server, gs_fapi_font *ff, float *wvector, int length)
1865
0
{
1866
#if defined(SHARE_FT) && SHARE_FT == 1 && \
1867
    FREETYPE_MAJOR <= 2 && FREETYPE_MINOR <= 9 && FREETYPE_PATCH <= 1
1868
1869
    return gs_error_invalidaccess;
1870
#else
1871
0
    ff_face *face = (ff_face *) ff->server_font_data;
1872
0
    FT_Fixed nwv[16] = {0};
1873
0
    FT_Fixed cwv[16] = {0};
1874
0
    FT_UInt len = 16;
1875
0
    int i;
1876
0
    bool setit = false;
1877
0
    FT_Error ft_error;
1878
0
    (void)server;
1879
1880
0
    ft_error = FT_Get_MM_WeightVector(face->ft_face, &len, cwv);
1881
0
    if (ft_error != 0) return_error(gs_error_invalidaccess);
1882
1883
0
    for (i = 0; i < length; i++) {
1884
0
        nwv[i] = (FT_Fixed)(wvector[i] * 65536.0);
1885
0
        if (nwv[i] != cwv[i]) {
1886
0
            setit = true;
1887
0
        }
1888
0
    }
1889
1890
0
    if (setit == true) {
1891
0
        ft_error = FT_Set_MM_WeightVector(face->ft_face, length, nwv);
1892
0
        if (ft_error != 0) return_error(gs_error_invalidaccess);
1893
0
    }
1894
1895
0
    return 0;
1896
0
#endif
1897
0
}
1898
1899
static void gs_fapi_freetype_destroy(gs_fapi_server ** serv);
1900
1901
static const gs_fapi_server_descriptor freetypedescriptor = {
1902
    (const char *)"FAPI",
1903
    (const char *)"FreeType",
1904
    gs_fapi_freetype_destroy
1905
};
1906
1907
static const gs_fapi_server freetypeserver = {
1908
    {&freetypedescriptor},
1909
    NULL,                       /* client_ctx_p */
1910
    16,                         /* frac_shift */
1911
    {gs_no_id},
1912
    {0},
1913
    0,
1914
    false,
1915
    false,
1916
    {1, 0, 0, 1, 0, 0},
1917
    1,
1918
    {1, 0, 0, 1, 0, 0},
1919
    gs_fapi_ft_ensure_open,
1920
    gs_fapi_ft_get_scaled_font,
1921
    gs_fapi_ft_get_decodingID,
1922
    gs_fapi_ft_get_font_bbox,
1923
    gs_fapi_ft_get_font_proportional_feature,
1924
    gs_fapi_ft_can_retrieve_char_by_name,
1925
    gs_fapi_ft_can_replace_metrics,
1926
    NULL,                       /* can_simulate_style */
1927
    gs_fapi_ft_get_fontmatrix,
1928
    gs_fapi_ft_get_char_width,
1929
    gs_fapi_ft_get_char_raster_metrics,
1930
    gs_fapi_ft_get_char_raster,
1931
    gs_fapi_ft_get_char_outline_metrics,
1932
    gs_fapi_ft_get_char_outline,
1933
    gs_fapi_ft_release_char_data,
1934
    gs_fapi_ft_release_typeface,
1935
    gs_fapi_ft_check_cmap_for_GID,
1936
    NULL,                        /* get_font_info */
1937
    gs_fapi_ft_set_mm_weight_vector,
1938
};
1939
1940
int gs_fapi_ft_init(gs_memory_t * mem, gs_fapi_server ** server);
1941
1942
int
1943
gs_fapi_ft_init(gs_memory_t * mem, gs_fapi_server ** server)
1944
178k
{
1945
178k
    ff_server *serv;
1946
178k
    int code = 0;
1947
178k
    gs_memory_t *cmem = mem->non_gc_memory;
1948
1949
178k
    code = gs_memory_chunk_wrap(&(cmem), mem);
1950
178k
    if (code != 0) {
1951
0
        return (code);
1952
0
    }
1953
1954
1955
178k
    serv = (ff_server *) gs_alloc_bytes_immovable(cmem, sizeof(ff_server), "gs_fapi_ft_init");
1956
178k
    if (!serv) {
1957
0
        gs_memory_chunk_release(cmem);
1958
0
        return_error(gs_error_VMerror);
1959
0
    }
1960
178k
    memset(serv, 0, sizeof(*serv));
1961
178k
    serv->mem = cmem;
1962
178k
    serv->fapi_server = freetypeserver;
1963
1964
178k
    serv->ftmemory = (FT_Memory) (&(serv->ftmemory_rec));
1965
1966
178k
    (*server) = (gs_fapi_server *) serv;
1967
178k
    return (0);
1968
178k
}
1969
1970
1971
void
1972
gs_fapi_freetype_destroy(gs_fapi_server ** serv)
1973
178k
{
1974
178k
    ff_server *server = (ff_server *) * serv;
1975
178k
    gs_memory_t *cmem = server->mem;
1976
1977
178k
    if (server->outline_glyph != NULL)
1978
0
        FT_Done_Glyph(&server->outline_glyph->root);
1979
178k
    if (server->bitmap_glyph != NULL)
1980
0
        FT_Done_Glyph(&server->bitmap_glyph->root);
1981
1982
    /* As with initialization: since we're supplying memory management to
1983
     * FT, we cannot just to use FT_Done_FreeType (), we have to use
1984
     * FT_Done_Library () and then discard the memory ourselves
1985
     */
1986
178k
    FT_Done_Library(server->freetype_library);
1987
178k
    gs_free(cmem, *serv, 0, 0, "gs_fapi_freetype_destroy: ff_server");
1988
    *serv = NULL;
1989
178k
    gs_memory_chunk_release(cmem);
1990
178k
}