Coverage Report

Created: 2025-06-10 07:27

/src/ghostpdl/base/fapi_ft.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2024 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
160M
{
132
160M
    gs_memory_t *mem = (gs_memory_t *) memory->user;
133
134
160M
    return (gs_malloc(mem, size, 1, "FF_alloc"));
135
160M
}
136
137
static void *
138
    FF_realloc(FT_Memory memory, long cur_size, long new_size, void *block)
139
5.13M
{
140
5.13M
    gs_memory_t *mem = (gs_memory_t *) memory->user;
141
5.13M
    void *tmp;
142
143
5.13M
    if (cur_size == new_size) {
144
22.0k
        return (block);
145
22.0k
    }
146
147
5.11M
    tmp = gs_malloc(mem, new_size, 1, "FF_realloc");
148
5.11M
    if (tmp && block) {
149
5.11M
        memcpy(tmp, block, min(cur_size, new_size));
150
151
5.11M
        gs_free(mem, block, 0, 0, "FF_realloc");
152
5.11M
    }
153
154
5.11M
    return (tmp);
155
5.13M
}
156
157
static void
158
    FF_free(FT_Memory memory, void *block)
159
162M
{
160
162M
    gs_memory_t *mem = (gs_memory_t *) memory->user;
161
162
162M
    gs_free(mem, block, 0, 0, "FF_free");
163
162M
}
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.08M
{
283
1.08M
    ff_server *s = (ff_server *) a_server;
284
285
1.08M
    ff_face *face = (ff_face *) FF_alloc(s->ftmemory, sizeof(ff_face));
286
287
1.08M
    if (face) {
288
1.08M
        face->ft_face = a_ft_face;
289
1.08M
        face->ft_inc_int = a_ft_inc_int;
290
1.08M
        face->font_data = a_font_data;
291
1.08M
        face->font_data_len = a_font_data_len;
292
1.08M
        face->data_owned = data_owned;
293
1.08M
        face->ftstrm = ftstrm;
294
1.08M
        face->server = (ff_server *) a_server;
295
1.08M
    }
296
1.08M
    return face;
297
1.08M
}
298
299
static void
300
delete_face(gs_fapi_server * a_server, ff_face * a_face)
301
1.08M
{
302
1.08M
    if (a_face) {
303
1.08M
        ff_server *s = (ff_server *) a_server;
304
1.08M
        if (a_face->ft_inc_int) {
305
1.07M
            FT_Incremental a_info = a_face->ft_inc_int->object;
306
307
1.07M
            if (a_info->glyph_data) {
308
604k
                gs_free(s->mem, a_info->glyph_data, 0, 0, "delete_face");
309
604k
            }
310
1.07M
            a_info->glyph_data = NULL;
311
1.07M
            a_info->glyph_data_length = 0;
312
1.07M
            delete_inc_int(a_server, a_face->ft_inc_int);
313
1.07M
            a_face->ft_inc_int = NULL;
314
1.07M
        }
315
1.08M
        FT_Done_Face(a_face->ft_face);
316
317
1.08M
        FF_free(s->ftmemory, a_face->ft_inc_int);
318
1.08M
        if (a_face->data_owned)
319
1.07M
            FF_free(s->ftmemory, a_face->font_data);
320
1.08M
        if (a_face->ftstrm) {
321
0
            FF_free(s->ftmemory, a_face->ftstrm);
322
0
        }
323
1.08M
        FF_free(s->ftmemory, a_face);
324
1.08M
    }
325
1.08M
}
326
327
static FT_IncrementalRec *
328
new_inc_int_info(gs_fapi_server * a_server, gs_fapi_font * a_fapi_font)
329
1.07M
{
330
1.07M
    ff_server *s = (ff_server *) a_server;
331
332
1.07M
    FT_IncrementalRec *info =
333
1.07M
        (FT_IncrementalRec *) FF_alloc(s->ftmemory,
334
1.07M
                                       sizeof(FT_IncrementalRec));
335
1.07M
    if (info) {
336
1.07M
        info->fapi_font = a_fapi_font;
337
1.07M
        info->glyph_data = NULL;
338
1.07M
        info->glyph_data_length = 0;
339
1.07M
        info->glyph_data_in_use = false;
340
1.07M
        info->glyph_metrics_index = 0xFFFFFFFF;
341
1.07M
        info->metrics_type = gs_fapi_metrics_notdef;
342
1.07M
    }
343
1.07M
    return info;
344
1.07M
}
345
346
static void
347
delete_inc_int_info(gs_fapi_server * a_server,
348
                    FT_IncrementalRec * a_inc_int_info)
349
1.07M
{
350
1.07M
    ff_server *s = (ff_server *) a_server;
351
352
1.07M
    if (a_inc_int_info) {
353
1.07M
        FF_free(s->ftmemory, a_inc_int_info->glyph_data);
354
1.07M
        FF_free(s->ftmemory, a_inc_int_info);
355
1.07M
    }
356
1.07M
}
357
358
static FT_Error
359
get_fapi_glyph_data(FT_Incremental a_info, FT_UInt a_index, FT_Data * a_data)
360
18.2M
{
361
18.2M
    gs_fapi_font *ff = a_info->fapi_font;
362
18.2M
    int length = 0;
363
18.2M
    ff_face *face = (ff_face *) ff->server_font_data;
364
18.2M
    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
18.2M
    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
18.2M
    if (a_info->glyph_data_in_use) {
373
98.7k
        unsigned char *buffer = NULL;
374
375
98.7k
        length = ff->get_glyph(ff, a_index, NULL, 0);
376
98.7k
        if (length == gs_fapi_glyph_invalid_format
377
98.7k
            || length == gs_fapi_glyph_invalid_index)
378
0
            return FT_Err_Invalid_Glyph_Index;
379
380
98.7k
        buffer = gs_malloc(mem, length, 1, "get_fapi_glyph_data");
381
98.7k
        if (!buffer)
382
2.24k
            return FT_Err_Out_Of_Memory;
383
384
96.4k
        length = ff->get_glyph(ff, a_index, buffer, length);
385
96.4k
        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
96.4k
        a_data->pointer = buffer;
391
96.4k
    }
392
18.1M
    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
18.1M
        const void *saved_char_data = ff->char_data;
398
399
        /* Get as much of the glyph data as possible into the buffer */
400
18.1M
        length =
401
18.1M
            ff->get_glyph(ff, a_index, a_info->glyph_data,
402
18.1M
                          (ushort) a_info->glyph_data_length);
403
18.1M
        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
18.1M
        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
18.1M
        if (length > a_info->glyph_data_length) {
415
1.36M
            if (a_info->glyph_data) {
416
760k
                gs_free((gs_memory_t *) mem,
417
760k
                        a_info->glyph_data, 0, 0, "get_fapi_glyph_data");
418
760k
            }
419
420
1.36M
            a_info->glyph_data =
421
1.36M
                gs_malloc(mem, length, 1, "get_fapi_glyph_data");
422
423
1.36M
            if (!a_info->glyph_data) {
424
1.29k
                a_info->glyph_data_length = 0;
425
1.29k
                return FT_Err_Out_Of_Memory;
426
1.29k
            }
427
1.36M
            a_info->glyph_data_length = length;
428
1.36M
            ff->char_data = saved_char_data;
429
1.36M
            length = ff->get_glyph(ff, a_index, a_info->glyph_data, length);
430
1.36M
            if (length == gs_fapi_glyph_invalid_format)
431
0
                return FT_Err_Unknown_File_Format;
432
1.36M
            if (length == gs_fapi_glyph_invalid_index)
433
0
                return FT_Err_Invalid_Glyph_Index;
434
1.36M
        }
435
436
        /* Set the returned pointer and length. */
437
18.1M
        a_data->pointer = a_info->glyph_data;
438
439
18.1M
        a_info->glyph_data_in_use = true;
440
18.1M
    }
441
442
18.2M
    a_data->length = length;
443
18.2M
    return 0;
444
18.2M
}
445
446
static void
447
free_fapi_glyph_data(FT_Incremental a_info, FT_Data * a_data)
448
18.2M
{
449
18.2M
    gs_fapi_font *ff = a_info->fapi_font;
450
18.2M
    ff_face *face = (ff_face *) ff->server_font_data;
451
18.2M
    gs_memory_t *mem = (gs_memory_t *) face->server->mem;
452
453
18.2M
    if (a_data->pointer == (const FT_Byte *)a_info->glyph_data)
454
18.1M
        a_info->glyph_data_in_use = false;
455
95.7k
    else
456
18.2M
        gs_free(mem, (FT_Byte *) a_data->pointer, 0, 0, "free_fapi_glyph_data");
457
18.2M
}
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
19.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
19.0M
    if (bVertical && !a_info->fapi_font->is_type1)
469
925k
        a_metrics->advance = 0;
470
471
19.0M
    if (a_info->glyph_metrics_index == a_glyph_index) {
472
1.20M
        switch (a_info->metrics_type) {
473
1.20M
            case gs_fapi_metrics_add:
474
1.20M
                a_metrics->advance += a_info->glyph_metrics.advance;
475
1.20M
                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.20M
        }
488
1.20M
    }
489
19.0M
    return 0;
490
19.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.07M
{
501
1.07M
    ff_server *s = (ff_server *) a_server;
502
503
1.07M
    FT_Incremental_InterfaceRec *i =
504
1.07M
        (FT_Incremental_InterfaceRec *) FF_alloc(s->ftmemory,
505
1.07M
                                                 sizeof
506
1.07M
                                                 (FT_Incremental_InterfaceRec));
507
1.07M
    if (i) {
508
1.07M
        i->funcs = &TheFAPIIncrementalInterfaceFuncs;
509
1.07M
        i->object = (FT_Incremental) new_inc_int_info(a_server, a_fapi_font);
510
511
1.07M
        if (!i->object) {
512
0
            FF_free(s->ftmemory, i);
513
0
            i = NULL;
514
0
        }
515
1.07M
    }
516
1.07M
    return i;
517
1.07M
}
518
519
static void
520
delete_inc_int(gs_fapi_server * a_server,
521
               FT_Incremental_InterfaceRec * a_inc_int)
522
1.07M
{
523
1.07M
    ff_server *s = (ff_server *) a_server;
524
525
1.07M
    if (a_inc_int) {
526
1.07M
        delete_inc_int_info(a_server, a_inc_int->object);
527
1.07M
        FF_free(s->ftmemory, a_inc_int);
528
1.07M
    }
529
1.07M
}
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
22.1M
{
537
22.1M
    if (a_error) {
538
271k
        if (a_error == FT_Err_Out_Of_Memory)
539
0
            return_error(gs_error_VMerror);
540
271k
        else
541
271k
            return_error(gs_error_unknownerror);
542
271k
    }
543
21.8M
    return 0;
544
22.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
19.6M
{
554
19.6M
    ff_server *s = (ff_server *) a_server;
555
19.6M
    FT_Error ft_error = 0;
556
19.6M
    FT_Error ft_error_fb = 1;
557
19.6M
    ff_face *face = (ff_face *) a_fapi_font->server_font_data;
558
19.6M
    FT_Face ft_face = face->ft_face;
559
19.6M
    int index = a_char_ref->char_codes[0];
560
19.6M
    FT_Long w;
561
19.6M
    FT_Long h;
562
19.6M
    FT_Long fflags;
563
19.6M
    FT_Int32 load_flags = 0;
564
19.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
19.6M
    const void *saved_char_data = a_fapi_font->char_data;
571
19.6M
    const int saved_char_data_len = a_fapi_font->char_data_len;
572
573
19.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
19.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
19.6M
    if (!a_char_ref->is_glyph_index) {
585
16.8M
        if (ft_face->num_charmaps)
586
16.7M
            index = FT_Get_Char_Index(ft_face, index);
587
65.9k
        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
65.9k
            if (a_fapi_font->is_type1)
600
0
                index = 0;
601
65.9k
            else
602
65.9k
                index = a_char_ref->char_codes[0];
603
65.9k
        }
604
16.8M
    }
605
2.87M
    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
2.87M
        if (!a_fapi_font->is_cid && !face->ft_inc_int &&
612
2.87M
            (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
2.87M
    }
622
    /* Refresh the pointer to the FAPI_font held by the incremental interface. */
623
19.6M
    if (face->ft_inc_int)
624
18.0M
        face->ft_inc_int->object->fapi_font = a_fapi_font;
625
626
    /* Store the overriding metrics if they have been supplied. */
627
19.6M
    if (face->ft_inc_int && a_char_ref->metrics_type != gs_fapi_metrics_notdef) {
628
629
1.20M
        FT_Incremental_MetricsRec *m = &face->ft_inc_int->object->glyph_metrics;
630
631
1.20M
        m->bearing_x = a_char_ref->sb_x >> 16;
632
1.20M
        m->bearing_y = a_char_ref->sb_y >> 16;
633
1.20M
        m->advance = a_char_ref->aw_x >> 16;
634
635
1.20M
        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.20M
        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.20M
        else {
654
1.20M
            face->ft_inc_int->object->metrics_type = a_char_ref->metrics_type;
655
1.20M
        }
656
1.20M
    }
657
18.4M
    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
16.8M
        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
19.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
19.6M
        a_fapi_font->char_data = saved_char_data;
667
19.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
2.61M
            if (a_server->grid_fit == 0) {
673
0
                load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT;
674
0
            }
675
2.61M
            else if (a_server->grid_fit == 2) {
676
0
                load_flags = FT_LOAD_FORCE_AUTOHINT;
677
0
            }
678
2.61M
            load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_NO_BITMAP | FT_LOAD_LINEAR_DESIGN | FT_LOAD_PEDANTIC;
679
2.61M
        }
680
17.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
17.0M
            load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_LINEAR_DESIGN;
684
17.0M
        }
685
686
19.6M
        ft_error = FT_Load_Glyph(ft_face, index, load_flags);
687
19.6M
        if (ft_error == FT_Err_Unknown_File_Format) {
688
0
            return index + 1;
689
0
        }
690
19.6M
    }
691
692
19.6M
    if (ft_error == FT_Err_Invalid_Argument
693
19.6M
        || ft_error == FT_Err_Invalid_Reference
694
19.6M
        || ft_error == FT_Err_Invalid_Glyph_Index
695
19.6M
        || ft_error == FT_Err_DEF_In_Glyf_Bytecode
696
19.6M
        || (ft_error >= FT_Err_Invalid_Opcode
697
19.5M
            && ft_error <= FT_Err_Too_Many_Instruction_Defs)) {
698
699
678k
        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
678k
        fflags = ft_face->face_flags;
703
678k
        ft_face->face_flags &= ~FT_FACE_FLAG_TRICKY;
704
678k
        load_flags |= FT_LOAD_NO_HINTING;
705
678k
        ft_error = FT_Load_Glyph(ft_face, index, load_flags);
706
707
678k
        ft_face->face_flags = fflags;
708
678k
    }
709
710
19.6M
    if (ft_error == FT_Err_Out_Of_Memory
711
19.6M
        || ft_error == FT_Err_Array_Too_Large) {
712
1.44k
        return (gs_error_VMerror);
713
1.44k
    }
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
19.6M
    if (ft_error) {
717
218k
        gs_string notdef_str;
718
719
218k
        notdef_str.data = (byte *)".notdef";
720
218k
        notdef_str.size = 7;
721
722
218k
        a_fapi_font->char_data = (void *)(&notdef_str);
723
218k
        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
218k
        fflags = ft_face->face_flags;
727
218k
        ft_face->face_flags &= ~FT_FACE_FLAG_TRICKY;
728
729
218k
        ft_error_fb = FT_Load_Glyph(ft_face, 0, load_flags);
730
731
218k
        ft_face->face_flags = fflags;
732
733
218k
        a_fapi_font->char_data = saved_char_data;
734
218k
        a_fapi_font->char_data_len = saved_char_data_len;
735
218k
    }
736
737
19.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
19.6M
    if ((!ft_error || !ft_error_fb) && a_metrics) {
745
19.6M
        FT_Long hx;
746
19.6M
        FT_Long hy;
747
19.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
19.6M
        hx = (FT_Long) (((double)ft_face->glyph->metrics.horiBearingX *
753
19.6M
                         ft_face->units_per_EM * 72.0) /
754
19.6M
                        ((double)face->width * face->horz_res))  + (a_fapi_font->is_mtx_skipped == 1 ? 0 : a_char_ref->sb_x >> 16);
755
19.6M
        hy = (FT_Long) (((double)ft_face->glyph->metrics.horiBearingY *
756
19.6M
                         ft_face->units_per_EM * 72.0) /
757
19.6M
                        ((double)face->height * face->vert_res)) + (a_fapi_font->is_mtx_skipped == 1 ? 0 : a_char_ref->sb_y >> 16);
758
759
19.6M
        w = (FT_Long) (((double)ft_face->glyph->metrics.width *
760
19.6M
                        ft_face->units_per_EM * 72.0) / ((double)face->width *
761
19.6M
                                                         face->horz_res));
762
19.6M
        h = (FT_Long) (((double)ft_face->glyph->metrics.height *
763
19.6M
                        ft_face->units_per_EM * 72.0) /
764
19.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
19.6M
        if (a_fapi_font->is_type1
772
19.6M
           || ((a_fapi_font->full_font_buf || a_fapi_font->font_file_path)
773
17.0M
           && a_fapi_font->is_vertical &&  FT_HAS_VERTICAL(ft_face))) {
774
775
17.0M
            vadv = ft_face->glyph->linearVertAdvance;
776
17.0M
        }
777
2.56M
        else {
778
2.56M
            vadv = 0;
779
2.56M
        }
780
781
19.6M
        a_metrics->bbox_x0 = hx;
782
19.6M
        a_metrics->bbox_y0 = hy - h;
783
19.6M
        a_metrics->bbox_x1 = a_metrics->bbox_x0 + w;
784
19.6M
        a_metrics->bbox_y1 = a_metrics->bbox_y0 + h;
785
19.6M
        a_metrics->escapement = ft_face->glyph->linearHoriAdvance;
786
19.6M
        a_metrics->v_escapement = vadv;
787
19.6M
        a_metrics->em_x = ft_face->units_per_EM;
788
19.6M
        a_metrics->em_y = ft_face->units_per_EM;
789
19.6M
    }
790
791
19.6M
    if ((!ft_error || !ft_error_fb)) {
792
793
19.6M
        FT_BBox cbox;
794
795
        /* compute the control box, and grid fit it - lifted from ft_raster1_render() */
796
19.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
19.6M
        cbox.xMin = ((cbox.xMin) & ~63);        /* FT_PIX_FLOOR( cbox.xMin ) */
803
19.6M
        cbox.yMin = ((cbox.yMin) & ~63);
804
19.6M
        cbox.xMax = (((cbox.xMax) + 63) & ~63);
805
19.6M
        cbox.yMax = (((cbox.yMax) + 63) & ~63); /* FT_PIX_CEIL( cbox.yMax ) */
806
807
19.6M
        w = (FT_UInt) ((cbox.xMax - cbox.xMin) >> 6);
808
19.6M
        h = (FT_UInt) ((cbox.yMax - cbox.yMin) >> 6);
809
810
19.6M
        if (!a_fapi_font->metrics_only && a_bitmap == true && ft_face->glyph->format != FT_GLYPH_FORMAT_BITMAP
811
19.6M
            && ft_face->glyph->format != FT_GLYPH_FORMAT_COMPOSITE) {
812
11.1M
            if ((bitmap_raster(w) * h) < max_bitmap) {
813
6.09M
                FT_Render_Mode mode = FT_RENDER_MODE_MONO;
814
815
6.09M
                ft_error = FT_Render_Glyph(ft_face->glyph, mode);
816
6.09M
                if (ft_error != 0) {
817
16
                    (*a_glyph) = NULL;
818
16
                    return (gs_error_VMerror);
819
16
                }
820
6.09M
            }
821
5.03M
            else {
822
5.03M
                (*a_glyph) = NULL;
823
5.03M
                return (gs_error_VMerror);
824
5.03M
            }
825
11.1M
        }
826
19.6M
    }
827
828
14.6M
    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
13.6M
        ft_face->glyph->advance.x = ft_face->glyph->advance.y = 0;
835
13.6M
        if ((!ft_error || !ft_error_fb) && a_glyph) {
836
13.6M
            ft_error = FT_Get_Glyph(ft_face->glyph, a_glyph);
837
13.6M
        }
838
54.2k
        else {
839
54.2k
            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
54.2k
            else if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
849
48.0k
                FT_OutlineGlyph olg;
850
851
48.0k
                ft_error = FT_Get_Glyph(ft_face->glyph, (FT_Glyph *) & olg);
852
48.0k
                if (!ft_error) {
853
48.0k
                    FT_Outline_Done(s->freetype_library, &olg->outline);
854
48.0k
                    FF_free(s->ftmemory, olg);
855
48.0k
                }
856
48.0k
            }
857
54.2k
        }
858
13.6M
    }
859
860
14.6M
    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
14.6M
    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
6.26k
        if (!ft_error_fb)
890
0
            ft_error = 0;
891
6.26k
    }
892
14.6M
    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
14.6M
    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
14.6M
    return ft_to_gs_error(ft_error);
925
19.6M
}
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.09M
{
936
1.09M
    ff_server *s = (ff_server *) a_server;
937
1.09M
    FT_UInt tt_ins_version = TT_INTERPRETER_VERSION_35;
938
1.09M
    FT_Error ft_error;
939
940
1.09M
    if (s->freetype_library)
941
1.03M
        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
60.8k
    s->ftmemory->user = s->mem;
947
60.8k
    s->ftmemory->alloc = FF_alloc;
948
60.8k
    s->ftmemory->free = FF_free;
949
60.8k
    s->ftmemory->realloc = FF_realloc;
950
951
60.8k
    ft_error = FT_New_Library(s->ftmemory, &s->freetype_library);
952
60.8k
    if (ft_error)
953
0
        return ft_to_gs_error(ft_error);
954
955
60.8k
    FT_Add_Default_Modules(s->freetype_library);
956
60.8k
    FT_Property_Set( s->freetype_library, "truetype", "interpreter-version", &tt_ins_version);
957
958
60.8k
    return 0;
959
60.8k
}
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
3.45M
{
999
3.45M
    double scalex, scaley, fact = 1.0;
1000
3.45M
    double factx = 1.0, facty = 1.0;
1001
3.45M
    FT_Matrix ftscale_mat;
1002
3.45M
    FT_UInt xres;
1003
3.45M
    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
3.45M
    double upe = units_per_EM > 512 ? (float)units_per_EM : 512.0;
1010
1011
3.45M
    scalex = hypot((double)a_transform->xx, (double)a_transform->xy);
1012
3.45M
    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
3.45M
    if (scalex < 64.0 || scaley < 64.0) {
1018
6.74k
        factx = 64.0/scalex;
1019
6.74k
        facty = 64.0/scaley;
1020
1021
6.74k
        ftscale_mat.xx = (FT_Fixed)(a_transform->xx * factx);
1022
6.74k
        ftscale_mat.xy = (FT_Fixed)(a_transform->xy * facty);
1023
6.74k
        ftscale_mat.yx = (FT_Fixed)(a_transform->yx * factx);
1024
6.74k
        ftscale_mat.yy = (FT_Fixed)(a_transform->yy * facty);
1025
6.74k
        memcpy(a_transform, &ftscale_mat, sizeof(ftscale_mat));
1026
6.74k
        scalex = hypot((double)a_transform->xx, (double)a_transform->xy);
1027
6.74k
        scaley = hypot((double)a_transform->yx, (double)a_transform->yy);
1028
6.74k
    }
1029
1030
3.45M
    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
3.45M
    else {
1058
        /* Life is considerably easier when square resolutions are in use! */
1059
3.45M
        xres = (FT_UInt)(*xresp / factx);
1060
3.45M
        yres = (FT_UInt)(*yresp / facty);
1061
3.45M
    }
1062
1063
3.45M
    scalex *= 1.0 / 65536.0;
1064
3.45M
    scaley *= 1.0 / 65536.0;
1065
1066
3.45M
    if (scalex < scaley) {
1067
153k
        scaley = scalex;
1068
153k
    }
1069
3.30M
    else if (scalex > scaley) {
1070
65.5k
        scalex = scaley;
1071
65.5k
    }
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
3.45M
    if (scalex < 1.0) {
1084
915k
        fact = 1.016 / scalex;
1085
915k
        scalex = scalex * fact;
1086
915k
        scaley = scaley * fact;
1087
915k
    }
1088
1089
    /* see above */
1090
3.45M
    if (scalex * xres < 2268.0 / 64.0) {
1091
4.03k
        fact = (2400.0 / 64.0) / (xres * scalex);
1092
4.03k
        scaley *= fact;
1093
4.03k
        scalex *= fact;
1094
4.03k
    }
1095
1096
    /* see above */
1097
3.45M
    fact = 1.0;
1098
10.0M
    while (scaley * yres > (double)upe * 72.0 && (xres > 0 && yres > 0)
1099
10.0M
           && (scalex > 0.0 && scaley > 0.0)) {
1100
6.55M
        if (scaley < yres) {
1101
2.49k
            xres >>= 1;
1102
2.49k
            yres >>= 1;
1103
2.49k
            fact *= 2.0;
1104
2.49k
        }
1105
6.55M
        else {
1106
6.55M
            scalex /= 1.25;
1107
6.55M
            scaley /= 1.25;
1108
6.55M
        }
1109
6.55M
    }
1110
1111
3.45M
    ftscale_mat.xx = (FT_Fixed) ((65536.0 / scalex) * fact);
1112
3.45M
    ftscale_mat.xy = 0;
1113
3.45M
    ftscale_mat.yx = 0;
1114
3.45M
    ftscale_mat.yy = (FT_Fixed) ((65536.0 / scaley) * fact);
1115
1116
3.45M
    FT_Matrix_Multiply(a_transform, &ftscale_mat);
1117
3.45M
    memcpy(a_transform, &ftscale_mat, sizeof(FT_Matrix));
1118
1119
3.45M
    *xresp = xres;
1120
3.45M
    *yresp = yres;
1121
    /* Return values ready scaled for FT */
1122
3.45M
    *a_x_scale = (FT_Fixed) (scalex * 64);
1123
3.45M
    *a_y_scale = (FT_Fixed) (scaley * 64);
1124
3.45M
}
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
3.46M
{
1134
3.46M
    ff_server *s = (ff_server *) a_server;
1135
3.46M
    ff_face *face = (ff_face *) a_font->server_font_data;
1136
3.46M
    FT_Error ft_error = 0;
1137
3.46M
    int i, j, code;
1138
3.46M
    FT_CharMap cmap = NULL;
1139
3.46M
    bool data_owned = true;
1140
1141
3.46M
    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
3.46M
    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
3.46M
    if (a_font->is_cid && a_font->is_type1 && a_font->font_file_path == NULL
1160
3.46M
        && (a_descendant_code == gs_fapi_toplevel_begin
1161
7.87k
            || a_descendant_code == gs_fapi_toplevel_complete)) {
1162
        /* dpf("gs_fapi_ft_get_scaled_font return 0\n"); */
1163
3.98k
        return 0;
1164
3.98k
    }
1165
1166
    /* Create the face if it doesn't already exist. */
1167
3.46M
    if (!face) {
1168
1.09M
        FT_Face ft_face = NULL;
1169
1.09M
        FT_Parameter ft_param;
1170
1.09M
        FT_Incremental_InterfaceRec *ft_inc_int = NULL;
1171
1.09M
        unsigned char *own_font_data = NULL;
1172
1.09M
        int own_font_data_len = -1;
1173
1.09M
        FT_Stream ft_strm = NULL;
1174
1175
        /* dpf("gs_fapi_ft_get_scaled_font creating face\n"); */
1176
1177
1.09M
        if (a_font->full_font_buf) {
1178
1179
14.3k
            own_font_data =
1180
14.3k
                gs_malloc(((gs_memory_t *) (s->ftmemory->user)),
1181
14.3k
                          a_font->full_font_buf_len, 1,
1182
14.3k
                          "gs_fapi_ft_get_scaled_font - full font buf");
1183
14.3k
            if (!own_font_data) {
1184
0
                return_error(gs_error_VMerror);
1185
0
            }
1186
1187
14.3k
            own_font_data_len = a_font->full_font_buf_len;
1188
14.3k
            memcpy(own_font_data, a_font->full_font_buf,
1189
14.3k
                   a_font->full_font_buf_len);
1190
1191
14.3k
            ft_error =
1192
14.3k
                FT_New_Memory_Face(s->freetype_library,
1193
14.3k
                                   (const FT_Byte *)own_font_data,
1194
14.3k
                                   own_font_data_len, a_font->subfont,
1195
14.3k
                                   &ft_face);
1196
1197
14.3k
            if (ft_error) {
1198
864
                gs_memory_t * mem = (gs_memory_t *) s->ftmemory->user;
1199
864
                gs_free(mem, own_font_data, 0, 0, "FF_open_read_stream");
1200
864
                return ft_to_gs_error(ft_error);
1201
864
            }
1202
14.3k
        }
1203
        /* Load a typeface from a file. */
1204
1.07M
        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
0
                return ft_to_gs_error(ft_error);
1225
0
            }
1226
0
        }
1227
1228
        /* Load a typeface from a representation in GhostScript's memory. */
1229
1.07M
        else {
1230
1.07M
            FT_Open_Args open_args;
1231
1232
1.07M
            open_args.flags = FT_OPEN_MEMORY;
1233
1.07M
            open_args.stream = NULL;
1234
1235
1.07M
            if (a_font->is_type1) {
1236
1.05M
                long length;
1237
1.05M
                unsigned short type = 0;
1238
1239
1.05M
                code = a_font->get_word(a_font, gs_fapi_font_feature_FontType, 0, &type);
1240
1.05M
                if (code < 0) {
1241
0
                    return code;
1242
0
                }
1243
1244
                /* Tell the FAPI interface that we need to decrypt the /Subrs data. */
1245
1.05M
                a_font->need_decrypt = true;
1246
1247
                /*
1248
                   Serialise a type 1 font in PostScript source form, or
1249
                   a Type 2 font in binary form, so that FreeType can read it.
1250
                 */
1251
1.05M
                if (type == 1)
1252
1.04M
                    length = gs_fapi_serialize_type1_font(a_font, NULL, 0);
1253
12.3k
                else
1254
12.3k
                    length = gs_fapi_serialize_type2_font(a_font, NULL, 0);
1255
1256
1.05M
                open_args.memory_base = own_font_data =
1257
1.05M
                    FF_alloc(s->ftmemory, length);
1258
1.05M
                if (!open_args.memory_base)
1259
56
                    return_error(gs_error_VMerror);
1260
1.05M
                own_font_data_len = length;
1261
1.05M
                if (type == 1)
1262
1.04M
                    open_args.memory_size =
1263
1.04M
                        gs_fapi_serialize_type1_font(a_font, own_font_data, length);
1264
12.3k
                else
1265
12.3k
                    open_args.memory_size =
1266
12.3k
                        gs_fapi_serialize_type2_font(a_font, own_font_data, length);
1267
1268
1.05M
                if (open_args.memory_size != length)
1269
0
                    return_error(gs_error_unregistered);        /* Must not happen. */
1270
1271
1.05M
                ft_inc_int = new_inc_int(a_server, a_font);
1272
1.05M
                if (!ft_inc_int) {
1273
0
                    FF_free(s->ftmemory, own_font_data);
1274
0
                    return_error(gs_error_VMerror);
1275
0
                }
1276
1.05M
            }
1277
1278
            /* It must be type 42 (see code in FAPI_FF_get_glyph in zfapi.c). */
1279
21.1k
            else {
1280
                /* Get the length of the TrueType data. */
1281
1282
21.1k
                if (a_font->retrieve_tt_font != NULL) {
1283
21.1k
                    unsigned int ms;
1284
21.1k
                    code = a_font->retrieve_tt_font(a_font, (void **)&own_font_data, &ms);
1285
21.1k
                    if (code == 0) {
1286
21.1k
                        data_owned = false;
1287
21.1k
                        open_args.memory_base = own_font_data;
1288
21.1k
                        open_args.memory_size = own_font_data_len = ms;
1289
21.1k
                    }
1290
21.1k
                }
1291
29
                else
1292
29
                    code = gs_error_unregistered;
1293
1294
21.1k
                if (code < 0) {
1295
29
                    unsigned long lms;
1296
29
                    code = a_font->get_long(a_font, gs_fapi_font_feature_TT_size, 0, &lms);
1297
29
                    if (code < 0)
1298
0
                        return code;
1299
29
                    if (lms == 0)
1300
0
                        return_error(gs_error_invalidfont);
1301
1302
29
                    open_args.memory_size = (FT_Long)lms;
1303
1304
                    /* Load the TrueType data into a single buffer. */
1305
29
                    open_args.memory_base = own_font_data =
1306
29
                        FF_alloc(s->ftmemory, open_args.memory_size);
1307
29
                    if (!own_font_data)
1308
0
                        return_error(gs_error_VMerror);
1309
1310
29
                    own_font_data_len = open_args.memory_size;
1311
1312
29
                    code = a_font->serialize_tt_font(a_font, own_font_data,
1313
29
                                          open_args.memory_size);
1314
29
                    if (code < 0)
1315
26
                        return code;
1316
29
                }
1317
1318
                /* We always load incrementally. */
1319
21.1k
                ft_inc_int = new_inc_int(a_server, a_font);
1320
21.1k
                if (!ft_inc_int) {
1321
0
                    if (data_owned)
1322
0
                        FF_free(s->ftmemory, own_font_data);
1323
0
                    return_error(gs_error_VMerror);
1324
0
                }
1325
21.1k
            }
1326
1327
1.07M
            if (ft_inc_int) {
1328
1.07M
                open_args.flags =
1329
1.07M
                    (FT_UInt) (open_args.flags | FT_OPEN_PARAMS);
1330
1.07M
                ft_param.tag = FT_PARAM_TAG_INCREMENTAL;
1331
1.07M
                ft_param.data = ft_inc_int;
1332
1.07M
                open_args.num_params = 1;
1333
1.07M
                open_args.params = &ft_param;
1334
1.07M
            }
1335
1.07M
            ft_error =
1336
1.07M
                FT_Open_Face(s->freetype_library, &open_args, a_font->subfont,
1337
1.07M
                             &ft_face);
1338
1.07M
            if (ft_error) {
1339
2.02k
                delete_inc_int (a_server, ft_inc_int);
1340
2.02k
                if (data_owned)
1341
40
                    FF_free(s->ftmemory, own_font_data);
1342
2.02k
                return ft_to_gs_error(ft_error);
1343
2.02k
            }
1344
1.07M
        }
1345
1346
1.08M
        if (ft_face) {
1347
1.08M
            face =
1348
1.08M
                new_face(a_server, ft_face, ft_inc_int, ft_strm,
1349
1.08M
                         own_font_data, own_font_data_len, data_owned);
1350
1.08M
            if (!face) {
1351
0
                if (data_owned)
1352
0
                    FF_free(s->ftmemory, own_font_data);
1353
0
                FT_Done_Face(ft_face);
1354
0
                delete_inc_int(a_server, ft_inc_int);
1355
0
                return_error(gs_error_VMerror);
1356
0
            }
1357
1.08M
            a_font->server_font_data = face;
1358
1359
1.08M
            if (!a_font->is_type1) {
1360
91.0k
                for (i = 0; i < GS_FAPI_NUM_TTF_CMAP_REQ && !cmap; i++) {
1361
64.8k
                    if (a_font->ttf_cmap_req[i].platform_id > 0) {
1362
104k
                        for (j = 0; j < face->ft_face->num_charmaps; j++) {
1363
71.8k
                            if (FT_Get_CMap_Format(face->ft_face->charmaps[j]) >= 0
1364
71.8k
                             && face->ft_face->charmaps[j]->platform_id == a_font->ttf_cmap_req[i].platform_id
1365
71.8k
                             && face->ft_face->charmaps[j]->encoding_id == a_font->ttf_cmap_req[i].encoding_id) {
1366
1367
26.2k
                                cmap = face->ft_face->charmaps[j];
1368
26.2k
                                break;
1369
26.2k
                            }
1370
71.8k
                        }
1371
58.4k
                    }
1372
6.35k
                    else {
1373
6.35k
                        break;
1374
6.35k
                    }
1375
64.8k
                }
1376
32.6k
                if (cmap) {
1377
26.2k
                    (void)FT_Set_Charmap(face->ft_face, cmap);
1378
26.2k
                }
1379
6.35k
                else if (a_font->full_font_buf != NULL || a_font->font_file_path != NULL) {
1380
                    /* If we've passed a complete TTF to Freetype, but *haven't* requested a
1381
                     * specific cmap table above, try to use a Unicode one
1382
                     * If that doesn't work, just leave the default in place.
1383
                     */
1384
4.06k
                    (void)FT_Select_Charmap(face->ft_face, ft_encoding_unicode);
1385
4.06k
                }
1386
                /* For PDF, we have to know which cmap table actually was selected */
1387
32.6k
                if (face->ft_face->charmap != NULL) {
1388
26.7k
                    a_font->ttf_cmap_selected.platform_id = face->ft_face->charmap->platform_id;
1389
26.7k
                    a_font->ttf_cmap_selected.encoding_id = face->ft_face->charmap->encoding_id;
1390
26.7k
                }
1391
5.87k
                else {
1392
                    /* Just in case */
1393
5.87k
                    a_font->ttf_cmap_selected.platform_id = -1;
1394
5.87k
                    a_font->ttf_cmap_selected.encoding_id = -1;
1395
5.87k
                }
1396
32.6k
            }
1397
1.05M
            else {
1398
                /* Just in case */
1399
1.05M
                a_font->ttf_cmap_selected.platform_id = -1;
1400
1.05M
                a_font->ttf_cmap_selected.encoding_id = -1;
1401
1.05M
            }
1402
1.08M
        }
1403
0
        else
1404
0
            a_font->server_font_data = NULL;
1405
1.08M
    }
1406
1407
    /* Set the point size and transformation.
1408
     * The matrix is scaled by the shift specified in the server, 16,
1409
     * so we divide by 65536 when converting to a gs_matrix.
1410
     */
1411
3.45M
    if (face) {
1412
        /* Convert the GS transform into an FT transform.
1413
         * Ignore the translation elements because they contain very large values
1414
         * derived from the current transformation matrix and so are of no use.
1415
         */
1416
3.45M
        face->ft_transform.xx = a_font_scale->matrix[0];
1417
3.45M
        face->ft_transform.xy = a_font_scale->matrix[2];
1418
3.45M
        face->ft_transform.yx = a_font_scale->matrix[1];
1419
3.45M
        face->ft_transform.yy = a_font_scale->matrix[3];
1420
1421
3.45M
        face->horz_res = a_font_scale->HWResolution[0] >> 16;
1422
3.45M
        face->vert_res = a_font_scale->HWResolution[1] >> 16;
1423
1424
        /* Split the transform into scale factors and a rotation-and-shear
1425
         * transform.
1426
         */
1427
3.45M
        transform_decompose(&face->ft_transform, &face->horz_res,
1428
3.45M
                            &face->vert_res, &face->width, &face->height, face->ft_face->units_per_EM);
1429
1430
3.45M
        ft_error = FT_Set_Char_Size(face->ft_face, face->width, face->height,
1431
3.45M
                                    face->horz_res, face->vert_res);
1432
1433
3.45M
        if (ft_error) {
1434
            /* The code originally cleaned up the face data here, but the "top level"
1435
               font object still has references to the face data, and we've no way
1436
               to tell it it's gone. So we defer releasing the data until the garbage
1437
               collector collects the font object, and the font's finalize call will
1438
               free the data correctly for us.
1439
             */
1440
143
            return ft_to_gs_error(ft_error);
1441
143
        }
1442
1443
        /* Concatenate the transform to a reflection around (y=0) so that it
1444
         * produces a glyph that is upside down in FreeType terms, with its
1445
         * first row at the bottom. That is what GhostScript needs.
1446
         */
1447
1448
3.45M
        FT_Set_Transform(face->ft_face, &face->ft_transform, NULL);
1449
1450
3.45M
    }
1451
1452
    /* dpf("gs_fapi_ft_get_scaled_font return %d\n", a_font->server_font_data ? 0 : -1); */
1453
3.45M
    return a_font->server_font_data ? 0 : -1;
1454
3.45M
}
1455
1456
/*
1457
 * Return the name of a resource which maps names to character codes. Do this
1458
 * by setting a_decoding_id to point to a null-terminated string. The resource
1459
 * is in the 'decoding' directory in the directory named by /GenericResourceDir
1460
 * in lib/gs_res.ps.
1461
 */
1462
static gs_fapi_retcode
1463
gs_fapi_ft_get_decodingID(gs_fapi_server * a_server, gs_fapi_font * a_font,
1464
               const char **a_decoding_id)
1465
13.3k
{
1466
13.3k
    *a_decoding_id = "Unicode";
1467
13.3k
    return 0;
1468
13.3k
}
1469
1470
/*
1471
 * Get the font bounding box in font units.
1472
 */
1473
static gs_fapi_retcode
1474
gs_fapi_ft_get_font_bbox(gs_fapi_server * a_server, gs_fapi_font * a_font, int a_box[4], int unitsPerEm[2])
1475
942k
{
1476
942k
    ff_face *face = (ff_face *) a_font->server_font_data;
1477
1478
942k
    a_box[0] = face->ft_face->bbox.xMin;
1479
942k
    a_box[1] = face->ft_face->bbox.yMin;
1480
942k
    a_box[2] = face->ft_face->bbox.xMax;
1481
942k
    a_box[3] = face->ft_face->bbox.yMax;
1482
1483
942k
    unitsPerEm[0] = unitsPerEm[1] = face->ft_face->units_per_EM;
1484
1485
942k
    return 0;
1486
942k
}
1487
1488
/*
1489
 * Return a boolean value in a_proportional stating whether the font is proportional
1490
 * or fixed-width.
1491
 */
1492
static gs_fapi_retcode
1493
gs_fapi_ft_get_font_proportional_feature(gs_fapi_server * a_server,
1494
                              gs_fapi_font * a_font, bool * a_proportional)
1495
0
{
1496
0
    *a_proportional = true;
1497
0
    return 0;
1498
0
}
1499
1500
/* Convert the character name in a_char_ref.char_name to a character code or
1501
 * glyph index and put it in a_char_ref.char_code, setting
1502
 * a_char_ref.is_glyph_index as appropriate. If this is possible set a_result
1503
 * to true, otherwise set it to false.  The return value is a standard error
1504
 * return code.
1505
 */
1506
static gs_fapi_retcode
1507
gs_fapi_ft_can_retrieve_char_by_name(gs_fapi_server * a_server, gs_fapi_font * a_font,
1508
                          gs_fapi_char_ref * a_char_ref, bool * a_result)
1509
0
{
1510
0
    ff_face *face = (ff_face *) a_font->server_font_data;
1511
0
    char name[128];
1512
1513
0
    if (FT_HAS_GLYPH_NAMES(face->ft_face)
1514
0
        && a_char_ref->char_name_length < sizeof(name)) {
1515
0
        memcpy(name, a_char_ref->char_name, a_char_ref->char_name_length);
1516
0
        name[a_char_ref->char_name_length] = 0;
1517
0
        a_char_ref->char_codes[0] = FT_Get_Name_Index(face->ft_face, name);
1518
0
        *a_result = a_char_ref->char_codes[0] != 0;
1519
0
        if (*a_result)
1520
0
            a_char_ref->is_glyph_index = true;
1521
0
    }
1522
0
    else
1523
0
        *a_result = false;
1524
0
    return 0;
1525
0
}
1526
1527
/*
1528
 * Return non-zero if the metrics can be replaced.
1529
 */
1530
static gs_fapi_retcode
1531
gs_fapi_ft_can_replace_metrics(gs_fapi_server * a_server, gs_fapi_font * a_font,
1532
                    gs_fapi_char_ref * a_char_ref, int *a_result)
1533
14.6M
{
1534
    /* Replace metrics only if the metrics are supplied in font units. */
1535
14.6M
    *a_result = 1;
1536
14.6M
    return 0;
1537
14.6M
}
1538
1539
/*
1540
 * Retrieve the metrics of a_char_ref and put them in a_metrics.
1541
 */
1542
static gs_fapi_retcode
1543
gs_fapi_ft_get_char_width(gs_fapi_server * a_server, gs_fapi_font * a_font,
1544
               gs_fapi_char_ref * a_char_ref, gs_fapi_metrics * a_metrics)
1545
0
{
1546
0
    ff_server *s = (ff_server *) a_server;
1547
1548
0
    return load_glyph(a_server, a_font, a_char_ref, a_metrics,
1549
0
                      (FT_Glyph *) & s->outline_glyph,
1550
0
                      false, a_server->max_bitmap);
1551
0
}
1552
1553
static gs_fapi_retcode
1554
gs_fapi_ft_get_fontmatrix(gs_fapi_server * server, gs_matrix * m)
1555
28.7M
{
1556
28.7M
    m->xx = 1.0;
1557
28.7M
    m->xy = 0.0;
1558
28.7M
    m->yx = 0.0;
1559
28.7M
    m->yy = 1.0;
1560
28.7M
    m->tx = 0.0;
1561
28.7M
    m->ty = 0.0;
1562
28.7M
    return 0;
1563
28.7M
}
1564
1565
/*
1566
 * Rasterize the character a_char and return its metrics. Do not return the
1567
 * bitmap but store this. It can be retrieved by a subsequent call to
1568
 * gs_fapi_ft_get_char_raster.
1569
 */
1570
static gs_fapi_retcode
1571
gs_fapi_ft_get_char_raster_metrics(gs_fapi_server * a_server, gs_fapi_font * a_font,
1572
                        gs_fapi_char_ref * a_char_ref,
1573
                        gs_fapi_metrics * a_metrics)
1574
11.1M
{
1575
11.1M
    ff_server *s = (ff_server *) a_server;
1576
11.1M
    gs_fapi_retcode error =
1577
11.1M
        load_glyph(a_server, a_font, a_char_ref, a_metrics,
1578
11.1M
                   (FT_Glyph *) & s->bitmap_glyph, true,
1579
11.1M
                   a_server->max_bitmap);
1580
11.1M
    return error;
1581
11.1M
}
1582
1583
/*
1584
 * Return the bitmap created by the last call to gs_fapi_ft_get_char_raster_metrics.
1585
 */
1586
static gs_fapi_retcode
1587
gs_fapi_ft_get_char_raster(gs_fapi_server * a_server, gs_fapi_raster * a_raster)
1588
13.6M
{
1589
13.6M
    ff_server *s = (ff_server *) a_server;
1590
1591
13.6M
    if (!s->bitmap_glyph)
1592
7.59M
        return(gs_error_unregistered);
1593
6.09M
    a_raster->p = s->bitmap_glyph->bitmap.buffer;
1594
6.09M
    a_raster->width = s->bitmap_glyph->bitmap.width;
1595
6.09M
    a_raster->height = s->bitmap_glyph->bitmap.rows;
1596
6.09M
    a_raster->line_step = s->bitmap_glyph->bitmap.pitch;
1597
6.09M
    a_raster->orig_x = s->bitmap_glyph->left * 16;
1598
6.09M
    a_raster->orig_y = s->bitmap_glyph->top * 16;
1599
6.09M
    a_raster->left_indent = a_raster->top_indent = a_raster->black_height =
1600
6.09M
        a_raster->black_width = 0;
1601
6.09M
    return 0;
1602
13.6M
}
1603
1604
/*
1605
 * Create an outline for the character a_char and return its metrics. Do not
1606
 * return the outline but store this.
1607
 * It can be retrieved by a subsequent call to gs_fapi_ft_get_char_outline.
1608
 */
1609
static gs_fapi_retcode
1610
gs_fapi_ft_get_char_outline_metrics(gs_fapi_server * a_server, gs_fapi_font * a_font,
1611
                         gs_fapi_char_ref * a_char_ref,
1612
                         gs_fapi_metrics * a_metrics)
1613
8.51M
{
1614
8.51M
    ff_server *s = (ff_server *) a_server;
1615
1616
8.51M
    return load_glyph(a_server, a_font, a_char_ref, a_metrics,
1617
8.51M
                      (FT_Glyph *) & s->outline_glyph, false,
1618
8.51M
                      a_server->max_bitmap);
1619
8.51M
}
1620
1621
typedef struct FF_path_info_s
1622
{
1623
    gs_fapi_path *path;
1624
    int64_t x;
1625
    int64_t y;
1626
    FT_Vector currentp;
1627
} FF_path_info;
1628
1629
static inline int
1630
FF_points_equal(const FT_Vector *p1, const FT_Vector *p2)
1631
91.1M
{
1632
91.1M
    if (p1->x == p2->x && p1->y == p2->y)
1633
64.4k
        return 1;
1634
91.0M
    else
1635
91.0M
        return 0;
1636
91.1M
}
1637
1638
static int
1639
move_to(const FT_Vector * aTo, void *aObject)
1640
8.55M
{
1641
8.55M
    FF_path_info *p = (FF_path_info *) aObject;
1642
1643
8.55M
    p->currentp = *aTo;
1644
1645
    /* FAPI expects that co-ordinates will be as implied by frac_shift
1646
     * in our case 16.16 fixed precision. True for 'low level' FT
1647
     * routines (apparently), it isn't true for these routines where
1648
     * FT returns a 26.6 format. Rescale to 16.16 so that FAPI will
1649
     * be able to convert to GS co-ordinates properly.
1650
     */
1651
    /* FAPI now expects these coordinates in 32.32 */
1652
8.55M
    p->x = ((int64_t) aTo->x) << 26;
1653
8.55M
    p->y = ((int64_t) aTo->y) << 26;
1654
1655
8.55M
    return p->path->moveto(p->path, p->x, p->y) ? -1 : 0;
1656
8.55M
}
1657
1658
static int
1659
line_to(const FT_Vector * aTo, void *aObject)
1660
38.2M
{
1661
38.2M
    FF_path_info *p = (FF_path_info *) aObject;
1662
1663
38.2M
    if (!FF_points_equal(&p->currentp, aTo)) {
1664
38.2M
        p->currentp = *aTo;
1665
1666
        /* See move_to() above */
1667
38.2M
        p->x = ((int64_t) aTo->x) << 26;
1668
38.2M
        p->y = ((int64_t) aTo->y) << 26;
1669
1670
38.2M
        return p->path->lineto(p->path, p->x, p->y) ? -1 : 0;
1671
38.2M
    }
1672
40.2k
    return 0;
1673
38.2M
}
1674
1675
static int
1676
conic_to(const FT_Vector * aControl, const FT_Vector * aTo, void *aObject)
1677
8.45M
{
1678
8.45M
    FF_path_info *p = (FF_path_info *) aObject;
1679
8.45M
    double x, y, Controlx, Controly;
1680
8.45M
    int64_t Control1x, Control1y, Control2x, Control2y;
1681
8.45M
    double sx, sy;
1682
1683
8.45M
    if (!FF_points_equal(&p->currentp, aControl) ||
1684
8.45M
        !FF_points_equal(&p->currentp, aTo) ||
1685
8.45M
        !FF_points_equal(aControl, aTo)) {
1686
8.45M
        p->currentp = *aTo;
1687
1688
        /* More complicated than above, we need to do arithmetic on the
1689
         * co-ordinates, so we want them as floats and we will convert the
1690
         * result into 16.16 fixed precision for FAPI
1691
         *
1692
         * NB this code is funcitonally the same as the original, but I don't believe
1693
         * the comment (below) to be what the code is actually doing....
1694
         *
1695
         * NB2: the comment below was wrong, even though the code was correct(!!)
1696
         * The comment has now been amended.
1697
         *
1698
         * Convert a quadratic spline to a cubic. Do this by changing the three points
1699
         * A, B and C to A, 2/3(B,A), 2/3(B,C), C - that is, the two cubic control points are
1700
         * a third of the way from the single quadratic control point to the end points. This
1701
         * gives the same curve as the original quadratic.
1702
         */
1703
1704
8.45M
        sx = (double) (p->x >> 32);
1705
8.45M
        sy = (double) (p->y >> 32);
1706
1707
8.45M
        x = aTo->x / 64.0;
1708
8.45M
        p->x = ((int64_t) float2fixed(x)) << 24;
1709
8.45M
        y = aTo->y / 64.0;
1710
8.45M
        p->y = ((int64_t) float2fixed(y)) << 24;
1711
8.45M
        Controlx = aControl->x / 64.0;
1712
8.45M
        Controly = aControl->y / 64.0;
1713
1714
8.45M
        Control1x = ((int64_t) float2fixed((sx + Controlx * 2) / 3)) << 24;
1715
8.45M
        Control1y = ((int64_t) float2fixed((sy + Controly * 2) / 3)) << 24;
1716
8.45M
        Control2x = ((int64_t) float2fixed((x + Controlx * 2) / 3)) << 24;
1717
8.45M
        Control2y = ((int64_t) float2fixed((y + Controly * 2) / 3)) << 24;
1718
1719
8.45M
        return p->path->curveto(p->path, Control1x,
1720
8.45M
                                Control1y,
1721
8.45M
                                Control2x, Control2y, p->x, p->y) ? -1 : 0;
1722
8.45M
    }
1723
1.18k
    return 0;
1724
8.45M
}
1725
1726
static int
1727
cubic_to(const FT_Vector * aControl1, const FT_Vector * aControl2,
1728
         const FT_Vector * aTo, void *aObject)
1729
44.3M
{
1730
44.3M
    FF_path_info *p = (FF_path_info *) aObject;
1731
44.3M
    int64_t Control1x, Control1y, Control2x, Control2y;
1732
1733
44.3M
    if (!FF_points_equal(&p->currentp, aControl1) ||
1734
44.3M
        !FF_points_equal(&p->currentp, aControl2) ||
1735
44.3M
        !FF_points_equal(&p->currentp, aTo) ||
1736
44.3M
        !FF_points_equal(aControl1, aControl2) ||
1737
44.3M
        !FF_points_equal(aControl1, aTo) ||
1738
44.3M
        !FF_points_equal(aControl2, aTo)) {
1739
44.3M
        p->currentp = *aTo;
1740
1741
        /* See move_to() above */
1742
44.3M
        p->x = ((int64_t) aTo->x) << 26;
1743
44.3M
        p->y = ((int64_t) aTo->y) << 26;
1744
1745
44.3M
        Control1x = ((int64_t) aControl1->x) << 26;
1746
44.3M
        Control1y = ((int64_t) aControl1->y) << 26;
1747
44.3M
        Control2x = ((int64_t) aControl2->x) << 26;
1748
44.3M
        Control2y = ((int64_t) aControl2->y) << 26;
1749
44.3M
        return p->path->curveto(p->path, Control1x, Control1y, Control2x,
1750
44.3M
                                Control2y, p->x, p->y) ? -1 : 0;
1751
44.3M
    }
1752
1.98k
    return 0;
1753
44.3M
}
1754
1755
static const FT_Outline_Funcs TheFtOutlineFuncs = {
1756
    move_to,
1757
    line_to,
1758
    conic_to,
1759
    cubic_to,
1760
    0,
1761
    0
1762
};
1763
1764
/*
1765
 * Return the outline created by the last call to gs_fapi_ft_get_char_outline_metrics.
1766
 */
1767
static gs_fapi_retcode
1768
gs_fapi_ft_get_char_outline(gs_fapi_server * a_server, gs_fapi_path * a_path)
1769
7.48M
{
1770
7.48M
    ff_server *s = (ff_server *) a_server;
1771
7.48M
    FF_path_info p;
1772
7.48M
    FT_Error ft_error = 0;
1773
1774
7.48M
    p.path = a_path;
1775
7.48M
    p.x = 0;
1776
7.48M
    p.y = 0;
1777
    /* If we got an error during glyph creation, we can get
1778
     * here with s->outline_glyph == NULL
1779
     */
1780
7.48M
    if (s->outline_glyph) {
1781
7.48M
        ft_error =
1782
7.48M
            FT_Outline_Decompose(&s->outline_glyph->outline, &TheFtOutlineFuncs,
1783
7.48M
                                 &p);
1784
7.48M
    }
1785
124
    else {
1786
124
        a_path->moveto(a_path, 0, 0);
1787
124
    }
1788
1789
7.48M
    if (a_path->gs_error == 0)
1790
7.21M
        a_path->closepath(a_path);
1791
7.48M
    return ft_to_gs_error(ft_error);
1792
7.48M
}
1793
1794
static gs_fapi_retcode
1795
gs_fapi_ft_release_char_data(gs_fapi_server * a_server)
1796
14.6M
{
1797
14.6M
    ff_server *s = (ff_server *) a_server;
1798
1799
14.6M
    if (s->outline_glyph) {
1800
7.52M
        FT_Outline_Done(s->freetype_library, &s->outline_glyph->outline);
1801
7.52M
        FF_free(s->ftmemory, s->outline_glyph);
1802
7.52M
    }
1803
1804
14.6M
    if (s->bitmap_glyph) {
1805
6.09M
        FT_Bitmap_Done(s->freetype_library, &s->bitmap_glyph->bitmap);
1806
6.09M
        FF_free(s->ftmemory, s->bitmap_glyph);
1807
6.09M
    }
1808
1809
14.6M
    s->outline_glyph = NULL;
1810
14.6M
    s->bitmap_glyph = NULL;
1811
14.6M
    return 0;
1812
14.6M
}
1813
1814
static gs_fapi_retcode
1815
gs_fapi_ft_release_typeface(gs_fapi_server * a_server, void *a_server_font_data)
1816
1.08M
{
1817
1.08M
    ff_face *face = (ff_face *) a_server_font_data;
1818
1819
1.08M
    delete_face(a_server, face);
1820
1.08M
    return 0;
1821
1.08M
}
1822
1823
static gs_fapi_retcode
1824
gs_fapi_ft_check_cmap_for_GID(gs_fapi_server * server, uint * index)
1825
10.5M
{
1826
10.5M
    ff_face *face = (ff_face *) (server->ff.server_font_data);
1827
10.5M
    FT_Face ft_face = face->ft_face;
1828
1829
10.5M
    *index = FT_Get_Char_Index(ft_face, *index);
1830
10.5M
    return 0;
1831
10.5M
}
1832
1833
static gs_fapi_retcode
1834
gs_fapi_ft_set_mm_weight_vector(gs_fapi_server *server, gs_fapi_font *ff, float *wvector, int length)
1835
0
{
1836
#if defined(SHARE_FT) && SHARE_FT == 1 && \
1837
    FREETYPE_MAJOR <= 2 && FREETYPE_MINOR <= 9 && FREETYPE_PATCH <= 1
1838
1839
    return gs_error_invalidaccess;
1840
#else
1841
0
    ff_face *face = (ff_face *) ff->server_font_data;
1842
0
    FT_Fixed nwv[16] = {0};
1843
0
    FT_Fixed cwv[16] = {0};
1844
0
    FT_UInt len = 16;
1845
0
    int i;
1846
0
    bool setit = false;
1847
0
    FT_Error ft_error;
1848
0
    (void)server;
1849
1850
0
    ft_error = FT_Get_MM_WeightVector(face->ft_face, &len, cwv);
1851
0
    if (ft_error != 0) return_error(gs_error_invalidaccess);
1852
1853
0
    for (i = 0; i < length; i++) {
1854
0
        nwv[i] = (FT_Fixed)(wvector[i] * 65536.0);
1855
0
        if (nwv[i] != cwv[i]) {
1856
0
            setit = true;
1857
0
        }
1858
0
    }
1859
1860
0
    if (setit == true) {
1861
0
        ft_error = FT_Set_MM_WeightVector(face->ft_face, length, nwv);
1862
0
        if (ft_error != 0) return_error(gs_error_invalidaccess);
1863
0
    }
1864
1865
0
    return 0;
1866
0
#endif
1867
0
}
1868
1869
static void gs_fapi_freetype_destroy(gs_fapi_server ** serv);
1870
1871
static const gs_fapi_server_descriptor freetypedescriptor = {
1872
    (const char *)"FAPI",
1873
    (const char *)"FreeType",
1874
    gs_fapi_freetype_destroy
1875
};
1876
1877
static const gs_fapi_server freetypeserver = {
1878
    {&freetypedescriptor},
1879
    NULL,                       /* client_ctx_p */
1880
    16,                         /* frac_shift */
1881
    {gs_no_id},
1882
    {0},
1883
    0,
1884
    false,
1885
    false,
1886
    {1, 0, 0, 1, 0, 0},
1887
    1,
1888
    {1, 0, 0, 1, 0, 0},
1889
    gs_fapi_ft_ensure_open,
1890
    gs_fapi_ft_get_scaled_font,
1891
    gs_fapi_ft_get_decodingID,
1892
    gs_fapi_ft_get_font_bbox,
1893
    gs_fapi_ft_get_font_proportional_feature,
1894
    gs_fapi_ft_can_retrieve_char_by_name,
1895
    gs_fapi_ft_can_replace_metrics,
1896
    NULL,                       /* can_simulate_style */
1897
    gs_fapi_ft_get_fontmatrix,
1898
    gs_fapi_ft_get_char_width,
1899
    gs_fapi_ft_get_char_raster_metrics,
1900
    gs_fapi_ft_get_char_raster,
1901
    gs_fapi_ft_get_char_outline_metrics,
1902
    gs_fapi_ft_get_char_outline,
1903
    gs_fapi_ft_release_char_data,
1904
    gs_fapi_ft_release_typeface,
1905
    gs_fapi_ft_check_cmap_for_GID,
1906
    NULL,                        /* get_font_info */
1907
    gs_fapi_ft_set_mm_weight_vector,
1908
};
1909
1910
int gs_fapi_ft_init(gs_memory_t * mem, gs_fapi_server ** server);
1911
1912
int
1913
gs_fapi_ft_init(gs_memory_t * mem, gs_fapi_server ** server)
1914
159k
{
1915
159k
    ff_server *serv;
1916
159k
    int code = 0;
1917
159k
    gs_memory_t *cmem = mem->non_gc_memory;
1918
1919
159k
    code = gs_memory_chunk_wrap(&(cmem), mem);
1920
159k
    if (code != 0) {
1921
0
        return (code);
1922
0
    }
1923
1924
1925
159k
    serv = (ff_server *) gs_alloc_bytes_immovable(cmem, sizeof(ff_server), "gs_fapi_ft_init");
1926
159k
    if (!serv) {
1927
0
        gs_memory_chunk_release(cmem);
1928
0
        return_error(gs_error_VMerror);
1929
0
    }
1930
159k
    memset(serv, 0, sizeof(*serv));
1931
159k
    serv->mem = cmem;
1932
159k
    serv->fapi_server = freetypeserver;
1933
1934
159k
    serv->ftmemory = (FT_Memory) (&(serv->ftmemory_rec));
1935
1936
159k
    (*server) = (gs_fapi_server *) serv;
1937
159k
    return (0);
1938
159k
}
1939
1940
1941
void
1942
gs_fapi_freetype_destroy(gs_fapi_server ** serv)
1943
159k
{
1944
159k
    ff_server *server = (ff_server *) * serv;
1945
159k
    gs_memory_t *cmem = server->mem;
1946
1947
159k
    FT_Done_Glyph(&server->outline_glyph->root);
1948
159k
    FT_Done_Glyph(&server->bitmap_glyph->root);
1949
1950
    /* As with initialization: since we're supplying memory management to
1951
     * FT, we cannot just to use FT_Done_FreeType (), we have to use
1952
     * FT_Done_Library () and then discard the memory ourselves
1953
     */
1954
159k
    FT_Done_Library(server->freetype_library);
1955
159k
    gs_free(cmem, *serv, 0, 0, "gs_fapi_freetype_destroy: ff_server");
1956
159k
    *serv = NULL;
1957
159k
    gs_memory_chunk_release(cmem);
1958
159k
}