Coverage Report

Created: 2024-05-20 06:23

/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
235k
#define RLE_THRESHOLD 256
31
32
fz_glyph *
33
fz_keep_glyph(fz_context *ctx, fz_glyph *glyph)
34
4.06M
{
35
4.06M
  return fz_keep_storable(ctx, &glyph->storable);
36
4.06M
}
37
38
void
39
fz_drop_glyph(fz_context *ctx, fz_glyph *glyph)
40
4.78M
{
41
4.78M
  fz_drop_storable(ctx, &glyph->storable);
42
4.78M
}
43
44
static void
45
fz_drop_glyph_imp(fz_context *ctx, fz_storable *glyph_)
46
727k
{
47
727k
  fz_glyph *glyph = (fz_glyph *)glyph_;
48
727k
  fz_drop_pixmap(ctx, glyph->pixmap);
49
727k
  fz_free(ctx, glyph);
50
727k
}
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
4.31M
{
66
4.31M
  fz_irect bbox;
67
4.31M
  bbox.x0 = glyph->x;
68
4.31M
  bbox.y0 = glyph->y;
69
4.31M
  bbox.x1 = glyph->x + glyph->w;
70
4.31M
  bbox.y1 = glyph->y + glyph->h;
71
4.31M
  return bbox;
72
4.31M
}
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
10.5k
{
155
10.5k
  fz_glyph *glyph = NULL;
156
157
10.5k
  if (pix == NULL)
158
7.18k
    return NULL;
159
160
3.32k
  fz_var(glyph);
161
162
6.64k
  fz_try(ctx)
163
6.64k
  {
164
3.32k
    if (pix->n != 1 || pix->w * pix->h < RLE_THRESHOLD)
165
2.56k
    {
166
2.56k
      glyph = fz_malloc_struct(ctx, fz_glyph);
167
2.56k
      FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
168
2.56k
      glyph->x = pix->x;
169
2.56k
      glyph->y = pix->y;
170
2.56k
      glyph->w = pix->w;
171
2.56k
      glyph->h = pix->h;
172
2.56k
      glyph->size = fz_pixmap_size(ctx, pix);
173
2.56k
      glyph->pixmap = fz_keep_pixmap(ctx, pix);
174
2.56k
    }
175
761
    else
176
761
      glyph = fz_new_glyph_from_8bpp_data(ctx, pix->x, pix->y, pix->w, pix->h, pix->samples, pix->stride);
177
3.32k
  }
178
6.64k
  fz_always(ctx)
179
3.32k
  {
180
3.32k
    fz_drop_pixmap(ctx, pix);
181
3.32k
  }
182
3.32k
  fz_catch(ctx)
183
0
  {
184
0
    fz_rethrow(ctx);
185
0
  }
186
187
3.32k
  return glyph;
188
3.32k
}
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
724k
{
193
724k
  fz_glyph *glyph = NULL;
194
724k
  fz_pixmap *pix = NULL;
195
724k
  int size, fill, yy;
196
724k
  unsigned char *orig_sp = sp;
197
198
724k
  fz_var(glyph);
199
724k
  fz_var(pix);
200
201
1.44M
  fz_try(ctx)
202
1.44M
  {
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
724k
    if (w <= 6 || w * h < RLE_THRESHOLD)
207
654k
      goto try_pixmap;
208
209
69.6k
    size = h * w;
210
69.6k
    fill = h * sizeof(int);
211
69.6k
    glyph = Memento_label(fz_malloc(ctx, sizeof(fz_glyph) + size), "fz_glyph(8)");
212
69.6k
    FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
213
69.6k
    glyph->x = x;
214
69.6k
    glyph->y = y;
215
69.6k
    glyph->w = w;
216
69.6k
    glyph->h = h;
217
69.6k
    glyph->pixmap = NULL;
218
69.6k
    if (h == 0)
219
0
    {
220
0
      glyph->size = 0;
221
0
      break;
222
0
    }
223
9.65M
    for (yy=0; yy < h; yy++)
224
9.59M
    {
225
9.59M
      int nonblankfill = fill;
226
9.59M
      int nonblankfill_end = fill;
227
9.59M
      int linefill = fill;
228
9.59M
      int ww = w;
229
9.59M
      do
230
47.5M
      {
231
47.5M
        int code;
232
47.5M
        int len = ww;
233
47.5M
        int needed;
234
47.5M
        unsigned char *ep;
235
47.5M
        switch (*sp)
236
47.5M
        {
237
23.3M
        case 0:
238
23.3M
          if (len > 0x1000)
239
477k
            len = 0x1000;
240
23.3M
          ep = sp+len;
241
4.12G
          while (++sp != ep && *sp == 0);
242
23.3M
          code = 1;
243
23.3M
          len -= ep-sp;
244
23.3M
          ww -= len;
245
23.3M
          needed = fill + 1 + (len > 0x40);
246
23.3M
          break;
247
6.19M
        case 255:
248
6.19M
          if (len > 0x800)
249
444k
            len = 0x800;
250
6.19M
          ep = sp+len;
251
493M
          while (++sp != ep && *sp == 255);
252
6.19M
          code = 2;
253
6.19M
          len -= ep-sp;
254
6.19M
          ww -= len;
255
6.19M
          needed = fill + 1 + (len > 0x20);
256
6.19M
          break;
257
17.9M
        default:
258
17.9M
        {
259
17.9M
          unsigned char c;
260
17.9M
          if (len > 0x800)
261
810k
            len = 0x800;
262
17.9M
          ep = sp+len;
263
43.0M
          while (++sp != ep && (c = *sp) != 255 && c != 0);
264
17.9M
          len -= ep-sp;
265
17.9M
          ww -= len;
266
17.9M
          needed = fill + 1 + len + (len > 0x20);
267
17.9M
          code = 3;
268
17.9M
        }
269
47.5M
        }
270
47.5M
        if (needed > size)
271
2.21k
          goto try_pixmap;
272
47.5M
        if (code == 1)
273
23.3M
        {
274
23.3M
          if (len > 0x40)
275
7.74M
            glyph->data[fill++] = ((len-1)>>6)<<2;
276
23.3M
          glyph->data[fill++] = 1 | (((len-1)&63)<<2);
277
23.3M
        }
278
24.1M
        else
279
24.1M
        {
280
24.1M
          if (len > 0x20)
281
1.11M
            glyph->data[fill++] = ((len-1)>>5)<<2;
282
24.1M
          nonblankfill = fill;
283
24.1M
          glyph->data[fill++] = code | (((len-1)&31)<<3);
284
24.1M
          if (code == 3)
285
17.9M
          {
286
17.9M
            memcpy(&glyph->data[fill], sp - len, len);
287
17.9M
            fill += len;
288
17.9M
          }
289
24.1M
          nonblankfill_end = fill;
290
24.1M
        }
291
47.5M
      }
292
47.5M
      while (ww > 0);
293
9.58M
      if (nonblankfill_end == linefill)
294
1.56M
      {
295
1.56M
        ((int *)(glyph->data))[yy] = -1;
296
1.56M
        fill = linefill;
297
1.56M
      }
298
8.02M
      else
299
8.02M
      {
300
8.02M
        glyph->data[nonblankfill] |= 4;
301
8.02M
        fill = nonblankfill_end;
302
8.02M
        ((int *)(glyph->data))[yy] = linefill;
303
8.02M
      }
304
9.58M
      sp += span - w;
305
9.58M
    }
306
67.3k
    if (fill != size)
307
67.3k
    {
308
67.3k
      glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph) + fill);
309
67.3k
      size = fill;
310
67.3k
    }
311
67.3k
    glyph->size = size;
312
67.3k
    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
657k
try_pixmap:
318
657k
    glyph = Memento_label(fz_realloc(ctx, glyph, sizeof(fz_glyph)), "fz_glyph(8r)");
319
657k
    FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
320
657k
    pix = fz_new_pixmap_from_8bpp_data(ctx, x, y, w, h, orig_sp, span);
321
657k
    glyph->x = pix->x;
322
657k
    glyph->y = pix->y;
323
657k
    glyph->w = pix->w;
324
657k
    glyph->h = pix->h;
325
657k
    glyph->size = fz_pixmap_size(ctx, pix);
326
657k
    glyph->pixmap = pix;
327
657k
  }
328
1.44M
  fz_catch(ctx)
329
2
  {
330
2
    fz_drop_pixmap(ctx, pix);
331
2
    fz_free(ctx, glyph);
332
2
    fz_rethrow(ctx);
333
2
  }
334
335
724k
  return glyph;
336
724k
}
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
}