Code

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