fix crashes reported by Debian Cylab Mayhem Team
[swftools.git] / lib / pdf / InfoOutputDev.cc
blobedfb7e7e59ce05a68b54e0dfadf13a06b82a6c1f
1 #include "../../config.h"
2 #include "Object.h"
3 #include "InfoOutputDev.h"
4 #include "SplashOutputDev.h"
5 #include "GfxState.h"
6 #include "CommonOutputDev.h"
7 #include "../log.h"
8 #include "../types.h"
9 #include "../q.h"
10 #include "../gfxdevice.h"
11 #include "../gfxfont.h"
12 #include <math.h>
13 #include <assert.h>
15 int config_unique_unicode = 1;
16 int config_poly2bitmap_pass1 = 0;
17 int config_skewedtobitmap_pass1 = 0;
18 int config_addspace = 1;
19 int config_fontquality = 10;
20 int config_bigchar = 0;
21 int config_marker_glyph = 0;
22 int config_normalize_fonts = 0;
23 int config_remove_font_transforms = 0;
24 int config_remove_invisible_outlines = 0;
26 static void* fontclass_clone(const void*_m) {
27 if(_m==0)
28 return 0;
29 const fontclass_t*m1=(const fontclass_t*)_m;
30 fontclass_t*m2 = (fontclass_t*)malloc(sizeof(fontclass_t));
31 *m2 = *m1;
32 m2->id = strdup(m1->id);
33 return m2;
35 static unsigned int fontclass_hash(const void*_m) {
36 if(!_m)
37 return 0;
38 const fontclass_t*m = (fontclass_t*)_m;
39 unsigned int h=0;
40 if(config_remove_font_transforms) {
41 U32 m00 = (*(U32*)&m->m00)&0xfff00000;
42 U32 m01 = (*(U32*)&m->m01)&0xfff00000;
43 U32 m10 = (*(U32*)&m->m10)&0xfff00000;
44 U32 m11 = (*(U32*)&m->m11)&0xfff00000;
45 h = crc32_add_bytes(h, (char*)&m00, sizeof(m00));
46 h = crc32_add_bytes(h, (char*)&m01, sizeof(m01));
47 h = crc32_add_bytes(h, (char*)&m10, sizeof(m10));
48 h = crc32_add_bytes(h, (char*)&m11, sizeof(m11));
50 if(config_remove_invisible_outlines) {
51 h = crc32_add_bytes(h, (char*)&m->alpha, 1);
53 return crc32_add_string(h, m->id);
55 static void fontclass_destroy(void*_m) {
56 fontclass_t*m = (fontclass_t*)_m;
57 free(m->id);m->id=0;
58 free(m);
60 static char fontclass_equals(const void*_m1, const void*_m2) {
61 const fontclass_t*m1=(const fontclass_t*)_m1;
62 const fontclass_t*m2=(const fontclass_t*)_m2;
63 if(!m1 || !m2)
64 return m1==m2;
66 if(config_remove_font_transforms) {
67 /* we do a binary comparison of the float32
68 bits here instead of a numerical comparison
69 to prevent the compiler from e.g. removing the
70 (float) cast during optimization, which would break
71 the equivalence between equals() and hash() (as
72 the hash is derived from the float32 values) */
73 if(((*(U32*)&m1->m00 ^ *(U32*)&m2->m00)&0xfff00000) ||
74 ((*(U32*)&m1->m01 ^ *(U32*)&m2->m01)&0xfff00000) ||
75 ((*(U32*)&m1->m10 ^ *(U32*)&m2->m10)&0xfff00000) ||
76 ((*(U32*)&m1->m11 ^ *(U32*)&m2->m11)&0xfff00000))
77 return 0;
79 if(config_remove_invisible_outlines) {
80 if(m1->alpha != m2->alpha)
81 return 0;
83 return !strcmp(m1->id, m2->id);
86 static type_t fontclass_type = {
87 fontclass_equals,
88 fontclass_hash,
89 fontclass_clone,
90 fontclass_destroy
93 InfoOutputDev::InfoOutputDev(XRef*xref)
95 num_links = 0;
96 num_jpeg_images = 0;
97 num_ppm_images = 0;
98 num_chars = 0;
99 num_fonts = 0;
100 num_polygons= 0;
101 num_layers = 0;
102 num_text_breaks = 0;
103 currentglyph = 0;
104 previous_was_char = 0;
105 SplashColor white = {255,255,255};
106 splash = new SplashOutputDev(splashModeRGB8,320,0,white,0,0);
107 splash->startDoc(xref);
108 last_font = 0;
109 current_type3_font = 0;
110 fontcache = dict_new2(&fontclass_type);
112 InfoOutputDev::~InfoOutputDev()
114 GHashIter*i;
116 DICT_ITERATE_DATA(this->fontcache, FontInfo*, fd) {
117 delete fd;
119 dict_destroy(this->fontcache);this->fontcache=0;
121 delete splash;splash=0;
124 void FontInfo::grow(int size)
126 if(size >= this->num_glyphs) {
127 this->glyphs = (GlyphInfo**)realloc(this->glyphs, sizeof(GlyphInfo*)*(size));
128 memset(&this->glyphs[this->num_glyphs], 0, sizeof(SplashPath*)*((size)-this->num_glyphs));
129 this->num_glyphs = size;
132 FontInfo::FontInfo(fontclass_t*fontclass)
134 if(config_remove_font_transforms) {
135 char buf[128];
136 static int counter=1;
137 sprintf(buf, "font%d", counter++);
138 this->id = strdup(buf);
139 } else {
140 this->id = strdup(fontclass->id);
143 this->fontclass = (fontclass_t*)fontclass_type.dup(fontclass);
144 this->seen = 0;
145 this->num_glyphs = 0;
146 this->glyphs = 0;
147 this->gfxfont = 0;
148 this->space_char = -1;
149 this->ascender = 0;
150 this->descender = 0;
151 this->scale = 1.0;
152 this->num_chars = 0;
153 this->num_spaces = 0;
154 resetPositioning();
156 FontInfo::~FontInfo()
158 if(this->id) {free(this->id);this->id=0;}
159 this->font = 0;
160 int t;
161 for(t=0;t<num_glyphs;t++) {
162 if(glyphs[t]) {
163 delete glyphs[t]->path;glyphs[t]->path = 0;
164 delete glyphs[t];
165 glyphs[t]=0;
168 free(glyphs);glyphs=0;
169 if(this->gfxfont)
170 gfxfont_free(this->gfxfont);
172 if(this->fontclass) {
173 fontclass_type.free(this->fontclass);
174 this->fontclass=0;
178 char FontInfo::usesSpaces()
180 if(this->num_chars &&
181 this->num_spaces / (double)this->num_chars >= 0.05) {
182 return 1;
184 return 0;
187 void FontInfo::resetPositioning()
189 this->lastchar = -1;
190 this->lastx = 0;
191 this->lasty = 0;
192 this->lastadvance = 0;
195 static int findSpace(gfxfont_t*font)
197 int first_space = -1;
198 int t;
199 for(t=0;t<font->num_glyphs;t++) {
200 gfxglyph_t*g = &font->glyphs[t];
201 if(GLYPH_IS_SPACE(g)) {
202 if(g->unicode == 32) {
203 /* now that we have found a space char, make sure it's unique */
204 int s;
205 for(s=0;s<font->num_glyphs;s++) {
206 if(s!=t && font->glyphs[s].unicode==32)
207 font->glyphs[s].unicode=0;
209 return t;
213 return -1;
216 static int addSpace(gfxfont_t*font)
218 /* first, make sure the new space char is the only char that'll use unicode 32 */
219 int t;
220 for(t=0;t<font->num_glyphs;t++) {
221 if(font->glyphs[t].unicode==32)
222 font->glyphs[t].unicode=0;
224 // createGfxFont reserves space for up to two extra characters, so we don't need to realloc.
225 int space_glyph = font->num_glyphs++;
226 gfxglyph_t*g = &font->glyphs[space_glyph];
227 memset(g, 0, sizeof(*g));
228 g->unicode = 32;
229 g->advance = fabs(font->ascent + font->descent) / 5.0;
230 if(font->max_unicode > 32)
231 font->unicode2glyph[32] = space_glyph;
232 #if 0
233 g->line = gfxline_makerectangle(0, -font->ascent, g->advance, font->descent);
234 #endif
235 return space_glyph;
238 static void transform_glyph(gfxglyph_t*g, fontclass_t*mm, double scale)
240 gfxmatrix_t m;
241 m.m00 = mm->m00 * scale;
242 m.m01 = mm->m01 * scale;
243 m.m10 = mm->m10 * scale;
244 m.m11 = mm->m11 * scale;
245 m.tx = 0;
246 m.ty = 0;
247 if(m.m00>0)
248 g->advance *= m.m00;
249 g->line = gfxline_clone(g->line);
250 gfxline_transform(g->line, &m);
253 void gfxfont_transform(gfxfont_t*font, gfxmatrix_t*m)
255 int t;
256 for(t=0;t<font->num_glyphs;t++) {
257 gfxglyph_t*g = &font->glyphs[t];
258 gfxline_t*line = g->line;
259 gfxline_transform(line, m);
260 if(m->m00>0)
261 g->advance *= m->m00;
265 gfxbbox_t gfxfont_bbox(gfxfont_t*font)
267 gfxbbox_t tmp = {0,0,0,0};
268 int t;
269 for(t=0;t<font->num_glyphs;t++) {
270 gfxline_t*line = font->glyphs[t].line;
271 gfxbbox_t b = gfxline_getbbox(line);
272 tmp = gfxbbox_expand_to_bbox(tmp, b);
274 return tmp;
277 gfxfont_t* FontInfo::createGfxFont()
279 gfxfont_t*font = (gfxfont_t*)rfx_calloc(sizeof(gfxfont_t));
281 font->glyphs = (gfxglyph_t*)malloc(sizeof(gfxglyph_t)*(this->num_glyphs+2));
282 memset(font->glyphs, 0, sizeof(gfxglyph_t)*this->num_glyphs);
283 font->id = 0;
284 int t;
286 double quality = (INTERNAL_FONT_SIZE * 200 / config_fontquality) / this->max_size;
287 //printf("%d glyphs\n", font->num_glyphs);
288 font->num_glyphs = 0;
289 font->ascent = fabs(this->ascender);
290 font->descent = fabs(this->descender);
292 for(t=0;t<this->num_glyphs;t++) {
293 if(this->glyphs[t]) {
294 SplashPath*path = this->glyphs[t]->path;
295 int len = path?path->getLength():0;
296 //printf("glyph %d) %08x (%d line segments)\n", t, path, len);
297 gfxglyph_t*glyph = &font->glyphs[font->num_glyphs];
298 this->glyphs[t]->glyphid = font->num_glyphs;
299 glyph->unicode = this->glyphs[t]->unicode;
300 gfxdrawer_t drawer;
301 gfxdrawer_target_gfxline(&drawer);
302 int s;
303 int count = 0;
304 double xmax = 0;
305 for(s=0;s<len;s++) {
306 Guchar f;
307 double x, y;
308 path->getPoint(s, &x, &y, &f);
309 if(!s || x > xmax)
310 xmax = x;
311 if(f&splashPathFirst) {
312 drawer.moveTo(&drawer, x, y);
314 if(f&splashPathCurve) {
315 double x2,y2;
316 path->getPoint(++s, &x2, &y2, &f);
317 if(f&splashPathCurve) {
318 double x3,y3;
319 path->getPoint(++s, &x3, &y3, &f);
320 gfxdraw_cubicTo(&drawer, x, y, x2, y2, x3, y3, quality);
321 } else {
322 drawer.splineTo(&drawer, x, y, x2, y2);
324 } else {
325 drawer.lineTo(&drawer, x, y);
327 // printf("%f %f %s %s\n", x, y, (f&splashPathCurve)?"curve":"",
328 // (f&splashPathFirst)?"first":"",
329 // (f&splashPathLast)?"last":"");
332 glyph->line = (gfxline_t*)drawer.result(&drawer);
333 if(this->glyphs[t]->advance>0) {
334 glyph->advance = this->glyphs[t]->advance;
335 } else {
336 glyph->advance = fmax(xmax, 0);
338 if(config_bigchar) {
339 double max = this->glyphs[t]->advance_max;
340 if(max>0 && max > glyph->advance) {
341 glyph->advance = max;
345 font->num_glyphs++;
349 if(config_remove_font_transforms) {
350 gfxmatrix_t glyph_transform;
351 glyph_transform.m00 = fontclass->m00;
352 glyph_transform.m01 = fontclass->m01;
353 glyph_transform.m10 = fontclass->m10;
354 glyph_transform.m11 = fontclass->m11;
355 glyph_transform.tx = 0;
356 glyph_transform.ty = 0;
357 /* apply the font transformation to the font */
358 gfxfont_transform(font, &glyph_transform);
360 gfxbbox_t total = gfxfont_bbox(font);
361 font->ascent = total.ymax;
362 font->descent = -total.ymin;
365 if(config_normalize_fonts) {
366 /* make all chars 1024 high */
367 gfxbbox_t bbox = gfxfont_bbox(font);
368 double height = bbox.ymax - bbox.ymin;
369 double scale = 1.0;
370 if(height>1e-5) {
371 scale = 1024.0 / height;
373 this->scale = 1.0 / scale;
374 gfxmatrix_t scale_matrix = {scale,0,0,
375 0,scale,0};
376 gfxfont_transform(font, &scale_matrix);
377 font->ascent *= scale;
378 font->descent *= scale;
381 if(config_remove_invisible_outlines) {
382 /* for OCR docs: remove the outlines of characters that are only
383 ever displayed with alpha=0 */
384 if(!fontclass->alpha) {
385 for(t=0;t<font->num_glyphs;t++) {
386 gfxglyph_t*g = &font->glyphs[t];
387 gfxline_t*line = font->glyphs[t].line;
388 gfxline_free(g->line);
389 g->line = (gfxline_t*)rfx_calloc(sizeof(gfxline_t));
390 g->line->type = gfx_moveTo;
391 g->line->x = g->advance;
396 return font;
399 static float find_average_glyph_advance(gfxfont_t*f)
401 if(!f->num_glyphs)
402 return 0.0;
404 float*values = (float*)malloc(sizeof(float)*f->num_glyphs);
405 int t;
406 for(t=0;t<f->num_glyphs;t++) {
407 values[t] = f->glyphs[t].advance;
409 float m = medianf(values, f->num_glyphs);
410 free(values);
411 return m;
414 gfxfont_t* FontInfo::getGfxFont()
416 if(!this->gfxfont) {
417 this->gfxfont = this->createGfxFont();
418 this->gfxfont->id = strdup(this->id);
419 this->space_char = findSpace(this->gfxfont);
420 this->average_advance = find_average_glyph_advance(this->gfxfont);
422 if(this->space_char>=0) {
423 msg("<debug> Font %s has space char %d (unicode=%d)",
424 this->id, this->space_char,
425 this->gfxfont->glyphs[this->space_char].unicode);
426 } else if(config_addspace) {
427 this->space_char = addSpace(this->gfxfont);
428 msg("<debug> Appending space char to font %s, position %d, width %f", this->gfxfont->id, this->space_char, this->gfxfont->glyphs[this->space_char].advance);
430 gfxfont_fix_unicode(this->gfxfont, config_unique_unicode);
432 /* optionally append a marker glyph */
433 if(config_marker_glyph) {
434 msg("<debug> Appending marker char to font %s, position %d, unicode %d", this->gfxfont->id, this->gfxfont->num_glyphs, config_marker_glyph);
435 gfxglyph_t*g = &this->gfxfont->glyphs[this->gfxfont->num_glyphs++];
436 g->name = 0;
437 g->unicode = config_marker_glyph;
438 g->advance = 2048;
439 g->line = (gfxline_t*)rfx_calloc(sizeof(gfxline_t));
440 g->line->type = gfx_moveTo;
441 g->line->x = g->advance;
444 return this->gfxfont;
447 GBool InfoOutputDev::upsideDown() {return gTrue;}
448 GBool InfoOutputDev::useDrawChar() {return gTrue;}
449 GBool InfoOutputDev::interpretType3Chars() {return gTrue;}
450 GBool InfoOutputDev::useTilingPatternFill() {return gFalse;}
452 GBool InfoOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
453 int rotate, GBool useMediaBox, GBool crop,
454 int sliceX, int sliceY, int sliceW, int sliceH,
455 GBool printing, Catalog *catalog,
456 GBool (*abortCheckCbk)(void *data),
457 void *abortCheckCbkData)
459 this->page = page;
460 return gTrue;
463 void InfoOutputDev::startPage(int pageNum, GfxState *state)
465 PDFRectangle *r = this->page->getCropBox();
466 double x1,y1,x2,y2;
467 state->transform(r->x1,r->y1,&x1,&y1);
468 state->transform(r->x2,r->y2,&x2,&y2);
469 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
470 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
471 this->x1 = (int)x1;
472 this->y1 = (int)y1;
473 this->x2 = (int)x2;
474 this->y2 = (int)y2;
475 msg("<verbose> Generating info structure for page %d", pageNum);
476 num_links = 0;
477 num_jpeg_images = 0;
478 num_ppm_images = 0;
479 num_chars = 0;
480 num_fonts = 0;
481 num_polygons= 0;
482 num_layers = 0;
483 average_char_size = 0;
485 void InfoOutputDev::endPage()
487 if(num_chars)
488 average_char_size /= num_chars;
490 void InfoOutputDev::drawLink(Link *link, Catalog *catalog)
492 num_links++;
495 /* } else if(!strcmp(key,"fontquality")) {
496 this->config_fontquality = atof(value);
497 if(this->config_fontquality<=1)
498 this->config_fontquality=1;
499 } else if(!strcmp(key,"bigchar")) {
500 this->config_bigchar = atoi(value);
504 char*getFontID(GfxFont*font)
506 Ref*ref = font->getID();
507 GString*gstr = font->getName();
508 char* fname = gstr==0?0:gstr->getCString();
509 char buf[128];
510 if(fname==0) {
511 if(font->getType() == fontType3) {
512 sprintf(buf, "t3font-%d-%d", ref->num, ref->gen);
513 } else {
514 sprintf(buf, "font-%d-%d", ref->num, ref->gen);
516 } else {
517 sprintf(buf, "%s-%d-%d", fname, ref->num, ref->gen);
519 return strdup(buf);
522 gfxmatrix_t gfxmatrix_from_state(GfxState*state)
524 double* ctm = state->getCTM();
525 double fontSize = state->getFontSize();
526 double*textMat = state->getTextMat();
528 /* taking the absolute value of horizScaling seems to be required for
529 some italic fonts. FIXME: SplashOutputDev doesn't need this- why? */
530 double hscale = fabs(state->getHorizScaling());
532 // from xpdf-3.02/SplashOutputDev:updateFont
533 double mm11 = textMat[0] * fontSize * hscale;
534 double mm12 = textMat[1] * fontSize * hscale;
535 double mm21 = textMat[2] * fontSize;
536 double mm22 = textMat[3] * fontSize;
538 // multiply with ctm, like state->getFontTransMat() does
539 gfxmatrix_t m;
540 m.m00 = (ctm[0]*mm11 + ctm[2]*mm12) / INTERNAL_FONT_SIZE;
541 m.m01 = (ctm[1]*mm11 + ctm[3]*mm12) / INTERNAL_FONT_SIZE;
542 m.m10 = (ctm[0]*mm21 + ctm[2]*mm22) / INTERNAL_FONT_SIZE;
543 m.m11 = (ctm[1]*mm21 + ctm[3]*mm22) / INTERNAL_FONT_SIZE;
544 m.tx = 0;
545 m.ty = 0;
546 return m;
549 void InfoOutputDev::updateTextMat(GfxState*state)
553 GBool InfoOutputDev::needNonText()
555 /* this switches off certain expensive operations, like
556 pattern fill and forms */
557 return gFalse;
560 void InfoOutputDev::updateFont(GfxState *state)
562 GfxFont*font = state->getFont();
563 if(!font) {
564 current_splash_font = 0;
565 return;
567 if(font->getType() == fontType3) {
568 current_splash_font = 0;
569 return;
571 GfxState* state2 = state->copy();
572 state2->setPath(0);
573 state2->setCTM(1.0,0,0,1.0,0,0);
574 splash->updateCTM(state2, 0,0,0,0,0,0);
575 state2->setTextMat(1.0,0,0,1.0,0,0);
576 state2->setFont(font, 1024.0);
577 splash->doUpdateFont(state2);
579 current_splash_font = splash->getCurrentFont();
580 delete state2;
583 double matrix_scale_factor(gfxmatrix_t*m)
585 double l1 = sqrt(m->m00 * m->m00 + m->m01 * m->m01);
586 double l2 = sqrt(m->m10 * m->m10 + m->m11 * m->m11);
587 return (l1+l2)/2.0;
590 #ifdef __GNUC__
591 int __attribute__((noinline))
592 font_classify(fontclass_t*out, gfxmatrix_t*in, const char*id, gfxcolor_t* color)
593 #else
594 int font_classify(fontclass_t*out, gfxmatrix_t*in, const char*id, gfxcolor_t* color)
595 #endif
597 if(!config_remove_font_transforms) {
598 out->m00 = 1.0;
599 out->m11 = 1.0;
600 out->m01 = 0.0;
601 out->m10 = 0.0;
602 } else {
603 double l = matrix_scale_factor(in);
604 if(l < 1e-10) {
605 /* treat all singularity characters the same */
606 memset(out, 0, sizeof(*out));
607 l = 0;
608 } else {
609 out->m00 = in->m00 / l;
610 out->m10 = in->m10 / l;
611 out->m01 = -in->m01 / l;
612 out->m11 = -in->m11 / l;
615 if(!color->a) {
616 /* for invisible characters, transforms don't need to be that
617 precise- use only 3 bits precision for mantissa. */
619 /* 0x80000000 //sign
620 0x78000000 //exponent
621 0x07ffffff //mantissa */
622 *(U32*)&out->m00 = (*(U32*)&out->m00)&0xffe00000;
623 *(U32*)&out->m01 = (*(U32*)&out->m01)&0xffe00000;
624 *(U32*)&out->m10 = (*(U32*)&out->m10)&0xffe00000;
625 *(U32*)&out->m11 = (*(U32*)&out->m11)&0xffe00000;
628 out->id = (char*)id;
629 out->alpha = color->a?1:0;
631 return 1;
634 void fontclass_print(fontclass_t*cls)
636 printf("[%f %f %f %f] %s alpha=%d\n",
637 cls->m00, cls->m01, cls->m10, cls->m11,
638 cls->id,
639 cls->alpha
643 gfxcolor_t gfxstate_getfontcolor(GfxState*state)
645 /* FIXME: instead of duplicating BitmapOutputDev's and VectorOutputDev's transparent
646 character logic here, we should move this code to CommonOutputDev and
647 call it from all three places */
649 gfxcolor_t col = gfxstate_getfillcolor(state);
650 /* HACK: if skewedtobitmap is on, weirdly rotated characters will
651 be drawn transparently in BitmapOutputDev. In order to anticipate this,
652 we duplicate the logic here */
653 if(config_remove_invisible_outlines &&
654 config_skewedtobitmap_pass1 &&
655 text_matrix_is_skewed(state)) {
656 col.a = 0;
658 if(state->getRender() == RENDER_INVISIBLE) {
659 col.a = 0;
661 if(config_poly2bitmap_pass1 && (state->getRender()&3)) {
662 /* with poly2bitmap, stroke or stroke+fill characters are drawn
663 to the bitmap and potentially overlaid with a transparent character.
664 duplicate that logic here. */
665 col.a = 0;
667 return col;
670 static inline fontclass_t fontclass_from_state(GfxState*state)
672 fontclass_t cls;
673 gfxcolor_t col = gfxstate_getfontcolor(state);
674 char*id = getFontID(state->getFont());
675 gfxmatrix_t m = gfxmatrix_from_state(state);
676 font_classify(&cls, &m, id, &col);
677 return cls;
679 static inline void fontclass_clear(fontclass_t*cls)
681 free(cls->id);cls->id=0;
684 FontInfo* InfoOutputDev::getOrCreateFontInfo(GfxState*state)
686 GfxFont*font = state->getFont();
687 fontclass_t fontclass = fontclass_from_state(state);
689 FontInfo* fontinfo = (FontInfo*)dict_lookup(this->fontcache, &fontclass);
690 if(!fontinfo) {
691 fontinfo = new FontInfo(&fontclass);
692 dict_put(this->fontcache, &fontclass, fontinfo);
693 fontinfo->font = font;
694 fontinfo->max_size = 0;
695 if(current_splash_font) {
696 fontinfo->ascender = current_splash_font->ascender;
697 fontinfo->descender = current_splash_font->descender;
698 } else {
699 fontinfo->ascender = fontinfo->descender = 0;
701 num_fonts++;
704 if(last_font && fontinfo!=last_font) {
705 last_font->resetPositioning();
708 this->last_font = fontinfo;
709 fontclass_clear(&fontclass);
710 return fontinfo;
713 FontInfo* InfoOutputDev::getFontInfo(GfxState*state)
715 fontclass_t fontclass = fontclass_from_state(state);
716 FontInfo*result = (FontInfo*)dict_lookup(this->fontcache, &fontclass);
717 if(!result) {
718 printf("NOT FOUND: ");
719 fontclass_print(&fontclass);
721 fontclass_clear(&fontclass);
722 return result;
725 gfxmatrix_t FontInfo::get_gfxmatrix(GfxState*state)
727 gfxmatrix_t m = gfxmatrix_from_state(state);
728 if(!config_remove_font_transforms) {
729 return m;
730 } else {
731 double scale = matrix_scale_factor(&m) * this->scale;
732 gfxmatrix_t m = {scale, 0, 0,
733 0, -scale, 0};
734 return m;
738 void InfoOutputDev::drawChar(GfxState *state, double x, double y,
739 double dx, double dy,
740 double originX, double originY,
741 CharCode code, int nBytes, Unicode *u, int uLen)
743 double m11,m21,m12,m22;
744 state->getFontTransMat(&m11, &m12, &m21, &m22);
745 m11 *= state->getHorizScaling();
746 m21 *= state->getHorizScaling();
747 double lenx = sqrt(m11*m11 + m12*m12);
748 double leny = sqrt(m21*m21 + m22*m22);
749 double len = lenx>leny?lenx:leny;
751 FontInfo*fontinfo = getOrCreateFontInfo(state);
753 if(!fontinfo) {
754 msg("<error> Internal error: No fontinfo for font");
755 return; //error
757 if(!current_splash_font) {
758 msg("<error> Internal error: No current splash fontinfo");
759 return; //error
761 if(fontinfo->max_size < len) {
762 fontinfo->max_size = len;
764 fontinfo->num_chars++;
765 if(uLen && u[0]==32) {
766 fontinfo->num_spaces++;
769 average_char_size += fmax(lenx,leny);
770 num_chars++;
772 if(!previous_was_char)
773 num_layers++;
774 previous_was_char=1;
776 fontinfo->grow(code+1);
777 GlyphInfo*g = fontinfo->glyphs[code];
778 if(!g) {
779 g = fontinfo->glyphs[code] = new GlyphInfo();
780 g->advance_max = 0;
781 current_splash_font->last_advance = -1;
782 g->path = current_splash_font->getGlyphPath(code);
783 g->advance = current_splash_font->last_advance;
784 g->unicode = 0;
786 if(uLen && ((u[0]>=32 && u[0]<g->unicode) || !g->unicode)) {
787 g->unicode = u[0];
789 if(fontinfo->lastchar>=0 && fontinfo->lasty == y) {
790 double xshift = (x - fontinfo->lastx);
791 if(xshift>=0 && xshift > g->advance_max) {
792 g->advance_max = xshift;
794 } else {
795 num_text_breaks++;
798 fontinfo->lastx = x;
799 fontinfo->lasty = y;
800 fontinfo->lastchar = code;
801 fontinfo->lastadvance = g->advance;
804 static char path_is_rectangular(GfxState* state)
806 GfxPath * path = state->getPath();
807 int num = path->getNumSubpaths();
808 if(num!=1) return 0;
809 GfxSubpath*subpath = path->getSubpath(0);
810 int subnum = path->getSubpath(0)->getNumPoints();
812 if(subnum>5) return 0;
813 int s;
814 for(s=1;s<subnum;s++) {
815 if(subpath->getCurve(s))
816 return 0;
817 if(subpath->getX(s) != subpath->getX(s-1) &&
818 subpath->getY(s) != subpath->getY(s-1)) {
819 return 0;
822 return 1;
825 void InfoOutputDev::fill(GfxState *state)
827 if(!path_is_rectangular(state))
828 previous_was_char=0;
829 num_polygons++;
832 void InfoOutputDev::eoFill(GfxState *state)
834 if(!path_is_rectangular(state))
835 previous_was_char=0;
836 num_polygons++;
839 GBool InfoOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
841 GfxFont*font = state->getFont();
842 if(!font)
843 return gTrue;
844 if(font->getType() != fontType3)
845 return gTrue;
847 current_splash_font = 0;
849 fontclass_t fontclass = fontclass_from_state(state);
850 FontInfo* fontinfo = (FontInfo*)dict_lookup(this->fontcache, &fontclass);
851 if(!fontinfo) {
852 fontinfo = new FontInfo(&fontclass);
853 dict_put(this->fontcache, &fontclass, fontinfo);
854 fontinfo->font = font;
855 fontinfo->max_size = 0;
856 num_fonts++;
858 fontclass_clear(&fontclass);
860 current_type3_font = fontinfo;
861 fontinfo->grow(code+1);
862 if(!fontinfo->glyphs[code]) {
863 currentglyph = fontinfo->glyphs[code] = new GlyphInfo();
864 currentglyph->unicode = uLen?u[0]:0;
865 currentglyph->path = new SplashPath();
866 currentglyph->x1=0;
867 currentglyph->y1=0;
868 currentglyph->x2=dx;
869 currentglyph->y2=dy;
870 currentglyph->advance=dx;
871 return gFalse;
872 } else {
873 return gTrue;
877 void InfoOutputDev::type3D0(GfxState *state, double wx, double wy)
879 currentglyph->x1=0;
880 currentglyph->y1=0;
881 currentglyph->x2=wx;
882 currentglyph->y2=wy;
885 void InfoOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury)
887 if(-lly>current_type3_font->descender)
888 current_type3_font->descender = -lly;
889 if(ury>current_type3_font->ascender)
890 current_type3_font->ascender = ury;
892 currentglyph->x1=llx;
893 currentglyph->y1=lly;
894 currentglyph->x2=urx;
895 currentglyph->y2=ury;
898 void InfoOutputDev::endType3Char(GfxState *state)
900 double x1 = currentglyph->x1;
901 double y1 = currentglyph->y1;
902 double x2 = currentglyph->x2;
903 double y2 = currentglyph->y2;
904 currentglyph->path->moveTo(x1,y1);
905 currentglyph->path->lineTo(x2,y1);
906 currentglyph->path->lineTo(x2,y2);
907 currentglyph->path->lineTo(x1,y2);
908 currentglyph->path->close();
911 void InfoOutputDev::saveState(GfxState *state)
913 updateAll(state);
916 void InfoOutputDev::restoreState(GfxState *state)
918 updateAll(state);
921 void InfoOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
922 int width, int height, GBool invert,
923 POPPLER_INTERPOLATE
924 GBool inlineImg)
926 previous_was_char=0;
927 if(str->getKind()==strDCT) num_jpeg_images++; else num_ppm_images++;
929 OutputDev::drawImageMask(state,ref,str,width,height,invert, POPPLER_INTERPOLATE_ARG inlineImg);
931 void InfoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
932 int width, int height, GfxImageColorMap *colorMap,
933 POPPLER_INTERPOLATE
934 int *maskColors, GBool inlineImg)
936 previous_was_char=0;
937 if(str->getKind()==strDCT) num_jpeg_images++; else num_ppm_images++;
939 OutputDev::drawImage(state,ref,str,width,height,colorMap, POPPLER_INTERPOLATE_ARG maskColors,inlineImg);
941 void InfoOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
942 int width, int height,
943 GfxImageColorMap *colorMap,
944 POPPLER_INTERPOLATE
945 Stream *maskStr,
946 int maskWidth, int maskHeight,
947 GBool maskInvert
948 POPPLER_MASK_INTERPOLATE)
950 previous_was_char=0;
951 if(str->getKind()==strDCT) num_jpeg_images++; else num_ppm_images++;
953 OutputDev::drawMaskedImage(state,ref,str,width,height,colorMap, POPPLER_INTERPOLATE_ARG maskStr,maskWidth,maskHeight,maskInvert POPPLER_MASK_INTERPOLATE_ARG);
956 void InfoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
957 int width, int height,
958 GfxImageColorMap *colorMap,
959 POPPLER_INTERPOLATE
960 Stream *maskStr,
961 int maskWidth, int maskHeight,
962 GfxImageColorMap *maskColorMap
963 POPPLER_MASK_INTERPOLATE)
965 previous_was_char=0;
966 if(str->getKind()==strDCT) num_jpeg_images++; else num_ppm_images++;
968 OutputDev::drawSoftMaskedImage(state,ref,str,width,height,colorMap, POPPLER_INTERPOLATE_ARG maskStr,maskWidth,maskHeight,maskColorMap POPPLER_MASK_INTERPOLATE_ARG);
971 void InfoOutputDev::dumpfonts(gfxdevice_t*dev)
973 GHashIter*i;
974 GString*key;
976 DICT_ITERATE_DATA(fontcache, FontInfo*, info) {
977 dev->addfont(dev, info->getGfxFont());