Coverage Report

Created: 2026-11-12 07:07

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