/src/libreoffice/canvas/source/tools/canvastools.cxx
Line | Count | Source |
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 <sal/config.h> |
21 | | |
22 | | #include <limits> |
23 | | |
24 | | #include <basegfx/matrix/b2dhommatrix.hxx> |
25 | | #include <basegfx/matrix/b2dhommatrixtools.hxx> |
26 | | #include <basegfx/numeric/ftools.hxx> |
27 | | #include <basegfx/point/b2dpoint.hxx> |
28 | | #include <basegfx/point/b2ipoint.hxx> |
29 | | #include <basegfx/polygon/b2dpolygon.hxx> |
30 | | #include <basegfx/polygon/b2dpolygontools.hxx> |
31 | | #include <basegfx/range/b2drange.hxx> |
32 | | #include <basegfx/range/b2drectangle.hxx> |
33 | | #include <basegfx/range/b2irange.hxx> |
34 | | #include <basegfx/utils/canvastools.hxx> |
35 | | #include <basegfx/vector/b2ivector.hxx> |
36 | | #include <com/sun/star/awt/Rectangle.hpp> |
37 | | #include <com/sun/star/awt/XWindow2.hpp> |
38 | | #include <com/sun/star/beans/XPropertySet.hpp> |
39 | | #include <com/sun/star/geometry/AffineMatrix2D.hpp> |
40 | | #include <com/sun/star/geometry/Matrix2D.hpp> |
41 | | #include <com/sun/star/lang/XServiceInfo.hpp> |
42 | | #include <com/sun/star/rendering/ColorComponentTag.hpp> |
43 | | #include <com/sun/star/rendering/ColorSpaceType.hpp> |
44 | | #include <com/sun/star/rendering/CompositeOperation.hpp> |
45 | | #include <com/sun/star/rendering/IntegerBitmapLayout.hpp> |
46 | | #include <com/sun/star/rendering/RenderState.hpp> |
47 | | #include <com/sun/star/rendering/RenderingIntent.hpp> |
48 | | #include <com/sun/star/rendering/ViewState.hpp> |
49 | | #include <com/sun/star/rendering/XCanvas.hpp> |
50 | | #include <com/sun/star/rendering/XColorSpace.hpp> |
51 | | #include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp> |
52 | | #include <com/sun/star/util/Endianness.hpp> |
53 | | #include <cppuhelper/implbase.hxx> |
54 | | #include <sal/log.hxx> |
55 | | #include <toolkit/helper/vclunohelper.hxx> |
56 | | #include <comphelper/diagnose_ex.hxx> |
57 | | #include <vcl/canvastools.hxx> |
58 | | #include <vcl/window.hxx> |
59 | | |
60 | | #include <canvas/canvastools.hxx> |
61 | | |
62 | | |
63 | | using namespace ::com::sun::star; |
64 | | |
65 | | namespace canvastools |
66 | | { |
67 | | geometry::RealSize2D createInfiniteSize2D() |
68 | 0 | { |
69 | 0 | return geometry::RealSize2D( |
70 | 0 | std::numeric_limits<double>::infinity(), |
71 | 0 | std::numeric_limits<double>::infinity() ); |
72 | 0 | } |
73 | | |
74 | | rendering::RenderState& initRenderState( rendering::RenderState& renderState ) |
75 | 0 | { |
76 | | // setup identity transform |
77 | 0 | setIdentityAffineMatrix2D( renderState.AffineTransform ); |
78 | 0 | renderState.Clip.clear(); |
79 | 0 | renderState.DeviceColor = uno::Sequence< double >(); |
80 | 0 | renderState.CompositeOperation = rendering::CompositeOperation::OVER; |
81 | |
|
82 | 0 | return renderState; |
83 | 0 | } |
84 | | |
85 | | rendering::ViewState& initViewState( rendering::ViewState& viewState ) |
86 | 0 | { |
87 | | // setup identity transform |
88 | 0 | setIdentityAffineMatrix2D( viewState.AffineTransform ); |
89 | 0 | viewState.Clip.clear(); |
90 | |
|
91 | 0 | return viewState; |
92 | 0 | } |
93 | | |
94 | | ::basegfx::B2DHomMatrix getViewStateTransform( const rendering::ViewState& viewState ) |
95 | 0 | { |
96 | 0 | ::basegfx::B2DHomMatrix aTransform; |
97 | 0 | return ::basegfx::unotools::homMatrixFromAffineMatrix( aTransform, viewState.AffineTransform ); |
98 | 0 | } |
99 | | |
100 | | rendering::ViewState& setViewStateTransform( rendering::ViewState& viewState, |
101 | | const ::basegfx::B2DHomMatrix& transform ) |
102 | 0 | { |
103 | 0 | ::basegfx::unotools::affineMatrixFromHomMatrix( viewState.AffineTransform, transform ); |
104 | |
|
105 | 0 | return viewState; |
106 | 0 | } |
107 | | |
108 | | ::basegfx::B2DHomMatrix getRenderStateTransform( const rendering::RenderState& renderState ) |
109 | 0 | { |
110 | 0 | ::basegfx::B2DHomMatrix aTransform; |
111 | 0 | return ::basegfx::unotools::homMatrixFromAffineMatrix( aTransform, renderState.AffineTransform ); |
112 | 0 | } |
113 | | |
114 | | rendering::RenderState& setRenderStateTransform( rendering::RenderState& renderState, |
115 | | const ::basegfx::B2DHomMatrix& transform ) |
116 | 0 | { |
117 | 0 | ::basegfx::unotools::affineMatrixFromHomMatrix( renderState.AffineTransform, transform ); |
118 | |
|
119 | 0 | return renderState; |
120 | 0 | } |
121 | | |
122 | | rendering::RenderState& appendToRenderState( rendering::RenderState& renderState, |
123 | | const ::basegfx::B2DHomMatrix& rTransform ) |
124 | 0 | { |
125 | 0 | ::basegfx::B2DHomMatrix transform = getRenderStateTransform( renderState ); |
126 | 0 | return setRenderStateTransform( renderState, transform * rTransform ); |
127 | 0 | } |
128 | | |
129 | | rendering::RenderState& prependToRenderState( rendering::RenderState& renderState, |
130 | | const ::basegfx::B2DHomMatrix& rTransform ) |
131 | 0 | { |
132 | 0 | ::basegfx::B2DHomMatrix transform = getRenderStateTransform( renderState ); |
133 | 0 | return setRenderStateTransform( renderState, rTransform * transform ); |
134 | 0 | } |
135 | | |
136 | | ::basegfx::B2DHomMatrix& mergeViewAndRenderTransform( ::basegfx::B2DHomMatrix& combinedTransform, |
137 | | const rendering::ViewState& viewState, |
138 | | const rendering::RenderState& renderState ) |
139 | 0 | { |
140 | 0 | ::basegfx::B2DHomMatrix viewTransform; |
141 | |
|
142 | 0 | ::basegfx::unotools::homMatrixFromAffineMatrix( combinedTransform, renderState.AffineTransform ); |
143 | 0 | ::basegfx::unotools::homMatrixFromAffineMatrix( viewTransform, viewState.AffineTransform ); |
144 | | |
145 | | // this statement performs combinedTransform = viewTransform * combinedTransform |
146 | 0 | combinedTransform *= viewTransform; |
147 | |
|
148 | 0 | return combinedTransform; |
149 | 0 | } |
150 | | |
151 | | geometry::AffineMatrix2D& setIdentityAffineMatrix2D( geometry::AffineMatrix2D& matrix ) |
152 | 0 | { |
153 | 0 | matrix.m00 = 1.0; |
154 | 0 | matrix.m01 = 0.0; |
155 | 0 | matrix.m02 = 0.0; |
156 | 0 | matrix.m10 = 0.0; |
157 | 0 | matrix.m11 = 1.0; |
158 | 0 | matrix.m12 = 0.0; |
159 | |
|
160 | 0 | return matrix; |
161 | 0 | } |
162 | | |
163 | | geometry::Matrix2D& setIdentityMatrix2D( geometry::Matrix2D& matrix ) |
164 | 0 | { |
165 | 0 | matrix.m00 = 1.0; |
166 | 0 | matrix.m01 = 0.0; |
167 | 0 | matrix.m10 = 0.0; |
168 | 0 | matrix.m11 = 1.0; |
169 | |
|
170 | 0 | return matrix; |
171 | 0 | } |
172 | | |
173 | | namespace |
174 | | { |
175 | | class StandardColorSpace : public cppu::WeakImplHelper< css::rendering::XIntegerBitmapColorSpace > |
176 | | { |
177 | | private: |
178 | | uno::Sequence< sal_Int8 > maComponentTags; |
179 | | uno::Sequence< sal_Int32 > maBitCounts; |
180 | | |
181 | | virtual ::sal_Int8 SAL_CALL getType( ) override |
182 | 0 | { |
183 | 0 | return rendering::ColorSpaceType::RGB; |
184 | 0 | } |
185 | | virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) override |
186 | 0 | { |
187 | 0 | return maComponentTags; |
188 | 0 | } |
189 | | virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) override |
190 | 0 | { |
191 | 0 | return rendering::RenderingIntent::PERCEPTUAL; |
192 | 0 | } |
193 | | virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) override |
194 | 0 | { |
195 | 0 | return uno::Sequence< beans::PropertyValue >(); |
196 | 0 | } |
197 | | virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor, |
198 | | const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override |
199 | 0 | { |
200 | | // TODO(P3): if we know anything about target |
201 | | // colorspace, this can be greatly sped up |
202 | 0 | uno::Sequence<rendering::ARGBColor> aIntermediate( |
203 | 0 | convertToARGB(deviceColor)); |
204 | 0 | return targetColorSpace->convertFromARGB(aIntermediate); |
205 | 0 | } |
206 | | virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) override |
207 | 0 | { |
208 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
209 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
210 | 0 | "number of channels no multiple of 4", |
211 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
212 | |
|
213 | 0 | uno::Sequence< rendering::RGBColor > aRes(nLen/4); |
214 | 0 | rendering::RGBColor* pOut( aRes.getArray() ); |
215 | 0 | for (sal_Int32 i = 0; i < nLen; i += 4) |
216 | 0 | { |
217 | 0 | *pOut++ = rendering::RGBColor(deviceColor[i], deviceColor[i+1], deviceColor[i+2]); |
218 | 0 | } |
219 | 0 | return aRes; |
220 | 0 | } |
221 | | virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) override |
222 | 0 | { |
223 | 0 | SAL_WARN_IF(!deviceColor.hasElements(), "canvas", "empty deviceColor argument"); |
224 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
225 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
226 | 0 | "number of channels no multiple of 4", |
227 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
228 | |
|
229 | 0 | uno::Sequence< rendering::ARGBColor > aRes(nLen/4); |
230 | 0 | rendering::ARGBColor* pOut( aRes.getArray() ); |
231 | 0 | for (sal_Int32 i = 0; i < nLen; i += 4) |
232 | 0 | { |
233 | 0 | *pOut++ = rendering::ARGBColor(deviceColor[i+3], deviceColor[i], deviceColor[i+1], deviceColor[i+2]); |
234 | 0 | } |
235 | 0 | return aRes; |
236 | 0 | } |
237 | | virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) override |
238 | 0 | { |
239 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
240 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
241 | 0 | "number of channels no multiple of 4", |
242 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
243 | |
|
244 | 0 | uno::Sequence< rendering::ARGBColor > aRes(nLen/4); |
245 | 0 | rendering::ARGBColor* pOut( aRes.getArray() ); |
246 | 0 | for (sal_Int32 i = 0; i < nLen; i += 4) |
247 | 0 | { |
248 | 0 | *pOut++ = rendering::ARGBColor(deviceColor[i+3], |
249 | 0 | deviceColor[i+3] * deviceColor[i], |
250 | 0 | deviceColor[i+3] * deviceColor[i+1], |
251 | 0 | deviceColor[i+3] * deviceColor[i+2]); |
252 | 0 | } |
253 | 0 | return aRes; |
254 | 0 | } |
255 | | virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override |
256 | 0 | { |
257 | 0 | uno::Sequence<double> aRes(rgbColor.getLength() * 4); |
258 | 0 | double* pColors=aRes.getArray(); |
259 | 0 | for (auto& color : rgbColor) |
260 | 0 | { |
261 | 0 | *pColors++ = color.Red; |
262 | 0 | *pColors++ = color.Green; |
263 | 0 | *pColors++ = color.Blue; |
264 | 0 | *pColors++ = 1.0; |
265 | 0 | } |
266 | 0 | return aRes; |
267 | 0 | } |
268 | | virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override |
269 | 0 | { |
270 | 0 | uno::Sequence<double> aRes(rgbColor.getLength() * 4); |
271 | 0 | double* pColors=aRes.getArray(); |
272 | 0 | for (auto& color : rgbColor) |
273 | 0 | { |
274 | 0 | *pColors++ = color.Red; |
275 | 0 | *pColors++ = color.Green; |
276 | 0 | *pColors++ = color.Blue; |
277 | 0 | *pColors++ = color.Alpha; |
278 | 0 | } |
279 | 0 | return aRes; |
280 | 0 | } |
281 | | virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override |
282 | 0 | { |
283 | 0 | uno::Sequence<double> aRes(rgbColor.getLength() * 4); |
284 | 0 | double* pColors=aRes.getArray(); |
285 | 0 | for (auto& color : rgbColor) |
286 | 0 | { |
287 | 0 | *pColors++ = color.Red / color.Alpha; |
288 | 0 | *pColors++ = color.Green / color.Alpha; |
289 | 0 | *pColors++ = color.Blue / color.Alpha; |
290 | 0 | *pColors++ = color.Alpha; |
291 | 0 | } |
292 | 0 | return aRes; |
293 | 0 | } |
294 | | |
295 | | // XIntegerBitmapColorSpace |
296 | | virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) override |
297 | 0 | { |
298 | 0 | return 32; |
299 | 0 | } |
300 | | virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) override |
301 | 0 | { |
302 | 0 | return maBitCounts; |
303 | 0 | } |
304 | | virtual ::sal_Int8 SAL_CALL getEndianness( ) override |
305 | 0 | { |
306 | 0 | return util::Endianness::LITTLE; |
307 | 0 | } |
308 | | virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor, |
309 | | const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override |
310 | 0 | { |
311 | 0 | if( dynamic_cast<StandardColorSpace*>(targetColorSpace.get()) ) |
312 | 0 | { |
313 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
314 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
315 | 0 | "number of channels no multiple of 4", |
316 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
317 | |
|
318 | 0 | uno::Sequence<double> aRes(nLen); |
319 | 0 | std::transform(deviceColor.begin(), deviceColor.end(), aRes.getArray(), |
320 | 0 | [](auto c) { return vcl::unotools::toDoubleColor(c); }); |
321 | 0 | return aRes; |
322 | 0 | } |
323 | 0 | else |
324 | 0 | { |
325 | | // TODO(P3): if we know anything about target |
326 | | // colorspace, this can be greatly sped up |
327 | 0 | uno::Sequence<rendering::ARGBColor> aIntermediate( |
328 | 0 | convertIntegerToARGB(deviceColor)); |
329 | 0 | return targetColorSpace->convertFromARGB(aIntermediate); |
330 | 0 | } |
331 | 0 | } |
332 | | virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor, |
333 | | const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) override |
334 | 0 | { |
335 | 0 | if( dynamic_cast<StandardColorSpace*>(targetColorSpace.get()) ) |
336 | 0 | { |
337 | | // it's us, so simply pass-through the data |
338 | 0 | return deviceColor; |
339 | 0 | } |
340 | 0 | else |
341 | 0 | { |
342 | | // TODO(P3): if we know anything about target |
343 | | // colorspace, this can be greatly sped up |
344 | 0 | uno::Sequence<rendering::ARGBColor> aIntermediate( |
345 | 0 | convertIntegerToARGB(deviceColor)); |
346 | 0 | return targetColorSpace->convertIntegerFromARGB(aIntermediate); |
347 | 0 | } |
348 | 0 | } |
349 | | virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override |
350 | 0 | { |
351 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
352 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
353 | 0 | "number of channels no multiple of 4", |
354 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
355 | |
|
356 | 0 | uno::Sequence< rendering::RGBColor > aRes(nLen/4); |
357 | 0 | rendering::RGBColor* pOut( aRes.getArray() ); |
358 | 0 | for (sal_Int32 i = 0; i < nLen; i += 4) |
359 | 0 | { |
360 | 0 | *pOut++ = rendering::RGBColor( |
361 | 0 | vcl::unotools::toDoubleColor(deviceColor[i]), |
362 | 0 | vcl::unotools::toDoubleColor(deviceColor[i+1]), |
363 | 0 | vcl::unotools::toDoubleColor(deviceColor[i+2])); |
364 | 0 | } |
365 | 0 | return aRes; |
366 | 0 | } |
367 | | |
368 | | virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override |
369 | 0 | { |
370 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
371 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
372 | 0 | "number of channels no multiple of 4", |
373 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
374 | |
|
375 | 0 | uno::Sequence< rendering::ARGBColor > aRes(nLen/4); |
376 | 0 | rendering::ARGBColor* pOut( aRes.getArray() ); |
377 | 0 | for (sal_Int32 i = 0; i < nLen; i += 4) |
378 | 0 | { |
379 | 0 | *pOut++ = rendering::ARGBColor( |
380 | 0 | vcl::unotools::toDoubleColor(deviceColor[i+3]), |
381 | 0 | vcl::unotools::toDoubleColor(deviceColor[i]), |
382 | 0 | vcl::unotools::toDoubleColor(deviceColor[i+1]), |
383 | 0 | vcl::unotools::toDoubleColor(deviceColor[i+2])); |
384 | 0 | } |
385 | 0 | return aRes; |
386 | 0 | } |
387 | | |
388 | | virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override |
389 | 0 | { |
390 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
391 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
392 | 0 | "number of channels no multiple of 4", |
393 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
394 | |
|
395 | 0 | uno::Sequence< rendering::ARGBColor > aRes(nLen/4); |
396 | 0 | rendering::ARGBColor* pOut( aRes.getArray() ); |
397 | 0 | for (sal_Int32 i = 0; i < nLen; i += 4) |
398 | 0 | { |
399 | 0 | const sal_Int8 nAlpha(deviceColor[i+3]); |
400 | 0 | *pOut++ = rendering::ARGBColor( |
401 | 0 | vcl::unotools::toDoubleColor(nAlpha), |
402 | 0 | vcl::unotools::toDoubleColor(nAlpha * deviceColor[i]), |
403 | 0 | vcl::unotools::toDoubleColor(nAlpha * deviceColor[i+1]), |
404 | 0 | vcl::unotools::toDoubleColor(nAlpha * deviceColor[i+2])); |
405 | 0 | } |
406 | 0 | return aRes; |
407 | 0 | } |
408 | | |
409 | | virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override |
410 | 0 | { |
411 | 0 | uno::Sequence<sal_Int8> aRes(rgbColor.getLength() * 4); |
412 | 0 | sal_Int8* pColors=aRes.getArray(); |
413 | 0 | for (auto& color : rgbColor) |
414 | 0 | { |
415 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Red); |
416 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Green); |
417 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Blue); |
418 | 0 | *pColors++ = 0; |
419 | 0 | } |
420 | 0 | return aRes; |
421 | 0 | } |
422 | | |
423 | | virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override |
424 | 0 | { |
425 | 0 | uno::Sequence<sal_Int8> aRes(rgbColor.getLength() * 4); |
426 | 0 | sal_Int8* pColors=aRes.getArray(); |
427 | 0 | for (auto& color : rgbColor) |
428 | 0 | { |
429 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Red); |
430 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Green); |
431 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Blue); |
432 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Alpha); |
433 | 0 | } |
434 | 0 | return aRes; |
435 | 0 | } |
436 | | |
437 | | virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override |
438 | 0 | { |
439 | 0 | uno::Sequence<sal_Int8> aRes(rgbColor.getLength() * 4); |
440 | 0 | sal_Int8* pColors=aRes.getArray(); |
441 | 0 | for (auto& color : rgbColor) |
442 | 0 | { |
443 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Red / color.Alpha); |
444 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Green / color.Alpha); |
445 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Blue / color.Alpha); |
446 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Alpha); |
447 | 0 | } |
448 | 0 | return aRes; |
449 | 0 | } |
450 | | |
451 | | public: |
452 | | StandardColorSpace() : |
453 | 0 | maComponentTags(4), |
454 | 0 | maBitCounts(4) |
455 | 0 | { |
456 | 0 | sal_Int8* pTags = maComponentTags.getArray(); |
457 | 0 | sal_Int32* pBitCounts = maBitCounts.getArray(); |
458 | 0 | pTags[0] = rendering::ColorComponentTag::RGB_RED; |
459 | 0 | pTags[1] = rendering::ColorComponentTag::RGB_GREEN; |
460 | 0 | pTags[2] = rendering::ColorComponentTag::RGB_BLUE; |
461 | 0 | pTags[3] = rendering::ColorComponentTag::ALPHA; |
462 | |
|
463 | 0 | pBitCounts[0] = |
464 | 0 | pBitCounts[1] = |
465 | 0 | pBitCounts[2] = |
466 | 0 | pBitCounts[3] = 8; |
467 | 0 | } |
468 | | }; |
469 | | |
470 | | class StandardNoAlphaColorSpace : public cppu::WeakImplHelper< css::rendering::XIntegerBitmapColorSpace > |
471 | | { |
472 | | private: |
473 | | uno::Sequence< sal_Int8 > maComponentTags; |
474 | | uno::Sequence< sal_Int32 > maBitCounts; |
475 | | |
476 | | virtual ::sal_Int8 SAL_CALL getType( ) override |
477 | 0 | { |
478 | 0 | return rendering::ColorSpaceType::RGB; |
479 | 0 | } |
480 | | virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) override |
481 | 0 | { |
482 | 0 | return maComponentTags; |
483 | 0 | } |
484 | | virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) override |
485 | 0 | { |
486 | 0 | return rendering::RenderingIntent::PERCEPTUAL; |
487 | 0 | } |
488 | | virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) override |
489 | 0 | { |
490 | 0 | return uno::Sequence< beans::PropertyValue >(); |
491 | 0 | } |
492 | | virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor, |
493 | | const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override |
494 | 0 | { |
495 | | // TODO(P3): if we know anything about target |
496 | | // colorspace, this can be greatly sped up |
497 | 0 | uno::Sequence<rendering::ARGBColor> aIntermediate( |
498 | 0 | convertToARGB(deviceColor)); |
499 | 0 | return targetColorSpace->convertFromARGB(aIntermediate); |
500 | 0 | } |
501 | | virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) override |
502 | 0 | { |
503 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
504 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
505 | 0 | "number of channels no multiple of 4", |
506 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
507 | |
|
508 | 0 | uno::Sequence< rendering::RGBColor > aRes(nLen/4); |
509 | 0 | rendering::RGBColor* pOut( aRes.getArray() ); |
510 | 0 | for (sal_Int32 i = 0; i < nLen; i += 4) |
511 | 0 | { |
512 | 0 | *pOut++ = rendering::RGBColor(deviceColor[i], deviceColor[i+1], deviceColor[i+2]); |
513 | 0 | } |
514 | 0 | return aRes; |
515 | 0 | } |
516 | | virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) override |
517 | 0 | { |
518 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
519 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
520 | 0 | "number of channels no multiple of 4", |
521 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
522 | |
|
523 | 0 | uno::Sequence< rendering::ARGBColor > aRes(nLen/4); |
524 | 0 | rendering::ARGBColor* pOut( aRes.getArray() ); |
525 | 0 | for (sal_Int32 i = 0; i < nLen; i += 4) |
526 | 0 | { |
527 | 0 | *pOut++ = rendering::ARGBColor(1.0, deviceColor[i], deviceColor[i+1], deviceColor[i+2]); |
528 | 0 | } |
529 | 0 | return aRes; |
530 | 0 | } |
531 | | virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) override |
532 | 0 | { |
533 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
534 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
535 | 0 | "number of channels no multiple of 4", |
536 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
537 | |
|
538 | 0 | uno::Sequence< rendering::ARGBColor > aRes(nLen/4); |
539 | 0 | rendering::ARGBColor* pOut( aRes.getArray() ); |
540 | 0 | for (sal_Int32 i = 0; i < nLen; i += 4) |
541 | 0 | { |
542 | 0 | *pOut++ = rendering::ARGBColor(1.0, deviceColor[i], deviceColor[i+1], deviceColor[i+2]); |
543 | 0 | } |
544 | 0 | return aRes; |
545 | 0 | } |
546 | | virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override |
547 | 0 | { |
548 | 0 | uno::Sequence<double> aRes(rgbColor.getLength() * 4); |
549 | 0 | double* pColors=aRes.getArray(); |
550 | 0 | for (auto& color : rgbColor) |
551 | 0 | { |
552 | 0 | *pColors++ = color.Red; |
553 | 0 | *pColors++ = color.Green; |
554 | 0 | *pColors++ = color.Blue; |
555 | 0 | *pColors++ = 1.0; // the value does not matter |
556 | 0 | } |
557 | 0 | return aRes; |
558 | 0 | } |
559 | | virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override |
560 | 0 | { |
561 | 0 | uno::Sequence<double> aRes(rgbColor.getLength() * 4); |
562 | 0 | double* pColors=aRes.getArray(); |
563 | 0 | for (auto& color : rgbColor) |
564 | 0 | { |
565 | 0 | *pColors++ = color.Red; |
566 | 0 | *pColors++ = color.Green; |
567 | 0 | *pColors++ = color.Blue; |
568 | 0 | *pColors++ = 1.0; // the value does not matter |
569 | 0 | } |
570 | 0 | return aRes; |
571 | 0 | } |
572 | | virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override |
573 | 0 | { |
574 | 0 | uno::Sequence<double> aRes(rgbColor.getLength() * 4); |
575 | 0 | double* pColors=aRes.getArray(); |
576 | 0 | for (auto& color : rgbColor) |
577 | 0 | { |
578 | 0 | *pColors++ = color.Red / color.Alpha; |
579 | 0 | *pColors++ = color.Green / color.Alpha; |
580 | 0 | *pColors++ = color.Blue / color.Alpha; |
581 | 0 | *pColors++ = 1.0; // the value does not matter |
582 | 0 | } |
583 | 0 | return aRes; |
584 | 0 | } |
585 | | |
586 | | // XIntegerBitmapColorSpace |
587 | | virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) override |
588 | 0 | { |
589 | 0 | return 32; |
590 | 0 | } |
591 | | virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) override |
592 | 0 | { |
593 | 0 | return maBitCounts; |
594 | 0 | } |
595 | | virtual ::sal_Int8 SAL_CALL getEndianness( ) override |
596 | 0 | { |
597 | 0 | return util::Endianness::LITTLE; |
598 | 0 | } |
599 | | virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor, |
600 | | const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override |
601 | 0 | { |
602 | 0 | if( dynamic_cast<StandardNoAlphaColorSpace*>(targetColorSpace.get()) ) |
603 | 0 | { |
604 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
605 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
606 | 0 | "number of channels no multiple of 4", |
607 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
608 | |
|
609 | 0 | uno::Sequence<double> aRes(nLen); |
610 | 0 | double* pOut( aRes.getArray() ); |
611 | 0 | for (sal_Int32 i = 0; i < nLen; i += 4) |
612 | 0 | { |
613 | 0 | *pOut++ = vcl::unotools::toDoubleColor(deviceColor[i]); |
614 | 0 | *pOut++ = vcl::unotools::toDoubleColor(deviceColor[i+1]); |
615 | 0 | *pOut++ = vcl::unotools::toDoubleColor(deviceColor[i+2]); |
616 | 0 | *pOut++ = 1.0; |
617 | 0 | } |
618 | 0 | return aRes; |
619 | 0 | } |
620 | 0 | else |
621 | 0 | { |
622 | | // TODO(P3): if we know anything about target |
623 | | // colorspace, this can be greatly sped up |
624 | 0 | uno::Sequence<rendering::ARGBColor> aIntermediate( |
625 | 0 | convertIntegerToARGB(deviceColor)); |
626 | 0 | return targetColorSpace->convertFromARGB(aIntermediate); |
627 | 0 | } |
628 | 0 | } |
629 | | virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor, |
630 | | const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) override |
631 | 0 | { |
632 | 0 | if( dynamic_cast<StandardNoAlphaColorSpace*>(targetColorSpace.get()) ) |
633 | 0 | { |
634 | | // it's us, so simply pass-through the data |
635 | 0 | return deviceColor; |
636 | 0 | } |
637 | 0 | else |
638 | 0 | { |
639 | | // TODO(P3): if we know anything about target |
640 | | // colorspace, this can be greatly sped up |
641 | 0 | uno::Sequence<rendering::ARGBColor> aIntermediate( |
642 | 0 | convertIntegerToARGB(deviceColor)); |
643 | 0 | return targetColorSpace->convertIntegerFromARGB(aIntermediate); |
644 | 0 | } |
645 | 0 | } |
646 | | virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override |
647 | 0 | { |
648 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
649 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
650 | 0 | "number of channels no multiple of 4", |
651 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
652 | |
|
653 | 0 | uno::Sequence< rendering::RGBColor > aRes(nLen/4); |
654 | 0 | rendering::RGBColor* pOut( aRes.getArray() ); |
655 | 0 | for (sal_Int32 i = 0; i < nLen; i += 4) |
656 | 0 | { |
657 | 0 | *pOut++ = rendering::RGBColor( |
658 | 0 | vcl::unotools::toDoubleColor(deviceColor[i]), |
659 | 0 | vcl::unotools::toDoubleColor(deviceColor[i+1]), |
660 | 0 | vcl::unotools::toDoubleColor(deviceColor[i+2])); |
661 | 0 | } |
662 | 0 | return aRes; |
663 | 0 | } |
664 | | |
665 | | virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override |
666 | 0 | { |
667 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
668 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
669 | 0 | "number of channels no multiple of 4", |
670 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
671 | |
|
672 | 0 | uno::Sequence< rendering::ARGBColor > aRes(nLen/4); |
673 | 0 | rendering::ARGBColor* pOut( aRes.getArray() ); |
674 | 0 | for (sal_Int32 i = 0; i < nLen; i += 4) |
675 | 0 | { |
676 | 0 | *pOut++ = rendering::ARGBColor( |
677 | 0 | 1.0, |
678 | 0 | vcl::unotools::toDoubleColor(deviceColor[i]), |
679 | 0 | vcl::unotools::toDoubleColor(deviceColor[i+1]), |
680 | 0 | vcl::unotools::toDoubleColor(deviceColor[i+2])); |
681 | 0 | } |
682 | 0 | return aRes; |
683 | 0 | } |
684 | | |
685 | | virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override |
686 | 0 | { |
687 | 0 | const sal_Int32 nLen(deviceColor.getLength()); |
688 | 0 | ENSURE_ARG_OR_THROW2(nLen%4==0, |
689 | 0 | "number of channels no multiple of 4", |
690 | 0 | static_cast<rendering::XColorSpace*>(this), 0); |
691 | |
|
692 | 0 | uno::Sequence< rendering::ARGBColor > aRes(nLen/4); |
693 | 0 | rendering::ARGBColor* pOut( aRes.getArray() ); |
694 | 0 | for (sal_Int32 i = 0; i < nLen; i += 4) |
695 | 0 | { |
696 | 0 | *pOut++ = rendering::ARGBColor( |
697 | 0 | 1.0, |
698 | 0 | vcl::unotools::toDoubleColor(deviceColor[i]), |
699 | 0 | vcl::unotools::toDoubleColor(deviceColor[i+1]), |
700 | 0 | vcl::unotools::toDoubleColor(deviceColor[i+2])); |
701 | 0 | } |
702 | 0 | return aRes; |
703 | 0 | } |
704 | | |
705 | | virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override |
706 | 0 | { |
707 | 0 | uno::Sequence<sal_Int8> aRes(rgbColor.getLength() * 4); |
708 | 0 | sal_Int8* pColors=aRes.getArray(); |
709 | 0 | for (auto& color : rgbColor) |
710 | 0 | { |
711 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Red); |
712 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Green); |
713 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Blue); |
714 | 0 | *pColors++ = 1.0; |
715 | 0 | } |
716 | 0 | return aRes; |
717 | 0 | } |
718 | | |
719 | | virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override |
720 | 0 | { |
721 | 0 | uno::Sequence<sal_Int8> aRes(rgbColor.getLength() * 4); |
722 | 0 | sal_Int8* pColors=aRes.getArray(); |
723 | 0 | for (auto& color : rgbColor) |
724 | 0 | { |
725 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Red); |
726 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Green); |
727 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Blue); |
728 | 0 | *pColors++ = -1; |
729 | 0 | } |
730 | 0 | return aRes; |
731 | 0 | } |
732 | | |
733 | | virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override |
734 | 0 | { |
735 | 0 | uno::Sequence<sal_Int8> aRes(rgbColor.getLength() * 4); |
736 | 0 | sal_Int8* pColors=aRes.getArray(); |
737 | 0 | for (auto& color : rgbColor) |
738 | 0 | { |
739 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Red / color.Alpha); |
740 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Green / color.Alpha); |
741 | 0 | *pColors++ = vcl::unotools::toByteColor(color.Blue / color.Alpha); |
742 | 0 | *pColors++ = -1; |
743 | 0 | } |
744 | 0 | return aRes; |
745 | 0 | } |
746 | | |
747 | | public: |
748 | | StandardNoAlphaColorSpace() : |
749 | 0 | maComponentTags(3), |
750 | 0 | maBitCounts(3) |
751 | 0 | { |
752 | 0 | sal_Int8* pTags = maComponentTags.getArray(); |
753 | 0 | sal_Int32* pBitCounts = maBitCounts.getArray(); |
754 | 0 | pTags[0] = rendering::ColorComponentTag::RGB_RED; |
755 | 0 | pTags[1] = rendering::ColorComponentTag::RGB_GREEN; |
756 | 0 | pTags[2] = rendering::ColorComponentTag::RGB_BLUE; |
757 | |
|
758 | 0 | pBitCounts[0] = |
759 | 0 | pBitCounts[1] = |
760 | 0 | pBitCounts[2] = 8; |
761 | 0 | } |
762 | | }; |
763 | | |
764 | | } |
765 | | |
766 | | uno::Reference<rendering::XIntegerBitmapColorSpace> const & getStdColorSpace() |
767 | 0 | { |
768 | 0 | static uno::Reference<rendering::XIntegerBitmapColorSpace> SPACE = new StandardColorSpace(); |
769 | 0 | return SPACE; |
770 | 0 | } |
771 | | |
772 | | uno::Reference<rendering::XIntegerBitmapColorSpace> const & getStdColorSpaceWithoutAlpha() |
773 | 0 | { |
774 | 0 | static uno::Reference<rendering::XIntegerBitmapColorSpace> SPACE = new StandardNoAlphaColorSpace(); |
775 | 0 | return SPACE; |
776 | 0 | } |
777 | | |
778 | | rendering::IntegerBitmapLayout getStdMemoryLayout( const geometry::IntegerSize2D& rBmpSize ) |
779 | 0 | { |
780 | 0 | rendering::IntegerBitmapLayout aLayout; |
781 | |
|
782 | 0 | aLayout.ScanLines = rBmpSize.Height; |
783 | 0 | aLayout.ScanLineBytes = rBmpSize.Width*4; |
784 | 0 | aLayout.ScanLineStride = aLayout.ScanLineBytes; |
785 | 0 | aLayout.PlaneStride = 0; |
786 | 0 | aLayout.ColorSpace = getStdColorSpace(); |
787 | 0 | aLayout.Palette.clear(); |
788 | 0 | aLayout.IsMsbFirst = false; |
789 | |
|
790 | 0 | return aLayout; |
791 | 0 | } |
792 | | |
793 | | uno::Sequence<sal_Int8> colorToStdIntSequence( const ::Color& rColor ) |
794 | 0 | { |
795 | 0 | uno::Sequence<sal_Int8> aRet(4); |
796 | 0 | sal_Int8* pCols( aRet.getArray() ); |
797 | | #ifdef OSL_BIGENDIAN |
798 | | pCols[0] = rColor.GetRed(); |
799 | | pCols[1] = rColor.GetGreen(); |
800 | | pCols[2] = rColor.GetBlue(); |
801 | | pCols[3] = rColor.GetAlpha(); |
802 | | #else |
803 | 0 | *reinterpret_cast<sal_Int32*>(pCols) = sal_Int32(rColor); |
804 | 0 | #endif |
805 | 0 | return aRet; |
806 | 0 | } |
807 | | |
808 | | // Create a corrected view transformation out of the give one, |
809 | | // which ensures that the rectangle given by (0,0) and |
810 | | // rSpriteSize is mapped with its left,top corner to (0,0) |
811 | | // again. This is required to properly render sprite |
812 | | // animations to buffer bitmaps. |
813 | | ::basegfx::B2DHomMatrix calcRectToOriginTransform( const ::basegfx::B2DRange& i_srcRect, |
814 | | const ::basegfx::B2DHomMatrix& i_transformation ) |
815 | 0 | { |
816 | 0 | ::basegfx::B2DHomMatrix o_transform; |
817 | 0 | if( i_srcRect.isEmpty() ) |
818 | 0 | { |
819 | 0 | o_transform = i_transformation; |
820 | 0 | return o_transform; |
821 | 0 | } |
822 | | |
823 | | // transform by given transformation |
824 | 0 | ::basegfx::B2DRectangle aTransformedRect = calcTransformedRectBounds( |
825 | 0 | i_srcRect, |
826 | 0 | i_transformation ); |
827 | | |
828 | | // now move resulting left,top point of bounds to (0,0) |
829 | 0 | const basegfx::B2DHomMatrix aCorrectedTransform(basegfx::utils::createTranslateB2DHomMatrix( |
830 | 0 | -aTransformedRect.getMinX(), -aTransformedRect.getMinY())); |
831 | | |
832 | | // prepend to original transformation |
833 | 0 | o_transform = aCorrectedTransform * i_transformation; |
834 | |
|
835 | 0 | return o_transform; |
836 | 0 | } |
837 | | |
838 | | ::basegfx::B2DRange calcTransformedRectBounds( const ::basegfx::B2DRange& inRect, |
839 | | const ::basegfx::B2DHomMatrix& transformation ) |
840 | 0 | { |
841 | 0 | ::basegfx::B2DRange outRect; |
842 | |
|
843 | 0 | if( inRect.isEmpty() ) |
844 | 0 | return outRect; |
845 | | |
846 | | // transform all four extremal points of the rectangle, |
847 | | // take bounding rect of those. |
848 | | |
849 | | // transform left-top point |
850 | 0 | outRect.expand( transformation * inRect.getMinimum() ); |
851 | | |
852 | | // transform bottom-right point |
853 | 0 | outRect.expand( transformation * inRect.getMaximum() ); |
854 | |
|
855 | 0 | ::basegfx::B2DPoint aPoint; |
856 | | |
857 | | // transform top-right point |
858 | 0 | aPoint.setX( inRect.getMaxX() ); |
859 | 0 | aPoint.setY( inRect.getMinY() ); |
860 | |
|
861 | 0 | aPoint *= transformation; |
862 | 0 | outRect.expand( aPoint ); |
863 | | |
864 | | // transform bottom-left point |
865 | 0 | aPoint.setX( inRect.getMinX() ); |
866 | 0 | aPoint.setY( inRect.getMaxY() ); |
867 | |
|
868 | 0 | aPoint *= transformation; |
869 | 0 | outRect.expand( aPoint ); |
870 | | |
871 | | // over and out. |
872 | 0 | return outRect; |
873 | 0 | } |
874 | | |
875 | | bool isInside( const ::basegfx::B2DRange& rContainedRect, |
876 | | const ::basegfx::B2DRange& rTransformRect, |
877 | | const ::basegfx::B2DHomMatrix& rTransformation ) |
878 | 0 | { |
879 | 0 | if( rContainedRect.isEmpty() || rTransformRect.isEmpty() ) |
880 | 0 | return false; |
881 | | |
882 | 0 | ::basegfx::B2DPolygon aPoly( |
883 | 0 | ::basegfx::utils::createPolygonFromRect( rTransformRect ) ); |
884 | 0 | aPoly.transform( rTransformation ); |
885 | |
|
886 | 0 | return ::basegfx::utils::isInside( aPoly, |
887 | 0 | ::basegfx::utils::createPolygonFromRect( |
888 | 0 | rContainedRect ), |
889 | 0 | true ); |
890 | 0 | } |
891 | | |
892 | | namespace |
893 | | { |
894 | | bool clipAreaImpl( ::basegfx::B2IRange* o_pDestArea, |
895 | | ::basegfx::B2IRange& io_rSourceArea, |
896 | | ::basegfx::B2IPoint& io_rDestPoint, |
897 | | const ::basegfx::B2IRange& rSourceBounds, |
898 | | const ::basegfx::B2IRange& rDestBounds ) |
899 | 0 | { |
900 | 0 | const ::basegfx::B2IPoint aSourceTopLeft( |
901 | 0 | io_rSourceArea.getMinimum() ); |
902 | |
|
903 | 0 | ::basegfx::B2IRange aLocalSourceArea( io_rSourceArea ); |
904 | | |
905 | | // clip source area (which must be inside rSourceBounds) |
906 | 0 | aLocalSourceArea.intersect( rSourceBounds ); |
907 | |
|
908 | 0 | if( aLocalSourceArea.isEmpty() ) |
909 | 0 | return false; |
910 | | |
911 | | // calc relative new source area points (relative to orig |
912 | | // source area) |
913 | 0 | const ::basegfx::B2IVector aUpperLeftOffset( |
914 | 0 | aLocalSourceArea.getMinimum()-aSourceTopLeft ); |
915 | 0 | const ::basegfx::B2IVector aLowerRightOffset( |
916 | 0 | aLocalSourceArea.getMaximum()-aSourceTopLeft ); |
917 | |
|
918 | 0 | ::basegfx::B2IRange aLocalDestArea( io_rDestPoint + aUpperLeftOffset, |
919 | 0 | io_rDestPoint + aLowerRightOffset ); |
920 | | |
921 | | // clip dest area (which must be inside rDestBounds) |
922 | 0 | aLocalDestArea.intersect( rDestBounds ); |
923 | |
|
924 | 0 | if( aLocalDestArea.isEmpty() ) |
925 | 0 | return false; |
926 | | |
927 | | // calc relative new dest area points (relative to orig |
928 | | // source area) |
929 | 0 | const ::basegfx::B2IVector aDestUpperLeftOffset( |
930 | 0 | aLocalDestArea.getMinimum()-io_rDestPoint ); |
931 | 0 | const ::basegfx::B2IVector aDestLowerRightOffset( |
932 | 0 | aLocalDestArea.getMaximum()-io_rDestPoint ); |
933 | |
|
934 | 0 | io_rSourceArea = ::basegfx::B2IRange( aSourceTopLeft + aDestUpperLeftOffset, |
935 | 0 | aSourceTopLeft + aDestLowerRightOffset ); |
936 | 0 | io_rDestPoint = aLocalDestArea.getMinimum(); |
937 | |
|
938 | 0 | if( o_pDestArea ) |
939 | 0 | *o_pDestArea = aLocalDestArea; |
940 | |
|
941 | 0 | return true; |
942 | 0 | } |
943 | | } |
944 | | |
945 | | bool clipScrollArea( ::basegfx::B2IRange& io_rSourceArea, |
946 | | ::basegfx::B2IPoint& io_rDestPoint, |
947 | | std::vector< ::basegfx::B2IRange >& o_ClippedAreas, |
948 | | const ::basegfx::B2IRange& rBounds ) |
949 | 0 | { |
950 | 0 | ::basegfx::B2IRange aResultingDestArea; |
951 | | |
952 | | // compute full destination area (to determine uninitialized |
953 | | // areas below) |
954 | 0 | const ::basegfx::B2I64Tuple aRange( io_rSourceArea.getRange() ); |
955 | 0 | ::basegfx::B2IRange aInputDestArea( io_rDestPoint.getX(), |
956 | 0 | io_rDestPoint.getY(), |
957 | 0 | (io_rDestPoint.getX() |
958 | 0 | + static_cast<sal_Int32>(aRange.getX())), |
959 | 0 | (io_rDestPoint.getY() |
960 | 0 | + static_cast<sal_Int32>(aRange.getY())) ); |
961 | | // limit to output area (no point updating outside of it) |
962 | 0 | aInputDestArea.intersect( rBounds ); |
963 | | |
964 | | // clip to rBounds |
965 | 0 | if( !clipAreaImpl( &aResultingDestArea, |
966 | 0 | io_rSourceArea, |
967 | 0 | io_rDestPoint, |
968 | 0 | rBounds, |
969 | 0 | rBounds ) ) |
970 | 0 | return false; |
971 | | |
972 | | // finally, compute all areas clipped off the total |
973 | | // destination area. |
974 | 0 | ::basegfx::computeSetDifference( o_ClippedAreas, |
975 | 0 | aInputDestArea, |
976 | 0 | aResultingDestArea ); |
977 | |
|
978 | 0 | return true; |
979 | 0 | } |
980 | | |
981 | | ::basegfx::B2IRange spritePixelAreaFromB2DRange( const ::basegfx::B2DRange& rRange ) |
982 | 0 | { |
983 | 0 | if( rRange.isEmpty() ) |
984 | 0 | return ::basegfx::B2IRange(); |
985 | | |
986 | 0 | const ::basegfx::B2IPoint aTopLeft( ::basegfx::fround( rRange.getMinX() ), |
987 | 0 | ::basegfx::fround( rRange.getMinY() ) ); |
988 | 0 | return ::basegfx::B2IRange( aTopLeft, |
989 | 0 | aTopLeft + ::basegfx::B2IPoint( |
990 | 0 | ::basegfx::fround( rRange.getWidth() ), |
991 | 0 | ::basegfx::fround( rRange.getHeight() ) ) ); |
992 | 0 | } |
993 | | |
994 | | uno::Sequence< uno::Any >& getDeviceInfo( const uno::Reference< rendering::XCanvas >& i_rxCanvas, |
995 | | uno::Sequence< uno::Any >& o_rxParams ) |
996 | 0 | { |
997 | 0 | o_rxParams.realloc( 0 ); |
998 | |
|
999 | 0 | if( !i_rxCanvas.is() ) |
1000 | 0 | return o_rxParams; |
1001 | | |
1002 | 0 | try |
1003 | 0 | { |
1004 | 0 | uno::Reference< rendering::XGraphicDevice > xDevice( i_rxCanvas->getDevice(), |
1005 | 0 | uno::UNO_SET_THROW ); |
1006 | |
|
1007 | 0 | uno::Reference< lang::XServiceInfo > xServiceInfo( xDevice, |
1008 | 0 | uno::UNO_QUERY_THROW ); |
1009 | 0 | uno::Reference< beans::XPropertySet > xPropSet( xDevice, |
1010 | 0 | uno::UNO_QUERY_THROW ); |
1011 | |
|
1012 | 0 | o_rxParams = { uno::Any(xServiceInfo->getImplementationName()), |
1013 | 0 | xPropSet->getPropertyValue( u"DeviceHandle"_ustr ) }; |
1014 | 0 | } |
1015 | 0 | catch( const uno::Exception& ) |
1016 | 0 | { |
1017 | | // ignore, but return empty sequence |
1018 | 0 | } |
1019 | |
|
1020 | 0 | return o_rxParams; |
1021 | 0 | } |
1022 | | |
1023 | | awt::Rectangle getAbsoluteWindowRect( const awt::Rectangle& rRect, |
1024 | | const uno::Reference< awt::XWindow2 >& xWin ) |
1025 | 0 | { |
1026 | 0 | awt::Rectangle aRetVal( rRect ); |
1027 | |
|
1028 | 0 | VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWin); |
1029 | 0 | if( pWindow ) |
1030 | 0 | { |
1031 | 0 | ::Point aPoint( aRetVal.X, |
1032 | 0 | aRetVal.Y ); |
1033 | |
|
1034 | 0 | aPoint = pWindow->OutputToScreenPixel( aPoint ); |
1035 | |
|
1036 | 0 | aRetVal.X = aPoint.X(); |
1037 | 0 | aRetVal.Y = aPoint.Y(); |
1038 | 0 | } |
1039 | |
|
1040 | 0 | return aRetVal; |
1041 | 0 | } |
1042 | | |
1043 | | ::basegfx::B2DPolyPolygon getBoundMarksPolyPolygon( const ::basegfx::B2DRange& rRange ) |
1044 | 0 | { |
1045 | 0 | ::basegfx::B2DPolyPolygon aPolyPoly; |
1046 | 0 | ::basegfx::B2DPolygon aPoly; |
1047 | |
|
1048 | 0 | const double nX0( rRange.getMinX() ); |
1049 | 0 | const double nY0( rRange.getMinY() ); |
1050 | 0 | const double nX1( rRange.getMaxX() ); |
1051 | 0 | const double nY1( rRange.getMaxY() ); |
1052 | |
|
1053 | 0 | aPoly.append( ::basegfx::B2DPoint( nX0+4, |
1054 | 0 | nY0 ) ); |
1055 | 0 | aPoly.append( ::basegfx::B2DPoint( nX0, |
1056 | 0 | nY0 ) ); |
1057 | 0 | aPoly.append( ::basegfx::B2DPoint( nX0, |
1058 | 0 | nY0+4 ) ); |
1059 | 0 | aPolyPoly.append( aPoly ); aPoly.clear(); |
1060 | |
|
1061 | 0 | aPoly.append( ::basegfx::B2DPoint( nX1-4, |
1062 | 0 | nY0 ) ); |
1063 | 0 | aPoly.append( ::basegfx::B2DPoint( nX1, |
1064 | 0 | nY0 ) ); |
1065 | 0 | aPoly.append( ::basegfx::B2DPoint( nX1, |
1066 | 0 | nY0+4 ) ); |
1067 | 0 | aPolyPoly.append( aPoly ); aPoly.clear(); |
1068 | |
|
1069 | 0 | aPoly.append( ::basegfx::B2DPoint( nX0+4, |
1070 | 0 | nY1 ) ); |
1071 | 0 | aPoly.append( ::basegfx::B2DPoint( nX0, |
1072 | 0 | nY1 ) ); |
1073 | 0 | aPoly.append( ::basegfx::B2DPoint( nX0, |
1074 | 0 | nY1-4 ) ); |
1075 | 0 | aPolyPoly.append( aPoly ); aPoly.clear(); |
1076 | |
|
1077 | 0 | aPoly.append( ::basegfx::B2DPoint( nX1-4, |
1078 | 0 | nY1 ) ); |
1079 | 0 | aPoly.append( ::basegfx::B2DPoint( nX1, |
1080 | 0 | nY1 ) ); |
1081 | 0 | aPoly.append( ::basegfx::B2DPoint( nX1, |
1082 | 0 | nY1-4 ) ); |
1083 | 0 | aPolyPoly.append( aPoly ); |
1084 | |
|
1085 | 0 | return aPolyPoly; |
1086 | 0 | } |
1087 | | |
1088 | | int calcGradientStepCount( ::basegfx::B2DHomMatrix& rTotalTransform, |
1089 | | const rendering::ViewState& viewState, |
1090 | | const rendering::RenderState& renderState, |
1091 | | const rendering::Texture& texture, |
1092 | | int nColorSteps ) |
1093 | 0 | { |
1094 | | // calculate overall texture transformation (directly from |
1095 | | // texture to device space). |
1096 | 0 | ::basegfx::B2DHomMatrix aMatrix; |
1097 | |
|
1098 | 0 | rTotalTransform.identity(); |
1099 | 0 | ::basegfx::unotools::homMatrixFromAffineMatrix( rTotalTransform, |
1100 | 0 | texture.AffineTransform ); |
1101 | 0 | mergeViewAndRenderTransform(aMatrix, viewState, renderState); |
1102 | 0 | rTotalTransform *= aMatrix; // prepend total view/render transformation |
1103 | | |
1104 | | // determine size of gradient in device coordinate system |
1105 | | // (to e.g. determine sensible number of gradient steps) |
1106 | 0 | ::basegfx::B2DPoint aLeftTop( 0.0, 0.0 ); |
1107 | 0 | ::basegfx::B2DPoint aLeftBottom( 0.0, 1.0 ); |
1108 | 0 | ::basegfx::B2DPoint aRightTop( 1.0, 0.0 ); |
1109 | 0 | ::basegfx::B2DPoint aRightBottom( 1.0, 1.0 ); |
1110 | |
|
1111 | 0 | aLeftTop *= rTotalTransform; |
1112 | 0 | aLeftBottom *= rTotalTransform; |
1113 | 0 | aRightTop *= rTotalTransform; |
1114 | 0 | aRightBottom*= rTotalTransform; |
1115 | | |
1116 | | // longest line in gradient bound rect |
1117 | 0 | const int nGradientSize( |
1118 | 0 | static_cast<int>( |
1119 | 0 | std::max( |
1120 | 0 | ::basegfx::B2DVector(aRightBottom-aLeftTop).getLength(), |
1121 | 0 | ::basegfx::B2DVector(aRightTop-aLeftBottom).getLength() ) + 1.0 ) ); |
1122 | | |
1123 | | // typical number for pixel of the same color (strip size) |
1124 | 0 | const int nStripSize( nGradientSize < 50 ? 2 : 4 ); |
1125 | | |
1126 | | // use at least three steps, and at utmost the number of color |
1127 | | // steps |
1128 | 0 | return std::max( 3, |
1129 | 0 | std::min( |
1130 | 0 | nGradientSize / nStripSize, |
1131 | 0 | nColorSteps ) ); |
1132 | 0 | } |
1133 | | |
1134 | | void clipOutDev(const rendering::ViewState& viewState, |
1135 | | const rendering::RenderState& renderState, |
1136 | | OutputDevice& rOutDev) |
1137 | 0 | { |
1138 | | // accumulate non-empty clips into one region |
1139 | 0 | vcl::Region aClipRegion(true); |
1140 | |
|
1141 | 0 | if( viewState.Clip.is() ) |
1142 | 0 | { |
1143 | 0 | ::basegfx::B2DPolyPolygon aClipPoly( |
1144 | 0 | ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(viewState.Clip) ); |
1145 | |
|
1146 | 0 | if( aClipPoly.count() ) |
1147 | 0 | { |
1148 | | // setup non-empty clipping |
1149 | 0 | ::basegfx::B2DHomMatrix aMatrix; |
1150 | 0 | aClipPoly.transform( |
1151 | 0 | ::basegfx::unotools::homMatrixFromAffineMatrix( aMatrix, |
1152 | 0 | viewState.AffineTransform ) ); |
1153 | |
|
1154 | 0 | aClipRegion = vcl::Region::GetRegionFromPolyPolygon( ::tools::PolyPolygon( aClipPoly ) ); |
1155 | 0 | } |
1156 | 0 | else |
1157 | 0 | { |
1158 | | // clip polygon is empty |
1159 | 0 | aClipRegion.SetEmpty(); |
1160 | 0 | } |
1161 | 0 | } |
1162 | |
|
1163 | 0 | if( renderState.Clip.is() ) |
1164 | 0 | { |
1165 | 0 | ::basegfx::B2DPolyPolygon aClipPoly( |
1166 | 0 | ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(renderState.Clip) ); |
1167 | |
|
1168 | 0 | ::basegfx::B2DHomMatrix aMatrix; |
1169 | 0 | aClipPoly.transform(mergeViewAndRenderTransform(aMatrix, viewState, renderState)); |
1170 | |
|
1171 | 0 | if( aClipPoly.count() ) |
1172 | 0 | { |
1173 | | // setup non-empty clipping |
1174 | 0 | vcl::Region aRegion = vcl::Region::GetRegionFromPolyPolygon( ::tools::PolyPolygon( aClipPoly ) ); |
1175 | 0 | aClipRegion.Intersect( aRegion ); |
1176 | 0 | } |
1177 | 0 | else |
1178 | 0 | { |
1179 | | // clip polygon is empty |
1180 | 0 | aClipRegion.SetEmpty(); |
1181 | 0 | } |
1182 | 0 | } |
1183 | | |
1184 | | // setup accumulated clip region. Note that setting an |
1185 | | // empty clip region denotes "clip everything" on the |
1186 | | // OutputDevice (which is why we translate that into |
1187 | | // SetClipRegion() here). When both view and render clip |
1188 | | // are empty, aClipRegion remains default-constructed, |
1189 | | // i.e. empty, too. |
1190 | 0 | if( aClipRegion.IsNull() ) |
1191 | 0 | rOutDev.SetClipRegion(); |
1192 | 0 | else |
1193 | 0 | rOutDev.SetClipRegion( aClipRegion ); |
1194 | 0 | } |
1195 | | |
1196 | | void extractExtraFontProperties(const uno::Sequence<beans::PropertyValue>& rExtraFontProperties, |
1197 | | sal_uInt32 &rEmphasisMark) |
1198 | 0 | { |
1199 | 0 | for(const beans::PropertyValue& rPropVal : rExtraFontProperties) |
1200 | 0 | { |
1201 | 0 | if (rPropVal.Name == "EmphasisMark") |
1202 | 0 | rPropVal.Value >>= rEmphasisMark; |
1203 | 0 | } |
1204 | 0 | } |
1205 | | |
1206 | | } // namespace |
1207 | | |
1208 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |