/src/librevenge/src/lib/RVNGSVGDrawingGenerator.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | | /* librevenge |
3 | | * Version: MPL 2.0 / LGPLv2.1+ |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * Major Contributor(s): |
10 | | * Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) |
11 | | * Copyright (C) 2005 Fridrich Strba (fridrich.strba@bluewin.ch) |
12 | | * |
13 | | * For minor contributions see the git repository. |
14 | | * |
15 | | * Alternatively, the contents of this file may be used under the terms |
16 | | * of the GNU Lesser General Public License Version 2.1 or later |
17 | | * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are |
18 | | * applicable instead of those above. |
19 | | */ |
20 | | |
21 | | #include <librevenge-generators/librevenge-generators.h> |
22 | | |
23 | | #include <stdio.h> |
24 | | |
25 | | #include <iostream> |
26 | | #include <map> |
27 | | #include <memory> |
28 | | #include <sstream> |
29 | | #include <string> |
30 | | #include <vector> |
31 | | |
32 | | #include "librevenge_internal.h" |
33 | | |
34 | | namespace librevenge |
35 | | { |
36 | | |
37 | | namespace DrawingSVG |
38 | | { |
39 | | |
40 | | static double getInchValue(librevenge::RVNGProperty const &prop) |
41 | 155k | { |
42 | 155k | double value=prop.getDouble(); |
43 | 155k | switch (prop.getUnit()) |
44 | 155k | { |
45 | 0 | case librevenge::RVNG_GENERIC: // assume inch |
46 | 154k | case librevenge::RVNG_INCH: |
47 | 154k | return value; |
48 | 206 | case librevenge::RVNG_POINT: |
49 | 206 | value /= 72.; |
50 | 206 | return value; |
51 | 0 | case librevenge::RVNG_TWIP: |
52 | 0 | value /= 1440.; |
53 | 0 | return value; |
54 | 0 | case librevenge::RVNG_PERCENT: |
55 | 0 | case librevenge::RVNG_UNIT_ERROR: |
56 | 0 | default: |
57 | 0 | { |
58 | 0 | static bool first=true; |
59 | 0 | if (first) |
60 | 0 | { |
61 | 0 | RVNG_DEBUG_MSG(("librevenge::getInchValue: call with no double value\n")); |
62 | 0 | first=false; |
63 | 0 | } |
64 | 0 | break; |
65 | 0 | } |
66 | 155k | } |
67 | 0 | return value; |
68 | 155k | } |
69 | | |
70 | | static std::string doubleToString(const double value) |
71 | 157k | { |
72 | 157k | std::unique_ptr<RVNGProperty> prop{RVNGPropertyFactory::newDoubleProp(value)}; |
73 | 157k | std::string retVal = prop->getStr().cstr(); |
74 | 157k | return retVal; |
75 | 157k | } |
76 | | |
77 | | static unsigned stringToColour(const RVNGString &s) |
78 | 0 | { |
79 | 0 | std::string str(s.cstr()); |
80 | 0 | if (str[0] == '#') |
81 | 0 | { |
82 | 0 | if (str.length() != 7) |
83 | 0 | return 0; |
84 | 0 | else |
85 | 0 | str.erase(str.begin()); |
86 | 0 | } |
87 | 0 | else |
88 | 0 | return 0; |
89 | | |
90 | 0 | std::istringstream istr(str); |
91 | 0 | unsigned val = 0; |
92 | 0 | istr >> std::hex >> val; |
93 | 0 | return val; |
94 | 0 | } |
95 | | |
96 | | //! basic class used to store table information |
97 | | struct Table |
98 | | { |
99 | | //! constructor |
100 | 0 | Table(const RVNGPropertyList &propList) : m_column(0), m_row(0), m_x(0), m_y(0), m_columnsDistanceFromOrigin(), m_rowsDistanceFromOrigin() |
101 | 0 | { |
102 | 0 | if (propList["svg:x"]) |
103 | 0 | m_x=getInchValue(*propList["svg:x"]); |
104 | 0 | if (propList["svg:y"]) |
105 | 0 | m_y=getInchValue(*propList["svg:y"]); |
106 | | // we do not actually use height/width, so... |
107 | |
|
108 | 0 | m_columnsDistanceFromOrigin.push_back(0); |
109 | 0 | m_rowsDistanceFromOrigin.push_back(0); |
110 | |
|
111 | 0 | const librevenge::RVNGPropertyListVector *columns = propList.child("librevenge:table-columns"); |
112 | 0 | if (columns) |
113 | 0 | { |
114 | 0 | double actDist=0; |
115 | 0 | for (unsigned long i=0; i<columns->count(); ++i) |
116 | 0 | { |
117 | 0 | if ((*columns)[i]["style:column-width"]) |
118 | 0 | actDist+=getInchValue(*(*columns)[i]["style:column-width"]); |
119 | 0 | m_columnsDistanceFromOrigin.push_back(actDist); |
120 | 0 | } |
121 | 0 | } |
122 | 0 | else |
123 | 0 | { |
124 | 0 | RVNG_DEBUG_MSG(("librevenge::DrawingSVG::Table::Table: can not find any columns\n")); |
125 | 0 | } |
126 | 0 | } |
127 | | //! calls to open a row |
128 | | void openRow(const RVNGPropertyList &propList) |
129 | 0 | { |
130 | 0 | double height=0; |
131 | 0 | if (propList["style:row-height"]) |
132 | 0 | height=getInchValue(*propList["style:row-height"]); |
133 | | // changeme |
134 | 0 | else if (propList["style:min-row-height"]) |
135 | 0 | height=getInchValue(*propList["style:min-row-height"]); |
136 | 0 | else |
137 | 0 | { |
138 | 0 | RVNG_DEBUG_MSG(("librevenge::DrawingSVG::Table::openRow: can not determine row height\n")); |
139 | 0 | } |
140 | 0 | m_rowsDistanceFromOrigin.push_back(m_rowsDistanceFromOrigin.back()+height); |
141 | 0 | } |
142 | | //! call to close a row |
143 | | void closeRow() |
144 | 0 | { |
145 | 0 | ++m_row; |
146 | 0 | } |
147 | | //! returns the position of a cellule |
148 | | bool getPosition(int column, int row, double &x, double &y) const |
149 | 0 | { |
150 | 0 | bool ok=true; |
151 | 0 | if (column>=0 && column <int(m_columnsDistanceFromOrigin.size())) |
152 | 0 | x=m_x+m_columnsDistanceFromOrigin[size_t(column)]; |
153 | 0 | else |
154 | 0 | { |
155 | 0 | ok=false; |
156 | 0 | RVNG_DEBUG_MSG(("librevenge::DrawingSVG::Table::getPosition: the column %d seems bad\n", column)); |
157 | 0 | x=(column<0 || m_columnsDistanceFromOrigin.empty()) ? m_x : m_x + m_columnsDistanceFromOrigin.back(); |
158 | 0 | } |
159 | 0 | if (row>=0 && row <int(m_rowsDistanceFromOrigin.size())) |
160 | 0 | y=m_y+m_rowsDistanceFromOrigin[size_t(row)]; |
161 | 0 | else |
162 | 0 | { |
163 | 0 | ok=false; |
164 | 0 | RVNG_DEBUG_MSG(("librevenge::DrawingSVG::Table::getPosition: the row %d seems bad\n", row)); |
165 | 0 | y=(row<0 || m_rowsDistanceFromOrigin.empty()) ? m_y : m_y + m_rowsDistanceFromOrigin.back(); |
166 | 0 | } |
167 | 0 | return ok; |
168 | 0 | } |
169 | | //! the actual column |
170 | | int m_column; |
171 | | //! the actual row |
172 | | int m_row; |
173 | | //! the origin table position in inches |
174 | | double m_x, m_y; |
175 | | //! the distance of each begin column in inches from origin |
176 | | std::vector<double> m_columnsDistanceFromOrigin; |
177 | | //! the distance of each begin row in inches from origin |
178 | | std::vector<double> m_rowsDistanceFromOrigin; |
179 | | }; |
180 | | |
181 | | } // DrawingSVG namespace |
182 | | |
183 | | using namespace DrawingSVG; |
184 | | |
185 | | struct RVNGSVGDrawingGeneratorPrivate |
186 | | { |
187 | | RVNGSVGDrawingGeneratorPrivate(RVNGStringVector &vec, const RVNGString &nmSpace); |
188 | | |
189 | | void setStyle(const RVNGPropertyList &propList); |
190 | | void writeStyle(bool isClosed=true); |
191 | | void drawPolySomething(const RVNGPropertyListVector &vertices, bool isClosed); |
192 | | |
193 | | //! return the namespace and the delimiter |
194 | | std::string const &getNamespaceAndDelim() const |
195 | 45.7k | { |
196 | 45.7k | return m_nmSpaceAndDelim; |
197 | 45.7k | } |
198 | | |
199 | | std::map<int, RVNGPropertyList> m_idSpanMap; |
200 | | |
201 | | RVNGPropertyListVector m_gradient; |
202 | | RVNGPropertyList m_style; |
203 | | int m_gradientIndex, m_shadowIndex; |
204 | | //! index uses when fill=bitmap |
205 | | int m_patternIndex; |
206 | | int m_arrowStartIndex /** start arrow index*/, m_arrowEndIndex /** end arrow index */; |
207 | | //! groupId used if svg:id is not defined when calling openGroup |
208 | | int m_groupId; |
209 | | //! layerId used if svg:id is not defined when calling startLayer |
210 | | int m_layerId; |
211 | | //! a prefix used to define the svg namespace |
212 | | std::string m_nmSpace; |
213 | | //! a prefix used to define the svg namespace with delimiter |
214 | | std::string m_nmSpaceAndDelim; |
215 | | std::ostringstream m_outputSink; |
216 | | RVNGStringVector &m_vec; |
217 | | //! the actual master name |
218 | | RVNGString m_masterName; |
219 | | //! a map master name to master content |
220 | | std::map<RVNGString, std::string> m_masterNameToContentMap; |
221 | | //! the actual opened table |
222 | | std::shared_ptr<Table> m_table; |
223 | | }; |
224 | | |
225 | | RVNGSVGDrawingGeneratorPrivate::RVNGSVGDrawingGeneratorPrivate(RVNGStringVector &vec, const RVNGString &nmSpace) : |
226 | 10.8k | m_idSpanMap(), |
227 | 10.8k | m_gradient(), |
228 | 10.8k | m_style(), |
229 | 10.8k | m_gradientIndex(1), |
230 | 10.8k | m_shadowIndex(1), |
231 | 10.8k | m_patternIndex(1), |
232 | 10.8k | m_arrowStartIndex(1), |
233 | 10.8k | m_arrowEndIndex(1), |
234 | 10.8k | m_groupId(1000), m_layerId(1000), |
235 | 10.8k | m_nmSpace(nmSpace.cstr()), |
236 | 10.8k | m_nmSpaceAndDelim(""), |
237 | 10.8k | m_outputSink(), |
238 | 10.8k | m_vec(vec), |
239 | 10.8k | m_masterName(), m_masterNameToContentMap(), |
240 | 10.8k | m_table() |
241 | 10.8k | { |
242 | 10.8k | if (!m_nmSpace.empty()) |
243 | 0 | m_nmSpaceAndDelim = m_nmSpace+":"; |
244 | 10.8k | } |
245 | | |
246 | | void RVNGSVGDrawingGeneratorPrivate::drawPolySomething(const RVNGPropertyListVector &vertices, bool isClosed) |
247 | 0 | { |
248 | 0 | if (vertices.count() < 2) |
249 | 0 | return; |
250 | | |
251 | 0 | if (vertices.count() == 2) |
252 | 0 | { |
253 | 0 | if (!vertices[0]["svg:x"]||!vertices[0]["svg:y"]||!vertices[1]["svg:x"]||!vertices[1]["svg:y"]) |
254 | 0 | return; |
255 | 0 | m_outputSink << "<" << getNamespaceAndDelim() << "line "; |
256 | 0 | m_outputSink << "x1=\"" << doubleToString(72*getInchValue(*vertices[0]["svg:x"])) << "\" y1=\"" << doubleToString(72*getInchValue(*vertices[0]["svg:y"])) << "\" "; |
257 | 0 | m_outputSink << "x2=\"" << doubleToString(72*getInchValue(*vertices[1]["svg:x"])) << "\" y2=\"" << doubleToString(72*getInchValue(*vertices[1]["svg:y"])) << "\"\n"; |
258 | 0 | writeStyle(); |
259 | 0 | m_outputSink << "/>\n"; |
260 | 0 | } |
261 | 0 | else |
262 | 0 | { |
263 | 0 | if (isClosed) |
264 | 0 | m_outputSink << "<" << getNamespaceAndDelim() << "polygon "; |
265 | 0 | else |
266 | 0 | m_outputSink << "<" << getNamespaceAndDelim() << "polyline "; |
267 | |
|
268 | 0 | m_outputSink << "points=\""; |
269 | 0 | for (unsigned long i = 0; i < vertices.count(); i++) |
270 | 0 | { |
271 | 0 | if (!vertices[i]["svg:x"]||!vertices[i]["svg:y"]) |
272 | 0 | continue; |
273 | 0 | m_outputSink << doubleToString(72*getInchValue(*vertices[i]["svg:x"])) << " " << doubleToString(72*getInchValue(*vertices[i]["svg:y"])); |
274 | 0 | if (i < vertices.count()-1) |
275 | 0 | m_outputSink << ", "; |
276 | 0 | } |
277 | 0 | m_outputSink << "\"\n"; |
278 | 0 | writeStyle(isClosed); |
279 | 0 | m_outputSink << "/>\n"; |
280 | 0 | } |
281 | 0 | } |
282 | | |
283 | | void RVNGSVGDrawingGeneratorPrivate::setStyle(const RVNGPropertyList &propList) |
284 | 3.17k | { |
285 | 3.17k | m_style.clear(); |
286 | 3.17k | m_style = propList; |
287 | | |
288 | 3.17k | const librevenge::RVNGPropertyListVector *gradient = propList.child("svg:linearGradient"); |
289 | 3.17k | if (!gradient) |
290 | 3.17k | gradient = propList.child("svg:radialGradient"); |
291 | 3.17k | m_gradient = gradient ? *gradient : librevenge::RVNGPropertyListVector(); |
292 | 3.17k | if (m_style["draw:shadow"] && m_style["draw:shadow"]->getStr() == "visible" && m_style["draw:shadow-opacity"]) |
293 | 0 | { |
294 | 0 | double shadowRed = 0.0; |
295 | 0 | double shadowGreen = 0.0; |
296 | 0 | double shadowBlue = 0.0; |
297 | 0 | if (m_style["draw:shadow-color"]) |
298 | 0 | { |
299 | 0 | unsigned shadowColour = stringToColour(m_style["draw:shadow-color"]->getStr()); |
300 | 0 | shadowRed = (double)((shadowColour & 0x00ff0000) >> 16)/255.0; |
301 | 0 | shadowGreen = (double)((shadowColour & 0x0000ff00) >> 8)/255.0; |
302 | 0 | shadowBlue = (double)(shadowColour & 0x000000ff)/255.0; |
303 | 0 | } |
304 | 0 | m_outputSink << "<" << getNamespaceAndDelim() << "defs>\n"; |
305 | 0 | m_outputSink << "<" << getNamespaceAndDelim() << "filter filterUnits=\"userSpaceOnUse\" id=\"shadow" << m_shadowIndex++ << "\">"; |
306 | 0 | m_outputSink << "<" << getNamespaceAndDelim() << "feOffset in=\"SourceGraphic\" result=\"offset\" "; |
307 | 0 | if (m_style["draw:shadow-offset-x"]) |
308 | 0 | m_outputSink << "dx=\"" << doubleToString(72*getInchValue(*m_style["draw:shadow-offset-x"])) << "\" "; |
309 | 0 | if (m_style["draw:shadow-offset-y"]) |
310 | 0 | m_outputSink << "dy=\"" << doubleToString(72*getInchValue(*m_style["draw:shadow-offset-y"])) << "\" "; |
311 | 0 | m_outputSink << "/>"; |
312 | 0 | m_outputSink << "<" << getNamespaceAndDelim() << "feColorMatrix in=\"offset\" result=\"offset-color\" type=\"matrix\" values=\""; |
313 | 0 | m_outputSink << "0 0 0 0 " << doubleToString(shadowRed) ; |
314 | 0 | m_outputSink << " 0 0 0 0 " << doubleToString(shadowGreen); |
315 | 0 | m_outputSink << " 0 0 0 0 " << doubleToString(shadowBlue); |
316 | 0 | if (m_style["draw:opacity"] && m_style["draw:opacity"]->getDouble() < 1) |
317 | 0 | m_outputSink << " 0 0 0 " << doubleToString(m_style["draw:shadow-opacity"]->getDouble()/m_style["draw:opacity"]->getDouble()) << " 0\"/>"; |
318 | 0 | else |
319 | 0 | m_outputSink << " 0 0 0 " << doubleToString(m_style["draw:shadow-opacity"]->getDouble()) << " 0\"/>"; |
320 | |
|
321 | 0 | m_outputSink << "<" << getNamespaceAndDelim() << "feMerge>"; |
322 | 0 | m_outputSink << "<" << getNamespaceAndDelim() << "feMergeNode in=\"offset-color\" />"; |
323 | 0 | m_outputSink << "<" << getNamespaceAndDelim() << "feMergeNode in=\"SourceGraphic\" />"; |
324 | 0 | m_outputSink << "</" << getNamespaceAndDelim() << "feMerge>"; |
325 | 0 | m_outputSink << "</" << getNamespaceAndDelim() << "filter>"; |
326 | 0 | m_outputSink << "</" << getNamespaceAndDelim() << "defs>"; |
327 | 0 | } |
328 | | |
329 | 3.17k | if (m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "gradient") |
330 | 333 | { |
331 | 333 | double angle = (m_style["draw:angle"] ? m_style["draw:angle"]->getDouble() : 0.0); |
332 | 333 | angle *= -1.0; |
333 | 424 | while (angle < 0) |
334 | 91 | angle += 360; |
335 | 333 | while (angle > 360) |
336 | 0 | angle -= 360; |
337 | | |
338 | 333 | if (m_style["draw:style"] && (m_style["draw:style"]->getStr() == "radial" || m_style["draw:style"]->getStr() == "rectangular" || |
339 | 91 | m_style["draw:style"]->getStr() == "square" || m_style["draw:style"]->getStr() == "ellipsoid")) |
340 | 242 | { |
341 | 242 | m_outputSink << "<" << getNamespaceAndDelim() << "defs>\n"; |
342 | 242 | m_outputSink << " <" << getNamespaceAndDelim() << "radialGradient id=\"grad" << m_gradientIndex++ << "\""; |
343 | | |
344 | 242 | if (m_style["svg:cx"]) |
345 | 242 | m_outputSink << " cx=\"" << m_style["svg:cx"]->getStr().cstr() << "\""; |
346 | 0 | else if (m_style["draw:cx"]) |
347 | 0 | m_outputSink << " cx=\"" << m_style["draw:cx"]->getStr().cstr() << "\""; |
348 | | |
349 | 242 | if (m_style["svg:cy"]) |
350 | 242 | m_outputSink << " cy=\"" << m_style["svg:cy"]->getStr().cstr() << "\""; |
351 | 0 | else if (m_style["draw:cy"]) |
352 | 0 | m_outputSink << " cy=\"" << m_style["draw:cy"]->getStr().cstr() << "\""; |
353 | 242 | if (m_style["svg:r"]) |
354 | 0 | m_outputSink << " r=\"" << m_style["svg:r"]->getStr().cstr() << "\""; |
355 | 242 | else if (m_style["draw:border"]) |
356 | 0 | m_outputSink << " r=\"" << doubleToString((1 - m_style["draw:border"]->getDouble())*100.0) << "%\""; |
357 | 242 | else |
358 | 242 | m_outputSink << " r=\"100%\""; |
359 | 242 | m_outputSink << " >\n"; |
360 | 242 | if (m_gradient.count()) |
361 | 0 | { |
362 | 0 | for (unsigned long c = 0; c < m_gradient.count(); c++) |
363 | 0 | { |
364 | 0 | RVNGPropertyList const &grad=m_gradient[c]; |
365 | 0 | m_outputSink << " <" << getNamespaceAndDelim() << "stop"; |
366 | 0 | if (grad["svg:offset"]) |
367 | 0 | m_outputSink << " offset=\"" << grad["svg:offset"]->getStr().cstr() << "\""; |
368 | 0 | if (grad["svg:stop-color"]) |
369 | 0 | m_outputSink << " stop-color=\"" << grad["svg:stop-color"]->getStr().cstr() << "\""; |
370 | 0 | if (grad["svg:stop-opacity"]) |
371 | 0 | m_outputSink << " stop-opacity=\"" << doubleToString(grad["svg:stop-opacity"]->getDouble()) << "\""; |
372 | 0 | m_outputSink << "/>" << std::endl; |
373 | 0 | } |
374 | 0 | } |
375 | 242 | else if (m_style["draw:start-color"] && m_style["draw:end-color"]) |
376 | 130 | { |
377 | 130 | m_outputSink << " <" << getNamespaceAndDelim() << "stop offset=\"0%\""; |
378 | 130 | m_outputSink << " stop-color=\"" << m_style["draw:end-color"]->getStr().cstr() << "\""; |
379 | 130 | m_outputSink << " stop-opacity=\"" << doubleToString(m_style["librevenge:end-opacity"] ? m_style["librevenge:end-opacity"]->getDouble() : 1) << "\" />" << std::endl; |
380 | | |
381 | 130 | m_outputSink << " <" << getNamespaceAndDelim() << "stop offset=\"100%\""; |
382 | 130 | m_outputSink << " stop-color=\"" << m_style["draw:start-color"]->getStr().cstr() << "\""; |
383 | 130 | m_outputSink << " stop-opacity=\"" << doubleToString(m_style["librevenge:start-opacity"] ? m_style["librevenge:start-opacity"]->getDouble() : 1) << "\" />" << std::endl; |
384 | 130 | } |
385 | 242 | m_outputSink << " </" << getNamespaceAndDelim() << "radialGradient>\n"; |
386 | 242 | m_outputSink << "</" << getNamespaceAndDelim() << "defs>\n"; |
387 | 242 | } |
388 | 91 | else if (!m_style["draw:style"] || m_style["draw:style"]->getStr() == "linear" || m_style["draw:style"]->getStr() == "axial") |
389 | 91 | { |
390 | 91 | m_outputSink << "<" << getNamespaceAndDelim() << "defs>\n"; |
391 | 91 | m_outputSink << " <" << getNamespaceAndDelim() << "linearGradient id=\"grad" << m_gradientIndex++ << "\" >\n"; |
392 | | |
393 | 91 | if (m_gradient.count()) |
394 | 0 | { |
395 | 0 | bool canBuildAxial = false; |
396 | 0 | if (m_style["draw:style"] && m_style["draw:style"]->getStr() == "axial") |
397 | 0 | { |
398 | | // check if we can reconstruct the linear offset, ie. if each offset is a valid percent% |
399 | 0 | canBuildAxial = true; |
400 | 0 | for (unsigned long c = 0; c < m_gradient.count(); ++c) |
401 | 0 | { |
402 | 0 | RVNGPropertyList const &grad=m_gradient[c]; |
403 | 0 | if (!grad["svg:offset"] || grad["svg:offset"]->getDouble()<0 || grad["svg:offset"]->getDouble() > 1) |
404 | 0 | { |
405 | 0 | canBuildAxial=false; |
406 | 0 | break; |
407 | 0 | } |
408 | 0 | RVNGString str=grad["svg:offset"]->getStr(); |
409 | 0 | int len=str.len(); |
410 | 0 | if (len<1 || str.cstr()[len-1]!='%') |
411 | 0 | { |
412 | 0 | canBuildAxial=false; |
413 | 0 | break; |
414 | 0 | } |
415 | 0 | } |
416 | 0 | } |
417 | 0 | if (canBuildAxial) |
418 | 0 | { |
419 | 0 | for (unsigned long c = m_gradient.count(); c>0 ;) |
420 | 0 | { |
421 | 0 | RVNGPropertyList const &grad=m_gradient[--c]; |
422 | 0 | m_outputSink << " <" << getNamespaceAndDelim() << "stop "; |
423 | 0 | if (grad["svg:offset"]) |
424 | 0 | m_outputSink << "offset=\"" << doubleToString(50.-50.*grad["svg:offset"]->getDouble()) << "%\""; |
425 | 0 | if (grad["svg:stop-color"]) |
426 | 0 | m_outputSink << " stop-color=\"" << grad["svg:stop-color"]->getStr().cstr() << "\""; |
427 | 0 | if (grad["svg:stop-opacity"]) |
428 | 0 | m_outputSink << " stop-opacity=\"" << doubleToString(grad["svg:stop-opacity"]->getDouble()) << "\""; |
429 | 0 | m_outputSink << "/>" << std::endl; |
430 | 0 | } |
431 | 0 | for (unsigned long c = 0; c < m_gradient.count(); ++c) |
432 | 0 | { |
433 | 0 | RVNGPropertyList const &grad=m_gradient[c]; |
434 | 0 | if (c==0 && grad["svg:offset"] && grad["svg:offset"]->getDouble() <= 0) |
435 | 0 | continue; |
436 | 0 | m_outputSink << " <" << getNamespaceAndDelim() << "stop "; |
437 | 0 | if (grad["svg:offset"]) |
438 | 0 | m_outputSink << "offset=\"" << doubleToString(50.+50.*grad["svg:offset"]->getDouble()) << "%\""; |
439 | 0 | if (grad["svg:stop-color"]) |
440 | 0 | m_outputSink << " stop-color=\"" << grad["svg:stop-color"]->getStr().cstr() << "\""; |
441 | 0 | if (grad["svg:stop-opacity"]) |
442 | 0 | m_outputSink << " stop-opacity=\"" << doubleToString(grad["svg:stop-opacity"]->getDouble()) << "\""; |
443 | 0 | m_outputSink << "/>" << std::endl; |
444 | 0 | } |
445 | 0 | } |
446 | 0 | else |
447 | 0 | { |
448 | 0 | for (unsigned long c = 0; c < m_gradient.count(); c++) |
449 | 0 | { |
450 | 0 | RVNGPropertyList const &grad=m_gradient[c]; |
451 | 0 | m_outputSink << " <" << getNamespaceAndDelim() << "stop"; |
452 | 0 | if (grad["svg:offset"]) |
453 | 0 | m_outputSink << " offset=\"" << grad["svg:offset"]->getStr().cstr() << "\""; |
454 | 0 | if (grad["svg:stop-color"]) |
455 | 0 | m_outputSink << " stop-color=\"" << grad["svg:stop-color"]->getStr().cstr() << "\""; |
456 | 0 | if (grad["svg:stop-opacity"]) |
457 | 0 | m_outputSink << " stop-opacity=\"" << doubleToString(grad["svg:stop-opacity"]->getDouble()) << "\""; |
458 | 0 | m_outputSink << "/>" << std::endl; |
459 | 0 | } |
460 | 0 | } |
461 | 0 | } |
462 | 91 | else if (m_style["draw:start-color"] && m_style["draw:end-color"]) |
463 | 69 | { |
464 | 69 | if (!m_style["draw:style"] || m_style["draw:style"]->getStr() == "linear") |
465 | 69 | { |
466 | 69 | m_outputSink << " <" << getNamespaceAndDelim() << "stop offset=\"0%\""; |
467 | 69 | m_outputSink << " stop-color=\"" << m_style["draw:start-color"]->getStr().cstr() << "\""; |
468 | 69 | m_outputSink << " stop-opacity=\"" << doubleToString(m_style["librevenge:start-opacity"] ? m_style["librevenge:start-opacity"]->getDouble() : 1) << "\" />" << std::endl; |
469 | | |
470 | 69 | m_outputSink << " <" << getNamespaceAndDelim() << "stop offset=\"100%\""; |
471 | 69 | m_outputSink << " stop-color=\"" << m_style["draw:end-color"]->getStr().cstr() << "\""; |
472 | 69 | m_outputSink << " stop-opacity=\"" << doubleToString(m_style["librevenge:end-opacity"] ? m_style["librevenge:end-opacity"]->getDouble() : 1) << "\" />" << std::endl; |
473 | 69 | } |
474 | 0 | else |
475 | 0 | { |
476 | 0 | m_outputSink << " <" << getNamespaceAndDelim() << "stop offset=\"0%\""; |
477 | 0 | m_outputSink << " stop-color=\"" << m_style["draw:end-color"]->getStr().cstr() << "\""; |
478 | 0 | m_outputSink << " stop-opacity=\"" << doubleToString(m_style["librevenge:end-opacity"] ? m_style["librevenge:end-opacity"]->getDouble() : 1) << "\" />" << std::endl; |
479 | |
|
480 | 0 | m_outputSink << " <" << getNamespaceAndDelim() << "stop offset=\"50%\""; |
481 | 0 | m_outputSink << " stop-color=\"" << m_style["draw:start-color"]->getStr().cstr() << "\""; |
482 | 0 | m_outputSink << " stop-opacity=\"" << doubleToString(m_style["librevenge:start-opacity"] ? m_style["librevenge:start-opacity"]->getDouble() : 1) << "\" />" << std::endl; |
483 | |
|
484 | 0 | m_outputSink << " <" << getNamespaceAndDelim() << "stop offset=\"100%\""; |
485 | 0 | m_outputSink << " stop-color=\"" << m_style["draw:end-color"]->getStr().cstr() << "\""; |
486 | 0 | m_outputSink << " stop-opacity=\"" << doubleToString(m_style["librevenge:end-opacity"] ? m_style["librevenge:end-opacity"]->getDouble() : 1) << "\" />" << std::endl; |
487 | 0 | } |
488 | 69 | } |
489 | 91 | m_outputSink << " </" << getNamespaceAndDelim() << "linearGradient>\n"; |
490 | | |
491 | | // not a simple horizontal gradient |
492 | 91 | if (angle<270 || angle>270) |
493 | 85 | { |
494 | 85 | m_outputSink << " <" << getNamespaceAndDelim() << "linearGradient xlink:href=\"#grad" << m_gradientIndex-1 << "\""; |
495 | 85 | m_outputSink << " id=\"grad" << m_gradientIndex++ << "\" "; |
496 | 85 | m_outputSink << "x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\" "; |
497 | 85 | m_outputSink << "gradientTransform=\"rotate(" << angle << " .5 .5)\" "; |
498 | 85 | m_outputSink << "gradientUnits=\"objectBoundingBox\" >\n"; |
499 | 85 | m_outputSink << " </" << getNamespaceAndDelim() << "linearGradient>\n"; |
500 | 85 | } |
501 | | |
502 | 91 | m_outputSink << "</" << getNamespaceAndDelim() << "defs>\n"; |
503 | 91 | } |
504 | 333 | } |
505 | 2.84k | else if (m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "bitmap" && m_style["draw:fill-image"] && m_style["librevenge:mime-type"]) |
506 | 1.42k | { |
507 | 1.42k | m_outputSink << "<" << getNamespaceAndDelim() << "defs>\n"; |
508 | 1.42k | m_outputSink << " <" << getNamespaceAndDelim() << "pattern id=\"img" << m_patternIndex++ << "\" patternUnits=\"userSpaceOnUse\" "; |
509 | 1.42k | if (m_style["svg:width"]) |
510 | 48 | m_outputSink << "width=\"" << doubleToString(72*getInchValue(*m_style["svg:width"])) << "\" "; |
511 | 1.37k | else |
512 | 1.37k | m_outputSink << "width=\"100\" "; |
513 | | |
514 | 1.42k | if (m_style["svg:height"]) |
515 | 48 | m_outputSink << "height=\"" << doubleToString(72*getInchValue(*m_style["svg:height"])) << "\">" << std::endl; |
516 | 1.37k | else |
517 | 1.37k | m_outputSink << "height=\"100\">" << std::endl; |
518 | 1.42k | m_outputSink << "<" << getNamespaceAndDelim() << "image "; |
519 | | |
520 | 1.42k | if (m_style["svg:x"]) |
521 | 0 | m_outputSink << "x=\"" << doubleToString(72*getInchValue(*m_style["svg:x"])) << "\" "; |
522 | 1.42k | else |
523 | 1.42k | m_outputSink << "x=\"0\" "; |
524 | | |
525 | 1.42k | if (m_style["svg:y"]) |
526 | 0 | m_outputSink << "y=\"" << doubleToString(72*getInchValue(*m_style["svg:y"])) << "\" "; |
527 | 1.42k | else |
528 | 1.42k | m_outputSink << "y=\"0\" "; |
529 | | |
530 | 1.42k | if (m_style["svg:width"]) |
531 | 48 | m_outputSink << "width=\"" << doubleToString(72*getInchValue(*m_style["svg:width"])) << "\" "; |
532 | 1.37k | else |
533 | 1.37k | m_outputSink << "width=\"100\" "; |
534 | | |
535 | 1.42k | if (m_style["svg:height"]) |
536 | 48 | m_outputSink << "height=\"" << doubleToString(72*getInchValue(*m_style["svg:height"])) << "\" "; |
537 | 1.37k | else |
538 | 1.37k | m_outputSink << "height=\"100\" "; |
539 | | |
540 | 1.42k | m_outputSink << "xlink:href=\"data:" << m_style["librevenge:mime-type"]->getStr().cstr() << ";base64,"; |
541 | 1.42k | m_outputSink << m_style["draw:fill-image"]->getStr().cstr(); |
542 | 1.42k | m_outputSink << "\" />\n"; |
543 | 1.42k | m_outputSink << " </" << getNamespaceAndDelim() << "pattern>\n"; |
544 | 1.42k | m_outputSink << "</" << getNamespaceAndDelim() << "defs>\n"; |
545 | 1.42k | } |
546 | | |
547 | | // check for arrow and if find some, define a basic arrow |
548 | 3.17k | if (m_style["draw:marker-start-path"]) |
549 | 340 | { |
550 | 340 | m_outputSink << "<" << getNamespaceAndDelim() << "defs>\n"; |
551 | 340 | m_outputSink << "<" << getNamespaceAndDelim() << "marker id=\"startMarker" << m_arrowStartIndex++ << "\" "; |
552 | 340 | m_outputSink << " markerUnits=\"strokeWidth\" orient=\"auto\" markerWidth=\"8\" markerHeight=\"6\"\n"; |
553 | 340 | m_outputSink << " viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\">\n"; |
554 | 340 | m_outputSink << "<" << getNamespaceAndDelim() << "polyline points=\"10,0 0,5 10,10 9,5\" fill=\"solid\" />\n"; |
555 | 340 | m_outputSink << "</" << getNamespaceAndDelim() << "marker>\n"; |
556 | 340 | m_outputSink << "</" << getNamespaceAndDelim() << "defs>\n"; |
557 | 340 | } |
558 | 3.17k | if (m_style["draw:marker-end-path"]) |
559 | 348 | { |
560 | 348 | m_outputSink << "<" << getNamespaceAndDelim() << "defs>\n"; |
561 | 348 | m_outputSink << "<" << getNamespaceAndDelim() << "marker id=\"endMarker" << m_arrowEndIndex++ << "\" "; |
562 | 348 | m_outputSink << " markerUnits=\"strokeWidth\" orient=\"auto\" markerWidth=\"8\" markerHeight=\"6\"\n"; |
563 | 348 | m_outputSink << " viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\">\n"; |
564 | 348 | m_outputSink << "<" << getNamespaceAndDelim() << "polyline points=\"0,0 10,5 0,10 1,5\" fill=\"solid\" />\n"; |
565 | 348 | m_outputSink << "</" << getNamespaceAndDelim() << "marker>\n"; |
566 | 348 | m_outputSink << "</" << getNamespaceAndDelim() << "defs>\n"; |
567 | 348 | } |
568 | 3.17k | } |
569 | | |
570 | | // create "style" attribute based on current pen and brush |
571 | | void RVNGSVGDrawingGeneratorPrivate::writeStyle(bool /* isClosed */) |
572 | 3.17k | { |
573 | 3.17k | m_outputSink << "style=\""; |
574 | | |
575 | 3.17k | double width = 1.0 / 72.0; |
576 | 3.17k | if (m_style["svg:stroke-width"]) |
577 | 1.15k | { |
578 | 1.15k | width = getInchValue(*m_style["svg:stroke-width"]); |
579 | | #if 0 |
580 | | // add me in libmspub and libcdr |
581 | | if (width <= 0.0 && m_style["draw:stroke"] && m_style["draw:stroke"]->getStr() != "none") |
582 | | width = 0.2 / 72.0; // reasonable hairline |
583 | | #endif |
584 | 1.15k | m_outputSink << "stroke-width: " << doubleToString(72*width) << "; "; |
585 | 1.15k | } |
586 | | |
587 | 3.17k | if (m_style["draw:stroke"] && m_style["draw:stroke"]->getStr() != "none") |
588 | 1.18k | { |
589 | 1.18k | if (m_style["svg:stroke-color"]) |
590 | 1.14k | m_outputSink << "stroke: " << m_style["svg:stroke-color"]->getStr().cstr() << "; "; |
591 | 1.18k | if (m_style["svg:stroke-opacity"] && m_style["svg:stroke-opacity"]->getInt()!= 1) |
592 | 0 | m_outputSink << "stroke-opacity: " << doubleToString(m_style["svg:stroke-opacity"]->getDouble()) << "; "; |
593 | 1.18k | } |
594 | | |
595 | 3.17k | if (m_style["draw:stroke"] && m_style["draw:stroke"]->getStr() == "solid") |
596 | 1.12k | m_outputSink << "stroke-dasharray: none; "; |
597 | 2.05k | else if (m_style["draw:stroke"] && m_style["draw:stroke"]->getStr() == "dash") |
598 | 59 | { |
599 | 59 | int dots1 = m_style["draw:dots1"] ? m_style["draw:dots1"]->getInt() : 0; |
600 | 59 | int dots2 = m_style["draw:dots2"] ? m_style["draw:dots2"]->getInt() : 0; |
601 | 59 | double dots1len = 72.*width, dots2len = 72.*width, gap = 72.*width; |
602 | 59 | if (m_style["draw:dots1-length"]) |
603 | 59 | { |
604 | 59 | if (m_style["draw:dots1-length"]->getUnit()==librevenge::RVNG_PERCENT) |
605 | 0 | dots1len=72*m_style["draw:dots1-length"]->getDouble()*width; |
606 | 59 | else |
607 | 59 | dots1len=72*getInchValue(*m_style["draw:dots1-length"]); |
608 | 59 | } |
609 | 59 | if (m_style["draw:dots2-length"]) |
610 | 47 | { |
611 | 47 | if (m_style["draw:dots2-length"]->getUnit()==librevenge::RVNG_PERCENT) |
612 | 0 | dots2len=72*m_style["draw:dots2-length"]->getDouble()*width; |
613 | 47 | else |
614 | 47 | dots2len=72*getInchValue(*m_style["draw:dots2-length"]); |
615 | 47 | } |
616 | 59 | if (m_style["draw:distance"]) |
617 | 59 | { |
618 | 59 | if (m_style["draw:distance"]->getUnit()==librevenge::RVNG_PERCENT) |
619 | 0 | gap=72*m_style["draw:distance"]->getDouble()*width; |
620 | 59 | else |
621 | 59 | gap=72*getInchValue(*m_style["draw:distance"]); |
622 | 59 | } |
623 | 59 | m_outputSink << "stroke-dasharray: "; |
624 | 147 | for (int i = 0; i < dots1; i++) |
625 | 88 | { |
626 | 88 | if (i) |
627 | 29 | m_outputSink << ", "; |
628 | 88 | m_outputSink << doubleToString(dots1len); |
629 | 88 | m_outputSink << ", "; |
630 | 88 | m_outputSink << doubleToString(gap); |
631 | 88 | } |
632 | 117 | for (int j = 0; j < dots2; j++) |
633 | 58 | { |
634 | 58 | m_outputSink << ", "; |
635 | 58 | m_outputSink << doubleToString(dots2len); |
636 | 58 | m_outputSink << ", "; |
637 | 58 | m_outputSink << doubleToString(gap); |
638 | 58 | } |
639 | 59 | m_outputSink << "; "; |
640 | 59 | } |
641 | | |
642 | 3.17k | if (m_style["svg:stroke-linecap"]) |
643 | 0 | m_outputSink << "stroke-linecap: " << m_style["svg:stroke-linecap"]->getStr().cstr() << "; "; |
644 | | |
645 | 3.17k | if (m_style["svg:stroke-linejoin"]) |
646 | 0 | m_outputSink << "stroke-linejoin: " << m_style["svg:stroke-linejoin"]->getStr().cstr() << "; "; |
647 | | |
648 | 3.17k | if (m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "none") |
649 | 961 | m_outputSink << "fill: none; "; |
650 | 2.21k | else if (m_style["svg:fill-rule"]) |
651 | 0 | m_outputSink << "fill-rule: " << m_style["svg:fill-rule"]->getStr().cstr() << "; "; |
652 | | |
653 | 3.17k | if (m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "gradient") |
654 | 333 | m_outputSink << "fill: url(#grad" << m_gradientIndex-1 << "); "; |
655 | 2.84k | else if (m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "bitmap") |
656 | 1.42k | m_outputSink << "fill: url(#img" << m_patternIndex-1 << "); "; |
657 | | |
658 | 3.17k | if (m_style["draw:shadow"] && m_style["draw:shadow"]->getStr() == "visible") |
659 | 0 | m_outputSink << "filter:url(#shadow" << m_shadowIndex-1 << "); "; |
660 | | |
661 | 3.17k | if (m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "solid") |
662 | 460 | if (m_style["draw:fill-color"]) |
663 | 460 | m_outputSink << "fill: " << m_style["draw:fill-color"]->getStr().cstr() << "; "; |
664 | 3.17k | if (m_style["draw:opacity"] && m_style["draw:opacity"]->getDouble() < 1) |
665 | 0 | m_outputSink << "fill-opacity: " << doubleToString(m_style["draw:opacity"]->getDouble()) << "; "; |
666 | | |
667 | 3.17k | if (m_style["draw:marker-start-path"]) |
668 | 340 | m_outputSink << "marker-start: url(#startMarker" << m_arrowStartIndex-1 << "); "; |
669 | 3.17k | if (m_style["draw:marker-end-path"]) |
670 | 348 | m_outputSink << "marker-end: url(#endMarker" << m_arrowEndIndex-1 << "); "; |
671 | | |
672 | 3.17k | m_outputSink << "\""; // style |
673 | 3.17k | } |
674 | | |
675 | | |
676 | | RVNGSVGDrawingGenerator::RVNGSVGDrawingGenerator(RVNGStringVector &vec, const RVNGString &nmSpace) : |
677 | 10.8k | m_pImpl(new RVNGSVGDrawingGeneratorPrivate(vec, nmSpace)) |
678 | 10.8k | { |
679 | 10.8k | } |
680 | | |
681 | | RVNGSVGDrawingGenerator::~RVNGSVGDrawingGenerator() |
682 | 10.8k | { |
683 | 10.8k | delete m_pImpl; |
684 | 10.8k | } |
685 | | |
686 | 0 | void RVNGSVGDrawingGenerator::startDocument(const RVNGPropertyList & /*propList*/) {} |
687 | 0 | void RVNGSVGDrawingGenerator::endDocument() {} |
688 | 0 | void RVNGSVGDrawingGenerator::setDocumentMetaData(const RVNGPropertyList & /*propList*/) {} |
689 | 0 | void RVNGSVGDrawingGenerator::defineEmbeddedFont(const RVNGPropertyList & /*propList*/) {} |
690 | | |
691 | | void RVNGSVGDrawingGenerator::startPage(const RVNGPropertyList &propList) |
692 | 10.7k | { |
693 | 10.7k | if (propList["librevenge:master-page-name"]) |
694 | 0 | { |
695 | 0 | if (m_pImpl->m_masterNameToContentMap.find(propList["librevenge:master-page-name"]->getStr())!= |
696 | 0 | m_pImpl->m_masterNameToContentMap.end()) |
697 | 0 | { |
698 | 0 | m_pImpl->m_outputSink << m_pImpl->m_masterNameToContentMap.find(propList["librevenge:master-page-name"]->getStr())->second; |
699 | 0 | return; |
700 | 0 | } |
701 | 0 | RVNG_DEBUG_MSG(("RVNGSVGDrawingGenerator::startPage: can not find page with given master name\n")); |
702 | 0 | } |
703 | | |
704 | 10.7k | m_pImpl->m_outputSink << "<" << m_pImpl->getNamespaceAndDelim() << "svg version=\"1.1\" xmlns"; |
705 | 10.7k | m_pImpl->m_outputSink << (m_pImpl->m_nmSpace.empty() ? "" : ":") << m_pImpl->m_nmSpace << "=\"http://www.w3.org/2000/svg\" "; |
706 | 10.7k | m_pImpl->m_outputSink << "xmlns:xlink=\"http://www.w3.org/1999/xlink\" "; |
707 | 10.7k | if (propList["svg:width"]) |
708 | 10.7k | m_pImpl->m_outputSink << "width=\"" << doubleToString(getInchValue(*propList["svg:width"])) << "in\" "; |
709 | 10.7k | if (propList["svg:height"]) |
710 | 10.7k | m_pImpl->m_outputSink << "height=\"" << doubleToString(getInchValue(*propList["svg:height"])) << "in\" "; |
711 | 10.7k | if (propList["svg:width"] && propList["svg:height"]) |
712 | 10.7k | { |
713 | 10.7k | m_pImpl->m_outputSink << "viewBox=\"0 0 " << doubleToString(72*getInchValue(*propList["svg:width"])); |
714 | 10.7k | m_pImpl->m_outputSink << " " << doubleToString(72*getInchValue(*propList["svg:height"])) << "\""; |
715 | 10.7k | } |
716 | 10.7k | m_pImpl->m_outputSink << " >\n"; |
717 | 10.7k | } |
718 | | |
719 | | void RVNGSVGDrawingGenerator::endPage() |
720 | 10.7k | { |
721 | 10.7k | m_pImpl->m_outputSink << "</" << m_pImpl->getNamespaceAndDelim() << "svg>\n"; |
722 | 10.7k | m_pImpl->m_vec.append(m_pImpl->m_outputSink.str().c_str()); |
723 | 10.7k | m_pImpl->m_outputSink.str(""); |
724 | 10.7k | } |
725 | | |
726 | | void RVNGSVGDrawingGenerator::startMasterPage(const RVNGPropertyList &propList) |
727 | 0 | { |
728 | 0 | if (!m_pImpl->m_masterName.empty()) |
729 | 0 | { |
730 | 0 | RVNG_DEBUG_MSG(("RVNGSVGDrawingGenerator::startMasterPage: a master page is already opened\n")); |
731 | 0 | } |
732 | 0 | else if (propList["librevenge:master-page-name"]) |
733 | 0 | { |
734 | 0 | m_pImpl->m_masterName=propList["librevenge:master-page-name"]->getStr(); |
735 | 0 | RVNGPropertyList pList(propList); |
736 | 0 | pList.remove("librevenge:master-page-name"); |
737 | 0 | startPage(pList); |
738 | 0 | } |
739 | 0 | else |
740 | 0 | { |
741 | 0 | RVNG_DEBUG_MSG(("RVNGSVGDrawingGenerator::startMasterPage: can not find the master name\n")); |
742 | 0 | } |
743 | 0 | } |
744 | | |
745 | | void RVNGSVGDrawingGenerator::endMasterPage() |
746 | 0 | { |
747 | 0 | if (m_pImpl->m_masterName.empty()) |
748 | 0 | { |
749 | 0 | RVNG_DEBUG_MSG(("RVNGSVGDrawingGenerator::endMasterPage: no master pages are opened\n")); |
750 | 0 | } |
751 | 0 | else |
752 | 0 | { |
753 | 0 | if (m_pImpl->m_masterNameToContentMap.find(m_pImpl->m_masterName)!=m_pImpl->m_masterNameToContentMap.end()) |
754 | 0 | { |
755 | 0 | RVNG_DEBUG_MSG(("RVNGSVGDrawingGenerator::endMasterPage: a master page with name %s already exists\n", |
756 | 0 | m_pImpl->m_masterName.cstr())); |
757 | 0 | } |
758 | | // no need to close the page, this will be done when the master page will be used |
759 | 0 | m_pImpl->m_masterNameToContentMap[m_pImpl->m_masterName]=m_pImpl->m_outputSink.str(); |
760 | 0 | m_pImpl->m_masterName.clear(); |
761 | 0 | } |
762 | | // reset the content |
763 | 0 | m_pImpl->m_outputSink.str(""); |
764 | 0 | } |
765 | | |
766 | | void RVNGSVGDrawingGenerator::startLayer(const RVNGPropertyList &propList) |
767 | 0 | { |
768 | 0 | m_pImpl->m_outputSink << "<" << m_pImpl->getNamespaceAndDelim() << "g"; |
769 | 0 | librevenge::RVNGString layer("Layer"); |
770 | 0 | if (propList["draw:layer"]) |
771 | 0 | layer.append(propList["draw:layer"]->getStr()); |
772 | 0 | else if (propList["svg:id"]) |
773 | 0 | layer.append(propList["svg:id"]->getStr()); |
774 | 0 | else |
775 | 0 | layer.sprintf("Layer%d", m_pImpl->m_layerId++); |
776 | 0 | librevenge::RVNGString finalName(""); |
777 | 0 | finalName.appendEscapedXML(layer); |
778 | 0 | m_pImpl->m_outputSink << " id=\"" << finalName.cstr() << "\""; |
779 | 0 | if (propList["svg:fill-rule"]) |
780 | 0 | m_pImpl->m_outputSink << " fill-rule=\"" << propList["svg:fill-rule"]->getStr().cstr() << "\""; |
781 | 0 | m_pImpl->m_outputSink << " >\n"; |
782 | 0 | } |
783 | | |
784 | | void RVNGSVGDrawingGenerator::endLayer() |
785 | 0 | { |
786 | 0 | m_pImpl->m_outputSink << "</" << m_pImpl->getNamespaceAndDelim() << "g>\n"; |
787 | 0 | } |
788 | | |
789 | 0 | void RVNGSVGDrawingGenerator::startEmbeddedGraphics(const RVNGPropertyList & /*propList*/) {} |
790 | 0 | void RVNGSVGDrawingGenerator::endEmbeddedGraphics() {} |
791 | | |
792 | | void RVNGSVGDrawingGenerator::openGroup(const RVNGPropertyList & /*propList*/) |
793 | 1.27k | { |
794 | 1.27k | m_pImpl->m_outputSink << "<" << m_pImpl->getNamespaceAndDelim() << "g"; |
795 | 1.27k | librevenge::RVNGString group; |
796 | 1.27k | group.sprintf("Group%d", m_pImpl->m_groupId++); |
797 | 1.27k | m_pImpl->m_outputSink << " id=\"" << group.cstr() << "\""; |
798 | 1.27k | m_pImpl->m_outputSink << " >\n"; |
799 | 1.27k | } |
800 | | |
801 | | void RVNGSVGDrawingGenerator::closeGroup() |
802 | 1.27k | { |
803 | 1.27k | m_pImpl->m_outputSink << "</" << m_pImpl->getNamespaceAndDelim() << "g>\n"; |
804 | 1.27k | } |
805 | | |
806 | | void RVNGSVGDrawingGenerator::setStyle(const RVNGPropertyList &propList) |
807 | 3.17k | { |
808 | 3.17k | m_pImpl->setStyle(propList); |
809 | 3.17k | } |
810 | | |
811 | | void RVNGSVGDrawingGenerator::drawRectangle(const RVNGPropertyList &propList) |
812 | 0 | { |
813 | 0 | if (!propList["svg:x"] || !propList["svg:y"] || !propList["svg:width"] || !propList["svg:height"]) |
814 | 0 | return; |
815 | 0 | m_pImpl->m_outputSink << "<" << m_pImpl->getNamespaceAndDelim() << "rect "; |
816 | 0 | m_pImpl->m_outputSink << "x=\"" << doubleToString(72*getInchValue(*propList["svg:x"])) << "\" y=\"" << doubleToString(72*getInchValue(*propList["svg:y"])) << "\" "; |
817 | 0 | m_pImpl->m_outputSink << "width=\"" << doubleToString(72*getInchValue(*propList["svg:width"])) << "\" height=\"" << doubleToString(72*getInchValue(*propList["svg:height"])) << "\" "; |
818 | 0 | if (propList["svg:rx"] && propList["svg:rx"]->getDouble() > 0 && propList["svg:ry"] && propList["svg:ry"]->getDouble()>0) |
819 | 0 | m_pImpl->m_outputSink << "rx=\"" << doubleToString(72*getInchValue(*propList["svg:rx"])) << "\" ry=\"" << doubleToString(72*getInchValue(*propList["svg:ry"])) << "\" "; |
820 | 0 | m_pImpl->writeStyle(); |
821 | 0 | m_pImpl->m_outputSink << "/>\n"; |
822 | 0 | } |
823 | | |
824 | | void RVNGSVGDrawingGenerator::drawEllipse(const RVNGPropertyList &propList) |
825 | 0 | { |
826 | 0 | if (!propList["svg:cx"] || !propList["svg:cy"] || !propList["svg:rx"] || !propList["svg:ry"]) |
827 | 0 | return; |
828 | 0 | m_pImpl->m_outputSink << "<" << m_pImpl->getNamespaceAndDelim() << "ellipse "; |
829 | 0 | m_pImpl->m_outputSink << "cx=\"" << doubleToString(72*getInchValue(*propList["svg:cx"])) << "\" cy=\"" << doubleToString(72*getInchValue(*propList["svg:cy"])) << "\" "; |
830 | 0 | m_pImpl->m_outputSink << "rx=\"" << doubleToString(72*getInchValue(*propList["svg:rx"])) << "\" ry=\"" << doubleToString(72*getInchValue(*propList["svg:ry"])) << "\" "; |
831 | 0 | m_pImpl->writeStyle(); |
832 | 0 | if (propList["librevenge:rotate"] && (propList["librevenge:rotate"]->getDouble()<0||propList["librevenge:rotate"]->getDouble()>0)) |
833 | 0 | m_pImpl->m_outputSink << " transform=\" rotate(" << doubleToString(-propList["librevenge:rotate"]->getDouble()) |
834 | 0 | << ", " << doubleToString(72*getInchValue(*propList["svg:cx"])) |
835 | 0 | << ", " << doubleToString(72*getInchValue(*propList["svg:cy"])) |
836 | 0 | << ")\" "; |
837 | 0 | m_pImpl->m_outputSink << "/>\n"; |
838 | 0 | } |
839 | | |
840 | | void RVNGSVGDrawingGenerator::drawPolyline(const RVNGPropertyList &propList) |
841 | 0 | { |
842 | 0 | const RVNGPropertyListVector *vertices = propList.child("svg:points"); |
843 | 0 | if (vertices && vertices->count()) |
844 | 0 | m_pImpl->drawPolySomething(*vertices, false); |
845 | 0 | } |
846 | | |
847 | | void RVNGSVGDrawingGenerator::drawPolygon(const RVNGPropertyList &propList) |
848 | 0 | { |
849 | 0 | const RVNGPropertyListVector *vertices = propList.child("svg:points"); |
850 | 0 | if (vertices && vertices->count()) |
851 | 0 | m_pImpl->drawPolySomething(*vertices, true); |
852 | 0 | } |
853 | | |
854 | | void RVNGSVGDrawingGenerator::drawPath(const RVNGPropertyList &propList) |
855 | 3.17k | { |
856 | 3.17k | const RVNGPropertyListVector *path = propList.child("svg:d"); |
857 | 3.17k | if (!path) |
858 | 0 | return; |
859 | 3.17k | m_pImpl->m_outputSink << "<" << m_pImpl->getNamespaceAndDelim() << "path d=\" "; |
860 | 3.17k | bool isClosed = false; |
861 | 3.17k | unsigned long i=0; |
862 | 33.1k | for (i=0; i < path->count(); i++) |
863 | 29.9k | { |
864 | 29.9k | RVNGPropertyList pList((*path)[i]); |
865 | 29.9k | if (!pList["librevenge:path-action"]) continue; |
866 | 29.9k | std::string action=pList["librevenge:path-action"]->getStr().cstr(); |
867 | 29.9k | if (action.length()!=1) continue; |
868 | 29.9k | bool coordOk=pList["svg:x"]&&pList["svg:y"]; |
869 | 29.9k | bool coord1Ok=coordOk && pList["svg:x1"]&&pList["svg:y1"]; |
870 | 29.9k | bool coord2Ok=coord1Ok && pList["svg:x2"]&&pList["svg:y2"]; |
871 | 29.9k | if (pList["svg:x"] && action[0] == 'H') |
872 | 0 | m_pImpl->m_outputSink << "\nH" << doubleToString(72*getInchValue(*pList["svg:x"])); |
873 | 29.9k | else if (pList["svg:y"] && action[0] == 'V') |
874 | 0 | m_pImpl->m_outputSink << "\nV" << doubleToString(72*getInchValue(*pList["svg:y"])); |
875 | 29.9k | else if (coordOk && (action[0] == 'M' || action[0] == 'L' || action[0] == 'T')) |
876 | 12.1k | { |
877 | 12.1k | m_pImpl->m_outputSink << "\n" << action; |
878 | 12.1k | m_pImpl->m_outputSink << doubleToString(72*getInchValue(*pList["svg:x"])) << "," << doubleToString(72*getInchValue(*pList["svg:y"])); |
879 | 12.1k | } |
880 | 17.7k | else if (coord1Ok && (action[0] == 'Q' || action[0] == 'S')) |
881 | 2.81k | { |
882 | 2.81k | m_pImpl->m_outputSink << "\n" << action; |
883 | 2.81k | m_pImpl->m_outputSink << doubleToString(72*getInchValue(*pList["svg:x1"])) << "," << doubleToString(72*getInchValue(*pList["svg:y1"])) << " "; |
884 | 2.81k | m_pImpl->m_outputSink << doubleToString(72*getInchValue(*pList["svg:x"])) << "," << doubleToString(72*getInchValue(*pList["svg:y"])); |
885 | 2.81k | } |
886 | 14.9k | else if (coord2Ok && action[0] == 'C') |
887 | 12.1k | { |
888 | 12.1k | m_pImpl->m_outputSink << "\nC"; |
889 | 12.1k | m_pImpl->m_outputSink << doubleToString(72*getInchValue(*pList["svg:x1"])) << "," << doubleToString(72*getInchValue(*pList["svg:y1"])) << " "; |
890 | 12.1k | m_pImpl->m_outputSink << doubleToString(72*getInchValue(*pList["svg:x2"])) << "," << doubleToString(72*getInchValue(*pList["svg:y2"])) << " "; |
891 | 12.1k | m_pImpl->m_outputSink << doubleToString(72*getInchValue(*pList["svg:x"])) << "," << doubleToString(72*getInchValue(*pList["svg:y"])); |
892 | 12.1k | } |
893 | 2.80k | else if (coordOk && pList["svg:rx"] && pList["svg:ry"] && action[0] == 'A') |
894 | 0 | { |
895 | 0 | m_pImpl->m_outputSink << "\nA"; |
896 | 0 | m_pImpl->m_outputSink << doubleToString(72*getInchValue(*pList["svg:rx"])) << "," << doubleToString(72*getInchValue(*pList["svg:ry"])) << " "; |
897 | 0 | m_pImpl->m_outputSink << doubleToString(pList["librevenge:rotate"] ? pList["librevenge:rotate"]->getDouble() : 0) << " "; |
898 | 0 | m_pImpl->m_outputSink << (pList["librevenge:large-arc"] ? pList["librevenge:large-arc"]->getInt() : 1) << ","; |
899 | 0 | m_pImpl->m_outputSink << (pList["librevenge:sweep"] ? pList["librevenge:sweep"]->getInt() : 1) << " "; |
900 | 0 | m_pImpl->m_outputSink << doubleToString(72*getInchValue(*pList["svg:x"])) << "," << doubleToString(72*getInchValue(*pList["svg:y"])); |
901 | 0 | } |
902 | 2.80k | else if (action[0] == 'Z') |
903 | 2.80k | { |
904 | 2.80k | isClosed = true; |
905 | 2.80k | m_pImpl->m_outputSink << "\nZ"; |
906 | 2.80k | } |
907 | 29.9k | } |
908 | | |
909 | 3.17k | m_pImpl->m_outputSink << "\" \n"; |
910 | 3.17k | m_pImpl->writeStyle(isClosed); |
911 | 3.17k | m_pImpl->m_outputSink << "/>\n"; |
912 | 3.17k | } |
913 | | |
914 | | void RVNGSVGDrawingGenerator::drawGraphicObject(const RVNGPropertyList &propList) |
915 | 0 | { |
916 | 0 | if (!propList["librevenge:mime-type"] || propList["librevenge:mime-type"]->getStr().len() <= 0) |
917 | 0 | return; |
918 | 0 | if (!propList["office:binary-data"]) |
919 | 0 | return; |
920 | 0 | m_pImpl->m_outputSink << "<" << m_pImpl->getNamespaceAndDelim() << "image "; |
921 | 0 | if (propList["svg:x"] && propList["svg:y"] && propList["svg:width"] && propList["svg:height"]) |
922 | 0 | { |
923 | 0 | double x=getInchValue(*propList["svg:x"]); |
924 | 0 | double y=getInchValue(*propList["svg:y"]); |
925 | 0 | double width=getInchValue(*propList["svg:width"]); |
926 | 0 | double height=getInchValue(*propList["svg:height"]); |
927 | 0 | bool flipX(propList["draw:mirror-horizontal"] && propList["draw:mirror-horizontal"]->getInt()); |
928 | 0 | bool flipY(propList["draw:mirror-vertical"] && propList["draw:mirror-vertical"]->getInt()); |
929 | |
|
930 | 0 | m_pImpl->m_outputSink << "x=\"" << doubleToString(72*x) << "\" y=\"" << doubleToString(72*y) << "\" "; |
931 | 0 | m_pImpl->m_outputSink << "width=\"" << doubleToString(72*width) << "\" height=\"" << doubleToString(72*height) << "\" "; |
932 | 0 | if (flipX || flipY || propList["librevenge:rotate"]) |
933 | 0 | { |
934 | 0 | double xmiddle = x + width / 2.0; |
935 | 0 | double ymiddle = y + height / 2.0; |
936 | 0 | m_pImpl->m_outputSink << "transform=\""; |
937 | 0 | m_pImpl->m_outputSink << " translate(" << doubleToString(72*xmiddle) << ", " << doubleToString(72*ymiddle) << ") "; |
938 | 0 | m_pImpl->m_outputSink << " scale(" << (flipX ? "-1" : "1") << ", " << (flipY ? "-1" : "1") << ") "; |
939 | | // rotation is around the center of the object's bounding box |
940 | 0 | if (propList["librevenge:rotate"]) |
941 | 0 | { |
942 | 0 | double angle(propList["librevenge:rotate"]->getDouble()); |
943 | 0 | while (angle > 180.0) |
944 | 0 | angle -= 360.0; |
945 | 0 | while (angle < -180.0) |
946 | 0 | angle += 360.0; |
947 | 0 | m_pImpl->m_outputSink << " rotate(" << doubleToString(angle) << ") "; |
948 | 0 | } |
949 | 0 | m_pImpl->m_outputSink << " translate(" << doubleToString(-72*xmiddle) << ", " << doubleToString(-72*ymiddle) << ") "; |
950 | 0 | m_pImpl->m_outputSink << "\" "; |
951 | 0 | } |
952 | 0 | } |
953 | 0 | m_pImpl->m_outputSink << "xlink:href=\"data:" << propList["librevenge:mime-type"]->getStr().cstr() << ";base64,"; |
954 | 0 | m_pImpl->m_outputSink << propList["office:binary-data"]->getStr().cstr(); |
955 | 0 | m_pImpl->m_outputSink << "\" />\n"; |
956 | 0 | } |
957 | | |
958 | | void RVNGSVGDrawingGenerator::drawConnector(const RVNGPropertyList &/*propList*/) |
959 | 0 | { |
960 | | // TODO: implement me |
961 | 0 | } |
962 | | |
963 | | void RVNGSVGDrawingGenerator::startTextObject(const RVNGPropertyList &propList) |
964 | 504 | { |
965 | 504 | double x = 0.0; |
966 | 504 | double y = 0.0; |
967 | 504 | double height = 0.0; |
968 | 504 | m_pImpl->m_outputSink << "<" << m_pImpl->getNamespaceAndDelim() << "text "; |
969 | 504 | if (propList["svg:x"] && propList["svg:y"]) |
970 | 504 | { |
971 | 504 | x = getInchValue(*propList["svg:x"]); |
972 | 504 | y = getInchValue(*propList["svg:y"]); |
973 | 504 | } |
974 | | |
975 | 504 | double xmiddle = x; |
976 | 504 | double ymiddle = y; |
977 | | |
978 | 504 | if (propList["svg:width"]) |
979 | 504 | { |
980 | 504 | double width = getInchValue(*propList["svg:width"]); |
981 | 504 | xmiddle += width / 2.0; |
982 | 504 | } |
983 | | |
984 | 504 | if (propList["svg:height"]) |
985 | 504 | { |
986 | 504 | height = getInchValue(*propList["svg:height"]); |
987 | 504 | ymiddle += height / 2.0; |
988 | 504 | } |
989 | | |
990 | 504 | if (propList["draw:textarea-vertical-align"]) |
991 | 0 | { |
992 | 0 | if (propList["draw:textarea-vertical-align"]->getStr() == "middle") |
993 | 0 | y = ymiddle; |
994 | 0 | if (propList["draw:textarea-vertical-align"]->getStr() == "bottom") |
995 | 0 | { |
996 | 0 | y += height; |
997 | 0 | if (propList["fo:padding-bottom"]) |
998 | 0 | y -= propList["fo:padding-bottom"]->getDouble(); |
999 | 0 | } |
1000 | 0 | } |
1001 | 504 | else |
1002 | 504 | y += height; |
1003 | | |
1004 | 504 | if (propList["fo:padding-left"]) |
1005 | 111 | x += propList["fo:padding-left"]->getDouble(); |
1006 | | |
1007 | 504 | m_pImpl->m_outputSink << "x=\"" << doubleToString(72*x) << "\" y=\"" << doubleToString(72*y) << "\""; |
1008 | | |
1009 | | // rotation is around the center of the object's bounding box |
1010 | 504 | if (propList["librevenge:rotate"] && (propList["librevenge:rotate"]->getDouble()<0||propList["librevenge:rotate"]->getDouble()>0)) |
1011 | 184 | { |
1012 | 184 | double angle(propList["librevenge:rotate"]->getDouble()); |
1013 | 184 | while (angle > 180.0) |
1014 | 0 | angle -= 360.0; |
1015 | 184 | while (angle < -180.0) |
1016 | 0 | angle += 360.0; |
1017 | 184 | m_pImpl->m_outputSink << " transform=\"rotate(" << doubleToString(angle) << ", " << doubleToString(72*xmiddle) << ", " << doubleToString(72*ymiddle) << ")\" "; |
1018 | 184 | } |
1019 | 504 | m_pImpl->m_outputSink << ">\n"; |
1020 | | |
1021 | 504 | } |
1022 | | |
1023 | | void RVNGSVGDrawingGenerator::endTextObject() |
1024 | 504 | { |
1025 | 504 | m_pImpl->m_outputSink << "</" << m_pImpl->getNamespaceAndDelim() << "text>\n"; |
1026 | 504 | } |
1027 | | |
1028 | 0 | void RVNGSVGDrawingGenerator::openOrderedListLevel(const RVNGPropertyList & /*propList*/) {} |
1029 | 0 | void RVNGSVGDrawingGenerator::closeOrderedListLevel() {} |
1030 | | |
1031 | 0 | void RVNGSVGDrawingGenerator::openUnorderedListLevel(const RVNGPropertyList & /*propList*/) {} |
1032 | 0 | void RVNGSVGDrawingGenerator::closeUnorderedListLevel() {} |
1033 | | |
1034 | 0 | void RVNGSVGDrawingGenerator::openListElement(const RVNGPropertyList & /*propList*/) {} |
1035 | 0 | void RVNGSVGDrawingGenerator::closeListElement() {} |
1036 | | |
1037 | 0 | void RVNGSVGDrawingGenerator::defineParagraphStyle(const RVNGPropertyList & /*propList*/) {} |
1038 | 1.16k | void RVNGSVGDrawingGenerator::openParagraph(const RVNGPropertyList & /*propList*/) {} |
1039 | 1.16k | void RVNGSVGDrawingGenerator::closeParagraph() {} |
1040 | | |
1041 | | void RVNGSVGDrawingGenerator::defineCharacterStyle(const RVNGPropertyList &propList) |
1042 | 0 | { |
1043 | 0 | if (!propList["librevenge:span-id"]) |
1044 | 0 | { |
1045 | 0 | RVNG_DEBUG_MSG(("RVNGSVGDrawingGenerator::defineCharacterStyle: can not find the span-id\n")); |
1046 | 0 | return; |
1047 | 0 | } |
1048 | 0 | m_pImpl->m_idSpanMap[propList["librevenge:span-id"]->getInt()]=propList; |
1049 | 0 | } |
1050 | | |
1051 | | void RVNGSVGDrawingGenerator::openSpan(const RVNGPropertyList &propList) |
1052 | 2.51k | { |
1053 | 2.51k | RVNGPropertyList pList(propList); |
1054 | 2.51k | if (propList["librevenge:span-id"] && |
1055 | 0 | m_pImpl->m_idSpanMap.find(propList["librevenge:span-id"]->getInt())!=m_pImpl->m_idSpanMap.end()) |
1056 | 0 | pList=m_pImpl->m_idSpanMap.find(propList["librevenge:span-id"]->getInt())->second; |
1057 | | |
1058 | 2.51k | m_pImpl->m_outputSink << "<" << m_pImpl->getNamespaceAndDelim() << "tspan "; |
1059 | 2.51k | if (pList["style:font-name"]) |
1060 | 2.03k | m_pImpl->m_outputSink << "font-family=\"" << pList["style:font-name"]->getStr().cstr() << "\" "; |
1061 | 2.51k | if (pList["fo:font-style"]) |
1062 | 115 | m_pImpl->m_outputSink << "font-style=\"" << pList["fo:font-style"]->getStr().cstr() << "\" "; |
1063 | 2.51k | if (pList["fo:font-weight"]) |
1064 | 420 | m_pImpl->m_outputSink << "font-weight=\"" << pList["fo:font-weight"]->getStr().cstr() << "\" "; |
1065 | 2.51k | if (pList["fo:font-variant"]) |
1066 | 0 | m_pImpl->m_outputSink << "font-variant=\"" << pList["fo:font-variant"]->getStr().cstr() << "\" "; |
1067 | 2.51k | if (pList["fo:font-size"]) |
1068 | 2.23k | m_pImpl->m_outputSink << "font-size=\"" << doubleToString(pList["fo:font-size"]->getDouble()) << "\" "; |
1069 | 2.51k | if (pList["fo:color"]) |
1070 | 174 | m_pImpl->m_outputSink << "fill=\"" << pList["fo:color"]->getStr().cstr() << "\" "; |
1071 | 2.51k | if (pList["fo:text-transform"]) |
1072 | 0 | m_pImpl->m_outputSink << "text-transform=\"" << pList["fo:text-transform"]->getStr().cstr() << "\" "; |
1073 | 2.51k | if (pList["svg:fill-opacity"]) |
1074 | 0 | m_pImpl->m_outputSink << "fill-opacity=\"" << doubleToString(pList["svg:fill-opacity"]->getDouble()) << "\" "; |
1075 | 2.51k | if (pList["svg:stroke-opacity"]) |
1076 | 0 | m_pImpl->m_outputSink << "stroke-opacity=\"" << doubleToString(pList["svg:stroke-opacity"]->getDouble()) << "\" "; |
1077 | 2.51k | m_pImpl->m_outputSink << ">\n"; |
1078 | 2.51k | } |
1079 | | |
1080 | | void RVNGSVGDrawingGenerator::closeSpan() |
1081 | 2.51k | { |
1082 | 2.51k | m_pImpl->m_outputSink << "</" << m_pImpl->getNamespaceAndDelim() << "tspan>\n"; |
1083 | 2.51k | } |
1084 | | |
1085 | 0 | void RVNGSVGDrawingGenerator::openLink(const RVNGPropertyList & /*propList*/) {} |
1086 | 0 | void RVNGSVGDrawingGenerator::closeLink() {} |
1087 | | |
1088 | | void RVNGSVGDrawingGenerator::insertText(const RVNGString &str) |
1089 | 5.53k | { |
1090 | 5.53k | m_pImpl->m_outputSink << RVNGString::escapeXML(str).cstr(); |
1091 | 5.53k | } |
1092 | | |
1093 | | void RVNGSVGDrawingGenerator::insertTab() |
1094 | 6.84k | { |
1095 | 6.84k | m_pImpl->m_outputSink << "\t"; |
1096 | 6.84k | } |
1097 | | |
1098 | | void RVNGSVGDrawingGenerator::insertSpace() |
1099 | 0 | { |
1100 | 0 | m_pImpl->m_outputSink << " "; |
1101 | 0 | } |
1102 | | |
1103 | | void RVNGSVGDrawingGenerator::insertLineBreak() |
1104 | 0 | { |
1105 | 0 | m_pImpl->m_outputSink << "\n"; |
1106 | 0 | } |
1107 | | |
1108 | 0 | void RVNGSVGDrawingGenerator::insertField(const RVNGPropertyList & /*propList*/) {} |
1109 | | |
1110 | | void RVNGSVGDrawingGenerator::startTableObject(const RVNGPropertyList &propList) |
1111 | 0 | { |
1112 | 0 | if (m_pImpl->m_table) |
1113 | 0 | { |
1114 | 0 | RVNG_DEBUG_MSG(("RVNGSVGDrawingGenerator::startTableObject: a table is already opened\n")); |
1115 | 0 | return; |
1116 | 0 | } |
1117 | 0 | m_pImpl->m_table.reset(new Table(propList)); |
1118 | 0 | } |
1119 | | |
1120 | | void RVNGSVGDrawingGenerator::openTableRow(const RVNGPropertyList &propList) |
1121 | 0 | { |
1122 | 0 | if (!m_pImpl->m_table) return; |
1123 | 0 | m_pImpl->m_table->openRow(propList); |
1124 | 0 | } |
1125 | | |
1126 | | void RVNGSVGDrawingGenerator::closeTableRow() |
1127 | 0 | { |
1128 | 0 | if (!m_pImpl->m_table) return; |
1129 | 0 | m_pImpl->m_table->closeRow(); |
1130 | 0 | } |
1131 | | |
1132 | | void RVNGSVGDrawingGenerator::openTableCell(const RVNGPropertyList &propList) |
1133 | 0 | { |
1134 | 0 | if (!m_pImpl->m_table) return; |
1135 | | |
1136 | 0 | if (propList["librevenge:column"]) |
1137 | 0 | m_pImpl->m_table->m_column=propList["librevenge:column"]->getInt(); |
1138 | 0 | if (propList["librevenge:row"]) |
1139 | 0 | m_pImpl->m_table->m_row=propList["librevenge:row"]->getInt(); |
1140 | |
|
1141 | 0 | double x = 0, y=0; |
1142 | 0 | m_pImpl->m_table->getPosition(m_pImpl->m_table->m_column, m_pImpl->m_table->m_row, x, y); |
1143 | 0 | m_pImpl->m_outputSink << "<" << m_pImpl->getNamespaceAndDelim() << "text "; |
1144 | 0 | m_pImpl->m_outputSink << "x=\"" << doubleToString(72*x) << "\" y=\"" << doubleToString(72*y) << "\""; |
1145 | 0 | m_pImpl->m_outputSink << ">\n"; |
1146 | | |
1147 | | // time to update the next cell's column |
1148 | 0 | if (propList["table:number-columns-spanned"]) |
1149 | 0 | m_pImpl->m_table->m_column += propList["librevenge:column"]->getInt(); |
1150 | 0 | else |
1151 | 0 | ++m_pImpl->m_table->m_column; |
1152 | 0 | } |
1153 | | |
1154 | | void RVNGSVGDrawingGenerator::closeTableCell() |
1155 | 0 | { |
1156 | 0 | if (!m_pImpl->m_table) return; |
1157 | 0 | m_pImpl->m_outputSink << "</" << m_pImpl->getNamespaceAndDelim() << "text>\n"; |
1158 | 0 | } |
1159 | | |
1160 | | void RVNGSVGDrawingGenerator::insertCoveredTableCell(const RVNGPropertyList &/*propList*/) |
1161 | 0 | { |
1162 | 0 | if (!m_pImpl->m_table) return; |
1163 | | // TODO: implement me |
1164 | 0 | } |
1165 | | |
1166 | | void RVNGSVGDrawingGenerator::endTableObject() |
1167 | 0 | { |
1168 | 0 | if (!m_pImpl->m_table) |
1169 | 0 | { |
1170 | 0 | RVNG_DEBUG_MSG(("RVNGSVGDrawingGenerator::endTableObject: no table is already opened\n")); |
1171 | 0 | return; |
1172 | 0 | } |
1173 | 0 | m_pImpl->m_table.reset(); |
1174 | 0 | } |
1175 | | |
1176 | | } |
1177 | | |
1178 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |