Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 : *
7 : * For further information visit http://libwpg.sourceforge.net
8 : */
9 :
10 : #include "FilterInternal.hxx"
11 :
12 : #include "OdgGenerator.hxx"
13 : #include "DocumentElement.hxx"
14 : #include "OdfDocumentHandler.hxx"
15 : #include "TextRunStyle.hxx"
16 : #include "FontStyle.hxx"
17 : #include <locale.h>
18 : #include <math.h>
19 : #include <string>
20 : #include <map>
21 :
22 : #ifndef M_PI
23 : #define M_PI 3.14159265358979323846
24 : #endif
25 :
26 : // Workaround for the incapacity of draw to have multiple page
27 : // sizes in the same document. Once that limitation is lifted,
28 : // remove this
29 : #define MULTIPAGE_WORKAROUND 1
30 :
31 : namespace
32 : {
33 :
34 0 : static inline double getAngle(double bx, double by)
35 : {
36 0 : return fmod(2*M_PI + (by > 0.0 ? 1.0 : -1.0) * acos( bx / sqrt(bx * bx + by * by) ), 2*M_PI);
37 : }
38 :
39 0 : static void getEllipticalArcBBox(double x0, double y0,
40 : double rx, double ry, double phi, bool largeArc, bool sweep, double x, double y,
41 : double &xmin, double &ymin, double &xmax, double &ymax)
42 : {
43 0 : phi *= M_PI/180;
44 0 : if (rx < 0.0)
45 0 : rx *= -1.0;
46 0 : if (ry < 0.0)
47 0 : ry *= -1.0;
48 :
49 0 : if (rx == 0.0 || ry == 0.0)
50 : {
51 0 : xmin = (x0 < x ? x0 : x);
52 0 : xmax = (x0 > x ? x0 : x);
53 0 : ymin = (y0 < y ? y0 : y);
54 0 : ymax = (y0 > y ? y0 : y);
55 : return;
56 : }
57 :
58 : // F.6.5.1
59 0 : const double x1prime = cos(phi)*(x0 - x)/2 + sin(phi)*(y0 - y)/2;
60 0 : const double y1prime = -sin(phi)*(x0 - x)/2 + cos(phi)*(y0 - y)/2;
61 :
62 : // F.6.5.2
63 0 : double radicant = (rx*rx*ry*ry - rx*rx*y1prime*y1prime - ry*ry*x1prime*x1prime)/(rx*rx*y1prime*y1prime + ry*ry*x1prime*x1prime);
64 0 : double cxprime = 0.0;
65 0 : double cyprime = 0.0;
66 0 : if (radicant < 0.0)
67 : {
68 0 : double ratio = rx/ry;
69 0 : radicant = y1prime*y1prime + x1prime*x1prime/(ratio*ratio);
70 0 : if (radicant < 0.0)
71 : {
72 0 : xmin = (x0 < x ? x0 : x);
73 0 : xmax = (x0 > x ? x0 : x);
74 0 : ymin = (y0 < y ? y0 : y);
75 0 : ymax = (y0 > y ? y0 : y);
76 : return;
77 : }
78 0 : ry=sqrt(radicant);
79 0 : rx=ratio*ry;
80 : }
81 : else
82 : {
83 0 : double factor = (largeArc==sweep ? -1.0 : 1.0)*sqrt(radicant);
84 :
85 0 : cxprime = factor*rx*y1prime/ry;
86 0 : cyprime = -factor*ry*x1prime/rx;
87 : }
88 :
89 : // F.6.5.3
90 0 : double cx = cxprime*cos(phi) - cyprime*sin(phi) + (x0 + x)/2;
91 0 : double cy = cxprime*sin(phi) + cyprime*cos(phi) + (y0 + y)/2;
92 :
93 : // now compute bounding box of the whole ellipse
94 :
95 : // Parametric equation of an ellipse:
96 : // x(theta) = cx + rx*cos(theta)*cos(phi) - ry*sin(theta)*sin(phi)
97 : // y(theta) = cy + rx*cos(theta)*sin(phi) + ry*sin(theta)*cos(phi)
98 :
99 : // Compute local extrems
100 : // 0 = -rx*sin(theta)*cos(phi) - ry*cos(theta)*sin(phi)
101 : // 0 = -rx*sin(theta)*sin(phi) - ry*cos(theta)*cos(phi)
102 :
103 : // Local extrems for X:
104 : // theta = -atan(ry*tan(phi)/rx)
105 : // and
106 : // theta = M_PI -atan(ry*tan(phi)/rx)
107 :
108 : // Local extrems for Y:
109 : // theta = atan(ry/(tan(phi)*rx))
110 : // and
111 : // theta = M_PI + atan(ry/(tan(phi)*rx))
112 :
113 : double txmin, txmax, tymin, tymax;
114 :
115 : // First handle special cases
116 0 : if (phi == 0 || phi == M_PI)
117 : {
118 0 : xmin = cx - rx;
119 0 : txmin = getAngle(-rx, 0);
120 0 : xmax = cx + rx;
121 0 : txmax = getAngle(rx, 0);
122 0 : ymin = cy - ry;
123 0 : tymin = getAngle(0, -ry);
124 0 : ymax = cy + ry;
125 0 : tymax = getAngle(0, ry);
126 : }
127 0 : else if (phi == M_PI / 2.0 || phi == 3.0*M_PI/2.0)
128 : {
129 0 : xmin = cx - ry;
130 0 : txmin = getAngle(-ry, 0);
131 0 : xmax = cx + ry;
132 0 : txmax = getAngle(ry, 0);
133 0 : ymin = cy - rx;
134 0 : tymin = getAngle(0, -rx);
135 0 : ymax = cy + rx;
136 0 : tymax = getAngle(0, rx);
137 : }
138 : else
139 : {
140 0 : txmin = -atan(ry*tan(phi)/rx);
141 0 : txmax = M_PI - atan (ry*tan(phi)/rx);
142 0 : xmin = cx + rx*cos(txmin)*cos(phi) - ry*sin(txmin)*sin(phi);
143 0 : xmax = cx + rx*cos(txmax)*cos(phi) - ry*sin(txmax)*sin(phi);
144 0 : double tmpY = cy + rx*cos(txmin)*sin(phi) + ry*sin(txmin)*cos(phi);
145 0 : txmin = getAngle(xmin - cx, tmpY - cy);
146 0 : tmpY = cy + rx*cos(txmax)*sin(phi) + ry*sin(txmax)*cos(phi);
147 0 : txmax = getAngle(xmax - cx, tmpY - cy);
148 :
149 0 : tymin = atan(ry/(tan(phi)*rx));
150 0 : tymax = atan(ry/(tan(phi)*rx))+M_PI;
151 0 : ymin = cy + rx*cos(tymin)*sin(phi) + ry*sin(tymin)*cos(phi);
152 0 : ymax = cy + rx*cos(tymax)*sin(phi) + ry*sin(tymax)*cos(phi);
153 0 : double tmpX = cx + rx*cos(tymin)*cos(phi) - ry*sin(tymin)*sin(phi);
154 0 : tymin = getAngle(tmpX - cx, ymin - cy);
155 0 : tmpX = cx + rx*cos(tymax)*cos(phi) - ry*sin(tymax)*sin(phi);
156 0 : tymax = getAngle(tmpX - cx, ymax - cy);
157 : }
158 0 : if (xmin > xmax)
159 : {
160 0 : std::swap(xmin,xmax);
161 0 : std::swap(txmin,txmax);
162 : }
163 0 : if (ymin > ymax)
164 : {
165 0 : std::swap(ymin,ymax);
166 0 : std::swap(tymin,tymax);
167 : }
168 0 : double angle1 = getAngle(x0 - cx, y0 - cy);
169 0 : double angle2 = getAngle(x - cx, y - cy);
170 :
171 : // for sweep == 0 it is normal to have delta theta < 0
172 : // but we don't care about the rotation direction for bounding box
173 0 : if (!sweep)
174 0 : std::swap(angle1, angle2);
175 :
176 : // We cannot check directly for whether an angle is included in
177 : // an interval of angles that cross the 360/0 degree boundary
178 : // So here we will have to check for their absence in the complementary
179 : // angle interval
180 0 : bool otherArc = false;
181 0 : if (angle1 > angle2)
182 : {
183 0 : std::swap(angle1, angle2);
184 0 : otherArc = true;
185 : }
186 :
187 : // Check txmin
188 0 : if ((!otherArc && (angle1 > txmin || angle2 < txmin)) || (otherArc && !(angle1 > txmin || angle2 < txmin)))
189 0 : xmin = x0 < x ? x0 : x;
190 : // Check txmax
191 0 : if ((!otherArc && (angle1 > txmax || angle2 < txmax)) || (otherArc && !(angle1 > txmax || angle2 < txmax)))
192 0 : xmax = x0 > x ? x0 : x;
193 : // Check tymin
194 0 : if ((!otherArc && (angle1 > tymin || angle2 < tymin)) || (otherArc && !(angle1 > tymin || angle2 < tymin)))
195 0 : ymin = y0 < y ? y0 : y;
196 : // Check tymax
197 0 : if ((!otherArc && (angle1 > tymax || angle2 < tymax)) || (otherArc && !(angle1 > tymax || angle2 < tymax)))
198 0 : ymax = y0 > y ? y0 : y;
199 : }
200 :
201 0 : static inline double quadraticExtreme(double t, double a, double b, double c)
202 : {
203 0 : return (1.0-t)*(1.0-t)*a + 2.0*(1.0-t)*t*b + t*t*c;
204 : }
205 :
206 0 : static inline double quadraticDerivative(double a, double b, double c)
207 : {
208 0 : double denominator = a - 2.0*b + c;
209 0 : if (fabs(denominator) != 0.0)
210 0 : return (a - b)/denominator;
211 0 : return -1.0;
212 : }
213 :
214 0 : static void getQuadraticBezierBBox(double x0, double y0, double x1, double y1, double x, double y,
215 : double &xmin, double &ymin, double &xmax, double &ymax)
216 : {
217 0 : xmin = x0 < x ? x0 : x;
218 0 : xmax = x0 > x ? x0 : x;
219 0 : ymin = y0 < y ? y0 : y;
220 0 : ymax = y0 > y ? y0 : y;
221 :
222 0 : double t = quadraticDerivative(x0, x1, x);
223 0 : if(t>=0 && t<=1)
224 : {
225 0 : double tmpx = quadraticExtreme(t, x0, x1, x);
226 0 : xmin = tmpx < xmin ? tmpx : xmin;
227 0 : xmax = tmpx > xmax ? tmpx : xmax;
228 : }
229 :
230 0 : t = quadraticDerivative(y0, y1, y);
231 0 : if(t>=0 && t<=1)
232 : {
233 0 : double tmpy = quadraticExtreme(t, y0, y1, y);
234 0 : ymin = tmpy < ymin ? tmpy : ymin;
235 0 : ymax = tmpy > ymax ? tmpy : ymax;
236 : }
237 0 : }
238 :
239 0 : static inline double cubicBase(double t, double a, double b, double c, double d)
240 : {
241 0 : return (1.0-t)*(1.0-t)*(1.0-t)*a + 3.0*(1.0-t)*(1.0-t)*t*b + 3.0*(1.0-t)*t*t*c + t*t*t*d;
242 : }
243 :
244 0 : static void getCubicBezierBBox(double x0, double y0, double x1, double y1, double x2, double y2, double x, double y,
245 : double &xmin, double &ymin, double &xmax, double &ymax)
246 : {
247 0 : xmin = x0 < x ? x0 : x;
248 0 : xmax = x0 > x ? x0 : x;
249 0 : ymin = y0 < y ? y0 : y;
250 0 : ymax = y0 > y ? y0 : y;
251 :
252 0 : for (double t = 0.0; t <= 1.0; t+=0.01)
253 : {
254 0 : double tmpx = cubicBase(t, x0, x1, x2, x);
255 0 : xmin = tmpx < xmin ? tmpx : xmin;
256 0 : xmax = tmpx > xmax ? tmpx : xmax;
257 0 : double tmpy = cubicBase(t, y0, y1, y2, y);
258 0 : ymin = tmpy < ymin ? tmpy : ymin;
259 0 : ymax = tmpy > ymax ? tmpy : ymax;
260 : }
261 0 : }
262 :
263 :
264 0 : static WPXString doubleToString(const double value)
265 : {
266 0 : WPXString tempString;
267 0 : tempString.sprintf("%.4f", value);
268 : #ifndef ANDROID
269 0 : std::string decimalPoint(localeconv()->decimal_point);
270 : #else
271 : std::string decimalPoint(".");
272 : #endif
273 0 : if (decimalPoint.empty() || (decimalPoint == "."))
274 0 : return tempString;
275 0 : std::string stringValue(tempString.cstr());
276 0 : if (!stringValue.empty())
277 : {
278 : std::string::size_type pos;
279 0 : while ((pos = stringValue.find(decimalPoint)) != std::string::npos)
280 0 : stringValue.replace(pos,decimalPoint.size(),".");
281 : }
282 0 : return WPXString(stringValue.c_str());
283 : }
284 :
285 : } // anonymous namespace
286 :
287 : class OdgGeneratorPrivate
288 : {
289 : public:
290 : OdgGeneratorPrivate(OdfDocumentHandler *pHandler, const OdfStreamType streamType);
291 : ~OdgGeneratorPrivate();
292 : void _writeGraphicsStyle();
293 : void _drawPolySomething(const ::WPXPropertyListVector &vertices, bool isClosed);
294 : void _drawPath(const WPXPropertyListVector &path);
295 : // body elements
296 : std::vector <DocumentElement *> mBodyElements;
297 :
298 : // graphics styles
299 : std::vector<DocumentElement *> mGraphicsStrokeDashStyles;
300 : std::vector<DocumentElement *> mGraphicsGradientStyles;
301 : std::vector<DocumentElement *> mGraphicsBitmapStyles;
302 : std::vector<DocumentElement *> mGraphicsMarkerStyles;
303 : std::vector<DocumentElement *> mGraphicsAutomaticStyles;
304 :
305 : // page styles
306 : std::vector<DocumentElement *> mPageAutomaticStyles;
307 : std::vector<DocumentElement *> mPageMasterStyles;
308 :
309 : // paragraph styles
310 : ParagraphStyleManager mParagraphManager;
311 :
312 : // span styles
313 : SpanStyleManager mSpanManager;
314 :
315 : // font styles
316 : FontStyleManager mFontManager;
317 :
318 : OdfDocumentHandler *mpHandler;
319 :
320 : ::WPXPropertyList mxStyle;
321 : ::WPXPropertyListVector mxGradient;
322 : ::WPXPropertyListVector mxMarker;
323 : int miGradientIndex;
324 : int miBitmapIndex;
325 : int miStartMarkerIndex;
326 : int miEndMarkerIndex;
327 : int miDashIndex;
328 : int miGraphicsStyleIndex;
329 : int miPageIndex;
330 : double mfWidth, mfMaxWidth;
331 : double mfHeight, mfMaxHeight;
332 :
333 : const OdfStreamType mxStreamType;
334 :
335 : bool mbIsTextBox;
336 : bool mbIsTextLine;
337 : bool mbIsTextOnPath;
338 : };
339 :
340 0 : OdgGeneratorPrivate::OdgGeneratorPrivate(OdfDocumentHandler *pHandler, const OdfStreamType streamType):
341 : mBodyElements(),
342 : mGraphicsStrokeDashStyles(),
343 : mGraphicsGradientStyles(),
344 : mGraphicsBitmapStyles(),
345 : mGraphicsAutomaticStyles(),
346 : mPageAutomaticStyles(),
347 : mPageMasterStyles(),
348 : mParagraphManager(),
349 : mSpanManager(),
350 : mFontManager(),
351 : mpHandler(pHandler),
352 : mxStyle(), mxGradient(),
353 : mxMarker(),
354 : miGradientIndex(1),
355 : miBitmapIndex(1),
356 : miStartMarkerIndex(1),
357 : miEndMarkerIndex(1),
358 : miDashIndex(1),
359 : miGraphicsStyleIndex(1),
360 : miPageIndex(1),
361 : mfWidth(0.0),
362 : mfMaxWidth(0.0),
363 : mfHeight(0.0),
364 : mfMaxHeight(0.0),
365 : mxStreamType(streamType),
366 : mbIsTextBox(false),
367 : mbIsTextLine(false),
368 0 : mbIsTextOnPath(false)
369 : {
370 0 : }
371 :
372 0 : OdgGeneratorPrivate::~OdgGeneratorPrivate()
373 : {
374 :
375 0 : for (std::vector<DocumentElement *>::iterator iterBody = mBodyElements.begin(); iterBody != mBodyElements.end(); ++iterBody)
376 : {
377 0 : delete (*iterBody);
378 0 : (*iterBody) = 0;
379 : }
380 :
381 0 : for (std::vector<DocumentElement *>::iterator iterGraphicsAutomaticStyles = mGraphicsAutomaticStyles.begin();
382 0 : iterGraphicsAutomaticStyles != mGraphicsAutomaticStyles.end(); ++iterGraphicsAutomaticStyles)
383 : {
384 0 : delete((*iterGraphicsAutomaticStyles));
385 : }
386 :
387 0 : for (std::vector<DocumentElement *>::iterator iterGraphicsStrokeDashStyles = mGraphicsStrokeDashStyles.begin();
388 0 : iterGraphicsStrokeDashStyles != mGraphicsStrokeDashStyles.end(); ++iterGraphicsStrokeDashStyles)
389 : {
390 0 : delete((*iterGraphicsStrokeDashStyles));
391 : }
392 :
393 0 : for (std::vector<DocumentElement *>::iterator iterGraphicsGradientStyles = mGraphicsGradientStyles.begin();
394 0 : iterGraphicsGradientStyles != mGraphicsGradientStyles.end(); ++iterGraphicsGradientStyles)
395 : {
396 0 : delete((*iterGraphicsGradientStyles));
397 : }
398 :
399 0 : for (std::vector<DocumentElement *>::iterator iterGraphicsBitmapStyles = mGraphicsBitmapStyles.begin();
400 0 : iterGraphicsBitmapStyles != mGraphicsBitmapStyles.end(); ++iterGraphicsBitmapStyles)
401 : {
402 0 : delete((*iterGraphicsBitmapStyles));
403 : }
404 :
405 0 : for (std::vector<DocumentElement *>::iterator iterGraphicsMarkerStyles = mGraphicsMarkerStyles.begin();
406 0 : iterGraphicsMarkerStyles != mGraphicsMarkerStyles.end(); ++iterGraphicsMarkerStyles)
407 : {
408 0 : delete((*iterGraphicsMarkerStyles));
409 : }
410 :
411 0 : for (std::vector<DocumentElement *>::iterator iterPageAutomaticStyles = mPageAutomaticStyles.begin();
412 0 : iterPageAutomaticStyles != mPageAutomaticStyles.end(); ++iterPageAutomaticStyles)
413 : {
414 0 : delete((*iterPageAutomaticStyles));
415 : }
416 :
417 0 : for (std::vector<DocumentElement *>::iterator iterPageMasterStyles = mPageMasterStyles.begin();
418 0 : iterPageMasterStyles != mPageMasterStyles.end(); ++iterPageMasterStyles)
419 : {
420 0 : delete((*iterPageMasterStyles));
421 : }
422 :
423 0 : mParagraphManager.clean();
424 0 : mSpanManager.clean();
425 0 : mFontManager.clean();
426 0 : }
427 :
428 :
429 0 : OdgGenerator::OdgGenerator(OdfDocumentHandler *pHandler, const OdfStreamType streamType):
430 0 : mpImpl(new OdgGeneratorPrivate(pHandler, streamType))
431 : {
432 0 : mpImpl->mpHandler->startDocument();
433 : TagOpenElement tmpOfficeDocumentContent(
434 : (mpImpl->mxStreamType == ODF_FLAT_XML) ? "office:document" : (
435 : (mpImpl->mxStreamType == ODF_CONTENT_XML) ? "office:document-content" : (
436 : (mpImpl->mxStreamType == ODF_STYLES_XML) ? "office:document-styles" : (
437 : (mpImpl->mxStreamType == ODF_SETTINGS_XML) ? "office:document-settings" : (
438 0 : (mpImpl->mxStreamType == ODF_META_XML) ? "office:document-meta" : "office:document" )))));
439 0 : tmpOfficeDocumentContent.addAttribute("xmlns:office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0");
440 0 : tmpOfficeDocumentContent.addAttribute("xmlns:style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0");
441 0 : tmpOfficeDocumentContent.addAttribute("xmlns:text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0");
442 0 : tmpOfficeDocumentContent.addAttribute("xmlns:draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0");
443 0 : tmpOfficeDocumentContent.addAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
444 0 : tmpOfficeDocumentContent.addAttribute("xmlns:svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0");
445 0 : tmpOfficeDocumentContent.addAttribute("xmlns:fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0");
446 0 : tmpOfficeDocumentContent.addAttribute("xmlns:config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0");
447 0 : tmpOfficeDocumentContent.addAttribute("xmlns:ooo", "http://openoffice.org/2004/office");
448 0 : tmpOfficeDocumentContent.addAttribute("office:version", "1.0");
449 0 : if (mpImpl->mxStreamType == ODF_FLAT_XML)
450 0 : tmpOfficeDocumentContent.addAttribute("office:mimetype", "application/vnd.oasis.opendocument.graphics");
451 0 : tmpOfficeDocumentContent.write(mpImpl->mpHandler);
452 0 : }
453 :
454 0 : OdgGenerator::~OdgGenerator()
455 : {
456 0 : if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_SETTINGS_XML))
457 : {
458 0 : TagOpenElement("office:settings").write(mpImpl->mpHandler);
459 :
460 0 : TagOpenElement configItemSetOpenElement("config:config-item-set");
461 0 : configItemSetOpenElement.addAttribute("config:name", "ooo:view-settings");
462 0 : configItemSetOpenElement.write(mpImpl->mpHandler);
463 :
464 0 : TagOpenElement configItemOpenElement("config:config-item");
465 :
466 0 : configItemOpenElement.addAttribute("config:name", "VisibleAreaTop");
467 0 : configItemOpenElement.addAttribute("config:type", "int");
468 0 : configItemOpenElement.write(mpImpl->mpHandler);
469 0 : mpImpl->mpHandler->characters("0");
470 0 : mpImpl->mpHandler->endElement("config:config-item");
471 :
472 0 : configItemOpenElement.addAttribute("config:name", "VisibleAreaLeft");
473 0 : configItemOpenElement.addAttribute("config:type", "int");
474 0 : configItemOpenElement.write(mpImpl->mpHandler);
475 0 : mpImpl->mpHandler->characters("0");
476 0 : mpImpl->mpHandler->endElement("config:config-item");
477 :
478 0 : configItemOpenElement.addAttribute("config:name", "VisibleAreaWidth");
479 0 : configItemOpenElement.addAttribute("config:type", "int");
480 0 : configItemOpenElement.write(mpImpl->mpHandler);
481 0 : WPXString sWidth;
482 0 : sWidth.sprintf("%li", (unsigned long)(2540 * mpImpl->mfMaxWidth));
483 0 : mpImpl->mpHandler->characters(sWidth);
484 0 : mpImpl->mpHandler->endElement("config:config-item");
485 :
486 0 : configItemOpenElement.addAttribute("config:name", "VisibleAreaHeight");
487 0 : configItemOpenElement.addAttribute("config:type", "int");
488 0 : configItemOpenElement.write(mpImpl->mpHandler);
489 0 : WPXString sHeight;
490 0 : sHeight.sprintf("%li", (unsigned long)(2540 * mpImpl->mfMaxHeight));
491 0 : mpImpl->mpHandler->characters(sHeight);
492 0 : mpImpl->mpHandler->endElement("config:config-item");
493 :
494 0 : mpImpl->mpHandler->endElement("config:config-item-set");
495 :
496 0 : mpImpl->mpHandler->endElement("office:settings");
497 : }
498 :
499 :
500 0 : if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_STYLES_XML))
501 : {
502 0 : TagOpenElement("office:styles").write(mpImpl->mpHandler);
503 :
504 0 : for (std::vector<DocumentElement *>::const_iterator iterGraphicsStrokeDashStyles = mpImpl->mGraphicsStrokeDashStyles.begin();
505 0 : iterGraphicsStrokeDashStyles != mpImpl->mGraphicsStrokeDashStyles.end(); ++iterGraphicsStrokeDashStyles)
506 : {
507 0 : (*iterGraphicsStrokeDashStyles)->write(mpImpl->mpHandler);
508 : }
509 :
510 0 : for (std::vector<DocumentElement *>::const_iterator iterGraphicsGradientStyles = mpImpl->mGraphicsGradientStyles.begin();
511 0 : iterGraphicsGradientStyles != mpImpl->mGraphicsGradientStyles.end(); ++iterGraphicsGradientStyles)
512 : {
513 0 : (*iterGraphicsGradientStyles)->write(mpImpl->mpHandler);
514 : }
515 :
516 0 : for (std::vector<DocumentElement *>::const_iterator iterGraphicsBitmapStyles = mpImpl->mGraphicsBitmapStyles.begin();
517 0 : iterGraphicsBitmapStyles != mpImpl->mGraphicsBitmapStyles.end(); ++iterGraphicsBitmapStyles)
518 : {
519 0 : (*iterGraphicsBitmapStyles)->write(mpImpl->mpHandler);
520 : }
521 :
522 0 : for (std::vector<DocumentElement *>::const_iterator iterGraphicsMarkerStyles = mpImpl->mGraphicsMarkerStyles.begin();
523 0 : iterGraphicsMarkerStyles != mpImpl->mGraphicsMarkerStyles.end(); ++iterGraphicsMarkerStyles)
524 : {
525 0 : (*iterGraphicsMarkerStyles)->write(mpImpl->mpHandler);
526 : }
527 0 : mpImpl->mpHandler->endElement("office:styles");
528 : }
529 :
530 :
531 0 : if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_CONTENT_XML) || (mpImpl->mxStreamType == ODF_STYLES_XML))
532 : {
533 0 : mpImpl->mFontManager.writeFontsDeclaration(mpImpl->mpHandler);
534 :
535 0 : TagOpenElement("office:automatic-styles").write(mpImpl->mpHandler);
536 : }
537 :
538 0 : if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_CONTENT_XML))
539 : {
540 : // writing out the graphics automatic styles
541 0 : for (std::vector<DocumentElement *>::iterator iterGraphicsAutomaticStyles = mpImpl->mGraphicsAutomaticStyles.begin();
542 0 : iterGraphicsAutomaticStyles != mpImpl->mGraphicsAutomaticStyles.end(); ++iterGraphicsAutomaticStyles)
543 : {
544 0 : (*iterGraphicsAutomaticStyles)->write(mpImpl->mpHandler);
545 : }
546 0 : mpImpl->mParagraphManager.write(mpImpl->mpHandler);
547 0 : mpImpl->mSpanManager.write(mpImpl->mpHandler);
548 : }
549 : #ifdef MULTIPAGE_WORKAROUND
550 0 : if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_STYLES_XML))
551 : {
552 0 : TagOpenElement tmpStylePageLayoutOpenElement("style:page-layout");
553 0 : tmpStylePageLayoutOpenElement.addAttribute("style:name", "PM0");
554 0 : tmpStylePageLayoutOpenElement.write(mpImpl->mpHandler);
555 :
556 0 : TagOpenElement tmpStylePageLayoutPropertiesOpenElement("style:page-layout-properties");
557 0 : tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-top", "0in");
558 0 : tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-bottom", "0in");
559 0 : tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-left", "0in");
560 0 : tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-right", "0in");
561 0 : WPXString sValue;
562 0 : sValue = doubleToString(mpImpl->mfMaxWidth);
563 0 : sValue.append("in");
564 0 : tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:page-width", sValue);
565 0 : sValue = doubleToString(mpImpl->mfMaxHeight);
566 0 : sValue.append("in");
567 0 : tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:page-height", sValue);
568 0 : tmpStylePageLayoutPropertiesOpenElement.addAttribute("style:print-orientation", "portrait");
569 0 : tmpStylePageLayoutPropertiesOpenElement.write(mpImpl->mpHandler);
570 :
571 0 : mpImpl->mpHandler->endElement("style:page-layout-properties");
572 :
573 0 : mpImpl->mpHandler->endElement("style:page-layout");
574 :
575 0 : TagOpenElement tmpStyleStyleOpenElement("style:style");
576 0 : tmpStyleStyleOpenElement.addAttribute("style:name", "dp1");
577 0 : tmpStyleStyleOpenElement.addAttribute("style:family", "drawing-page");
578 0 : tmpStyleStyleOpenElement.write(mpImpl->mpHandler);
579 :
580 0 : TagOpenElement tmpStyleDrawingPagePropertiesOpenElement("style:drawing-page-properties");
581 : // tmpStyleDrawingPagePropertiesOpenElement.addAttribute("draw:background-size", "border");
582 0 : tmpStyleDrawingPagePropertiesOpenElement.addAttribute("draw:fill", "none");
583 0 : tmpStyleDrawingPagePropertiesOpenElement.write(mpImpl->mpHandler);
584 :
585 0 : mpImpl->mpHandler->endElement("style:drawing-page-properties");
586 :
587 0 : mpImpl->mpHandler->endElement("style:style");
588 : }
589 : #else
590 : if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_STYLES_XML))
591 : {
592 : // writing out the page automatic styles
593 : for (std::vector<DocumentElement *>::iterator iterPageAutomaticStyles = mpImpl->mPageAutomaticStyles.begin();
594 : iterPageAutomaticStyles != mpImpl->mPageAutomaticStyles.end(); ++iterPageAutomaticStyles)
595 : {
596 : (*iterPageAutomaticStyles)->write(mpImpl->mpHandler);
597 : }
598 : }
599 : #endif
600 0 : if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_CONTENT_XML) || (mpImpl->mxStreamType == ODF_STYLES_XML))
601 : {
602 0 : mpImpl->mpHandler->endElement("office:automatic-styles");
603 : }
604 :
605 0 : if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_STYLES_XML))
606 : {
607 0 : TagOpenElement("office:master-styles").write(mpImpl->mpHandler);
608 :
609 0 : for (std::vector<DocumentElement *>::const_iterator pageMasterIter = mpImpl->mPageMasterStyles.begin();
610 0 : pageMasterIter != mpImpl->mPageMasterStyles.end(); ++pageMasterIter)
611 : {
612 0 : (*pageMasterIter)->write(mpImpl->mpHandler);
613 : }
614 0 : mpImpl->mpHandler->endElement("office:master-styles");
615 : }
616 :
617 0 : if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_CONTENT_XML))
618 : {
619 0 : TagOpenElement("office:body").write(mpImpl->mpHandler);
620 :
621 0 : TagOpenElement("office:drawing").write(mpImpl->mpHandler);
622 :
623 0 : for (std::vector<DocumentElement *>::const_iterator bodyIter = mpImpl->mBodyElements.begin();
624 0 : bodyIter != mpImpl->mBodyElements.end(); ++bodyIter)
625 : {
626 0 : (*bodyIter)->write(mpImpl->mpHandler);
627 : }
628 :
629 0 : mpImpl->mpHandler->endElement("office:drawing");
630 0 : mpImpl->mpHandler->endElement("office:body");
631 : }
632 :
633 : mpImpl->mpHandler->endElement(
634 : (mpImpl->mxStreamType == ODF_FLAT_XML) ? "office:document" : (
635 : (mpImpl->mxStreamType == ODF_CONTENT_XML) ? "office:document-content" : (
636 : (mpImpl->mxStreamType == ODF_STYLES_XML) ? "office:document-styles" : (
637 : (mpImpl->mxStreamType == ODF_SETTINGS_XML) ? "office:document-settings" : (
638 0 : (mpImpl->mxStreamType == ODF_META_XML) ? "office:document-meta" : "office:document" )))));
639 :
640 0 : mpImpl->mpHandler->endDocument();
641 :
642 0 : if (mpImpl)
643 0 : delete mpImpl;
644 0 : }
645 :
646 0 : void OdgGenerator::startGraphics(const ::WPXPropertyList &propList)
647 : {
648 0 : if (propList["svg:width"])
649 : {
650 0 : mpImpl->mfWidth = propList["svg:width"]->getDouble();
651 0 : mpImpl->mfMaxWidth = mpImpl->mfMaxWidth < mpImpl->mfWidth ? mpImpl->mfWidth : mpImpl->mfMaxWidth;
652 : }
653 :
654 0 : if (propList["svg:height"])
655 : {
656 0 : mpImpl->mfHeight = propList["svg:height"]->getDouble();
657 0 : mpImpl->mfMaxHeight = mpImpl->mfMaxHeight < mpImpl->mfHeight ? mpImpl->mfHeight : mpImpl->mfMaxHeight;
658 : }
659 :
660 0 : TagOpenElement *pStyleMasterPageOpenElement = new TagOpenElement("style:master-page");
661 :
662 0 : TagOpenElement *pDrawPageOpenElement = new TagOpenElement("draw:page");
663 :
664 0 : TagOpenElement *pStylePageLayoutOpenElement = new TagOpenElement("style:page-layout");
665 :
666 0 : WPXString sValue;
667 0 : sValue.sprintf("page%i", mpImpl->miPageIndex);
668 0 : pDrawPageOpenElement->addAttribute("draw:name", sValue);
669 : #ifdef MULTIPAGE_WORKAROUND
670 0 : pStyleMasterPageOpenElement->addAttribute("style:page-layout-name", "PM0");
671 0 : pStylePageLayoutOpenElement->addAttribute("style:page-layout-name", "PM0");
672 : #else
673 : sValue.sprintf("PM%i", mpImpl->miPageIndex);
674 : pStyleMasterPageOpenElement->addAttribute("style:page-layout-name", sValue);
675 : pStylePageLayoutOpenElement->addAttribute("style:name", sValue);
676 : #endif
677 :
678 0 : mpImpl->mPageAutomaticStyles.push_back(pStylePageLayoutOpenElement);
679 :
680 0 : TagOpenElement *pStylePageLayoutPropertiesOpenElement = new TagOpenElement("style:page-layout-properties");
681 0 : pStylePageLayoutPropertiesOpenElement->addAttribute("fo:margin-top", "0in");
682 0 : pStylePageLayoutPropertiesOpenElement->addAttribute("fo:margin-bottom", "0in");
683 0 : pStylePageLayoutPropertiesOpenElement->addAttribute("fo:margin-left", "0in");
684 0 : pStylePageLayoutPropertiesOpenElement->addAttribute("fo:margin-right", "0in");
685 0 : sValue.sprintf("%s%s", doubleToString(mpImpl->mfWidth).cstr(), "in");
686 0 : pStylePageLayoutPropertiesOpenElement->addAttribute("fo:page-width", sValue);
687 0 : sValue.sprintf("%s%s", doubleToString(mpImpl->mfHeight).cstr(), "in");
688 0 : pStylePageLayoutPropertiesOpenElement->addAttribute("fo:page-height", sValue);
689 0 : pStylePageLayoutPropertiesOpenElement->addAttribute("style:print-orientation", "portrait");
690 0 : mpImpl->mPageAutomaticStyles.push_back(pStylePageLayoutPropertiesOpenElement);
691 :
692 0 : mpImpl->mPageAutomaticStyles.push_back(new TagCloseElement("style:page-layout-properties"));
693 :
694 0 : mpImpl->mPageAutomaticStyles.push_back(new TagCloseElement("style:page-layout"));
695 :
696 : #ifdef MULTIPAGE_WORKAROUND
697 0 : pDrawPageOpenElement->addAttribute("draw:style-name", "dp1");
698 0 : pStyleMasterPageOpenElement->addAttribute("draw:style-name", "dp1");
699 : #else
700 : sValue.sprintf("dp%i", mpImpl->miPageIndex);
701 : pDrawPageOpenElement->addAttribute("draw:style-name", sValue);
702 : pStyleMasterPageOpenElement->addAttribute("draw:style-name", sValue);
703 : #endif
704 :
705 0 : TagOpenElement *pStyleStyleOpenElement = new TagOpenElement("style:style");
706 0 : pStyleStyleOpenElement->addAttribute("style:name", sValue);
707 0 : pStyleStyleOpenElement->addAttribute("style:family", "drawing-page");
708 0 : mpImpl->mPageAutomaticStyles.push_back(pStyleStyleOpenElement);
709 :
710 : #ifdef MULTIPAGE_WORKAROUND
711 0 : pDrawPageOpenElement->addAttribute("draw:master-page-name", "Default");
712 0 : pStyleMasterPageOpenElement->addAttribute("style:name", "Default");
713 : #else
714 : sValue.sprintf("Page%i", mpImpl->miPageIndex);
715 : pDrawPageOpenElement->addAttribute("draw:master-page-name", sValue);
716 : pStyleMasterPageOpenElement->addAttribute("style:name", sValue);
717 : #endif
718 :
719 0 : mpImpl->mBodyElements.push_back(pDrawPageOpenElement);
720 :
721 0 : mpImpl->mPageMasterStyles.push_back(pStyleMasterPageOpenElement);
722 0 : mpImpl->mPageMasterStyles.push_back(new TagCloseElement("style:master-page"));
723 :
724 :
725 0 : TagOpenElement *pStyleDrawingPagePropertiesOpenElement = new TagOpenElement("style:drawing-page-properties");
726 0 : pStyleDrawingPagePropertiesOpenElement->addAttribute("draw:fill", "none");
727 0 : mpImpl->mPageAutomaticStyles.push_back(pStyleDrawingPagePropertiesOpenElement);
728 :
729 0 : mpImpl->mPageAutomaticStyles.push_back(new TagCloseElement("style:drawing-page-properties"));
730 :
731 0 : mpImpl->mPageAutomaticStyles.push_back(new TagCloseElement("style:style"));
732 0 : }
733 :
734 0 : void OdgGenerator::endGraphics()
735 : {
736 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("draw:page"));
737 0 : mpImpl->miPageIndex++;
738 0 : }
739 :
740 0 : void OdgGenerator::setStyle(const ::WPXPropertyList &propList, const ::WPXPropertyListVector &gradient)
741 : {
742 0 : mpImpl->mxStyle.clear();
743 0 : mpImpl->mxStyle = propList;
744 0 : mpImpl->mxGradient = gradient;
745 0 : }
746 :
747 0 : void OdgGenerator::startLayer(const ::WPXPropertyList & /* propList */)
748 : {
749 0 : mpImpl->mBodyElements.push_back(new TagOpenElement("draw:g"));
750 0 : }
751 :
752 0 : void OdgGenerator::endLayer()
753 : {
754 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("draw:g"));
755 0 : }
756 :
757 0 : void OdgGenerator::drawRectangle(const ::WPXPropertyList &propList)
758 : {
759 0 : mpImpl->_writeGraphicsStyle();
760 0 : TagOpenElement *pDrawRectElement = new TagOpenElement("draw:rect");
761 0 : WPXString sValue;
762 0 : sValue.sprintf("gr%i", mpImpl->miGraphicsStyleIndex-1);
763 0 : pDrawRectElement->addAttribute("draw:style-name", sValue);
764 0 : pDrawRectElement->addAttribute("svg:x", propList["svg:x"]->getStr());
765 0 : pDrawRectElement->addAttribute("svg:y", propList["svg:y"]->getStr());
766 0 : pDrawRectElement->addAttribute("svg:width", propList["svg:width"]->getStr());
767 0 : pDrawRectElement->addAttribute("svg:height", propList["svg:height"]->getStr());
768 : // FIXME: what to do when rx != ry ?
769 0 : if (propList["svg:rx"])
770 0 : pDrawRectElement->addAttribute("draw:corner-radius", propList["svg:rx"]->getStr());
771 : else
772 0 : pDrawRectElement->addAttribute("draw:corner-radius", "0.0000in");
773 0 : mpImpl->mBodyElements.push_back(pDrawRectElement);
774 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("draw:rect"));
775 0 : }
776 :
777 0 : void OdgGenerator::drawEllipse(const ::WPXPropertyList &propList)
778 : {
779 0 : mpImpl->_writeGraphicsStyle();
780 0 : TagOpenElement *pDrawEllipseElement = new TagOpenElement("draw:ellipse");
781 0 : WPXString sValue;
782 0 : sValue.sprintf("gr%i", mpImpl->miGraphicsStyleIndex-1);
783 0 : pDrawEllipseElement->addAttribute("draw:style-name", sValue);
784 0 : sValue = doubleToString(2 * propList["svg:rx"]->getDouble());
785 0 : sValue.append("in");
786 0 : pDrawEllipseElement->addAttribute("svg:width", sValue);
787 0 : sValue = doubleToString(2 * propList["svg:ry"]->getDouble());
788 0 : sValue.append("in");
789 0 : pDrawEllipseElement->addAttribute("svg:height", sValue);
790 0 : if (propList["libwpg:rotate"] && propList["libwpg:rotate"]->getDouble() != 0.0)
791 : {
792 0 : double rotation = propList["libwpg:rotate"]->getDouble();
793 0 : while(rotation < -180)
794 0 : rotation += 360;
795 0 : while(rotation > 180)
796 0 : rotation -= 360;
797 0 : double radrotation = rotation*M_PI/180.0;
798 0 : double deltax = sqrt(pow(propList["svg:rx"]->getDouble(), 2.0)
799 0 : + pow(propList["svg:ry"]->getDouble(), 2.0))*cos(atan(propList["svg:ry"]->getDouble()/propList["svg:rx"]->getDouble())
800 0 : - radrotation ) - propList["svg:rx"]->getDouble();
801 0 : double deltay = sqrt(pow(propList["svg:rx"]->getDouble(), 2.0)
802 0 : + pow(propList["svg:ry"]->getDouble(), 2.0))*sin(atan(propList["svg:ry"]->getDouble()/propList["svg:rx"]->getDouble())
803 0 : - radrotation ) - propList["svg:ry"]->getDouble();
804 0 : sValue = "rotate(";
805 0 : sValue.append(doubleToString(radrotation));
806 0 : sValue.append(") ");
807 0 : sValue.append("translate(");
808 0 : sValue.append(doubleToString(propList["svg:cx"]->getDouble() - propList["svg:rx"]->getDouble() - deltax));
809 0 : sValue.append("in, ");
810 0 : sValue.append(doubleToString(propList["svg:cy"]->getDouble() - propList["svg:ry"]->getDouble() - deltay));
811 0 : sValue.append("in)");
812 0 : pDrawEllipseElement->addAttribute("draw:transform", sValue);
813 : }
814 : else
815 : {
816 0 : sValue = doubleToString(propList["svg:cx"]->getDouble()-propList["svg:rx"]->getDouble());
817 0 : sValue.append("in");
818 0 : pDrawEllipseElement->addAttribute("svg:x", sValue);
819 0 : sValue = doubleToString(propList["svg:cy"]->getDouble()-propList["svg:ry"]->getDouble());
820 0 : sValue.append("in");
821 0 : pDrawEllipseElement->addAttribute("svg:y", sValue);
822 : }
823 0 : mpImpl->mBodyElements.push_back(pDrawEllipseElement);
824 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("draw:ellipse"));
825 0 : }
826 :
827 0 : void OdgGenerator::drawPolyline(const ::WPXPropertyListVector &vertices)
828 : {
829 0 : mpImpl->_drawPolySomething(vertices, false);
830 0 : }
831 :
832 0 : void OdgGenerator::drawPolygon(const ::WPXPropertyListVector &vertices)
833 : {
834 0 : mpImpl->_drawPolySomething(vertices, true);
835 0 : }
836 :
837 0 : void OdgGeneratorPrivate::_drawPolySomething(const ::WPXPropertyListVector &vertices, bool isClosed)
838 : {
839 0 : if(vertices.count() < 2)
840 0 : return;
841 :
842 0 : if(vertices.count() == 2)
843 : {
844 0 : _writeGraphicsStyle();
845 0 : TagOpenElement *pDrawLineElement = new TagOpenElement("draw:line");
846 0 : WPXString sValue;
847 0 : sValue.sprintf("gr%i", miGraphicsStyleIndex-1);
848 0 : pDrawLineElement->addAttribute("draw:style-name", sValue);
849 0 : pDrawLineElement->addAttribute("draw:layer", "layout");
850 0 : pDrawLineElement->addAttribute("svg:x1", vertices[0]["svg:x"]->getStr());
851 0 : pDrawLineElement->addAttribute("svg:y1", vertices[0]["svg:y"]->getStr());
852 0 : pDrawLineElement->addAttribute("svg:x2", vertices[1]["svg:x"]->getStr());
853 0 : pDrawLineElement->addAttribute("svg:y2", vertices[1]["svg:y"]->getStr());
854 0 : mBodyElements.push_back(pDrawLineElement);
855 0 : mBodyElements.push_back(new TagCloseElement("draw:line"));
856 : }
857 : else
858 : {
859 0 : ::WPXPropertyListVector path;
860 0 : ::WPXPropertyList element;
861 :
862 0 : for (unsigned long ii = 0; ii < vertices.count(); ++ii)
863 : {
864 0 : element = vertices[ii];
865 0 : if (ii == 0)
866 0 : element.insert("libwpg:path-action", "M");
867 : else
868 0 : element.insert("libwpg:path-action", "L");
869 0 : path.append(element);
870 0 : element.clear();
871 : }
872 0 : if (isClosed)
873 : {
874 0 : element.insert("libwpg:path-action", "Z");
875 0 : path.append(element);
876 : }
877 0 : _drawPath(path);
878 : }
879 : }
880 :
881 0 : void OdgGeneratorPrivate::_drawPath(const WPXPropertyListVector &path)
882 : {
883 0 : if(path.count() == 0)
884 : return;
885 : // This must be a mistake and we do not want to crash lower
886 0 : if(path[0]["libwpg:path-action"]->getStr() == "Z")
887 : return;
888 :
889 : // try to find the bounding box
890 : // this is simple convex hull technique, the bounding box might not be
891 : // accurate but that should be enough for this purpose
892 0 : bool isFirstPoint = true;
893 :
894 0 : double px = 0.0, py = 0.0, qx = 0.0, qy = 0.0;
895 0 : double lastX = 0.0;
896 0 : double lastY = 0.0;
897 :
898 0 : for(unsigned k = 0; k < path.count(); ++k)
899 : {
900 0 : if (!path[k]["svg:x"] || !path[k]["svg:y"])
901 0 : continue;
902 0 : if (isFirstPoint)
903 : {
904 0 : px = path[k]["svg:x"]->getDouble();
905 0 : py = path[k]["svg:y"]->getDouble();
906 0 : qx = px;
907 0 : qy = py;
908 0 : lastX = px;
909 0 : lastY = py;
910 0 : isFirstPoint = false;
911 : }
912 0 : px = (px > path[k]["svg:x"]->getDouble()) ? path[k]["svg:x"]->getDouble() : px;
913 0 : py = (py > path[k]["svg:y"]->getDouble()) ? path[k]["svg:y"]->getDouble() : py;
914 0 : qx = (qx < path[k]["svg:x"]->getDouble()) ? path[k]["svg:x"]->getDouble() : qx;
915 0 : qy = (qy < path[k]["svg:y"]->getDouble()) ? path[k]["svg:y"]->getDouble() : qy;
916 :
917 : double xmin, xmax, ymin, ymax;
918 :
919 0 : if(path[k]["libwpg:path-action"]->getStr() == "C")
920 : {
921 0 : getCubicBezierBBox(lastX, lastY, path[k]["svg:x1"]->getDouble(), path[k]["svg:y1"]->getDouble(),
922 0 : path[k]["svg:x2"]->getDouble(), path[k]["svg:y2"]->getDouble(),
923 0 : path[k]["svg:x"]->getDouble(), path[k]["svg:y"]->getDouble(), xmin, ymin, xmax, ymax);
924 :
925 0 : px = (px > xmin ? xmin : px);
926 0 : py = (py > ymin ? ymin : py);
927 0 : qx = (qx < xmax ? xmax : qx);
928 0 : qy = (qy < ymax ? ymax : qy);
929 : }
930 0 : if(path[k]["libwpg:path-action"]->getStr() == "Q")
931 : {
932 0 : getQuadraticBezierBBox(lastX, lastY, path[k]["svg:x1"]->getDouble(), path[k]["svg:y1"]->getDouble(),
933 0 : path[k]["svg:x"]->getDouble(), path[k]["svg:y"]->getDouble(), xmin, ymin, xmax, ymax);
934 :
935 0 : px = (px > xmin ? xmin : px);
936 0 : py = (py > ymin ? ymin : py);
937 0 : qx = (qx < xmax ? xmax : qx);
938 0 : qy = (qy < ymax ? ymax : qy);
939 : }
940 0 : if(path[k]["libwpg:path-action"]->getStr() == "A")
941 : {
942 0 : getEllipticalArcBBox(lastX, lastY, path[k]["svg:rx"]->getDouble(), path[k]["svg:ry"]->getDouble(),
943 0 : path[k]["libwpg:rotate"] ? path[k]["libwpg:rotate"]->getDouble() : 0.0,
944 0 : path[k]["libwpg:large-arc"] ? path[k]["libwpg:large-arc"]->getInt() : 1,
945 0 : path[k]["libwpg:sweep"] ? path[k]["libwpg:sweep"]->getInt() : 1,
946 0 : path[k]["svg:x"]->getDouble(), path[k]["svg:y"]->getDouble(), xmin, ymin, xmax, ymax);
947 :
948 0 : px = (px > xmin ? xmin : px);
949 0 : py = (py > ymin ? ymin : py);
950 0 : qx = (qx < xmax ? xmax : qx);
951 0 : qy = (qy < ymax ? ymax : qy);
952 : }
953 0 : lastX = path[k]["svg:x"]->getDouble();
954 0 : lastY = path[k]["svg:y"]->getDouble();
955 : }
956 :
957 :
958 0 : WPXString sValue;
959 0 : _writeGraphicsStyle();
960 0 : TagOpenElement *pDrawPathElement = new TagOpenElement("draw:path");
961 0 : sValue.sprintf("gr%i", miGraphicsStyleIndex-1);
962 0 : pDrawPathElement->addAttribute("draw:style-name", sValue);
963 0 : pDrawPathElement->addAttribute("draw:layer", "layout");
964 0 : sValue = doubleToString(px);
965 0 : sValue.append("in");
966 0 : pDrawPathElement->addAttribute("svg:x", sValue);
967 0 : sValue = doubleToString(py);
968 0 : sValue.append("in");
969 0 : pDrawPathElement->addAttribute("svg:y", sValue);
970 0 : sValue = doubleToString((qx - px));
971 0 : sValue.append("in");
972 0 : pDrawPathElement->addAttribute("svg:width", sValue);
973 0 : sValue = doubleToString((qy - py));
974 0 : sValue.append("in");
975 0 : pDrawPathElement->addAttribute("svg:height", sValue);
976 0 : sValue.sprintf("%i %i %i %i", 0, 0, (unsigned)(2540*(qx - px)), (unsigned)(2540*(qy - py)));
977 0 : pDrawPathElement->addAttribute("svg:viewBox", sValue);
978 :
979 0 : sValue.clear();
980 0 : for(unsigned i = 0; i < path.count(); ++i)
981 : {
982 0 : WPXString sElement;
983 0 : if (path[i]["libwpg:path-action"]->getStr() == "M")
984 : {
985 : // 2540 is 2.54*1000, 2.54 in = 1 inch
986 0 : sElement.sprintf("M%i %i", (unsigned)((path[i]["svg:x"]->getDouble()-px)*2540),
987 0 : (unsigned)((path[i]["svg:y"]->getDouble()-py)*2540));
988 0 : sValue.append(sElement);
989 : }
990 0 : else if (path[i]["libwpg:path-action"]->getStr() == "L")
991 : {
992 0 : sElement.sprintf("L%i %i", (unsigned)((path[i]["svg:x"]->getDouble()-px)*2540),
993 0 : (unsigned)((path[i]["svg:y"]->getDouble()-py)*2540));
994 0 : sValue.append(sElement);
995 : }
996 0 : else if (path[i]["libwpg:path-action"]->getStr() == "C")
997 : {
998 0 : sElement.sprintf("C%i %i %i %i %i %i", (unsigned)((path[i]["svg:x1"]->getDouble()-px)*2540),
999 0 : (unsigned)((path[i]["svg:y1"]->getDouble()-py)*2540), (unsigned)((path[i]["svg:x2"]->getDouble()-px)*2540),
1000 0 : (unsigned)((path[i]["svg:y2"]->getDouble()-py)*2540), (unsigned)((path[i]["svg:x"]->getDouble()-px)*2540),
1001 0 : (unsigned)((path[i]["svg:y"]->getDouble()-py)*2540));
1002 0 : sValue.append(sElement);
1003 : }
1004 0 : else if (path[i]["libwpg:path-action"]->getStr() == "Q")
1005 : {
1006 0 : sElement.sprintf("Q%i %i %i %i", (unsigned)((path[i]["svg:x1"]->getDouble()-px)*2540),
1007 0 : (unsigned)((path[i]["svg:y1"]->getDouble()-py)*2540), (unsigned)((path[i]["svg:x"]->getDouble()-px)*2540),
1008 0 : (unsigned)((path[i]["svg:y"]->getDouble()-py)*2540));
1009 0 : sValue.append(sElement);
1010 : }
1011 0 : else if (path[i]["libwpg:path-action"]->getStr() == "A")
1012 : {
1013 0 : sElement.sprintf("A%i %i %i %i %i %i %i", (unsigned)((path[i]["svg:rx"]->getDouble())*2540),
1014 0 : (unsigned)((path[i]["svg:ry"]->getDouble())*2540), (path[i]["libwpg:rotate"] ? path[i]["libwpg:rotate"]->getInt() : 0),
1015 0 : (path[i]["libwpg:large-arc"] ? path[i]["libwpg:large-arc"]->getInt() : 1),
1016 0 : (path[i]["libwpg:sweep"] ? path[i]["libwpg:sweep"]->getInt() : 1),
1017 0 : (unsigned)((path[i]["svg:x"]->getDouble()-px)*2540), (unsigned)((path[i]["svg:y"]->getDouble()-py)*2540));
1018 0 : sValue.append(sElement);
1019 : }
1020 0 : else if (path[i]["libwpg:path-action"]->getStr() == "Z")
1021 0 : sValue.append(" Z");
1022 0 : }
1023 0 : pDrawPathElement->addAttribute("svg:d", sValue);
1024 0 : mBodyElements.push_back(pDrawPathElement);
1025 0 : mBodyElements.push_back(new TagCloseElement("draw:path"));
1026 : }
1027 :
1028 0 : void OdgGenerator::drawPath(const WPXPropertyListVector &path)
1029 : {
1030 0 : mpImpl->_drawPath(path);
1031 0 : }
1032 :
1033 0 : void OdgGenerator::drawGraphicObject(const ::WPXPropertyList &propList, const ::WPXBinaryData &binaryData)
1034 : {
1035 0 : if (!propList["libwpg:mime-type"] || propList["libwpg:mime-type"]->getStr().len() <= 0)
1036 : return;
1037 0 : if (!propList["svg:x"] || !propList["svg:y"] || !propList["svg:width"] || !propList["svg:height"])
1038 : return;
1039 :
1040 0 : bool flipX(propList["draw:mirror-horizontal"] && propList["draw:mirror-horizontal"]->getInt());
1041 0 : bool flipY(propList["draw:mirror-vertical"] && propList["draw:mirror-vertical"]->getInt());
1042 0 : if ((flipX && !flipY) || (!flipX && flipY))
1043 0 : mpImpl->mxStyle.insert("style:mirror", "horizontal");
1044 : else
1045 0 : mpImpl->mxStyle.insert("style:mirror", "none");
1046 0 : if (propList["draw:color-mode"])
1047 0 : mpImpl->mxStyle.insert("draw:color-mode", propList["draw:color-mode"]->getStr());
1048 0 : if (propList["draw:luminance"])
1049 0 : mpImpl->mxStyle.insert("draw:luminance", propList["draw:luminance"]->getStr());
1050 0 : if (propList["draw:contrast"])
1051 0 : mpImpl->mxStyle.insert("draw:contrast", propList["draw:contrast"]->getStr());
1052 0 : if (propList["draw:gamma"])
1053 0 : mpImpl->mxStyle.insert("draw:gamma", propList["draw:gamma"]->getStr());
1054 0 : if (propList["draw:red"])
1055 0 : mpImpl->mxStyle.insert("draw:red", propList["draw:red"]->getStr());
1056 0 : if (propList["draw:green"])
1057 0 : mpImpl->mxStyle.insert("draw:green", propList["draw:green"]->getStr());
1058 0 : if (propList["draw:blue"])
1059 0 : mpImpl->mxStyle.insert("draw:blue", propList["draw:blue"]->getStr());
1060 :
1061 :
1062 0 : mpImpl->_writeGraphicsStyle();
1063 :
1064 0 : double x = propList["svg:x"]->getDouble();
1065 0 : double y = propList["svg:y"]->getDouble();
1066 0 : double height = propList["svg:height"]->getDouble();
1067 0 : double width = propList["svg:width"]->getDouble();
1068 :
1069 0 : if (flipY)
1070 : {
1071 0 : x += width;
1072 0 : y += height;
1073 0 : width *= -1.0;
1074 0 : height *= -1.0;
1075 : }
1076 :
1077 0 : double angle(propList["libwpg:rotate"] ? - M_PI * propList["libwpg:rotate"]->getDouble() / 180.0 : 0.0);
1078 0 : if (angle != 0.0)
1079 : {
1080 0 : double deltax((width*cos(angle)+height*sin(angle)-width)/2.0);
1081 0 : double deltay((-width*sin(angle)+height*cos(angle)-height)/2.0);
1082 0 : x -= deltax;
1083 0 : y -= deltay;
1084 : }
1085 :
1086 0 : WPXPropertyList framePropList;
1087 :
1088 0 : framePropList.insert("svg:x", x);
1089 0 : framePropList.insert("svg:y", y);
1090 0 : framePropList.insert("svg:height", height);
1091 0 : framePropList.insert("svg:width", width);
1092 :
1093 0 : TagOpenElement *pDrawFrameElement = new TagOpenElement("draw:frame");
1094 :
1095 0 : WPXString sValue;
1096 0 : sValue.sprintf("gr%i", mpImpl->miGraphicsStyleIndex-1);
1097 0 : pDrawFrameElement->addAttribute("draw:style-name", sValue);
1098 :
1099 0 : pDrawFrameElement->addAttribute("svg:height", framePropList["svg:height"]->getStr());
1100 0 : pDrawFrameElement->addAttribute("svg:width", framePropList["svg:width"]->getStr());
1101 :
1102 0 : if (angle != 0.0)
1103 : {
1104 0 : framePropList.insert("libwpg:rotate", angle, WPX_GENERIC);
1105 : sValue.sprintf("rotate (%s) translate(%s, %s)",
1106 0 : framePropList["libwpg:rotate"]->getStr().cstr(),
1107 0 : framePropList["svg:x"]->getStr().cstr(),
1108 0 : framePropList["svg:y"]->getStr().cstr());
1109 0 : pDrawFrameElement->addAttribute("draw:transform", sValue);
1110 : }
1111 : else
1112 : {
1113 0 : pDrawFrameElement->addAttribute("svg:x", framePropList["svg:x"]->getStr());
1114 0 : pDrawFrameElement->addAttribute("svg:y", framePropList["svg:y"]->getStr());
1115 : }
1116 0 : mpImpl->mBodyElements.push_back(pDrawFrameElement);
1117 :
1118 0 : if (propList["libwpg:mime-type"]->getStr() == "object/ole")
1119 0 : mpImpl->mBodyElements.push_back(new TagOpenElement("draw:object-ole"));
1120 : else
1121 0 : mpImpl->mBodyElements.push_back(new TagOpenElement("draw:image"));
1122 :
1123 0 : mpImpl->mBodyElements.push_back(new TagOpenElement("office:binary-data"));
1124 :
1125 0 : ::WPXString base64Binary = binaryData.getBase64Data();
1126 0 : mpImpl->mBodyElements.push_back(new CharDataElement(base64Binary.cstr()));
1127 :
1128 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("office:binary-data"));
1129 :
1130 0 : if (propList["libwpg:mime-type"]->getStr() == "object/ole")
1131 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("draw:object-ole"));
1132 : else
1133 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("draw:image"));
1134 :
1135 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("draw:frame"));
1136 : }
1137 :
1138 0 : void OdgGeneratorPrivate::_writeGraphicsStyle()
1139 : {
1140 0 : bool bUseOpacityGradient = false;
1141 :
1142 0 : if (mxStyle["draw:stroke"] && mxStyle["draw:stroke"]->getStr() == "dash")
1143 : {
1144 0 : TagOpenElement *pDrawStrokeDashElement = new TagOpenElement("draw:stroke-dash");
1145 0 : WPXString sValue;
1146 0 : sValue.sprintf("Dash_%i", miDashIndex++);
1147 0 : pDrawStrokeDashElement->addAttribute("draw:name", sValue);
1148 0 : if (mxStyle["svg:stoke-linecap"])
1149 0 : pDrawStrokeDashElement->addAttribute("draw:style", mxStyle["svg:stroke-linecap"]->getStr());
1150 : else
1151 0 : pDrawStrokeDashElement->addAttribute("draw:style", "rect");
1152 0 : if (mxStyle["draw:distance"])
1153 0 : pDrawStrokeDashElement->addAttribute("draw:distance", mxStyle["draw:distance"]->getStr());
1154 0 : if (mxStyle["draw:dots1"])
1155 0 : pDrawStrokeDashElement->addAttribute("draw:dots1", mxStyle["draw:dots1"]->getStr());
1156 0 : if (mxStyle["draw:dots1-length"])
1157 0 : pDrawStrokeDashElement->addAttribute("draw:dots1-length", mxStyle["draw:dots1-length"]->getStr());
1158 0 : if (mxStyle["draw:dots2"])
1159 0 : pDrawStrokeDashElement->addAttribute("draw:dots2", mxStyle["draw:dots2"]->getStr());
1160 0 : if (mxStyle["draw:dots2-length"])
1161 0 : pDrawStrokeDashElement->addAttribute("draw:dots2-length", mxStyle["draw:dots2-length"]->getStr());
1162 0 : mGraphicsStrokeDashStyles.push_back(pDrawStrokeDashElement);
1163 0 : mGraphicsStrokeDashStyles.push_back(new TagCloseElement("draw:stroke-dash"));
1164 : }
1165 :
1166 0 : if (mxStyle["draw:marker-start-path"])
1167 : {
1168 0 : WPXString sValue;
1169 0 : TagOpenElement *pDrawMarkerElement = new TagOpenElement("draw:marker");
1170 0 : sValue.sprintf("StartMarker_%i", miStartMarkerIndex);
1171 0 : pDrawMarkerElement->addAttribute("draw:name", sValue);
1172 0 : if (mxStyle["draw:marker-start-viewbox"])
1173 0 : pDrawMarkerElement->addAttribute("svg:viewBox", mxStyle["draw:marker-start-viewbox"]->getStr());
1174 0 : pDrawMarkerElement->addAttribute("svg:d", mxStyle["draw:marker-start-path"]->getStr());
1175 0 : mGraphicsMarkerStyles.push_back(pDrawMarkerElement);
1176 0 : mGraphicsMarkerStyles.push_back(new TagCloseElement("draw:marker"));
1177 : }
1178 0 : if(mxStyle["draw:marker-end-path"])
1179 : {
1180 0 : WPXString sValue;
1181 0 : TagOpenElement *pDrawMarkerElement = new TagOpenElement("draw:marker");
1182 0 : sValue.sprintf("EndMarker_%i", miEndMarkerIndex);
1183 0 : pDrawMarkerElement->addAttribute("draw:name", sValue);
1184 0 : if (mxStyle["draw:marker-end-viewbox"])
1185 0 : pDrawMarkerElement->addAttribute("svg:viewBox", mxStyle["draw:marker-end-viewbox"]->getStr());
1186 0 : pDrawMarkerElement->addAttribute("svg:d", mxStyle["draw:marker-end-path"]->getStr());
1187 0 : mGraphicsMarkerStyles.push_back(pDrawMarkerElement);
1188 0 : mGraphicsMarkerStyles.push_back(new TagCloseElement("draw:marker"));
1189 : }
1190 :
1191 0 : if(mxStyle["draw:fill"] && mxStyle["draw:fill"]->getStr() == "gradient")
1192 : {
1193 0 : TagOpenElement *pDrawGradientElement = new TagOpenElement("draw:gradient");
1194 0 : TagOpenElement *pDrawOpacityElement = new TagOpenElement("draw:opacity");
1195 0 : if (mxStyle["draw:style"])
1196 : {
1197 0 : pDrawGradientElement->addAttribute("draw:style", mxStyle["draw:style"]->getStr());
1198 0 : pDrawOpacityElement->addAttribute("draw:style", mxStyle["draw:style"]->getStr());
1199 : }
1200 : else
1201 : {
1202 0 : pDrawGradientElement->addAttribute("draw:style", "linear");
1203 0 : pDrawOpacityElement->addAttribute("draw:style", "linear");
1204 : }
1205 0 : WPXString sValue;
1206 0 : sValue.sprintf("Gradient_%i", miGradientIndex);
1207 0 : pDrawGradientElement->addAttribute("draw:name", sValue);
1208 0 : sValue.sprintf("Transparency_%i", miGradientIndex++);
1209 0 : pDrawOpacityElement->addAttribute("draw:name", sValue);
1210 :
1211 : // ODG angle unit is 0.1 degree
1212 0 : double angle = mxStyle["draw:angle"] ? mxStyle["draw:angle"]->getDouble() : 0.0;
1213 0 : while(angle < 0)
1214 0 : angle += 360;
1215 0 : while(angle > 360)
1216 0 : angle -= 360;
1217 0 : sValue.sprintf("%i", (unsigned)(angle*10));
1218 0 : pDrawGradientElement->addAttribute("draw:angle", sValue);
1219 0 : pDrawOpacityElement->addAttribute("draw:angle", sValue);
1220 :
1221 0 : if (!mxGradient.count())
1222 : {
1223 0 : if (mxStyle["draw:start-color"])
1224 0 : pDrawGradientElement->addAttribute("draw:start-color", mxStyle["draw:start-color"]->getStr());
1225 0 : if (mxStyle["draw:end-color"])
1226 0 : pDrawGradientElement->addAttribute("draw:end-color", mxStyle["draw:end-color"]->getStr());
1227 :
1228 0 : if (mxStyle["draw:border"])
1229 : {
1230 0 : pDrawGradientElement->addAttribute("draw:border", mxStyle["draw:border"]->getStr());
1231 0 : pDrawOpacityElement->addAttribute("draw:border", mxStyle["draw:border"]->getStr());
1232 : }
1233 : else
1234 : {
1235 0 : pDrawGradientElement->addAttribute("draw:border", "0%");
1236 0 : pDrawOpacityElement->addAttribute("draw:border", "0%");
1237 : }
1238 :
1239 0 : if (mxStyle["svg:cx"])
1240 : {
1241 0 : pDrawGradientElement->addAttribute("draw:cx", mxStyle["svg:cx"]->getStr());
1242 0 : pDrawOpacityElement->addAttribute("draw:cx", mxStyle["svg:cx"]->getStr());
1243 : }
1244 0 : else if (mxStyle["draw:cx"])
1245 : {
1246 0 : pDrawGradientElement->addAttribute("draw:cx", mxStyle["draw:cx"]->getStr());
1247 0 : pDrawOpacityElement->addAttribute("draw:cx", mxStyle["draw:cx"]->getStr());
1248 : }
1249 :
1250 0 : if (mxStyle["svg:cy"])
1251 : {
1252 0 : pDrawGradientElement->addAttribute("draw:cy", mxStyle["svg:cy"]->getStr());
1253 0 : pDrawOpacityElement->addAttribute("draw:cy", mxStyle["svg:cy"]->getStr());
1254 : }
1255 0 : else if (mxStyle["draw:cx"])
1256 : {
1257 0 : pDrawGradientElement->addAttribute("draw:cx", mxStyle["svg:cx"]->getStr());
1258 0 : pDrawOpacityElement->addAttribute("draw:cx", mxStyle["svg:cx"]->getStr());
1259 : }
1260 :
1261 0 : if (mxStyle["draw:start-intensity"])
1262 0 : pDrawGradientElement->addAttribute("draw:start-intensity", mxStyle["draw:start-intensity"]->getStr());
1263 : else
1264 0 : pDrawGradientElement->addAttribute("draw:start-intensity", "100%");
1265 :
1266 0 : if (mxStyle["draw:end-intensity"])
1267 0 : pDrawGradientElement->addAttribute("draw:end-intensity", mxStyle["draw:end-intensity"]->getStr());
1268 : else
1269 0 : pDrawGradientElement->addAttribute("draw:end-intensity", "100%");
1270 :
1271 0 : if (mxStyle["libwpg:start-opacity"])
1272 0 : pDrawOpacityElement->addAttribute("draw:start", mxStyle["libwpg:start-opacity"]->getStr());
1273 : else
1274 0 : pDrawOpacityElement->addAttribute("draw:start", "100%");
1275 :
1276 0 : if (mxStyle["libwpg:end-opacity"])
1277 0 : pDrawOpacityElement->addAttribute("draw:end", mxStyle["libwpg:end-opacity"]->getStr());
1278 : else
1279 0 : pDrawOpacityElement->addAttribute("draw:end", "100%");
1280 :
1281 0 : mGraphicsGradientStyles.push_back(pDrawGradientElement);
1282 0 : mGraphicsGradientStyles.push_back(new TagCloseElement("draw:gradient"));
1283 :
1284 : // Work around a mess in LibreOffice where both opacities of 100% are interpreted as complete transparency
1285 : // Nevertheless, when one is different, immediately, they are interpreted correctly
1286 0 : if (mxStyle["libwpg:start-opacity"] && mxStyle["libwpg:end-opacity"]
1287 0 : && (mxStyle["libwpg:start-opacity"]->getDouble() != 1.0 || mxStyle["libwpg:end-opacity"]->getDouble() != 1.0))
1288 : {
1289 0 : bUseOpacityGradient = true;
1290 0 : mGraphicsGradientStyles.push_back(pDrawOpacityElement);
1291 0 : mGraphicsGradientStyles.push_back(new TagCloseElement("draw:opacity"));
1292 : }
1293 : }
1294 0 : else if(mxGradient.count() >= 2)
1295 : {
1296 0 : sValue.sprintf("%i", (unsigned)(angle*10));
1297 0 : pDrawGradientElement->addAttribute("draw:angle", sValue);
1298 :
1299 0 : pDrawGradientElement->addAttribute("draw:start-color", mxGradient[1]["svg:stop-color"]->getStr());
1300 0 : pDrawGradientElement->addAttribute("draw:end-color", mxGradient[0]["svg:stop-color"]->getStr());
1301 0 : if (mxStyle["svg:cx"])
1302 0 : pDrawGradientElement->addAttribute("draw:cx", mxStyle["svg:cx"]->getStr());
1303 0 : if (mxStyle["svg:cy"])
1304 0 : pDrawGradientElement->addAttribute("draw:cy", mxStyle["svg:cy"]->getStr());
1305 0 : if (mxGradient[1]["svg:stop-opacity"])
1306 : {
1307 0 : pDrawOpacityElement->addAttribute("draw:start", mxGradient[1]["svg:stop-opacity"]->getStr());
1308 0 : bUseOpacityGradient = true;
1309 : }
1310 : else
1311 0 : pDrawOpacityElement->addAttribute("draw:start", "100%");
1312 0 : if (mxGradient[0]["svg:stop-opacity"])
1313 : {
1314 0 : pDrawOpacityElement->addAttribute("draw:end", mxGradient[0]["svg:stop-opacity"]->getStr());
1315 0 : bUseOpacityGradient = true;
1316 : }
1317 : else
1318 0 : pDrawOpacityElement->addAttribute("draw:end", "100%");
1319 0 : pDrawGradientElement->addAttribute("draw:border", "0%");
1320 0 : mGraphicsGradientStyles.push_back(pDrawGradientElement);
1321 0 : mGraphicsGradientStyles.push_back(new TagCloseElement("draw:gradient"));
1322 0 : if (bUseOpacityGradient)
1323 : {
1324 0 : mGraphicsGradientStyles.push_back(pDrawOpacityElement);
1325 0 : mGraphicsGradientStyles.push_back(new TagCloseElement("draw:opacity"));
1326 : }
1327 : }
1328 :
1329 0 : if(!bUseOpacityGradient)
1330 0 : delete pDrawOpacityElement;
1331 : }
1332 :
1333 0 : if(mxStyle["draw:fill"] && mxStyle["draw:fill"]->getStr() == "bitmap" &&
1334 0 : mxStyle["draw:fill-image"] && mxStyle["libwpg:mime-type"])
1335 : {
1336 0 : TagOpenElement *pDrawBitmapElement = new TagOpenElement("draw:fill-image");
1337 0 : WPXString sValue;
1338 0 : sValue.sprintf("Bitmap_%i", miBitmapIndex++);
1339 0 : pDrawBitmapElement->addAttribute("draw:name", sValue);
1340 0 : mGraphicsBitmapStyles.push_back(pDrawBitmapElement);
1341 0 : mGraphicsBitmapStyles.push_back(new TagOpenElement("office:binary-data"));
1342 0 : mGraphicsBitmapStyles.push_back(new CharDataElement(mxStyle["draw:fill-image"]->getStr()));
1343 0 : mGraphicsBitmapStyles.push_back(new TagCloseElement("office:binary-data"));
1344 0 : mGraphicsBitmapStyles.push_back(new TagCloseElement("draw:fill-image"));
1345 : }
1346 :
1347 0 : TagOpenElement *pStyleStyleElement = new TagOpenElement("style:style");
1348 0 : WPXString sValue;
1349 0 : sValue.sprintf("gr%i", miGraphicsStyleIndex);
1350 0 : pStyleStyleElement->addAttribute("style:name", sValue);
1351 0 : pStyleStyleElement->addAttribute("style:family", "graphic");
1352 0 : pStyleStyleElement->addAttribute("style:parent-style-name", "standard");
1353 0 : mGraphicsAutomaticStyles.push_back(pStyleStyleElement);
1354 :
1355 0 : TagOpenElement *pStyleGraphicsPropertiesElement = new TagOpenElement("style:graphic-properties");
1356 :
1357 0 : if (mxStyle["draw:color-mode"] && mxStyle["draw:color-mode"]->getStr().len() > 0)
1358 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:color-mode", mxStyle["draw:color-mode"]->getStr());
1359 0 : if (mxStyle["draw:luminance"] && mxStyle["draw:luminance"]->getStr().len() > 0)
1360 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:luminance", mxStyle["draw:luminance"]->getStr());
1361 0 : if (mxStyle["draw:contrast"] && mxStyle["draw:contrast"]->getStr().len() > 0)
1362 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:contrast", mxStyle["draw:contrast"]->getStr());
1363 0 : if (mxStyle["draw:gamma"] && mxStyle["draw:gamma"]->getStr().len() > 0)
1364 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:gamma", mxStyle["draw:gamma"]->getStr());
1365 0 : if (mxStyle["draw:red"] && mxStyle["draw:red"]->getStr().len() > 0)
1366 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:red", mxStyle["draw:red"]->getStr());
1367 0 : if (mxStyle["draw:green"] && mxStyle["draw:green"]->getStr().len() > 0)
1368 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:green", mxStyle["draw:green"]->getStr());
1369 0 : if (mxStyle["draw:blue"] && mxStyle["draw:blue"]->getStr().len() > 0)
1370 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:blue", mxStyle["draw:blue"]->getStr());
1371 :
1372 0 : if (mxStyle["draw:stroke"] && mxStyle["draw:stroke"]->getStr() == "none")
1373 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:stroke", "none");
1374 : else
1375 : {
1376 0 : if (mxStyle["svg:stroke-width"])
1377 0 : pStyleGraphicsPropertiesElement->addAttribute("svg:stroke-width", mxStyle["svg:stroke-width"]->getStr());
1378 :
1379 0 : if (mxStyle["svg:stroke-color"])
1380 0 : pStyleGraphicsPropertiesElement->addAttribute("svg:stroke-color", mxStyle["svg:stroke-color"]->getStr());
1381 :
1382 0 : if (mxStyle["svg:stroke-opacity"])
1383 0 : pStyleGraphicsPropertiesElement->addAttribute("svg:stroke-opacity", mxStyle["svg:stroke-opacity"]->getStr());
1384 :
1385 0 : if (mxStyle["svg:stroke-linejoin"])
1386 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:stroke-linejoin", mxStyle["svg:stroke-linejoin"]->getStr());
1387 :
1388 0 : if (mxStyle["svg:stroke-linecap"])
1389 0 : pStyleGraphicsPropertiesElement->addAttribute("svg:stoke-linecap", mxStyle["svg:stroke-linecap"]->getStr());
1390 :
1391 0 : if (mxStyle["draw:stroke"] && mxStyle["draw:stroke"]->getStr() == "dash")
1392 : {
1393 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:stroke", "dash");
1394 0 : sValue.sprintf("Dash_%i", miDashIndex-1);
1395 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:stroke-dash", sValue);
1396 : }
1397 : else
1398 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:stroke", "solid");
1399 : }
1400 :
1401 0 : if(mxStyle["draw:fill"] && mxStyle["draw:fill"]->getStr() == "none")
1402 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "none");
1403 : else
1404 : {
1405 0 : if (mxStyle["draw:shadow"])
1406 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:shadow", mxStyle["draw:shadow"]->getStr());
1407 : else
1408 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:shadow", "hidden");
1409 0 : if (mxStyle["draw:shadow-offset-x"])
1410 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:shadow-offset-x", mxStyle["draw:shadow-offset-x"]->getStr());
1411 0 : if (mxStyle["draw:shadow-offset-y"])
1412 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:shadow-offset-y", mxStyle["draw:shadow-offset-y"]->getStr());
1413 0 : if (mxStyle["draw:shadow-color"])
1414 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:shadow-color", mxStyle["draw:shadow-color"]->getStr());
1415 0 : if (mxStyle["draw:shadow-opacity"])
1416 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:shadow-opacity", mxStyle["draw:shadow-opacity"]->getStr());
1417 0 : if (mxStyle["svg:fill-rule"])
1418 0 : pStyleGraphicsPropertiesElement->addAttribute("svg:fill-rule", mxStyle["svg:fill-rule"]->getStr());
1419 : }
1420 :
1421 0 : if(mxStyle["draw:fill"] && mxStyle["draw:fill"]->getStr() == "solid")
1422 : {
1423 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "solid");
1424 0 : if (mxStyle["draw:fill-color"])
1425 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill-color", mxStyle["draw:fill-color"]->getStr());
1426 0 : if (mxStyle["draw:opacity"])
1427 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:opacity", mxStyle["draw:opacity"]->getStr());
1428 : }
1429 :
1430 0 : if(mxStyle["draw:fill"] && mxStyle["draw:fill"]->getStr() == "gradient")
1431 : {
1432 0 : if (!mxGradient.count() || mxGradient.count() >= 2)
1433 : {
1434 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "gradient");
1435 0 : sValue.sprintf("Gradient_%i", miGradientIndex-1);
1436 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill-gradient-name", sValue);
1437 0 : if (bUseOpacityGradient)
1438 : {
1439 0 : sValue.sprintf("Transparency_%i", miGradientIndex-1);
1440 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:opacity-name", sValue);
1441 : }
1442 : }
1443 : else
1444 : {
1445 0 : if (mxGradient[0]["svg:stop-color"])
1446 : {
1447 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "solid");
1448 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill-color", mxGradient[0]["svg:stop-color"]->getStr());
1449 : }
1450 : else
1451 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "solid");
1452 : }
1453 : }
1454 :
1455 0 : if(mxStyle["draw:fill"] && mxStyle["draw:fill"]->getStr() == "bitmap")
1456 : {
1457 0 : if (mxStyle["draw:fill-image"] && mxStyle["libwpg:mime-type"])
1458 : {
1459 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "bitmap");
1460 0 : sValue.sprintf("Bitmap_%i", miBitmapIndex-1);
1461 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill-image-name", sValue);
1462 0 : if (mxStyle["svg:width"])
1463 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill-image-width", mxStyle["svg:width"]->getStr());
1464 0 : if (mxStyle["svg:height"])
1465 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill-image-height", mxStyle["svg:height"]->getStr());
1466 0 : if (mxStyle["style:repeat"])
1467 0 : pStyleGraphicsPropertiesElement->addAttribute("style:repeat", mxStyle["style:repeat"]->getStr());
1468 0 : if (mxStyle["draw:fill-image-ref-point"])
1469 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill-image-ref-point", mxStyle["draw:fill-image-ref-point"]->getStr());
1470 0 : if (mxStyle["draw:fill-image-ref-point-x"])
1471 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill-image-ref-point-x", mxStyle["draw:fill-image-ref-point-x"]->getStr());
1472 0 : if (mxStyle["draw:fill-image-ref-point-y"])
1473 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill-image-ref-point-y", mxStyle["draw:fill-image-ref-point-y"]->getStr());
1474 : }
1475 : else
1476 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "none");
1477 : }
1478 :
1479 :
1480 0 : if(mxStyle["draw:marker-start-path"])
1481 : {
1482 0 : sValue.sprintf("StartMarker_%i", miStartMarkerIndex++);
1483 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:marker-start", sValue);
1484 0 : if (mxStyle["draw:marker-start-width"])
1485 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:marker-start-width", mxStyle["draw:marker-start-width"]->getStr());
1486 : else
1487 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:marker-start-width", "0.118in");
1488 : }
1489 0 : if (mxStyle["draw:marker-end-path"])
1490 : {
1491 0 : sValue.sprintf("EndMarker_%i", miEndMarkerIndex++);
1492 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:marker-end", sValue);
1493 0 : if (mxStyle["draw:marker-end-width"])
1494 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:marker-end-width", mxStyle["draw:marker-end-width"]->getStr());
1495 : else
1496 0 : pStyleGraphicsPropertiesElement->addAttribute("draw:marker-end-width", "0.118in");
1497 : }
1498 0 : if (mxStyle["style:mirror"])
1499 0 : pStyleGraphicsPropertiesElement->addAttribute("style:mirror", mxStyle["style:mirror"]->getStr());
1500 :
1501 0 : mGraphicsAutomaticStyles.push_back(pStyleGraphicsPropertiesElement);
1502 0 : mGraphicsAutomaticStyles.push_back(new TagCloseElement("style:graphic-properties"));
1503 :
1504 0 : mGraphicsAutomaticStyles.push_back(new TagCloseElement("style:style"));
1505 0 : miGraphicsStyleIndex++;
1506 0 : }
1507 :
1508 0 : void OdgGenerator::startEmbeddedGraphics(const WPXPropertyList &)
1509 : {
1510 0 : }
1511 :
1512 0 : void OdgGenerator::endEmbeddedGraphics()
1513 : {
1514 0 : }
1515 :
1516 0 : void OdgGenerator::startTextObject(const WPXPropertyList &propList, const WPXPropertyListVector &)
1517 : {
1518 0 : TagOpenElement *pDrawFrameOpenElement = new TagOpenElement("draw:frame");
1519 0 : TagOpenElement *pStyleStyleOpenElement = new TagOpenElement("style:style");
1520 :
1521 0 : WPXString sValue;
1522 0 : sValue.sprintf("gr%i", mpImpl->miGraphicsStyleIndex++);
1523 0 : pStyleStyleOpenElement->addAttribute("style:name", sValue);
1524 0 : pStyleStyleOpenElement->addAttribute("style:family", "graphic");
1525 0 : pStyleStyleOpenElement->addAttribute("style:parent-style-name", "standard");
1526 0 : mpImpl->mGraphicsAutomaticStyles.push_back(pStyleStyleOpenElement);
1527 :
1528 0 : pDrawFrameOpenElement->addAttribute("draw:style-name", sValue);
1529 0 : pDrawFrameOpenElement->addAttribute("draw:layer", "layout");
1530 :
1531 0 : TagOpenElement *pStyleGraphicPropertiesOpenElement = new TagOpenElement("style:graphic-properties");
1532 0 : pStyleGraphicPropertiesOpenElement->addAttribute("draw:stroke", "none");
1533 0 : pStyleGraphicPropertiesOpenElement->addAttribute("svg:stroke-color", "#000000");
1534 0 : pStyleGraphicPropertiesOpenElement->addAttribute("draw:fill", "none");
1535 0 : pStyleGraphicPropertiesOpenElement->addAttribute("draw:fill-color", "#ffffff");
1536 :
1537 0 : double x = 0.0;
1538 0 : double y = 0.0;
1539 0 : double height = 0.0;
1540 0 : double width = 0.0;
1541 0 : if (propList["svg:x"])
1542 0 : x = propList["svg:x"]->getDouble();
1543 0 : if (propList["svg:y"])
1544 0 : y = propList["svg:y"]->getDouble();
1545 0 : if (propList["svg:width"])
1546 0 : width = propList["svg:width"]->getDouble();
1547 0 : if (propList["svg:height"])
1548 0 : height = propList["svg:height"]->getDouble();
1549 :
1550 0 : double angle(propList["libwpg:rotate"] ? - M_PI * propList["libwpg:rotate"]->getDouble() / 180.0 : 0.0);
1551 0 : if (angle != 0.0)
1552 : {
1553 0 : double deltax((width*cos(angle)+height*sin(angle)-width)/2.0);
1554 0 : double deltay((-width*sin(angle)+height*cos(angle)-height)/2.0);
1555 0 : x -= deltax;
1556 0 : y -= deltay;
1557 : }
1558 :
1559 0 : if (!propList["svg:width"] && !propList["svg:height"])
1560 : {
1561 0 : if (!propList["fo:min-width"])
1562 : {
1563 0 : pDrawFrameOpenElement->addAttribute("fo:min-width", "1in");
1564 0 : pStyleGraphicPropertiesOpenElement->addAttribute("fo:min-width", "1in");
1565 : }
1566 0 : pDrawFrameOpenElement->addAttribute("svg:width", "10in");
1567 : }
1568 : else
1569 : {
1570 0 : if(propList["svg:width"])
1571 0 : pDrawFrameOpenElement->addAttribute("svg:width", propList["svg:width"]->getStr());
1572 0 : if(propList["svg:height"])
1573 0 : pDrawFrameOpenElement->addAttribute("svg:height", propList["svg:height"]->getStr());
1574 : }
1575 0 : if (propList["fo:min-width"])
1576 : {
1577 0 : pDrawFrameOpenElement->addAttribute("fo:min-width", propList["fo:min-width"]->getStr());
1578 0 : pStyleGraphicPropertiesOpenElement->addAttribute("fo:min-width", propList["fo:min-width"]->getStr());
1579 : }
1580 0 : if (propList["fo:min-height"])
1581 : {
1582 0 : pDrawFrameOpenElement->addAttribute("fo:min-height", propList["fo:min-height"]->getStr());
1583 0 : pStyleGraphicPropertiesOpenElement->addAttribute("fo:min-height", propList["fo:min-height"]->getStr());
1584 : }
1585 0 : if (propList["fo:max-width"])
1586 : {
1587 0 : pDrawFrameOpenElement->addAttribute("fo:max-width", propList["fo:max-height"]->getStr());
1588 0 : pStyleGraphicPropertiesOpenElement->addAttribute("fo:max-width", propList["fo:max-width"]->getStr());
1589 : }
1590 0 : if (propList["fo:max-height"])
1591 : {
1592 0 : pDrawFrameOpenElement->addAttribute("fo:max-height", propList["fo:max-height"]->getStr());
1593 0 : pStyleGraphicPropertiesOpenElement->addAttribute("fo:max-height", propList["fo:max-height"]->getStr());
1594 : }
1595 0 : if (propList["fo:padding-top"])
1596 : {
1597 0 : pDrawFrameOpenElement->addAttribute("fo:padding-top", propList["fo:padding-top"]->getStr());
1598 0 : pStyleGraphicPropertiesOpenElement->addAttribute("fo:padding-top", propList["fo:padding-top"]->getStr());
1599 : }
1600 0 : if (propList["fo:padding-bottom"])
1601 : {
1602 0 : pDrawFrameOpenElement->addAttribute("fo:padding-bottom", propList["fo:padding-bottom"]->getStr());
1603 0 : pStyleGraphicPropertiesOpenElement->addAttribute("fo:padding-bottom", propList["fo:padding-bottom"]->getStr());
1604 : }
1605 0 : if (propList["fo:padding-left"])
1606 : {
1607 0 : pDrawFrameOpenElement->addAttribute("fo:padding-left", propList["fo:padding-left"]->getStr());
1608 0 : pStyleGraphicPropertiesOpenElement->addAttribute("fo:padding-left", propList["fo:padding-left"]->getStr());
1609 : }
1610 0 : if (propList["fo:padding-right"])
1611 : {
1612 0 : pDrawFrameOpenElement->addAttribute("fo:padding-right", propList["fo:padding-right"]->getStr());
1613 0 : pStyleGraphicPropertiesOpenElement->addAttribute("fo:padding-right", propList["fo:padding-right"]->getStr());
1614 : }
1615 0 : if (propList["draw:textarea-vertical-align"])
1616 : {
1617 0 : pDrawFrameOpenElement->addAttribute("draw:textarea-vertical-align", propList["draw:textarea-vertical-align"]->getStr());
1618 0 : pStyleGraphicPropertiesOpenElement->addAttribute("draw:textarea-vertical-align", propList["draw:textarea-vertical-align"]->getStr());
1619 : }
1620 0 : if (propList["draw:fill"])
1621 : {
1622 0 : pDrawFrameOpenElement->addAttribute("draw:fill", propList["draw:fill"]->getStr());
1623 0 : pStyleGraphicPropertiesOpenElement->addAttribute("draw:fill", propList["draw:fill"]->getStr());
1624 : }
1625 0 : if (propList["draw:fill-color"])
1626 : {
1627 0 : pDrawFrameOpenElement->addAttribute("draw:fill-color", propList["draw:fill-color"]->getStr());
1628 0 : pStyleGraphicPropertiesOpenElement->addAttribute("draw:fill-color", propList["draw:fill-color"]->getStr());
1629 : }
1630 0 : if (propList["draw:opacity"])
1631 : {
1632 0 : pDrawFrameOpenElement->addAttribute("draw:opacity", propList["draw:opacity"]->getStr());
1633 0 : pStyleGraphicPropertiesOpenElement->addAttribute("draw:opacity", propList["draw:opacity"]->getStr());
1634 : }
1635 :
1636 0 : WPXProperty *svg_x = WPXPropertyFactory::newInchProp(x);
1637 0 : WPXProperty *svg_y = WPXPropertyFactory::newInchProp(y);
1638 0 : if (angle != 0.0)
1639 : {
1640 0 : WPXProperty *libwpg_rotate = WPXPropertyFactory::newDoubleProp(angle);
1641 : sValue.sprintf("rotate (%s) translate(%s, %s)",
1642 0 : libwpg_rotate->getStr().cstr(),
1643 0 : svg_x->getStr().cstr(),
1644 0 : svg_y->getStr().cstr());
1645 0 : delete libwpg_rotate;
1646 0 : pDrawFrameOpenElement->addAttribute("draw:transform", sValue);
1647 : }
1648 : else
1649 : {
1650 0 : if (propList["svg:x"])
1651 0 : pDrawFrameOpenElement->addAttribute("svg:x", svg_x->getStr());
1652 0 : if (propList["svg:y"])
1653 0 : pDrawFrameOpenElement->addAttribute("svg:y", svg_y->getStr());
1654 : }
1655 0 : delete svg_x;
1656 0 : delete svg_y;
1657 0 : mpImpl->mBodyElements.push_back(pDrawFrameOpenElement);
1658 0 : mpImpl->mBodyElements.push_back(new TagOpenElement("draw:text-box"));
1659 0 : mpImpl->mGraphicsAutomaticStyles.push_back(pStyleGraphicPropertiesOpenElement);
1660 0 : mpImpl->mGraphicsAutomaticStyles.push_back(new TagCloseElement("style:graphic-properties"));
1661 0 : mpImpl->mGraphicsAutomaticStyles.push_back(new TagCloseElement("style:style"));
1662 0 : mpImpl->mbIsTextBox = true;
1663 0 : }
1664 :
1665 0 : void OdgGenerator::endTextObject()
1666 : {
1667 0 : if (mpImpl->mbIsTextBox)
1668 : {
1669 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("draw:text-box"));
1670 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("draw:frame"));
1671 0 : mpImpl->mbIsTextBox = false;
1672 : }
1673 0 : }
1674 :
1675 0 : void OdgGenerator::startTextLine(const WPXPropertyList &propList)
1676 : {
1677 0 : WPXPropertyList finalPropList(propList);
1678 0 : finalPropList.insert("style:parent-style-name", "Standard");
1679 0 : WPXString paragName = mpImpl->mParagraphManager.findOrAdd(finalPropList, WPXPropertyListVector());
1680 :
1681 :
1682 : // create a document element corresponding to the paragraph, and append it to our list of document elements
1683 0 : TagOpenElement *pParagraphOpenElement = new TagOpenElement("text:p");
1684 0 : pParagraphOpenElement->addAttribute("text:style-name", paragName);
1685 0 : mpImpl->mBodyElements.push_back(pParagraphOpenElement);
1686 0 : }
1687 :
1688 0 : void OdgGenerator::endTextLine()
1689 : {
1690 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("text:p"));
1691 0 : }
1692 :
1693 0 : void OdgGenerator::startTextSpan(const WPXPropertyList &propList)
1694 : {
1695 0 : if (propList["style:font-name"])
1696 0 : mpImpl->mFontManager.findOrAdd(propList["style:font-name"]->getStr().cstr());
1697 :
1698 0 : WPXString sName = mpImpl->mSpanManager.findOrAdd(propList);
1699 :
1700 0 : TagOpenElement *pSpanOpenElement = new TagOpenElement("text:span");
1701 0 : pSpanOpenElement->addAttribute("text:style-name", sName.cstr());
1702 0 : mpImpl->mBodyElements.push_back(pSpanOpenElement);
1703 0 : }
1704 :
1705 0 : void OdgGenerator::endTextSpan()
1706 : {
1707 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("text:span"));
1708 0 : }
1709 :
1710 0 : void OdgGenerator::insertText(const WPXString &text)
1711 : {
1712 0 : WPXString out;
1713 0 : WPXString::Iter i(text);
1714 0 : for (i.rewind(); i.next();)
1715 : {
1716 0 : if ((*i()) == '\n' || (*i()) == '\t')
1717 : {
1718 0 : if (out.len() != 0)
1719 : {
1720 0 : DocumentElement *pText = new TextElement(out);
1721 0 : mpImpl->mBodyElements.push_back(pText);
1722 0 : out.clear();
1723 : }
1724 0 : if ((*i()) == '\n')
1725 : {
1726 0 : mpImpl->mBodyElements.push_back(new TagOpenElement("text:line-break"));
1727 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("text:line-break"));
1728 : }
1729 0 : else if ((*i()) == '\t')
1730 : {
1731 0 : mpImpl->mBodyElements.push_back(new TagOpenElement("text:tab"));
1732 0 : mpImpl->mBodyElements.push_back(new TagCloseElement("text:tab"));
1733 : }
1734 : }
1735 : else
1736 : {
1737 0 : out.append(i());
1738 : }
1739 : }
1740 0 : if (out.len() != 0)
1741 : {
1742 0 : DocumentElement *pText = new TextElement(out);
1743 0 : mpImpl->mBodyElements.push_back(pText);
1744 0 : }
1745 0 : }
1746 :
1747 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|