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