1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
10 #include <drawinglayer/tools/primitive2dxmldump.hxx>
11
12 #include <vcl/metaact.hxx>
13 #include <rtl/string.hxx>
14 #include <rtl/strbuf.hxx>
15 #include <tools/stream.hxx>
16 #include <tools/XmlWriter.hxx>
17
18 #include <memory>
19
20 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
21 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
22 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
23 #include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
24 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
25 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
26 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
27 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
28 #include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx>
29 #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
30 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
31 #include <drawinglayer/geometry/viewinformation2d.hxx>
32 #include <drawinglayer/attribute/lineattribute.hxx>
33 #include <drawinglayer/attribute/fontattribute.hxx>
34
35 #include <basegfx/polygon/b2dpolypolygontools.hxx>
36 #include <basegfx/polygon/b2dpolygontools.hxx>
37
38 using namespace drawinglayer::primitive2d;
39
40 namespace drawinglayer::tools
41 {
42
43 namespace
44 {
45
46 const size_t constMaxActionType = 513;
47
convertColorToString(const basegfx::BColor & rColor)48 OUString convertColorToString(const basegfx::BColor& rColor)
49 {
50 OUString aRGBString = Color(rColor).AsRGBHexString();
51 return "#" + aRGBString;
52 }
53
writePolyPolygon(::tools::XmlWriter & rWriter,const basegfx::B2DPolyPolygon & rB2DPolyPolygon)54 void writePolyPolygon(::tools::XmlWriter& rWriter, const basegfx::B2DPolyPolygon& rB2DPolyPolygon)
55 {
56 rWriter.startElement("polypolygon");
57 const basegfx::B2DRange aB2DRange(rB2DPolyPolygon.getB2DRange());
58 rWriter.attributeDouble("height", aB2DRange.getHeight());
59 rWriter.attributeDouble("width", aB2DRange.getWidth());
60 rWriter.attributeDouble("minx", aB2DRange.getMinX());
61 rWriter.attributeDouble("miny", aB2DRange.getMinY());
62 rWriter.attributeDouble("maxx", aB2DRange.getMaxX());
63 rWriter.attributeDouble("maxy", aB2DRange.getMaxY());
64 rWriter.attribute("path", basegfx::utils::exportToSvgD(rB2DPolyPolygon, true, true, false));
65
66 for (basegfx::B2DPolygon const & rPolygon : rB2DPolyPolygon)
67 {
68 rWriter.startElement("polygon");
69 for (sal_uInt32 i = 0; i <rPolygon.count(); ++i)
70 {
71 basegfx::B2DPoint const & rPoint = rPolygon.getB2DPoint(i);
72
73 rWriter.startElement("point");
74 rWriter.attribute("x", OUString::number(rPoint.getX()));
75 rWriter.attribute("y", OUString::number(rPoint.getY()));
76 rWriter.endElement();
77 }
78 rWriter.endElement();
79 }
80
81 rWriter.endElement();
82 }
83
84 } // end anonymous namespace
85
Primitive2dXmlDump()86 Primitive2dXmlDump::Primitive2dXmlDump() :
87 maFilter(constMaxActionType, false)
88 {}
89
90 Primitive2dXmlDump::~Primitive2dXmlDump() = default;
91
dump(const drawinglayer::primitive2d::Primitive2DContainer & rPrimitive2DSequence,const OUString & rStreamName)92 void Primitive2dXmlDump::dump(
93 const drawinglayer::primitive2d::Primitive2DContainer& rPrimitive2DSequence,
94 const OUString& rStreamName)
95 {
96 std::unique_ptr<SvStream> pStream;
97
98 if (rStreamName.isEmpty())
99 pStream.reset(new SvMemoryStream());
100 else
101 pStream.reset(new SvFileStream(rStreamName, StreamMode::STD_READWRITE | StreamMode::TRUNC));
102
103 ::tools::XmlWriter aWriter(pStream.get());
104 aWriter.startDocument();
105 aWriter.startElement("primitive2D");
106
107 decomposeAndWrite(rPrimitive2DSequence, aWriter);
108
109 aWriter.endElement();
110 aWriter.endDocument();
111
112 pStream->Seek(STREAM_SEEK_TO_BEGIN);
113 }
114
dumpAndParse(const drawinglayer::primitive2d::Primitive2DContainer & rPrimitive2DSequence,const OUString & rStreamName)115 xmlDocPtr Primitive2dXmlDump::dumpAndParse(
116 const drawinglayer::primitive2d::Primitive2DContainer& rPrimitive2DSequence,
117 const OUString& rStreamName)
118 {
119 std::unique_ptr<SvStream> pStream;
120
121 if (rStreamName.isEmpty())
122 pStream.reset(new SvMemoryStream());
123 else
124 pStream.reset(new SvFileStream(rStreamName, StreamMode::STD_READWRITE | StreamMode::TRUNC));
125
126 ::tools::XmlWriter aWriter(pStream.get());
127 aWriter.startDocument();
128 aWriter.startElement("primitive2D");
129
130 decomposeAndWrite(rPrimitive2DSequence, aWriter);
131
132 aWriter.endElement();
133 aWriter.endDocument();
134
135 pStream->Seek(STREAM_SEEK_TO_BEGIN);
136
137 std::size_t nSize = pStream->remainingSize();
138 std::unique_ptr<sal_uInt8[]> pBuffer(new sal_uInt8[nSize + 1]);
139 pStream->ReadBytes(pBuffer.get(), nSize);
140 pBuffer[nSize] = 0;
141
142 xmlDocPtr pDoc = xmlParseDoc(reinterpret_cast<xmlChar*>(pBuffer.get()));
143
144 return pDoc;
145 }
146
decomposeAndWrite(const drawinglayer::primitive2d::Primitive2DContainer & rPrimitive2DSequence,::tools::XmlWriter & rWriter)147 void Primitive2dXmlDump::decomposeAndWrite(
148 const drawinglayer::primitive2d::Primitive2DContainer& rPrimitive2DSequence,
149 ::tools::XmlWriter& rWriter)
150 {
151 for (size_t i = 0; i < rPrimitive2DSequence.size(); i++)
152 {
153 drawinglayer::primitive2d::Primitive2DReference xPrimitive2DReference = rPrimitive2DSequence[i];
154 const BasePrimitive2D* pBasePrimitive = dynamic_cast<const BasePrimitive2D* >(xPrimitive2DReference.get());
155 if (!pBasePrimitive)
156 continue;
157 sal_uInt32 nId = pBasePrimitive->getPrimitive2DID();
158 if (maFilter[nId])
159 continue;
160
161 OUString sCurrentElementTag = drawinglayer::primitive2d::idToString(nId);
162
163 switch (nId)
164 {
165 case PRIMITIVE2D_ID_HIDDENGEOMETRYPRIMITIVE2D:
166 {
167 const HiddenGeometryPrimitive2D& rHiddenGeometryPrimitive2D = dynamic_cast<const HiddenGeometryPrimitive2D&>(*pBasePrimitive);
168 rWriter.startElement("hiddengeometry");
169 decomposeAndWrite(rHiddenGeometryPrimitive2D.getChildren(), rWriter);
170 rWriter.endElement();
171 }
172 break;
173
174 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D:
175 {
176 const TransformPrimitive2D& rTransformPrimitive2D = dynamic_cast<const TransformPrimitive2D&>(*pBasePrimitive);
177 rWriter.startElement("transform");
178
179 basegfx::B2DHomMatrix const & rMatrix = rTransformPrimitive2D.getTransformation();
180 rWriter.attributeDouble("xy11", rMatrix.get(0,0));
181 rWriter.attributeDouble("xy12", rMatrix.get(0,1));
182 rWriter.attributeDouble("xy13", rMatrix.get(0,2));
183 rWriter.attributeDouble("xy21", rMatrix.get(1,0));
184 rWriter.attributeDouble("xy22", rMatrix.get(1,1));
185 rWriter.attributeDouble("xy23", rMatrix.get(1,2));
186 rWriter.attributeDouble("xy31", rMatrix.get(2,0));
187 rWriter.attributeDouble("xy32", rMatrix.get(2,1));
188 rWriter.attributeDouble("xy33", rMatrix.get(2,2));
189
190 decomposeAndWrite(rTransformPrimitive2D.getChildren(), rWriter);
191 rWriter.endElement();
192 }
193 break;
194
195 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D:
196 {
197 const PolyPolygonColorPrimitive2D& rPolyPolygonColorPrimitive2D = dynamic_cast<const PolyPolygonColorPrimitive2D&>(*pBasePrimitive);
198
199 rWriter.startElement("polypolygoncolor");
200 rWriter.attribute("color", convertColorToString(rPolyPolygonColorPrimitive2D.getBColor()));
201
202 const basegfx::B2DPolyPolygon& aB2DPolyPolygon(rPolyPolygonColorPrimitive2D.getB2DPolyPolygon());
203 writePolyPolygon(rWriter, aB2DPolyPolygon);
204
205 rWriter.endElement();
206 }
207 break;
208
209 case PRIMITIVE2D_ID_POLYPOLYGONSTROKEPRIMITIVE2D:
210 {
211 const PolyPolygonStrokePrimitive2D& rPolyPolygonStrokePrimitive2D = dynamic_cast<const PolyPolygonStrokePrimitive2D&>(*pBasePrimitive);
212 rWriter.startElement("polypolygonstroke");
213
214 rWriter.startElement("line");
215 const drawinglayer::attribute::LineAttribute& aLineAttribute = rPolyPolygonStrokePrimitive2D.getLineAttribute();
216 rWriter.attribute("color", convertColorToString(aLineAttribute.getColor()));
217 rWriter.attribute("width", aLineAttribute.getWidth());
218 //rWriter.attribute("linejoin", aLineAttribute.getLineJoin());
219 //rWriter.attribute("linecap", aLineAttribute.getLineCap());
220 rWriter.endElement();
221
222 //getStrokeAttribute()
223
224 writePolyPolygon(rWriter, rPolyPolygonStrokePrimitive2D.getB2DPolyPolygon());
225
226 rWriter.endElement();
227 }
228 break;
229
230 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D:
231 {
232 const PolygonHairlinePrimitive2D& rPolygonHairlinePrimitive2D = dynamic_cast<const PolygonHairlinePrimitive2D&>(*pBasePrimitive);
233 rWriter.startElement("polygonhairline");
234
235 rWriter.attribute("color", convertColorToString(rPolygonHairlinePrimitive2D.getBColor()));
236
237 rWriter.startElement("polygon");
238 rWriter.content(basegfx::utils::exportToSvgPoints(rPolygonHairlinePrimitive2D.getB2DPolygon()));
239 rWriter.endElement();
240
241
242 rWriter.endElement();
243 }
244 break;
245
246 case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D:
247 {
248 const TextSimplePortionPrimitive2D& rTextSimplePortionPrimitive2D = dynamic_cast<const TextSimplePortionPrimitive2D&>(*pBasePrimitive);
249 rWriter.startElement("textsimpleportion");
250
251 basegfx::B2DVector aScale, aTranslate;
252 double fRotate, fShearX;
253 if(rTextSimplePortionPrimitive2D.getTextTransform().decompose(aScale, aTranslate, fRotate, fShearX))
254 {
255 rWriter.attribute("height", aScale.getY());
256 }
257 rWriter.attribute("x", aTranslate.getX());
258 rWriter.attribute("y", aTranslate.getY());
259 rWriter.attribute("text", rTextSimplePortionPrimitive2D.getText());
260 rWriter.attribute("fontcolor", convertColorToString(rTextSimplePortionPrimitive2D.getFontColor()));
261
262 const drawinglayer::attribute::FontAttribute& aFontAttribute = rTextSimplePortionPrimitive2D.getFontAttribute();
263 rWriter.attribute("familyname", aFontAttribute.getFamilyName());
264 rWriter.endElement();
265 }
266 break;
267
268 case PRIMITIVE2D_ID_MASKPRIMITIVE2D:
269 {
270 const MaskPrimitive2D& rMaskPrimitive2D = dynamic_cast<const MaskPrimitive2D&>(*pBasePrimitive);
271 rWriter.startElement("mask");
272 writePolyPolygon(rWriter, rMaskPrimitive2D.getMask());
273 decomposeAndWrite(rMaskPrimitive2D.getChildren(), rWriter);
274 rWriter.endElement();
275 }
276 break;
277
278 case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D:
279 {
280 const UnifiedTransparencePrimitive2D& rUnifiedTransparencePrimitive2D = dynamic_cast<const UnifiedTransparencePrimitive2D&>(*pBasePrimitive);
281 rWriter.startElement("unifiedtransparence");
282 rWriter.attribute("transparence", OString::number(rUnifiedTransparencePrimitive2D.getTransparence()));
283 decomposeAndWrite(rUnifiedTransparencePrimitive2D.getChildren(), rWriter);
284
285 rWriter.endElement();
286 }
287 break;
288
289 case PRIMITIVE2D_ID_OBJECTINFOPRIMITIVE2D:
290 {
291 const ObjectInfoPrimitive2D& rObjectInfoPrimitive2D = dynamic_cast<const ObjectInfoPrimitive2D&>(*pBasePrimitive);
292 rWriter.startElement("objectinfo");
293
294 decomposeAndWrite(rObjectInfoPrimitive2D.getChildren(), rWriter);
295 rWriter.endElement();
296 }
297 break;
298
299 case PRIMITIVE2D_ID_SVGRADIALGRADIENTPRIMITIVE2D:
300 {
301 const SvgRadialGradientPrimitive2D& rSvgRadialGradientPrimitive2D = dynamic_cast<const SvgRadialGradientPrimitive2D&>(*pBasePrimitive);
302 rWriter.startElement("svgradialgradient");
303 basegfx::B2DPoint aFocusAttribute = rSvgRadialGradientPrimitive2D.getFocal();
304
305 rWriter.attribute("radius", OString::number(rSvgRadialGradientPrimitive2D.getRadius()));
306 rWriter.attribute("focusx", aFocusAttribute.getX());
307 rWriter.attribute("focusy", aFocusAttribute.getY());
308
309 rWriter.endElement();
310 }
311 break;
312
313 case PRIMITIVE2D_ID_SVGLINEARGRADIENTPRIMITIVE2D:
314 {
315 const SvgLinearGradientPrimitive2D& rSvgLinearGradientPrimitive2D = dynamic_cast<const SvgLinearGradientPrimitive2D&>(*pBasePrimitive);
316 rWriter.startElement("svglineargradient");
317 basegfx::B2DPoint aEndAttribute = rSvgLinearGradientPrimitive2D.getEnd();
318
319 rWriter.attribute("endx", aEndAttribute.getX());
320 rWriter.attribute("endy", aEndAttribute.getY());
321
322 rWriter.endElement();
323 }
324 break;
325
326 case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D:
327 {
328 const MetafilePrimitive2D& rMetafilePrimitive2D = dynamic_cast<const MetafilePrimitive2D&>(*pBasePrimitive);
329 rWriter.startElement("metafile");
330 drawinglayer::primitive2d::Primitive2DContainer aPrimitiveContainer;
331 // since the graphic is not rendered in a document, we do not need a concrete view information
332 rMetafilePrimitive2D.get2DDecomposition(aPrimitiveContainer, drawinglayer::geometry::ViewInformation2D());
333 decomposeAndWrite(aPrimitiveContainer,rWriter);
334 rWriter.endElement();
335 }
336
337 break;
338
339 default:
340 {
341 rWriter.element(OUStringToOString(sCurrentElementTag, RTL_TEXTENCODING_UTF8));
342 }
343 break;
344 }
345
346 }
347 }
348
349 } // end namespace drawinglayer::tools
350
351 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
352