~ubuntu-branches/ubuntu/precise/inkscape/precise-updates

« back to all changes in this revision

Viewing changes to src/libnrtype/FontInstance.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alex Valavanis
  • Date: 2010-09-12 19:44:58 UTC
  • mfrom: (1.1.12 upstream) (45.1.3 maverick)
  • Revision ID: james.westby@ubuntu.com-20100912194458-4sjwmbl7dlsrk5dc
Tags: 0.48.0-1ubuntu1
* Merge with Debian unstable (LP: #628048, LP: #401567, LP: #456248, 
  LP: #463602, LP: #591986)
* debian/control: 
  - Ubuntu maintainers
  - Promote python-lxml, python-numpy, python-uniconvertor to Recommends.
  - Demote pstoedit to Suggests (universe package).
  - Suggests ttf-dejavu instead of ttf-bitstream-vera (LP: #513319)
* debian/rules:
  - Run intltool-update on build (Ubuntu-specific).
  - Add translation domain to .desktop files (Ubuntu-specific).
* debian/dirs:
  - Add usr/share/pixmaps.  Allow inkscape.xpm installation
* drop 50-poppler-API.dpatch (now upstream)
* drop 51-paste-in-unwritable-directory.dpatch (now upstream) 

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
#define PANGO_ENABLE_ENGINE
12
12
 
13
13
#ifdef HAVE_CONFIG_H
14
 
# include <config.h>
 
14
# include "config.h"
15
15
#endif
16
 
#include <libnr/nr-rect.h>
17
 
#include <libnrtype/font-glyph.h>
18
 
#include <libnrtype/font-instance.h>
 
16
 
 
17
#include <ft2build.h>
 
18
#include FT_OUTLINE_H
 
19
#include FT_BBOX_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>
21
 
 
22
 
#include "RasterFont.h"
23
 
 
24
 
/* Freetype 2 */
25
 
# include <ft2build.h>
26
 
# include FT_OUTLINE_H
27
 
# include FT_BBOX_H
28
 
# include FT_TRUETYPE_TAGS_H
29
 
# include FT_TRUETYPE_TABLES_H
30
 
# include <pango/pangoft2.h>
31
 
 
32
 
 
33
 
 
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;
 
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"
 
30
 
 
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)
 
36
#endif
 
37
 
 
38
 
 
39
struct font_style_hash : public std::unary_function<font_style, size_t> {
 
40
    size_t operator()(font_style const &x) const;
 
41
};
 
42
 
 
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;
 
45
};
 
46
 
 
47
typedef INK_UNORDERED_MAP<font_style, raster_font*, font_style_hash, font_style_equal> StyleMap;
 
48
 
 
49
static const double STROKE_WIDTH_THREASHOLD = 0.01;
 
50
 
 
51
 
 
52
 
 
53
size_t font_style_hash::operator()(const font_style &x) const {
 
54
    int h = 0;
 
55
    int n = static_cast<int>(floor(100 * x.stroke_width));
 
56
    h *= 12186;
 
57
    h += n;
 
58
    n = (x.vertical) ? 1:0;
 
59
    h *= 12186;
 
60
    h += n;
 
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);
 
63
        h *= 12186;
 
64
        h += n;
 
65
        if ( x.nbDash > 0 ) {
 
66
            n = x.nbDash;
 
67
            h *= 12186;
 
68
            h += n;
 
69
            n = static_cast<int>(floor(100 * x.dash_offset));
 
70
            h *= 12186;
 
71
            h += n;
 
72
            for (int i = 0; i < x.nbDash; i++) {
 
73
                n = static_cast<int>(floor(100 * x.dashes[i]));
 
74
                h *= 12186;
 
75
                h += n;
 
76
            }
 
77
        }
 
78
    }
 
79
    return h;
61
80
}
62
81
 
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;
72
 
 
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;
 
82
bool font_style_equal::operator()(const font_style &a,const font_style &b) const {
 
83
    bool same = true;
 
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]) );
 
86
    }
 
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])) );
 
98
            }
 
99
        }
 
100
    }
 
101
    return same;
83
102
}
84
103
 
85
104
#ifndef USE_PANGO_WIN32
87
106
 * Outline extraction
88
107
 */
89
108
typedef struct ft2_to_liv {
90
 
        Path*        theP;
91
 
        double       scale;
92
 
        Geom::Point    last;
 
109
    Path*        theP;
 
110
    double       scale;
 
111
    Geom::Point  last;
93
112
} ft2_to_liv;
94
113
 
95
114
// Note: Freetype 2.2.1 redefined function signatures for functions to be placed in an
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);
113
 
        user->last=p;
114
 
        return 0;
 
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);
 
132
    user->last=p;
 
133
    return 0;
115
134
}
116
135
 
117
136
static int ft2_line_to(FREETYPE_VECTOR *to, void *i_user)
118
137
{
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);
123
 
        user->last=p;
124
 
        return 0;
 
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);
 
142
    user->last=p;
 
143
    return 0;
125
144
}
126
145
 
127
146
static int ft2_conic_to(FREETYPE_VECTOR *control, FREETYPE_VECTOR *to, void *i_user)
128
147
{
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();
135
 
        user->last=p;
136
 
        return 0;
 
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();
 
154
    user->last=p;
 
155
    return 0;
137
156
}
138
157
 
139
158
static int ft2_cubic_to(FREETYPE_VECTOR *control1, FREETYPE_VECTOR *control2, FREETYPE_VECTOR *to, void *i_user)
140
159
{
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));
147
 
        user->last=p;
148
 
        return 0;
 
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));
 
166
    user->last=p;
 
167
    return 0;
149
168
}
150
169
#endif
151
170
 
155
174
 *
156
175
 */
157
176
 
158
 
font_instance::font_instance(void)
 
177
font_instance::font_instance(void) :
 
178
    pFont(0),
 
179
    descr(0),
 
180
    refCount(0),
 
181
    daddy(0),
 
182
    nbGlyph(0),
 
183
    maxGlyph(0),
 
184
    glyphs(0),
 
185
    loadedPtr(new StyleMap()),
 
186
    theFace(0)
159
187
{
160
 
        //printf("font instance born\n");
161
 
        descr=NULL;
162
 
        pFont=NULL;
163
 
        refCount=0;
164
 
        daddy=NULL;
165
 
        nbGlyph=maxGlyph=0;
166
 
        glyphs=NULL;
167
 
        theFace=NULL;
 
188
    //printf("font instance born\n");
168
189
}
169
190
 
170
191
font_instance::~font_instance(void)
171
192
{
172
 
        if ( daddy ) daddy->UnrefFace(this);
173
 
        //printf("font instance death\n");
174
 
        if ( pFont ) g_object_unref(pFont);
175
 
        pFont=NULL;
176
 
        if ( descr ) pango_font_description_free(descr);
177
 
        descr=NULL;
178
 
        //      if ( theFace ) FT_Done_Face(theFace); // owned by pFont. don't touch
179
 
        theFace=NULL;
180
 
 
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;
184
 
        }
185
 
        if ( glyphs ) free(glyphs);
186
 
        nbGlyph=maxGlyph=0;
187
 
        glyphs=NULL;
 
193
    if ( loadedPtr ) {
 
194
        StyleMap* tmp = static_cast<StyleMap*>(loadedPtr);
 
195
        delete tmp;
 
196
        loadedPtr = 0;
 
197
    }
 
198
 
 
199
    if ( daddy ) {
 
200
        daddy->UnrefFace(this);
 
201
        daddy = 0;
 
202
    }
 
203
 
 
204
    //printf("font instance death\n");
 
205
    if ( pFont ) {
 
206
        g_object_unref(pFont);
 
207
        pFont = 0;
 
208
    }
 
209
 
 
210
    if ( descr ) {
 
211
        pango_font_description_free(descr);
 
212
        descr = 0;
 
213
    }
 
214
 
 
215
    //    if ( theFace ) FT_Done_Face(theFace); // owned by pFont. don't touch
 
216
    theFace = 0;
 
217
 
 
218
    for (int i=0;i<nbGlyph;i++) {
 
219
        if ( glyphs[i].outline ) {
 
220
            delete glyphs[i].outline;
 
221
        }
 
222
        if ( glyphs[i].pathvector ) {
 
223
            delete glyphs[i].pathvector;
 
224
        }
 
225
    }
 
226
    if ( glyphs ) {
 
227
        free(glyphs);
 
228
        glyphs = 0;
 
229
    }
 
230
    nbGlyph = 0;
 
231
    maxGlyph = 0;
188
232
}
189
233
 
190
234
void font_instance::Ref(void)
191
235
{
192
 
        refCount++;
193
 
        //char *tc=pango_font_description_to_string(descr);
194
 
        //printf("font %x %s ref'd %i\n",this,tc,refCount);
195
 
        //free(tc);
 
236
    refCount++;
 
237
    //char *tc=pango_font_description_to_string(descr);
 
238
    //printf("font %x %s ref'd %i\n",this,tc,refCount);
 
239
    //free(tc);
196
240
}
197
241
 
198
242
void font_instance::Unref(void)
199
243
{
200
 
        refCount--;
201
 
        //char *tc=pango_font_description_to_string(descr);
202
 
        //printf("font %x %s unref'd %i\n",this,tc,refCount);
203
 
        //free(tc);
204
 
        if ( refCount <= 0 ) {
205
 
                if ( daddy ) daddy->UnrefFace(this);
206
 
                daddy=NULL;
207
 
                delete this;
208
 
        }
 
244
    refCount--;
 
245
    //char *tc=pango_font_description_to_string(descr);
 
246
    //printf("font %x %s unref'd %i\n",this,tc,refCount);
 
247
    //free(tc);
 
248
    if ( refCount <= 0 ) {
 
249
        if ( daddy ) {
 
250
            daddy->UnrefFace(this);
 
251
        }
 
252
        daddy=NULL;
 
253
        delete this;
 
254
    }
209
255
}
210
256
 
211
257
unsigned int font_instance::Name(gchar *str, unsigned int size)
212
258
{
213
 
        return Attribute("name", str, size);
 
259
    return Attribute("name", str, size);
214
260
}
215
261
 
216
262
unsigned int font_instance::Family(gchar *str, unsigned int size)
217
263
{
218
 
        return Attribute("family", str, size);
 
264
    return Attribute("family", str, size);
219
265
}
220
266
 
221
267
unsigned int font_instance::PSName(gchar *str, unsigned int size)
222
268
{
223
 
        return Attribute("psname", str, size);
 
269
    return Attribute("psname", str, size);
224
270
}
225
271
 
226
272
unsigned int font_instance::Attribute(const gchar *key, gchar *str, unsigned int size)
227
273
{
228
 
        if ( descr == NULL ) {
229
 
                if ( size > 0 ) str[0]=0;
230
 
                return 0;
231
 
        }
232
 
        char*   res=NULL;
233
 
        bool    free_res=false;
 
274
    if ( descr == NULL ) {
 
275
        if ( size > 0 ) {
 
276
            str[0]=0;
 
277
        }
 
278
        return 0;
 
279
    }
 
280
    char*   res=NULL;
 
281
    bool    free_res=false;
234
282
 
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);
240
 
                free_res=true;
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);
 
288
        free_res=true;
 
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
244
292
#endif
257
305
                                    (i) ? "Italic" : ((o) ? "Oblique" : "")  );
258
306
             free_res = true;
259
307
         }
260
 
        } else if ( strcmp(key,"family") == 0 ) {
261
 
                res=(char*)pango_font_description_get_family(descr);
262
 
                free_res=false;
263
 
        } else if ( strcmp(key,"style") == 0 ) {
264
 
                PangoStyle v=pango_font_description_get_style(descr);
265
 
                if ( v == PANGO_STYLE_ITALIC ) {
266
 
                        res=(char*)"italic";
267
 
                } else if ( v == PANGO_STYLE_OBLIQUE ) {
268
 
                        res=(char*)"oblique";
269
 
                } else {
270
 
                        res=(char*)"normal";
271
 
                }
272
 
                free_res=false;
273
 
        } else if ( strcmp(key,"weight") == 0 ) {
274
 
                PangoWeight v=pango_font_description_get_weight(descr);
275
 
                if ( v <= PANGO_WEIGHT_ULTRALIGHT ) {
276
 
                        res=(char*)"200";
277
 
                } else if ( v <= PANGO_WEIGHT_LIGHT ) {
278
 
                        res=(char*)"300";
279
 
                } else if ( v <= PANGO_WEIGHT_NORMAL ) {
280
 
                        res=(char*)"normal";
281
 
                } else if ( v <= PANGO_WEIGHT_BOLD ) {
282
 
                        res=(char*)"bold";
283
 
                } else if ( v <= PANGO_WEIGHT_ULTRABOLD ) {
284
 
                    res=(char*)"800";
285
 
                } else { // HEAVY
286
 
                        res=(char*)"900";
287
 
                }
288
 
                free_res=false;
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 ) {
298
 
                        res=(char*)"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";
303
 
                } else {
304
 
                        res=(char*)"extra-expanded";
305
 
                }
306
 
                free_res=false;
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";
311
 
                } else {
312
 
                        res=(char*)"normal";
313
 
                }
314
 
                free_res=false;
315
 
        } else {
316
 
                res = NULL;
317
 
                free_res=false;
318
 
        }
319
 
        if ( res == NULL ) {
320
 
                if ( size > 0 ) str[0]=0;
321
 
                return 0;
322
 
        }
 
308
    } else if ( strcmp(key,"family") == 0 ) {
 
309
        res=(char*)pango_font_description_get_family(descr);
 
310
        free_res=false;
 
311
    } else if ( strcmp(key,"style") == 0 ) {
 
312
        PangoStyle v=pango_font_description_get_style(descr);
 
313
        if ( v == PANGO_STYLE_ITALIC ) {
 
314
            res=(char*)"italic";
 
315
        } else if ( v == PANGO_STYLE_OBLIQUE ) {
 
316
            res=(char*)"oblique";
 
317
        } else {
 
318
            res=(char*)"normal";
 
319
        }
 
320
        free_res=false;
 
321
    } else if ( strcmp(key,"weight") == 0 ) {
 
322
        PangoWeight v=pango_font_description_get_weight(descr);
 
323
        if ( v <= PANGO_WEIGHT_THIN ) {
 
324
            res=(char*)"100";
 
325
        } else if ( v <= PANGO_WEIGHT_ULTRALIGHT ) {
 
326
            res=(char*)"200";
 
327
        } else if ( v <= PANGO_WEIGHT_LIGHT ) {
 
328
            res=(char*)"300";
 
329
        } else if ( v <= PANGO_WEIGHT_BOOK ) {
 
330
            res=(char*)"380";
 
331
        } else if ( v <= PANGO_WEIGHT_NORMAL ) {
 
332
            res=(char*)"normal";
 
333
        } else if ( v <= PANGO_WEIGHT_MEDIUM ) {
 
334
            res=(char*)"500";
 
335
        } else if ( v <= PANGO_WEIGHT_SEMIBOLD ) {
 
336
            res=(char*)"600";
 
337
        } else if ( v <= PANGO_WEIGHT_BOLD ) {
 
338
            res=(char*)"bold";
 
339
        } else if ( v <= PANGO_WEIGHT_ULTRABOLD ) {
 
340
            res=(char*)"800";
 
341
        } else { // HEAVY   NB: Pango defines ULTRAHEAVY = 1000 but not CSS2
 
342
            res=(char*)"900";
 
343
        }
 
344
        free_res=false;
 
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 ) {
 
354
            res=(char*)"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";
 
359
        } else {
 
360
            res=(char*)"extra-expanded";
 
361
        }
 
362
        free_res=false;
 
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";
 
367
        } else {
 
368
            res=(char*)"normal";
 
369
        }
 
370
        free_res=false;
 
371
    } else {
 
372
        res = NULL;
 
373
        free_res=false;
 
374
    }
 
375
    if ( res == NULL ) {
 
376
        if ( size > 0 ) {
 
377
            str[0] = 0;
 
378
        }
 
379
        return 0;
 
380
    }
323
381
 
324
 
        if (res) {
325
 
                unsigned int len=strlen(res);
326
 
                unsigned int rlen=(size-1<len)?size-1:len;
327
 
                if ( str ) {
328
 
                        if ( rlen > 0 ) memcpy(str,res,rlen);
329
 
                        if ( size > 0 ) str[rlen]=0;
330
 
                }
331
 
                if (free_res) free(res);
332
 
                return len;
333
 
        }
334
 
        return 0;
 
382
    if (res) {
 
383
        unsigned int len=strlen(res);
 
384
        unsigned int rlen=(size-1<len)?size-1:len;
 
385
        if ( str ) {
 
386
            if ( rlen > 0 ) {
 
387
                memcpy(str, res, rlen);
 
388
            }
 
389
            if ( size > 0 ) {
 
390
                str[rlen] = 0;
 
391
            }
 
392
        }
 
393
        if (free_res) {
 
394
            free(res);
 
395
        }
 
396
        return len;
 
397
    }
 
398
    return 0;
335
399
}
336
400
 
337
401
void font_instance::InitTheFace()
348
412
    SetGraphicsMode(daddy->hScreenDC, GM_COMPATIBLE);
349
413
    SelectObject(daddy->hScreenDC,theFace);
350
414
#else
351
 
        theFace=pango_ft2_font_get_face(pFont);
352
 
    if ( theFace )
 
415
    theFace=pango_ft2_font_get_face(pFont); // Deprecated, use pango_fc_font_lock_face() instead
 
416
    if ( theFace ) {
353
417
        FT_Select_Charmap(theFace,ft_encoding_unicode) && FT_Select_Charmap(theFace,ft_encoding_symbol);
 
418
    }
354
419
#endif
355
420
}
356
421
 
365
430
 
366
431
void font_instance::InstallFace(PangoFont* iFace)
367
432
{
368
 
        if ( !iFace )
369
 
            return;
370
 
        pFont=iFace;
 
433
    if ( !iFace ) {
 
434
        return;
 
435
    }
 
436
    pFont=iFace;
371
437
 
372
438
    InitTheFace();
373
439
 
374
 
        if ( pFont && IsOutlineFont() == false ) {
 
440
    if ( pFont && IsOutlineFont() == false ) {
375
441
        FreeTheFace();
376
 
                if ( pFont ) g_object_unref(pFont);
377
 
                pFont=NULL;
378
 
        }
 
442
        if ( pFont ) {
 
443
            g_object_unref(pFont);
 
444
        }
 
445
        pFont=NULL;
 
446
    }
379
447
}
380
448
 
381
 
bool    font_instance::IsOutlineFont(void)
 
449
bool font_instance::IsOutlineFont(void)
382
450
{
383
 
        if ( pFont == NULL ) return false;
 
451
    if ( pFont == NULL ) {
 
452
        return false;
 
453
    }
384
454
    InitTheFace();
385
455
#ifdef USE_PANGO_WIN32
386
456
    TEXTMETRIC tm;
387
457
    return GetTextMetrics(daddy->hScreenDC,&tm) && tm.tmPitchAndFamily&(TMPF_TRUETYPE|TMPF_DEVICE);
388
458
#else
389
 
        return FT_IS_SCALABLE(theFace);
 
459
    return FT_IS_SCALABLE(theFace);
390
460
#endif
391
461
}
392
462
 
393
463
int font_instance::MapUnicodeChar(gunichar c)
394
464
{
395
 
        if ( pFont == NULL ) return 0;
 
465
    int res = 0;
 
466
    if ( pFont  ) {
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);
398
469
#else
399
 
        int res=0;
400
 
        theFace=pango_ft2_font_get_face(pFont);
401
 
        if ( c > 0xf0000 ) {
402
 
                res=CLAMP(c,0xf0000,0x1fffff)-0xf0000;
403
 
        } else {
404
 
                res=FT_Get_Char_Index(theFace, c);
405
 
        }
406
 
        return res;
 
470
        theFace = pango_ft2_font_get_face(pFont);
 
471
        if ( c > 0xf0000 ) {
 
472
            res = CLAMP(c, 0xf0000, 0x1fffff) - 0xf0000;
 
473
        } else {
 
474
            res = FT_Get_Char_Index(theFace, c);
 
475
        }
407
476
#endif
 
477
    }
 
478
    return res;
408
479
}
409
480
 
410
481
 
418
489
 
419
490
void font_instance::LoadGlyph(int glyph_id)
420
491
{
421
 
        if ( pFont == NULL ) return;
 
492
    if ( pFont == NULL ) {
 
493
        return;
 
494
    }
422
495
    InitTheFace();
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
 
499
    }
425
500
#endif
426
501
 
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));
431
 
                }
432
 
                font_glyph  n_g;
433
 
                n_g.outline=NULL;
 
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));
 
506
        }
 
507
        font_glyph  n_g;
 
508
        n_g.outline=NULL;
434
509
        n_g.pathvector=NULL;
435
 
                n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0;
436
 
                bool   doAdd=false;
 
510
        n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0;
 
511
        bool   doAdd=false;
437
512
 
438
513
#ifdef USE_PANGO_WIN32
439
514
 
458
533
            // character has no visual representation, but is valid (eg whitespace)
459
534
            doAdd=true;
460
535
        } else {
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 ) {
463
538
                // shit happened
464
539
            } else {
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;
471
546
 
472
547
                    if (polyHeader->dwType == TT_POLYGON_TYPE) {
474
549
                        DWORD curveOffset=polyOffset+sizeof(TTPOLYGONHEADER);
475
550
 
476
551
                        while ( curveOffset < polyOffset+polyHeader->cb ) {
477
 
                            TTPOLYCURVE const *polyCurve=(TTPOLYCURVE const *)(buffer.get()+curveOffset);
 
552
                            TTPOLYCURVE const *polyCurve=(TTPOLYCURVE const *)(buffer+curveOffset);
478
553
                            POINTFX const *p=polyCurve->apfx;
479
554
                            POINTFX const *endp=p+polyCurve->cpfx;
480
555
 
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();
497
572
                                        ++p;
498
573
                                        this_mid=next_mid;
499
574
                                    }
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();
503
578
                                    break;
504
579
                                }
505
580
 
519
594
                }
520
595
                doAdd=true;
521
596
            }
 
597
            delete [] buffer;
522
598
        }
523
599
#else
524
 
                if (FT_Load_Glyph (theFace, glyph_id, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) {
525
 
                        // shit happened
526
 
                } else {
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);
530
 
                        } else {
531
 
                                n_g.h_width=n_g.h_advance=((double)(theFace->bbox.xMax-theFace->bbox.xMin))/((double)theFace->units_per_EM);
532
 
                        }
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);
536
 
                        } else {
537
 
                                n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM);
538
 
                        }
539
 
                        if ( theFace->glyph->format == ft_glyph_format_outline ) {
540
 
                                FT_Outline_Funcs ft2_outline_funcs = {
541
 
                                        ft2_move_to,
542
 
                                        ft2_line_to,
543
 
                                        ft2_conic_to,
544
 
                                        ft2_cubic_to,
545
 
                                        0, 0
546
 
                                };
547
 
                                n_g.outline=new Path;
548
 
                                ft2_to_liv   tData;
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);
553
 
                        }
554
 
                        doAdd=true;
555
 
                }
 
600
        if (FT_Load_Glyph (theFace, glyph_id, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) {
 
601
            // shit happened
 
602
        } else {
 
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);
 
606
            } else {
 
607
                n_g.h_width=n_g.h_advance=((double)(theFace->bbox.xMax-theFace->bbox.xMin))/((double)theFace->units_per_EM);
 
608
            }
 
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);
 
612
            } else {
 
613
                n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM);
 
614
            }
 
615
            if ( theFace->glyph->format == ft_glyph_format_outline ) {
 
616
                FT_Outline_Funcs ft2_outline_funcs = {
 
617
                    ft2_move_to,
 
618
                    ft2_line_to,
 
619
                    ft2_conic_to,
 
620
                    ft2_cubic_to,
 
621
                    0, 0
 
622
                };
 
623
                n_g.outline=new Path;
 
624
                ft2_to_liv   tData;
 
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);
 
629
            }
 
630
            doAdd=true;
 
631
        }
556
632
#endif
557
633
 
558
 
                if ( doAdd ) {
559
 
                        if ( n_g.outline ) {
560
 
                                n_g.outline->FastBBox(n_g.bbox[0],n_g.bbox[1],n_g.bbox[2],n_g.bbox[3]);
 
634
        if ( doAdd ) {
 
635
            if ( n_g.outline ) {
 
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();
562
 
                        }
563
 
                        glyphs[nbGlyph]=n_g;
564
 
                        id_to_no[glyph_id]=nbGlyph;
565
 
                        nbGlyph++;
566
 
                }
 
638
            }
 
639
            glyphs[nbGlyph]=n_g;
 
640
            id_to_no[glyph_id]=nbGlyph;
 
641
            nbGlyph++;
 
642
        }
567
643
    } else {
568
644
    }
569
645
}
570
646
 
571
647
bool font_instance::FontMetrics(double &ascent,double &descent,double &leading)
572
648
{
573
 
        if ( pFont == NULL ) return false;
 
649
    if ( pFont == NULL ) {
 
650
        return false;
 
651
    }
574
652
    InitTheFace();
575
 
        if ( theFace == NULL ) return false;
 
653
    if ( theFace == NULL ) {
 
654
        return false;
 
655
    }
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) ) {
 
659
        return false;
 
660
    }
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, 
583
666
#else
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
 
669
    }
 
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;
589
674
#endif
590
 
        return true;
 
675
    return true;
591
676
}
592
677
 
593
678
bool font_instance::FontSlope(double &run, double &rise)
595
680
    run = 0.0;
596
681
    rise = 1.0;
597
682
 
598
 
        if ( pFont == NULL ) return false;
 
683
    if ( pFont == NULL ) {
 
684
        return false;
 
685
    }
599
686
    InitTheFace();
600
 
        if ( theFace == NULL ) return false;
 
687
    if ( theFace == NULL ) {
 
688
        return false;
 
689
    }
601
690
 
602
691
#ifdef USE_PANGO_WIN32
603
692
    OUTLINETEXTMETRIC otm;
605
694
    run=otm.otmsCharSlopeRun;
606
695
    rise=otm.otmsCharSlopeRise;
607
696
#else
608
 
        if ( !FT_IS_SCALABLE(theFace) ) return false; // bitmap font
 
697
    if ( !FT_IS_SCALABLE(theFace) ) {
 
698
        return false; // bitmap font
 
699
    }
609
700
 
610
701
    TT_HoriHeader *hhea = (TT_HoriHeader*)FT_Get_Sfnt_Table(theFace, ft_sfnt_hhea);
611
 
    if (hhea == NULL) return false;
 
702
    if (hhea == NULL) {
 
703
        return false;
 
704
    }
612
705
    run = hhea->caret_Slope_Run;
613
706
    rise = hhea->caret_Slope_Rise;
614
707
#endif
615
 
        return true;
 
708
    return true;
616
709
}
617
710
 
618
711
Geom::OptRect font_instance::BBox(int glyph_id)
619
712
{
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 ) {
632
 
            return Geom::OptRect();
 
713
    int no = -1;
 
714
    if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
 
715
        LoadGlyph(glyph_id);
 
716
        if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
 
717
            // didn't load
633
718
        } else {
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];
637
720
        }
 
721
    } else {
 
722
        no = id_to_no[glyph_id];
 
723
    }
 
724
    if ( no < 0 ) {
 
725
        return Geom::OptRect();
 
726
    } else {
 
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);
 
730
    }
638
731
}
639
732
 
640
733
Path* font_instance::Outline(int glyph_id,Path* copyInto)
641
734
{
642
 
        int no=-1;
643
 
        if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
644
 
                LoadGlyph(glyph_id);
645
 
                if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
646
 
                        // didn't load
647
 
                } else {
648
 
                        no=id_to_no[glyph_id];
649
 
                }
650
 
        } else {
651
 
                no=id_to_no[glyph_id];
652
 
        }
653
 
        if ( no < 0 ) return NULL;
654
 
        Path*    src_o=glyphs[no].outline;
655
 
        if ( copyInto ) {
656
 
                copyInto->Reset();
657
 
                copyInto->Copy(src_o);
658
 
                return copyInto;
659
 
        }
660
 
        return src_o;
 
735
    int no = -1;
 
736
    if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
 
737
        LoadGlyph(glyph_id);
 
738
        if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
 
739
            // didn't load
 
740
        } else {
 
741
            no = id_to_no[glyph_id];
 
742
        }
 
743
    } else {
 
744
        no = id_to_no[glyph_id];
 
745
    }
 
746
    if ( no < 0 ) return NULL;
 
747
    Path *src_o = glyphs[no].outline;
 
748
    if ( copyInto ) {
 
749
        copyInto->Reset();
 
750
        copyInto->Copy(src_o);
 
751
        return copyInto;
 
752
    }
 
753
    return src_o;
661
754
}
662
755
 
663
756
Geom::PathVector* font_instance::PathVector(int glyph_id)
679
772
 
680
773
double font_instance::Advance(int glyph_id,bool vertical)
681
774
{
682
 
        int no=-1;
683
 
        if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
684
 
                LoadGlyph(glyph_id);
685
 
                if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
686
 
                        // didn't load
687
 
                } else {
688
 
                        no=id_to_no[glyph_id];
689
 
                }
690
 
        } else {
691
 
                no=id_to_no[glyph_id];
692
 
        }
693
 
        if ( no >= 0 ) {
694
 
                if ( vertical ) {
695
 
                        return glyphs[no].v_advance;
696
 
                } else {
697
 
                        return glyphs[no].h_advance;
698
 
                }
699
 
        }
700
 
        return 0;
 
775
    int no = -1;
 
776
    if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
 
777
        LoadGlyph(glyph_id);
 
778
        if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
 
779
            // didn't load
 
780
        } else {
 
781
            no=id_to_no[glyph_id];
 
782
        }
 
783
    } else {
 
784
        no = id_to_no[glyph_id];
 
785
    }
 
786
    if ( no >= 0 ) {
 
787
        if ( vertical ) {
 
788
            return glyphs[no].v_advance;
 
789
        } else {
 
790
            return glyphs[no].h_advance;
 
791
        }
 
792
    }
 
793
    return 0;
701
794
}
702
795
 
703
796
 
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*/)
705
798
{
706
 
        font_style  nStyle;
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;
712
 
        nStyle.nbDash=0;
713
 
        nStyle.dash_offset=0;
714
 
        nStyle.dashes=NULL;
715
 
        return RasterFont(nStyle);
 
799
    font_style  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;
 
805
    nStyle.nbDash=0;
 
806
    nStyle.dash_offset=0;
 
807
    nStyle.dashes=NULL;
 
808
    return RasterFont(nStyle);
716
809
}
717
810
 
718
811
raster_font* font_instance::RasterFont(const font_style &inStyle)
719
812
{
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));
730
 
        }
731
 
        if ( loadedStyles.find(nStyle) == loadedStyles.end() ) {
732
 
                raster_font *nR = new raster_font(nStyle);
733
 
                nR->Ref();
734
 
                nR->daddy=this;
735
 
                loadedStyles[nStyle]=nR;
736
 
                res=nR;
737
 
                if ( res ) Ref();
738
 
        } else {
739
 
                res=loadedStyles[nStyle];
740
 
                res->Ref();
741
 
                if ( nStyle.dashes ) free(nStyle.dashes); // since they're not taken by a new rasterfont
742
 
        }
743
 
        nStyle.dashes=savDashes;
744
 
        return res;
 
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));
 
823
    }
 
824
    StyleMap& loadedStyles = *static_cast<StyleMap*>(loadedPtr);
 
825
    if ( loadedStyles.find(nStyle) == loadedStyles.end() ) {
 
826
        raster_font *nR = new raster_font(nStyle);
 
827
        nR->Ref();
 
828
        nR->daddy=this;
 
829
        loadedStyles[nStyle]=nR;
 
830
        res=nR;
 
831
        if ( res ) {
 
832
            Ref();
 
833
        }
 
834
    } else {
 
835
        res=loadedStyles[nStyle];
 
836
        res->Ref();
 
837
        if ( nStyle.dashes ) {
 
838
            free(nStyle.dashes); // since they're not taken by a new rasterfont
 
839
        }
 
840
    }
 
841
    nStyle.dashes=savDashes;
 
842
    return res;
745
843
}
746
844
 
747
845
void font_instance::RemoveRasterFont(raster_font* who)
748
846
{
749
 
        if ( who == NULL ) return;
750
 
        if ( loadedStyles.find(who->style) == loadedStyles.end() ) {
751
 
                //g_print("RemoveRasterFont failed \n");
752
 
                // not found
753
 
        } else {
754
 
                loadedStyles.erase(loadedStyles.find(who->style));
755
 
                //g_print("RemoveRasterFont\n");
756
 
                Unref();
757
 
        }
 
847
    if ( who ) {
 
848
        StyleMap& loadedStyles = *static_cast<StyleMap*>(loadedPtr);
 
849
        if ( loadedStyles.find(who->style) == loadedStyles.end() ) {
 
850
            //g_print("RemoveRasterFont failed \n");
 
851
            // not found
 
852
        } else {
 
853
            loadedStyles.erase(loadedStyles.find(who->style));
 
854
            //g_print("RemoveRasterFont\n");
 
855
            Unref();
 
856
        }
 
857
    }
758
858
}
759
859
 
760
860