Code

rearrange effect submenus, rename some effects, fix capitalization
[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         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;
84         
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;
121 static int ft2_line_to (FT_Vector * to, void * i_user)
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;
131 static int ft2_conic_to (FT_Vector * control, FT_Vector * to, void * i_user)
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;
143 static int ft2_cubic_to (FT_Vector * control1, FT_Vector * control2, FT_Vector * to, void * i_user)
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;
154 #endif
156 /*
157  *
158  */
160 font_instance::font_instance(void)
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;
172 font_instance::~font_instance(void)
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;
192 void font_instance::Ref(void)
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);
200 void font_instance::Unref(void)
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         }
213 unsigned int font_instance::Name(gchar *str, unsigned int size)
215         return Attribute("name", str, size);
218 unsigned int font_instance::Family(gchar *str, unsigned int size)
220         return Attribute("family", str, size);
223 unsigned int font_instance::PSName(gchar *str, unsigned int size)
225         return Attribute("psname", str, size);
228 unsigned int font_instance::Attribute(const gchar *key, gchar *str, unsigned int size)
230         if ( descr == NULL ) {
231                 if ( size > 0 ) str[0]=0;
232                 return 0;
233         }
234         char*   res=NULL;
235         bool    free_res=false;
236         
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);
254    
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         }
323         
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;
337 void font_instance::InitTheFace()
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         FT_Select_Charmap(theFace,ft_encoding_unicode) && FT_Select_Charmap(theFace,ft_encoding_symbol);
353 #endif
356 void font_instance::FreeTheFace()
358 #ifdef USE_PANGO_WIN32
359     SelectObject(daddy->hScreenDC,GetStockObject(SYSTEM_FONT));
360     pango_win32_font_cache_unload(daddy->pangoFontCache,theFace);
361 #endif
362     theFace=NULL;
365 void font_instance::InstallFace(PangoFont* iFace)
367         if ( !iFace )
368             return;
369         pFont=iFace;
371     InitTheFace();
373         if ( pFont && IsOutlineFont() == false ) {
374         FreeTheFace();
375                 if ( pFont ) g_object_unref(pFont);
376                 pFont=NULL;
377         }
380 bool    font_instance::IsOutlineFont(void)
382         if ( pFont == NULL ) return false;
383     InitTheFace();
384 #ifdef USE_PANGO_WIN32
385     TEXTMETRIC tm;
386     return GetTextMetrics(daddy->hScreenDC,&tm) && tm.tmPitchAndFamily&TMPF_TRUETYPE;
387 #else
388         return FT_IS_SCALABLE(theFace);
389 #endif
392 int font_instance::MapUnicodeChar(gunichar c)
394         if ( pFont == NULL ) return 0;
395 #ifdef USE_PANGO_WIN32
396     return pango_win32_font_get_glyph_index(pFont,c);
397 #else
398         int res=0;
399         theFace=pango_ft2_font_get_face(pFont);
400         if ( c > 0xf0000 ) {
401                 res=CLAMP(c,0xf0000,0x1fffff)-0xf0000;
402         } else {
403                 res=FT_Get_Char_Index(theFace, c);
404         }
405         return res;
406 #endif
410 #ifdef USE_PANGO_WIN32
411 static inline NR::Point pointfx_to_nrpoint(const POINTFX &p, double scale)
413     return NR::Point(*(long*)&p.x / 65536.0 * scale,
414                      *(long*)&p.y / 65536.0 * scale);
416 #endif
418 void font_instance::LoadGlyph(int glyph_id)
420         if ( pFont == NULL ) return;
421     InitTheFace();
422 #ifndef USE_PANGO_WIN32
423         if ( theFace->units_per_EM == 0 ) return; // bitmap font
424 #endif
426         if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
427                 if ( nbGlyph >= maxGlyph ) {
428                         maxGlyph=2*nbGlyph+1;
429                         glyphs=(font_glyph*)realloc(glyphs,maxGlyph*sizeof(font_glyph));
430                 }
431                 font_glyph  n_g;
432                 n_g.outline=NULL;
433                 n_g.artbpath=NULL;
434                 n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0;
435                 bool   doAdd=false;
437 #ifdef USE_PANGO_WIN32
438         MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
439         OUTLINETEXTMETRIC otm;
440         GetOutlineTextMetrics(daddy->hScreenDC, sizeof(otm), &otm);
441         GLYPHMETRICS metrics;
442         DWORD bufferSize=GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity);
443         double scale=1.0/daddy->fontSize;
444         n_g.h_advance=metrics.gmCellIncX*scale;
445         n_g.v_advance=otm.otmTextMetrics.tmHeight*scale;
446         n_g.h_width=metrics.gmBlackBoxX*scale;
447         n_g.v_width=metrics.gmBlackBoxY*scale;
448         n_g.outline=NULL;
449         if ( bufferSize == GDI_ERROR) {
450             // shit happened
451         } else if ( bufferSize == 0) {
452             // character has no visual representation, but is valid (eg whitespace)
453             doAdd=true;
454         } else {
455             std::auto_ptr<char> buffer(new char[bufferSize]);
456             if ( GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, bufferSize, buffer.get(), &identity) <= 0 ) {
457                 // shit happened
458             } else {
459                 // Platform SDK is rubbish, read KB87115 instead
460                 n_g.outline=new Path;
461                 DWORD polyOffset=0;
462                 while ( polyOffset < bufferSize ) {
463                     TTPOLYGONHEADER const *polyHeader=(TTPOLYGONHEADER const *)(buffer.get()+polyOffset);
464                     if (polyOffset+polyHeader->cb > bufferSize) break;
466                     if (polyHeader->dwType == TT_POLYGON_TYPE) {
467                         n_g.outline->MoveTo(pointfx_to_nrpoint(polyHeader->pfxStart, scale));
468                         DWORD curveOffset=polyOffset+sizeof(TTPOLYGONHEADER);
470                         while ( curveOffset < polyOffset+polyHeader->cb ) {
471                             TTPOLYCURVE const *polyCurve=(TTPOLYCURVE const *)(buffer.get()+curveOffset);
472                             POINTFX const *p=polyCurve->apfx;
473                             POINTFX const *endp=p+polyCurve->cpfx;
475                             switch (polyCurve->wType) {
476                                 case TT_PRIM_LINE:
477                                     while ( p != endp )
478                                         n_g.outline->LineTo(pointfx_to_nrpoint(*p++, scale));
479                                     break;
481                                 case TT_PRIM_QSPLINE:
482                                 {
483                                     g_assert(polyCurve->cpfx >= 2);
484                                     endp -= 2;
485                                     NR::Point this_mid=pointfx_to_nrpoint(p[0], scale);
486                                     while ( p != endp ) {
487                                         NR::Point next_mid=pointfx_to_nrpoint(p[1], scale);
488                                             n_g.outline->BezierTo((next_mid+this_mid)/2);
489                                             n_g.outline->IntermBezierTo(this_mid);
490                                             n_g.outline->EndBezierTo();
491                                         ++p;
492                                         this_mid=next_mid;
493                                     }
494                                         n_g.outline->BezierTo(pointfx_to_nrpoint(p[1], scale));
495                                         n_g.outline->IntermBezierTo(this_mid);
496                                         n_g.outline->EndBezierTo();
497                                     break;
498                                 }
500                                 case 3:  // TT_PRIM_CSPLINE
501                                     g_assert(polyCurve->cpfx % 3 == 0);
502                                     while ( p != endp ) {
503                                         n_g.outline->CubicTo(pointfx_to_nrpoint(p[2], scale), pointfx_to_nrpoint(p[0], scale), pointfx_to_nrpoint(p[1], scale));
504                                         p += 3;
505                                     }
506                                     break;
507                             }
508                             curveOffset += sizeof(TTPOLYCURVE)+sizeof(POINTFX)*(polyCurve->cpfx-1);
509                         }
510                         n_g.outline->Close();
511                     }
512                     polyOffset += polyHeader->cb;
513                 }
514                 doAdd=true;
515             }
516         }
517 #else
518                 if (FT_Load_Glyph (theFace, glyph_id, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) {
519                         // shit happened
520                 } else {
521                         if ( FT_HAS_HORIZONTAL(theFace) ) {
522                                 n_g.h_advance=((double)theFace->glyph->metrics.horiAdvance)/((double)theFace->units_per_EM);
523                                 n_g.h_width=((double)theFace->glyph->metrics.width)/((double)theFace->units_per_EM);
524                         } else {
525                                 n_g.h_width=n_g.h_advance=((double)(theFace->bbox.xMax-theFace->bbox.xMin))/((double)theFace->units_per_EM);
526                         }
527                         if ( FT_HAS_VERTICAL(theFace) ) {
528                                 n_g.v_advance=((double)theFace->glyph->metrics.vertAdvance)/((double)theFace->units_per_EM);
529                                 n_g.v_width=((double)theFace->glyph->metrics.height)/((double)theFace->units_per_EM);
530                         } else {
531                                 n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM);
532                         }
533                         if ( theFace->glyph->format == ft_glyph_format_outline ) {
534                                 FT_Outline_Funcs ft2_outline_funcs = {
535                                         ft2_move_to,
536                                         ft2_line_to,
537                                         ft2_conic_to,
538                                         ft2_cubic_to,
539                                         0, 0
540                                 };
541                                 n_g.outline=new Path;
542                                 ft2_to_liv   tData;
543                                 tData.theP=n_g.outline;
544                                 tData.scale=1.0/((double)theFace->units_per_EM);
545                                 tData.last=NR::Point(0,0);
546                                 FT_Outline_Decompose (&theFace->glyph->outline, &ft2_outline_funcs, &tData);
547                         }
548                         doAdd=true;
549                 }
550 #endif
552                 if ( doAdd ) {
553                         if ( n_g.outline ) {
554                                 n_g.outline->FastBBox(n_g.bbox[0],n_g.bbox[1],n_g.bbox[2],n_g.bbox[3]);
555                                 n_g.artbpath=n_g.outline->MakeArtBPath();
556                         }
557                         glyphs[nbGlyph]=n_g;
558                         id_to_no[glyph_id]=nbGlyph;
559                         nbGlyph++;
560                 }
561     } else {
562     }
565 bool font_instance::FontMetrics(double &ascent,double &descent,double &leading)
567         if ( pFont == NULL ) return false;
568     InitTheFace();
569         if ( theFace == NULL ) return false;
570 #ifdef USE_PANGO_WIN32
571     OUTLINETEXTMETRIC otm;
572     if ( !GetOutlineTextMetrics(daddy->hScreenDC,sizeof(otm),&otm) ) return false;
573     double scale=1.0/daddy->fontSize;
574     ascent=fabs(otm.otmAscent*scale);
575     descent=fabs(otm.otmDescent*scale);
576     leading=fabs(otm.otmLineGap*scale);
577 #else
578         if ( theFace->units_per_EM == 0 ) return false; // bitmap font
579         ascent=fabs(((double)theFace->ascender)/((double)theFace->units_per_EM));
580         descent=fabs(((double)theFace->descender)/((double)theFace->units_per_EM));
581         leading=fabs(((double)theFace->height)/((double)theFace->units_per_EM));
582         leading-=ascent+descent;
583 #endif
584         return true;
587 bool font_instance::FontSlope(double &run, double &rise)
589     run = 0.0;
590     rise = 1.0;
592         if ( pFont == NULL ) return false;
593     InitTheFace();
594         if ( theFace == NULL ) return false;
596 #ifdef USE_PANGO_WIN32
597     OUTLINETEXTMETRIC otm;
598     if ( !GetOutlineTextMetrics(daddy->hScreenDC,sizeof(otm),&otm) ) return false;
599     run=otm.otmsCharSlopeRun;
600     rise=otm.otmsCharSlopeRise;
601 #else
602         if ( theFace->units_per_EM == 0 ) return false; // bitmap font
603         
604     TT_HoriHeader *hhea = (TT_HoriHeader*)FT_Get_Sfnt_Table(theFace, ft_sfnt_hhea);
605     if (hhea == NULL) return false;
606     run = hhea->caret_Slope_Run;
607     rise = hhea->caret_Slope_Rise;
608 #endif
609         return true;
612 NR::Rect font_instance::BBox(int glyph_id)
614         int no=-1;
615         if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
616                 LoadGlyph(glyph_id);
617                 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
618                         // didn't load
619                 } else {
620                         no=id_to_no[glyph_id];
621                 }
622         } else {
623                 no=id_to_no[glyph_id];
624         }
625         if ( no < 0 ) return NR::Rect(NR::Point(0,0),NR::Point(0,0));
626         NR::Point rmin(glyphs[no].bbox[0],glyphs[no].bbox[1]);
627         NR::Point rmax(glyphs[no].bbox[2],glyphs[no].bbox[3]);
628         NR::Rect  res(rmin,rmax);
629         return res;
632 Path* font_instance::Outline(int glyph_id,Path* copyInto)
634         int no=-1;
635         if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
636                 LoadGlyph(glyph_id);
637                 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
638                         // didn't load
639                 } else {
640                         no=id_to_no[glyph_id];
641                 }
642         } else {
643                 no=id_to_no[glyph_id];
644         }
645         if ( no < 0 ) return NULL;
646         Path*    src_o=glyphs[no].outline;
647         if ( copyInto ) {
648                 copyInto->Reset();
649                 copyInto->Copy(src_o);
650                 return copyInto;
651         }
652         return src_o;
655 void* font_instance::ArtBPath(int glyph_id)
657         int no=-1;
658         if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
659                 LoadGlyph(glyph_id);
660                 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
661                         // didn't load
662                 } else {
663                         no=id_to_no[glyph_id];
664                 }
665         } else {
666                 no=id_to_no[glyph_id];
667         }
668         if ( no < 0 ) return NULL;
669         return glyphs[no].artbpath;
672 double font_instance::Advance(int glyph_id,bool vertical)
674         int no=-1;
675         if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
676                 LoadGlyph(glyph_id);
677                 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
678                         // didn't load
679                 } else {
680                         no=id_to_no[glyph_id];
681                 }
682         } else {
683                 no=id_to_no[glyph_id];
684         }
685         if ( no >= 0 ) {
686                 if ( vertical ) {
687                         return glyphs[no].v_advance;
688                 } else {
689                         return glyphs[no].h_advance;
690                 }
691         }
692         return 0;
693 }       
696 raster_font* font_instance::RasterFont(const NR::Matrix &trs,double stroke_width,bool vertical,JoinType stroke_join,ButtType stroke_cap,float miter_limit)
698         font_style  nStyle;
699         nStyle.transform=trs;
700         nStyle.vertical=vertical;
701         nStyle.stroke_width=stroke_width;
702         nStyle.stroke_cap=stroke_cap;
703         nStyle.stroke_join=stroke_join;
704         nStyle.nbDash=0;
705         nStyle.dash_offset=0;
706         nStyle.dashes=NULL;
707         return RasterFont(nStyle);
710 raster_font* font_instance::RasterFont(const font_style &inStyle)
712         raster_font  *res=NULL;
713         double *savDashes=NULL;
714         font_style nStyle=inStyle;
715     // for some evil reason font_style doesn't have a copy ctor, so the
716     // stuff that should be done there is done here instead (because the
717     // raster_font ctor copies nStyle).
718         if ( nStyle.stroke_width > 0 && nStyle.nbDash > 0 && nStyle.dashes ) {
719                 savDashes=nStyle.dashes;
720                 nStyle.dashes=(double*)malloc(nStyle.nbDash*sizeof(double));
721                 memcpy(nStyle.dashes,savDashes,nStyle.nbDash*sizeof(double));
722         }
723         if ( loadedStyles.find(nStyle) == loadedStyles.end() ) {
724                 raster_font *nR = new raster_font(nStyle);
725                 nR->Ref();
726                 nR->daddy=this;
727                 loadedStyles[nStyle]=nR;
728                 res=nR;
729                 if ( res ) Ref();
730         } else {
731                 res=loadedStyles[nStyle];
732                 res->Ref();
733                 if ( nStyle.dashes ) free(nStyle.dashes); // since they're not taken by a new rasterfont
734         }
735         nStyle.dashes=savDashes;
736         return res;
739 void font_instance::RemoveRasterFont(raster_font* who)
741         if ( who == NULL ) return;
742         if ( loadedStyles.find(who->style) == loadedStyles.end() ) {
743                 //g_print("RemoveRasterFont failed \n");
744                 // not found
745         } else {
746                 loadedStyles.erase(loadedStyles.find(who->style));
747                 //g_print("RemoveRasterFont\n");
748                 Unref();
749         }
754 /*
755  Local Variables:
756  mode:c++
757  c-file-style:"stroustrup"
758  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
759  indent-tabs-mode:nil
760  fill-column:99
761  End:
762  */
763 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :