Avoid potential negative array index access to cached text.
[LibreOffice.git] / chart2 / source / tools / RelativePositionHelper.cxx
blob260888e907dd6cb5ed2af21027015a3087996362
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <RelativePositionHelper.hxx>
21 #include <com/sun/star/chart2/RelativeSize.hpp>
22 #include <com/sun/star/awt/Size.hpp>
23 #include <rtl/math.hxx>
24 #include <osl/diagnose.h>
26 using namespace ::com::sun::star;
28 namespace chart
31 chart2::RelativePosition RelativePositionHelper::getReanchoredPosition(
32 const chart2::RelativePosition & rPosition,
33 const chart2::RelativeSize & rObjectSize,
34 drawing::Alignment aNewAnchor )
36 chart2::RelativePosition aResult( rPosition );
37 if( rPosition.Anchor != aNewAnchor )
39 sal_Int32 nShiftHalfWidths = 0;
40 sal_Int32 nShiftHalfHeights = 0;
42 // normalize to top-left
43 switch( rPosition.Anchor )
45 case drawing::Alignment_TOP_LEFT:
46 break;
47 case drawing::Alignment_LEFT:
48 nShiftHalfHeights -= 1;
49 break;
50 case drawing::Alignment_BOTTOM_LEFT:
51 nShiftHalfHeights -= 2;
52 break;
53 case drawing::Alignment_TOP:
54 nShiftHalfWidths -= 1;
55 break;
56 case drawing::Alignment_CENTER:
57 nShiftHalfWidths -= 1;
58 nShiftHalfHeights -= 1;
59 break;
60 case drawing::Alignment_BOTTOM:
61 nShiftHalfWidths -= 1;
62 nShiftHalfHeights -= 2;
63 break;
64 case drawing::Alignment_TOP_RIGHT:
65 nShiftHalfWidths -= 2;
66 break;
67 case drawing::Alignment_RIGHT:
68 nShiftHalfWidths -= 2;
69 nShiftHalfHeights -= 1;
70 break;
71 case drawing::Alignment_BOTTOM_RIGHT:
72 nShiftHalfWidths -= 2;
73 nShiftHalfHeights -= 2;
74 break;
75 case drawing::Alignment::Alignment_MAKE_FIXED_SIZE:
76 break;
79 // transform
80 switch( aNewAnchor )
82 case drawing::Alignment_TOP_LEFT:
83 break;
84 case drawing::Alignment_LEFT:
85 nShiftHalfHeights += 1;
86 break;
87 case drawing::Alignment_BOTTOM_LEFT:
88 nShiftHalfHeights += 2;
89 break;
90 case drawing::Alignment_TOP:
91 nShiftHalfWidths += 1;
92 break;
93 case drawing::Alignment_CENTER:
94 nShiftHalfWidths += 1;
95 nShiftHalfHeights += 1;
96 break;
97 case drawing::Alignment_BOTTOM:
98 nShiftHalfWidths += 1;
99 nShiftHalfHeights += 2;
100 break;
101 case drawing::Alignment_TOP_RIGHT:
102 nShiftHalfWidths += 2;
103 break;
104 case drawing::Alignment_RIGHT:
105 nShiftHalfWidths += 2;
106 nShiftHalfHeights += 1;
107 break;
108 case drawing::Alignment_BOTTOM_RIGHT:
109 nShiftHalfWidths += 2;
110 nShiftHalfHeights += 2;
111 break;
112 case drawing::Alignment::Alignment_MAKE_FIXED_SIZE:
113 break;
116 if( nShiftHalfWidths != 0 )
117 aResult.Primary += (rObjectSize.Primary / 2.0) * nShiftHalfWidths;
118 if( nShiftHalfHeights != 0 )
119 aResult.Secondary += (rObjectSize.Secondary / 2.0) * nShiftHalfHeights;
122 return aResult;
125 awt::Point RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
126 awt::Point aPoint
127 , awt::Size aObjectSize
128 , drawing::Alignment aAnchor )
130 awt::Point aResult( aPoint );
132 double fXDelta = 0.0;
133 double fYDelta = 0.0;
135 // adapt x-value
136 switch( aAnchor )
138 case drawing::Alignment_TOP:
139 case drawing::Alignment_CENTER:
140 case drawing::Alignment_BOTTOM:
141 fXDelta -= static_cast< double >( aObjectSize.Width ) / 2.0;
142 break;
143 case drawing::Alignment_TOP_RIGHT:
144 case drawing::Alignment_RIGHT:
145 case drawing::Alignment_BOTTOM_RIGHT:
146 fXDelta -= aObjectSize.Width;
147 break;
148 case drawing::Alignment_TOP_LEFT:
149 case drawing::Alignment_LEFT:
150 case drawing::Alignment_BOTTOM_LEFT:
151 default:
152 // nothing to do
153 break;
156 // adapt y-value
157 switch( aAnchor )
159 case drawing::Alignment_LEFT:
160 case drawing::Alignment_CENTER:
161 case drawing::Alignment_RIGHT:
162 fYDelta -= static_cast< double >( aObjectSize.Height ) / 2.0;
163 break;
164 case drawing::Alignment_BOTTOM_LEFT:
165 case drawing::Alignment_BOTTOM:
166 case drawing::Alignment_BOTTOM_RIGHT:
167 fYDelta -= aObjectSize.Height;
168 break;
169 case drawing::Alignment_TOP_LEFT:
170 case drawing::Alignment_TOP:
171 case drawing::Alignment_TOP_RIGHT:
172 default:
173 // nothing to do
174 break;
177 aResult.X += static_cast< sal_Int32 >( ::rtl::math::round( fXDelta ));
178 aResult.Y += static_cast< sal_Int32 >( ::rtl::math::round( fYDelta ));
180 return aResult;
183 awt::Point RelativePositionHelper::getCenterOfAnchoredObject(
184 awt::Point aPoint
185 , awt::Size aUnrotatedObjectSize
186 , drawing::Alignment aAnchor
187 , double fAnglePi )
189 awt::Point aResult( aPoint );
191 double fXDelta = 0.0;
192 double fYDelta = 0.0;
194 // adapt x-value
195 switch( aAnchor )
197 case drawing::Alignment_TOP:
198 case drawing::Alignment_CENTER:
199 case drawing::Alignment_BOTTOM:
200 // nothing to do
201 break;
202 case drawing::Alignment_TOP_RIGHT:
203 case drawing::Alignment_RIGHT:
204 case drawing::Alignment_BOTTOM_RIGHT:
205 fXDelta -= aUnrotatedObjectSize.Width/2;
206 break;
207 case drawing::Alignment_TOP_LEFT:
208 case drawing::Alignment_LEFT:
209 case drawing::Alignment_BOTTOM_LEFT:
210 default:
211 fXDelta += aUnrotatedObjectSize.Width/2;
212 break;
215 // adapt y-value
216 switch( aAnchor )
218 case drawing::Alignment_LEFT:
219 case drawing::Alignment_CENTER:
220 case drawing::Alignment_RIGHT:
221 // nothing to do
222 break;
223 case drawing::Alignment_BOTTOM_LEFT:
224 case drawing::Alignment_BOTTOM:
225 case drawing::Alignment_BOTTOM_RIGHT:
226 fYDelta -= aUnrotatedObjectSize.Height/2;
227 break;
228 case drawing::Alignment_TOP_LEFT:
229 case drawing::Alignment_TOP:
230 case drawing::Alignment_TOP_RIGHT:
231 fYDelta += aUnrotatedObjectSize.Height/2;
232 break;
233 default:
234 // nothing to do
235 break;
238 //take rotation into account:
239 aResult.X += static_cast< sal_Int32 >(
240 ::rtl::math::round( fXDelta * std::cos( fAnglePi ) + fYDelta * std::sin( fAnglePi ) ) );
241 aResult.Y += static_cast< sal_Int32 >(
242 ::rtl::math::round( - fXDelta * std::sin( fAnglePi ) + fYDelta * std::cos( fAnglePi ) ) );
244 return aResult;
247 bool RelativePositionHelper::centerGrow(
248 chart2::RelativePosition & rInOutPosition,
249 chart2::RelativeSize & rInOutSize,
250 double fAmountX, double fAmountY )
252 chart2::RelativePosition aPos( rInOutPosition );
253 chart2::RelativeSize aSize( rInOutSize );
254 const double fPosCheckThreshold = 0.02;
255 const double fSizeCheckThreshold = 0.1;
257 // grow/shrink, back to relative
258 aSize.Primary += fAmountX;
259 aSize.Secondary += fAmountY;
261 double fShiftAmountX = fAmountX / 2.0;
262 double fShiftAmountY = fAmountY / 2.0;
264 // shift X
265 switch( rInOutPosition.Anchor )
267 case drawing::Alignment_TOP_LEFT:
268 case drawing::Alignment_LEFT:
269 case drawing::Alignment_BOTTOM_LEFT:
270 aPos.Primary -= fShiftAmountX;
271 break;
272 case drawing::Alignment_TOP:
273 case drawing::Alignment_CENTER:
274 case drawing::Alignment_BOTTOM:
275 // nothing
276 break;
277 case drawing::Alignment_TOP_RIGHT:
278 case drawing::Alignment_RIGHT:
279 case drawing::Alignment_BOTTOM_RIGHT:
280 aPos.Primary += fShiftAmountX;
281 break;
282 case drawing::Alignment::Alignment_MAKE_FIXED_SIZE:
283 break;
286 // shift Y
287 switch( rInOutPosition.Anchor )
289 case drawing::Alignment_TOP:
290 case drawing::Alignment_TOP_LEFT:
291 case drawing::Alignment_TOP_RIGHT:
292 aPos.Secondary -= fShiftAmountY;
293 break;
294 case drawing::Alignment_CENTER:
295 case drawing::Alignment_LEFT:
296 case drawing::Alignment_RIGHT:
297 // nothing
298 break;
299 case drawing::Alignment_BOTTOM:
300 case drawing::Alignment_BOTTOM_LEFT:
301 case drawing::Alignment_BOTTOM_RIGHT:
302 aPos.Secondary += fShiftAmountY;
303 break;
304 case drawing::Alignment::Alignment_MAKE_FIXED_SIZE:
305 break;
308 // anchor must not be changed
309 OSL_ASSERT( rInOutPosition.Anchor == aPos.Anchor );
311 if( rInOutPosition.Primary == aPos.Primary &&
312 rInOutPosition.Secondary == aPos.Secondary &&
313 rInOutSize.Primary == aSize.Primary &&
314 rInOutSize.Secondary == aSize.Secondary )
315 return false;
317 // Note: this somewhat complicated check allows the output being
318 // out-of-bounds if the input was also out-of-bounds, and the change is
319 // for "advantage". E.g., you have a chart that laps out on the left
320 // side. If you shrink it, this should be possible, also if it still
321 // laps out on the left side afterwards. But you shouldn't be able to
322 // grow it then.
324 chart2::RelativePosition aUpperLeft(
325 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_TOP_LEFT ));
326 chart2::RelativePosition aLowerRight(
327 RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_BOTTOM_RIGHT ));
329 // Do not grow, if this leads to corners being off-screen
330 if( fAmountX > 0.0 &&
331 ( (aUpperLeft.Primary < fPosCheckThreshold) ||
332 (aLowerRight.Primary > (1.0 - fPosCheckThreshold)) ))
333 return false;
334 if( fAmountY > 0.0 &&
335 ( (aUpperLeft.Secondary < fPosCheckThreshold) ||
336 (aLowerRight.Secondary > (1.0 - fPosCheckThreshold)) ))
337 return false;
339 // Do not shrink, if this leads to a size too small
340 if( fAmountX < 0.0 &&
341 ( aSize.Primary < fSizeCheckThreshold ))
342 return false;
343 if( fAmountY < 0.0 &&
344 ( aSize.Secondary < fSizeCheckThreshold ))
345 return false;
347 rInOutPosition = aPos;
348 rInOutSize = aSize;
349 return true;
352 bool RelativePositionHelper::moveObject(
353 chart2::RelativePosition & rInOutPosition,
354 const chart2::RelativeSize & rObjectSize,
355 double fAmountX, double fAmountY )
357 chart2::RelativePosition aPos( rInOutPosition );
358 aPos.Primary += fAmountX;
359 aPos.Secondary += fAmountY;
360 const double fPosCheckThreshold = 0.02;
362 chart2::RelativePosition aUpperLeft(
363 RelativePositionHelper::getReanchoredPosition( aPos, rObjectSize, drawing::Alignment_TOP_LEFT ));
364 chart2::RelativePosition aLowerRight( aUpperLeft );
365 aLowerRight.Primary += rObjectSize.Primary;
366 aLowerRight.Secondary += rObjectSize.Secondary;
368 const double fFarEdgeThreshold = 1.0 - fPosCheckThreshold;
369 if( ( fAmountX > 0.0 && (aLowerRight.Primary > fFarEdgeThreshold)) ||
370 ( fAmountX < 0.0 && (aUpperLeft.Primary < fPosCheckThreshold)) ||
371 ( fAmountY > 0.0 && (aLowerRight.Secondary > fFarEdgeThreshold)) ||
372 ( fAmountY < 0.0 && (aUpperLeft.Secondary < fPosCheckThreshold)) )
373 return false;
375 rInOutPosition = aPos;
376 return true;
379 } // namespace chart
381 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */