3 #include "InfoOutputDev.h"
4 #include "SplashOutputDev.h"
6 #include <splash/SplashTypes.h>
7 #include <splash/SplashPath.h>
8 #include <splash/SplashFont.h>
9 #include <splash/SplashFontFile.h>
11 #include "SplashTypes.h"
12 #include "SplashPath.h"
13 #include "SplashFont.h"
14 #include "SplashFontFile.h"
20 #include "../gfxfont.h"
24 int config_addspace
= 1;
25 int config_fontquality
= 10;
26 int config_bigchar
= 0;
28 InfoOutputDev::InfoOutputDev(XRef
*xref
)
38 id2font
= new GHash(1);
39 SplashColor white
= {255,255,255};
40 splash
= new SplashOutputDev(splashModeRGB8
,320,0,white
,0,0);
41 splash
->startDoc(xref
);
43 InfoOutputDev::~InfoOutputDev()
46 id2font
->startIter(&i
);
49 while(id2font
->getNext(&i
, &key
, (void**)&fontinfo
)) {
52 id2font
->killIter(&i
);
54 delete id2font
;id2font
=0;
55 delete splash
;splash
=0;
58 void FontInfo::grow(int size
)
60 if(size
>= this->num_glyphs
) {
61 this->glyphs
= (GlyphInfo
**)realloc(this->glyphs
, sizeof(GlyphInfo
*)*(size
));
62 this->kerning
= (dict_t
**)realloc(this->kerning
, sizeof(dict_t
*)*(size
));
63 memset(&this->glyphs
[this->num_glyphs
], 0, sizeof(SplashPath
*)*((size
)-this->num_glyphs
));
64 memset(&this->kerning
[this->num_glyphs
], 0, sizeof(dict_t
*)*((size
)-this->num_glyphs
));
65 this->num_glyphs
= size
;
68 FontInfo::FontInfo(char*id
)
70 this->id
= strdup(id
);
75 this->splash_font
= 0;
80 this->space_char
= -1;
86 if(this->id
) {free(this->id
);this->id
=0;}
89 for(t
=0;t
<num_glyphs
;t
++) {
91 delete glyphs
[t
]->path
;glyphs
[t
]->path
= 0;
96 free(glyphs
);glyphs
=0;
98 gfxfont_free(this->gfxfont
);
101 for(t
=0;t
<num_glyphs
;t
++) {
102 dict_t
* d
= kerning
[t
];
104 DICT_ITERATE_ITEMS(d
,void*,key
,mtf_t
*,m
) {
114 static int findSpace(gfxfont_t
*font
)
116 int first_space
= -1;
118 for(t
=0;t
<font
->num_glyphs
;t
++) {
119 gfxglyph_t
*g
= &font
->glyphs
[t
];
120 if(GLYPH_IS_SPACE(g
)) {
121 if(g
->unicode
== 32) return t
;
126 if(font
->num_glyphs
>32 && GLYPH_IS_SPACE(&font
->glyphs
[32])) {
132 static int addSpace(gfxfont_t
*font
)
134 /* first, make sure the new space char is the only char that'll use unicode 32 */
136 for(t
=0;t
<font
->num_glyphs
;t
++) {
137 if(font
->glyphs
[t
].unicode
==32)
138 font
->glyphs
[t
].unicode
=0;
141 font
->glyphs
= (gfxglyph_t
*)realloc(font
->glyphs
, sizeof(gfxglyph_t
)*font
->num_glyphs
);
142 gfxglyph_t
*g
= &font
->glyphs
[font
->num_glyphs
-1];
143 memset(g
, 0, sizeof(*g
));
145 g
->advance
= fabs(font
->ascent
+ font
->descent
)*2 / 3;
146 if(font
->max_unicode
> 32)
147 font
->unicode2glyph
[32] = font
->num_glyphs
-1;
149 g
->line
= gfxline_makerectangle(0, -font
->ascent
, g
->advance
, font
->descent
);
151 return font
->num_glyphs
-1;
154 static gfxfont_t
* createGfxFont(FontInfo
*src
)
156 gfxfont_t
*font
= (gfxfont_t
*)malloc(sizeof(gfxfont_t
));
157 memset(font
, 0, sizeof(gfxfont_t
));
159 font
->glyphs
= (gfxglyph_t
*)malloc(sizeof(gfxglyph_t
)*src
->num_glyphs
);
160 memset(font
->glyphs
, 0, sizeof(gfxglyph_t
)*src
->num_glyphs
);
164 double quality
= (INTERNAL_FONT_SIZE
* 200 / config_fontquality
) / src
->max_size
;
166 //printf("%d glyphs\n", font->num_glyphs);
167 font
->num_glyphs
= 0;
168 font
->ascent
= fabs(src
->ascender
);
169 font
->descent
= fabs(src
->descender
);
171 for(t
=0;t
<src
->num_glyphs
;t
++) {
173 SplashPath
*path
= src
->glyphs
[t
]->path
;
174 int len
= path
?path
->getLength():0;
175 //printf("glyph %d) %08x (%d line segments)\n", t, path, len);
176 gfxglyph_t
*glyph
= &font
->glyphs
[font
->num_glyphs
];
177 src
->glyphs
[t
]->glyphid
= font
->num_glyphs
;
178 glyph
->unicode
= src
->glyphs
[t
]->unicode
;
180 gfxdrawer_target_gfxline(&drawer
);
187 path
->getPoint(s
, &x
, &y
, &f
);
190 if(f
&splashPathFirst
) {
191 drawer
.moveTo(&drawer
, x
*scale
, y
*scale
);
193 if(f
&splashPathCurve
) {
195 path
->getPoint(++s
, &x2
, &y2
, &f
);
196 if(f
&splashPathCurve
) {
198 path
->getPoint(++s
, &x3
, &y3
, &f
);
199 gfxdraw_cubicTo(&drawer
, x
*scale
, y
*scale
, x2
*scale
, y2
*scale
, x3
*scale
, y3
*scale
, quality
);
201 drawer
.splineTo(&drawer
, x
*scale
, y
*scale
, x2
*scale
, y2
*scale
);
204 drawer
.lineTo(&drawer
, x
*scale
, y
*scale
);
206 // printf("%f %f %s %s\n", x, y, (f&splashPathCurve)?"curve":"",
207 // (f&splashPathFirst)?"first":"",
208 // (f&splashPathLast)?"last":"");
211 glyph
->line
= (gfxline_t
*)drawer
.result(&drawer
);
212 if(src
->glyphs
[t
]->advance
>0) {
213 glyph
->advance
= src
->glyphs
[t
]->advance
;
215 glyph
->advance
= xmax
*scale
;
218 double max
= src
->glyphs
[t
]->advance_max
;
219 if(max
>0 && max
> glyph
->advance
) {
220 glyph
->advance
= max
;
228 int kerning_size
= 0;
229 for(t
=0;t
<src
->num_glyphs
;t
++) {
230 dict_t
* d
= src
->kerning
[t
];
232 DICT_ITERATE_ITEMS(d
,void*,key
,mtf_t
*,m
) {
238 font
->kerning_size
= kerning_size
;
239 font
->kerning
= (gfxkerning_t
*)malloc(sizeof(gfxkerning_t
)*kerning_size
);
241 for(t
=0;t
<src
->num_glyphs
;t
++) {
242 dict_t
* d
= src
->kerning
[t
];
244 DICT_ITERATE_ITEMS(d
,void*,key
,mtf_t
*,m
) {
246 font
->kerning
[pos
].c1
= src
->glyphs
[t
]->glyphid
;
247 font
->kerning
[pos
].c2
= src
->glyphs
[(int)(ptroff_t
)key
]->glyphid
;
248 font
->kerning
[pos
].advance
= (int)(ptroff_t
)m
->first
->key
;
253 //int advance = (int)(ptroff_t)m->first->key;
258 static float find_average_glyph_advance(gfxfont_t
*f
)
263 float*values
= (float*)malloc(sizeof(float)*f
->num_glyphs
);
265 for(t
=0;t
<f
->num_glyphs
;t
++) {
266 values
[t
] = f
->glyphs
[t
].advance
;
268 float m
= medianf(values
, f
->num_glyphs
);
273 gfxfont_t
* FontInfo::getGfxFont()
276 this->gfxfont
= createGfxFont(this);
277 this->gfxfont
->id
= strdup(this->id
);
278 this->space_char
= findSpace(this->gfxfont
);
279 this->average_advance
= find_average_glyph_advance(this->gfxfont
);
281 if(this->space_char
>=0) {
282 msg("<debug> Font %s has space char %d (unicode=%d)",
283 this->id
, this->space_char
,
284 this->gfxfont
->glyphs
[this->space_char
].unicode
);
285 } else if(config_addspace
) {
286 this->space_char
= addSpace(this->gfxfont
);
287 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
);
289 gfxfont_fix_unicode(this->gfxfont
);
291 return this->gfxfont
;
294 GBool
InfoOutputDev::upsideDown() {return gTrue
;}
295 GBool
InfoOutputDev::useDrawChar() {return gTrue
;}
296 GBool
InfoOutputDev::interpretType3Chars() {return gTrue
;}
297 GBool
InfoOutputDev::useTilingPatternFill() {return gTrue
;}
299 void InfoOutputDev::startPage(int pageNum
, GfxState
*state
, double crop_x1
, double crop_y1
, double crop_x2
, double crop_y2
)
302 state
->transform(crop_x1
,crop_y1
,&x1
,&y1
);
303 state
->transform(crop_x2
,crop_y2
,&x2
,&y2
);
304 if(x2
<x1
) {double x3
=x1
;x1
=x2
;x2
=x3
;}
305 if(y2
<y1
) {double y3
=y1
;y1
=y2
;y2
=y3
;}
310 msg("<verbose> Generating info structure for page %d", pageNum
);
312 void InfoOutputDev::endPage()
315 void InfoOutputDev::drawLink(Link
*link
, Catalog
*catalog
)
320 /* } else if(!strcmp(key,"fontquality")) {
321 this->config_fontquality = atof(value);
322 if(this->config_fontquality<=1)
323 this->config_fontquality=1;
324 } else if(!strcmp(key,"bigchar")) {
325 this->config_bigchar = atoi(value);
329 double InfoOutputDev::getMaximumFontSize(char*id
)
331 FontInfo
*info
= (FontInfo
*)id2font
->lookup(id
);
333 msg("<error> Unknown font id: %s", id
);
336 return info
->max_size
;
339 char*getFontID(GfxFont
*font
)
341 Ref
*ref
= font
->getID();
342 GString
*gstr
= font
->getName();
343 char* fname
= gstr
==0?0:gstr
->getCString();
346 if(font
->getType() == fontType3
) {
347 sprintf(buf
, "t3font-%d-%d", ref
->num
, ref
->gen
);
349 sprintf(buf
, "font-%d-%d", ref
->num
, ref
->gen
);
352 sprintf(buf
, "%s-%d-%d", fname
, ref
->num
, ref
->gen
);
357 void InfoOutputDev::updateFont(GfxState
*state
)
359 GfxFont
*font
= state
->getFont();
364 if(font
->getType() == fontType3
) {
368 char*id
= getFontID(font
);
371 currentfont
->splash_font
= 0;
373 currentfont
= (FontInfo
*)id2font
->lookup(id
);
375 currentfont
= new FontInfo(id
);
376 currentfont
->font
= font
;
377 currentfont
->max_size
= 0;
378 GString
* idStr
= new GString(id
);
379 id2font
->add(idStr
, (void*)currentfont
);
383 state
->setCTM(1.0,0,0,1.0,0,0);
384 splash
->updateCTM(state
, 0,0,0,0,0,0);
385 state
->setTextMat(1.0,0,0,1.0,0,0);
386 state
->setFont(font
, 1024.0);
387 splash
->doUpdateFont(state
);
388 currentfont
->splash_font
= splash
->getCurrentFont();
389 if(currentfont
->splash_font
) {
390 currentfont
->ascender
= currentfont
->splash_font
->ascender
;
391 currentfont
->descender
= currentfont
->splash_font
->descender
;
393 currentfont
->ascender
= currentfont
->descender
= 0;
399 void InfoOutputDev::fill(GfxState
*state
)
404 void InfoOutputDev::eoFill(GfxState
*state
)
409 FontInfo
* InfoOutputDev::getFont(char*id
)
411 return (FontInfo
*)id2font
->lookup(id
);
414 void InfoOutputDev::drawChar(GfxState
*state
, double x
, double y
,
415 double dx
, double dy
,
416 double originX
, double originY
,
417 CharCode code
, int nBytes
, Unicode
*u
, int uLen
)
419 double m11
,m21
,m12
,m22
;
420 state
->getFontTransMat(&m11
, &m12
, &m21
, &m22
);
421 m11
*= state
->getHorizScaling();
422 m21
*= state
->getHorizScaling();
423 double lenx
= sqrt(m11
*m11
+ m12
*m12
);
424 double leny
= sqrt(m21
*m21
+ m22
*m22
);
425 double len
= lenx
>leny
?lenx
:leny
;
426 if(!currentfont
|| !currentfont
->splash_font
) {
429 if(currentfont
&& currentfont
->max_size
< len
) {
430 currentfont
->max_size
= len
;
435 currentfont
->grow(code
+1);
436 GlyphInfo
*g
= currentfont
->glyphs
[code
];
438 g
= currentfont
->glyphs
[code
] = new GlyphInfo();
440 currentfont
->splash_font
->last_advance
= -1;
441 g
->path
= currentfont
->splash_font
->getGlyphPath(code
);
442 g
->advance
= currentfont
->splash_font
->last_advance
;
445 if(uLen
&& ((u
[0]>=32 && u
[0]<g
->unicode
) || !g
->unicode
)) {
448 if(currentfont
->lastchar
>=0 && currentfont
->lasty
== y
) {
449 double xshift
= (x
- currentfont
->lastx
);
450 if(xshift
>=0 && xshift
> g
->advance_max
) {
451 g
->advance_max
= xshift
;
453 int advance
= (int)xshift
;
454 if(advance
>=0 && advance
<g
->advance
*4 && advance
!=currentfont
->lastadvance
) {
455 int c1
= currentfont
->lastchar
;
457 dict_t
*d
= currentfont
->kerning
[c1
];
459 d
= currentfont
->kerning
[c1
] = dict_new2(&int_type
);
461 mtf_t
*k
= (mtf_t
*)dict_lookup(d
, (void*)(ptroff_t
)c2
);
463 k
= mtf_new(&int_type
);
464 dict_put(d
, (void*)(ptroff_t
)c2
, k
);
466 mtf_increase(k
, (void*)(ptroff_t
)advance
);
470 currentfont
->lastx
= x
;
471 currentfont
->lasty
= y
;
472 currentfont
->lastchar
= code
;
473 currentfont
->lastadvance
= (int)(g
->advance
+0.5);
476 GBool
InfoOutputDev::beginType3Char(GfxState
*state
, double x
, double y
, double dx
, double dy
, CharCode code
, Unicode
*u
, int uLen
)
478 GfxFont
*font
= state
->getFont();
481 if(font
->getType() != fontType3
)
484 char*id
= getFontID(font
);
485 currentfont
= (FontInfo
*)id2font
->lookup(id
);
487 currentfont
= new FontInfo(id
);
488 currentfont
->font
= font
;
489 GString
* idStr
= new GString(id
);
490 id2font
->add(idStr
, (void*)currentfont
);
493 currentfont
= currentfont
;
496 currentfont
->grow(code
+1);
497 if(!currentfont
->glyphs
[code
]) {
498 currentglyph
= currentfont
->glyphs
[code
] = new GlyphInfo();
499 currentglyph
->unicode
= uLen
?u
[0]:0;
500 currentglyph
->path
= new SplashPath();
505 currentglyph
->advance
=dx
;
512 void InfoOutputDev::type3D0(GfxState
*state
, double wx
, double wy
)
520 void InfoOutputDev::type3D1(GfxState
*state
, double wx
, double wy
, double llx
, double lly
, double urx
, double ury
)
522 if(-lly
>currentfont
->descender
)
523 currentfont
->descender
= -lly
;
524 if(ury
>currentfont
->ascender
)
525 currentfont
->ascender
= ury
;
527 currentglyph
->x1
=llx
;
528 currentglyph
->y1
=lly
;
529 currentglyph
->x2
=urx
;
530 currentglyph
->y2
=ury
;
533 void InfoOutputDev::endType3Char(GfxState
*state
)
535 double x1
= currentglyph
->x1
;
536 double y1
= currentglyph
->y1
;
537 double x2
= currentglyph
->x2
;
538 double y2
= currentglyph
->y2
;
539 currentglyph
->path
->moveTo(x1
,y1
);
540 currentglyph
->path
->lineTo(x2
,y1
);
541 currentglyph
->path
->lineTo(x2
,y2
);
542 currentglyph
->path
->lineTo(x1
,y2
);
543 currentglyph
->path
->close();
546 void InfoOutputDev::drawImageMask(GfxState
*state
, Object
*ref
, Stream
*str
,
547 int width
, int height
, GBool invert
,
550 if(str
->getKind()==strDCT
) num_jpeg_images
++; else num_ppm_images
++;
552 OutputDev::drawImageMask(state
,ref
,str
,width
,height
,invert
,inlineImg
);
554 void InfoOutputDev::drawImage(GfxState
*state
, Object
*ref
, Stream
*str
,
555 int width
, int height
, GfxImageColorMap
*colorMap
,
556 int *maskColors
, GBool inlineImg
)
558 if(str
->getKind()==strDCT
) num_jpeg_images
++; else num_ppm_images
++;
560 OutputDev::drawImage(state
,ref
,str
,width
,height
,colorMap
,maskColors
,inlineImg
);
562 void InfoOutputDev::drawMaskedImage(GfxState
*state
, Object
*ref
, Stream
*str
,
563 int width
, int height
,
564 GfxImageColorMap
*colorMap
,
566 int maskWidth
, int maskHeight
,
569 if(str
->getKind()==strDCT
) num_jpeg_images
++; else num_ppm_images
++;
571 OutputDev::drawMaskedImage(state
,ref
,str
,width
,height
,colorMap
,maskStr
,maskWidth
,maskHeight
,maskInvert
);
574 void InfoOutputDev::drawSoftMaskedImage(GfxState
*state
, Object
*ref
, Stream
*str
,
575 int width
, int height
,
576 GfxImageColorMap
*colorMap
,
578 int maskWidth
, int maskHeight
,
579 GfxImageColorMap
*maskColorMap
)
581 if(str
->getKind()==strDCT
) num_jpeg_images
++; else num_ppm_images
++;
583 OutputDev::drawSoftMaskedImage(state
,ref
,str
,width
,height
,colorMap
,maskStr
,maskWidth
,maskHeight
,maskColorMap
);
586 void InfoOutputDev::dumpfonts(gfxdevice_t
*dev
)
591 id2font
->startIter(&i
);
592 while(id2font
->getNext(&i
, &key
, (void**)&font
)) {
593 dev
->addfont(dev
, font
->getGfxFont());