summaryrefslogtreecommitdiff
path: root/writerperfect/source/common/OdgGenerator.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'writerperfect/source/common/OdgGenerator.cxx')
-rw-r--r--writerperfect/source/common/OdgGenerator.cxx1756
1 files changed, 1756 insertions, 0 deletions
diff --git a/writerperfect/source/common/OdgGenerator.cxx b/writerperfect/source/common/OdgGenerator.cxx
new file mode 100644
index 000000000000..d166a09bbda5
--- /dev/null
+++ b/writerperfect/source/common/OdgGenerator.cxx
@@ -0,0 +1,1756 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * For further information visit http://libwpg.sourceforge.net
+ */
+
+#include "FilterInternal.hxx"
+
+#include "OdgGenerator.hxx"
+#include "DocumentElement.hxx"
+#include "OdfDocumentHandler.hxx"
+#include "TextRunStyle.hxx"
+#include "FontStyle.hxx"
+#include <locale.h>
+#include <math.h>
+#include <string>
+#include <map>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+// Workaround for the incapacity of draw to have multiple page
+// sizes in the same document. Once that limitation is lifted,
+// remove this
+#define MULTIPAGE_WORKAROUND 1
+
+namespace
+{
+
+static inline double getAngle(double bx, double by)
+{
+ return fmod(2*M_PI + (by > 0.0 ? 1.0 : -1.0) * acos( bx / sqrt(bx * bx + by * by) ), 2*M_PI);
+}
+
+static void getEllipticalArcBBox(double x0, double y0,
+ double rx, double ry, double phi, bool largeArc, bool sweep, double x, double y,
+ double &xmin, double &ymin, double &xmax, double &ymax)
+{
+ phi *= M_PI/180;
+ if (rx < 0.0)
+ rx *= -1.0;
+ if (ry < 0.0)
+ ry *= -1.0;
+
+ if (rx == 0.0 || ry == 0.0)
+ {
+ xmin = (x0 < x ? x0 : x);
+ xmax = (x0 > x ? x0 : x);
+ ymin = (y0 < y ? y0 : y);
+ ymax = (y0 > y ? y0 : y);
+ return;
+ }
+
+ // F.6.5.1
+ const double x1prime = cos(phi)*(x0 - x)/2 + sin(phi)*(y0 - y)/2;
+ const double y1prime = -sin(phi)*(x0 - x)/2 + cos(phi)*(y0 - y)/2;
+
+ // F.6.5.2
+ double radicant = (rx*rx*ry*ry - rx*rx*y1prime*y1prime - ry*ry*x1prime*x1prime)/(rx*rx*y1prime*y1prime + ry*ry*x1prime*x1prime);
+ double cxprime = 0.0;
+ double cyprime = 0.0;
+ if (radicant < 0.0)
+ {
+ double ratio = rx/ry;
+ radicant = y1prime*y1prime + x1prime*x1prime/(ratio*ratio);
+ if (radicant < 0.0)
+ {
+ xmin = (x0 < x ? x0 : x);
+ xmax = (x0 > x ? x0 : x);
+ ymin = (y0 < y ? y0 : y);
+ ymax = (y0 > y ? y0 : y);
+ return;
+ }
+ ry=sqrt(radicant);
+ rx=ratio*ry;
+ }
+ else
+ {
+ double factor = (largeArc==sweep ? -1.0 : 1.0)*sqrt(radicant);
+
+ cxprime = factor*rx*y1prime/ry;
+ cyprime = -factor*ry*x1prime/rx;
+ }
+
+ // F.6.5.3
+ double cx = cxprime*cos(phi) - cyprime*sin(phi) + (x0 + x)/2;
+ double cy = cxprime*sin(phi) + cyprime*cos(phi) + (y0 + y)/2;
+
+ // now compute bounding box of the whole ellipse
+
+ // Parametric equation of an ellipse:
+ // x(theta) = cx + rx*cos(theta)*cos(phi) - ry*sin(theta)*sin(phi)
+ // y(theta) = cy + rx*cos(theta)*sin(phi) + ry*sin(theta)*cos(phi)
+
+ // Compute local extrems
+ // 0 = -rx*sin(theta)*cos(phi) - ry*cos(theta)*sin(phi)
+ // 0 = -rx*sin(theta)*sin(phi) - ry*cos(theta)*cos(phi)
+
+ // Local extrems for X:
+ // theta = -atan(ry*tan(phi)/rx)
+ // and
+ // theta = M_PI -atan(ry*tan(phi)/rx)
+
+ // Local extrems for Y:
+ // theta = atan(ry/(tan(phi)*rx))
+ // and
+ // theta = M_PI + atan(ry/(tan(phi)*rx))
+
+ double txmin, txmax, tymin, tymax;
+
+ // First handle special cases
+ if (phi == 0 || phi == M_PI)
+ {
+ xmin = cx - rx;
+ txmin = getAngle(-rx, 0);
+ xmax = cx + rx;
+ txmax = getAngle(rx, 0);
+ ymin = cy - ry;
+ tymin = getAngle(0, -ry);
+ ymax = cy + ry;
+ tymax = getAngle(0, ry);
+ }
+ else if (phi == M_PI / 2.0 || phi == 3.0*M_PI/2.0)
+ {
+ xmin = cx - ry;
+ txmin = getAngle(-ry, 0);
+ xmax = cx + ry;
+ txmax = getAngle(ry, 0);
+ ymin = cy - rx;
+ tymin = getAngle(0, -rx);
+ ymax = cy + rx;
+ tymax = getAngle(0, rx);
+ }
+ else
+ {
+ txmin = -atan(ry*tan(phi)/rx);
+ txmax = M_PI - atan (ry*tan(phi)/rx);
+ xmin = cx + rx*cos(txmin)*cos(phi) - ry*sin(txmin)*sin(phi);
+ xmax = cx + rx*cos(txmax)*cos(phi) - ry*sin(txmax)*sin(phi);
+ double tmpY = cy + rx*cos(txmin)*sin(phi) + ry*sin(txmin)*cos(phi);
+ txmin = getAngle(xmin - cx, tmpY - cy);
+ tmpY = cy + rx*cos(txmax)*sin(phi) + ry*sin(txmax)*cos(phi);
+ txmax = getAngle(xmax - cx, tmpY - cy);
+
+ tymin = atan(ry/(tan(phi)*rx));
+ tymax = atan(ry/(tan(phi)*rx))+M_PI;
+ ymin = cy + rx*cos(tymin)*sin(phi) + ry*sin(tymin)*cos(phi);
+ ymax = cy + rx*cos(tymax)*sin(phi) + ry*sin(tymax)*cos(phi);
+ double tmpX = cx + rx*cos(tymin)*cos(phi) - ry*sin(tymin)*sin(phi);
+ tymin = getAngle(tmpX - cx, ymin - cy);
+ tmpX = cx + rx*cos(tymax)*cos(phi) - ry*sin(tymax)*sin(phi);
+ tymax = getAngle(tmpX - cx, ymax - cy);
+ }
+ if (xmin > xmax)
+ {
+ std::swap(xmin,xmax);
+ std::swap(txmin,txmax);
+ }
+ if (ymin > ymax)
+ {
+ std::swap(ymin,ymax);
+ std::swap(tymin,tymax);
+ }
+ double angle1 = getAngle(x0 - cx, y0 - cy);
+ double angle2 = getAngle(x - cx, y - cy);
+
+ // for sweep == 0 it is normal to have delta theta < 0
+ // but we don't care about the rotation direction for bounding box
+ if (!sweep)
+ std::swap(angle1, angle2);
+
+ // We cannot check directly for whether an angle is included in
+ // an interval of angles that cross the 360/0 degree boundary
+ // So here we will have to check for their absence in the complementary
+ // angle interval
+ bool otherArc = false;
+ if (angle1 > angle2)
+ {
+ std::swap(angle1, angle2);
+ otherArc = true;
+ }
+
+ // Check txmin
+ if ((!otherArc && (angle1 > txmin || angle2 < txmin)) || (otherArc && !(angle1 > txmin || angle2 < txmin)))
+ xmin = x0 < x ? x0 : x;
+ // Check txmax
+ if ((!otherArc && (angle1 > txmax || angle2 < txmax)) || (otherArc && !(angle1 > txmax || angle2 < txmax)))
+ xmax = x0 > x ? x0 : x;
+ // Check tymin
+ if ((!otherArc && (angle1 > tymin || angle2 < tymin)) || (otherArc && !(angle1 > tymin || angle2 < tymin)))
+ ymin = y0 < y ? y0 : y;
+ // Check tymax
+ if ((!otherArc && (angle1 > tymax || angle2 < tymax)) || (otherArc && !(angle1 > tymax || angle2 < tymax)))
+ ymax = y0 > y ? y0 : y;
+}
+
+static inline double quadraticExtreme(double t, double a, double b, double c)
+{
+ return (1.0-t)*(1.0-t)*a + 2.0*(1.0-t)*t*b + t*t*c;
+}
+
+static inline double quadraticDerivative(double a, double b, double c)
+{
+ double denominator = a - 2.0*b + c;
+ if (fabs(denominator) != 0.0)
+ return (a - b)/denominator;
+ return -1.0;
+}
+
+static void getQuadraticBezierBBox(double x0, double y0, double x1, double y1, double x, double y,
+ double &xmin, double &ymin, double &xmax, double &ymax)
+{
+ xmin = x0 < x ? x0 : x;
+ xmax = x0 > x ? x0 : x;
+ ymin = y0 < y ? y0 : y;
+ ymax = y0 > y ? y0 : y;
+
+ double t = quadraticDerivative(x0, x1, x);
+ if(t>=0 && t<=1)
+ {
+ double tmpx = quadraticExtreme(t, x0, x1, x);
+ xmin = tmpx < xmin ? tmpx : xmin;
+ xmax = tmpx > xmax ? tmpx : xmax;
+ }
+
+ t = quadraticDerivative(y0, y1, y);
+ if(t>=0 && t<=1)
+ {
+ double tmpy = quadraticExtreme(t, y0, y1, y);
+ ymin = tmpy < ymin ? tmpy : ymin;
+ ymax = tmpy > ymax ? tmpy : ymax;
+ }
+}
+
+static inline double cubicBase(double t, double a, double b, double c, double d)
+{
+ 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;
+}
+
+static void getCubicBezierBBox(double x0, double y0, double x1, double y1, double x2, double y2, double x, double y,
+ double &xmin, double &ymin, double &xmax, double &ymax)
+{
+ xmin = x0 < x ? x0 : x;
+ xmax = x0 > x ? x0 : x;
+ ymin = y0 < y ? y0 : y;
+ ymax = y0 > y ? y0 : y;
+
+ for (double t = 0.0; t <= 1.0; t+=0.01)
+ {
+ double tmpx = cubicBase(t, x0, x1, x2, x);
+ xmin = tmpx < xmin ? tmpx : xmin;
+ xmax = tmpx > xmax ? tmpx : xmax;
+ double tmpy = cubicBase(t, y0, y1, y2, y);
+ ymin = tmpy < ymin ? tmpy : ymin;
+ ymax = tmpy > ymax ? tmpy : ymax;
+ }
+}
+
+
+static WPXString doubleToString(const double value)
+{
+ WPXString tempString;
+ tempString.sprintf("%.4f", value);
+#ifndef ANDROID
+ std::string decimalPoint(localeconv()->decimal_point);
+#else
+ std::string decimalPoint(".");
+#endif
+ if (decimalPoint.empty() || (decimalPoint == "."))
+ return tempString;
+ std::string stringValue(tempString.cstr());
+ if (!stringValue.empty())
+ {
+ std::string::size_type pos;
+ while ((pos = stringValue.find(decimalPoint)) != std::string::npos)
+ stringValue.replace(pos,decimalPoint.size(),".");
+ }
+ return WPXString(stringValue.c_str());
+}
+
+} // anonymous namespace
+
+class OdgGeneratorPrivate
+{
+public:
+ OdgGeneratorPrivate(OdfDocumentHandler *pHandler, const OdfStreamType streamType);
+ ~OdgGeneratorPrivate();
+ void _writeGraphicsStyle();
+ void _drawPolySomething(const ::WPXPropertyListVector &vertices, bool isClosed);
+ void _drawPath(const WPXPropertyListVector &path);
+ // body elements
+ std::vector <DocumentElement *> mBodyElements;
+
+ // graphics styles
+ std::vector<DocumentElement *> mGraphicsStrokeDashStyles;
+ std::vector<DocumentElement *> mGraphicsGradientStyles;
+ std::vector<DocumentElement *> mGraphicsBitmapStyles;
+ std::vector<DocumentElement *> mGraphicsMarkerStyles;
+ std::vector<DocumentElement *> mGraphicsAutomaticStyles;
+
+ // page styles
+ std::vector<DocumentElement *> mPageAutomaticStyles;
+ std::vector<DocumentElement *> mPageMasterStyles;
+
+ // paragraph styles
+ ParagraphStyleManager mParagraphManager;
+
+ // span styles
+ SpanStyleManager mSpanManager;
+
+ // font styles
+ FontStyleManager mFontManager;
+
+ OdfDocumentHandler *mpHandler;
+
+ ::WPXPropertyList mxStyle;
+ ::WPXPropertyListVector mxGradient;
+ ::WPXPropertyListVector mxMarker;
+ int miGradientIndex;
+ int miBitmapIndex;
+ int miStartMarkerIndex;
+ int miEndMarkerIndex;
+ int miDashIndex;
+ int miGraphicsStyleIndex;
+ int miPageIndex;
+ double mfWidth, mfMaxWidth;
+ double mfHeight, mfMaxHeight;
+
+ const OdfStreamType mxStreamType;
+
+ bool mbIsTextBox;
+ bool mbIsTextLine;
+ bool mbIsTextOnPath;
+};
+
+OdgGeneratorPrivate::OdgGeneratorPrivate(OdfDocumentHandler *pHandler, const OdfStreamType streamType):
+ mBodyElements(),
+ mGraphicsStrokeDashStyles(),
+ mGraphicsGradientStyles(),
+ mGraphicsBitmapStyles(),
+ mGraphicsAutomaticStyles(),
+ mPageAutomaticStyles(),
+ mPageMasterStyles(),
+ mParagraphManager(),
+ mSpanManager(),
+ mFontManager(),
+ mpHandler(pHandler),
+ mxStyle(), mxGradient(),
+ mxMarker(),
+ miGradientIndex(1),
+ miBitmapIndex(1),
+ miStartMarkerIndex(1),
+ miEndMarkerIndex(1),
+ miDashIndex(1),
+ miGraphicsStyleIndex(1),
+ miPageIndex(1),
+ mfWidth(0.0),
+ mfMaxWidth(0.0),
+ mfHeight(0.0),
+ mfMaxHeight(0.0),
+ mxStreamType(streamType),
+ mbIsTextBox(false),
+ mbIsTextLine(false),
+ mbIsTextOnPath(false)
+{
+}
+
+OdgGeneratorPrivate::~OdgGeneratorPrivate()
+{
+
+ for (std::vector<DocumentElement *>::iterator iterBody = mBodyElements.begin(); iterBody != mBodyElements.end(); ++iterBody)
+ {
+ delete (*iterBody);
+ (*iterBody) = 0;
+ }
+
+ for (std::vector<DocumentElement *>::iterator iterGraphicsAutomaticStyles = mGraphicsAutomaticStyles.begin();
+ iterGraphicsAutomaticStyles != mGraphicsAutomaticStyles.end(); ++iterGraphicsAutomaticStyles)
+ {
+ delete((*iterGraphicsAutomaticStyles));
+ }
+
+ for (std::vector<DocumentElement *>::iterator iterGraphicsStrokeDashStyles = mGraphicsStrokeDashStyles.begin();
+ iterGraphicsStrokeDashStyles != mGraphicsStrokeDashStyles.end(); ++iterGraphicsStrokeDashStyles)
+ {
+ delete((*iterGraphicsStrokeDashStyles));
+ }
+
+ for (std::vector<DocumentElement *>::iterator iterGraphicsGradientStyles = mGraphicsGradientStyles.begin();
+ iterGraphicsGradientStyles != mGraphicsGradientStyles.end(); ++iterGraphicsGradientStyles)
+ {
+ delete((*iterGraphicsGradientStyles));
+ }
+
+ for (std::vector<DocumentElement *>::iterator iterGraphicsBitmapStyles = mGraphicsBitmapStyles.begin();
+ iterGraphicsBitmapStyles != mGraphicsBitmapStyles.end(); ++iterGraphicsBitmapStyles)
+ {
+ delete((*iterGraphicsBitmapStyles));
+ }
+
+ for (std::vector<DocumentElement *>::iterator iterGraphicsMarkerStyles = mGraphicsMarkerStyles.begin();
+ iterGraphicsMarkerStyles != mGraphicsMarkerStyles.end(); ++iterGraphicsMarkerStyles)
+ {
+ delete((*iterGraphicsMarkerStyles));
+ }
+
+ for (std::vector<DocumentElement *>::iterator iterPageAutomaticStyles = mPageAutomaticStyles.begin();
+ iterPageAutomaticStyles != mPageAutomaticStyles.end(); ++iterPageAutomaticStyles)
+ {
+ delete((*iterPageAutomaticStyles));
+ }
+
+ for (std::vector<DocumentElement *>::iterator iterPageMasterStyles = mPageMasterStyles.begin();
+ iterPageMasterStyles != mPageMasterStyles.end(); ++iterPageMasterStyles)
+ {
+ delete((*iterPageMasterStyles));
+ }
+
+ mParagraphManager.clean();
+ mSpanManager.clean();
+ mFontManager.clean();
+}
+
+
+OdgGenerator::OdgGenerator(OdfDocumentHandler *pHandler, const OdfStreamType streamType):
+ mpImpl(new OdgGeneratorPrivate(pHandler, streamType))
+{
+ mpImpl->mpHandler->startDocument();
+ TagOpenElement tmpOfficeDocumentContent(
+ (mpImpl->mxStreamType == ODF_FLAT_XML) ? "office:document" : (
+ (mpImpl->mxStreamType == ODF_CONTENT_XML) ? "office:document-content" : (
+ (mpImpl->mxStreamType == ODF_STYLES_XML) ? "office:document-styles" : (
+ (mpImpl->mxStreamType == ODF_SETTINGS_XML) ? "office:document-settings" : (
+ (mpImpl->mxStreamType == ODF_META_XML) ? "office:document-meta" : "office:document" )))));
+ tmpOfficeDocumentContent.addAttribute("xmlns:office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0");
+ tmpOfficeDocumentContent.addAttribute("xmlns:style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0");
+ tmpOfficeDocumentContent.addAttribute("xmlns:text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0");
+ tmpOfficeDocumentContent.addAttribute("xmlns:draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0");
+ tmpOfficeDocumentContent.addAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
+ tmpOfficeDocumentContent.addAttribute("xmlns:svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0");
+ tmpOfficeDocumentContent.addAttribute("xmlns:fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0");
+ tmpOfficeDocumentContent.addAttribute("xmlns:config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0");
+ tmpOfficeDocumentContent.addAttribute("xmlns:ooo", "http://openoffice.org/2004/office");
+ tmpOfficeDocumentContent.addAttribute("office:version", "1.0");
+ if (mpImpl->mxStreamType == ODF_FLAT_XML)
+ tmpOfficeDocumentContent.addAttribute("office:mimetype", "application/vnd.oasis.opendocument.graphics");
+ tmpOfficeDocumentContent.write(mpImpl->mpHandler);
+}
+
+OdgGenerator::~OdgGenerator()
+{
+ if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_SETTINGS_XML))
+ {
+ TagOpenElement("office:settings").write(mpImpl->mpHandler);
+
+ TagOpenElement configItemSetOpenElement("config:config-item-set");
+ configItemSetOpenElement.addAttribute("config:name", "ooo:view-settings");
+ configItemSetOpenElement.write(mpImpl->mpHandler);
+
+ TagOpenElement configItemOpenElement("config:config-item");
+
+ configItemOpenElement.addAttribute("config:name", "VisibleAreaTop");
+ configItemOpenElement.addAttribute("config:type", "int");
+ configItemOpenElement.write(mpImpl->mpHandler);
+ mpImpl->mpHandler->characters("0");
+ mpImpl->mpHandler->endElement("config:config-item");
+
+ configItemOpenElement.addAttribute("config:name", "VisibleAreaLeft");
+ configItemOpenElement.addAttribute("config:type", "int");
+ configItemOpenElement.write(mpImpl->mpHandler);
+ mpImpl->mpHandler->characters("0");
+ mpImpl->mpHandler->endElement("config:config-item");
+
+ configItemOpenElement.addAttribute("config:name", "VisibleAreaWidth");
+ configItemOpenElement.addAttribute("config:type", "int");
+ configItemOpenElement.write(mpImpl->mpHandler);
+ WPXString sWidth;
+ sWidth.sprintf("%li", (unsigned long)(2540 * mpImpl->mfMaxWidth));
+ mpImpl->mpHandler->characters(sWidth);
+ mpImpl->mpHandler->endElement("config:config-item");
+
+ configItemOpenElement.addAttribute("config:name", "VisibleAreaHeight");
+ configItemOpenElement.addAttribute("config:type", "int");
+ configItemOpenElement.write(mpImpl->mpHandler);
+ WPXString sHeight;
+ sHeight.sprintf("%li", (unsigned long)(2540 * mpImpl->mfMaxHeight));
+ mpImpl->mpHandler->characters(sHeight);
+ mpImpl->mpHandler->endElement("config:config-item");
+
+ mpImpl->mpHandler->endElement("config:config-item-set");
+
+ mpImpl->mpHandler->endElement("office:settings");
+ }
+
+
+ if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_STYLES_XML))
+ {
+ TagOpenElement("office:styles").write(mpImpl->mpHandler);
+
+ for (std::vector<DocumentElement *>::const_iterator iterGraphicsStrokeDashStyles = mpImpl->mGraphicsStrokeDashStyles.begin();
+ iterGraphicsStrokeDashStyles != mpImpl->mGraphicsStrokeDashStyles.end(); ++iterGraphicsStrokeDashStyles)
+ {
+ (*iterGraphicsStrokeDashStyles)->write(mpImpl->mpHandler);
+ }
+
+ for (std::vector<DocumentElement *>::const_iterator iterGraphicsGradientStyles = mpImpl->mGraphicsGradientStyles.begin();
+ iterGraphicsGradientStyles != mpImpl->mGraphicsGradientStyles.end(); ++iterGraphicsGradientStyles)
+ {
+ (*iterGraphicsGradientStyles)->write(mpImpl->mpHandler);
+ }
+
+ for (std::vector<DocumentElement *>::const_iterator iterGraphicsBitmapStyles = mpImpl->mGraphicsBitmapStyles.begin();
+ iterGraphicsBitmapStyles != mpImpl->mGraphicsBitmapStyles.end(); ++iterGraphicsBitmapStyles)
+ {
+ (*iterGraphicsBitmapStyles)->write(mpImpl->mpHandler);
+ }
+
+ for (std::vector<DocumentElement *>::const_iterator iterGraphicsMarkerStyles = mpImpl->mGraphicsMarkerStyles.begin();
+ iterGraphicsMarkerStyles != mpImpl->mGraphicsMarkerStyles.end(); ++iterGraphicsMarkerStyles)
+ {
+ (*iterGraphicsMarkerStyles)->write(mpImpl->mpHandler);
+ }
+ mpImpl->mpHandler->endElement("office:styles");
+ }
+
+
+ if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_CONTENT_XML) || (mpImpl->mxStreamType == ODF_STYLES_XML))
+ {
+ mpImpl->mFontManager.writeFontsDeclaration(mpImpl->mpHandler);
+
+ TagOpenElement("office:automatic-styles").write(mpImpl->mpHandler);
+ }
+
+ if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_CONTENT_XML))
+ {
+ // writing out the graphics automatic styles
+ for (std::vector<DocumentElement *>::iterator iterGraphicsAutomaticStyles = mpImpl->mGraphicsAutomaticStyles.begin();
+ iterGraphicsAutomaticStyles != mpImpl->mGraphicsAutomaticStyles.end(); ++iterGraphicsAutomaticStyles)
+ {
+ (*iterGraphicsAutomaticStyles)->write(mpImpl->mpHandler);
+ }
+ mpImpl->mParagraphManager.write(mpImpl->mpHandler);
+ mpImpl->mSpanManager.write(mpImpl->mpHandler);
+ }
+#ifdef MULTIPAGE_WORKAROUND
+ if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_STYLES_XML))
+ {
+ TagOpenElement tmpStylePageLayoutOpenElement("style:page-layout");
+ tmpStylePageLayoutOpenElement.addAttribute("style:name", "PM0");
+ tmpStylePageLayoutOpenElement.write(mpImpl->mpHandler);
+
+ TagOpenElement tmpStylePageLayoutPropertiesOpenElement("style:page-layout-properties");
+ tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-top", "0in");
+ tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-bottom", "0in");
+ tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-left", "0in");
+ tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:margin-right", "0in");
+ WPXString sValue;
+ sValue = doubleToString(mpImpl->mfMaxWidth);
+ sValue.append("in");
+ tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:page-width", sValue);
+ sValue = doubleToString(mpImpl->mfMaxHeight);
+ sValue.append("in");
+ tmpStylePageLayoutPropertiesOpenElement.addAttribute("fo:page-height", sValue);
+ tmpStylePageLayoutPropertiesOpenElement.addAttribute("style:print-orientation", "portrait");
+ tmpStylePageLayoutPropertiesOpenElement.write(mpImpl->mpHandler);
+
+ mpImpl->mpHandler->endElement("style:page-layout-properties");
+
+ mpImpl->mpHandler->endElement("style:page-layout");
+
+ TagOpenElement tmpStyleStyleOpenElement("style:style");
+ tmpStyleStyleOpenElement.addAttribute("style:name", "dp1");
+ tmpStyleStyleOpenElement.addAttribute("style:family", "drawing-page");
+ tmpStyleStyleOpenElement.write(mpImpl->mpHandler);
+
+ TagOpenElement tmpStyleDrawingPagePropertiesOpenElement("style:drawing-page-properties");
+ // tmpStyleDrawingPagePropertiesOpenElement.addAttribute("draw:background-size", "border");
+ tmpStyleDrawingPagePropertiesOpenElement.addAttribute("draw:fill", "none");
+ tmpStyleDrawingPagePropertiesOpenElement.write(mpImpl->mpHandler);
+
+ mpImpl->mpHandler->endElement("style:drawing-page-properties");
+
+ mpImpl->mpHandler->endElement("style:style");
+ }
+#else
+ if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_STYLES_XML))
+ {
+ // writing out the page automatic styles
+ for (std::vector<DocumentElement *>::iterator iterPageAutomaticStyles = mpImpl->mPageAutomaticStyles.begin();
+ iterPageAutomaticStyles != mpImpl->mPageAutomaticStyles.end(); ++iterPageAutomaticStyles)
+ {
+ (*iterPageAutomaticStyles)->write(mpImpl->mpHandler);
+ }
+ }
+#endif
+ if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_CONTENT_XML) || (mpImpl->mxStreamType == ODF_STYLES_XML))
+ {
+ mpImpl->mpHandler->endElement("office:automatic-styles");
+ }
+
+ if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_STYLES_XML))
+ {
+ TagOpenElement("office:master-styles").write(mpImpl->mpHandler);
+
+ for (std::vector<DocumentElement *>::const_iterator pageMasterIter = mpImpl->mPageMasterStyles.begin();
+ pageMasterIter != mpImpl->mPageMasterStyles.end(); ++pageMasterIter)
+ {
+ (*pageMasterIter)->write(mpImpl->mpHandler);
+ }
+ mpImpl->mpHandler->endElement("office:master-styles");
+ }
+
+ if ((mpImpl->mxStreamType == ODF_FLAT_XML) || (mpImpl->mxStreamType == ODF_CONTENT_XML))
+ {
+ TagOpenElement("office:body").write(mpImpl->mpHandler);
+
+ TagOpenElement("office:drawing").write(mpImpl->mpHandler);
+
+ for (std::vector<DocumentElement *>::const_iterator bodyIter = mpImpl->mBodyElements.begin();
+ bodyIter != mpImpl->mBodyElements.end(); ++bodyIter)
+ {
+ (*bodyIter)->write(mpImpl->mpHandler);
+ }
+
+ mpImpl->mpHandler->endElement("office:drawing");
+ mpImpl->mpHandler->endElement("office:body");
+ }
+
+ mpImpl->mpHandler->endElement(
+ (mpImpl->mxStreamType == ODF_FLAT_XML) ? "office:document" : (
+ (mpImpl->mxStreamType == ODF_CONTENT_XML) ? "office:document-content" : (
+ (mpImpl->mxStreamType == ODF_STYLES_XML) ? "office:document-styles" : (
+ (mpImpl->mxStreamType == ODF_SETTINGS_XML) ? "office:document-settings" : (
+ (mpImpl->mxStreamType == ODF_META_XML) ? "office:document-meta" : "office:document" )))));
+
+ mpImpl->mpHandler->endDocument();
+
+ if (mpImpl)
+ delete mpImpl;
+}
+
+void OdgGenerator::startGraphics(const ::WPXPropertyList &propList)
+{
+ if (propList["svg:width"])
+ {
+ mpImpl->mfWidth = propList["svg:width"]->getDouble();
+ mpImpl->mfMaxWidth = mpImpl->mfMaxWidth < mpImpl->mfWidth ? mpImpl->mfWidth : mpImpl->mfMaxWidth;
+ }
+
+ if (propList["svg:height"])
+ {
+ mpImpl->mfHeight = propList["svg:height"]->getDouble();
+ mpImpl->mfMaxHeight = mpImpl->mfMaxHeight < mpImpl->mfHeight ? mpImpl->mfHeight : mpImpl->mfMaxHeight;
+ }
+
+ TagOpenElement *pStyleMasterPageOpenElement = new TagOpenElement("style:master-page");
+
+ TagOpenElement *pDrawPageOpenElement = new TagOpenElement("draw:page");
+
+ TagOpenElement *pStylePageLayoutOpenElement = new TagOpenElement("style:page-layout");
+
+ WPXString sValue;
+ if (propList["draw:name"])
+ sValue = WPXString(propList["draw:name"]->getStr(), true); // escape special xml characters
+ else
+ sValue.sprintf("page%i", mpImpl->miPageIndex);
+ pDrawPageOpenElement->addAttribute("draw:name", sValue);
+#ifdef MULTIPAGE_WORKAROUND
+ pStyleMasterPageOpenElement->addAttribute("style:page-layout-name", "PM0");
+ pStylePageLayoutOpenElement->addAttribute("style:page-layout-name", "PM0");
+#else
+ sValue.sprintf("PM%i", mpImpl->miPageIndex);
+ pStyleMasterPageOpenElement->addAttribute("style:page-layout-name", sValue);
+ pStylePageLayoutOpenElement->addAttribute("style:name", sValue);
+#endif
+
+ mpImpl->mPageAutomaticStyles.push_back(pStylePageLayoutOpenElement);
+
+ TagOpenElement *pStylePageLayoutPropertiesOpenElement = new TagOpenElement("style:page-layout-properties");
+ pStylePageLayoutPropertiesOpenElement->addAttribute("fo:margin-top", "0in");
+ pStylePageLayoutPropertiesOpenElement->addAttribute("fo:margin-bottom", "0in");
+ pStylePageLayoutPropertiesOpenElement->addAttribute("fo:margin-left", "0in");
+ pStylePageLayoutPropertiesOpenElement->addAttribute("fo:margin-right", "0in");
+ sValue.sprintf("%s%s", doubleToString(mpImpl->mfWidth).cstr(), "in");
+ pStylePageLayoutPropertiesOpenElement->addAttribute("fo:page-width", sValue);
+ sValue.sprintf("%s%s", doubleToString(mpImpl->mfHeight).cstr(), "in");
+ pStylePageLayoutPropertiesOpenElement->addAttribute("fo:page-height", sValue);
+ pStylePageLayoutPropertiesOpenElement->addAttribute("style:print-orientation", "portrait");
+ mpImpl->mPageAutomaticStyles.push_back(pStylePageLayoutPropertiesOpenElement);
+
+ mpImpl->mPageAutomaticStyles.push_back(new TagCloseElement("style:page-layout-properties"));
+
+ mpImpl->mPageAutomaticStyles.push_back(new TagCloseElement("style:page-layout"));
+
+#ifdef MULTIPAGE_WORKAROUND
+ pDrawPageOpenElement->addAttribute("draw:style-name", "dp1");
+ pStyleMasterPageOpenElement->addAttribute("draw:style-name", "dp1");
+#else
+ sValue.sprintf("dp%i", mpImpl->miPageIndex);
+ pDrawPageOpenElement->addAttribute("draw:style-name", sValue);
+ pStyleMasterPageOpenElement->addAttribute("draw:style-name", sValue);
+#endif
+
+ TagOpenElement *pStyleStyleOpenElement = new TagOpenElement("style:style");
+ pStyleStyleOpenElement->addAttribute("style:name", sValue);
+ pStyleStyleOpenElement->addAttribute("style:family", "drawing-page");
+ mpImpl->mPageAutomaticStyles.push_back(pStyleStyleOpenElement);
+
+#ifdef MULTIPAGE_WORKAROUND
+ pDrawPageOpenElement->addAttribute("draw:master-page-name", "Default");
+ pStyleMasterPageOpenElement->addAttribute("style:name", "Default");
+#else
+ sValue.sprintf("Page%i", mpImpl->miPageIndex);
+ pDrawPageOpenElement->addAttribute("draw:master-page-name", sValue);
+ pStyleMasterPageOpenElement->addAttribute("style:name", sValue);
+#endif
+
+ mpImpl->mBodyElements.push_back(pDrawPageOpenElement);
+
+ mpImpl->mPageMasterStyles.push_back(pStyleMasterPageOpenElement);
+ mpImpl->mPageMasterStyles.push_back(new TagCloseElement("style:master-page"));
+
+
+ TagOpenElement *pStyleDrawingPagePropertiesOpenElement = new TagOpenElement("style:drawing-page-properties");
+ pStyleDrawingPagePropertiesOpenElement->addAttribute("draw:fill", "none");
+ mpImpl->mPageAutomaticStyles.push_back(pStyleDrawingPagePropertiesOpenElement);
+
+ mpImpl->mPageAutomaticStyles.push_back(new TagCloseElement("style:drawing-page-properties"));
+
+ mpImpl->mPageAutomaticStyles.push_back(new TagCloseElement("style:style"));
+}
+
+void OdgGenerator::endGraphics()
+{
+ mpImpl->mBodyElements.push_back(new TagCloseElement("draw:page"));
+ mpImpl->miPageIndex++;
+}
+
+void OdgGenerator::setStyle(const ::WPXPropertyList &propList, const ::WPXPropertyListVector &gradient)
+{
+ mpImpl->mxStyle.clear();
+ mpImpl->mxStyle = propList;
+ mpImpl->mxGradient = gradient;
+}
+
+void OdgGenerator::startLayer(const ::WPXPropertyList & /* propList */)
+{
+ mpImpl->mBodyElements.push_back(new TagOpenElement("draw:g"));
+}
+
+void OdgGenerator::endLayer()
+{
+ mpImpl->mBodyElements.push_back(new TagCloseElement("draw:g"));
+}
+
+void OdgGenerator::drawRectangle(const ::WPXPropertyList &propList)
+{
+ mpImpl->_writeGraphicsStyle();
+ TagOpenElement *pDrawRectElement = new TagOpenElement("draw:rect");
+ WPXString sValue;
+ sValue.sprintf("gr%i", mpImpl->miGraphicsStyleIndex-1);
+ pDrawRectElement->addAttribute("draw:style-name", sValue);
+ pDrawRectElement->addAttribute("svg:x", propList["svg:x"]->getStr());
+ pDrawRectElement->addAttribute("svg:y", propList["svg:y"]->getStr());
+ pDrawRectElement->addAttribute("svg:width", propList["svg:width"]->getStr());
+ pDrawRectElement->addAttribute("svg:height", propList["svg:height"]->getStr());
+ // FIXME: what to do when rx != ry ?
+ if (propList["svg:rx"])
+ pDrawRectElement->addAttribute("draw:corner-radius", propList["svg:rx"]->getStr());
+ else
+ pDrawRectElement->addAttribute("draw:corner-radius", "0.0000in");
+ mpImpl->mBodyElements.push_back(pDrawRectElement);
+ mpImpl->mBodyElements.push_back(new TagCloseElement("draw:rect"));
+}
+
+void OdgGenerator::drawEllipse(const ::WPXPropertyList &propList)
+{
+ mpImpl->_writeGraphicsStyle();
+ TagOpenElement *pDrawEllipseElement = new TagOpenElement("draw:ellipse");
+ WPXString sValue;
+ sValue.sprintf("gr%i", mpImpl->miGraphicsStyleIndex-1);
+ pDrawEllipseElement->addAttribute("draw:style-name", sValue);
+ sValue = doubleToString(2 * propList["svg:rx"]->getDouble());
+ sValue.append("in");
+ pDrawEllipseElement->addAttribute("svg:width", sValue);
+ sValue = doubleToString(2 * propList["svg:ry"]->getDouble());
+ sValue.append("in");
+ pDrawEllipseElement->addAttribute("svg:height", sValue);
+ if (propList["libwpg:rotate"] && propList["libwpg:rotate"]->getDouble() != 0.0)
+ {
+ double rotation = propList["libwpg:rotate"]->getDouble();
+ while(rotation < -180)
+ rotation += 360;
+ while(rotation > 180)
+ rotation -= 360;
+ double radrotation = rotation*M_PI/180.0;
+ double deltax = sqrt(pow(propList["svg:rx"]->getDouble(), 2.0)
+ + pow(propList["svg:ry"]->getDouble(), 2.0))*cos(atan(propList["svg:ry"]->getDouble()/propList["svg:rx"]->getDouble())
+ - radrotation ) - propList["svg:rx"]->getDouble();
+ double deltay = sqrt(pow(propList["svg:rx"]->getDouble(), 2.0)
+ + pow(propList["svg:ry"]->getDouble(), 2.0))*sin(atan(propList["svg:ry"]->getDouble()/propList["svg:rx"]->getDouble())
+ - radrotation ) - propList["svg:ry"]->getDouble();
+ sValue = "rotate(";
+ sValue.append(doubleToString(radrotation));
+ sValue.append(") ");
+ sValue.append("translate(");
+ sValue.append(doubleToString(propList["svg:cx"]->getDouble() - propList["svg:rx"]->getDouble() - deltax));
+ sValue.append("in, ");
+ sValue.append(doubleToString(propList["svg:cy"]->getDouble() - propList["svg:ry"]->getDouble() - deltay));
+ sValue.append("in)");
+ pDrawEllipseElement->addAttribute("draw:transform", sValue);
+ }
+ else
+ {
+ sValue = doubleToString(propList["svg:cx"]->getDouble()-propList["svg:rx"]->getDouble());
+ sValue.append("in");
+ pDrawEllipseElement->addAttribute("svg:x", sValue);
+ sValue = doubleToString(propList["svg:cy"]->getDouble()-propList["svg:ry"]->getDouble());
+ sValue.append("in");
+ pDrawEllipseElement->addAttribute("svg:y", sValue);
+ }
+ mpImpl->mBodyElements.push_back(pDrawEllipseElement);
+ mpImpl->mBodyElements.push_back(new TagCloseElement("draw:ellipse"));
+}
+
+void OdgGenerator::drawPolyline(const ::WPXPropertyListVector &vertices)
+{
+ mpImpl->_drawPolySomething(vertices, false);
+}
+
+void OdgGenerator::drawPolygon(const ::WPXPropertyListVector &vertices)
+{
+ mpImpl->_drawPolySomething(vertices, true);
+}
+
+void OdgGeneratorPrivate::_drawPolySomething(const ::WPXPropertyListVector &vertices, bool isClosed)
+{
+ if(vertices.count() < 2)
+ return;
+
+ if(vertices.count() == 2)
+ {
+ _writeGraphicsStyle();
+ TagOpenElement *pDrawLineElement = new TagOpenElement("draw:line");
+ WPXString sValue;
+ sValue.sprintf("gr%i", miGraphicsStyleIndex-1);
+ pDrawLineElement->addAttribute("draw:style-name", sValue);
+ pDrawLineElement->addAttribute("draw:layer", "layout");
+ pDrawLineElement->addAttribute("svg:x1", vertices[0]["svg:x"]->getStr());
+ pDrawLineElement->addAttribute("svg:y1", vertices[0]["svg:y"]->getStr());
+ pDrawLineElement->addAttribute("svg:x2", vertices[1]["svg:x"]->getStr());
+ pDrawLineElement->addAttribute("svg:y2", vertices[1]["svg:y"]->getStr());
+ mBodyElements.push_back(pDrawLineElement);
+ mBodyElements.push_back(new TagCloseElement("draw:line"));
+ }
+ else
+ {
+ ::WPXPropertyListVector path;
+ ::WPXPropertyList element;
+
+ for (unsigned long ii = 0; ii < vertices.count(); ++ii)
+ {
+ element = vertices[ii];
+ if (ii == 0)
+ element.insert("libwpg:path-action", "M");
+ else
+ element.insert("libwpg:path-action", "L");
+ path.append(element);
+ element.clear();
+ }
+ if (isClosed)
+ {
+ element.insert("libwpg:path-action", "Z");
+ path.append(element);
+ }
+ _drawPath(path);
+ }
+}
+
+void OdgGeneratorPrivate::_drawPath(const WPXPropertyListVector &path)
+{
+ if(path.count() == 0)
+ return;
+ // This must be a mistake and we do not want to crash lower
+ if(path[0]["libwpg:path-action"]->getStr() == "Z")
+ return;
+
+ // try to find the bounding box
+ // this is simple convex hull technique, the bounding box might not be
+ // accurate but that should be enough for this purpose
+ bool isFirstPoint = true;
+
+ double px = 0.0, py = 0.0, qx = 0.0, qy = 0.0;
+ double lastX = 0.0;
+ double lastY = 0.0;
+
+ for(unsigned k = 0; k < path.count(); ++k)
+ {
+ if (!path[k]["svg:x"] || !path[k]["svg:y"])
+ continue;
+ if (isFirstPoint)
+ {
+ px = path[k]["svg:x"]->getDouble();
+ py = path[k]["svg:y"]->getDouble();
+ qx = px;
+ qy = py;
+ lastX = px;
+ lastY = py;
+ isFirstPoint = false;
+ }
+ px = (px > path[k]["svg:x"]->getDouble()) ? path[k]["svg:x"]->getDouble() : px;
+ py = (py > path[k]["svg:y"]->getDouble()) ? path[k]["svg:y"]->getDouble() : py;
+ qx = (qx < path[k]["svg:x"]->getDouble()) ? path[k]["svg:x"]->getDouble() : qx;
+ qy = (qy < path[k]["svg:y"]->getDouble()) ? path[k]["svg:y"]->getDouble() : qy;
+
+ double xmin, xmax, ymin, ymax;
+
+ if(path[k]["libwpg:path-action"]->getStr() == "C")
+ {
+ getCubicBezierBBox(lastX, lastY, path[k]["svg:x1"]->getDouble(), path[k]["svg:y1"]->getDouble(),
+ path[k]["svg:x2"]->getDouble(), path[k]["svg:y2"]->getDouble(),
+ path[k]["svg:x"]->getDouble(), path[k]["svg:y"]->getDouble(), xmin, ymin, xmax, ymax);
+
+ px = (px > xmin ? xmin : px);
+ py = (py > ymin ? ymin : py);
+ qx = (qx < xmax ? xmax : qx);
+ qy = (qy < ymax ? ymax : qy);
+ }
+ if(path[k]["libwpg:path-action"]->getStr() == "Q")
+ {
+ getQuadraticBezierBBox(lastX, lastY, path[k]["svg:x1"]->getDouble(), path[k]["svg:y1"]->getDouble(),
+ path[k]["svg:x"]->getDouble(), path[k]["svg:y"]->getDouble(), xmin, ymin, xmax, ymax);
+
+ px = (px > xmin ? xmin : px);
+ py = (py > ymin ? ymin : py);
+ qx = (qx < xmax ? xmax : qx);
+ qy = (qy < ymax ? ymax : qy);
+ }
+ if(path[k]["libwpg:path-action"]->getStr() == "A")
+ {
+ getEllipticalArcBBox(lastX, lastY, path[k]["svg:rx"]->getDouble(), path[k]["svg:ry"]->getDouble(),
+ path[k]["libwpg:rotate"] ? path[k]["libwpg:rotate"]->getDouble() : 0.0,
+ path[k]["libwpg:large-arc"] ? path[k]["libwpg:large-arc"]->getInt() : 1,
+ path[k]["libwpg:sweep"] ? path[k]["libwpg:sweep"]->getInt() : 1,
+ path[k]["svg:x"]->getDouble(), path[k]["svg:y"]->getDouble(), xmin, ymin, xmax, ymax);
+
+ px = (px > xmin ? xmin : px);
+ py = (py > ymin ? ymin : py);
+ qx = (qx < xmax ? xmax : qx);
+ qy = (qy < ymax ? ymax : qy);
+ }
+ lastX = path[k]["svg:x"]->getDouble();
+ lastY = path[k]["svg:y"]->getDouble();
+ }
+
+
+ WPXString sValue;
+ _writeGraphicsStyle();
+ TagOpenElement *pDrawPathElement = new TagOpenElement("draw:path");
+ sValue.sprintf("gr%i", miGraphicsStyleIndex-1);
+ pDrawPathElement->addAttribute("draw:style-name", sValue);
+ pDrawPathElement->addAttribute("draw:layer", "layout");
+ sValue = doubleToString(px);
+ sValue.append("in");
+ pDrawPathElement->addAttribute("svg:x", sValue);
+ sValue = doubleToString(py);
+ sValue.append("in");
+ pDrawPathElement->addAttribute("svg:y", sValue);
+ sValue = doubleToString((qx - px));
+ sValue.append("in");
+ pDrawPathElement->addAttribute("svg:width", sValue);
+ sValue = doubleToString((qy - py));
+ sValue.append("in");
+ pDrawPathElement->addAttribute("svg:height", sValue);
+ sValue.sprintf("%i %i %i %i", 0, 0, (unsigned)(2540*(qx - px)), (unsigned)(2540*(qy - py)));
+ pDrawPathElement->addAttribute("svg:viewBox", sValue);
+
+ sValue.clear();
+ for(unsigned i = 0; i < path.count(); ++i)
+ {
+ WPXString sElement;
+ if (path[i]["libwpg:path-action"]->getStr() == "M")
+ {
+ // 2540 is 2.54*1000, 2.54 in = 1 inch
+ sElement.sprintf("M%i %i", (unsigned)((path[i]["svg:x"]->getDouble()-px)*2540),
+ (unsigned)((path[i]["svg:y"]->getDouble()-py)*2540));
+ sValue.append(sElement);
+ }
+ else if (path[i]["libwpg:path-action"]->getStr() == "L")
+ {
+ sElement.sprintf("L%i %i", (unsigned)((path[i]["svg:x"]->getDouble()-px)*2540),
+ (unsigned)((path[i]["svg:y"]->getDouble()-py)*2540));
+ sValue.append(sElement);
+ }
+ else if (path[i]["libwpg:path-action"]->getStr() == "C")
+ {
+ sElement.sprintf("C%i %i %i %i %i %i", (unsigned)((path[i]["svg:x1"]->getDouble()-px)*2540),
+ (unsigned)((path[i]["svg:y1"]->getDouble()-py)*2540), (unsigned)((path[i]["svg:x2"]->getDouble()-px)*2540),
+ (unsigned)((path[i]["svg:y2"]->getDouble()-py)*2540), (unsigned)((path[i]["svg:x"]->getDouble()-px)*2540),
+ (unsigned)((path[i]["svg:y"]->getDouble()-py)*2540));
+ sValue.append(sElement);
+ }
+ else if (path[i]["libwpg:path-action"]->getStr() == "Q")
+ {
+ sElement.sprintf("Q%i %i %i %i", (unsigned)((path[i]["svg:x1"]->getDouble()-px)*2540),
+ (unsigned)((path[i]["svg:y1"]->getDouble()-py)*2540), (unsigned)((path[i]["svg:x"]->getDouble()-px)*2540),
+ (unsigned)((path[i]["svg:y"]->getDouble()-py)*2540));
+ sValue.append(sElement);
+ }
+ else if (path[i]["libwpg:path-action"]->getStr() == "A")
+ {
+ sElement.sprintf("A%i %i %i %i %i %i %i", (unsigned)((path[i]["svg:rx"]->getDouble())*2540),
+ (unsigned)((path[i]["svg:ry"]->getDouble())*2540), (path[i]["libwpg:rotate"] ? path[i]["libwpg:rotate"]->getInt() : 0),
+ (path[i]["libwpg:large-arc"] ? path[i]["libwpg:large-arc"]->getInt() : 1),
+ (path[i]["libwpg:sweep"] ? path[i]["libwpg:sweep"]->getInt() : 1),
+ (unsigned)((path[i]["svg:x"]->getDouble()-px)*2540), (unsigned)((path[i]["svg:y"]->getDouble()-py)*2540));
+ sValue.append(sElement);
+ }
+ else if (path[i]["libwpg:path-action"]->getStr() == "Z")
+ sValue.append(" Z");
+ }
+ pDrawPathElement->addAttribute("svg:d", sValue);
+ mBodyElements.push_back(pDrawPathElement);
+ mBodyElements.push_back(new TagCloseElement("draw:path"));
+}
+
+void OdgGenerator::drawPath(const WPXPropertyListVector &path)
+{
+ mpImpl->_drawPath(path);
+}
+
+void OdgGenerator::drawGraphicObject(const ::WPXPropertyList &propList, const ::WPXBinaryData &binaryData)
+{
+ if (!propList["libwpg:mime-type"] || propList["libwpg:mime-type"]->getStr().len() <= 0)
+ return;
+ if (!propList["svg:x"] || !propList["svg:y"] || !propList["svg:width"] || !propList["svg:height"])
+ return;
+
+ bool flipX(propList["draw:mirror-horizontal"] && propList["draw:mirror-horizontal"]->getInt());
+ bool flipY(propList["draw:mirror-vertical"] && propList["draw:mirror-vertical"]->getInt());
+ if ((flipX && !flipY) || (!flipX && flipY))
+ mpImpl->mxStyle.insert("style:mirror", "horizontal");
+ else
+ mpImpl->mxStyle.insert("style:mirror", "none");
+ if (propList["draw:color-mode"])
+ mpImpl->mxStyle.insert("draw:color-mode", propList["draw:color-mode"]->getStr());
+ if (propList["draw:luminance"])
+ mpImpl->mxStyle.insert("draw:luminance", propList["draw:luminance"]->getStr());
+ if (propList["draw:contrast"])
+ mpImpl->mxStyle.insert("draw:contrast", propList["draw:contrast"]->getStr());
+ if (propList["draw:gamma"])
+ mpImpl->mxStyle.insert("draw:gamma", propList["draw:gamma"]->getStr());
+ if (propList["draw:red"])
+ mpImpl->mxStyle.insert("draw:red", propList["draw:red"]->getStr());
+ if (propList["draw:green"])
+ mpImpl->mxStyle.insert("draw:green", propList["draw:green"]->getStr());
+ if (propList["draw:blue"])
+ mpImpl->mxStyle.insert("draw:blue", propList["draw:blue"]->getStr());
+
+
+ mpImpl->_writeGraphicsStyle();
+
+ double x = propList["svg:x"]->getDouble();
+ double y = propList["svg:y"]->getDouble();
+ double height = propList["svg:height"]->getDouble();
+ double width = propList["svg:width"]->getDouble();
+
+ if (flipY)
+ {
+ x += width;
+ y += height;
+ width *= -1.0;
+ height *= -1.0;
+ }
+
+ double angle(propList["libwpg:rotate"] ? - M_PI * propList["libwpg:rotate"]->getDouble() / 180.0 : 0.0);
+ if (angle != 0.0)
+ {
+ double deltax((width*cos(angle)+height*sin(angle)-width)/2.0);
+ double deltay((-width*sin(angle)+height*cos(angle)-height)/2.0);
+ x -= deltax;
+ y -= deltay;
+ }
+
+ WPXPropertyList framePropList;
+
+ framePropList.insert("svg:x", x);
+ framePropList.insert("svg:y", y);
+ framePropList.insert("svg:height", height);
+ framePropList.insert("svg:width", width);
+
+ TagOpenElement *pDrawFrameElement = new TagOpenElement("draw:frame");
+
+ WPXString sValue;
+ sValue.sprintf("gr%i", mpImpl->miGraphicsStyleIndex-1);
+ pDrawFrameElement->addAttribute("draw:style-name", sValue);
+
+ pDrawFrameElement->addAttribute("svg:height", framePropList["svg:height"]->getStr());
+ pDrawFrameElement->addAttribute("svg:width", framePropList["svg:width"]->getStr());
+
+ if (angle != 0.0)
+ {
+ framePropList.insert("libwpg:rotate", angle, WPX_GENERIC);
+ sValue.sprintf("rotate (%s) translate(%s, %s)",
+ framePropList["libwpg:rotate"]->getStr().cstr(),
+ framePropList["svg:x"]->getStr().cstr(),
+ framePropList["svg:y"]->getStr().cstr());
+ pDrawFrameElement->addAttribute("draw:transform", sValue);
+ }
+ else
+ {
+ pDrawFrameElement->addAttribute("svg:x", framePropList["svg:x"]->getStr());
+ pDrawFrameElement->addAttribute("svg:y", framePropList["svg:y"]->getStr());
+ }
+ mpImpl->mBodyElements.push_back(pDrawFrameElement);
+
+ if (propList["libwpg:mime-type"]->getStr() == "object/ole")
+ mpImpl->mBodyElements.push_back(new TagOpenElement("draw:object-ole"));
+ else
+ mpImpl->mBodyElements.push_back(new TagOpenElement("draw:image"));
+
+ mpImpl->mBodyElements.push_back(new TagOpenElement("office:binary-data"));
+
+ ::WPXString base64Binary = binaryData.getBase64Data();
+ mpImpl->mBodyElements.push_back(new CharDataElement(base64Binary.cstr()));
+
+ mpImpl->mBodyElements.push_back(new TagCloseElement("office:binary-data"));
+
+ if (propList["libwpg:mime-type"]->getStr() == "object/ole")
+ mpImpl->mBodyElements.push_back(new TagCloseElement("draw:object-ole"));
+ else
+ mpImpl->mBodyElements.push_back(new TagCloseElement("draw:image"));
+
+ mpImpl->mBodyElements.push_back(new TagCloseElement("draw:frame"));
+}
+
+void OdgGeneratorPrivate::_writeGraphicsStyle()
+{
+ bool bUseOpacityGradient = false;
+
+ if (mxStyle["draw:stroke"] && mxStyle["draw:stroke"]->getStr() == "dash")
+ {
+ TagOpenElement *pDrawStrokeDashElement = new TagOpenElement("draw:stroke-dash");
+ WPXString sValue;
+ sValue.sprintf("Dash_%i", miDashIndex++);
+ pDrawStrokeDashElement->addAttribute("draw:name", sValue);
+ if (mxStyle["svg:stoke-linecap"])
+ pDrawStrokeDashElement->addAttribute("draw:style", mxStyle["svg:stroke-linecap"]->getStr());
+ else
+ pDrawStrokeDashElement->addAttribute("draw:style", "rect");
+ if (mxStyle["draw:distance"])
+ pDrawStrokeDashElement->addAttribute("draw:distance", mxStyle["draw:distance"]->getStr());
+ if (mxStyle["draw:dots1"])
+ pDrawStrokeDashElement->addAttribute("draw:dots1", mxStyle["draw:dots1"]->getStr());
+ if (mxStyle["draw:dots1-length"])
+ pDrawStrokeDashElement->addAttribute("draw:dots1-length", mxStyle["draw:dots1-length"]->getStr());
+ if (mxStyle["draw:dots2"])
+ pDrawStrokeDashElement->addAttribute("draw:dots2", mxStyle["draw:dots2"]->getStr());
+ if (mxStyle["draw:dots2-length"])
+ pDrawStrokeDashElement->addAttribute("draw:dots2-length", mxStyle["draw:dots2-length"]->getStr());
+ mGraphicsStrokeDashStyles.push_back(pDrawStrokeDashElement);
+ mGraphicsStrokeDashStyles.push_back(new TagCloseElement("draw:stroke-dash"));
+ }
+
+ if (mxStyle["draw:marker-start-path"])
+ {
+ WPXString sValue;
+ TagOpenElement *pDrawMarkerElement = new TagOpenElement("draw:marker");
+ sValue.sprintf("StartMarker_%i", miStartMarkerIndex);
+ pDrawMarkerElement->addAttribute("draw:name", sValue);
+ if (mxStyle["draw:marker-start-viewbox"])
+ pDrawMarkerElement->addAttribute("svg:viewBox", mxStyle["draw:marker-start-viewbox"]->getStr());
+ pDrawMarkerElement->addAttribute("svg:d", mxStyle["draw:marker-start-path"]->getStr());
+ mGraphicsMarkerStyles.push_back(pDrawMarkerElement);
+ mGraphicsMarkerStyles.push_back(new TagCloseElement("draw:marker"));
+ }
+ if(mxStyle["draw:marker-end-path"])
+ {
+ WPXString sValue;
+ TagOpenElement *pDrawMarkerElement = new TagOpenElement("draw:marker");
+ sValue.sprintf("EndMarker_%i", miEndMarkerIndex);
+ pDrawMarkerElement->addAttribute("draw:name", sValue);
+ if (mxStyle["draw:marker-end-viewbox"])
+ pDrawMarkerElement->addAttribute("svg:viewBox", mxStyle["draw:marker-end-viewbox"]->getStr());
+ pDrawMarkerElement->addAttribute("svg:d", mxStyle["draw:marker-end-path"]->getStr());
+ mGraphicsMarkerStyles.push_back(pDrawMarkerElement);
+ mGraphicsMarkerStyles.push_back(new TagCloseElement("draw:marker"));
+ }
+
+ if(mxStyle["draw:fill"] && mxStyle["draw:fill"]->getStr() == "gradient")
+ {
+ TagOpenElement *pDrawGradientElement = new TagOpenElement("draw:gradient");
+ TagOpenElement *pDrawOpacityElement = new TagOpenElement("draw:opacity");
+ if (mxStyle["draw:style"])
+ {
+ pDrawGradientElement->addAttribute("draw:style", mxStyle["draw:style"]->getStr());
+ pDrawOpacityElement->addAttribute("draw:style", mxStyle["draw:style"]->getStr());
+ }
+ else
+ {
+ pDrawGradientElement->addAttribute("draw:style", "linear");
+ pDrawOpacityElement->addAttribute("draw:style", "linear");
+ }
+ WPXString sValue;
+ sValue.sprintf("Gradient_%i", miGradientIndex);
+ pDrawGradientElement->addAttribute("draw:name", sValue);
+ sValue.sprintf("Transparency_%i", miGradientIndex++);
+ pDrawOpacityElement->addAttribute("draw:name", sValue);
+
+ // ODG angle unit is 0.1 degree
+ double angle = mxStyle["draw:angle"] ? mxStyle["draw:angle"]->getDouble() : 0.0;
+ while(angle < 0)
+ angle += 360;
+ while(angle > 360)
+ angle -= 360;
+ sValue.sprintf("%i", (unsigned)(angle*10));
+ pDrawGradientElement->addAttribute("draw:angle", sValue);
+ pDrawOpacityElement->addAttribute("draw:angle", sValue);
+
+ if (!mxGradient.count())
+ {
+ if (mxStyle["draw:start-color"])
+ pDrawGradientElement->addAttribute("draw:start-color", mxStyle["draw:start-color"]->getStr());
+ if (mxStyle["draw:end-color"])
+ pDrawGradientElement->addAttribute("draw:end-color", mxStyle["draw:end-color"]->getStr());
+
+ if (mxStyle["draw:border"])
+ {
+ pDrawGradientElement->addAttribute("draw:border", mxStyle["draw:border"]->getStr());
+ pDrawOpacityElement->addAttribute("draw:border", mxStyle["draw:border"]->getStr());
+ }
+ else
+ {
+ pDrawGradientElement->addAttribute("draw:border", "0%");
+ pDrawOpacityElement->addAttribute("draw:border", "0%");
+ }
+
+ if (mxStyle["svg:cx"])
+ {
+ pDrawGradientElement->addAttribute("draw:cx", mxStyle["svg:cx"]->getStr());
+ pDrawOpacityElement->addAttribute("draw:cx", mxStyle["svg:cx"]->getStr());
+ }
+ else if (mxStyle["draw:cx"])
+ {
+ pDrawGradientElement->addAttribute("draw:cx", mxStyle["draw:cx"]->getStr());
+ pDrawOpacityElement->addAttribute("draw:cx", mxStyle["draw:cx"]->getStr());
+ }
+
+ if (mxStyle["svg:cy"])
+ {
+ pDrawGradientElement->addAttribute("draw:cy", mxStyle["svg:cy"]->getStr());
+ pDrawOpacityElement->addAttribute("draw:cy", mxStyle["svg:cy"]->getStr());
+ }
+ else if (mxStyle["draw:cx"])
+ {
+ pDrawGradientElement->addAttribute("draw:cx", mxStyle["svg:cx"]->getStr());
+ pDrawOpacityElement->addAttribute("draw:cx", mxStyle["svg:cx"]->getStr());
+ }
+
+ if (mxStyle["draw:start-intensity"])
+ pDrawGradientElement->addAttribute("draw:start-intensity", mxStyle["draw:start-intensity"]->getStr());
+ else
+ pDrawGradientElement->addAttribute("draw:start-intensity", "100%");
+
+ if (mxStyle["draw:end-intensity"])
+ pDrawGradientElement->addAttribute("draw:end-intensity", mxStyle["draw:end-intensity"]->getStr());
+ else
+ pDrawGradientElement->addAttribute("draw:end-intensity", "100%");
+
+ if (mxStyle["libwpg:start-opacity"])
+ pDrawOpacityElement->addAttribute("draw:start", mxStyle["libwpg:start-opacity"]->getStr());
+ else
+ pDrawOpacityElement->addAttribute("draw:start", "100%");
+
+ if (mxStyle["libwpg:end-opacity"])
+ pDrawOpacityElement->addAttribute("draw:end", mxStyle["libwpg:end-opacity"]->getStr());
+ else
+ pDrawOpacityElement->addAttribute("draw:end", "100%");
+
+ mGraphicsGradientStyles.push_back(pDrawGradientElement);
+ mGraphicsGradientStyles.push_back(new TagCloseElement("draw:gradient"));
+
+ // Work around a mess in LibreOffice where both opacities of 100% are interpreted as complete transparency
+ // Nevertheless, when one is different, immediately, they are interpreted correctly
+ if (mxStyle["libwpg:start-opacity"] && mxStyle["libwpg:end-opacity"]
+ && (mxStyle["libwpg:start-opacity"]->getDouble() != 1.0 || mxStyle["libwpg:end-opacity"]->getDouble() != 1.0))
+ {
+ bUseOpacityGradient = true;
+ mGraphicsGradientStyles.push_back(pDrawOpacityElement);
+ mGraphicsGradientStyles.push_back(new TagCloseElement("draw:opacity"));
+ }
+ }
+ else if(mxGradient.count() >= 2)
+ {
+ sValue.sprintf("%i", (unsigned)(angle*10));
+ pDrawGradientElement->addAttribute("draw:angle", sValue);
+
+ pDrawGradientElement->addAttribute("draw:start-color", mxGradient[1]["svg:stop-color"]->getStr());
+ pDrawGradientElement->addAttribute("draw:end-color", mxGradient[0]["svg:stop-color"]->getStr());
+ if (mxStyle["svg:cx"])
+ pDrawGradientElement->addAttribute("draw:cx", mxStyle["svg:cx"]->getStr());
+ if (mxStyle["svg:cy"])
+ pDrawGradientElement->addAttribute("draw:cy", mxStyle["svg:cy"]->getStr());
+ if (mxGradient[1]["svg:stop-opacity"])
+ {
+ pDrawOpacityElement->addAttribute("draw:start", mxGradient[1]["svg:stop-opacity"]->getStr());
+ bUseOpacityGradient = true;
+ }
+ else
+ pDrawOpacityElement->addAttribute("draw:start", "100%");
+ if (mxGradient[0]["svg:stop-opacity"])
+ {
+ pDrawOpacityElement->addAttribute("draw:end", mxGradient[0]["svg:stop-opacity"]->getStr());
+ bUseOpacityGradient = true;
+ }
+ else
+ pDrawOpacityElement->addAttribute("draw:end", "100%");
+ pDrawGradientElement->addAttribute("draw:border", "0%");
+ mGraphicsGradientStyles.push_back(pDrawGradientElement);
+ mGraphicsGradientStyles.push_back(new TagCloseElement("draw:gradient"));
+ if (bUseOpacityGradient)
+ {
+ mGraphicsGradientStyles.push_back(pDrawOpacityElement);
+ mGraphicsGradientStyles.push_back(new TagCloseElement("draw:opacity"));
+ }
+ }
+ else
+ {
+ /* if mxGradient.count() == 1 for some reason we would leak
+ * pDrawGradientElement
+ */
+ delete pDrawGradientElement;
+ }
+ if(!bUseOpacityGradient)
+ delete pDrawOpacityElement;
+ }
+
+ if(mxStyle["draw:fill"] && mxStyle["draw:fill"]->getStr() == "bitmap" &&
+ mxStyle["draw:fill-image"] && mxStyle["libwpg:mime-type"])
+ {
+ TagOpenElement *pDrawBitmapElement = new TagOpenElement("draw:fill-image");
+ WPXString sValue;
+ sValue.sprintf("Bitmap_%i", miBitmapIndex++);
+ pDrawBitmapElement->addAttribute("draw:name", sValue);
+ mGraphicsBitmapStyles.push_back(pDrawBitmapElement);
+ mGraphicsBitmapStyles.push_back(new TagOpenElement("office:binary-data"));
+ mGraphicsBitmapStyles.push_back(new CharDataElement(mxStyle["draw:fill-image"]->getStr()));
+ mGraphicsBitmapStyles.push_back(new TagCloseElement("office:binary-data"));
+ mGraphicsBitmapStyles.push_back(new TagCloseElement("draw:fill-image"));
+ }
+
+ TagOpenElement *pStyleStyleElement = new TagOpenElement("style:style");
+ WPXString sValue;
+ sValue.sprintf("gr%i", miGraphicsStyleIndex);
+ pStyleStyleElement->addAttribute("style:name", sValue);
+ pStyleStyleElement->addAttribute("style:family", "graphic");
+ pStyleStyleElement->addAttribute("style:parent-style-name", "standard");
+ mGraphicsAutomaticStyles.push_back(pStyleStyleElement);
+
+ TagOpenElement *pStyleGraphicsPropertiesElement = new TagOpenElement("style:graphic-properties");
+
+ if (mxStyle["draw:color-mode"] && mxStyle["draw:color-mode"]->getStr().len() > 0)
+ pStyleGraphicsPropertiesElement->addAttribute("draw:color-mode", mxStyle["draw:color-mode"]->getStr());
+ if (mxStyle["draw:luminance"] && mxStyle["draw:luminance"]->getStr().len() > 0)
+ pStyleGraphicsPropertiesElement->addAttribute("draw:luminance", mxStyle["draw:luminance"]->getStr());
+ if (mxStyle["draw:contrast"] && mxStyle["draw:contrast"]->getStr().len() > 0)
+ pStyleGraphicsPropertiesElement->addAttribute("draw:contrast", mxStyle["draw:contrast"]->getStr());
+ if (mxStyle["draw:gamma"] && mxStyle["draw:gamma"]->getStr().len() > 0)
+ pStyleGraphicsPropertiesElement->addAttribute("draw:gamma", mxStyle["draw:gamma"]->getStr());
+ if (mxStyle["draw:red"] && mxStyle["draw:red"]->getStr().len() > 0)
+ pStyleGraphicsPropertiesElement->addAttribute("draw:red", mxStyle["draw:red"]->getStr());
+ if (mxStyle["draw:green"] && mxStyle["draw:green"]->getStr().len() > 0)
+ pStyleGraphicsPropertiesElement->addAttribute("draw:green", mxStyle["draw:green"]->getStr());
+ if (mxStyle["draw:blue"] && mxStyle["draw:blue"]->getStr().len() > 0)
+ pStyleGraphicsPropertiesElement->addAttribute("draw:blue", mxStyle["draw:blue"]->getStr());
+
+ if (mxStyle["draw:stroke"] && mxStyle["draw:stroke"]->getStr() == "none")
+ pStyleGraphicsPropertiesElement->addAttribute("draw:stroke", "none");
+ else
+ {
+ if (mxStyle["svg:stroke-width"])
+ pStyleGraphicsPropertiesElement->addAttribute("svg:stroke-width", mxStyle["svg:stroke-width"]->getStr());
+
+ if (mxStyle["svg:stroke-color"])
+ pStyleGraphicsPropertiesElement->addAttribute("svg:stroke-color", mxStyle["svg:stroke-color"]->getStr());
+
+ if (mxStyle["svg:stroke-opacity"])
+ pStyleGraphicsPropertiesElement->addAttribute("svg:stroke-opacity", mxStyle["svg:stroke-opacity"]->getStr());
+
+ if (mxStyle["svg:stroke-linejoin"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:stroke-linejoin", mxStyle["svg:stroke-linejoin"]->getStr());
+
+ if (mxStyle["svg:stroke-linecap"])
+ pStyleGraphicsPropertiesElement->addAttribute("svg:stoke-linecap", mxStyle["svg:stroke-linecap"]->getStr());
+
+ if (mxStyle["draw:stroke"] && mxStyle["draw:stroke"]->getStr() == "dash")
+ {
+ pStyleGraphicsPropertiesElement->addAttribute("draw:stroke", "dash");
+ sValue.sprintf("Dash_%i", miDashIndex-1);
+ pStyleGraphicsPropertiesElement->addAttribute("draw:stroke-dash", sValue);
+ }
+ else
+ pStyleGraphicsPropertiesElement->addAttribute("draw:stroke", "solid");
+ }
+
+ if(mxStyle["draw:fill"] && mxStyle["draw:fill"]->getStr() == "none")
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "none");
+ else
+ {
+ if (mxStyle["draw:shadow"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:shadow", mxStyle["draw:shadow"]->getStr());
+ else
+ pStyleGraphicsPropertiesElement->addAttribute("draw:shadow", "hidden");
+ if (mxStyle["draw:shadow-offset-x"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:shadow-offset-x", mxStyle["draw:shadow-offset-x"]->getStr());
+ if (mxStyle["draw:shadow-offset-y"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:shadow-offset-y", mxStyle["draw:shadow-offset-y"]->getStr());
+ if (mxStyle["draw:shadow-color"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:shadow-color", mxStyle["draw:shadow-color"]->getStr());
+ if (mxStyle["draw:shadow-opacity"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:shadow-opacity", mxStyle["draw:shadow-opacity"]->getStr());
+ if (mxStyle["svg:fill-rule"])
+ pStyleGraphicsPropertiesElement->addAttribute("svg:fill-rule", mxStyle["svg:fill-rule"]->getStr());
+ }
+
+ if(mxStyle["draw:fill"] && mxStyle["draw:fill"]->getStr() == "solid")
+ {
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "solid");
+ if (mxStyle["draw:fill-color"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill-color", mxStyle["draw:fill-color"]->getStr());
+ if (mxStyle["draw:opacity"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:opacity", mxStyle["draw:opacity"]->getStr());
+ }
+
+ if(mxStyle["draw:fill"] && mxStyle["draw:fill"]->getStr() == "gradient")
+ {
+ if (!mxGradient.count() || mxGradient.count() >= 2)
+ {
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "gradient");
+ sValue.sprintf("Gradient_%i", miGradientIndex-1);
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill-gradient-name", sValue);
+ if (bUseOpacityGradient)
+ {
+ sValue.sprintf("Transparency_%i", miGradientIndex-1);
+ pStyleGraphicsPropertiesElement->addAttribute("draw:opacity-name", sValue);
+ }
+ }
+ else
+ {
+ if (mxGradient[0]["svg:stop-color"])
+ {
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "solid");
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill-color", mxGradient[0]["svg:stop-color"]->getStr());
+ }
+ else
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "solid");
+ }
+ }
+
+ if(mxStyle["draw:fill"] && mxStyle["draw:fill"]->getStr() == "bitmap")
+ {
+ if (mxStyle["draw:fill-image"] && mxStyle["libwpg:mime-type"])
+ {
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "bitmap");
+ sValue.sprintf("Bitmap_%i", miBitmapIndex-1);
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill-image-name", sValue);
+ if (mxStyle["svg:width"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill-image-width", mxStyle["svg:width"]->getStr());
+ if (mxStyle["svg:height"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill-image-height", mxStyle["svg:height"]->getStr());
+ if (mxStyle["style:repeat"])
+ pStyleGraphicsPropertiesElement->addAttribute("style:repeat", mxStyle["style:repeat"]->getStr());
+ if (mxStyle["draw:fill-image-ref-point"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill-image-ref-point", mxStyle["draw:fill-image-ref-point"]->getStr());
+ if (mxStyle["draw:fill-image-ref-point-x"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill-image-ref-point-x", mxStyle["draw:fill-image-ref-point-x"]->getStr());
+ if (mxStyle["draw:fill-image-ref-point-y"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill-image-ref-point-y", mxStyle["draw:fill-image-ref-point-y"]->getStr());
+ }
+ else
+ pStyleGraphicsPropertiesElement->addAttribute("draw:fill", "none");
+ }
+
+
+ if(mxStyle["draw:marker-start-path"])
+ {
+ sValue.sprintf("StartMarker_%i", miStartMarkerIndex++);
+ pStyleGraphicsPropertiesElement->addAttribute("draw:marker-start", sValue);
+ if (mxStyle["draw:marker-start-width"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:marker-start-width", mxStyle["draw:marker-start-width"]->getStr());
+ else
+ pStyleGraphicsPropertiesElement->addAttribute("draw:marker-start-width", "0.118in");
+ }
+ if (mxStyle["draw:marker-end-path"])
+ {
+ sValue.sprintf("EndMarker_%i", miEndMarkerIndex++);
+ pStyleGraphicsPropertiesElement->addAttribute("draw:marker-end", sValue);
+ if (mxStyle["draw:marker-end-width"])
+ pStyleGraphicsPropertiesElement->addAttribute("draw:marker-end-width", mxStyle["draw:marker-end-width"]->getStr());
+ else
+ pStyleGraphicsPropertiesElement->addAttribute("draw:marker-end-width", "0.118in");
+ }
+ if (mxStyle["style:mirror"])
+ pStyleGraphicsPropertiesElement->addAttribute("style:mirror", mxStyle["style:mirror"]->getStr());
+
+ mGraphicsAutomaticStyles.push_back(pStyleGraphicsPropertiesElement);
+ mGraphicsAutomaticStyles.push_back(new TagCloseElement("style:graphic-properties"));
+
+ mGraphicsAutomaticStyles.push_back(new TagCloseElement("style:style"));
+ miGraphicsStyleIndex++;
+}
+
+void OdgGenerator::startEmbeddedGraphics(const WPXPropertyList &)
+{
+}
+
+void OdgGenerator::endEmbeddedGraphics()
+{
+}
+
+void OdgGenerator::startTextObject(const WPXPropertyList &propList, const WPXPropertyListVector &)
+{
+ TagOpenElement *pDrawFrameOpenElement = new TagOpenElement("draw:frame");
+ TagOpenElement *pStyleStyleOpenElement = new TagOpenElement("style:style");
+
+ WPXString sValue;
+ sValue.sprintf("gr%i", mpImpl->miGraphicsStyleIndex++);
+ pStyleStyleOpenElement->addAttribute("style:name", sValue);
+ pStyleStyleOpenElement->addAttribute("style:family", "graphic");
+ pStyleStyleOpenElement->addAttribute("style:parent-style-name", "standard");
+ mpImpl->mGraphicsAutomaticStyles.push_back(pStyleStyleOpenElement);
+
+ pDrawFrameOpenElement->addAttribute("draw:style-name", sValue);
+ pDrawFrameOpenElement->addAttribute("draw:layer", "layout");
+
+ TagOpenElement *pStyleGraphicPropertiesOpenElement = new TagOpenElement("style:graphic-properties");
+ pStyleGraphicPropertiesOpenElement->addAttribute("draw:stroke", "none");
+ pStyleGraphicPropertiesOpenElement->addAttribute("svg:stroke-color", "#000000");
+ pStyleGraphicPropertiesOpenElement->addAttribute("draw:fill", "none");
+ pStyleGraphicPropertiesOpenElement->addAttribute("draw:fill-color", "#ffffff");
+
+ double x = 0.0;
+ double y = 0.0;
+ double height = 0.0;
+ double width = 0.0;
+ if (propList["svg:x"])
+ x = propList["svg:x"]->getDouble();
+ if (propList["svg:y"])
+ y = propList["svg:y"]->getDouble();
+ if (propList["svg:width"])
+ width = propList["svg:width"]->getDouble();
+ if (propList["svg:height"])
+ height = propList["svg:height"]->getDouble();
+
+ double angle(propList["libwpg:rotate"] ? - M_PI * propList["libwpg:rotate"]->getDouble() / 180.0 : 0.0);
+ if (angle != 0.0)
+ {
+ double deltax((width*cos(angle)+height*sin(angle)-width)/2.0);
+ double deltay((-width*sin(angle)+height*cos(angle)-height)/2.0);
+ x -= deltax;
+ y -= deltay;
+ }
+
+ if (!propList["svg:width"] && !propList["svg:height"])
+ {
+ if (!propList["fo:min-width"])
+ {
+ pDrawFrameOpenElement->addAttribute("fo:min-width", "1in");
+ pStyleGraphicPropertiesOpenElement->addAttribute("fo:min-width", "1in");
+ }
+ pDrawFrameOpenElement->addAttribute("svg:width", "10in");
+ }
+ else
+ {
+ if(propList["svg:width"])
+ pDrawFrameOpenElement->addAttribute("svg:width", propList["svg:width"]->getStr());
+ if(propList["svg:height"])
+ pDrawFrameOpenElement->addAttribute("svg:height", propList["svg:height"]->getStr());
+ }
+ if (propList["fo:min-width"])
+ {
+ pDrawFrameOpenElement->addAttribute("fo:min-width", propList["fo:min-width"]->getStr());
+ pStyleGraphicPropertiesOpenElement->addAttribute("fo:min-width", propList["fo:min-width"]->getStr());
+ }
+ if (propList["fo:min-height"])
+ {
+ pDrawFrameOpenElement->addAttribute("fo:min-height", propList["fo:min-height"]->getStr());
+ pStyleGraphicPropertiesOpenElement->addAttribute("fo:min-height", propList["fo:min-height"]->getStr());
+ }
+ if (propList["fo:max-width"])
+ {
+ pDrawFrameOpenElement->addAttribute("fo:max-width", propList["fo:max-height"]->getStr());
+ pStyleGraphicPropertiesOpenElement->addAttribute("fo:max-width", propList["fo:max-width"]->getStr());
+ }
+ if (propList["fo:max-height"])
+ {
+ pDrawFrameOpenElement->addAttribute("fo:max-height", propList["fo:max-height"]->getStr());
+ pStyleGraphicPropertiesOpenElement->addAttribute("fo:max-height", propList["fo:max-height"]->getStr());
+ }
+ if (propList["fo:padding-top"])
+ {
+ pDrawFrameOpenElement->addAttribute("fo:padding-top", propList["fo:padding-top"]->getStr());
+ pStyleGraphicPropertiesOpenElement->addAttribute("fo:padding-top", propList["fo:padding-top"]->getStr());
+ }
+ if (propList["fo:padding-bottom"])
+ {
+ pDrawFrameOpenElement->addAttribute("fo:padding-bottom", propList["fo:padding-bottom"]->getStr());
+ pStyleGraphicPropertiesOpenElement->addAttribute("fo:padding-bottom", propList["fo:padding-bottom"]->getStr());
+ }
+ if (propList["fo:padding-left"])
+ {
+ pDrawFrameOpenElement->addAttribute("fo:padding-left", propList["fo:padding-left"]->getStr());
+ pStyleGraphicPropertiesOpenElement->addAttribute("fo:padding-left", propList["fo:padding-left"]->getStr());
+ }
+ if (propList["fo:padding-right"])
+ {
+ pDrawFrameOpenElement->addAttribute("fo:padding-right", propList["fo:padding-right"]->getStr());
+ pStyleGraphicPropertiesOpenElement->addAttribute("fo:padding-right", propList["fo:padding-right"]->getStr());
+ }
+ if (propList["draw:textarea-vertical-align"])
+ {
+ pDrawFrameOpenElement->addAttribute("draw:textarea-vertical-align", propList["draw:textarea-vertical-align"]->getStr());
+ pStyleGraphicPropertiesOpenElement->addAttribute("draw:textarea-vertical-align", propList["draw:textarea-vertical-align"]->getStr());
+ }
+ if (propList["draw:fill"])
+ {
+ pDrawFrameOpenElement->addAttribute("draw:fill", propList["draw:fill"]->getStr());
+ pStyleGraphicPropertiesOpenElement->addAttribute("draw:fill", propList["draw:fill"]->getStr());
+ }
+ if (propList["draw:fill-color"])
+ {
+ pDrawFrameOpenElement->addAttribute("draw:fill-color", propList["draw:fill-color"]->getStr());
+ pStyleGraphicPropertiesOpenElement->addAttribute("draw:fill-color", propList["draw:fill-color"]->getStr());
+ }
+ if (propList["draw:opacity"])
+ {
+ pDrawFrameOpenElement->addAttribute("draw:opacity", propList["draw:opacity"]->getStr());
+ pStyleGraphicPropertiesOpenElement->addAttribute("draw:opacity", propList["draw:opacity"]->getStr());
+ }
+
+ WPXProperty *svg_x = WPXPropertyFactory::newInchProp(x);
+ WPXProperty *svg_y = WPXPropertyFactory::newInchProp(y);
+ if (angle != 0.0)
+ {
+ WPXProperty *libwpg_rotate = WPXPropertyFactory::newDoubleProp(angle);
+ sValue.sprintf("rotate (%s) translate(%s, %s)",
+ libwpg_rotate->getStr().cstr(),
+ svg_x->getStr().cstr(),
+ svg_y->getStr().cstr());
+ delete libwpg_rotate;
+ pDrawFrameOpenElement->addAttribute("draw:transform", sValue);
+ }
+ else
+ {
+ if (propList["svg:x"])
+ pDrawFrameOpenElement->addAttribute("svg:x", svg_x->getStr());
+ if (propList["svg:y"])
+ pDrawFrameOpenElement->addAttribute("svg:y", svg_y->getStr());
+ }
+ delete svg_x;
+ delete svg_y;
+ mpImpl->mBodyElements.push_back(pDrawFrameOpenElement);
+ mpImpl->mBodyElements.push_back(new TagOpenElement("draw:text-box"));
+ mpImpl->mGraphicsAutomaticStyles.push_back(pStyleGraphicPropertiesOpenElement);
+ mpImpl->mGraphicsAutomaticStyles.push_back(new TagCloseElement("style:graphic-properties"));
+ mpImpl->mGraphicsAutomaticStyles.push_back(new TagCloseElement("style:style"));
+ mpImpl->mbIsTextBox = true;
+}
+
+void OdgGenerator::endTextObject()
+{
+ if (mpImpl->mbIsTextBox)
+ {
+ mpImpl->mBodyElements.push_back(new TagCloseElement("draw:text-box"));
+ mpImpl->mBodyElements.push_back(new TagCloseElement("draw:frame"));
+ mpImpl->mbIsTextBox = false;
+ }
+}
+
+void OdgGenerator::startTextLine(const WPXPropertyList &propList)
+{
+ WPXPropertyList finalPropList(propList);
+ finalPropList.insert("style:parent-style-name", "Standard");
+ WPXString paragName = mpImpl->mParagraphManager.findOrAdd(finalPropList, WPXPropertyListVector());
+
+
+ // create a document element corresponding to the paragraph, and append it to our list of document elements
+ TagOpenElement *pParagraphOpenElement = new TagOpenElement("text:p");
+ pParagraphOpenElement->addAttribute("text:style-name", paragName);
+ mpImpl->mBodyElements.push_back(pParagraphOpenElement);
+}
+
+void OdgGenerator::endTextLine()
+{
+ mpImpl->mBodyElements.push_back(new TagCloseElement("text:p"));
+}
+
+void OdgGenerator::startTextSpan(const WPXPropertyList &propList)
+{
+ if (propList["style:font-name"])
+ mpImpl->mFontManager.findOrAdd(propList["style:font-name"]->getStr().cstr());
+
+ WPXString sName = mpImpl->mSpanManager.findOrAdd(propList);
+
+ TagOpenElement *pSpanOpenElement = new TagOpenElement("text:span");
+ pSpanOpenElement->addAttribute("text:style-name", sName.cstr());
+ mpImpl->mBodyElements.push_back(pSpanOpenElement);
+}
+
+void OdgGenerator::endTextSpan()
+{
+ mpImpl->mBodyElements.push_back(new TagCloseElement("text:span"));
+}
+
+void OdgGenerator::insertText(const WPXString &text)
+{
+ WPXString out;
+ WPXString::Iter i(text);
+ for (i.rewind(); i.next();)
+ {
+ if ((*i()) == '\n' || (*i()) == '\t')
+ {
+ if (out.len() != 0)
+ {
+ DocumentElement *pText = new TextElement(out);
+ mpImpl->mBodyElements.push_back(pText);
+ out.clear();
+ }
+ if ((*i()) == '\n')
+ {
+ mpImpl->mBodyElements.push_back(new TagOpenElement("text:line-break"));
+ mpImpl->mBodyElements.push_back(new TagCloseElement("text:line-break"));
+ }
+ else if ((*i()) == '\t')
+ {
+ mpImpl->mBodyElements.push_back(new TagOpenElement("text:tab"));
+ mpImpl->mBodyElements.push_back(new TagCloseElement("text:tab"));
+ }
+ }
+ else
+ {
+ out.append(i());
+ }
+ }
+ if (out.len() != 0)
+ {
+ DocumentElement *pText = new TextElement(out);
+ mpImpl->mBodyElements.push_back(pText);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */