Line data Source code
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 <rtfsdrimport.hxx>
11 : #include <com/sun/star/container/XNamed.hpp>
12 : #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
13 : #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
14 : #include <com/sun/star/drawing/LineStyle.hpp>
15 : #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
16 : #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
17 : #include <com/sun/star/lang/XServiceInfo.hpp>
18 : #include <com/sun/star/table/BorderLine2.hpp>
19 : #include <com/sun/star/text/HoriOrientation.hpp>
20 : #include <com/sun/star/text/RelOrientation.hpp>
21 : #include <com/sun/star/text/SizeType.hpp>
22 : #include <com/sun/star/text/VertOrientation.hpp>
23 : #include <com/sun/star/text/WrapTextMode.hpp>
24 : #include <com/sun/star/text/WritingMode.hpp>
25 : #include <com/sun/star/text/TextContentAnchorType.hpp>
26 : #include <ooxml/resourceids.hxx>
27 : #include <filter/msfilter/util.hxx>
28 : #include <svx/svdtrans.hxx>
29 : #include <comphelper/sequence.hxx>
30 : #include <rtfreferenceproperties.hxx>
31 : #include <oox/vml/vmlformatting.hxx>
32 : #include <oox/helper/modelobjecthelper.hxx>
33 : #include <oox/drawingml/shapepropertymap.hxx>
34 : #include <oox/helper/propertyset.hxx>
35 : #include <boost/logic/tribool.hpp>
36 :
37 : using namespace com::sun::star;
38 :
39 : namespace writerfilter
40 : {
41 : namespace rtftok
42 : {
43 :
44 504 : RTFSdrImport::RTFSdrImport(RTFDocumentImpl& rDocument,
45 : uno::Reference<lang::XComponent> const& xDstDoc)
46 : : m_rImport(rDocument)
47 : , m_bTextFrame(false)
48 : , m_bTextGraphicObject(false)
49 504 : , m_bFakePict(false)
50 : {
51 504 : uno::Reference<drawing::XDrawPageSupplier> xDrawings(xDstDoc, uno::UNO_QUERY);
52 504 : if (xDrawings.is())
53 478 : m_aParents.push(xDrawings->getDrawPage());
54 504 : }
55 :
56 1512 : RTFSdrImport::~RTFSdrImport()
57 : {
58 504 : if (m_aParents.size())
59 478 : m_aParents.pop();
60 1008 : }
61 :
62 109 : void RTFSdrImport::createShape(const OUString& aStr, uno::Reference<drawing::XShape>& xShape, uno::Reference<beans::XPropertySet>& xPropertySet)
63 : {
64 109 : if (m_rImport.getModelFactory().is())
65 100 : xShape.set(m_rImport.getModelFactory()->createInstance(aStr), uno::UNO_QUERY);
66 109 : xPropertySet.set(xShape, uno::UNO_QUERY);
67 109 : }
68 :
69 48 : std::vector<beans::PropertyValue> RTFSdrImport::getTextFrameDefaults(bool bNew)
70 : {
71 48 : std::vector<beans::PropertyValue> aRet;
72 96 : beans::PropertyValue aPropertyValue;
73 :
74 48 : aPropertyValue.Name = "HoriOrient";
75 48 : aPropertyValue.Value <<= text::HoriOrientation::NONE;
76 48 : aRet.push_back(aPropertyValue);
77 48 : aPropertyValue.Name = "HoriOrientRelation";
78 48 : aPropertyValue.Value <<= text::RelOrientation::FRAME;
79 48 : aRet.push_back(aPropertyValue);
80 48 : aPropertyValue.Name = "VertOrient";
81 48 : aPropertyValue.Value <<= text::VertOrientation::NONE;
82 48 : aRet.push_back(aPropertyValue);
83 48 : aPropertyValue.Name = "VertOrientRelation";
84 48 : aPropertyValue.Value <<= text::RelOrientation::FRAME;
85 48 : aRet.push_back(aPropertyValue);
86 48 : if (!bNew)
87 : {
88 13 : aPropertyValue.Name = "BackColorTransparency";
89 13 : aPropertyValue.Value <<= sal_Int32(100);
90 13 : aRet.push_back(aPropertyValue);
91 : }
92 : // See the spec, new-style frame default margins are specified in EMUs.
93 48 : aPropertyValue.Name = "LeftBorderDistance";
94 48 : aPropertyValue.Value <<= sal_Int32(bNew ? (91440 / 360) : 0);
95 48 : aRet.push_back(aPropertyValue);
96 48 : aPropertyValue.Name = "RightBorderDistance";
97 48 : aPropertyValue.Value <<= sal_Int32(bNew ? (91440 / 360) : 0);
98 48 : aRet.push_back(aPropertyValue);
99 48 : aPropertyValue.Name = "TopBorderDistance";
100 48 : aPropertyValue.Value <<= sal_Int32(bNew ? (45720 / 360) : 0);
101 48 : aRet.push_back(aPropertyValue);
102 48 : aPropertyValue.Name = "BottomBorderDistance";
103 48 : aPropertyValue.Value <<= sal_Int32(bNew ? (45720 / 360) : 0);
104 48 : aRet.push_back(aPropertyValue);
105 48 : aPropertyValue.Name = "SizeType";
106 48 : aPropertyValue.Value <<= text::SizeType::FIX;
107 48 : aRet.push_back(aPropertyValue);
108 96 : return aRet;
109 : }
110 :
111 6 : void RTFSdrImport::pushParent(uno::Reference<drawing::XShapes> const& xParent)
112 : {
113 6 : m_aParents.push(xParent);
114 6 : }
115 :
116 6 : void RTFSdrImport::popParent()
117 : {
118 6 : m_aParents.pop();
119 6 : }
120 :
121 85 : void RTFSdrImport::resolveDhgt(uno::Reference<beans::XPropertySet> const& xPropertySet,
122 : sal_Int32 const nZOrder, bool const bOldStyle)
123 : {
124 85 : xPropertySet->setPropertyValue("ZOrder", uno::makeAny(m_aGraphicZOrderHelper.findZOrder(nZOrder, bOldStyle)));
125 85 : m_aGraphicZOrderHelper.addItem(xPropertySet, nZOrder);
126 85 : }
127 :
128 110 : void RTFSdrImport::resolveLineColorAndWidth(bool bTextFrame, const uno::Reference<beans::XPropertySet>& xPropertySet, uno::Any& rLineColor, uno::Any& rLineWidth)
129 : {
130 110 : if (!bTextFrame)
131 : {
132 74 : xPropertySet->setPropertyValue("LineColor", rLineColor);
133 74 : xPropertySet->setPropertyValue("LineWidth", rLineWidth);
134 : }
135 : else
136 : {
137 : static const char* aBorders[] =
138 : {
139 : "TopBorder", "LeftBorder", "BottomBorder", "RightBorder"
140 : };
141 180 : for (unsigned int i = 0; i < SAL_N_ELEMENTS(aBorders); ++i)
142 : {
143 144 : table::BorderLine2 aBorderLine = xPropertySet->getPropertyValue(OUString::createFromAscii(aBorders[i])).get<table::BorderLine2>();
144 144 : if (rLineColor.hasValue())
145 144 : aBorderLine.Color = rLineColor.get<sal_Int32>();
146 144 : if (rLineWidth.hasValue())
147 140 : aBorderLine.LineWidth = rLineWidth.get<sal_Int32>();
148 144 : xPropertySet->setPropertyValue(OUString::createFromAscii(aBorders[i]), uno::makeAny(aBorderLine));
149 : }
150 : }
151 110 : }
152 :
153 43 : void RTFSdrImport::resolveFLine(uno::Reference<beans::XPropertySet> const& xPropertySet,
154 : sal_Int32 const nFLine)
155 : {
156 43 : if (nFLine == 0)
157 26 : xPropertySet->setPropertyValue("LineStyle", uno::makeAny(drawing::LineStyle_NONE));
158 : else
159 17 : xPropertySet->setPropertyValue("LineStyle", uno::makeAny(drawing::LineStyle_SOLID));
160 43 : }
161 :
162 58 : void RTFSdrImport::applyProperty(uno::Reference<drawing::XShape> const& xShape, const OUString& aKey, const OUString& aValue)
163 : {
164 58 : uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
165 58 : sal_Int16 nHoriOrient = 0;
166 58 : sal_Int16 nVertOrient = 0;
167 58 : boost::logic::tribool obFitShapeToText(boost::logic::indeterminate);
168 58 : bool bFilled = true;
169 :
170 58 : if (aKey == "posh")
171 : {
172 11 : switch (aValue.toInt32())
173 : {
174 : case 1:
175 0 : nHoriOrient = text::HoriOrientation::LEFT;
176 0 : break;
177 : case 2:
178 10 : nHoriOrient = text::HoriOrientation::CENTER;
179 10 : break;
180 : case 3:
181 0 : nHoriOrient = text::HoriOrientation::RIGHT;
182 0 : break;
183 : case 4:
184 0 : nHoriOrient = text::HoriOrientation::INSIDE;
185 0 : break;
186 : case 5:
187 0 : nHoriOrient = text::HoriOrientation::OUTSIDE;
188 0 : break;
189 : default:
190 1 : break;
191 : }
192 : }
193 47 : else if (aKey == "posv")
194 : {
195 5 : switch (aValue.toInt32())
196 : {
197 : case 1:
198 2 : nVertOrient = text::VertOrientation::TOP;
199 2 : break;
200 : case 2:
201 2 : nVertOrient = text::VertOrientation::CENTER;
202 2 : break;
203 : case 3:
204 0 : nVertOrient = text::VertOrientation::BOTTOM;
205 0 : break;
206 : default:
207 1 : break;
208 : }
209 : }
210 42 : else if (aKey == "fFitShapeToText")
211 11 : obFitShapeToText = aValue.toInt32() == 1;
212 31 : else if (aKey == "fFilled")
213 28 : bFilled = aValue.toInt32() == 1;
214 3 : else if (aKey == "rotation")
215 : {
216 : // See DffPropertyReader::Fix16ToAngle(): in RTF, positive rotation angles are clockwise, we have them as counter-clockwise.
217 : // Additionally, RTF type is 0..360*2^16, our is 0..360*100.
218 3 : sal_Int32 nRotation = aValue.toInt32()*100/65536;
219 3 : uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY);
220 3 : if (!xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
221 2 : xPropertySet->setPropertyValue("RotateAngle", uno::makeAny(sal_Int32(NormAngle360(nRotation * -1))));
222 : }
223 :
224 58 : if (nHoriOrient != 0 && xPropertySet.is())
225 9 : xPropertySet->setPropertyValue("HoriOrient", uno::makeAny(nHoriOrient));
226 58 : if (nVertOrient != 0 && xPropertySet.is())
227 3 : xPropertySet->setPropertyValue("VertOrient", uno::makeAny(nVertOrient));
228 58 : if (!boost::logic::indeterminate(obFitShapeToText) && xPropertySet.is())
229 : {
230 7 : xPropertySet->setPropertyValue("SizeType", uno::makeAny(obFitShapeToText ? text::SizeType::MIN : text::SizeType::FIX));
231 7 : xPropertySet->setPropertyValue("FrameIsAutomaticHeight", uno::makeAny(static_cast<bool>(obFitShapeToText)));
232 : }
233 58 : if (!bFilled && xPropertySet.is())
234 : {
235 14 : if (m_bTextFrame)
236 5 : xPropertySet->setPropertyValue("BackColorTransparency", uno::makeAny(sal_Int32(100)));
237 : else
238 9 : xPropertySet->setPropertyValue("FillStyle", uno::makeAny(drawing::FillStyle_NONE));
239 58 : }
240 58 : }
241 :
242 109 : int RTFSdrImport::initShape(uno::Reference<drawing::XShape>& o_xShape,
243 : uno::Reference<beans::XPropertySet>& o_xPropSet,
244 : bool& o_rIsCustomShape,
245 : RTFShape const& rShape, bool const bClose, ShapeOrPict const shapeOrPict)
246 : {
247 : assert(!o_xShape.is());
248 : assert(!o_xPropSet.is());
249 109 : o_rIsCustomShape = false;
250 109 : m_bFakePict = false;
251 :
252 : // first, find the shape type
253 109 : int nType = -1;
254 270 : auto iter = std::find_if(rShape.aProperties.begin(), rShape.aProperties.end(), [](std::pair<OUString, OUString> aProperty)
255 : {
256 270 : return aProperty.first == "shapeType";
257 379 : });
258 :
259 109 : if (iter == rShape.aProperties.end())
260 : {
261 7 : if (SHAPE == shapeOrPict)
262 : {
263 : // The spec doesn't state what is the default for shapeType,
264 : // Word seems to implement it as a rectangle.
265 5 : nType = ESCHER_ShpInst_Rectangle;
266 : }
267 : else
268 : {
269 : // pict is picture by default but can be a rectangle too fdo#79319
270 2 : nType = ESCHER_ShpInst_PictureFrame;
271 : }
272 : }
273 : else
274 : {
275 102 : nType = iter->second.toInt32();
276 102 : if (PICT == shapeOrPict && ESCHER_ShpInst_PictureFrame != nType)
277 : {
278 2 : m_bFakePict = true;
279 : }
280 : }
281 :
282 109 : switch (nType)
283 : {
284 : case ESCHER_ShpInst_PictureFrame:
285 27 : createShape("com.sun.star.drawing.GraphicObjectShape", o_xShape, o_xPropSet);
286 27 : m_bTextGraphicObject = true;
287 27 : break;
288 : case ESCHER_ShpInst_Line:
289 6 : createShape("com.sun.star.drawing.LineShape", o_xShape, o_xPropSet);
290 6 : break;
291 : case ESCHER_ShpInst_Rectangle:
292 : case ESCHER_ShpInst_TextBox:
293 : // If we're inside a groupshape, can't use text frames.
294 64 : if (!bClose && m_aParents.size() == 1)
295 : {
296 35 : createShape("com.sun.star.text.TextFrame", o_xShape, o_xPropSet);
297 35 : m_bTextFrame = true;
298 35 : std::vector<beans::PropertyValue> aDefaults = getTextFrameDefaults(true);
299 350 : for (size_t j = 0; j < aDefaults.size(); ++j)
300 315 : o_xPropSet->setPropertyValue(aDefaults[j].Name, aDefaults[j].Value);
301 35 : break;
302 : }
303 : // fall-through intended
304 : default:
305 41 : createShape("com.sun.star.drawing.CustomShape", o_xShape, o_xPropSet);
306 41 : o_rIsCustomShape = true;
307 41 : break;
308 : }
309 :
310 : // Defaults
311 109 : if (o_xPropSet.is() && !m_bTextFrame)
312 : {
313 65 : o_xPropSet->setPropertyValue("FillColor", uno::makeAny(sal_uInt32(0xffffff))); // White in Word, kind of blue in Writer.
314 : }
315 :
316 109 : return nType;
317 : }
318 :
319 109 : void RTFSdrImport::resolve(RTFShape& rShape, bool bClose, ShapeOrPict const shapeOrPict)
320 : {
321 109 : bool bPib = false;
322 109 : m_bTextFrame = false;
323 109 : m_bTextGraphicObject = false;
324 :
325 109 : uno::Reference<drawing::XShape> xShape;
326 190 : uno::Reference<beans::XPropertySet> xPropertySet;
327 190 : uno::Any aAny;
328 190 : beans::PropertyValue aPropertyValue;
329 109 : awt::Rectangle aViewBox;
330 190 : std::vector<beans::PropertyValue> aPath;
331 : // Default line color is black in Word, blue in Writer.
332 190 : uno::Any aLineColor = uno::makeAny(COL_BLACK);
333 : // Default line width is 0.75 pt (26 mm100) in Word, 0 in Writer.
334 190 : uno::Any aLineWidth = uno::makeAny(sal_Int32(26));
335 109 : text::WritingMode eWritingMode = text::WritingMode_LR_TB;
336 : // Groupshape support
337 190 : boost::optional<sal_Int32> oGroupLeft, oGroupTop, oGroupRight, oGroupBottom;
338 190 : boost::optional<sal_Int32> oRelLeft, oRelTop, oRelRight, oRelBottom;
339 :
340 : // Importing these are not trivial, let the VML import do the hard work.
341 190 : oox::vml::FillModel aFillModel; // Gradient.
342 190 : oox::vml::ShadowModel aShadowModel; // Shadow.
343 :
344 109 : bool bOpaque = true;
345 :
346 190 : boost::optional<sal_Int16> oRelativeWidth, oRelativeHeight;
347 109 : sal_Int16 nRelativeWidthRelation = text::RelOrientation::PAGE_FRAME;
348 109 : sal_Int16 nRelativeHeightRelation = text::RelOrientation::PAGE_FRAME;
349 :
350 109 : bool bCustom(false);
351 109 : int const nType = initShape(xShape, xPropertySet, bCustom, rShape, bClose, shapeOrPict);
352 :
353 3204 : for (std::vector< std::pair<OUString, OUString> >::iterator i = rShape.aProperties.begin();
354 2136 : i != rShape.aProperties.end(); ++i)
355 : {
356 959 : if (i->first == "shapeType")
357 : {
358 103 : continue; // ignore: already handled by initShape
359 : }
360 856 : else if (i->first == "wzName")
361 : {
362 14 : if (m_bTextFrame)
363 : {
364 0 : uno::Reference<container::XNamed> xNamed(xShape, uno::UNO_QUERY);
365 0 : xNamed->setName(i->second);
366 : }
367 : else
368 14 : xPropertySet->setPropertyValue("Name", uno::makeAny(i->second));
369 : }
370 842 : else if (i->first == "wzDescription")
371 19 : xPropertySet->setPropertyValue("Description", uno::makeAny(i->second));
372 823 : else if (i->first == "pib")
373 : {
374 22 : m_rImport.setDestinationText(i->second);
375 22 : bPib = true;
376 : }
377 801 : else if (i->first == "fillColor" && xPropertySet.is())
378 : {
379 26 : aAny <<= msfilter::util::BGRToRGB(i->second.toUInt32());
380 26 : if (m_bTextFrame)
381 10 : xPropertySet->setPropertyValue("BackColor", aAny);
382 : else
383 16 : xPropertySet->setPropertyValue("FillColor", aAny);
384 :
385 : // fillType will decide, possible it'll be the start color of a gradient.
386 26 : aFillModel.moColor.set("#" + OUString::fromUtf8(msfilter::util::ConvertColor(aAny.get<sal_Int32>())));
387 : }
388 775 : else if (i->first == "fillBackColor")
389 : // fillType will decide, possible it'll be the end color of a gradient.
390 10 : aFillModel.moColor2.set("#" + OUString::fromUtf8(msfilter::util::ConvertColor(msfilter::util::BGRToRGB(i->second.toInt32()))));
391 765 : else if (i->first == "lineColor")
392 26 : aLineColor <<= msfilter::util::BGRToRGB(i->second.toInt32());
393 739 : else if (i->first == "lineBackColor")
394 : ; // Ignore: complementer of lineColor
395 735 : else if (i->first == "txflTextFlow" && xPropertySet.is())
396 : {
397 3 : if (i->second.toInt32() == 1)
398 0 : eWritingMode = text::WritingMode_TB_RL;
399 : }
400 732 : else if (i->first == "fLine" && xPropertySet.is())
401 17 : resolveFLine(xPropertySet, i->second.toInt32());
402 715 : else if (i->first == "fillOpacity" && xPropertySet.is())
403 : {
404 0 : int opacity = 100 - (i->second.toInt32())*100/65536;
405 0 : aAny <<= uno::makeAny(sal_uInt32(opacity));
406 0 : xPropertySet->setPropertyValue("FillTransparence", aAny);
407 : }
408 715 : else if (i->first == "lineWidth")
409 25 : aLineWidth <<= i->second.toInt32()/360;
410 690 : else if (i->first == "pVerticies")
411 : {
412 5 : std::vector<drawing::EnhancedCustomShapeParameterPair> aCoordinates;
413 5 : sal_Int32 nSize = 0; // Size of a token (its value is hardwired in the exporter)
414 5 : sal_Int32 nCount = 0; // Number of tokens
415 5 : sal_Int32 nCharIndex = 0; // Character index
416 140 : do
417 : {
418 140 : OUString aToken = i->second.getToken(0, ';', nCharIndex);
419 140 : if (!nSize)
420 5 : nSize = aToken.toInt32();
421 135 : else if (!nCount)
422 5 : nCount = aToken.toInt32();
423 130 : else if (aToken.getLength())
424 : {
425 : // The coordinates are in an (x,y) form.
426 130 : aToken = aToken.copy(1, aToken.getLength() - 2);
427 130 : sal_Int32 nI = 0;
428 130 : boost::optional<sal_Int32> oX;
429 260 : boost::optional<sal_Int32> oY;
430 260 : do
431 : {
432 260 : OUString aPoint = aToken.getToken(0, ',', nI);
433 260 : if (!oX)
434 130 : oX.reset(aPoint.toInt32());
435 : else
436 130 : oY.reset(aPoint.toInt32());
437 : }
438 260 : while (nI >= 0);
439 260 : drawing::EnhancedCustomShapeParameterPair aPair;
440 130 : aPair.First.Value <<= *oX;
441 130 : aPair.Second.Value <<= *oY;
442 260 : aCoordinates.push_back(aPair);
443 140 : }
444 : }
445 140 : while (nCharIndex >= 0);
446 5 : aPropertyValue.Name = "Coordinates";
447 5 : aPropertyValue.Value <<= comphelper::containerToSequence(aCoordinates);
448 5 : aPath.push_back(aPropertyValue);
449 : }
450 685 : else if (i->first == "pSegmentInfo")
451 : {
452 5 : std::vector<drawing::EnhancedCustomShapeSegment> aSegments;
453 5 : sal_Int32 nSize = 0;
454 5 : sal_Int32 nCount = 0;
455 5 : sal_Int32 nCharIndex = 0;
456 41 : do
457 : {
458 41 : sal_Int32 nSeg = i->second.getToken(0, ';', nCharIndex).toInt32();
459 41 : if (!nSize)
460 5 : nSize = nSeg;
461 36 : else if (!nCount)
462 5 : nCount = nSeg;
463 : else
464 : {
465 31 : sal_Int32 nPoints = 1;
466 31 : if (nSeg >= 0x2000 && nSeg < 0x20FF)
467 : {
468 6 : nPoints = nSeg & 0x0FFF;
469 6 : nSeg &= 0xFF00;
470 : }
471 :
472 31 : drawing::EnhancedCustomShapeSegment aSegment;
473 31 : switch (nSeg)
474 : {
475 : case 0x0001: // lineto
476 3 : aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::LINETO;
477 3 : aSegment.Count = sal_Int32(1);
478 3 : aSegments.push_back(aSegment);
479 3 : break;
480 : case 0x4000: // moveto
481 7 : aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::MOVETO;
482 7 : aSegment.Count = sal_Int32(1);
483 7 : aSegments.push_back(aSegment);
484 7 : break;
485 : case 0x2000: // curveto
486 6 : aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::CURVETO;
487 6 : aSegment.Count = sal_Int32(nPoints);
488 6 : aSegments.push_back(aSegment);
489 6 : break;
490 : case 0xb300: // arcto
491 0 : aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::ARCTO;
492 0 : aSegment.Count = sal_Int32(0);
493 0 : aSegments.push_back(aSegment);
494 0 : break;
495 : case 0xac00:
496 : case 0xaa00: // nofill
497 : case 0xab00: // nostroke
498 : case 0x6001: // close
499 3 : break;
500 : case 0x8000: // end
501 7 : aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
502 7 : aSegment.Count = sal_Int32(0);
503 7 : aSegments.push_back(aSegment);
504 7 : break;
505 : default: // given number of lineto elements
506 5 : aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::LINETO;
507 5 : aSegment.Count = nSeg;
508 5 : aSegments.push_back(aSegment);
509 5 : break;
510 : }
511 : }
512 : }
513 41 : while (nCharIndex >= 0);
514 5 : aPropertyValue.Name = "Segments";
515 5 : aPropertyValue.Value <<= comphelper::containerToSequence(aSegments);
516 5 : aPath.push_back(aPropertyValue);
517 : }
518 680 : else if (i->first == "geoLeft")
519 2 : aViewBox.X = i->second.toInt32();
520 678 : else if (i->first == "geoTop")
521 2 : aViewBox.Y = i->second.toInt32();
522 676 : else if (i->first == "geoRight")
523 4 : aViewBox.Width = i->second.toInt32();
524 672 : else if (i->first == "geoBottom")
525 4 : aViewBox.Height = i->second.toInt32();
526 668 : else if (i->first == "dhgt")
527 : {
528 : // dhgt is Word 2007, \shpz is Word 97-2003, the later has priority.
529 13 : if (!rShape.oZ)
530 0 : resolveDhgt(xPropertySet, i->second.toInt32(), /*bOldStyle=*/false);
531 : }
532 : // These are in EMU, convert to mm100.
533 655 : else if (i->first == "dxTextLeft")
534 : {
535 19 : if (xPropertySet.is())
536 15 : xPropertySet->setPropertyValue("LeftBorderDistance", uno::makeAny(i->second.toInt32() / 360));
537 : }
538 636 : else if (i->first == "dyTextTop")
539 : {
540 18 : if (xPropertySet.is())
541 14 : xPropertySet->setPropertyValue("TopBorderDistance", uno::makeAny(i->second.toInt32() / 360));
542 : }
543 618 : else if (i->first == "dxTextRight")
544 : {
545 19 : if (xPropertySet.is())
546 15 : xPropertySet->setPropertyValue("RightBorderDistance", uno::makeAny(i->second.toInt32() / 360));
547 : }
548 599 : else if (i->first == "dyTextBottom")
549 : {
550 18 : if (xPropertySet.is())
551 14 : xPropertySet->setPropertyValue("BottomBorderDistance", uno::makeAny(i->second.toInt32() / 360));
552 : }
553 581 : else if (i->first == "dxWrapDistLeft")
554 : {
555 13 : if (m_bTextGraphicObject)
556 1 : rShape.aAnchorAttributes.set(NS_ooxml::LN_CT_Anchor_distL, std::make_shared<RTFValue>(i->second.toInt32()));
557 12 : else if (xPropertySet.is())
558 12 : xPropertySet->setPropertyValue("LeftMargin", uno::makeAny(i->second.toInt32() / 360));
559 : }
560 568 : else if (i->first == "dyWrapDistTop")
561 : {
562 12 : if (m_bTextGraphicObject)
563 1 : rShape.aAnchorAttributes.set(NS_ooxml::LN_CT_Anchor_distT, std::make_shared<RTFValue>(i->second.toInt32()));
564 11 : else if (xPropertySet.is())
565 11 : xPropertySet->setPropertyValue("TopMargin", uno::makeAny(i->second.toInt32() / 360));
566 : }
567 556 : else if (i->first == "dxWrapDistRight")
568 : {
569 13 : if (m_bTextGraphicObject)
570 1 : rShape.aAnchorAttributes.set(NS_ooxml::LN_CT_Anchor_distR, std::make_shared<RTFValue>(i->second.toInt32()));
571 12 : else if (xPropertySet.is())
572 12 : xPropertySet->setPropertyValue("RightMargin", uno::makeAny(i->second.toInt32() / 360));
573 : }
574 543 : else if (i->first == "dyWrapDistBottom")
575 : {
576 12 : if (m_bTextGraphicObject)
577 1 : rShape.aAnchorAttributes.set(NS_ooxml::LN_CT_Anchor_distB, std::make_shared<RTFValue>(i->second.toInt32()));
578 11 : else if (xPropertySet.is())
579 11 : xPropertySet->setPropertyValue("BottomMargin", uno::makeAny(i->second.toInt32() / 360));
580 : }
581 531 : else if (i->first == "fillType")
582 : {
583 10 : switch (i->second.toInt32())
584 : {
585 : case 7: // Shade using the fillAngle
586 6 : aFillModel.moType.set(oox::XML_gradient);
587 6 : break;
588 : default:
589 : SAL_INFO("writerfilter", "TODO handle fillType value '" << i->second << "'");
590 4 : break;
591 : }
592 : }
593 521 : else if (i->first == "fillFocus")
594 6 : aFillModel.moFocus.set(i->second.toDouble() / 100); // percent
595 515 : else if (i->first == "fShadow" && xPropertySet.is())
596 : {
597 15 : if (i->second.toInt32() == 1)
598 12 : aShadowModel.mbHasShadow = true;
599 : }
600 500 : else if (i->first == "shadowColor")
601 12 : aShadowModel.moColor.set("#" + OUString::fromUtf8(msfilter::util::ConvertColor(msfilter::util::BGRToRGB(i->second.toInt32()))));
602 488 : else if (i->first == "shadowOffsetX")
603 : // EMUs to points
604 12 : aShadowModel.moOffset.set(OUString::number(i->second.toDouble() / 12700) + "pt");
605 476 : else if (i->first == "posh" || i->first == "posv" || i->first == "fFitShapeToText" || i->first == "fFilled" || i->first == "rotation")
606 47 : applyProperty(xShape, i->first, i->second);
607 429 : else if (i->first == "posrelh")
608 : {
609 26 : switch (i->second.toInt32())
610 : {
611 : case 1:
612 7 : rShape.nHoriOrientRelation = text::RelOrientation::PAGE_FRAME;
613 7 : break;
614 : default:
615 19 : break;
616 : }
617 : }
618 403 : else if (i->first == "posrelv")
619 : {
620 22 : switch (i->second.toInt32())
621 : {
622 : case 1:
623 7 : rShape.nVertOrientRelation = text::RelOrientation::PAGE_FRAME;
624 7 : break;
625 : default:
626 15 : break;
627 : }
628 : }
629 381 : else if (i->first == "groupLeft")
630 13 : oGroupLeft.reset(convertTwipToMm100(i->second.toInt32()));
631 368 : else if (i->first == "groupTop")
632 13 : oGroupTop.reset(convertTwipToMm100(i->second.toInt32()));
633 355 : else if (i->first == "groupRight")
634 13 : oGroupRight.reset(convertTwipToMm100(i->second.toInt32()));
635 342 : else if (i->first == "groupBottom")
636 13 : oGroupBottom.reset(convertTwipToMm100(i->second.toInt32()));
637 329 : else if (i->first == "relLeft")
638 13 : oRelLeft.reset(convertTwipToMm100(i->second.toInt32()));
639 316 : else if (i->first == "relTop")
640 13 : oRelTop.reset(convertTwipToMm100(i->second.toInt32()));
641 303 : else if (i->first == "relRight")
642 13 : oRelRight.reset(convertTwipToMm100(i->second.toInt32()));
643 290 : else if (i->first == "relBottom")
644 13 : oRelBottom.reset(convertTwipToMm100(i->second.toInt32()));
645 277 : else if (i->first == "fBehindDocument")
646 15 : bOpaque = !i->second.toInt32();
647 262 : else if (i->first == "pctHoriz" || i->first == "pctVert")
648 : {
649 6 : sal_Int16 nPercentage = rtl::math::round(i->second.toDouble() / 10);
650 6 : boost::optional<sal_Int16>& rPercentage = i->first == "pctHoriz" ? oRelativeWidth : oRelativeHeight;
651 6 : if (nPercentage)
652 6 : rPercentage = nPercentage;
653 : }
654 256 : else if (i->first == "sizerelh")
655 : {
656 1 : if (xPropertySet.is())
657 : {
658 1 : switch (i->second.toInt32())
659 : {
660 : case 0: // margin
661 0 : nRelativeWidthRelation = text::RelOrientation::FRAME;
662 0 : break;
663 : case 1: // page
664 1 : nRelativeWidthRelation = text::RelOrientation::PAGE_FRAME;
665 1 : break;
666 : default:
667 : SAL_WARN("writerfilter", "RTFSdrImport::resolve: unhandled sizerelh value: " << i->second);
668 0 : break;
669 : }
670 : }
671 : }
672 255 : else if (i->first == "sizerelv")
673 : {
674 3 : if (xPropertySet.is())
675 : {
676 3 : switch (i->second.toInt32())
677 : {
678 : case 0: // margin
679 3 : nRelativeHeightRelation = text::RelOrientation::FRAME;
680 3 : break;
681 : case 1: // page
682 0 : nRelativeHeightRelation = text::RelOrientation::PAGE_FRAME;
683 0 : break;
684 : default:
685 : SAL_WARN("writerfilter", "RTFSdrImport::resolve: unhandled sizerelv value: " << i->second);
686 0 : break;
687 : }
688 : }
689 : }
690 252 : else if (i->first == "fHorizRule") // TODO: what does "fStandardHR" do?
691 : {
692 : // horizontal rule: relative width defaults to 100% of paragraph
693 : // TODO: does it have a default height?
694 1 : if (!oRelativeWidth)
695 : {
696 1 : oRelativeWidth = 100;
697 : }
698 1 : nRelativeWidthRelation = text::RelOrientation::FRAME;
699 1 : sal_Int16 const nVertOrient = text::VertOrientation::CENTER;
700 1 : if (xPropertySet.is())
701 : {
702 1 : xPropertySet->setPropertyValue("VertOrient", uno::makeAny(nVertOrient));
703 : }
704 : }
705 251 : else if (i->first == "pctHR")
706 : {
707 : // horizontal rule relative width in permille
708 0 : oRelativeWidth = i->second.toInt32() / 10;
709 : }
710 251 : else if (i->first == "dxHeightHR")
711 : {
712 : // horizontal rule height
713 1 : sal_uInt32 const nHeight(convertTwipToMm100(i->second.toInt32()));
714 1 : rShape.nBottom = rShape.nTop + nHeight;
715 : }
716 250 : else if (i->first == "dxWidthHR")
717 : {
718 : // horizontal rule width
719 0 : sal_uInt32 const nWidth(convertTwipToMm100(i->second.toInt32()));
720 0 : rShape.nRight = rShape.nLeft + nWidth;
721 : }
722 250 : else if (i->first == "alignHR")
723 : {
724 : // horizontal orientation *for horizontal rule*
725 1 : sal_Int16 nHoriOrient = text::HoriOrientation::NONE;
726 1 : switch (i->second.toInt32())
727 : {
728 : case 0:
729 0 : nHoriOrient = text::HoriOrientation::LEFT;
730 0 : break;
731 : case 1:
732 1 : nHoriOrient = text::HoriOrientation::CENTER;
733 1 : break;
734 : case 2:
735 0 : nHoriOrient = text::HoriOrientation::RIGHT;
736 0 : break;
737 : }
738 1 : if (xPropertySet.is() && text::HoriOrientation::NONE != nHoriOrient)
739 : {
740 1 : xPropertySet->setPropertyValue("HoriOrient", uno::makeAny(nHoriOrient));
741 : }
742 : }
743 249 : else if (i->first == "pWrapPolygonVertices")
744 : {
745 3 : RTFSprms aPolygonSprms;
746 3 : sal_Int32 nSize = 0; // Size of a token
747 3 : sal_Int32 nCount = 0; // Number of tokens
748 3 : sal_Int32 nCharIndex = 0; // Character index
749 39 : do
750 : {
751 39 : OUString aToken = i->second.getToken(0, ';', nCharIndex);
752 39 : if (!nSize)
753 3 : nSize = aToken.toInt32();
754 36 : else if (!nCount)
755 3 : nCount = aToken.toInt32();
756 33 : else if (aToken.getLength())
757 : {
758 : // The coordinates are in an (x,y) form.
759 33 : aToken = aToken.copy(1, aToken.getLength() - 2);
760 33 : sal_Int32 nI = 0;
761 33 : boost::optional<sal_Int32> oX;
762 66 : boost::optional<sal_Int32> oY;
763 66 : do
764 : {
765 66 : OUString aPoint = aToken.getToken(0, ',', nI);
766 66 : if (!oX)
767 33 : oX.reset(aPoint.toInt32());
768 : else
769 33 : oY.reset(aPoint.toInt32());
770 : }
771 66 : while (nI >= 0);
772 66 : RTFSprms aPathAttributes;
773 33 : aPathAttributes.set(NS_ooxml::LN_CT_Point2D_x, std::make_shared<RTFValue>(*oX));
774 33 : aPathAttributes.set(NS_ooxml::LN_CT_Point2D_y, std::make_shared<RTFValue>(*oY));
775 66 : aPolygonSprms.set(NS_ooxml::LN_CT_WrapPath_lineTo, std::make_shared<RTFValue>(aPathAttributes), RTFOverwrite::NO_APPEND);
776 39 : }
777 : }
778 39 : while (nCharIndex >= 0);
779 3 : rShape.aWrapPolygonSprms = aPolygonSprms;
780 : }
781 : else
782 : SAL_INFO("writerfilter", "TODO handle shape property '" << i->first << "':'" << i->second << "'");
783 : }
784 :
785 109 : if (xPropertySet.is())
786 : {
787 100 : resolveLineColorAndWidth(m_bTextFrame, xPropertySet, aLineColor, aLineWidth);
788 100 : if (rShape.oZ)
789 59 : resolveDhgt(xPropertySet, *rShape.oZ, /*bOldStyle=*/false);
790 100 : if (m_bTextFrame)
791 : // Writer textframes implement text::WritingMode2, which is a different data type.
792 35 : xPropertySet->setPropertyValue("WritingMode", uno::makeAny(sal_Int16(eWritingMode)));
793 : else
794 65 : xPropertySet->setPropertyValue("TextWritingMode", uno::makeAny(eWritingMode));
795 : }
796 :
797 109 : if (m_aParents.size() && m_aParents.top().is() && !m_bTextFrame)
798 65 : m_aParents.top()->add(xShape);
799 :
800 109 : if (bPib)
801 : {
802 22 : m_rImport.resolvePict(false, xShape);
803 : }
804 :
805 109 : if (nType == ESCHER_ShpInst_PictureFrame) // picture frame
806 : {
807 : assert(!m_bTextFrame);
808 27 : if (!bPib) // ??? not sure if the early return should be removed on else?
809 : {
810 6 : m_xShape = xShape; // store it for later resolvePict call
811 : }
812 27 : return;
813 : }
814 :
815 82 : if (bCustom && xShape.is() && !bPib)
816 : {
817 33 : uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter(xShape, uno::UNO_QUERY);
818 33 : xDefaulter->createCustomShapeDefaults(OUString::number(nType));
819 : }
820 :
821 : // Creating CustomShapeGeometry property
822 82 : std::vector<beans::PropertyValue> aGeometry;
823 82 : if (aViewBox.X || aViewBox.Y || aViewBox.Width || aViewBox.Height)
824 : {
825 4 : aViewBox.Width -= aViewBox.X;
826 4 : aViewBox.Height -= aViewBox.Y;
827 4 : aPropertyValue.Name = "ViewBox";
828 4 : aPropertyValue.Value <<= aViewBox;
829 4 : aGeometry.push_back(aPropertyValue);
830 : }
831 82 : if (!aPath.empty())
832 : {
833 5 : aPropertyValue.Name = "Path";
834 5 : aPropertyValue.Value <<= comphelper::containerToSequence(aPath);
835 5 : aGeometry.push_back(aPropertyValue);
836 : }
837 82 : if (!aGeometry.empty() && xPropertySet.is() && !m_bTextFrame)
838 4 : xPropertySet->setPropertyValue("CustomShapeGeometry", uno::Any(comphelper::containerToSequence(aGeometry)));
839 :
840 : // Set position and size
841 82 : if (xShape.is())
842 : {
843 75 : sal_Int32 nLeft = rShape.nLeft;
844 75 : sal_Int32 nTop = rShape.nTop;
845 :
846 87 : bool bInShapeGroup = oGroupLeft && oGroupTop && oGroupRight && oGroupBottom
847 87 : && oRelLeft && oRelTop && oRelRight && oRelBottom;
848 75 : if (bInShapeGroup)
849 : {
850 : // See lclGetAbsPoint() in the VML import: rShape is the group shape, oGroup is its coordinate system, oRel is the relative child shape.
851 12 : sal_Int32 nShapeWidth = rShape.nRight - rShape.nLeft;
852 12 : sal_Int32 nShapeHeight = rShape.nBottom - rShape.nTop;
853 12 : sal_Int32 nCoordSysWidth = *oGroupRight - *oGroupLeft;
854 12 : sal_Int32 nCoordSysHeight = *oGroupBottom - *oGroupTop;
855 12 : double fWidthRatio = static_cast< double >(nShapeWidth) / nCoordSysWidth;
856 12 : double fHeightRatio = static_cast< double >(nShapeHeight) / nCoordSysHeight;
857 12 : nLeft = static_cast< sal_Int32 >(rShape.nLeft + fWidthRatio * (*oRelLeft - *oGroupLeft));
858 12 : nTop = static_cast< sal_Int32 >(rShape.nTop + fHeightRatio * (*oRelTop - *oGroupTop));
859 : }
860 :
861 75 : if (m_bTextFrame)
862 : {
863 35 : xPropertySet->setPropertyValue("HoriOrientPosition", uno::makeAny(nLeft));
864 35 : xPropertySet->setPropertyValue("VertOrientPosition", uno::makeAny(nTop));
865 : }
866 : else
867 40 : xShape->setPosition(awt::Point(nLeft, nTop));
868 :
869 75 : if (bInShapeGroup)
870 12 : xShape->setSize(awt::Size(*oRelRight - *oRelLeft, *oRelBottom - *oRelTop));
871 : else
872 63 : xShape->setSize(awt::Size(rShape.nRight - rShape.nLeft, rShape.nBottom - rShape.nTop));
873 :
874 75 : if (rShape.nHoriOrientRelation != 0)
875 20 : xPropertySet->setPropertyValue("HoriOrientRelation", uno::makeAny(rShape.nHoriOrientRelation));
876 75 : if (rShape.nVertOrientRelation != 0)
877 19 : xPropertySet->setPropertyValue("VertOrientRelation", uno::makeAny(rShape.nVertOrientRelation));
878 75 : if (rShape.nWrap != -1)
879 65 : xPropertySet->setPropertyValue("Surround", uno::makeAny(text::WrapTextMode(rShape.nWrap)));
880 75 : oox::ModelObjectHelper aModelObjectHelper(m_rImport.getModelFactory());
881 75 : if (aFillModel.moType.has())
882 : {
883 6 : oox::drawingml::ShapePropertyMap aPropMap(aModelObjectHelper);
884 6 : aFillModel.pushToPropMap(aPropMap, m_rImport.getGraphicHelper());
885 : // Sets the FillStyle and FillGradient UNO properties.
886 6 : oox::PropertySet(xShape).setProperties(aPropMap);
887 : }
888 :
889 75 : if (aShadowModel.mbHasShadow)
890 : {
891 12 : oox::drawingml::ShapePropertyMap aPropMap(aModelObjectHelper);
892 12 : aShadowModel.pushToPropMap(aPropMap, m_rImport.getGraphicHelper());
893 : // Sets the ShadowFormat UNO property.
894 12 : oox::PropertySet(xShape).setProperties(aPropMap);
895 : }
896 75 : xPropertySet->setPropertyValue("AnchorType", uno::makeAny(text::TextContentAnchorType_AT_CHARACTER));
897 75 : xPropertySet->setPropertyValue("Opaque", uno::makeAny(bOpaque));
898 75 : if (oRelativeWidth)
899 : {
900 4 : xPropertySet->setPropertyValue("RelativeWidth", uno::makeAny(*oRelativeWidth));
901 4 : xPropertySet->setPropertyValue("RelativeWidthRelation", uno::makeAny(nRelativeWidthRelation));
902 : }
903 75 : if (oRelativeHeight)
904 : {
905 3 : xPropertySet->setPropertyValue("RelativeHeight", uno::makeAny(*oRelativeHeight));
906 3 : xPropertySet->setPropertyValue("RelativeHeightRelation", uno::makeAny(nRelativeHeightRelation));
907 75 : }
908 : }
909 :
910 82 : if (m_rImport.isInBackground())
911 : {
912 1 : RTFSprms aAttributes;
913 1 : aAttributes.set(NS_ooxml::LN_CT_Background_color, std::make_shared<RTFValue>(xPropertySet->getPropertyValue("FillColor").get<sal_Int32>()));
914 1 : m_rImport.Mapper().props(std::make_shared<RTFReferenceProperties>(aAttributes));
915 :
916 2 : uno::Reference<lang::XComponent> xComponent(xShape, uno::UNO_QUERY);
917 1 : xComponent->dispose();
918 2 : return;
919 : }
920 :
921 : // Send it to dmapper
922 81 : m_rImport.Mapper().startShape(xShape);
923 81 : if (bClose)
924 : {
925 37 : m_rImport.Mapper().endShape();
926 : }
927 162 : m_xShape = xShape;
928 : }
929 :
930 44 : void RTFSdrImport::close()
931 : {
932 44 : m_rImport.Mapper().endShape();
933 44 : }
934 :
935 10 : void RTFSdrImport::append(const OUString& aKey, const OUString& aValue)
936 : {
937 10 : applyProperty(m_xShape, aKey, aValue);
938 10 : }
939 :
940 2 : void RTFSdrImport::appendGroupProperty(const OUString& aKey, const OUString& aValue)
941 : {
942 2 : uno::Reference<drawing::XShape> xShape(m_aParents.top(), uno::UNO_QUERY);
943 2 : if (xShape.is())
944 1 : applyProperty(xShape, aKey, aValue);
945 2 : }
946 :
947 : } // namespace rtftok
948 72 : } // namespace writerfilter
949 :
950 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|