~valavanisalex/ubuntu/precise/inkscape/fix-943984

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/svg/path-string.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Inkscape::SVG::PathString - builder for SVG path strings
 
3
 *
 
4
 * Copyright 2008 Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU General Public License
 
8
 * as published by the Free Software Foundation; either version 2
 
9
 * of the License, or (at your option) any later version.
 
10
 *
 
11
 * See the file COPYING for details.
 
12
 *
 
13
 */
 
14
 
 
15
#include "svg/path-string.h"
 
16
#include "svg/stringstream.h"
 
17
#include "svg/svg.h"
 
18
#include "preferences.h"
 
19
#include <algorithm>
 
20
 
 
21
// 1<=numericprecision<=16, doubles are only accurate upto (slightly less than) 16 digits (and less than one digit doesn't make sense)
 
22
// Please note that these constants are used to allocate sufficient space to hold serialized numbers
 
23
static int const minprec = 1;
 
24
static int const maxprec = 16;
 
25
 
 
26
int Inkscape::SVG::PathString::numericprecision;
 
27
int Inkscape::SVG::PathString::minimumexponent;
 
28
 
 
29
Inkscape::SVG::PathString::PathString() :
 
30
    allow_relative_coordinates(Inkscape::Preferences::get()->getBool("/options/svgoutput/allowrelativecoordinates", true)),
 
31
    force_repeat_commands(Inkscape::Preferences::get()->getBool("/options/svgoutput/forcerepeatcommands"))
 
32
{
 
33
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
 
34
    numericprecision = std::max<int>(minprec,std::min<int>(maxprec, prefs->getInt("/options/svgoutput/numericprecision", 8)));
 
35
    minimumexponent = prefs->getInt("/options/svgoutput/minimumexponent", -8);
 
36
}
 
37
 
 
38
void Inkscape::SVG::PathString::_appendOp(char abs_op, char rel_op) {
 
39
    bool abs_op_repeated = _abs_state.prevop == abs_op && !force_repeat_commands;
 
40
    bool rel_op_repeated = _rel_state.prevop == rel_op && !force_repeat_commands;
 
41
    unsigned int const abs_added_size = abs_op_repeated ? 0 : 2;
 
42
    unsigned int const rel_added_size = rel_op_repeated ? 0 : 2;
 
43
    if ( _rel_state.str.size()+2 < _abs_state.str.size()+abs_added_size && allow_relative_coordinates ) {
 
44
        // Store common prefix
 
45
        commonbase += _rel_state.str;
 
46
        _rel_state.str.clear();
 
47
        // Copy rel to abs
 
48
        _abs_state = _rel_state;
 
49
        _abs_state.switches++;
 
50
        abs_op_repeated = false;
 
51
        // We do not have to copy abs to rel:
 
52
        //   _rel_state.str.size()+2 < _abs_state.str.size()+abs_added_size
 
53
        //   _rel_state.str.size()+rel_added_size < _abs_state.str.size()+2
 
54
        //   _abs_state.str.size()+2 > _rel_state.str.size()+rel_added_size
 
55
    } else if ( _abs_state.str.size()+2 < _rel_state.str.size()+rel_added_size ) {
 
56
        // Store common prefix
 
57
        commonbase += _abs_state.str;
 
58
        _abs_state.str.clear();
 
59
        // Copy abs to rel
 
60
        _rel_state = _abs_state;
 
61
        _abs_state.switches++;
 
62
        rel_op_repeated = false;
 
63
    }
 
64
    if ( !abs_op_repeated ) _abs_state.appendOp(abs_op);
 
65
    if ( !rel_op_repeated ) _rel_state.appendOp(rel_op);
 
66
}
 
67
 
 
68
void Inkscape::SVG::PathString::State::append(Geom::Coord v) {
 
69
    str += ' ';
 
70
    appendNumber(v);
 
71
}
 
72
 
 
73
void Inkscape::SVG::PathString::State::append(Geom::Point p) {
 
74
    str += ' ';
 
75
    appendNumber(p[Geom::X]);
 
76
    str += ',';
 
77
    appendNumber(p[Geom::Y]);
 
78
}
 
79
 
 
80
void Inkscape::SVG::PathString::State::append(Geom::Coord v, Geom::Coord& rv) {
 
81
    str += ' ';
 
82
    appendNumber(v, rv);
 
83
}
 
84
 
 
85
void Inkscape::SVG::PathString::State::append(Geom::Point p, Geom::Point &rp) {
 
86
    str += ' ';
 
87
    appendNumber(p[Geom::X], rp[Geom::X]);
 
88
    str += ',';
 
89
    appendNumber(p[Geom::Y], rp[Geom::Y]);
 
90
}
 
91
 
 
92
// NOTE: The following appendRelativeCoord function will not be exact if the total number of digits needed
 
93
// to represent the difference exceeds the precision of a double. This is not very likely though, and if
 
94
// it does happen the imprecise value is not likely to be chosen (because it will probably be a lot longer
 
95
// than the absolute value).
 
96
 
 
97
// NOTE: This assumes v and r are already rounded (this includes flushing to zero if they are < 10^minexp)
 
98
void Inkscape::SVG::PathString::State::appendRelativeCoord(Geom::Coord v, Geom::Coord r) {
 
99
    int const minexp = minimumexponent-numericprecision+1;
 
100
    int const digitsEnd = (int)floor(log10(std::min(fabs(v),fabs(r)))) - numericprecision; // Position just beyond the last significant digit of the smallest (in absolute sense) number
 
101
    double const roundeddiff = floor((v-r)*pow(10.,-digitsEnd-1)+.5);
 
102
    int const numDigits = (int)floor(log10(fabs(roundeddiff)))+1; // Number of digits in roundeddiff
 
103
    if (r == 0) {
 
104
        appendNumber(v, numericprecision, minexp);
 
105
    } else if (v == 0) {
 
106
        appendNumber(-r, numericprecision, minexp);
 
107
    } else if (numDigits>0) {
 
108
        appendNumber(v-r, numDigits, minexp);
 
109
    } else {
 
110
        // This assumes the input numbers are already rounded to 'precision' digits
 
111
        str += '0';
 
112
    }
 
113
}
 
114
 
 
115
void Inkscape::SVG::PathString::State::appendRelative(Geom::Point p, Geom::Point r) {
 
116
    str += ' ';
 
117
    appendRelativeCoord(p[Geom::X], r[Geom::X]);
 
118
    str += ',';
 
119
    appendRelativeCoord(p[Geom::Y], r[Geom::Y]);
 
120
}
 
121
 
 
122
void Inkscape::SVG::PathString::State::appendRelative(Geom::Coord v, Geom::Coord r) {
 
123
    str += ' ';
 
124
    appendRelativeCoord(v, r);
 
125
}
 
126
 
 
127
void Inkscape::SVG::PathString::State::appendNumber(double v, int precision, int minexp) {
 
128
    size_t const reserve = precision+1+1+1+1+3; // Just large enough to hold the maximum number of digits plus a sign, a period, the letter 'e', another sign and three digits for the exponent
 
129
    size_t const oldsize = str.size();
 
130
    str.append(reserve, (char)0);
 
131
    char* begin_of_num = const_cast<char*>(str.data()+oldsize); // Slightly evil, I know (but std::string should be storing its data in one big block of memory, so...)
 
132
    size_t added = sp_svg_number_write_de(begin_of_num, v, precision, minexp);
 
133
    str.resize(oldsize+added); // remove any trailing characters
 
134
}
 
135
 
 
136
void Inkscape::SVG::PathString::State::appendNumber(double v, double &rv, int precision, int minexp) {
 
137
    size_t const oldsize = str.size();
 
138
    appendNumber(v, precision, minexp);
 
139
    char* begin_of_num = const_cast<char*>(str.data()+oldsize); // Slightly evil, I know (but std::string should be storing its data in one big block of memory, so...)
 
140
    sp_svg_number_read_d(begin_of_num, &rv);
 
141
}
 
142
 
 
143
/*
 
144
  Local Variables:
 
145
  mode:c++
 
146
  c-file-style:"stroustrup"
 
147
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
148
  indent-tabs-mode:nil
 
149
  fill-column:99
 
150
  End:
 
151
*/
 
152
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :