Coverage Report

Created: 2025-09-04 06:50

/src/mupdf/source/fitz/glyph.c
Line
Count
Source (jump to first uncovered line)
1
// Copyright (C) 2004-2021 Artifex Software, Inc.
2
//
3
// This file is part of MuPDF.
4
//
5
// MuPDF is free software: you can redistribute it and/or modify it under the
6
// terms of the GNU Affero General Public License as published by the Free
7
// Software Foundation, either version 3 of the License, or (at your option)
8
// any later version.
9
//
10
// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
// details.
14
//
15
// You should have received a copy of the GNU Affero General Public License
16
// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17
//
18
// Alternative licensing terms are available from the licensor.
19
// For commercial licensing, see <https://www.artifex.com/> or contact
20
// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21
// CA 94129, USA, for further information.
22
23
#include "mupdf/fitz.h"
24
25
#include "glyph-imp.h"
26
#include "pixmap-imp.h"
27
28
#include <string.h>
29
30
77
#define RLE_THRESHOLD 256
31
32
fz_glyph *
33
fz_keep_glyph(fz_context *ctx, fz_glyph *glyph)
34
219
{
35
219
  return fz_keep_storable(ctx, &glyph->storable);
36
219
}
37
38
void
39
fz_drop_glyph(fz_context *ctx, fz_glyph *glyph)
40
338
{
41
338
  fz_drop_storable(ctx, &glyph->storable);
42
338
}
43
44
static void
45
fz_drop_glyph_imp(fz_context *ctx, fz_storable *glyph_)
46
119
{
47
119
  fz_glyph *glyph = (fz_glyph *)glyph_;
48
119
  fz_drop_pixmap(ctx, glyph->pixmap);
49
119
  fz_free(ctx, glyph);
50
119
}
51
52
fz_irect
53
fz_glyph_bbox(fz_context *ctx, fz_glyph *glyph)
54
0
{
55
0
  fz_irect bbox;
56
0
  bbox.x0 = glyph->x;
57
0
  bbox.y0 = glyph->y;
58
0
  bbox.x1 = glyph->x + glyph->w;
59
0
  bbox.y1 = glyph->y + glyph->h;
60
0
  return bbox;
61
0
}
62
63
fz_irect
64
fz_glyph_bbox_no_ctx(fz_glyph *glyph)
65
219
{
66
219
  fz_irect bbox;
67
219
  bbox.x0 = glyph->x;
68
219
  bbox.y0 = glyph->y;
69
219
  bbox.x1 = glyph->x + glyph->w;
70
219
  bbox.y1 = glyph->y + glyph->h;
71
219
  return bbox;
72
219
}
73
74
int
75
fz_glyph_width(fz_context *ctx, fz_glyph *glyph)
76
0
{
77
0
  return glyph->w;
78
0
}
79
80
int
81
fz_glyph_height(fz_context *ctx, fz_glyph *glyph)
82
0
{
83
0
  return glyph->h;
84
0
}
85
86
#ifndef NDEBUG
87
#include <stdio.h>
88
89
void
90
fz_dump_glyph(fz_glyph *glyph)
91
0
{
92
0
  int x, y;
93
94
0
  if (glyph->pixmap)
95
0
  {
96
0
    printf("pixmap glyph\n");
97
0
    return;
98
0
  }
99
0
  printf("glyph: %dx%d @ (%d,%d)\n", glyph->w, glyph->h, glyph->x, glyph->y);
100
101
0
  for (y = 0; y < glyph->h; y++)
102
0
  {
103
0
    int offset = ((int *)(glyph->data))[y];
104
0
    if (offset >= 0)
105
0
    {
106
0
      int extend = 0;
107
0
      int eol = 0;
108
0
      x = glyph->w;
109
0
      do
110
0
      {
111
0
        int v = glyph->data[offset++];
112
0
        int len;
113
0
        char c;
114
0
        switch(v&3)
115
0
        {
116
0
        case 0: /* extend */
117
0
          extend = v>>2;
118
0
          len = 0;
119
0
          break;
120
0
        case 1: /* Transparent pixels */
121
0
          len = 1 + (v>>2) + (extend<<6);
122
0
          extend = 0;
123
0
          c = '.';
124
0
          break;
125
0
        case 2: /* Solid pixels */
126
0
          len = 1 + (v>>3) + (extend<<5);
127
0
          extend = 0;
128
0
          eol = v & 4;
129
0
          c = (eol ? '$' :'#');
130
0
          break;
131
0
        default: /* Intermediate pixels */
132
0
          len = 1 + (v>>3) + (extend<<5);
133
0
          extend = 0;
134
0
          offset += len;
135
0
          eol = v & 4;
136
0
          c = (eol ? '!' : '?');
137
0
          break;
138
0
        }
139
0
        x -= len;
140
0
        while (len--)
141
0
          fputc(c, stdout);
142
0
        if (eol)
143
0
          break;
144
0
      }
145
0
      while (x > 0);
146
0
    }
147
0
    printf("\n");
148
0
  }
149
0
}
150
#endif
151
152
fz_glyph *
153
fz_new_glyph_from_pixmap(fz_context *ctx, fz_pixmap *pix)
154
0
{
155
0
  fz_glyph *glyph = NULL;
156
157
0
  if (pix == NULL)
158
0
    return NULL;
159
160
0
  fz_var(glyph);
161
162
0
  fz_try(ctx)
163
0
  {
164
0
    if (pix->n != 1 || pix->w * pix->h < RLE_THRESHOLD)
165
0
    {
166
0
      glyph = fz_malloc_struct(ctx, fz_glyph);
167
0
      FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
168
0
      glyph->x = pix->x;
169
0
      glyph->y = pix->y;
170
0
      glyph->w = pix->w;
171
0
      glyph->h = pix->h;
172
0
      glyph->size = fz_pixmap_size(ctx, pix);
173
0
      glyph->pixmap = fz_keep_pixmap(ctx, pix);
174
0
    }
175
0
    else
176
0
      glyph = fz_new_glyph_from_8bpp_data(ctx, pix->x, pix->y, pix->w, pix->h, pix->samples, pix->stride);
177
0
  }
178
0
  fz_always(ctx)
179
0
  {
180
0
    fz_drop_pixmap(ctx, pix);
181
0
  }
182
0
  fz_catch(ctx)
183
0
  {
184
0
    fz_rethrow(ctx);
185
0
  }
186
187
0
  return glyph;
188
0
}
189
190
fz_glyph *
191
fz_new_glyph_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
192
119
{
193
119
  fz_glyph *glyph = NULL;
194
119
  fz_pixmap *pix = NULL;
195
119
  int size, fill, yy;
196
119
  unsigned char *orig_sp = sp;
197
198
119
  fz_var(glyph);
199
119
  fz_var(pix);
200
201
238
  fz_try(ctx)
202
238
  {
203
    /* We start out by allocating space as large as the pixmap.
204
     * If we need more than that give up on using RLE. We can
205
     * never hope to beat the pixmap for really small sizes. */
206
119
    if (w <= 6 || w * h < RLE_THRESHOLD)
207
102
      goto try_pixmap;
208
209
17
    size = h * w;
210
17
    fill = h * sizeof(int);
211
17
    glyph = Memento_label(fz_malloc(ctx, sizeof(fz_glyph) + size), "fz_glyph(8)");
212
17
    FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
213
17
    glyph->x = x;
214
17
    glyph->y = y;
215
17
    glyph->w = w;
216
17
    glyph->h = h;
217
17
    glyph->pixmap = NULL;
218
17
    if (h == 0)
219
0
    {
220
0
      glyph->size = 0;
221
0
      break;
222
0
    }
223
313
    for (yy=0; yy < h; yy++)
224
301
    {
225
301
      int nonblankfill = fill;
226
301
      int nonblankfill_end = fill;
227
301
      int linefill = fill;
228
301
      int ww = w;
229
301
      do
230
2.17k
      {
231
2.17k
        int code;
232
2.17k
        int len = ww;
233
2.17k
        int needed;
234
2.17k
        unsigned char *ep;
235
2.17k
        switch (*sp)
236
2.17k
        {
237
551
        case 0:
238
551
          if (len > 0x1000)
239
0
            len = 0x1000;
240
551
          ep = sp+len;
241
2.34k
          while (++sp != ep && *sp == 0);
242
551
          code = 1;
243
551
          len -= ep-sp;
244
551
          ww -= len;
245
551
          needed = fill + 1 + (len > 0x40);
246
551
          break;
247
550
        case 255:
248
550
          if (len > 0x800)
249
0
            len = 0x800;
250
550
          ep = sp+len;
251
1.05k
          while (++sp != ep && *sp == 255);
252
550
          code = 2;
253
550
          len -= ep-sp;
254
550
          ww -= len;
255
550
          needed = fill + 1 + (len > 0x20);
256
550
          break;
257
1.07k
        default:
258
1.07k
        {
259
1.07k
          unsigned char c;
260
1.07k
          if (len > 0x800)
261
0
            len = 0x800;
262
1.07k
          ep = sp+len;
263
1.78k
          while (++sp != ep && (c = *sp) != 255 && c != 0);
264
1.07k
          len -= ep-sp;
265
1.07k
          ww -= len;
266
1.07k
          needed = fill + 1 + len + (len > 0x20);
267
1.07k
          code = 3;
268
1.07k
        }
269
2.17k
        }
270
2.17k
        if (needed > size)
271
5
          goto try_pixmap;
272
2.16k
        if (code == 1)
273
550
        {
274
550
          if (len > 0x40)
275
0
            glyph->data[fill++] = ((len-1)>>6)<<2;
276
550
          glyph->data[fill++] = 1 | (((len-1)&63)<<2);
277
550
        }
278
1.61k
        else
279
1.61k
        {
280
1.61k
          if (len > 0x20)
281
0
            glyph->data[fill++] = ((len-1)>>5)<<2;
282
1.61k
          nonblankfill = fill;
283
1.61k
          glyph->data[fill++] = code | (((len-1)&31)<<3);
284
1.61k
          if (code == 3)
285
1.06k
          {
286
1.06k
            memcpy(&glyph->data[fill], sp - len, len);
287
1.06k
            fill += len;
288
1.06k
          }
289
1.61k
          nonblankfill_end = fill;
290
1.61k
        }
291
2.16k
      }
292
2.16k
      while (ww > 0);
293
296
      if (nonblankfill_end == linefill)
294
0
      {
295
0
        ((int *)(glyph->data))[yy] = -1;
296
0
        fill = linefill;
297
0
      }
298
296
      else
299
296
      {
300
296
        glyph->data[nonblankfill] |= 4;
301
296
        fill = nonblankfill_end;
302
296
        ((int *)(glyph->data))[yy] = linefill;
303
296
      }
304
296
      sp += span - w;
305
296
    }
306
12
    if (fill != size)
307
12
    {
308
12
      glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph) + fill);
309
12
      size = fill;
310
12
    }
311
12
    glyph->size = size;
312
12
    break;
313
314
    /* Nasty use of a goto here, but it saves us having to exit
315
     * and reenter the try context, and this routine is speed
316
     * critical. */
317
107
try_pixmap:
318
107
    glyph = Memento_label(fz_realloc(ctx, glyph, sizeof(fz_glyph)), "fz_glyph(8r)");
319
107
    FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
320
107
    pix = fz_new_pixmap_from_8bpp_data(ctx, x, y, w, h, orig_sp, span);
321
107
    glyph->x = pix->x;
322
107
    glyph->y = pix->y;
323
107
    glyph->w = pix->w;
324
107
    glyph->h = pix->h;
325
107
    glyph->size = fz_pixmap_size(ctx, pix);
326
107
    glyph->pixmap = pix;
327
107
  }
328
238
  fz_catch(ctx)
329
0
  {
330
0
    fz_drop_pixmap(ctx, pix);
331
0
    fz_free(ctx, glyph);
332
0
    fz_rethrow(ctx);
333
0
  }
334
335
119
  return glyph;
336
119
}
337
338
fz_glyph *
339
fz_new_glyph_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
340
0
{
341
0
  fz_pixmap *pix = NULL;
342
0
  fz_glyph *glyph = NULL;
343
0
  int size, fill, yy;
344
0
  unsigned char *orig_sp = sp;
345
346
0
  fz_var(glyph);
347
0
  fz_var(pix);
348
349
0
  fz_try(ctx)
350
0
  {
351
    /* We start out by allocating space as large as the pixmap.
352
     * If we need more than that give up on using RLE. We can
353
     * never hope to beat the pixmap for really small sizes. */
354
0
    if (w <= 6 || w * h < RLE_THRESHOLD)
355
0
      goto try_pixmap;
356
357
0
    size = h * w;
358
0
    fill = h * sizeof(int);
359
0
    glyph = Memento_label(fz_malloc(ctx, sizeof(fz_glyph) + size), "fz_glyph(1)");
360
0
    FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
361
0
    glyph->x = x;
362
0
    glyph->y = y;
363
0
    glyph->w = w;
364
0
    glyph->h = h;
365
0
    glyph->pixmap = NULL;
366
0
    if (h == 0)
367
0
    {
368
0
      glyph->size = 0;
369
0
      break;
370
0
    }
371
0
    for (yy=0; yy < h; yy++)
372
0
    {
373
0
      int nonblankfill = fill;
374
0
      int nonblankfill_end = fill;
375
0
      int linefill = fill;
376
0
      int ww = w;
377
0
      int bit = 0x80;
378
0
      do
379
0
      {
380
0
        int len = 0;
381
0
        int needed;
382
0
        int b = *sp & bit;
383
0
        bit >>= 1;
384
0
        if (bit == 0)
385
0
          bit = 0x80, sp++;
386
0
        ww--;
387
0
        if (b == 0)
388
0
        {
389
0
          while (ww > 0 && len < 0xfff && (*sp & bit) == 0)
390
0
          {
391
0
            bit >>= 1;
392
0
            if (bit == 0)
393
0
              bit = 0x80, sp++;
394
0
            len++;
395
0
            ww--;
396
0
          }
397
0
          needed = fill + (len >= 0x40) + 1;
398
0
          if (needed > size)
399
0
            goto try_pixmap;
400
0
          if (len >= 0x40)
401
0
            glyph->data[fill++] = (len>>6)<<2;
402
0
          glyph->data[fill++] = 1 | ((len&63)<<2);
403
0
        }
404
0
        else
405
0
        {
406
0
          while (ww > 0 && len < 0x7ff && (*sp & bit) != 0)
407
0
          {
408
0
            bit >>= 1;
409
0
            if (bit == 0)
410
0
              bit = 0x80, sp++;
411
0
            len++;
412
0
            ww--;
413
0
          }
414
0
          needed = fill + (len >= 0x20) + 1;
415
0
          if (needed > size)
416
0
            goto try_pixmap;
417
0
          if (len >= 0x20)
418
0
            glyph->data[fill++] = (len>>5)<<2;
419
0
          nonblankfill = fill;
420
0
          glyph->data[fill++] = 2 | ((len&31)<<3);
421
0
          nonblankfill_end = fill;
422
0
        }
423
0
      }
424
0
      while (ww > 0);
425
0
      if (nonblankfill_end == linefill)
426
0
      {
427
0
        ((int *)(glyph->data))[yy] = -1;
428
0
        fill = linefill;
429
0
      }
430
0
      else
431
0
      {
432
0
        glyph->data[nonblankfill] |= 4;
433
0
        fill = nonblankfill_end;
434
0
        ((int *)(glyph->data))[yy] = linefill;
435
0
      }
436
0
      sp += span - (w>>3);
437
0
    }
438
0
    if (fill != size)
439
0
    {
440
0
      glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph) + fill);
441
0
      size = fill;
442
0
    }
443
0
    glyph->size = size;
444
0
    break;
445
446
    /* Nasty use of a goto here, but it saves us having to exit
447
     * and reenter the try context, and this routine is speed
448
     * critical. */
449
0
try_pixmap:
450
0
    glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph));
451
0
    FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
452
0
    pix = fz_new_pixmap_from_1bpp_data(ctx, x, y, w, h, orig_sp, span);
453
0
    glyph->x = pix->x;
454
0
    glyph->y = pix->y;
455
0
    glyph->w = pix->w;
456
0
    glyph->h = pix->h;
457
0
    glyph->size = fz_pixmap_size(ctx, pix);
458
0
    glyph->pixmap = pix;
459
0
  }
460
0
  fz_catch(ctx)
461
0
  {
462
0
    fz_drop_pixmap(ctx, pix);
463
0
    fz_free(ctx, glyph);
464
0
    fz_rethrow(ctx);
465
0
  }
466
467
0
  return glyph;
468
0
}