comparison mupdf-source/source/fitz/glyph.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
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 #define RLE_THRESHOLD 256
31
32 fz_glyph *
33 fz_keep_glyph(fz_context *ctx, fz_glyph *glyph)
34 {
35 return fz_keep_storable(ctx, &glyph->storable);
36 }
37
38 void
39 fz_drop_glyph(fz_context *ctx, fz_glyph *glyph)
40 {
41 fz_drop_storable(ctx, &glyph->storable);
42 }
43
44 static void
45 fz_drop_glyph_imp(fz_context *ctx, fz_storable *glyph_)
46 {
47 fz_glyph *glyph = (fz_glyph *)glyph_;
48 fz_drop_pixmap(ctx, glyph->pixmap);
49 fz_free(ctx, glyph);
50 }
51
52 fz_irect
53 fz_glyph_bbox(fz_context *ctx, fz_glyph *glyph)
54 {
55 fz_irect bbox;
56 bbox.x0 = glyph->x;
57 bbox.y0 = glyph->y;
58 bbox.x1 = glyph->x + glyph->w;
59 bbox.y1 = glyph->y + glyph->h;
60 return bbox;
61 }
62
63 fz_irect
64 fz_glyph_bbox_no_ctx(fz_glyph *glyph)
65 {
66 fz_irect bbox;
67 bbox.x0 = glyph->x;
68 bbox.y0 = glyph->y;
69 bbox.x1 = glyph->x + glyph->w;
70 bbox.y1 = glyph->y + glyph->h;
71 return bbox;
72 }
73
74 int
75 fz_glyph_width(fz_context *ctx, fz_glyph *glyph)
76 {
77 return glyph->w;
78 }
79
80 int
81 fz_glyph_height(fz_context *ctx, fz_glyph *glyph)
82 {
83 return glyph->h;
84 }
85
86 #ifndef NDEBUG
87 #include <stdio.h>
88
89 void
90 fz_dump_glyph(fz_glyph *glyph)
91 {
92 int x, y;
93
94 if (glyph->pixmap)
95 {
96 printf("pixmap glyph\n");
97 return;
98 }
99 printf("glyph: %dx%d @ (%d,%d)\n", glyph->w, glyph->h, glyph->x, glyph->y);
100
101 for (y = 0; y < glyph->h; y++)
102 {
103 int offset = ((int *)(glyph->data))[y];
104 if (offset >= 0)
105 {
106 int extend = 0;
107 int eol = 0;
108 x = glyph->w;
109 do
110 {
111 int v = glyph->data[offset++];
112 int len;
113 char c;
114 switch(v&3)
115 {
116 case 0: /* extend */
117 extend = v>>2;
118 len = 0;
119 break;
120 case 1: /* Transparent pixels */
121 len = 1 + (v>>2) + (extend<<6);
122 extend = 0;
123 c = '.';
124 break;
125 case 2: /* Solid pixels */
126 len = 1 + (v>>3) + (extend<<5);
127 extend = 0;
128 eol = v & 4;
129 c = (eol ? '$' :'#');
130 break;
131 default: /* Intermediate pixels */
132 len = 1 + (v>>3) + (extend<<5);
133 extend = 0;
134 offset += len;
135 eol = v & 4;
136 c = (eol ? '!' : '?');
137 break;
138 }
139 x -= len;
140 while (len--)
141 fputc(c, stdout);
142 if (eol)
143 break;
144 }
145 while (x > 0);
146 }
147 printf("\n");
148 }
149 }
150 #endif
151
152 fz_glyph *
153 fz_new_glyph_from_pixmap(fz_context *ctx, fz_pixmap *pix)
154 {
155 fz_glyph *glyph = NULL;
156
157 if (pix == NULL)
158 return NULL;
159
160 fz_var(glyph);
161
162 fz_try(ctx)
163 {
164 if (pix->n != 1 || pix->w * pix->h < RLE_THRESHOLD)
165 {
166 glyph = fz_malloc_struct(ctx, fz_glyph);
167 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
168 glyph->x = pix->x;
169 glyph->y = pix->y;
170 glyph->w = pix->w;
171 glyph->h = pix->h;
172 glyph->size = fz_pixmap_size(ctx, pix);
173 glyph->pixmap = fz_keep_pixmap(ctx, pix);
174 }
175 else
176 glyph = fz_new_glyph_from_8bpp_data(ctx, pix->x, pix->y, pix->w, pix->h, pix->samples, pix->stride);
177 }
178 fz_always(ctx)
179 {
180 fz_drop_pixmap(ctx, pix);
181 }
182 fz_catch(ctx)
183 {
184 fz_rethrow(ctx);
185 }
186
187 return glyph;
188 }
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 {
193 fz_glyph *glyph = NULL;
194 fz_pixmap *pix = NULL;
195 int size, fill, yy;
196 unsigned char *orig_sp = sp;
197
198 fz_var(glyph);
199 fz_var(pix);
200
201 fz_try(ctx)
202 {
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 if (w <= 6 || w * h < RLE_THRESHOLD)
207 goto try_pixmap;
208
209 size = h * w;
210 fill = h * sizeof(int);
211 glyph = Memento_label(fz_malloc(ctx, sizeof(fz_glyph) + size), "fz_glyph(8)");
212 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
213 glyph->x = x;
214 glyph->y = y;
215 glyph->w = w;
216 glyph->h = h;
217 glyph->pixmap = NULL;
218 if (h == 0)
219 {
220 glyph->size = 0;
221 break;
222 }
223 for (yy=0; yy < h; yy++)
224 {
225 int nonblankfill = fill;
226 int nonblankfill_end = fill;
227 int linefill = fill;
228 int ww = w;
229 do
230 {
231 int code;
232 int len = ww;
233 int needed;
234 unsigned char *ep;
235 switch (*sp)
236 {
237 case 0:
238 if (len > 0x1000)
239 len = 0x1000;
240 ep = sp+len;
241 while (++sp != ep && *sp == 0);
242 code = 1;
243 len -= ep-sp;
244 ww -= len;
245 needed = fill + 1 + (len > 0x40);
246 break;
247 case 255:
248 if (len > 0x800)
249 len = 0x800;
250 ep = sp+len;
251 while (++sp != ep && *sp == 255);
252 code = 2;
253 len -= ep-sp;
254 ww -= len;
255 needed = fill + 1 + (len > 0x20);
256 break;
257 default:
258 {
259 unsigned char c;
260 if (len > 0x800)
261 len = 0x800;
262 ep = sp+len;
263 while (++sp != ep && (c = *sp) != 255 && c != 0);
264 len -= ep-sp;
265 ww -= len;
266 needed = fill + 1 + len + (len > 0x20);
267 code = 3;
268 }
269 }
270 if (needed > size)
271 goto try_pixmap;
272 if (code == 1)
273 {
274 if (len > 0x40)
275 glyph->data[fill++] = ((len-1)>>6)<<2;
276 glyph->data[fill++] = 1 | (((len-1)&63)<<2);
277 }
278 else
279 {
280 if (len > 0x20)
281 glyph->data[fill++] = ((len-1)>>5)<<2;
282 nonblankfill = fill;
283 glyph->data[fill++] = code | (((len-1)&31)<<3);
284 if (code == 3)
285 {
286 memcpy(&glyph->data[fill], sp - len, len);
287 fill += len;
288 }
289 nonblankfill_end = fill;
290 }
291 }
292 while (ww > 0);
293 if (nonblankfill_end == linefill)
294 {
295 ((int *)(glyph->data))[yy] = -1;
296 fill = linefill;
297 }
298 else
299 {
300 glyph->data[nonblankfill] |= 4;
301 fill = nonblankfill_end;
302 ((int *)(glyph->data))[yy] = linefill;
303 }
304 sp += span - w;
305 }
306 if (fill != size)
307 {
308 glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph) + fill);
309 size = fill;
310 }
311 glyph->size = size;
312 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 try_pixmap:
318 glyph = Memento_label(fz_realloc(ctx, glyph, sizeof(fz_glyph)), "fz_glyph(8r)");
319 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
320 pix = fz_new_pixmap_from_8bpp_data(ctx, x, y, w, h, orig_sp, span);
321 glyph->x = pix->x;
322 glyph->y = pix->y;
323 glyph->w = pix->w;
324 glyph->h = pix->h;
325 glyph->size = fz_pixmap_size(ctx, pix);
326 glyph->pixmap = pix;
327 }
328 fz_catch(ctx)
329 {
330 fz_drop_pixmap(ctx, pix);
331 fz_free(ctx, glyph);
332 fz_rethrow(ctx);
333 }
334
335 return glyph;
336 }
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 {
341 fz_pixmap *pix = NULL;
342 fz_glyph *glyph = NULL;
343 int size, fill, yy;
344 unsigned char *orig_sp = sp;
345
346 fz_var(glyph);
347 fz_var(pix);
348
349 fz_try(ctx)
350 {
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 if (w <= 6 || w * h < RLE_THRESHOLD)
355 goto try_pixmap;
356
357 size = h * w;
358 fill = h * sizeof(int);
359 glyph = Memento_label(fz_malloc(ctx, sizeof(fz_glyph) + size), "fz_glyph(1)");
360 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
361 glyph->x = x;
362 glyph->y = y;
363 glyph->w = w;
364 glyph->h = h;
365 glyph->pixmap = NULL;
366 if (h == 0)
367 {
368 glyph->size = 0;
369 break;
370 }
371 for (yy=0; yy < h; yy++)
372 {
373 int nonblankfill = fill;
374 int nonblankfill_end = fill;
375 int linefill = fill;
376 int ww = w;
377 int bit = 0x80;
378 do
379 {
380 int len = 0;
381 int needed;
382 int b = *sp & bit;
383 bit >>= 1;
384 if (bit == 0)
385 bit = 0x80, sp++;
386 ww--;
387 if (b == 0)
388 {
389 while (ww > 0 && len < 0xfff && (*sp & bit) == 0)
390 {
391 bit >>= 1;
392 if (bit == 0)
393 bit = 0x80, sp++;
394 len++;
395 ww--;
396 }
397 needed = fill + (len >= 0x40) + 1;
398 if (needed > size)
399 goto try_pixmap;
400 if (len >= 0x40)
401 glyph->data[fill++] = (len>>6)<<2;
402 glyph->data[fill++] = 1 | ((len&63)<<2);
403 }
404 else
405 {
406 while (ww > 0 && len < 0x7ff && (*sp & bit) != 0)
407 {
408 bit >>= 1;
409 if (bit == 0)
410 bit = 0x80, sp++;
411 len++;
412 ww--;
413 }
414 needed = fill + (len >= 0x20) + 1;
415 if (needed > size)
416 goto try_pixmap;
417 if (len >= 0x20)
418 glyph->data[fill++] = (len>>5)<<2;
419 nonblankfill = fill;
420 glyph->data[fill++] = 2 | ((len&31)<<3);
421 nonblankfill_end = fill;
422 }
423 }
424 while (ww > 0);
425 if (nonblankfill_end == linefill)
426 {
427 ((int *)(glyph->data))[yy] = -1;
428 fill = linefill;
429 }
430 else
431 {
432 glyph->data[nonblankfill] |= 4;
433 fill = nonblankfill_end;
434 ((int *)(glyph->data))[yy] = linefill;
435 }
436 sp += span - (w>>3);
437 }
438 if (fill != size)
439 {
440 glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph) + fill);
441 size = fill;
442 }
443 glyph->size = size;
444 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 try_pixmap:
450 glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph));
451 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
452 pix = fz_new_pixmap_from_1bpp_data(ctx, x, y, w, h, orig_sp, span);
453 glyph->x = pix->x;
454 glyph->y = pix->y;
455 glyph->w = pix->w;
456 glyph->h = pix->h;
457 glyph->size = fz_pixmap_size(ctx, pix);
458 glyph->pixmap = pix;
459 }
460 fz_catch(ctx)
461 {
462 fz_drop_pixmap(ctx, pix);
463 fz_free(ctx, glyph);
464 fz_rethrow(ctx);
465 }
466
467 return glyph;
468 }