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