Code

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