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 | */ |
14 | fz_glyph * |
15 | fz_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 | */ |
26 | void |
27 | fz_drop_glyph(fz_context *ctx, fz_glyph *glyph) |
28 | { |
29 | fz_drop_storable(ctx, &glyph->storable); |
30 | } |
31 | |
32 | static void |
33 | fz_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 | |
40 | fz_irect |
41 | fz_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 | |
51 | fz_irect |
52 | fz_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 | */ |
65 | int |
66 | fz_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 | */ |
74 | int |
75 | fz_glyph_height(fz_context *ctx, fz_glyph *glyph) |
76 | { |
77 | return glyph->h; |
78 | } |
79 | |
80 | #ifndef NDEBUG |
81 | #include <stdio.h> |
82 | |
83 | void |
84 | fz_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 | */ |
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 | /* |
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 | */ |
204 | fz_glyph * |
205 | fz_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. */ |
331 | try_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 | */ |
366 | fz_glyph * |
367 | fz_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. */ |
477 | try_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 | |