Code

25a6af935157b3ddd2a1242309e534852bf5374f
[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>
17 #include <2geom/pathvector.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;
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         Geom::Point    last;
91 } ft2_to_liv;
93 // Note: Freetype 2.2.1 redefined function signatures for functions to be placed in an
94 // FT_Outline_Funcs structure.  This is needed to keep backwards compatibility with the
95 // 2.1.x series.
97 /* *** BEGIN #if HACK *** */
98 #if FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 2
99 typedef FT_Vector const FREETYPE_VECTOR;
100 #else
101 typedef FT_Vector FREETYPE_VECTOR;
102 #endif
104 // outline as returned by freetype -> livarot Path
105 // see nr-type-ft2.cpp for the freetype -> artBPath on which this code is based
106 static int ft2_move_to(FREETYPE_VECTOR *to, void * i_user) {
107         ft2_to_liv* user=(ft2_to_liv*)i_user;
108         Geom::Point   p(user->scale*to->x,user->scale*to->y);
109         //      printf("m  t=%f %f\n",p[0],p[1]);
110         user->theP->MoveTo(p);
111         user->last=p;
112         return 0;
115 static int ft2_line_to(FREETYPE_VECTOR *to, void *i_user)
117         ft2_to_liv* user=(ft2_to_liv*)i_user;
118         Geom::Point   p(user->scale*to->x,user->scale*to->y);
119         //      printf("l  t=%f %f\n",p[0],p[1]);
120         user->theP->LineTo(p);
121         user->last=p;
122         return 0;
125 static int ft2_conic_to(FREETYPE_VECTOR *control, FREETYPE_VECTOR *to, void *i_user)
127         ft2_to_liv* user=(ft2_to_liv*)i_user;
128         Geom::Point   p(user->scale*to->x,user->scale*to->y),c(user->scale*control->x,user->scale*control->y);
129         //      printf("b c=%f %f  t=%f %f\n",c[0],c[1],p[0],p[1]);
130         user->theP->BezierTo(p);
131         user->theP->IntermBezierTo(c);
132         user->theP->EndBezierTo();
133         user->last=p;
134         return 0;
137 static int ft2_cubic_to(FREETYPE_VECTOR *control1, FREETYPE_VECTOR *control2, FREETYPE_VECTOR *to, void *i_user)
139         ft2_to_liv* user=(ft2_to_liv*)i_user;
140         Geom::Point   p(user->scale*to->x,user->scale*to->y),
141         c1(user->scale*control1->x,user->scale*control1->y),
142         c2(user->scale*control2->x,user->scale*control2->y);
143         //      printf("c c1=%f %f  c2=%f %f   t=%f %f\n",c1[0],c1[1],c2[0],c2[1],p[0],p[1]);
144         user->theP->CubicTo(p,3*(c1-user->last),3*(p-c2));
145         user->last=p;
146         return 0;
148 #endif
150 /* *** END #if HACK *** */
152 /*
153  *
154  */
156 font_instance::font_instance(void)
158         //printf("font instance born\n");
159         descr=NULL;
160         pFont=NULL;
161         refCount=0;
162         daddy=NULL;
163         nbGlyph=maxGlyph=0;
164         glyphs=NULL;
165         theFace=NULL;
168 font_instance::~font_instance(void)
170         if ( daddy ) daddy->UnrefFace(this);
171         //printf("font instance death\n");
172         if ( pFont ) g_object_unref(pFont);
173         pFont=NULL;
174         if ( descr ) pango_font_description_free(descr);
175         descr=NULL;
176         //      if ( theFace ) FT_Done_Face(theFace); // owned by pFont. don't touch
177         theFace=NULL;
179         for (int i=0;i<nbGlyph;i++) {
180                 if ( glyphs[i].outline ) delete glyphs[i].outline;
181         if ( glyphs[i].pathvector ) delete glyphs[i].pathvector;
182         }
183         if ( glyphs ) free(glyphs);
184         nbGlyph=maxGlyph=0;
185         glyphs=NULL;
188 void font_instance::Ref(void)
190         refCount++;
191         //char *tc=pango_font_description_to_string(descr);
192         //printf("font %x %s ref'd %i\n",this,tc,refCount);
193         //free(tc);
196 void font_instance::Unref(void)
198         refCount--;
199         //char *tc=pango_font_description_to_string(descr);
200         //printf("font %x %s unref'd %i\n",this,tc,refCount);
201         //free(tc);
202         if ( refCount <= 0 ) {
203                 if ( daddy ) daddy->UnrefFace(this);
204                 daddy=NULL;
205                 delete this;
206         }
209 unsigned int font_instance::Name(gchar *str, unsigned int size)
211         return Attribute("name", str, size);
214 unsigned int font_instance::Family(gchar *str, unsigned int size)
216         return Attribute("family", str, size);
219 unsigned int font_instance::PSName(gchar *str, unsigned int size)
221         return Attribute("psname", str, size);
224 unsigned int font_instance::Attribute(const gchar *key, gchar *str, unsigned int size)
226         if ( descr == NULL ) {
227                 if ( size > 0 ) str[0]=0;
228                 return 0;
229         }
230         char*   res=NULL;
231         bool    free_res=false;
233         if ( strcmp(key,"name") == 0 ) {
234                 PangoFontDescription* td=pango_font_description_copy(descr);
235                 pango_font_description_unset_fields (td, PANGO_FONT_MASK_SIZE);
236                 res=pango_font_description_to_string (td);
237                 pango_font_description_free(td);
238                 free_res=true;
239         } else if ( strcmp(key,"psname") == 0 ) {
240 #ifndef USE_PANGO_WIN32
241          res = (char *) FT_Get_Postscript_Name (theFace); // that's the main method, seems to always work
242 #endif
243          free_res=false;
244          if (res == NULL) { // a very limited workaround, only bold, italic, and oblique will work
245              PangoStyle style=pango_font_description_get_style(descr);
246              bool i = (style == PANGO_STYLE_ITALIC);
247              bool o = (style == PANGO_STYLE_OBLIQUE);
248              PangoWeight weight=pango_font_description_get_weight(descr);
249              bool b = (weight >= PANGO_WEIGHT_BOLD);
251              res = g_strdup_printf ("%s%s%s%s",
252                                     pango_font_description_get_family(descr),
253                                     (b || i || o) ? "-" : "",
254                                     (b) ? "Bold" : "",
255                                     (i) ? "Italic" : ((o) ? "Oblique" : "")  );
256              free_res = true;
257          }
258         } else if ( strcmp(key,"family") == 0 ) {
259                 res=(char*)pango_font_description_get_family(descr);
260                 free_res=false;
261         } else if ( strcmp(key,"style") == 0 ) {
262                 PangoStyle v=pango_font_description_get_style(descr);
263                 if ( v == PANGO_STYLE_ITALIC ) {
264                         res=(char*)"italic";
265                 } else if ( v == PANGO_STYLE_OBLIQUE ) {
266                         res=(char*)"oblique";
267                 } else {
268                         res=(char*)"normal";
269                 }
270                 free_res=false;
271         } else if ( strcmp(key,"weight") == 0 ) {
272                 PangoWeight v=pango_font_description_get_weight(descr);
273                 if ( v <= PANGO_WEIGHT_ULTRALIGHT ) {
274                         res=(char*)"200";
275                 } else if ( v <= PANGO_WEIGHT_LIGHT ) {
276                         res=(char*)"300";
277                 } else if ( v <= PANGO_WEIGHT_NORMAL ) {
278                         res=(char*)"normal";
279                 } else if ( v <= PANGO_WEIGHT_BOLD ) {
280                         res=(char*)"bold";
281                 } else if ( v <= PANGO_WEIGHT_ULTRABOLD ) {
282                     res=(char*)"800";
283                 } else { // HEAVY
284                         res=(char*)"900";
285                 }
286                 free_res=false;
287         } else if ( strcmp(key,"stretch") == 0 ) {
288                 PangoStretch v=pango_font_description_get_stretch(descr);
289                 if ( v <= PANGO_STRETCH_EXTRA_CONDENSED ) {
290                         res=(char*)"extra-condensed";
291                 } else if ( v <= PANGO_STRETCH_CONDENSED ) {
292                         res=(char*)"condensed";
293                 } else if ( v <= PANGO_STRETCH_SEMI_CONDENSED ) {
294                         res=(char*)"semi-condensed";
295                 } else if ( v <= PANGO_STRETCH_NORMAL ) {
296                         res=(char*)"normal";
297                 } else if ( v <= PANGO_STRETCH_SEMI_EXPANDED ) {
298                         res=(char*)"semi-expanded";
299                 } else if ( v <= PANGO_STRETCH_EXPANDED ) {
300                         res=(char*)"expanded";
301                 } else {
302                         res=(char*)"extra-expanded";
303                 }
304                 free_res=false;
305         } else if ( strcmp(key,"variant") == 0 ) {
306                 PangoVariant v=pango_font_description_get_variant(descr);
307                 if ( v == PANGO_VARIANT_SMALL_CAPS ) {
308                         res=(char*)"small-caps";
309                 } else {
310                         res=(char*)"normal";
311                 }
312                 free_res=false;
313         } else {
314                 res = NULL;
315                 free_res=false;
316         }
317         if ( res == NULL ) {
318                 if ( size > 0 ) str[0]=0;
319                 return 0;
320         }
322         if (res) {
323                 unsigned int len=strlen(res);
324                 unsigned int rlen=(size-1<len)?size-1:len;
325                 if ( str ) {
326                         if ( rlen > 0 ) memcpy(str,res,rlen);
327                         if ( size > 0 ) str[rlen]=0;
328                 }
329                 if (free_res) free(res);
330                 return len;
331         }
332         return 0;
335 void font_instance::InitTheFace()
337 #ifdef USE_PANGO_WIN32
338     if ( !theFace ) {
339         LOGFONT *lf=pango_win32_font_logfont(pFont);
340         g_assert(lf != NULL);
341         theFace=pango_win32_font_cache_load(daddy->pangoFontCache,lf);
342         g_free(lf);
343     }
344     XFORM identity = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
345     SetWorldTransform(daddy->hScreenDC, &identity);
346     SetGraphicsMode(daddy->hScreenDC, GM_COMPATIBLE);
347     SelectObject(daddy->hScreenDC,theFace);
348 #else
349         theFace=pango_ft2_font_get_face(pFont);
350     if ( theFace )
351         FT_Select_Charmap(theFace,ft_encoding_unicode) && FT_Select_Charmap(theFace,ft_encoding_symbol);
352 #endif
355 void font_instance::FreeTheFace()
357 #ifdef USE_PANGO_WIN32
358     SelectObject(daddy->hScreenDC,GetStockObject(SYSTEM_FONT));
359     pango_win32_font_cache_unload(daddy->pangoFontCache,theFace);
360 #endif
361     theFace=NULL;
364 void font_instance::InstallFace(PangoFont* iFace)
366         if ( !iFace )
367             return;
368         pFont=iFace;
370     InitTheFace();
372         if ( pFont && IsOutlineFont() == false ) {
373         FreeTheFace();
374                 if ( pFont ) g_object_unref(pFont);
375                 pFont=NULL;
376         }
379 bool    font_instance::IsOutlineFont(void)
381         if ( pFont == NULL ) return false;
382     InitTheFace();
383 #ifdef USE_PANGO_WIN32
384     TEXTMETRIC tm;
385     return GetTextMetrics(daddy->hScreenDC,&tm) && tm.tmPitchAndFamily&(TMPF_TRUETYPE|TMPF_DEVICE);
386 #else
387         return FT_IS_SCALABLE(theFace);
388 #endif
391 int font_instance::MapUnicodeChar(gunichar c)
393         if ( pFont == NULL ) return 0;
394 #ifdef USE_PANGO_WIN32
395     return pango_win32_font_get_glyph_index(pFont,c);
396 #else
397         int res=0;
398         theFace=pango_ft2_font_get_face(pFont);
399         if ( c > 0xf0000 ) {
400                 res=CLAMP(c,0xf0000,0x1fffff)-0xf0000;
401         } else {
402                 res=FT_Get_Char_Index(theFace, c);
403         }
404         return res;
405 #endif
409 #ifdef USE_PANGO_WIN32
410 static inline Geom::Point pointfx_to_nrpoint(const POINTFX &p, double scale)
412     return Geom::Point(*(long*)&p.x / 65536.0 * scale,
413                      *(long*)&p.y / 65536.0 * scale);
415 #endif
417 void font_instance::LoadGlyph(int glyph_id)
419         if ( pFont == NULL ) return;
420     InitTheFace();
421 #ifndef USE_PANGO_WIN32
422         if ( !FT_IS_SCALABLE(theFace) ) return; // bitmap font
423 #endif
425         if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
426                 if ( nbGlyph >= maxGlyph ) {
427                         maxGlyph=2*nbGlyph+1;
428                         glyphs=(font_glyph*)realloc(glyphs,maxGlyph*sizeof(font_glyph));
429                 }
430                 font_glyph  n_g;
431                 n_g.outline=NULL;
432         n_g.pathvector=NULL;
433                 n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0;
434                 bool   doAdd=false;
436 #ifdef USE_PANGO_WIN32
438 #ifndef GGO_UNHINTED         // For compatibility with old SDKs.
439 #define GGO_UNHINTED 0x0100
440 #endif
442         MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
443         OUTLINETEXTMETRIC otm;
444         GetOutlineTextMetrics(daddy->hScreenDC, sizeof(otm), &otm);
445         GLYPHMETRICS metrics;
446         DWORD bufferSize=GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity);
447         double scale=1.0/daddy->fontSize;
448         n_g.h_advance=metrics.gmCellIncX*scale;
449         n_g.v_advance=otm.otmTextMetrics.tmHeight*scale;
450         n_g.h_width=metrics.gmBlackBoxX*scale;
451         n_g.v_width=metrics.gmBlackBoxY*scale;
452         n_g.outline=NULL;
453         if ( bufferSize == GDI_ERROR) {
454             // shit happened
455         } else if ( bufferSize == 0) {
456             // character has no visual representation, but is valid (eg whitespace)
457             doAdd=true;
458         } else {
459             std::auto_ptr<char> buffer(new char[bufferSize]);
460             if ( GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, bufferSize, buffer.get(), &identity) <= 0 ) {
461                 // shit happened
462             } else {
463                 // Platform SDK is rubbish, read KB87115 instead
464                 n_g.outline=new Path;
465                 DWORD polyOffset=0;
466                 while ( polyOffset < bufferSize ) {
467                     TTPOLYGONHEADER const *polyHeader=(TTPOLYGONHEADER const *)(buffer.get()+polyOffset);
468                     if (polyOffset+polyHeader->cb > bufferSize) break;
470                     if (polyHeader->dwType == TT_POLYGON_TYPE) {
471                         n_g.outline->MoveTo(pointfx_to_nrpoint(polyHeader->pfxStart, scale));
472                         DWORD curveOffset=polyOffset+sizeof(TTPOLYGONHEADER);
474                         while ( curveOffset < polyOffset+polyHeader->cb ) {
475                             TTPOLYCURVE const *polyCurve=(TTPOLYCURVE const *)(buffer.get()+curveOffset);
476                             POINTFX const *p=polyCurve->apfx;
477                             POINTFX const *endp=p+polyCurve->cpfx;
479                             switch (polyCurve->wType) {
480                                 case TT_PRIM_LINE:
481                                     while ( p != endp )
482                                         n_g.outline->LineTo(pointfx_to_nrpoint(*p++, scale));
483                                     break;
485                                 case TT_PRIM_QSPLINE:
486                                 {
487                                     g_assert(polyCurve->cpfx >= 2);
488                                     endp -= 2;
489                                     Geom::Point this_mid=pointfx_to_nrpoint(p[0], scale);
490                                     while ( p != endp ) {
491                                         Geom::Point next_mid=pointfx_to_nrpoint(p[1], scale);
492                                             n_g.outline->BezierTo((next_mid+this_mid)/2);
493                                             n_g.outline->IntermBezierTo(this_mid);
494                                             n_g.outline->EndBezierTo();
495                                         ++p;
496                                         this_mid=next_mid;
497                                     }
498                                         n_g.outline->BezierTo(pointfx_to_nrpoint(p[1], scale));
499                                         n_g.outline->IntermBezierTo(this_mid);
500                                         n_g.outline->EndBezierTo();
501                                     break;
502                                 }
504                                 case 3:  // TT_PRIM_CSPLINE
505                                     g_assert(polyCurve->cpfx % 3 == 0);
506                                     while ( p != endp ) {
507                                         n_g.outline->CubicTo(pointfx_to_nrpoint(p[2], scale), pointfx_to_nrpoint(p[0], scale), pointfx_to_nrpoint(p[1], scale));
508                                         p += 3;
509                                     }
510                                     break;
511                             }
512                             curveOffset += sizeof(TTPOLYCURVE)+sizeof(POINTFX)*(polyCurve->cpfx-1);
513                         }
514                         n_g.outline->Close();
515                     }
516                     polyOffset += polyHeader->cb;
517                 }
518                 doAdd=true;
519             }
520         }
521 #else
522                 if (FT_Load_Glyph (theFace, glyph_id, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) {
523                         // shit happened
524                 } else {
525                         if ( FT_HAS_HORIZONTAL(theFace) ) {
526                                 n_g.h_advance=((double)theFace->glyph->metrics.horiAdvance)/((double)theFace->units_per_EM);
527                                 n_g.h_width=((double)theFace->glyph->metrics.width)/((double)theFace->units_per_EM);
528                         } else {
529                                 n_g.h_width=n_g.h_advance=((double)(theFace->bbox.xMax-theFace->bbox.xMin))/((double)theFace->units_per_EM);
530                         }
531                         if ( FT_HAS_VERTICAL(theFace) ) {
532                                 n_g.v_advance=((double)theFace->glyph->metrics.vertAdvance)/((double)theFace->units_per_EM);
533                                 n_g.v_width=((double)theFace->glyph->metrics.height)/((double)theFace->units_per_EM);
534                         } else {
535                                 n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM);
536                         }
537                         if ( theFace->glyph->format == ft_glyph_format_outline ) {
538                                 FT_Outline_Funcs ft2_outline_funcs = {
539                                         ft2_move_to,
540                                         ft2_line_to,
541                                         ft2_conic_to,
542                                         ft2_cubic_to,
543                                         0, 0
544                                 };
545                                 n_g.outline=new Path;
546                                 ft2_to_liv   tData;
547                                 tData.theP=n_g.outline;
548                                 tData.scale=1.0/((double)theFace->units_per_EM);
549                                 tData.last=Geom::Point(0,0);
550                                 FT_Outline_Decompose (&theFace->glyph->outline, &ft2_outline_funcs, &tData);
551                         }
552                         doAdd=true;
553                 }
554 #endif
556                 if ( doAdd ) {
557                         if ( n_g.outline ) {
558                                 n_g.outline->FastBBox(n_g.bbox[0],n_g.bbox[1],n_g.bbox[2],n_g.bbox[3]);
559                 n_g.pathvector=n_g.outline->MakePathVector();
560                         }
561                         glyphs[nbGlyph]=n_g;
562                         id_to_no[glyph_id]=nbGlyph;
563                         nbGlyph++;
564                 }
565     } else {
566     }
569 bool font_instance::FontMetrics(double &ascent,double &descent,double &leading)
571         if ( pFont == NULL ) return false;
572     InitTheFace();
573         if ( theFace == NULL ) return false;
574 #ifdef USE_PANGO_WIN32
575     OUTLINETEXTMETRIC otm;
576     if ( !GetOutlineTextMetrics(daddy->hScreenDC,sizeof(otm),&otm) ) return false;
577     double scale=1.0/daddy->fontSize;
578     ascent=fabs(otm.otmAscent*scale);
579     descent=fabs(otm.otmDescent*scale);
580     leading=fabs(otm.otmLineGap*scale);
581 #else
582         if ( theFace->units_per_EM == 0 ) return false; // bitmap font
583         ascent=fabs(((double)theFace->ascender)/((double)theFace->units_per_EM));
584         descent=fabs(((double)theFace->descender)/((double)theFace->units_per_EM));
585         leading=fabs(((double)theFace->height)/((double)theFace->units_per_EM));
586         leading-=ascent+descent;
587 #endif
588         return true;
591 bool font_instance::FontSlope(double &run, double &rise)
593     run = 0.0;
594     rise = 1.0;
596         if ( pFont == NULL ) return false;
597     InitTheFace();
598         if ( theFace == NULL ) return false;
600 #ifdef USE_PANGO_WIN32
601     OUTLINETEXTMETRIC otm;
602     if ( !GetOutlineTextMetrics(daddy->hScreenDC,sizeof(otm),&otm) ) return false;
603     run=otm.otmsCharSlopeRun;
604     rise=otm.otmsCharSlopeRise;
605 #else
606         if ( !FT_IS_SCALABLE(theFace) ) return false; // bitmap font
608     TT_HoriHeader *hhea = (TT_HoriHeader*)FT_Get_Sfnt_Table(theFace, ft_sfnt_hhea);
609     if (hhea == NULL) return false;
610     run = hhea->caret_Slope_Run;
611     rise = hhea->caret_Slope_Rise;
612 #endif
613         return true;
616 boost::optional<Geom::Rect> font_instance::BBox(int glyph_id)
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 ) {
630             return boost::optional<Geom::Rect>();
631         } else {
632             Geom::Point rmin(glyphs[no].bbox[0],glyphs[no].bbox[1]);
633             Geom::Point rmax(glyphs[no].bbox[2],glyphs[no].bbox[3]);
634             return Geom::Rect(rmin, rmax);
635         }
638 Path* font_instance::Outline(int glyph_id,Path* copyInto)
640         int no=-1;
641         if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
642                 LoadGlyph(glyph_id);
643                 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
644                         // didn't load
645                 } else {
646                         no=id_to_no[glyph_id];
647                 }
648         } else {
649                 no=id_to_no[glyph_id];
650         }
651         if ( no < 0 ) return NULL;
652         Path*    src_o=glyphs[no].outline;
653         if ( copyInto ) {
654                 copyInto->Reset();
655                 copyInto->Copy(src_o);
656                 return copyInto;
657         }
658         return src_o;
661 Geom::PathVector* font_instance::PathVector(int glyph_id)
663     int no = -1;
664     if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
665         LoadGlyph(glyph_id);
666         if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
667             // didn't load
668         } else {
669             no = id_to_no[glyph_id];
670         }
671     } else {
672         no = id_to_no[glyph_id];
673     }
674     if ( no < 0 ) return NULL;
675     return glyphs[no].pathvector;
678 double font_instance::Advance(int glyph_id,bool vertical)
680         int no=-1;
681         if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
682                 LoadGlyph(glyph_id);
683                 if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
684                         // didn't load
685                 } else {
686                         no=id_to_no[glyph_id];
687                 }
688         } else {
689                 no=id_to_no[glyph_id];
690         }
691         if ( no >= 0 ) {
692                 if ( vertical ) {
693                         return glyphs[no].v_advance;
694                 } else {
695                         return glyphs[no].h_advance;
696                 }
697         }
698         return 0;
702 raster_font* font_instance::RasterFont(const Geom::Matrix &trs, double stroke_width, bool vertical, JoinType stroke_join, ButtType stroke_cap, float /*miter_limit*/)
704         font_style  nStyle;
705         nStyle.transform=trs;
706         nStyle.vertical=vertical;
707         nStyle.stroke_width=stroke_width;
708         nStyle.stroke_cap=stroke_cap;
709         nStyle.stroke_join=stroke_join;
710         nStyle.nbDash=0;
711         nStyle.dash_offset=0;
712         nStyle.dashes=NULL;
713         return RasterFont(nStyle);
716 raster_font* font_instance::RasterFont(const font_style &inStyle)
718         raster_font  *res=NULL;
719         double *savDashes=NULL;
720         font_style nStyle=inStyle;
721     // for some evil reason font_style doesn't have a copy ctor, so the
722     // stuff that should be done there is done here instead (because the
723     // raster_font ctor copies nStyle).
724         if ( nStyle.stroke_width > 0 && nStyle.nbDash > 0 && nStyle.dashes ) {
725                 savDashes=nStyle.dashes;
726                 nStyle.dashes=(double*)malloc(nStyle.nbDash*sizeof(double));
727                 memcpy(nStyle.dashes,savDashes,nStyle.nbDash*sizeof(double));
728         }
729         if ( loadedStyles.find(nStyle) == loadedStyles.end() ) {
730                 raster_font *nR = new raster_font(nStyle);
731                 nR->Ref();
732                 nR->daddy=this;
733                 loadedStyles[nStyle]=nR;
734                 res=nR;
735                 if ( res ) Ref();
736         } else {
737                 res=loadedStyles[nStyle];
738                 res->Ref();
739                 if ( nStyle.dashes ) free(nStyle.dashes); // since they're not taken by a new rasterfont
740         }
741         nStyle.dashes=savDashes;
742         return res;
745 void font_instance::RemoveRasterFont(raster_font* who)
747         if ( who == NULL ) return;
748         if ( loadedStyles.find(who->style) == loadedStyles.end() ) {
749                 //g_print("RemoveRasterFont failed \n");
750                 // not found
751         } else {
752                 loadedStyles.erase(loadedStyles.find(who->style));
753                 //g_print("RemoveRasterFont\n");
754                 Unref();
755         }
760 /*
761  Local Variables:
762  mode:c++
763  c-file-style:"stroustrup"
764  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
765  indent-tabs-mode:nil
766  fill-column:99
767  End:
768  */
769 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :