1 /*
2 * FontInstance.cpp
3 * testICU
4 *
5 * Authors:
6 * fred
7 * bulia byak <buliabyak@users.sf.net>
8 *
9 */
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14 #include <libnr/nr-rect.h>
15 #include <libnrtype/font-glyph.h>
16 #include <libnrtype/font-instance.h>
18 /* #include <layout/LEGlyphStorage.h> */
20 #include <livarot/Path.h>
22 #include "RasterFont.h"
24 /* Freetype 2 */
25 # include <freetype/ftoutln.h>
26 # include <freetype/ftbbox.h>
27 # include <freetype/internal/tttypes.h>
28 # include <freetype/internal/ftstream.h>
29 # include <freetype/tttags.h>
30 # include <pango/pangoft2.h>
34 size_t font_style_hash::operator()(const font_style &x) const {
35 int h=0,n;
36 for (int i=0;i<6;i++) {
37 n=(int)floor(100*x.transform[i]);
38 h*=12186;
39 h+=n;
40 }
41 n=(int)floor(100*x.stroke_width);
42 h*=12186;
43 h+=n;
44 n=(x.vertical)?1:0;
45 h*=12186;
46 h+=n;
47 if ( x.stroke_width >= 0.01 ) {
48 n=x.stroke_cap*10+x.stroke_join+(int)(x.stroke_miter_limit*100);
49 h*=12186;
50 h+=n;
51 if ( x.nbDash > 0 ) {
52 n=x.nbDash;
53 h*=12186;
54 h+=n;
55 n=(int)floor(100*x.dash_offset);
56 h*=12186;
57 h+=n;
58 for (int i=0;i<x.nbDash;i++) {
59 n=(int)floor(100*x.dashes[i]);
60 h*=12186;
61 h+=n;
62 }
63 }
64 }
65 return h;
66 }
68 bool font_style_equal::operator()(const font_style &a,const font_style &b) {
69 NR::Matrix diff=a.transform.inverse();
70 diff*=b.transform;
71 if ( diff.is_translation(0.01) ) {
72 if ( fabs(diff[4]) < 0.01 && fabs(diff[5]) < 0.01 ) {
73 } else {
74 return false;
75 }
76 } else {
77 return false;
78 }
79 if ( a.vertical && b.vertical == false ) return false;
80 if ( a.vertical == false && b.vertical ) return false;
81 if ( a.stroke_width > 0.01 && b.stroke_width <= 0.01 ) return false;
82 if ( a.stroke_width <= 0.01 && b.stroke_width > 0.01 ) return false;
83 if ( a.stroke_width <= 0.01 && b.stroke_width <= 0.01 ) return true;
85 if ( a.stroke_cap != b.stroke_cap ) return false;
86 if ( a.stroke_join != b.stroke_join ) return false;
87 if ( fabs(a.stroke_miter_limit-b.stroke_miter_limit) > 0.01) return false;
88 if ( a.nbDash != b.nbDash ) return false;
89 if ( a.nbDash <= 0 ) return true;
90 if ( fabs(a.dash_offset-b.dash_offset) < 0.01 ) {
91 for (int i=0;i<a.nbDash;i++) {
92 if ( fabs(a.dashes[i]-b.dashes[i]) >= 0.01 ) return false;
93 }
94 } else {
95 return false;
96 }
97 return true;
98 }
100 #ifndef USE_PANGO_WIN32
101 /*
102 * Outline extraction
103 */
104 typedef struct ft2_to_liv {
105 Path* theP;
106 double scale;
107 NR::Point last;
108 } ft2_to_liv;
110 // outline as returned by freetype -> livarot Path
111 // see nr-type-ft2.cpp for the freetype -> artBPath on which this code is based
112 static int ft2_move_to (FT_Vector * to, void * i_user) {
113 ft2_to_liv* user=(ft2_to_liv*)i_user;
114 NR::Point p(user->scale*to->x,user->scale*to->y);
115 // printf("m t=%f %f\n",p[0],p[1]);
116 user->theP->MoveTo(p);
117 user->last=p;
118 return 0;
119 }
121 static int ft2_line_to (FT_Vector * to, void * i_user)
122 {
123 ft2_to_liv* user=(ft2_to_liv*)i_user;
124 NR::Point p(user->scale*to->x,user->scale*to->y);
125 // printf("l t=%f %f\n",p[0],p[1]);
126 user->theP->LineTo(p);
127 user->last=p;
128 return 0;
129 }
131 static int ft2_conic_to (FT_Vector * control, FT_Vector * to, void * i_user)
132 {
133 ft2_to_liv* user=(ft2_to_liv*)i_user;
134 NR::Point p(user->scale*to->x,user->scale*to->y),c(user->scale*control->x,user->scale*control->y);
135 // printf("b c=%f %f t=%f %f\n",c[0],c[1],p[0],p[1]);
136 user->theP->BezierTo(p);
137 user->theP->IntermBezierTo(c);
138 user->theP->EndBezierTo();
139 user->last=p;
140 return 0;
141 }
143 static int ft2_cubic_to (FT_Vector * control1, FT_Vector * control2, FT_Vector * to, void * i_user)
144 {
145 ft2_to_liv* user=(ft2_to_liv*)i_user;
146 NR::Point p(user->scale*to->x,user->scale*to->y),
147 c1(user->scale*control1->x,user->scale*control1->y),
148 c2(user->scale*control2->x,user->scale*control2->y);
149 // printf("c c1=%f %f c2=%f %f t=%f %f\n",c1[0],c1[1],c2[0],c2[1],p[0],p[1]);
150 user->theP->CubicTo(p,3*(c1-user->last),3*(p-c2));
151 user->last=p;
152 return 0;
153 }
154 #endif
156 /*
157 *
158 */
160 font_instance::font_instance(void)
161 {
162 //printf("font instance born\n");
163 descr=NULL;
164 pFont=NULL;
165 refCount=0;
166 daddy=NULL;
167 nbGlyph=maxGlyph=0;
168 glyphs=NULL;
169 theFace=NULL;
170 }
172 font_instance::~font_instance(void)
173 {
174 if ( daddy ) daddy->UnrefFace(this);
175 //printf("font instance death\n");
176 if ( pFont ) g_object_unref(pFont);
177 pFont=NULL;
178 if ( descr ) pango_font_description_free(descr);
179 descr=NULL;
180 // if ( theFace ) FT_Done_Face(theFace); // owned by pFont. don't touch
181 theFace=NULL;
183 for (int i=0;i<nbGlyph;i++) {
184 if ( glyphs[i].outline ) delete glyphs[i].outline;
185 if ( glyphs[i].artbpath ) free(glyphs[i].artbpath);
186 }
187 if ( glyphs ) free(glyphs);
188 nbGlyph=maxGlyph=0;
189 glyphs=NULL;
190 }
192 void font_instance::Ref(void)
193 {
194 refCount++;
195 //char *tc=pango_font_description_to_string(descr);
196 //printf("font %x %s ref'd %i\n",this,tc,refCount);
197 //free(tc);
198 }
200 void font_instance::Unref(void)
201 {
202 refCount--;
203 //char *tc=pango_font_description_to_string(descr);
204 //printf("font %x %s unref'd %i\n",this,tc,refCount);
205 //free(tc);
206 if ( refCount <= 0 ) {
207 if ( daddy ) daddy->UnrefFace(this);
208 daddy=NULL;
209 delete this;
210 }
211 }
213 unsigned int font_instance::Name(gchar *str, unsigned int size)
214 {
215 return Attribute("name", str, size);
216 }
218 unsigned int font_instance::Family(gchar *str, unsigned int size)
219 {
220 return Attribute("family", str, size);
221 }
223 unsigned int font_instance::PSName(gchar *str, unsigned int size)
224 {
225 return Attribute("psname", str, size);
226 }
228 unsigned int font_instance::Attribute(const gchar *key, gchar *str, unsigned int size)
229 {
230 if ( descr == NULL ) {
231 if ( size > 0 ) str[0]=0;
232 return 0;
233 }
234 char* res=NULL;
235 bool free_res=false;
237 if ( strcmp(key,"name") == 0 ) {
238 PangoFontDescription* td=pango_font_description_copy(descr);
239 pango_font_description_unset_fields (td, PANGO_FONT_MASK_SIZE);
240 res=pango_font_description_to_string (td);
241 pango_font_description_free(td);
242 free_res=true;
243 } else if ( strcmp(key,"psname") == 0 ) {
244 #ifndef USE_PANGO_WIN32
245 res = (char *) FT_Get_Postscript_Name (theFace); // that's the main method, seems to always work
246 #endif
247 free_res=false;
248 if (res == NULL) { // a very limited workaround, only bold, italic, and oblique will work
249 PangoStyle style=pango_font_description_get_style(descr);
250 bool i = (style == PANGO_STYLE_ITALIC);
251 bool o = (style == PANGO_STYLE_OBLIQUE);
252 PangoWeight weight=pango_font_description_get_weight(descr);
253 bool b = (weight >= PANGO_WEIGHT_BOLD);
255 res = g_strdup_printf ("%s%s%s%s",
256 pango_font_description_get_family(descr),
257 (b || i || o) ? "-" : "",
258 (b) ? "Bold" : "",
259 (i) ? "Italic" : ((o) ? "Oblique" : "") );
260 free_res = true;
261 }
262 } else if ( strcmp(key,"family") == 0 ) {
263 res=(char*)pango_font_description_get_family(descr);
264 free_res=false;
265 } else if ( strcmp(key,"style") == 0 ) {
266 PangoStyle v=pango_font_description_get_style(descr);
267 if ( v == PANGO_STYLE_ITALIC ) {
268 res="italic";
269 } else if ( v == PANGO_STYLE_OBLIQUE ) {
270 res="oblique";
271 } else {
272 res="normal";
273 }
274 free_res=false;
275 } else if ( strcmp(key,"weight") == 0 ) {
276 PangoWeight v=pango_font_description_get_weight(descr);
277 if ( v <= PANGO_WEIGHT_ULTRALIGHT ) {
278 res="200";
279 } else if ( v <= PANGO_WEIGHT_LIGHT ) {
280 res="300";
281 } else if ( v <= PANGO_WEIGHT_NORMAL ) {
282 res="normal";
283 } else if ( v <= PANGO_WEIGHT_BOLD ) {
284 res="bold";
285 } else {
286 res="800";
287 }
288 free_res=false;
289 } else if ( strcmp(key,"stretch") == 0 ) {
290 PangoStretch v=pango_font_description_get_stretch(descr);
291 if ( v <= PANGO_STRETCH_EXTRA_CONDENSED ) {
292 res="extra-condensed";
293 } else if ( v <= PANGO_STRETCH_CONDENSED ) {
294 res="condensed";
295 } else if ( v <= PANGO_STRETCH_SEMI_CONDENSED ) {
296 res="semi-condensed";
297 } else if ( v <= PANGO_STRETCH_NORMAL ) {
298 res="normal";
299 } else if ( v <= PANGO_STRETCH_SEMI_EXPANDED ) {
300 res="semi-expanded";
301 } else if ( v <= PANGO_STRETCH_EXPANDED ) {
302 res="expanded";
303 } else {
304 res="extra-expanded";
305 }
306 free_res=false;
307 } else if ( strcmp(key,"variant") == 0 ) {
308 PangoVariant v=pango_font_description_get_variant(descr);
309 if ( v == PANGO_VARIANT_SMALL_CAPS ) {
310 res="small-caps";
311 } else {
312 res="normal";
313 }
314 free_res=false;
315 } else {
316 res = NULL;
317 free_res=false;
318 }
319 if ( res == NULL ) {
320 if ( size > 0 ) str[0]=0;
321 return 0;
322 }
324 if (res) {
325 unsigned int len=strlen(res);
326 unsigned int rlen=(size-1<len)?size-1:len;
327 if ( str ) {
328 if ( rlen > 0 ) memcpy(str,res,rlen);
329 if ( size > 0 ) str[rlen]=0;
330 }
331 if (free_res) free(res);
332 return len;
333 }
334 return 0;
335 }
337 void font_instance::InitTheFace()
338 {
339 #ifdef USE_PANGO_WIN32
340 if ( !theFace ) {
341 LOGFONT *lf=pango_win32_font_logfont(pFont);
342 g_assert(lf != NULL);
343 theFace=pango_win32_font_cache_load(daddy->pangoFontCache,lf);
344 g_free(lf);
345 }
346 XFORM identity = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
347 SetWorldTransform(daddy->hScreenDC, &identity);
348 SetGraphicsMode(daddy->hScreenDC, GM_COMPATIBLE);
349 SelectObject(daddy->hScreenDC,theFace);
350 #else
351 theFace=pango_ft2_font_get_face(pFont);
352 if ( theFace )
353 FT_Select_Charmap(theFace,ft_encoding_unicode) && FT_Select_Charmap(theFace,ft_encoding_symbol);
354 #endif
355 }
357 void font_instance::FreeTheFace()
358 {
359 #ifdef USE_PANGO_WIN32
360 SelectObject(daddy->hScreenDC,GetStockObject(SYSTEM_FONT));
361 pango_win32_font_cache_unload(daddy->pangoFontCache,theFace);
362 #endif
363 theFace=NULL;
364 }
366 void font_instance::InstallFace(PangoFont* iFace)
367 {
368 if ( !iFace )
369 return;
370 pFont=iFace;
372 InitTheFace();
374 if ( pFont && IsOutlineFont() == false ) {
375 FreeTheFace();
376 if ( pFont ) g_object_unref(pFont);
377 pFont=NULL;
378 }
379 }
381 bool font_instance::IsOutlineFont(void)
382 {
383 if ( pFont == NULL ) return false;
384 InitTheFace();
385 #ifdef USE_PANGO_WIN32
386 TEXTMETRIC tm;
387 return GetTextMetrics(daddy->hScreenDC,&tm) && tm.tmPitchAndFamily&(TMPF_TRUETYPE|TMPF_DEVICE);
388 #else
389 return FT_IS_SCALABLE(theFace);
390 #endif
391 }
393 int font_instance::MapUnicodeChar(gunichar c)
394 {
395 if ( pFont == NULL ) return 0;
396 #ifdef USE_PANGO_WIN32
397 return pango_win32_font_get_glyph_index(pFont,c);
398 #else
399 int res=0;
400 theFace=pango_ft2_font_get_face(pFont);
401 if ( c > 0xf0000 ) {
402 res=CLAMP(c,0xf0000,0x1fffff)-0xf0000;
403 } else {
404 res=FT_Get_Char_Index(theFace, c);
405 }
406 return res;
407 #endif
408 }
411 #ifdef USE_PANGO_WIN32
412 static inline NR::Point pointfx_to_nrpoint(const POINTFX &p, double scale)
413 {
414 return NR::Point(*(long*)&p.x / 65536.0 * scale,
415 *(long*)&p.y / 65536.0 * scale);
416 }
417 #endif
419 void font_instance::LoadGlyph(int glyph_id)
420 {
421 if ( pFont == NULL ) return;
422 InitTheFace();
423 #ifndef USE_PANGO_WIN32
424 if ( theFace->units_per_EM == 0 ) return; // bitmap font
425 #endif
427 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
428 if ( nbGlyph >= maxGlyph ) {
429 maxGlyph=2*nbGlyph+1;
430 glyphs=(font_glyph*)realloc(glyphs,maxGlyph*sizeof(font_glyph));
431 }
432 font_glyph n_g;
433 n_g.outline=NULL;
434 n_g.artbpath=NULL;
435 n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0;
436 bool doAdd=false;
438 #ifdef USE_PANGO_WIN32
439 MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
440 OUTLINETEXTMETRIC otm;
441 GetOutlineTextMetrics(daddy->hScreenDC, sizeof(otm), &otm);
442 GLYPHMETRICS metrics;
443 DWORD bufferSize=GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity);
444 double scale=1.0/daddy->fontSize;
445 n_g.h_advance=metrics.gmCellIncX*scale;
446 n_g.v_advance=otm.otmTextMetrics.tmHeight*scale;
447 n_g.h_width=metrics.gmBlackBoxX*scale;
448 n_g.v_width=metrics.gmBlackBoxY*scale;
449 n_g.outline=NULL;
450 if ( bufferSize == GDI_ERROR) {
451 // shit happened
452 } else if ( bufferSize == 0) {
453 // character has no visual representation, but is valid (eg whitespace)
454 doAdd=true;
455 } else {
456 std::auto_ptr<char> buffer(new char[bufferSize]);
457 if ( GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, bufferSize, buffer.get(), &identity) <= 0 ) {
458 // shit happened
459 } else {
460 // Platform SDK is rubbish, read KB87115 instead
461 n_g.outline=new Path;
462 DWORD polyOffset=0;
463 while ( polyOffset < bufferSize ) {
464 TTPOLYGONHEADER const *polyHeader=(TTPOLYGONHEADER const *)(buffer.get()+polyOffset);
465 if (polyOffset+polyHeader->cb > bufferSize) break;
467 if (polyHeader->dwType == TT_POLYGON_TYPE) {
468 n_g.outline->MoveTo(pointfx_to_nrpoint(polyHeader->pfxStart, scale));
469 DWORD curveOffset=polyOffset+sizeof(TTPOLYGONHEADER);
471 while ( curveOffset < polyOffset+polyHeader->cb ) {
472 TTPOLYCURVE const *polyCurve=(TTPOLYCURVE const *)(buffer.get()+curveOffset);
473 POINTFX const *p=polyCurve->apfx;
474 POINTFX const *endp=p+polyCurve->cpfx;
476 switch (polyCurve->wType) {
477 case TT_PRIM_LINE:
478 while ( p != endp )
479 n_g.outline->LineTo(pointfx_to_nrpoint(*p++, scale));
480 break;
482 case TT_PRIM_QSPLINE:
483 {
484 g_assert(polyCurve->cpfx >= 2);
485 endp -= 2;
486 NR::Point this_mid=pointfx_to_nrpoint(p[0], scale);
487 while ( p != endp ) {
488 NR::Point next_mid=pointfx_to_nrpoint(p[1], scale);
489 n_g.outline->BezierTo((next_mid+this_mid)/2);
490 n_g.outline->IntermBezierTo(this_mid);
491 n_g.outline->EndBezierTo();
492 ++p;
493 this_mid=next_mid;
494 }
495 n_g.outline->BezierTo(pointfx_to_nrpoint(p[1], scale));
496 n_g.outline->IntermBezierTo(this_mid);
497 n_g.outline->EndBezierTo();
498 break;
499 }
501 case 3: // TT_PRIM_CSPLINE
502 g_assert(polyCurve->cpfx % 3 == 0);
503 while ( p != endp ) {
504 n_g.outline->CubicTo(pointfx_to_nrpoint(p[2], scale), pointfx_to_nrpoint(p[0], scale), pointfx_to_nrpoint(p[1], scale));
505 p += 3;
506 }
507 break;
508 }
509 curveOffset += sizeof(TTPOLYCURVE)+sizeof(POINTFX)*(polyCurve->cpfx-1);
510 }
511 n_g.outline->Close();
512 }
513 polyOffset += polyHeader->cb;
514 }
515 doAdd=true;
516 }
517 }
518 #else
519 if (FT_Load_Glyph (theFace, glyph_id, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) {
520 // shit happened
521 } else {
522 if ( FT_HAS_HORIZONTAL(theFace) ) {
523 n_g.h_advance=((double)theFace->glyph->metrics.horiAdvance)/((double)theFace->units_per_EM);
524 n_g.h_width=((double)theFace->glyph->metrics.width)/((double)theFace->units_per_EM);
525 } else {
526 n_g.h_width=n_g.h_advance=((double)(theFace->bbox.xMax-theFace->bbox.xMin))/((double)theFace->units_per_EM);
527 }
528 if ( FT_HAS_VERTICAL(theFace) ) {
529 n_g.v_advance=((double)theFace->glyph->metrics.vertAdvance)/((double)theFace->units_per_EM);
530 n_g.v_width=((double)theFace->glyph->metrics.height)/((double)theFace->units_per_EM);
531 } else {
532 n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM);
533 }
534 if ( theFace->glyph->format == ft_glyph_format_outline ) {
535 FT_Outline_Funcs ft2_outline_funcs = {
536 ft2_move_to,
537 ft2_line_to,
538 ft2_conic_to,
539 ft2_cubic_to,
540 0, 0
541 };
542 n_g.outline=new Path;
543 ft2_to_liv tData;
544 tData.theP=n_g.outline;
545 tData.scale=1.0/((double)theFace->units_per_EM);
546 tData.last=NR::Point(0,0);
547 FT_Outline_Decompose (&theFace->glyph->outline, &ft2_outline_funcs, &tData);
548 }
549 doAdd=true;
550 }
551 #endif
553 if ( doAdd ) {
554 if ( n_g.outline ) {
555 n_g.outline->FastBBox(n_g.bbox[0],n_g.bbox[1],n_g.bbox[2],n_g.bbox[3]);
556 n_g.artbpath=n_g.outline->MakeArtBPath();
557 }
558 glyphs[nbGlyph]=n_g;
559 id_to_no[glyph_id]=nbGlyph;
560 nbGlyph++;
561 }
562 } else {
563 }
564 }
566 bool font_instance::FontMetrics(double &ascent,double &descent,double &leading)
567 {
568 if ( pFont == NULL ) return false;
569 InitTheFace();
570 if ( theFace == NULL ) return false;
571 #ifdef USE_PANGO_WIN32
572 OUTLINETEXTMETRIC otm;
573 if ( !GetOutlineTextMetrics(daddy->hScreenDC,sizeof(otm),&otm) ) return false;
574 double scale=1.0/daddy->fontSize;
575 ascent=fabs(otm.otmAscent*scale);
576 descent=fabs(otm.otmDescent*scale);
577 leading=fabs(otm.otmLineGap*scale);
578 #else
579 if ( theFace->units_per_EM == 0 ) return false; // bitmap font
580 ascent=fabs(((double)theFace->ascender)/((double)theFace->units_per_EM));
581 descent=fabs(((double)theFace->descender)/((double)theFace->units_per_EM));
582 leading=fabs(((double)theFace->height)/((double)theFace->units_per_EM));
583 leading-=ascent+descent;
584 #endif
585 return true;
586 }
588 bool font_instance::FontSlope(double &run, double &rise)
589 {
590 run = 0.0;
591 rise = 1.0;
593 if ( pFont == NULL ) return false;
594 InitTheFace();
595 if ( theFace == NULL ) return false;
597 #ifdef USE_PANGO_WIN32
598 OUTLINETEXTMETRIC otm;
599 if ( !GetOutlineTextMetrics(daddy->hScreenDC,sizeof(otm),&otm) ) return false;
600 run=otm.otmsCharSlopeRun;
601 rise=otm.otmsCharSlopeRise;
602 #else
603 if ( theFace->units_per_EM == 0 ) return false; // bitmap font
605 TT_HoriHeader *hhea = (TT_HoriHeader*)FT_Get_Sfnt_Table(theFace, ft_sfnt_hhea);
606 if (hhea == NULL) return false;
607 run = hhea->caret_Slope_Run;
608 rise = hhea->caret_Slope_Rise;
609 #endif
610 return true;
611 }
613 NR::Rect font_instance::BBox(int glyph_id)
614 {
615 int no=-1;
616 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
617 LoadGlyph(glyph_id);
618 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
619 // didn't load
620 } else {
621 no=id_to_no[glyph_id];
622 }
623 } else {
624 no=id_to_no[glyph_id];
625 }
626 if ( no < 0 ) return NR::Rect(NR::Point(0,0),NR::Point(0,0));
627 NR::Point rmin(glyphs[no].bbox[0],glyphs[no].bbox[1]);
628 NR::Point rmax(glyphs[no].bbox[2],glyphs[no].bbox[3]);
629 NR::Rect res(rmin,rmax);
630 return res;
631 }
633 Path* font_instance::Outline(int glyph_id,Path* copyInto)
634 {
635 int no=-1;
636 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
637 LoadGlyph(glyph_id);
638 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
639 // didn't load
640 } else {
641 no=id_to_no[glyph_id];
642 }
643 } else {
644 no=id_to_no[glyph_id];
645 }
646 if ( no < 0 ) return NULL;
647 Path* src_o=glyphs[no].outline;
648 if ( copyInto ) {
649 copyInto->Reset();
650 copyInto->Copy(src_o);
651 return copyInto;
652 }
653 return src_o;
654 }
656 void* font_instance::ArtBPath(int glyph_id)
657 {
658 int no=-1;
659 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
660 LoadGlyph(glyph_id);
661 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
662 // didn't load
663 } else {
664 no=id_to_no[glyph_id];
665 }
666 } else {
667 no=id_to_no[glyph_id];
668 }
669 if ( no < 0 ) return NULL;
670 return glyphs[no].artbpath;
671 }
673 double font_instance::Advance(int glyph_id,bool vertical)
674 {
675 int no=-1;
676 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
677 LoadGlyph(glyph_id);
678 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
679 // didn't load
680 } else {
681 no=id_to_no[glyph_id];
682 }
683 } else {
684 no=id_to_no[glyph_id];
685 }
686 if ( no >= 0 ) {
687 if ( vertical ) {
688 return glyphs[no].v_advance;
689 } else {
690 return glyphs[no].h_advance;
691 }
692 }
693 return 0;
694 }
697 raster_font* font_instance::RasterFont(const NR::Matrix &trs,double stroke_width,bool vertical,JoinType stroke_join,ButtType stroke_cap,float miter_limit)
698 {
699 font_style nStyle;
700 nStyle.transform=trs;
701 nStyle.vertical=vertical;
702 nStyle.stroke_width=stroke_width;
703 nStyle.stroke_cap=stroke_cap;
704 nStyle.stroke_join=stroke_join;
705 nStyle.nbDash=0;
706 nStyle.dash_offset=0;
707 nStyle.dashes=NULL;
708 return RasterFont(nStyle);
709 }
711 raster_font* font_instance::RasterFont(const font_style &inStyle)
712 {
713 raster_font *res=NULL;
714 double *savDashes=NULL;
715 font_style nStyle=inStyle;
716 // for some evil reason font_style doesn't have a copy ctor, so the
717 // stuff that should be done there is done here instead (because the
718 // raster_font ctor copies nStyle).
719 if ( nStyle.stroke_width > 0 && nStyle.nbDash > 0 && nStyle.dashes ) {
720 savDashes=nStyle.dashes;
721 nStyle.dashes=(double*)malloc(nStyle.nbDash*sizeof(double));
722 memcpy(nStyle.dashes,savDashes,nStyle.nbDash*sizeof(double));
723 }
724 if ( loadedStyles.find(nStyle) == loadedStyles.end() ) {
725 raster_font *nR = new raster_font(nStyle);
726 nR->Ref();
727 nR->daddy=this;
728 loadedStyles[nStyle]=nR;
729 res=nR;
730 if ( res ) Ref();
731 } else {
732 res=loadedStyles[nStyle];
733 res->Ref();
734 if ( nStyle.dashes ) free(nStyle.dashes); // since they're not taken by a new rasterfont
735 }
736 nStyle.dashes=savDashes;
737 return res;
738 }
740 void font_instance::RemoveRasterFont(raster_font* who)
741 {
742 if ( who == NULL ) return;
743 if ( loadedStyles.find(who->style) == loadedStyles.end() ) {
744 //g_print("RemoveRasterFont failed \n");
745 // not found
746 } else {
747 loadedStyles.erase(loadedStyles.find(who->style));
748 //g_print("RemoveRasterFont\n");
749 Unref();
750 }
751 }
755 /*
756 Local Variables:
757 mode:c++
758 c-file-style:"stroustrup"
759 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
760 indent-tabs-mode:nil
761 fill-column:99
762 End:
763 */
764 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :