Code

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