Coverage Report

Created: 2022-10-31 07:00

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