/src/libreoffice/oox/source/drawingml/transform2dcontext.cxx
Line | Count | Source (jump to first uncovered line) |
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 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <cmath> |
21 | | |
22 | | #include <drawingml/transform2dcontext.hxx> |
23 | | |
24 | | #include <basegfx/matrix/b2dhommatrixtools.hxx> |
25 | | #include <basegfx/numeric/ftools.hxx> |
26 | | #include <basegfx/point/b2dpoint.hxx> |
27 | | #include <drawingml/customshapeproperties.hxx> |
28 | | #include <drawingml/textbody.hxx> |
29 | | #include <oox/drawingml/shape.hxx> |
30 | | #include <oox/helper/attributelist.hxx> |
31 | | #include <oox/token/namespaces.hxx> |
32 | | |
33 | | #include <com/sun/star/awt/Rectangle.hpp> |
34 | | |
35 | | using namespace ::com::sun::star; |
36 | | using ::oox::core::ContextHandlerRef; |
37 | | |
38 | | namespace oox::drawingml { |
39 | | |
40 | | /** context to import a CT_Transform2D */ |
41 | | Transform2DContext::Transform2DContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, Shape& rShape, bool btxXfrm ) |
42 | 133k | : ContextHandler2( rParent ) |
43 | 133k | , mrShape( rShape ) |
44 | 133k | , mbtxXfrm ( btxXfrm ) |
45 | 133k | { |
46 | 133k | if( !btxXfrm ) |
47 | 133k | { |
48 | 133k | mrShape.setRotation( rAttribs.getInteger( XML_rot, 0 ) ); // 60000ths of a degree Positive angles are clockwise; negative angles are counter-clockwise |
49 | 133k | mrShape.setFlip( rAttribs.getBool( XML_flipH, false ), rAttribs.getBool( XML_flipV, false ) ); |
50 | 133k | } |
51 | 294 | else |
52 | 294 | { |
53 | 294 | if (rAttribs.hasAttribute(XML_rot) && mrShape.getTextBody()) |
54 | 65 | { |
55 | 65 | mno_txXfrmRot = rAttribs.getInteger(XML_rot, 0); |
56 | 65 | sal_Int32 nTextAreaRot = mrShape.getTextBody()->getTextProperties().moTextAreaRotation.value_or(0); |
57 | 65 | mrShape.getTextBody()->getTextProperties().moTextAreaRotation = mno_txXfrmRot.value() + nTextAreaRot; |
58 | 65 | } |
59 | 294 | } |
60 | 133k | } |
61 | | |
62 | | namespace |
63 | | { |
64 | | bool ConstructPresetTextRectangle(Shape& rShape, awt::Rectangle& rRect) |
65 | 588 | { |
66 | | // When we are here, we have neither xShape nor a SdrObject. So need to manually calc the text |
67 | | // area rectangle defined in the preset in OOXML standard, but only for those types of shapes |
68 | | // where we know, that MS Office SmartArt presets do not use the default text area rectangle. |
69 | 588 | const sal_Int32 nType = rShape.getCustomShapeProperties()->getShapePresetType(); |
70 | 588 | switch (nType) |
71 | 588 | { |
72 | 60 | case XML_ellipse: |
73 | | // The preset text rectangle touches the perimeter of the ellipse at 45deg. |
74 | 60 | rRect.X = rShape.getPosition().X + rShape.getSize().Width * ((1.0 - M_SQRT1_2) / 2.0); |
75 | 60 | rRect.Y = rShape.getPosition().Y + rShape.getSize().Height * ((1.0 - M_SQRT1_2) / 2.0); |
76 | 60 | rRect.Width = rShape.getSize().Width * M_SQRT1_2; |
77 | 60 | rRect.Height = rShape.getSize().Height * M_SQRT1_2; |
78 | 60 | return true; |
79 | 126 | case XML_roundRect: |
80 | 126 | case XML_round2SameRect: |
81 | 126 | { |
82 | | // Second handle of round2SameRect used in preset diagrams has value 0. |
83 | 126 | const auto& aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); |
84 | 126 | double fAdj = aAdjGdList.empty() ? 16667 : aAdjGdList[0].maFormula.toDouble(); |
85 | 126 | sal_Int32 nWidth = rShape.getSize().Width; |
86 | 126 | sal_Int32 nHeight = rShape.getSize().Height; |
87 | 126 | if (nWidth == 0 || nHeight == 0) |
88 | 0 | return false; |
89 | 126 | double fMaxAdj = 50000.0 * nWidth / std::min(nWidth, nHeight); |
90 | 126 | fAdj = std::clamp<double>(fAdj, 0, fMaxAdj); |
91 | 126 | sal_Int32 nTextLeft = std::min(nWidth, nHeight) * fAdj / 100000.0 * 0.29289; |
92 | 126 | sal_Int32 nTextTop = nTextLeft; |
93 | 126 | rRect.X = rShape.getPosition().X + nTextLeft; |
94 | 126 | rRect.Y = rShape.getPosition().Y + nTextTop; |
95 | 126 | rRect.Width = nWidth - 2 * nTextLeft; |
96 | 126 | rRect.Height = nHeight - (nType == XML_roundRect ? 2 : 1) * nTextTop; |
97 | 126 | return true; |
98 | 126 | } |
99 | 0 | case XML_trapezoid: |
100 | 0 | { |
101 | 0 | const auto& aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); |
102 | 0 | double fAdj = aAdjGdList.empty() ? 25000 : aAdjGdList[0].maFormula.toDouble(); |
103 | 0 | sal_Int32 nWidth = rShape.getSize().Width; |
104 | 0 | sal_Int32 nHeight = rShape.getSize().Height; |
105 | 0 | if (nWidth == 0 || nHeight == 0) |
106 | 0 | return false; |
107 | 0 | double fMaxAdj = 50000.0 * nWidth / std::min(nWidth, nHeight); |
108 | 0 | fAdj = std::clamp<double>(fAdj, 0, fMaxAdj); |
109 | 0 | sal_Int32 nTextLeft = nWidth / 3.0 * fAdj / fMaxAdj; |
110 | 0 | sal_Int32 nTextTop = nHeight / 3.0 * fAdj / fMaxAdj; |
111 | 0 | rRect.X = rShape.getPosition().X + nTextLeft; |
112 | 0 | rRect.Y = rShape.getPosition().Y + nTextTop; |
113 | 0 | rRect.Width = nWidth - 2 * nTextLeft; |
114 | 0 | rRect.Height = nHeight - 2 * nTextTop; |
115 | 0 | return true; |
116 | 0 | } |
117 | 0 | case XML_flowChartManualOperation: |
118 | 0 | { |
119 | 0 | sal_Int32 nWidth = rShape.getSize().Width; |
120 | 0 | sal_Int32 nTextLeft = nWidth / 5; |
121 | 0 | rRect.X = rShape.getPosition().X + nTextLeft; |
122 | 0 | rRect.Y = rShape.getPosition().Y; |
123 | 0 | rRect.Width = nWidth - 2 * nTextLeft; |
124 | 0 | rRect.Height = rShape.getSize().Height; |
125 | 0 | return true; |
126 | 0 | } |
127 | 12 | case XML_pie: |
128 | 232 | case XML_rect: |
129 | 232 | case XML_wedgeRectCallout: |
130 | 232 | { |
131 | | // When tdf#149918 is fixed, pie will need its own case |
132 | 232 | rRect.X = rShape.getPosition().X; |
133 | 232 | rRect.Y = rShape.getPosition().Y; |
134 | 232 | rRect.Width = rShape.getSize().Width; |
135 | 232 | rRect.Height = rShape.getSize().Height; |
136 | 232 | return true; |
137 | 232 | } |
138 | 0 | case XML_upArrowCallout: |
139 | 0 | case XML_downArrowCallout: |
140 | 0 | { |
141 | | // The identifiers here reflect the guides name value in presetShapeDefinitions.xml |
142 | 0 | sal_Int32 nWidth = rShape.getSize().Width; |
143 | 0 | sal_Int32 nHeight = rShape.getSize().Height; |
144 | 0 | if (nWidth == 0 || nHeight == 0) |
145 | 0 | return false; |
146 | | // double adj1 = 25000.0; |
147 | | // double adj2 = 25000.0; |
148 | 0 | double adj3 = 25000.0; // height of arrow head |
149 | 0 | double adj4 = 64977.0; // height of arrow shaft |
150 | 0 | const auto& aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); |
151 | 0 | if (aAdjGdList.size() == 4) |
152 | 0 | { |
153 | | // adj1 = aAdjGdList[0].maFormula.toDouble(); |
154 | | // adj2 = aAdjGdList[1].maFormula.toDouble(); |
155 | 0 | adj3 = aAdjGdList[2].maFormula.toDouble(); |
156 | 0 | adj4 = aAdjGdList[3].maFormula.toDouble(); |
157 | 0 | } |
158 | |
|
159 | 0 | double maxAdj3 = 100000.0 * nHeight / std::min(nWidth, nHeight); |
160 | 0 | adj3 = std::clamp<double>(adj3, 0, maxAdj3); |
161 | 0 | double q2 = adj3 * std::min(nWidth, nHeight) / nHeight; |
162 | 0 | double maxAdj4 = 100000.0 - q2; |
163 | 0 | adj4 = std::clamp<double>(adj4, 0, maxAdj4); |
164 | |
|
165 | 0 | rRect.X = rShape.getPosition().X; |
166 | 0 | rRect.Y = rShape.getPosition().Y; |
167 | 0 | rRect.Width = rShape.getSize().Width; |
168 | 0 | rRect.Height = nHeight * adj4 / 100000.0; |
169 | 0 | return true; |
170 | 0 | } |
171 | 0 | case XML_gear6: |
172 | 0 | { |
173 | | // The identifiers here reflect the guides name value in presetShapeDefinitions.xml |
174 | 0 | double w = rShape.getSize().Width; |
175 | 0 | double h = rShape.getSize().Height; |
176 | 0 | if (w <= 0 || h <= 0) |
177 | 0 | return false; |
178 | 0 | double a1(15000.0); |
179 | 0 | double a2(3526.0); |
180 | 0 | const auto& aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); |
181 | 0 | if (aAdjGdList.size() == 2) |
182 | 0 | { |
183 | 0 | a1 = aAdjGdList[0].maFormula.toDouble(); |
184 | 0 | a2 = aAdjGdList[1].maFormula.toDouble(); |
185 | 0 | a1 = std::clamp<double>(a1, 0, 20000); |
186 | 0 | a2 = std::clamp<double>(a2, 0, 5358); |
187 | 0 | } |
188 | 0 | double th = std::min(w, h) * a1 / 100000.0; |
189 | 0 | double l2 = std::min(w, h) * a2 / 100000.0 / 2.0; |
190 | 0 | double l3 = th / 2.0 + l2; |
191 | |
|
192 | 0 | double rh = h / 2.0 - th; |
193 | 0 | double rw = w / 2.0 - th; |
194 | |
|
195 | 0 | double maxr = std::min(rw, rh); |
196 | 0 | double ha = atan2(l3, maxr); |
197 | |
|
198 | 0 | double aA1 = basegfx::deg2rad(330) - ha; |
199 | 0 | double ta11 = rw * cos(aA1); |
200 | 0 | double ta12 = rh * sin(aA1); |
201 | 0 | double bA1 = atan2(ta12, ta11); |
202 | 0 | double cta1 = rh * cos(bA1); |
203 | 0 | double sta1 = rw * sin(bA1); |
204 | 0 | double ma1 = std::hypot(cta1, sta1); |
205 | 0 | double na1 = rw * rh / ma1; |
206 | 0 | double dxa1 = na1 * cos(bA1); |
207 | 0 | double dya1 = na1 * sin(bA1); |
208 | |
|
209 | 0 | double xA1 = w / 2.0 + dxa1; // r |
210 | 0 | double yA1 = h / 2.0 + dya1; // t |
211 | 0 | double yD2 = h - yA1; // b |
212 | 0 | double xD5 = w - xA1; // l |
213 | |
|
214 | 0 | rRect.X = rShape.getPosition().X + xD5; |
215 | 0 | rRect.Y = rShape.getPosition().Y + yA1; |
216 | 0 | rRect.Width = xA1 - xD5; |
217 | 0 | rRect.Height = yD2 - yA1; |
218 | 0 | return true; |
219 | 0 | } |
220 | 0 | case XML_hexagon: |
221 | 0 | { |
222 | 0 | const auto& aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); |
223 | 0 | double fAdj = aAdjGdList.empty() ? 25000 : aAdjGdList[0].maFormula.toDouble(); |
224 | 0 | sal_Int32 nWidth = rShape.getSize().Width; |
225 | 0 | sal_Int32 nHeight = rShape.getSize().Height; |
226 | 0 | if (nWidth == 0 || nHeight == 0) |
227 | 0 | return false; |
228 | 0 | double fMaxAdj = 50000.0 * nWidth / std::min(nWidth, nHeight); |
229 | 0 | fAdj = std::clamp<double>(fAdj, 0, fMaxAdj); |
230 | 0 | double fFactor = fAdj / fMaxAdj / 6.0 + 1.0 / 12.0; |
231 | 0 | sal_Int32 nTextLeft = nWidth * fFactor; |
232 | 0 | sal_Int32 nTextTop = nHeight * fFactor; |
233 | 0 | rRect.X = rShape.getPosition().X + nTextLeft; |
234 | 0 | rRect.Y = rShape.getPosition().Y + nTextTop; |
235 | 0 | rRect.Width = nWidth - 2 * nTextLeft; |
236 | 0 | rRect.Height = nHeight - 2 * nTextTop; |
237 | 0 | return true; |
238 | 0 | } |
239 | 0 | case XML_round1Rect: |
240 | 0 | { |
241 | 0 | sal_Int32 nWidth = rShape.getSize().Width; |
242 | 0 | sal_Int32 nHeight = rShape.getSize().Height; |
243 | 0 | if (nWidth == 0 || nHeight == 0) |
244 | 0 | return false; |
245 | 0 | const auto& aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); |
246 | 0 | double fAdj = aAdjGdList.empty() ? 16667.0 : aAdjGdList[0].maFormula.toDouble(); |
247 | 0 | fAdj = std::clamp<double>(fAdj, 0.0, 50000.0); |
248 | 0 | double fDx = std::min(nWidth, nHeight) * fAdj / 100000.0 * 0.29289; |
249 | 0 | rRect.X = rShape.getPosition().X; |
250 | 0 | rRect.Y = rShape.getPosition().Y; |
251 | 0 | rRect.Width = nWidth - fDx; |
252 | 0 | rRect.Height = nHeight; |
253 | 0 | return true; |
254 | 0 | } |
255 | 28 | case XML_rightArrow: |
256 | 28 | { |
257 | | // The identifiers here reflect the guides name value in presetShapeDefinitions.xml |
258 | 28 | sal_Int32 nWidth = rShape.getSize().Width; |
259 | 28 | sal_Int32 nHeight = rShape.getSize().Height; |
260 | 28 | if (nWidth == 0 || nHeight == 0) |
261 | 0 | return false; |
262 | 28 | double a1(50000.0); |
263 | 28 | double a2(50000.0); |
264 | 28 | const auto& aAdjGdList = rShape.getCustomShapeProperties()->getAdjustmentGuideList(); |
265 | 28 | if (aAdjGdList.size() == 2) |
266 | 28 | { |
267 | 28 | a1 = aAdjGdList[0].maFormula.toDouble(); |
268 | 28 | a2 = aAdjGdList[1].maFormula.toDouble(); |
269 | 28 | a1 = std::clamp<double>(a1, 0, 100000); |
270 | 28 | } |
271 | 28 | double maxAdj2 = 100000.0 * nWidth / std::min(nWidth, nHeight); |
272 | 28 | a2 = std::clamp<double>(a2, 0, maxAdj2); |
273 | 28 | double dx1 = std::min(nWidth, nHeight) * a2 / 100000.0; |
274 | 28 | double x1 = nWidth - dx1; |
275 | 28 | double dy1 = nHeight * a1 / 200000.0; |
276 | 28 | double y1 = nHeight / 2.0 - dy1; // top |
277 | 28 | double y2 = nHeight / 2.0 + dy1; // bottom |
278 | 28 | double dx2 = y1 * dx1 / (nHeight / 2.0); |
279 | 28 | double x2 = x1 + dx2; // right |
280 | 28 | rRect.X = rShape.getPosition().X; // left = 0 |
281 | 28 | rRect.Y = rShape.getPosition().Y + y1; |
282 | 28 | rRect.Width = x2; |
283 | 28 | rRect.Height = y2 - y1; |
284 | 28 | return true; |
285 | 28 | } |
286 | 142 | default: |
287 | 142 | return false; |
288 | 588 | } |
289 | 588 | } |
290 | | |
291 | | basegfx::B2DPoint getCenter(const awt::Rectangle& rRect) |
292 | 8 | { |
293 | 8 | return basegfx::B2DPoint(rRect.X + rRect.Width / 2.0, rRect.Y + rRect.Height / 2.0); |
294 | 8 | } |
295 | | } // end namespace |
296 | | |
297 | | ContextHandlerRef Transform2DContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs ) |
298 | 324k | { |
299 | 324k | if (mbtxXfrm) |
300 | 588 | { |
301 | | // The child elements <a:off> and <a:ext> of a <dsp:txXfrm> element describe the position and |
302 | | // size of the text area rectangle. We cannot change the text area rectangle directly, because |
303 | | // currently we depend on the geometry definition of the preset. As workaround we change the |
304 | | // indents to move and scale the text block. The needed shifts are calculated here as moTextOff |
305 | | // and used in TextBodyProperties::pushTextDistances(). |
306 | 588 | awt::Rectangle aPresetTextRectangle; |
307 | 588 | if (!ConstructPresetTextRectangle(mrShape, aPresetTextRectangle)) |
308 | 142 | return nullptr; // faulty shape or text area calculation not implemented |
309 | | |
310 | 446 | switch (aElementToken) |
311 | 446 | { |
312 | 223 | case A_TOKEN(off): |
313 | 223 | { |
314 | | // need <a:ext> too, so only save values here. |
315 | 223 | const OUString sXValue = rAttribs.getStringDefaulted(XML_x); |
316 | 223 | const OUString sYValue = rAttribs.getStringDefaulted(XML_y); |
317 | 223 | if (!sXValue.isEmpty() && !sYValue.isEmpty()) |
318 | 223 | { |
319 | 223 | mno_txXfrmOffX = sXValue.toInt32(); |
320 | 223 | mno_txXfrmOffY = sYValue.toInt32(); |
321 | 223 | } |
322 | 223 | } |
323 | 223 | break; |
324 | 223 | case A_TOKEN(ext): |
325 | 223 | { |
326 | | // Build text frame from txXfrm element |
327 | 223 | awt::Rectangle aUnrotatedTxXfrm = aPresetTextRectangle; // dummy initialize |
328 | 223 | const OUString sCXValue = rAttribs.getStringDefaulted(XML_cx); |
329 | 223 | const OUString sCYValue = rAttribs.getStringDefaulted(XML_cy); |
330 | 223 | if (!sCXValue.isEmpty() && !sCYValue.isEmpty()) |
331 | 223 | { |
332 | 223 | aUnrotatedTxXfrm.Width = sCXValue.toInt32(); |
333 | 223 | aUnrotatedTxXfrm.Height = sCYValue.toInt32(); |
334 | 223 | } |
335 | 223 | if (mno_txXfrmOffX.has_value() && mno_txXfrmOffY.has_value()) |
336 | 223 | { |
337 | 223 | aUnrotatedTxXfrm.X = mno_txXfrmOffX.value(); |
338 | 223 | aUnrotatedTxXfrm.Y = mno_txXfrmOffY.value(); |
339 | 223 | } |
340 | | |
341 | | // Has the txXfrm an own rotation beyond compensation of the shape rotation? |
342 | | // Happens e.g. in diagram type 'Detailed Process'. |
343 | 223 | sal_Int32 nAngleDiff |
344 | 223 | = (mrShape.getRotation() + mno_txXfrmRot.value_or(0)) % 21600000; |
345 | 223 | if (nAngleDiff != 0) |
346 | 4 | { |
347 | | // Rectangle aUnrotatedTxXfrm rotates around its center not around text area |
348 | | // center from preset. We shift aUnrotatedTxXfrm so that it is at the original |
349 | | // position after rotation of text area rectangle from preset. |
350 | 4 | basegfx::B2DPoint aXfrmCenter(getCenter(aUnrotatedTxXfrm)); |
351 | 4 | basegfx::B2DPoint aPresetCenter(getCenter(aPresetTextRectangle)); |
352 | | |
353 | 4 | if (!aXfrmCenter.equal(aPresetCenter)) |
354 | 4 | { |
355 | 4 | double fAngleRad = basegfx::deg2rad(nAngleDiff / 60000.0); |
356 | 4 | basegfx::B2DHomMatrix aRotMatrix( |
357 | 4 | basegfx::utils::createRotateAroundPoint(aPresetCenter, -fAngleRad)); |
358 | 4 | basegfx::B2DPoint aNewCenter(aRotMatrix * aXfrmCenter); |
359 | 4 | aUnrotatedTxXfrm.X += aNewCenter.getX() - aXfrmCenter.getX(); |
360 | 4 | aUnrotatedTxXfrm.Y += aNewCenter.getY() - aXfrmCenter.getY(); |
361 | 4 | } |
362 | 4 | } |
363 | | |
364 | 223 | if(mrShape.getTextBody()) |
365 | 223 | { |
366 | | // Calculate indent offsets |
367 | 223 | sal_Int32 nOffsetLeft = aUnrotatedTxXfrm.X - aPresetTextRectangle.X; |
368 | 223 | sal_Int32 nOffsetTop = aUnrotatedTxXfrm.Y - aPresetTextRectangle.Y; |
369 | 223 | sal_Int32 nOffsetRight |
370 | 223 | = aPresetTextRectangle.Width - aUnrotatedTxXfrm.Width - nOffsetLeft; |
371 | 223 | sal_Int32 nOffsetBottom |
372 | 223 | = aPresetTextRectangle.Height - aUnrotatedTxXfrm.Height - nOffsetTop; |
373 | | |
374 | 223 | if (nOffsetLeft) |
375 | 103 | mrShape.getTextBody()->getTextProperties().moTextOffLeft |
376 | 103 | = GetCoordinate(nOffsetLeft); |
377 | 223 | if (nOffsetTop) |
378 | 113 | mrShape.getTextBody()->getTextProperties().moTextOffUpper |
379 | 113 | = GetCoordinate(nOffsetTop); |
380 | 223 | if (nOffsetRight) |
381 | 109 | mrShape.getTextBody()->getTextProperties().moTextOffRight |
382 | 109 | = GetCoordinate(nOffsetRight); |
383 | 223 | if (nOffsetBottom) |
384 | 113 | mrShape.getTextBody()->getTextProperties().moTextOffLower |
385 | 113 | = GetCoordinate(nOffsetBottom); |
386 | 223 | } |
387 | 223 | } |
388 | 223 | break; |
389 | 446 | } |
390 | 446 | return nullptr; |
391 | 446 | } // end of case mbtxXfrm |
392 | | |
393 | 323k | switch( aElementToken ) |
394 | 323k | { |
395 | 133k | case A_TOKEN( off ): // horz/vert translation |
396 | 133k | mrShape.setPosition( awt::Point( rAttribs.getInteger( XML_x, 0 ), rAttribs.getInteger( XML_y, 0 ) ) ); |
397 | 133k | break; |
398 | 133k | case A_TOKEN( ext ): // horz/vert size |
399 | 133k | mrShape.setSize( awt::Size( rAttribs.getInteger( XML_cx, 0 ), rAttribs.getInteger( XML_cy, 0 ) ) ); |
400 | 133k | break; |
401 | 28.4k | case A_TOKEN( chOff ): // horz/vert translation of children |
402 | 28.4k | mrShape.setChildPosition( awt::Point( rAttribs.getInteger( XML_x, 0 ), rAttribs.getInteger( XML_y, 0 ) ) ); |
403 | 28.4k | break; |
404 | 28.4k | case A_TOKEN( chExt ): // horz/vert size of children |
405 | 28.4k | { |
406 | 28.4k | sal_Int32 nChExtCx = rAttribs.getInteger(XML_cx, 0); |
407 | | |
408 | 28.4k | if(nChExtCx == 0) |
409 | 28.2k | nChExtCx = mrShape.getSize().Width; |
410 | | |
411 | 28.4k | sal_Int32 nChExtCy = rAttribs.getInteger(XML_cy, 0); |
412 | | |
413 | 28.4k | if(nChExtCy == 0) |
414 | 28.2k | nChExtCy = mrShape.getSize().Height; |
415 | | |
416 | 28.4k | mrShape.setChildSize(awt::Size(nChExtCx, nChExtCy)); |
417 | 28.4k | } |
418 | 28.4k | break; |
419 | 323k | } |
420 | | |
421 | 323k | return nullptr; |
422 | 323k | } |
423 | | |
424 | | } // namespace oox::drawingml |
425 | | |
426 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |