~mc.../inkscape/inkscape

« back to all changes in this revision

Viewing changes to src/libnrtype/Layout-TNG-Output.cpp

  • Committer: mental
  • Date: 2006-01-16 02:36:01 UTC
  • Revision ID: mental@users.sourceforge.net-20060116023601-wkr0h7edl5veyudq
moving trunk for module inkscape

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Inkscape::Text::Layout - text layout engine output functions
 
3
 *
 
4
 * Authors:
 
5
 *   Richard Hughes <cyreve@users.sf.net>
 
6
 *
 
7
 * Copyright (C) 2005 Richard Hughes
 
8
 *
 
9
 * Released under GNU GPL, read the file 'COPYING' for more information
 
10
 */
 
11
#include "Layout-TNG.h"
 
12
#include "display/nr-arena-glyphs.h"
 
13
#include "style.h"
 
14
#include "print.h"
 
15
#include "extension/print.h"
 
16
#include "livarot/Path.h"
 
17
#include "libnr/nr-scale-matrix-ops.h"
 
18
#include "font-instance.h"
 
19
#include "svg/svg-length.h"
 
20
 
 
21
namespace Inkscape {
 
22
namespace Text {
 
23
 
 
24
void Layout::_clearOutputObjects()
 
25
{
 
26
    _paragraphs.clear();
 
27
    _lines.clear();
 
28
    _chunks.clear();
 
29
    for (std::vector<Span>::iterator it_span = _spans.begin() ; it_span != _spans.end() ; it_span++)
 
30
        if (it_span->font) it_span->font->Unref();
 
31
    _spans.clear();
 
32
    _characters.clear();
 
33
    _glyphs.clear();
 
34
    _path_fitted = NULL;
 
35
}
 
36
 
 
37
void Layout::LineHeight::max(LineHeight const &other)
 
38
{
 
39
    if (other.ascent > ascent)  ascent  = other.ascent;
 
40
    if (other.descent > descent) descent = other.descent;
 
41
    if (other.leading > leading) leading = other.leading;
 
42
}
 
43
 
 
44
void Layout::_getGlyphTransformMatrix(int glyph_index, NRMatrix *matrix) const
 
45
{
 
46
    Span const &span = _glyphs[glyph_index].span(this);
 
47
    double sin_rotation = sin(_glyphs[glyph_index].rotation);
 
48
    double cos_rotation = cos(_glyphs[glyph_index].rotation);
 
49
    (*matrix)[0] = span.font_size * cos_rotation;
 
50
    (*matrix)[1] = span.font_size * sin_rotation;
 
51
    (*matrix)[2] = span.font_size * sin_rotation;
 
52
    (*matrix)[3] = -span.font_size * cos_rotation;
 
53
    if (span.block_progression == LEFT_TO_RIGHT || span.block_progression == RIGHT_TO_LEFT) {
 
54
        (*matrix)[4] = _lines[_chunks[span.in_chunk].in_line].baseline_y + _glyphs[glyph_index].y;
 
55
        (*matrix)[5] = _chunks[span.in_chunk].left_x + _glyphs[glyph_index].x;
 
56
    } else {
 
57
        (*matrix)[4] = _chunks[span.in_chunk].left_x + _glyphs[glyph_index].x;
 
58
        (*matrix)[5] = _lines[_chunks[span.in_chunk].in_line].baseline_y + _glyphs[glyph_index].y;
 
59
    }
 
60
}
 
61
 
 
62
void Layout::show(NRArenaGroup *in_arena, NRRect const *paintbox) const
 
63
{
 
64
    int glyph_index = 0;
 
65
    for (unsigned span_index = 0 ; span_index < _spans.size() ; span_index++) {
 
66
        if (_input_stream[_spans[span_index].in_input_stream_item]->Type() != TEXT_SOURCE) continue;
 
67
        InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[_spans[span_index].in_input_stream_item]);
 
68
        NRArenaGlyphsGroup *nr_group = NRArenaGlyphsGroup::create(in_arena->arena);
 
69
        nr_arena_item_add_child(in_arena, nr_group, NULL);
 
70
        nr_arena_item_unref(nr_group);
 
71
 
 
72
        nr_arena_glyphs_group_set_style(nr_group, text_source->style);
 
73
        while (glyph_index < (int)_glyphs.size() && _characters[_glyphs[glyph_index].in_character].in_span == span_index) {
 
74
            if (_characters[_glyphs[glyph_index].in_character].in_glyph != -1) {
 
75
                NRMatrix glyph_matrix;
 
76
                _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
 
77
                nr_arena_glyphs_group_add_component(nr_group, _spans[span_index].font, _glyphs[glyph_index].glyph, &glyph_matrix);
 
78
            }
 
79
            glyph_index++;
 
80
        }
 
81
        nr_arena_glyphs_group_set_paintbox(NR_ARENA_GLYPHS_GROUP(nr_group), paintbox);
 
82
    }
 
83
    nr_arena_item_request_update(NR_ARENA_ITEM(in_arena), NR_ARENA_ITEM_STATE_ALL, FALSE);
 
84
}
 
85
 
 
86
void Layout::getBoundingBox(NRRect *bounding_box, NR::Matrix const &transform) const
 
87
{
 
88
    for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; glyph_index++) {
 
89
        if (_characters[_glyphs[glyph_index].in_character].in_glyph == -1) continue;
 
90
        // this could be faster
 
91
        NRMatrix glyph_matrix;
 
92
        _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
 
93
        NR::Matrix total_transform = glyph_matrix;
 
94
        total_transform *= transform;
 
95
        NR::Rect glyph_rect = _glyphs[glyph_index].span(this).font->BBox(_glyphs[glyph_index].glyph);
 
96
        NR::Point bmi = glyph_rect.min(), bma = glyph_rect.max();
 
97
        NR::Point tlp(bmi[0],bmi[1]), trp(bma[0],bmi[1]), blp(bmi[0],bma[1]), brp(bma[0],bma[1]);
 
98
        tlp *= total_transform;
 
99
        trp *= total_transform;
 
100
        blp *= total_transform;
 
101
        brp *= total_transform;
 
102
        glyph_rect = NR::Rect(tlp,trp);
 
103
        glyph_rect.expandTo(blp);
 
104
        glyph_rect.expandTo(brp);
 
105
        if ( (glyph_rect.min())[0] < bounding_box->x0 ) bounding_box->x0=(glyph_rect.min())[0];
 
106
        if ( (glyph_rect.max())[0] > bounding_box->x1 ) bounding_box->x1=(glyph_rect.max())[0];
 
107
        if ( (glyph_rect.min())[1] < bounding_box->y0 ) bounding_box->y0=(glyph_rect.min())[1];
 
108
        if ( (glyph_rect.max())[1] > bounding_box->y1 ) bounding_box->y1=(glyph_rect.max())[1];
 
109
    }
 
110
}
 
111
 
 
112
void Layout::print(SPPrintContext *ctx,
 
113
                   NRRect const *pbox, NRRect const *dbox, NRRect const *bbox,
 
114
                   NRMatrix const &ctm) const
 
115
{
 
116
    if (_input_stream.empty()) return;
 
117
 
 
118
    Direction block_progression = _blockProgression();
 
119
    bool text_to_path = ctx->module->textToPath();
 
120
    for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; ) {
 
121
        if (_characters[_glyphs[glyph_index].in_character].in_glyph == -1) {
 
122
            // invisible glyphs
 
123
            unsigned same_character = _glyphs[glyph_index].in_character;
 
124
            while (_glyphs[glyph_index].in_character == same_character)
 
125
                glyph_index++;
 
126
            continue;
 
127
        }
 
128
        NRMatrix glyph_matrix;
 
129
        Span const &span = _spans[_characters[_glyphs[glyph_index].in_character].in_span];
 
130
        InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[span.in_input_stream_item]);
 
131
        if (text_to_path || _path_fitted) {
 
132
            NRBPath bpath;
 
133
            bpath.path = (NArtBpath*)span.font->ArtBPath(_glyphs[glyph_index].glyph);
 
134
            if (bpath.path) {
 
135
                NRBPath abp;
 
136
                _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
 
137
                abp.path = nr_artpath_affine(bpath.path, glyph_matrix);
 
138
                if (text_source->style->fill.type != SP_PAINT_TYPE_NONE)
 
139
                    sp_print_fill(ctx, &abp, &ctm, text_source->style, pbox, dbox, bbox);
 
140
                if (text_source->style->stroke.type != SP_PAINT_TYPE_NONE)
 
141
                    sp_print_stroke(ctx, &abp, &ctm, text_source->style, pbox, dbox, bbox);
 
142
                nr_free(abp.path);
 
143
            }
 
144
            glyph_index++;
 
145
        } else {
 
146
            NR::Point g_pos(0,0);    // all strings are output at (0,0) because we do the translation using the matrix
 
147
            glyph_matrix = NR::Matrix(NR::scale(1.0, -1.0) * NR::Matrix(NR::rotate(_glyphs[glyph_index].rotation)));
 
148
            if (block_progression == LEFT_TO_RIGHT || block_progression == RIGHT_TO_LEFT) {
 
149
                glyph_matrix.c[4] = span.line(this).baseline_y + span.baseline_shift;
 
150
                // since we're outputting character codes, not glyphs, we want the character x
 
151
                glyph_matrix.c[5] = span.chunk(this).left_x + span.x_start + _characters[_glyphs[glyph_index].in_character].x;
 
152
            } else {
 
153
                glyph_matrix.c[4] = span.chunk(this).left_x + span.x_start + _characters[_glyphs[glyph_index].in_character].x;
 
154
                glyph_matrix.c[5] = span.line(this).baseline_y + span.baseline_shift;
 
155
            }
 
156
            Glib::ustring::const_iterator span_iter = span.input_stream_first_character;
 
157
            unsigned char_index = _glyphs[glyph_index].in_character;
 
158
            unsigned original_span = _characters[char_index].in_span;
 
159
            while (char_index && _characters[char_index - 1].in_span == original_span) {
 
160
                char_index--;
 
161
                span_iter++;
 
162
            }
 
163
 
 
164
            // try to output as many characters as possible in one go by detecting kerning and stopping when we encounter it
 
165
            Glib::ustring span_string;
 
166
            double char_x = _characters[_glyphs[glyph_index].in_character].x;
 
167
            unsigned this_span_index = _characters[_glyphs[glyph_index].in_character].in_span;
 
168
            do {
 
169
                span_string += *span_iter;
 
170
                span_iter++;
 
171
 
 
172
                unsigned same_character = _glyphs[glyph_index].in_character;
 
173
                while (glyph_index < _glyphs.size() && _glyphs[glyph_index].in_character == same_character) {
 
174
                    char_x += _glyphs[glyph_index].width;
 
175
                    glyph_index++;
 
176
                }
 
177
            } while (glyph_index < _glyphs.size()
 
178
                     && _path_fitted == NULL
 
179
                     && _characters[_glyphs[glyph_index].in_character].in_span == this_span_index
 
180
                     && fabs(char_x - _characters[_glyphs[glyph_index].in_character].x) < 1e-5);
 
181
            sp_print_bind(ctx, glyph_matrix, 1.0);
 
182
            sp_print_text(ctx, span_string.c_str(), g_pos, text_source->style);
 
183
            sp_print_release(ctx);
 
184
        }
 
185
    }
 
186
}
 
187
 
 
188
// these functions are for dumpAsText() only. No need to translate
 
189
static char const *direction_to_text(Layout::Direction d)
 
190
{
 
191
    switch (d) {
 
192
        case Layout::LEFT_TO_RIGHT: return "ltr";
 
193
        case Layout::RIGHT_TO_LEFT: return "rtl";
 
194
        case Layout::TOP_TO_BOTTOM: return "ttb";
 
195
        case Layout::BOTTOM_TO_TOP: return "btt";
 
196
    }
 
197
    return "???";
 
198
}
 
199
 
 
200
static char const *style_to_text(PangoStyle s)
 
201
{
 
202
    switch (s) {
 
203
        case PANGO_STYLE_NORMAL: return "upright";
 
204
        case PANGO_STYLE_ITALIC: return "italic";
 
205
        case PANGO_STYLE_OBLIQUE: return "oblique";
 
206
    }
 
207
    return "???";
 
208
}
 
209
 
 
210
static char const *weight_to_text(PangoWeight w)
 
211
{
 
212
    switch (w) {
 
213
        case PANGO_WEIGHT_ULTRALIGHT: return "ultralight";
 
214
        case PANGO_WEIGHT_LIGHT     : return "light";
 
215
        case PANGO_WEIGHT_SEMIBOLD  : return "semibold";
 
216
        case PANGO_WEIGHT_NORMAL    : return "normalweight";
 
217
        case PANGO_WEIGHT_BOLD      : return "bold";
 
218
        case PANGO_WEIGHT_ULTRABOLD : return "ultrabold";
 
219
        case PANGO_WEIGHT_HEAVY     : return "heavy";
 
220
    }
 
221
    return "???";
 
222
}
 
223
 
 
224
Glib::ustring Layout::dumpAsText() const
 
225
{
 
226
    Glib::ustring result;
 
227
 
 
228
    for (unsigned span_index = 0 ; span_index < _spans.size() ; span_index++) {
 
229
        char line[256];
 
230
        snprintf(line, sizeof(line), "==== span %d\n", span_index);
 
231
        result += line;
 
232
        snprintf(line, sizeof(line), "  in para %d (direction=%s)\n", _lines[_chunks[_spans[span_index].in_chunk].in_line].in_paragraph,
 
233
                 direction_to_text(_paragraphs[_lines[_chunks[_spans[span_index].in_chunk].in_line].in_paragraph].base_direction));
 
234
        result += line;
 
235
        snprintf(line, sizeof(line), "  in source %d (type=%d, cookie=%p)\n", _spans[span_index].in_input_stream_item,
 
236
                 _input_stream[_spans[span_index].in_input_stream_item]->Type(),
 
237
                 _input_stream[_spans[span_index].in_input_stream_item]->source_cookie);
 
238
        result += line;
 
239
        snprintf(line, sizeof(line), "  in line %d (baseline=%f, shape=%d)\n", _chunks[_spans[span_index].in_chunk].in_line,
 
240
                 _lines[_chunks[_spans[span_index].in_chunk].in_line].baseline_y,
 
241
                 _lines[_chunks[_spans[span_index].in_chunk].in_line].in_shape);
 
242
        result += line;
 
243
        snprintf(line, sizeof(line), "  in chunk %d (x=%f, baselineshift=%f)\n", _spans[span_index].in_chunk, _chunks[_spans[span_index].in_chunk].left_x, _spans[span_index].baseline_shift);
 
244
        result += line;
 
245
        if (_spans[span_index].font) {
 
246
            snprintf(line, sizeof(line), "    font '%s' %f %s %s\n", pango_font_description_get_family(_spans[span_index].font->descr), _spans[span_index].font_size, style_to_text(pango_font_description_get_style(_spans[span_index].font->descr)), weight_to_text(pango_font_description_get_weight(_spans[span_index].font->descr)));
 
247
            result += line;
 
248
        }
 
249
        snprintf(line, sizeof(line), "    x_start = %f, x_end = %f\n", _spans[span_index].x_start, _spans[span_index].x_end);
 
250
        result += line;
 
251
        snprintf(line, sizeof(line), "    line height: ascent %f, descent %f leading %f\n", _spans[span_index].line_height.ascent, _spans[span_index].line_height.descent, _spans[span_index].line_height.leading);
 
252
        result += line;
 
253
        snprintf(line, sizeof(line), "    direction %s, block-progression %s\n", direction_to_text(_spans[span_index].direction), direction_to_text(_spans[span_index].block_progression));
 
254
        result += line;
 
255
        result += "    ** characters:\n";
 
256
        Glib::ustring::const_iterator iter_char = _spans[span_index].input_stream_first_character;
 
257
        // very inefficent code. what the hell, it's only debug stuff.
 
258
        for (unsigned char_index = 0 ; char_index < _characters.size() ; char_index++) {
 
259
            if (_characters[char_index].in_span != span_index) continue;
 
260
            if (_input_stream[_spans[span_index].in_input_stream_item]->Type() != TEXT_SOURCE) {
 
261
                snprintf(line, sizeof(line), "      %d: control x=%f flags=%03x glyph=%d\n", char_index, _characters[char_index].x, *(unsigned*)&_characters[char_index].char_attributes, _characters[char_index].in_glyph);
 
262
            } else {
 
263
                snprintf(line, sizeof(line), "      %d: '%c' x=%f flags=%03x glyph=%d\n", char_index, *iter_char, _characters[char_index].x, *(unsigned*)&_characters[char_index].char_attributes, _characters[char_index].in_glyph);
 
264
                iter_char++;
 
265
            }
 
266
            result += line;
 
267
        }
 
268
        result += "    ** glyphs:\n";
 
269
        for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; glyph_index++) {
 
270
            if (_characters[_glyphs[glyph_index].in_character].in_span != span_index) continue;
 
271
            snprintf(line, sizeof(line), "      %d: %d (%f,%f) rot=%f cx=%f char=%d\n", glyph_index, _glyphs[glyph_index].glyph, _glyphs[glyph_index].x, _glyphs[glyph_index].y, _glyphs[glyph_index].rotation, _glyphs[glyph_index].width, _glyphs[glyph_index].in_character);
 
272
            result += line;
 
273
        }
 
274
        result += "\n";
 
275
    }
 
276
    result += "EOT\n";
 
277
    return result;
 
278
}
 
279
 
 
280
void Layout::fitToPathAlign(SVGLength const &startOffset, Path const &path)
 
281
{
 
282
    double offset = 0.0;
 
283
 
 
284
    if (startOffset._set) {
 
285
        if (startOffset.unit == SVGLength::PERCENT)
 
286
            offset = startOffset.computed * const_cast<Path&>(path).Length();
 
287
        else
 
288
            offset = startOffset.computed;
 
289
    }
 
290
 
 
291
    switch (_paragraphs.front().alignment) {
 
292
        case CENTER:
 
293
            offset -= _getChunkWidth(0) * 0.5;
 
294
            break;
 
295
        case RIGHT:
 
296
            offset -= _getChunkWidth(0);
 
297
            break;
 
298
        default:
 
299
            break;
 
300
    }
 
301
 
 
302
    if (_characters.empty()) {
 
303
        int unused = 0;
 
304
        Path::cut_position *point_otp = const_cast<Path&>(path).CurvilignToPosition(1, &offset, unused);
 
305
        if (offset >= 0.0 && point_otp != NULL && point_otp[0].piece >= 0) {
 
306
            NR::Point point;
 
307
            NR::Point tangent;
 
308
            const_cast<Path&>(path).PointAndTangentAt(point_otp[0].piece, point_otp[0].t, point, tangent);
 
309
            _empty_cursor_shape.position = point;
 
310
            _empty_cursor_shape.rotation = atan2(tangent[NR::Y], tangent[NR::X]);
 
311
        }
 
312
    }
 
313
 
 
314
    for (unsigned char_index = 0 ; char_index < _characters.size() ; ) {
 
315
        int next_cluster_glyph_index;
 
316
        unsigned next_cluster_char_index;
 
317
        double character_advance;
 
318
        Span const &span = _characters[char_index].span(this);
 
319
 
 
320
        for (next_cluster_char_index = char_index + 1 ;
 
321
             next_cluster_char_index < _characters.size() && !_characters[next_cluster_char_index].char_attributes.is_cursor_position;
 
322
             next_cluster_char_index++);
 
323
 
 
324
        if (next_cluster_char_index == _characters.size()) {
 
325
            next_cluster_glyph_index = _glyphs.size();
 
326
            character_advance = 0.0;   // arbitrary because we're not going to advance
 
327
        } else {
 
328
            next_cluster_glyph_index = _characters[next_cluster_char_index].in_glyph;
 
329
            character_advance =   (_glyphs[next_cluster_glyph_index].x + _glyphs[next_cluster_glyph_index].chunk(this).left_x)
 
330
                - (_glyphs[_characters[char_index].in_glyph].x + span.chunk(this).left_x);
 
331
        }
 
332
 
 
333
        double start_offset = offset + span.x_start + _characters[char_index].x;
 
334
        double cluster_width = 0.0;
 
335
        for (int glyph_index = _characters[char_index].in_glyph ; glyph_index < next_cluster_glyph_index ; glyph_index++)
 
336
            cluster_width += _glyphs[glyph_index].width;
 
337
        if (span.direction == RIGHT_TO_LEFT)
 
338
            start_offset -= cluster_width;
 
339
        double end_offset = start_offset + cluster_width;
 
340
 
 
341
        int unused = 0;
 
342
        double midpoint_offset = (start_offset + end_offset) * 0.5;
 
343
        // as far as I know these functions are const, they're just not marked as such
 
344
        Path::cut_position *midpoint_otp = const_cast<Path&>(path).CurvilignToPosition(1, &midpoint_offset, unused);
 
345
        if (midpoint_offset >= 0.0 && midpoint_otp != NULL && midpoint_otp[0].piece >= 0) {
 
346
            NR::Point midpoint;
 
347
            NR::Point tangent;
 
348
 
 
349
            const_cast<Path&>(path).PointAndTangentAt(midpoint_otp[0].piece, midpoint_otp[0].t, midpoint, tangent);
 
350
 
 
351
            if (start_offset >= 0.0 && end_offset >= 0.0) {
 
352
                Path::cut_position *start_otp = const_cast<Path&>(path).CurvilignToPosition(1, &start_offset, unused);
 
353
                if (start_otp != NULL && start_otp[0].piece >= 0) {
 
354
                    Path::cut_position *end_otp = const_cast<Path&>(path).CurvilignToPosition(1, &end_offset, unused);
 
355
                    if (end_otp != NULL && end_otp[0].piece >= 0) {
 
356
                        bool on_same_subpath = true;
 
357
                        for (size_t i = 0 ; i < path.pts.size() ; i++) {
 
358
                            if (path.pts[i].piece <= start_otp[0].piece) continue;
 
359
                            if (path.pts[i].piece >= end_otp[0].piece) break;
 
360
                            if (path.pts[i].isMoveTo == polyline_moveto) {
 
361
                                on_same_subpath = false;
 
362
                                break;
 
363
                            }
 
364
                        }
 
365
                        if (on_same_subpath) {
 
366
                            // both points were on the same subpath (without this test the angle is very weird)
 
367
                            NR::Point startpoint, endpoint;
 
368
                            const_cast<Path&>(path).PointAt(start_otp[0].piece, start_otp[0].t, startpoint);
 
369
                            const_cast<Path&>(path).PointAt(end_otp[0].piece, end_otp[0].t, endpoint);
 
370
                            if (endpoint != startpoint) {
 
371
                                tangent = endpoint - startpoint;
 
372
                                tangent.normalize();
 
373
                            } else {
 
374
                                tangent = NR::Point (0,0);
 
375
                            }
 
376
                        }
 
377
                        g_free(end_otp);
 
378
                    }
 
379
                    g_free(start_otp);
 
380
                }
 
381
            }
 
382
 
 
383
            double rotation = atan2(tangent[1], tangent[0]);
 
384
            for (int glyph_index = _characters[char_index].in_glyph ; glyph_index < next_cluster_glyph_index ; glyph_index++) {
 
385
                double tangent_shift = -cluster_width * 0.5 + _glyphs[glyph_index].x - (_characters[char_index].x + span.x_start);
 
386
                double normal_shift = _glyphs[glyph_index].y;
 
387
                if (span.direction == RIGHT_TO_LEFT)
 
388
                    tangent_shift += cluster_width;
 
389
                _glyphs[glyph_index].x = midpoint[0] - span.chunk(this).left_x + tangent[0] * tangent_shift - tangent[1] * normal_shift;
 
390
                _glyphs[glyph_index].y = midpoint[1] - _lines.front().baseline_y + tangent[1] * tangent_shift + tangent[0] * normal_shift;
 
391
                _glyphs[glyph_index].rotation += rotation;
 
392
            }
 
393
        } else {  // outside the bounds of the path: hide the glyphs
 
394
            _characters[char_index].in_glyph = -1;
 
395
        }
 
396
        g_free(midpoint_otp);
 
397
 
 
398
        char_index = next_cluster_char_index;
 
399
    }
 
400
 
 
401
    for (unsigned span_index = 0 ; span_index < _spans.size() ; span_index++) {
 
402
        _spans[span_index].x_start += offset;
 
403
        _spans[span_index].x_end += offset;
 
404
    }
 
405
 
 
406
    _path_fitted = &path;
 
407
}
 
408
 
 
409
SPCurve *Layout::convertToCurves(iterator const &from_glyph, iterator const &to_glyph) const
 
410
{
 
411
    GSList *cc = NULL;
 
412
 
 
413
    for (int glyph_index = from_glyph._glyph_index ; glyph_index < to_glyph._glyph_index ; glyph_index++) {
 
414
        NRMatrix glyph_matrix;
 
415
        Span const &span = _glyphs[glyph_index].span(this);
 
416
        _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
 
417
 
 
418
        NRBPath bpath;
 
419
        bpath.path = (NArtBpath*)span.font->ArtBPath(_glyphs[glyph_index].glyph);
 
420
        if (bpath.path) {
 
421
            NArtBpath *abp = nr_artpath_affine(bpath.path, glyph_matrix);
 
422
            SPCurve *c = sp_curve_new_from_bpath(abp);
 
423
            if (c) cc = g_slist_prepend(cc, c);
 
424
        }
 
425
    }
 
426
    cc = g_slist_reverse(cc);
 
427
 
 
428
    SPCurve *curve;
 
429
    if ( cc ) {
 
430
        curve = sp_curve_concat(cc);
 
431
    } else {
 
432
        curve = sp_curve_new();
 
433
    }
 
434
 
 
435
    while (cc) {
 
436
        /* fixme: This is dangerous, as we are mixing art_alloc and g_new */
 
437
        sp_curve_unref((SPCurve *) cc->data);
 
438
        cc = g_slist_remove(cc, cc->data);
 
439
    }
 
440
 
 
441
    return curve;
 
442
}
 
443
 
 
444
void Layout::transform(NR::Matrix const &transform)
 
445
{
 
446
    // this is all massively oversimplified
 
447
    // I can't actually think of anybody who'll want to use it at the moment, so it'll stay simple
 
448
    for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; glyph_index++) {
 
449
        NR::Point point(_glyphs[glyph_index].x, _glyphs[glyph_index].y);
 
450
        point *= transform;
 
451
        _glyphs[glyph_index].x = point[0];
 
452
        _glyphs[glyph_index].y = point[1];
 
453
    }
 
454
}
 
455
 
 
456
}//namespace Text
 
457
}//namespace Inkscape
 
458
 
 
459
 
 
460
/*
 
461
  Local Variables:
 
462
  mode:c++
 
463
  c-file-style:"stroustrup"
 
464
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
465
  indent-tabs-mode:nil
 
466
  fill-column:99
 
467
  End:
 
468
*/
 
469
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :