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;
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;
102 }
104 static int ft2_line_to (FT_Vector * to, void * i_user)
105 {
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;
112 }
114 static int ft2_conic_to (FT_Vector * control, FT_Vector * to, void * i_user)
115 {
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;
124 }
126 static int ft2_cubic_to (FT_Vector * control1, FT_Vector * control2, FT_Vector * to, void * i_user)
127 {
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;
136 }
137 #endif
139 /*
140 *
141 */
143 font_instance::font_instance(void)
144 {
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;
153 }
155 font_instance::~font_instance(void)
156 {
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;
173 }
175 void font_instance::Ref(void)
176 {
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);
181 }
183 void font_instance::Unref(void)
184 {
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 }
194 }
196 unsigned int font_instance::Name(gchar *str, unsigned int size)
197 {
198 return Attribute("name", str, size);
199 }
201 unsigned int font_instance::Family(gchar *str, unsigned int size)
202 {
203 return Attribute("family", str, size);
204 }
206 unsigned int font_instance::PSName(gchar *str, unsigned int size)
207 {
208 return Attribute("psname", str, size);
209 }
211 unsigned int font_instance::Attribute(const gchar *key, gchar *str, unsigned int size)
212 {
213 if ( descr == NULL ) {
214 if ( size > 0 ) str[0]=0;
215 return 0;
216 }
217 char* res=NULL;
218 bool free_res=false;
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);
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 }
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;
318 }
320 void font_instance::InitTheFace()
321 {
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
338 }
340 void font_instance::FreeTheFace()
341 {
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;
347 }
349 void font_instance::InstallFace(PangoFont* iFace)
350 {
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 }
362 }
364 bool font_instance::IsOutlineFont(void)
365 {
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
374 }
376 int font_instance::MapUnicodeChar(gunichar c)
377 {
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
391 }
394 #ifdef USE_PANGO_WIN32
395 static inline NR::Point pointfx_to_nrpoint(const POINTFX &p, double scale)
396 {
397 return NR::Point(*(long*)&p.x / 65536.0 * scale,
398 *(long*)&p.y / 65536.0 * scale);
399 }
400 #endif
402 void font_instance::LoadGlyph(int glyph_id)
403 {
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 (FT_Outline_MoveToFunc) ft2_move_to,
520 (FT_Outline_LineToFunc) ft2_line_to,
521 (FT_Outline_ConicToFunc) ft2_conic_to,
522 (FT_Outline_CubicToFunc) 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 }
547 }
549 bool font_instance::FontMetrics(double &ascent,double &descent,double &leading)
550 {
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 ( !FT_IS_SCALABLE(theFace) ) 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;
569 }
571 bool font_instance::FontSlope(double &run, double &rise)
572 {
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
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;
594 }
596 NR::Rect font_instance::BBox(int glyph_id)
597 {
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;
614 }
616 Path* font_instance::Outline(int glyph_id,Path* copyInto)
617 {
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;
637 }
639 void* font_instance::ArtBPath(int glyph_id)
640 {
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;
654 }
656 double font_instance::Advance(int glyph_id,bool vertical)
657 {
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)
681 {
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);
692 }
694 raster_font* font_instance::RasterFont(const font_style &inStyle)
695 {
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;
721 }
723 void font_instance::RemoveRasterFont(raster_font* who)
724 {
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 }
734 }
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 :