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