11
11
#define PANGO_ENABLE_ENGINE
13
13
#ifdef HAVE_CONFIG_H
16
#include <libnr/nr-rect.h>
17
#include <libnrtype/font-glyph.h>
18
#include <libnrtype/font-instance.h>
20
#include FT_TRUETYPE_TAGS_H
21
#include FT_TRUETYPE_TABLES_H
22
#include <pango/pangoft2.h>
19
23
#include <2geom/pathvector.h>
20
#include <livarot/Path.h>
22
#include "RasterFont.h"
25
# include <ft2build.h>
26
# include FT_OUTLINE_H
28
# include FT_TRUETYPE_TAGS_H
29
# include FT_TRUETYPE_TABLES_H
30
# include <pango/pangoft2.h>
34
size_t font_style_hash::operator()(const font_style &x) const {
36
n=(int)floor(100*x.stroke_width);
42
if ( x.stroke_width >= 0.01 ) {
43
n=x.stroke_cap*10+x.stroke_join+(int)(x.stroke_miter_limit*100);
50
n=(int)floor(100*x.dash_offset);
53
for (int i=0;i<x.nbDash;i++) {
54
n=(int)floor(100*x.dashes[i]);
24
#include "libnr/nr-rect.h"
25
#include "libnrtype/font-glyph.h"
26
#include "libnrtype/font-instance.h"
27
#include "libnrtype/RasterFont.h"
28
#include "livarot/Path.h"
29
#include "util/unordered-containers.h"
31
#if !PANGO_VERSION_CHECK(1,24,0)
32
#define PANGO_WEIGHT_THIN static_cast<PangoWeight>(100)
33
#define PANGO_WEIGHT_BOOK static_cast<PangoWeight>(380)
34
#define PANGO_WEIGHT_MEDIUM static_cast<PangoWeight>(500)
35
#define PANGO_WEIGHT_ULTRAHEAVY static_cast<PangoWeight>(1000)
39
struct font_style_hash : public std::unary_function<font_style, size_t> {
40
size_t operator()(font_style const &x) const;
43
struct font_style_equal : public std::binary_function<font_style, font_style, bool> {
44
bool operator()(font_style const &a, font_style const &b) const;
47
typedef INK_UNORDERED_MAP<font_style, raster_font*, font_style_hash, font_style_equal> StyleMap;
49
static const double STROKE_WIDTH_THREASHOLD = 0.01;
53
size_t font_style_hash::operator()(const font_style &x) const {
55
int n = static_cast<int>(floor(100 * x.stroke_width));
58
n = (x.vertical) ? 1:0;
61
if ( x.stroke_width >= STROKE_WIDTH_THREASHOLD ) {
62
n = x.stroke_cap * 10 + x.stroke_join + static_cast<int>(x.stroke_miter_limit * 100);
69
n = static_cast<int>(floor(100 * x.dash_offset));
72
for (int i = 0; i < x.nbDash; i++) {
73
n = static_cast<int>(floor(100 * x.dashes[i]));
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;
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;
82
bool font_style_equal::operator()(const font_style &a,const font_style &b) const {
84
for (int i = 0; (i < 6) && same; i++) {
85
same = ( static_cast<int>(100 * a.transform[i]) == static_cast<int>(100 * b.transform[i]) );
87
same &= ( a.vertical == b.vertical )
88
&& ( a.stroke_width > STROKE_WIDTH_THREASHOLD ) == ( b.stroke_width > STROKE_WIDTH_THREASHOLD );
89
if ( same && ( a.stroke_width > STROKE_WIDTH_THREASHOLD ) ) {
90
same = ( a.stroke_cap == b.stroke_cap )
91
&& ( a.stroke_join == b.stroke_join )
92
&& ( static_cast<int>(a.stroke_miter_limit * 100) == static_cast<int>(b.stroke_miter_limit * 100) )
93
&& ( a.nbDash == b.nbDash );
94
if ( same && ( a.nbDash > 0 ) ) {
95
same = ( static_cast<int>(floor(100 * a.dash_offset)) == static_cast<int>(floor(100 * b.dash_offset)) );
96
for (int i = 0; (i < a.nbDash) && same; i++) {
97
same = ( static_cast<int>(floor(100 * a.dashes[i])) == static_cast<int>(floor(100 * b.dashes[i])) );
85
104
#ifndef USE_PANGO_WIN32
106
125
// outline as returned by freetype -> livarot Path
107
126
// see nr-type-ft2.cpp for the freetype -> artBPath on which this code is based
108
127
static int ft2_move_to(FREETYPE_VECTOR *to, void * i_user) {
109
ft2_to_liv* user=(ft2_to_liv*)i_user;
110
Geom::Point p(user->scale*to->x,user->scale*to->y);
111
// printf("m t=%f %f\n",p[0],p[1]);
112
user->theP->MoveTo(p);
128
ft2_to_liv* user=(ft2_to_liv*)i_user;
129
Geom::Point p(user->scale*to->x,user->scale*to->y);
130
// printf("m t=%f %f\n",p[0],p[1]);
131
user->theP->MoveTo(p);
117
136
static int ft2_line_to(FREETYPE_VECTOR *to, void *i_user)
119
ft2_to_liv* user=(ft2_to_liv*)i_user;
120
Geom::Point p(user->scale*to->x,user->scale*to->y);
121
// printf("l t=%f %f\n",p[0],p[1]);
122
user->theP->LineTo(p);
138
ft2_to_liv* user=(ft2_to_liv*)i_user;
139
Geom::Point p(user->scale*to->x,user->scale*to->y);
140
// printf("l t=%f %f\n",p[0],p[1]);
141
user->theP->LineTo(p);
127
146
static int ft2_conic_to(FREETYPE_VECTOR *control, FREETYPE_VECTOR *to, void *i_user)
129
ft2_to_liv* user=(ft2_to_liv*)i_user;
130
Geom::Point p(user->scale*to->x,user->scale*to->y),c(user->scale*control->x,user->scale*control->y);
131
// printf("b c=%f %f t=%f %f\n",c[0],c[1],p[0],p[1]);
132
user->theP->BezierTo(p);
133
user->theP->IntermBezierTo(c);
134
user->theP->EndBezierTo();
148
ft2_to_liv* user=(ft2_to_liv*)i_user;
149
Geom::Point p(user->scale*to->x,user->scale*to->y),c(user->scale*control->x,user->scale*control->y);
150
// printf("b c=%f %f t=%f %f\n",c[0],c[1],p[0],p[1]);
151
user->theP->BezierTo(p);
152
user->theP->IntermBezierTo(c);
153
user->theP->EndBezierTo();
139
158
static int ft2_cubic_to(FREETYPE_VECTOR *control1, FREETYPE_VECTOR *control2, FREETYPE_VECTOR *to, void *i_user)
141
ft2_to_liv* user=(ft2_to_liv*)i_user;
142
Geom::Point p(user->scale*to->x,user->scale*to->y),
143
c1(user->scale*control1->x,user->scale*control1->y),
144
c2(user->scale*control2->x,user->scale*control2->y);
145
// printf("c c1=%f %f c2=%f %f t=%f %f\n",c1[0],c1[1],c2[0],c2[1],p[0],p[1]);
146
user->theP->CubicTo(p,3*(c1-user->last),3*(p-c2));
160
ft2_to_liv* user=(ft2_to_liv*)i_user;
161
Geom::Point p(user->scale*to->x,user->scale*to->y);
162
Geom::Point c1(user->scale*control1->x,user->scale*control1->y);
163
Geom::Point c2(user->scale*control2->x,user->scale*control2->y);
164
// printf("c c1=%f %f c2=%f %f t=%f %f\n",c1[0],c1[1],c2[0],c2[1],p[0],p[1]);
165
user->theP->CubicTo(p,3*(c1-user->last),3*(p-c2));
158
font_instance::font_instance(void)
177
font_instance::font_instance(void) :
185
loadedPtr(new StyleMap()),
160
//printf("font instance born\n");
188
//printf("font instance born\n");
170
191
font_instance::~font_instance(void)
172
if ( daddy ) daddy->UnrefFace(this);
173
//printf("font instance death\n");
174
if ( pFont ) g_object_unref(pFont);
176
if ( descr ) pango_font_description_free(descr);
178
// if ( theFace ) FT_Done_Face(theFace); // owned by pFont. don't touch
181
for (int i=0;i<nbGlyph;i++) {
182
if ( glyphs[i].outline ) delete glyphs[i].outline;
183
if ( glyphs[i].pathvector ) delete glyphs[i].pathvector;
185
if ( glyphs ) free(glyphs);
194
StyleMap* tmp = static_cast<StyleMap*>(loadedPtr);
200
daddy->UnrefFace(this);
204
//printf("font instance death\n");
206
g_object_unref(pFont);
211
pango_font_description_free(descr);
215
// if ( theFace ) FT_Done_Face(theFace); // owned by pFont. don't touch
218
for (int i=0;i<nbGlyph;i++) {
219
if ( glyphs[i].outline ) {
220
delete glyphs[i].outline;
222
if ( glyphs[i].pathvector ) {
223
delete glyphs[i].pathvector;
190
234
void font_instance::Ref(void)
193
//char *tc=pango_font_description_to_string(descr);
194
//printf("font %x %s ref'd %i\n",this,tc,refCount);
237
//char *tc=pango_font_description_to_string(descr);
238
//printf("font %x %s ref'd %i\n",this,tc,refCount);
198
242
void font_instance::Unref(void)
201
//char *tc=pango_font_description_to_string(descr);
202
//printf("font %x %s unref'd %i\n",this,tc,refCount);
204
if ( refCount <= 0 ) {
205
if ( daddy ) daddy->UnrefFace(this);
245
//char *tc=pango_font_description_to_string(descr);
246
//printf("font %x %s unref'd %i\n",this,tc,refCount);
248
if ( refCount <= 0 ) {
250
daddy->UnrefFace(this);
211
257
unsigned int font_instance::Name(gchar *str, unsigned int size)
213
return Attribute("name", str, size);
259
return Attribute("name", str, size);
216
262
unsigned int font_instance::Family(gchar *str, unsigned int size)
218
return Attribute("family", str, size);
264
return Attribute("family", str, size);
221
267
unsigned int font_instance::PSName(gchar *str, unsigned int size)
223
return Attribute("psname", str, size);
269
return Attribute("psname", str, size);
226
272
unsigned int font_instance::Attribute(const gchar *key, gchar *str, unsigned int size)
228
if ( descr == NULL ) {
229
if ( size > 0 ) str[0]=0;
274
if ( descr == NULL ) {
235
if ( strcmp(key,"name") == 0 ) {
236
PangoFontDescription* td=pango_font_description_copy(descr);
237
pango_font_description_unset_fields (td, PANGO_FONT_MASK_SIZE);
238
res=pango_font_description_to_string (td);
239
pango_font_description_free(td);
241
} else if ( strcmp(key,"psname") == 0 ) {
283
if ( strcmp(key,"name") == 0 ) {
284
PangoFontDescription* td=pango_font_description_copy(descr);
285
pango_font_description_unset_fields (td, PANGO_FONT_MASK_SIZE);
286
res=pango_font_description_to_string (td);
287
pango_font_description_free(td);
289
} else if ( strcmp(key,"psname") == 0 ) {
242
290
#ifndef USE_PANGO_WIN32
243
291
res = (char *) FT_Get_Postscript_Name (theFace); // that's the main method, seems to always work
257
305
(i) ? "Italic" : ((o) ? "Oblique" : "") );
260
} else if ( strcmp(key,"family") == 0 ) {
261
res=(char*)pango_font_description_get_family(descr);
263
} else if ( strcmp(key,"style") == 0 ) {
264
PangoStyle v=pango_font_description_get_style(descr);
265
if ( v == PANGO_STYLE_ITALIC ) {
267
} else if ( v == PANGO_STYLE_OBLIQUE ) {
268
res=(char*)"oblique";
273
} else if ( strcmp(key,"weight") == 0 ) {
274
PangoWeight v=pango_font_description_get_weight(descr);
275
if ( v <= PANGO_WEIGHT_ULTRALIGHT ) {
277
} else if ( v <= PANGO_WEIGHT_LIGHT ) {
279
} else if ( v <= PANGO_WEIGHT_NORMAL ) {
281
} else if ( v <= PANGO_WEIGHT_BOLD ) {
283
} else if ( v <= PANGO_WEIGHT_ULTRABOLD ) {
289
} else if ( strcmp(key,"stretch") == 0 ) {
290
PangoStretch v=pango_font_description_get_stretch(descr);
291
if ( v <= PANGO_STRETCH_EXTRA_CONDENSED ) {
292
res=(char*)"extra-condensed";
293
} else if ( v <= PANGO_STRETCH_CONDENSED ) {
294
res=(char*)"condensed";
295
} else if ( v <= PANGO_STRETCH_SEMI_CONDENSED ) {
296
res=(char*)"semi-condensed";
297
} else if ( v <= PANGO_STRETCH_NORMAL ) {
299
} else if ( v <= PANGO_STRETCH_SEMI_EXPANDED ) {
300
res=(char*)"semi-expanded";
301
} else if ( v <= PANGO_STRETCH_EXPANDED ) {
302
res=(char*)"expanded";
304
res=(char*)"extra-expanded";
307
} else if ( strcmp(key,"variant") == 0 ) {
308
PangoVariant v=pango_font_description_get_variant(descr);
309
if ( v == PANGO_VARIANT_SMALL_CAPS ) {
310
res=(char*)"small-caps";
320
if ( size > 0 ) str[0]=0;
308
} else if ( strcmp(key,"family") == 0 ) {
309
res=(char*)pango_font_description_get_family(descr);
311
} else if ( strcmp(key,"style") == 0 ) {
312
PangoStyle v=pango_font_description_get_style(descr);
313
if ( v == PANGO_STYLE_ITALIC ) {
315
} else if ( v == PANGO_STYLE_OBLIQUE ) {
316
res=(char*)"oblique";
321
} else if ( strcmp(key,"weight") == 0 ) {
322
PangoWeight v=pango_font_description_get_weight(descr);
323
if ( v <= PANGO_WEIGHT_THIN ) {
325
} else if ( v <= PANGO_WEIGHT_ULTRALIGHT ) {
327
} else if ( v <= PANGO_WEIGHT_LIGHT ) {
329
} else if ( v <= PANGO_WEIGHT_BOOK ) {
331
} else if ( v <= PANGO_WEIGHT_NORMAL ) {
333
} else if ( v <= PANGO_WEIGHT_MEDIUM ) {
335
} else if ( v <= PANGO_WEIGHT_SEMIBOLD ) {
337
} else if ( v <= PANGO_WEIGHT_BOLD ) {
339
} else if ( v <= PANGO_WEIGHT_ULTRABOLD ) {
341
} else { // HEAVY NB: Pango defines ULTRAHEAVY = 1000 but not CSS2
345
} else if ( strcmp(key,"stretch") == 0 ) {
346
PangoStretch v=pango_font_description_get_stretch(descr);
347
if ( v <= PANGO_STRETCH_EXTRA_CONDENSED ) {
348
res=(char*)"extra-condensed";
349
} else if ( v <= PANGO_STRETCH_CONDENSED ) {
350
res=(char*)"condensed";
351
} else if ( v <= PANGO_STRETCH_SEMI_CONDENSED ) {
352
res=(char*)"semi-condensed";
353
} else if ( v <= PANGO_STRETCH_NORMAL ) {
355
} else if ( v <= PANGO_STRETCH_SEMI_EXPANDED ) {
356
res=(char*)"semi-expanded";
357
} else if ( v <= PANGO_STRETCH_EXPANDED ) {
358
res=(char*)"expanded";
360
res=(char*)"extra-expanded";
363
} else if ( strcmp(key,"variant") == 0 ) {
364
PangoVariant v=pango_font_description_get_variant(descr);
365
if ( v == PANGO_VARIANT_SMALL_CAPS ) {
366
res=(char*)"small-caps";
325
unsigned int len=strlen(res);
326
unsigned int rlen=(size-1<len)?size-1:len;
328
if ( rlen > 0 ) memcpy(str,res,rlen);
329
if ( size > 0 ) str[rlen]=0;
331
if (free_res) free(res);
383
unsigned int len=strlen(res);
384
unsigned int rlen=(size-1<len)?size-1:len;
387
memcpy(str, res, rlen);
337
401
void font_instance::InitTheFace()
366
431
void font_instance::InstallFace(PangoFont* iFace)
374
if ( pFont && IsOutlineFont() == false ) {
440
if ( pFont && IsOutlineFont() == false ) {
376
if ( pFont ) g_object_unref(pFont);
443
g_object_unref(pFont);
381
bool font_instance::IsOutlineFont(void)
449
bool font_instance::IsOutlineFont(void)
383
if ( pFont == NULL ) return false;
451
if ( pFont == NULL ) {
385
455
#ifdef USE_PANGO_WIN32
387
457
return GetTextMetrics(daddy->hScreenDC,&tm) && tm.tmPitchAndFamily&(TMPF_TRUETYPE|TMPF_DEVICE);
389
return FT_IS_SCALABLE(theFace);
459
return FT_IS_SCALABLE(theFace);
393
463
int font_instance::MapUnicodeChar(gunichar c)
395
if ( pFont == NULL ) return 0;
396
467
#ifdef USE_PANGO_WIN32
397
return pango_win32_font_get_glyph_index(pFont,c);
468
res = pango_win32_font_get_glyph_index(pFont, c);
400
theFace=pango_ft2_font_get_face(pFont);
402
res=CLAMP(c,0xf0000,0x1fffff)-0xf0000;
404
res=FT_Get_Char_Index(theFace, c);
470
theFace = pango_ft2_font_get_face(pFont);
472
res = CLAMP(c, 0xf0000, 0x1fffff) - 0xf0000;
474
res = FT_Get_Char_Index(theFace, c);
419
490
void font_instance::LoadGlyph(int glyph_id)
421
if ( pFont == NULL ) return;
492
if ( pFont == NULL ) {
423
496
#ifndef USE_PANGO_WIN32
424
if ( !FT_IS_SCALABLE(theFace) ) return; // bitmap font
497
if ( !FT_IS_SCALABLE(theFace) ) {
498
return; // bitmap font
427
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
428
if ( nbGlyph >= maxGlyph ) {
429
maxGlyph=2*nbGlyph+1;
430
glyphs=(font_glyph*)realloc(glyphs,maxGlyph*sizeof(font_glyph));
502
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
503
if ( nbGlyph >= maxGlyph ) {
504
maxGlyph=2*nbGlyph+1;
505
glyphs=(font_glyph*)realloc(glyphs,maxGlyph*sizeof(font_glyph));
434
509
n_g.pathvector=NULL;
435
n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0;
510
n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0;
438
513
#ifdef USE_PANGO_WIN32
458
533
// character has no visual representation, but is valid (eg whitespace)
461
std::auto_ptr<char> buffer(new char[bufferSize]);
462
if ( GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, bufferSize, buffer.get(), &identity) <= 0 ) {
536
char *buffer = new char[bufferSize];
537
if ( GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, bufferSize, buffer, &identity) <= 0 ) {
465
540
// Platform SDK is rubbish, read KB87115 instead
466
541
n_g.outline=new Path;
467
542
DWORD polyOffset=0;
468
543
while ( polyOffset < bufferSize ) {
469
TTPOLYGONHEADER const *polyHeader=(TTPOLYGONHEADER const *)(buffer.get()+polyOffset);
544
TTPOLYGONHEADER const *polyHeader=(TTPOLYGONHEADER const *)(buffer+polyOffset);
470
545
if (polyOffset+polyHeader->cb > bufferSize) break;
472
547
if (polyHeader->dwType == TT_POLYGON_TYPE) {
491
566
Geom::Point this_mid=pointfx_to_nrpoint(p[0], scale);
492
567
while ( p != endp ) {
493
568
Geom::Point next_mid=pointfx_to_nrpoint(p[1], scale);
494
n_g.outline->BezierTo((next_mid+this_mid)/2);
495
n_g.outline->IntermBezierTo(this_mid);
496
n_g.outline->EndBezierTo();
569
n_g.outline->BezierTo((next_mid+this_mid)/2);
570
n_g.outline->IntermBezierTo(this_mid);
571
n_g.outline->EndBezierTo();
498
573
this_mid=next_mid;
500
n_g.outline->BezierTo(pointfx_to_nrpoint(p[1], scale));
501
n_g.outline->IntermBezierTo(this_mid);
502
n_g.outline->EndBezierTo();
575
n_g.outline->BezierTo(pointfx_to_nrpoint(p[1], scale));
576
n_g.outline->IntermBezierTo(this_mid);
577
n_g.outline->EndBezierTo();
524
if (FT_Load_Glyph (theFace, glyph_id, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) {
527
if ( FT_HAS_HORIZONTAL(theFace) ) {
528
n_g.h_advance=((double)theFace->glyph->metrics.horiAdvance)/((double)theFace->units_per_EM);
529
n_g.h_width=((double)theFace->glyph->metrics.width)/((double)theFace->units_per_EM);
531
n_g.h_width=n_g.h_advance=((double)(theFace->bbox.xMax-theFace->bbox.xMin))/((double)theFace->units_per_EM);
533
if ( FT_HAS_VERTICAL(theFace) ) {
534
n_g.v_advance=((double)theFace->glyph->metrics.vertAdvance)/((double)theFace->units_per_EM);
535
n_g.v_width=((double)theFace->glyph->metrics.height)/((double)theFace->units_per_EM);
537
n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM);
539
if ( theFace->glyph->format == ft_glyph_format_outline ) {
540
FT_Outline_Funcs ft2_outline_funcs = {
547
n_g.outline=new Path;
549
tData.theP=n_g.outline;
550
tData.scale=1.0/((double)theFace->units_per_EM);
551
tData.last=Geom::Point(0,0);
552
FT_Outline_Decompose (&theFace->glyph->outline, &ft2_outline_funcs, &tData);
600
if (FT_Load_Glyph (theFace, glyph_id, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) {
603
if ( FT_HAS_HORIZONTAL(theFace) ) {
604
n_g.h_advance=((double)theFace->glyph->metrics.horiAdvance)/((double)theFace->units_per_EM);
605
n_g.h_width=((double)theFace->glyph->metrics.width)/((double)theFace->units_per_EM);
607
n_g.h_width=n_g.h_advance=((double)(theFace->bbox.xMax-theFace->bbox.xMin))/((double)theFace->units_per_EM);
609
if ( FT_HAS_VERTICAL(theFace) ) {
610
n_g.v_advance=((double)theFace->glyph->metrics.vertAdvance)/((double)theFace->units_per_EM);
611
n_g.v_width=((double)theFace->glyph->metrics.height)/((double)theFace->units_per_EM);
613
n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM);
615
if ( theFace->glyph->format == ft_glyph_format_outline ) {
616
FT_Outline_Funcs ft2_outline_funcs = {
623
n_g.outline=new Path;
625
tData.theP=n_g.outline;
626
tData.scale=1.0/((double)theFace->units_per_EM);
627
tData.last=Geom::Point(0,0);
628
FT_Outline_Decompose (&theFace->glyph->outline, &ft2_outline_funcs, &tData);
560
n_g.outline->FastBBox(n_g.bbox[0],n_g.bbox[1],n_g.bbox[2],n_g.bbox[3]);
636
n_g.outline->FastBBox(n_g.bbox[0],n_g.bbox[1],n_g.bbox[2],n_g.bbox[3]);
561
637
n_g.pathvector=n_g.outline->MakePathVector();
564
id_to_no[glyph_id]=nbGlyph;
640
id_to_no[glyph_id]=nbGlyph;
571
647
bool font_instance::FontMetrics(double &ascent,double &descent,double &leading)
573
if ( pFont == NULL ) return false;
649
if ( pFont == NULL ) {
575
if ( theFace == NULL ) return false;
653
if ( theFace == NULL ) {
576
656
#ifdef USE_PANGO_WIN32
577
657
OUTLINETEXTMETRIC otm;
578
if ( !GetOutlineTextMetrics(daddy->hScreenDC,sizeof(otm),&otm) ) return false;
658
if ( !GetOutlineTextMetrics(daddy->hScreenDC,sizeof(otm),&otm) ) {
579
661
double scale=1.0/daddy->fontSize;
580
662
ascent=fabs(otm.otmAscent*scale);
581
663
descent=fabs(otm.otmDescent*scale);
582
664
leading=fabs(otm.otmLineGap*scale);
665
//otmSubscriptSize, otmSubscriptOffset, otmSuperscriptSize, otmSuperscriptOffset,
584
if ( theFace->units_per_EM == 0 ) return false; // bitmap font
585
ascent=fabs(((double)theFace->ascender)/((double)theFace->units_per_EM));
586
descent=fabs(((double)theFace->descender)/((double)theFace->units_per_EM));
587
leading=fabs(((double)theFace->height)/((double)theFace->units_per_EM));
588
leading-=ascent+descent;
667
if ( theFace->units_per_EM == 0 ) {
668
return false; // bitmap font
670
ascent=fabs(((double)theFace->ascender)/((double)theFace->units_per_EM));
671
descent=fabs(((double)theFace->descender)/((double)theFace->units_per_EM));
672
leading=fabs(((double)theFace->height)/((double)theFace->units_per_EM));
673
leading-=ascent+descent;
593
678
bool font_instance::FontSlope(double &run, double &rise)
605
694
run=otm.otmsCharSlopeRun;
606
695
rise=otm.otmsCharSlopeRise;
608
if ( !FT_IS_SCALABLE(theFace) ) return false; // bitmap font
697
if ( !FT_IS_SCALABLE(theFace) ) {
698
return false; // bitmap font
610
701
TT_HoriHeader *hhea = (TT_HoriHeader*)FT_Get_Sfnt_Table(theFace, ft_sfnt_hhea);
611
if (hhea == NULL) return false;
612
705
run = hhea->caret_Slope_Run;
613
706
rise = hhea->caret_Slope_Rise;
618
711
Geom::OptRect font_instance::BBox(int glyph_id)
621
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
623
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
626
no=id_to_no[glyph_id];
629
no=id_to_no[glyph_id];
632
return Geom::OptRect();
714
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
716
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
634
Geom::Point rmin(glyphs[no].bbox[0],glyphs[no].bbox[1]);
635
Geom::Point rmax(glyphs[no].bbox[2],glyphs[no].bbox[3]);
636
return Geom::Rect(rmin, rmax);
719
no = id_to_no[glyph_id];
722
no = id_to_no[glyph_id];
725
return Geom::OptRect();
727
Geom::Point rmin(glyphs[no].bbox[0],glyphs[no].bbox[1]);
728
Geom::Point rmax(glyphs[no].bbox[2],glyphs[no].bbox[3]);
729
return Geom::Rect(rmin, rmax);
640
733
Path* font_instance::Outline(int glyph_id,Path* copyInto)
643
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
645
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
648
no=id_to_no[glyph_id];
651
no=id_to_no[glyph_id];
653
if ( no < 0 ) return NULL;
654
Path* src_o=glyphs[no].outline;
657
copyInto->Copy(src_o);
736
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
738
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
741
no = id_to_no[glyph_id];
744
no = id_to_no[glyph_id];
746
if ( no < 0 ) return NULL;
747
Path *src_o = glyphs[no].outline;
750
copyInto->Copy(src_o);
663
756
Geom::PathVector* font_instance::PathVector(int glyph_id)
680
773
double font_instance::Advance(int glyph_id,bool vertical)
683
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
685
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
688
no=id_to_no[glyph_id];
691
no=id_to_no[glyph_id];
695
return glyphs[no].v_advance;
697
return glyphs[no].h_advance;
776
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
778
if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
781
no=id_to_no[glyph_id];
784
no = id_to_no[glyph_id];
788
return glyphs[no].v_advance;
790
return glyphs[no].h_advance;
704
797
raster_font* font_instance::RasterFont(const Geom::Matrix &trs, double stroke_width, bool vertical, JoinType stroke_join, ButtType stroke_cap, float /*miter_limit*/)
707
nStyle.transform=trs;
708
nStyle.vertical=vertical;
709
nStyle.stroke_width=stroke_width;
710
nStyle.stroke_cap=stroke_cap;
711
nStyle.stroke_join=stroke_join;
713
nStyle.dash_offset=0;
715
return RasterFont(nStyle);
800
nStyle.transform=trs;
801
nStyle.vertical=vertical;
802
nStyle.stroke_width=stroke_width;
803
nStyle.stroke_cap=stroke_cap;
804
nStyle.stroke_join=stroke_join;
806
nStyle.dash_offset=0;
808
return RasterFont(nStyle);
718
811
raster_font* font_instance::RasterFont(const font_style &inStyle)
720
raster_font *res=NULL;
721
double *savDashes=NULL;
722
font_style nStyle=inStyle;
813
raster_font *res=NULL;
814
double *savDashes=NULL;
815
font_style nStyle=inStyle;
723
816
// for some evil reason font_style doesn't have a copy ctor, so the
724
817
// stuff that should be done there is done here instead (because the
725
818
// raster_font ctor copies nStyle).
726
if ( nStyle.stroke_width > 0 && nStyle.nbDash > 0 && nStyle.dashes ) {
727
savDashes=nStyle.dashes;
728
nStyle.dashes=(double*)malloc(nStyle.nbDash*sizeof(double));
729
memcpy(nStyle.dashes,savDashes,nStyle.nbDash*sizeof(double));
731
if ( loadedStyles.find(nStyle) == loadedStyles.end() ) {
732
raster_font *nR = new raster_font(nStyle);
735
loadedStyles[nStyle]=nR;
739
res=loadedStyles[nStyle];
741
if ( nStyle.dashes ) free(nStyle.dashes); // since they're not taken by a new rasterfont
743
nStyle.dashes=savDashes;
819
if ( (nStyle.stroke_width > 0) && (nStyle.nbDash > 0) && nStyle.dashes ) {
820
savDashes=nStyle.dashes;
821
nStyle.dashes=(double*)malloc(nStyle.nbDash*sizeof(double));
822
memcpy(nStyle.dashes,savDashes,nStyle.nbDash*sizeof(double));
824
StyleMap& loadedStyles = *static_cast<StyleMap*>(loadedPtr);
825
if ( loadedStyles.find(nStyle) == loadedStyles.end() ) {
826
raster_font *nR = new raster_font(nStyle);
829
loadedStyles[nStyle]=nR;
835
res=loadedStyles[nStyle];
837
if ( nStyle.dashes ) {
838
free(nStyle.dashes); // since they're not taken by a new rasterfont
841
nStyle.dashes=savDashes;
747
845
void font_instance::RemoveRasterFont(raster_font* who)
749
if ( who == NULL ) return;
750
if ( loadedStyles.find(who->style) == loadedStyles.end() ) {
751
//g_print("RemoveRasterFont failed \n");
754
loadedStyles.erase(loadedStyles.find(who->style));
755
//g_print("RemoveRasterFont\n");
848
StyleMap& loadedStyles = *static_cast<StyleMap*>(loadedPtr);
849
if ( loadedStyles.find(who->style) == loadedStyles.end() ) {
850
//g_print("RemoveRasterFont failed \n");
853
loadedStyles.erase(loadedStyles.find(who->style));
854
//g_print("RemoveRasterFont\n");