1#include "mupdf/fitz.h"
2
3#include <string.h>
4
5#define RLE_THRESHOLD 256
6
7/*
8 Take a reference to a glyph.
9
10 pix: The glyph to increment the reference for.
11
12 Returns pix.
13*/
14fz_glyph *
15fz_keep_glyph(fz_context *ctx, fz_glyph *glyph)
16{
17 return fz_keep_storable(ctx, &glyph->storable);
18}
19
20/*
21 Drop a reference and free a glyph.
22
23 Decrement the reference count for the glyph. When no
24 references remain the glyph will be freed.
25*/
26void
27fz_drop_glyph(fz_context *ctx, fz_glyph *glyph)
28{
29 fz_drop_storable(ctx, &glyph->storable);
30}
31
32static void
33fz_drop_glyph_imp(fz_context *ctx, fz_storable *glyph_)
34{
35 fz_glyph *glyph = (fz_glyph *)glyph_;
36 fz_drop_pixmap(ctx, glyph->pixmap);
37 fz_free(ctx, glyph);
38}
39
40fz_irect
41fz_glyph_bbox(fz_context *ctx, fz_glyph *glyph)
42{
43 fz_irect bbox;
44 bbox.x0 = glyph->x;
45 bbox.y0 = glyph->y;
46 bbox.x1 = glyph->x + glyph->w;
47 bbox.y1 = glyph->y + glyph->h;
48 return bbox;
49}
50
51fz_irect
52fz_glyph_bbox_no_ctx(fz_glyph *glyph)
53{
54 fz_irect bbox;
55 bbox.x0 = glyph->x;
56 bbox.y0 = glyph->y;
57 bbox.x1 = glyph->x + glyph->w;
58 bbox.y1 = glyph->y + glyph->h;
59 return bbox;
60}
61
62/*
63 Return the width of the glyph in pixels.
64*/
65int
66fz_glyph_width(fz_context *ctx, fz_glyph *glyph)
67{
68 return glyph->w;
69}
70
71/*
72 Return the height of the glyph in pixels.
73*/
74int
75fz_glyph_height(fz_context *ctx, fz_glyph *glyph)
76{
77 return glyph->h;
78}
79
80#ifndef NDEBUG
81#include <stdio.h>
82
83void
84fz_dump_glyph(fz_glyph *glyph)
85{
86 int x, y;
87
88 if (glyph->pixmap)
89 {
90 printf("pixmap glyph\n");
91 return;
92 }
93 printf("glyph: %dx%d @ (%d,%d)\n", glyph->w, glyph->h, glyph->x, glyph->y);
94
95 for (y = 0; y < glyph->h; y++)
96 {
97 int offset = ((int *)(glyph->data))[y];
98 if (offset >= 0)
99 {
100 int extend = 0;
101 int eol = 0;
102 x = glyph->w;
103 do
104 {
105 int v = glyph->data[offset++];
106 int len;
107 char c;
108 switch(v&3)
109 {
110 case 0: /* extend */
111 extend = v>>2;
112 len = 0;
113 break;
114 case 1: /* Transparent pixels */
115 len = 1 + (v>>2) + (extend<<6);
116 extend = 0;
117 c = '.';
118 break;
119 case 2: /* Solid pixels */
120 len = 1 + (v>>3) + (extend<<5);
121 extend = 0;
122 eol = v & 4;
123 c = (eol ? '$' :'#');
124 break;
125 default: /* Intermediate pixels */
126 len = 1 + (v>>3) + (extend<<5);
127 extend = 0;
128 offset += len;
129 eol = v & 4;
130 c = (eol ? '!' : '?');
131 break;
132 }
133 x -= len;
134 while (len--)
135 fputc(c, stdout);
136 if (eol)
137 break;
138 }
139 while (x > 0);
140 }
141 printf("\n");
142 }
143}
144#endif
145
146/*
147 Create a new glyph from a pixmap
148
149 Returns a pointer to the new glyph. Throws exception on failure to
150 allocate.
151*/
152fz_glyph *
153fz_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/*
191 Create a new glyph from 8bpp data
192
193 x, y: X and Y position for the glyph
194
195 w, h: Width and Height for the glyph
196
197 sp: Source Pointer to data
198
199 span: Increment from line to line of data
200
201 Returns a pointer to the new glyph. Throws exception on failure to
202 allocate.
203*/
204fz_glyph *
205fz_new_glyph_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
206{
207 fz_glyph *glyph = NULL;
208 fz_pixmap *pix = NULL;
209 int size, fill, yy;
210 unsigned char *orig_sp = sp;
211
212 fz_var(glyph);
213 fz_var(pix);
214
215 fz_try(ctx)
216 {
217 /* We start out by allocating space as large as the pixmap.
218 * If we need more than that give up on using RLE. We can
219 * never hope to beat the pixmap for really small sizes. */
220 if (w <= 6 || w * h < RLE_THRESHOLD)
221 goto try_pixmap;
222
223 size = h * w;
224 fill = h * sizeof(int);
225 glyph = fz_malloc(ctx, sizeof(fz_glyph) + size);
226 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
227 glyph->x = x;
228 glyph->y = y;
229 glyph->w = w;
230 glyph->h = h;
231 glyph->pixmap = NULL;
232 if (w == 0 || h == 0)
233 {
234 glyph->size = 0;
235 break;
236 }
237 for (yy=0; yy < h; yy++)
238 {
239 int nonblankfill = fill;
240 int nonblankfill_end = fill;
241 int linefill = fill;
242 int ww = w;
243 do
244 {
245 int code;
246 int len = ww;
247 int needed;
248 unsigned char *ep;
249 switch (*sp)
250 {
251 case 0:
252 if (len > 0x1000)
253 len = 0x1000;
254 ep = sp+len;
255 while (++sp != ep && *sp == 0);
256 code = 1;
257 len -= ep-sp;
258 ww -= len;
259 needed = fill + 1 + (len > 0x40);
260 break;
261 case 255:
262 if (len > 0x800)
263 len = 0x800;
264 ep = sp+len;
265 while (++sp != ep && *sp == 255);
266 code = 2;
267 len -= ep-sp;
268 ww -= len;
269 needed = fill + 1 + (len > 0x20);
270 break;
271 default:
272 {
273 unsigned char c;
274 if (len > 0x800)
275 len = 0x800;
276 ep = sp+len;
277 while (++sp != ep && (c = *sp) != 255 && c != 0);
278 len -= ep-sp;
279 ww -= len;
280 needed = fill + 1 + len + (len > 0x20);
281 code = 3;
282 }
283 }
284 if (needed > size)
285 goto try_pixmap;
286 if (code == 1)
287 {
288 if (len > 0x40)
289 glyph->data[fill++] = ((len-1)>>6)<<2;
290 glyph->data[fill++] = 1 | (((len-1)&63)<<2);
291 }
292 else
293 {
294 if (len > 0x20)
295 glyph->data[fill++] = ((len-1)>>5)<<2;
296 nonblankfill = fill;
297 glyph->data[fill++] = code | (((len-1)&31)<<3);
298 if (code == 3)
299 {
300 memcpy(&glyph->data[fill], sp - len, len);
301 fill += len;
302 }
303 nonblankfill_end = fill;
304 }
305 }
306 while (ww > 0);
307 if (nonblankfill_end == linefill)
308 {
309 ((int *)(glyph->data))[yy] = -1;
310 fill = linefill;
311 }
312 else
313 {
314 glyph->data[nonblankfill] |= 4;
315 fill = nonblankfill_end;
316 ((int *)(glyph->data))[yy] = linefill;
317 }
318 sp += span - w;
319 }
320 if (fill != size)
321 {
322 glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph) + fill);
323 size = fill;
324 }
325 glyph->size = size;
326 break;
327
328 /* Nasty use of a goto here, but it saves us having to exit
329 * and reenter the try context, and this routine is speed
330 * critical. */
331try_pixmap:
332 glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph));
333 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
334 pix = fz_new_pixmap_from_8bpp_data(ctx, x, y, w, h, orig_sp, span);
335 glyph->x = pix->x;
336 glyph->y = pix->y;
337 glyph->w = pix->w;
338 glyph->h = pix->h;
339 glyph->size = fz_pixmap_size(ctx, pix);
340 glyph->pixmap = pix;
341 }
342 fz_catch(ctx)
343 {
344 fz_drop_pixmap(ctx, pix);
345 fz_free(ctx, glyph);
346 fz_rethrow(ctx);
347 }
348
349 return glyph;
350}
351
352/*
353 Create a new glyph from 1bpp data
354
355 x, y: X and Y position for the glyph
356
357 w, h: Width and Height for the glyph
358
359 sp: Source Pointer to data
360
361 span: Increment from line to line of data
362
363 Returns a pointer to the new glyph. Throws exception on failure to
364 allocate.
365*/
366fz_glyph *
367fz_new_glyph_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
368{
369 fz_pixmap *pix = NULL;
370 fz_glyph *glyph = NULL;
371 int size, fill, yy;
372 unsigned char *orig_sp = sp;
373
374 fz_var(glyph);
375 fz_var(pix);
376
377 fz_try(ctx)
378 {
379 /* We start out by allocating space as large as the pixmap.
380 * If we need more than that give up on using RLE. We can
381 * never hope to beat the pixmap for really small sizes. */
382 if (w <= 6 || w * h < RLE_THRESHOLD)
383 goto try_pixmap;
384
385 size = h * w;
386 fill = h * sizeof(int);
387 glyph = fz_malloc(ctx, sizeof(fz_glyph) + size);
388 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
389 glyph->x = x;
390 glyph->y = y;
391 glyph->w = w;
392 glyph->h = h;
393 glyph->pixmap = NULL;
394 if (w == 0 || h == 0)
395 {
396 glyph->size = 0;
397 break;
398 }
399 for (yy=0; yy < h; yy++)
400 {
401 int nonblankfill = fill;
402 int nonblankfill_end = fill;
403 int linefill = fill;
404 int ww = w;
405 int bit = 0x80;
406 do
407 {
408 int len = 0;
409 int needed;
410 int b = *sp & bit;
411 bit >>= 1;
412 if (bit == 0)
413 bit = 0x80, sp++;
414 ww--;
415 if (b == 0)
416 {
417 while (ww > 0 && len < 0xfff && (*sp & bit) == 0)
418 {
419 bit >>= 1;
420 if (bit == 0)
421 bit = 0x80, sp++;
422 len++;
423 ww--;
424 }
425 needed = fill + (len >= 0x40) + 1;
426 if (needed > size)
427 goto try_pixmap;
428 if (len >= 0x40)
429 glyph->data[fill++] = (len>>6)<<2;
430 glyph->data[fill++] = 1 | ((len&63)<<2);
431 }
432 else
433 {
434 while (ww > 0 && len < 0x7ff && (*sp & bit) != 0)
435 {
436 bit >>= 1;
437 if (bit == 0)
438 bit = 0x80, sp++;
439 len++;
440 ww--;
441 }
442 needed = fill + (len >= 0x20) + 1;
443 if (needed > size)
444 goto try_pixmap;
445 if (len >= 0x20)
446 glyph->data[fill++] = (len>>5)<<2;
447 nonblankfill = fill;
448 glyph->data[fill++] = 2 | ((len&31)<<3);
449 nonblankfill_end = fill;
450 }
451 }
452 while (ww > 0);
453 if (nonblankfill_end == linefill)
454 {
455 ((int *)(glyph->data))[yy] = -1;
456 fill = linefill;
457 }
458 else
459 {
460 glyph->data[nonblankfill] |= 4;
461 fill = nonblankfill_end;
462 ((int *)(glyph->data))[yy] = linefill;
463 }
464 sp += span - (w>>3);
465 }
466 if (fill != size)
467 {
468 glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph) + fill);
469 size = fill;
470 }
471 glyph->size = size;
472 break;
473
474 /* Nasty use of a goto here, but it saves us having to exit
475 * and reenter the try context, and this routine is speed
476 * critical. */
477try_pixmap:
478 glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph));
479 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
480 pix = fz_new_pixmap_from_1bpp_data(ctx, x, y, w, h, orig_sp, span);
481 glyph->x = pix->x;
482 glyph->y = pix->y;
483 glyph->w = pix->w;
484 glyph->h = pix->h;
485 glyph->size = fz_pixmap_size(ctx, pix);
486 glyph->pixmap = pix;
487 }
488 fz_catch(ctx)
489 {
490 fz_drop_pixmap(ctx, pix);
491 fz_free(ctx, glyph);
492 fz_rethrow(ctx);
493 }
494
495 return glyph;
496}
497