1 #include "../../config.h"
3 #include "InfoOutputDev.h"
4 #include "SplashOutputDev.h"
6 #include "CommonOutputDev.h"
10 #include "../gfxdevice.h"
11 #include "../gfxfont.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
) {
29 const fontclass_t
*m1
=(const fontclass_t
*)_m
;
30 fontclass_t
*m2
= (fontclass_t
*)malloc(sizeof(fontclass_t
));
32 m2
->id
= strdup(m1
->id
);
35 static unsigned int fontclass_hash(const void*_m
) {
38 const fontclass_t
*m
= (fontclass_t
*)_m
;
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
;
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
;
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))
79 if(config_remove_invisible_outlines
) {
80 if(m1
->alpha
!= m2
->alpha
)
83 return !strcmp(m1
->id
, m2
->id
);
86 static type_t fontclass_type
= {
93 InfoOutputDev::InfoOutputDev(XRef
*xref
)
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
);
109 current_type3_font
= 0;
110 fontcache
= dict_new2(&fontclass_type
);
112 InfoOutputDev::~InfoOutputDev()
116 DICT_ITERATE_DATA(this->fontcache
, FontInfo
*, 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
) {
136 static int counter
=1;
137 sprintf(buf
, "font%d", counter
++);
138 this->id
= strdup(buf
);
140 this->id
= strdup(fontclass
->id
);
143 this->fontclass
= (fontclass_t
*)fontclass_type
.dup(fontclass
);
145 this->num_glyphs
= 0;
148 this->space_char
= -1;
153 this->num_spaces
= 0;
156 FontInfo::~FontInfo()
158 if(this->id
) {free(this->id
);this->id
=0;}
161 for(t
=0;t
<num_glyphs
;t
++) {
163 delete glyphs
[t
]->path
;glyphs
[t
]->path
= 0;
168 free(glyphs
);glyphs
=0;
170 gfxfont_free(this->gfxfont
);
172 if(this->fontclass
) {
173 fontclass_type
.free(this->fontclass
);
178 char FontInfo::usesSpaces()
180 if(this->num_chars
&&
181 this->num_spaces
/ (double)this->num_chars
>= 0.05) {
187 void FontInfo::resetPositioning()
192 this->lastadvance
= 0;
195 static int findSpace(gfxfont_t
*font
)
197 int first_space
= -1;
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 */
205 for(s
=0;s
<font
->num_glyphs
;s
++) {
206 if(s
!=t
&& font
->glyphs
[s
].unicode
==32)
207 font
->glyphs
[s
].unicode
=0;
216 static int addSpace(gfxfont_t
*font
)
218 /* first, make sure the new space char is the only char that'll use unicode 32 */
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
));
229 g
->advance
= fabs(font
->ascent
+ font
->descent
) / 5.0;
230 if(font
->max_unicode
> 32)
231 font
->unicode2glyph
[32] = space_glyph
;
233 g
->line
= gfxline_makerectangle(0, -font
->ascent
, g
->advance
, font
->descent
);
238 static void transform_glyph(gfxglyph_t
*g
, fontclass_t
*mm
, double scale
)
241 m
.m00
= mm
->m00
* scale
;
242 m
.m01
= mm
->m01
* scale
;
243 m
.m10
= mm
->m10
* scale
;
244 m
.m11
= mm
->m11
* scale
;
249 g
->line
= gfxline_clone(g
->line
);
250 gfxline_transform(g
->line
, &m
);
253 void gfxfont_transform(gfxfont_t
*font
, gfxmatrix_t
*m
)
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
);
261 g
->advance
*= m
->m00
;
265 gfxbbox_t
gfxfont_bbox(gfxfont_t
*font
)
267 gfxbbox_t tmp
= {0,0,0,0};
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
);
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
);
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
;
301 gfxdrawer_target_gfxline(&drawer
);
308 path
->getPoint(s
, &x
, &y
, &f
);
311 if(f
&splashPathFirst
) {
312 drawer
.moveTo(&drawer
, x
, y
);
314 if(f
&splashPathCurve
) {
316 path
->getPoint(++s
, &x2
, &y2
, &f
);
317 if(f
&splashPathCurve
) {
319 path
->getPoint(++s
, &x3
, &y3
, &f
);
320 gfxdraw_cubicTo(&drawer
, x
, y
, x2
, y2
, x3
, y3
, quality
);
322 drawer
.splineTo(&drawer
, x
, y
, x2
, y2
);
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
;
336 glyph
->advance
= fmax(xmax
, 0);
339 double max
= this->glyphs
[t
]->advance_max
;
340 if(max
>0 && max
> glyph
->advance
) {
341 glyph
->advance
= max
;
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
;
371 scale
= 1024.0 / height
;
373 this->scale
= 1.0 / scale
;
374 gfxmatrix_t scale_matrix
= {scale
,0,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
;
399 static float find_average_glyph_advance(gfxfont_t
*f
)
404 float*values
= (float*)malloc(sizeof(float)*f
->num_glyphs
);
406 for(t
=0;t
<f
->num_glyphs
;t
++) {
407 values
[t
] = f
->glyphs
[t
].advance
;
409 float m
= medianf(values
, f
->num_glyphs
);
414 gfxfont_t
* FontInfo::getGfxFont()
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
++];
437 g
->unicode
= config_marker_glyph
;
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
)
463 void InfoOutputDev::startPage(int pageNum
, GfxState
*state
)
465 PDFRectangle
*r
= this->page
->getCropBox();
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
;}
475 msg("<verbose> Generating info structure for page %d", pageNum
);
483 average_char_size
= 0;
485 void InfoOutputDev::endPage()
488 average_char_size
/= num_chars
;
490 void InfoOutputDev::drawLink(Link
*link
, Catalog
*catalog
)
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();
511 if(font
->getType() == fontType3
) {
512 sprintf(buf
, "t3font-%d-%d", ref
->num
, ref
->gen
);
514 sprintf(buf
, "font-%d-%d", ref
->num
, ref
->gen
);
517 sprintf(buf
, "%s-%d-%d", fname
, ref
->num
, ref
->gen
);
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
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
;
549 void InfoOutputDev::updateTextMat(GfxState
*state
)
553 GBool
InfoOutputDev::needNonText()
555 /* this switches off certain expensive operations, like
556 pattern fill and forms */
560 void InfoOutputDev::updateFont(GfxState
*state
)
562 GfxFont
*font
= state
->getFont();
564 current_splash_font
= 0;
567 if(font
->getType() == fontType3
) {
568 current_splash_font
= 0;
571 GfxState
* state2
= state
->copy();
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();
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
);
591 int __attribute__((noinline
))
592 font_classify(fontclass_t
*out
, gfxmatrix_t
*in
, const char*id
, gfxcolor_t
* color
)
594 int font_classify(fontclass_t
*out
, gfxmatrix_t
*in
, const char*id
, gfxcolor_t
* color
)
597 if(!config_remove_font_transforms
) {
603 double l
= matrix_scale_factor(in
);
605 /* treat all singularity characters the same */
606 memset(out
, 0, sizeof(*out
));
609 out
->m00
= in
->m00
/ l
;
610 out
->m10
= in
->m10
/ l
;
611 out
->m01
= -in
->m01
/ l
;
612 out
->m11
= -in
->m11
/ l
;
616 /* for invisible characters, transforms don't need to be that
617 precise- use only 3 bits precision for mantissa. */
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;
629 out
->alpha
= color
->a
?1:0;
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
,
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
)) {
658 if(state
->getRender() == RENDER_INVISIBLE
) {
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. */
670 static inline fontclass_t
fontclass_from_state(GfxState
*state
)
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
);
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
);
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
;
699 fontinfo
->ascender
= fontinfo
->descender
= 0;
704 if(last_font
&& fontinfo
!=last_font
) {
705 last_font
->resetPositioning();
708 this->last_font
= fontinfo
;
709 fontclass_clear(&fontclass
);
713 FontInfo
* InfoOutputDev::getFontInfo(GfxState
*state
)
715 fontclass_t fontclass
= fontclass_from_state(state
);
716 FontInfo
*result
= (FontInfo
*)dict_lookup(this->fontcache
, &fontclass
);
718 printf("NOT FOUND: ");
719 fontclass_print(&fontclass
);
721 fontclass_clear(&fontclass
);
725 gfxmatrix_t
FontInfo::get_gfxmatrix(GfxState
*state
)
727 gfxmatrix_t m
= gfxmatrix_from_state(state
);
728 if(!config_remove_font_transforms
) {
731 double scale
= matrix_scale_factor(&m
) * this->scale
;
732 gfxmatrix_t m
= {scale
, 0, 0,
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
);
754 msg("<error> Internal error: No fontinfo for font");
757 if(!current_splash_font
) {
758 msg("<error> Internal error: No current splash fontinfo");
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
);
772 if(!previous_was_char
)
776 fontinfo
->grow(code
+1);
777 GlyphInfo
*g
= fontinfo
->glyphs
[code
];
779 g
= fontinfo
->glyphs
[code
] = new GlyphInfo();
781 current_splash_font
->last_advance
= -1;
782 g
->path
= current_splash_font
->getGlyphPath(code
);
783 g
->advance
= current_splash_font
->last_advance
;
786 if(uLen
&& ((u
[0]>=32 && u
[0]<g
->unicode
) || !g
->unicode
)) {
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
;
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();
809 GfxSubpath
*subpath
= path
->getSubpath(0);
810 int subnum
= path
->getSubpath(0)->getNumPoints();
812 if(subnum
>5) return 0;
814 for(s
=1;s
<subnum
;s
++) {
815 if(subpath
->getCurve(s
))
817 if(subpath
->getX(s
) != subpath
->getX(s
-1) &&
818 subpath
->getY(s
) != subpath
->getY(s
-1)) {
825 void InfoOutputDev::fill(GfxState
*state
)
827 if(!path_is_rectangular(state
))
832 void InfoOutputDev::eoFill(GfxState
*state
)
834 if(!path_is_rectangular(state
))
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();
844 if(font
->getType() != fontType3
)
847 current_splash_font
= 0;
849 fontclass_t fontclass
= fontclass_from_state(state
);
850 FontInfo
* fontinfo
= (FontInfo
*)dict_lookup(this->fontcache
, &fontclass
);
852 fontinfo
= new FontInfo(&fontclass
);
853 dict_put(this->fontcache
, &fontclass
, fontinfo
);
854 fontinfo
->font
= font
;
855 fontinfo
->max_size
= 0;
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();
870 currentglyph
->advance
=dx
;
877 void InfoOutputDev::type3D0(GfxState
*state
, double wx
, double 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
)
916 void InfoOutputDev::restoreState(GfxState
*state
)
921 void InfoOutputDev::drawImageMask(GfxState
*state
, Object
*ref
, Stream
*str
,
922 int width
, int height
, GBool invert
,
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
,
934 int *maskColors
, GBool inlineImg
)
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
,
946 int maskWidth
, int maskHeight
,
948 POPPLER_MASK_INTERPOLATE
)
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
,
961 int maskWidth
, int maskHeight
,
962 GfxImageColorMap
*maskColorMap
963 POPPLER_MASK_INTERPOLATE
)
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
)
976 DICT_ITERATE_DATA(fontcache
, FontInfo
*, info
) {
977 dev
->addfont(dev
, info
->getGfxFont());