Move setting of LD_LIBRARY_PATH closer to invocation of cppunittester
[LibreOffice.git] / canvas / source / tools / canvastools.cxx
blobcf72e8fed4018425e057a1090c719079817a8408
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 <sal/config.h>
22 #include <limits>
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>
60 #include <canvas/canvastools.hxx>
63 using namespace ::com::sun::star;
65 namespace canvas::tools
67 geometry::RealSize2D createInfiniteSize2D()
69 return geometry::RealSize2D(
70 std::numeric_limits<double>::infinity(),
71 std::numeric_limits<double>::infinity() );
74 rendering::RenderState& initRenderState( rendering::RenderState& renderState )
76 // setup identity transform
77 setIdentityAffineMatrix2D( renderState.AffineTransform );
78 renderState.Clip.clear();
79 renderState.DeviceColor = uno::Sequence< double >();
80 renderState.CompositeOperation = rendering::CompositeOperation::OVER;
82 return renderState;
85 rendering::ViewState& initViewState( rendering::ViewState& viewState )
87 // setup identity transform
88 setIdentityAffineMatrix2D( viewState.AffineTransform );
89 viewState.Clip.clear();
91 return viewState;
94 ::basegfx::B2DHomMatrix getViewStateTransform( const rendering::ViewState& viewState )
96 ::basegfx::B2DHomMatrix aTransform;
97 return ::basegfx::unotools::homMatrixFromAffineMatrix( aTransform, viewState.AffineTransform );
100 rendering::ViewState& setViewStateTransform( rendering::ViewState& viewState,
101 const ::basegfx::B2DHomMatrix& transform )
103 ::basegfx::unotools::affineMatrixFromHomMatrix( viewState.AffineTransform, transform );
105 return viewState;
108 ::basegfx::B2DHomMatrix getRenderStateTransform( const rendering::RenderState& renderState )
110 ::basegfx::B2DHomMatrix aTransform;
111 return ::basegfx::unotools::homMatrixFromAffineMatrix( aTransform, renderState.AffineTransform );
114 rendering::RenderState& setRenderStateTransform( rendering::RenderState& renderState,
115 const ::basegfx::B2DHomMatrix& transform )
117 ::basegfx::unotools::affineMatrixFromHomMatrix( renderState.AffineTransform, transform );
119 return renderState;
122 rendering::RenderState& appendToRenderState( rendering::RenderState& renderState,
123 const ::basegfx::B2DHomMatrix& rTransform )
125 ::basegfx::B2DHomMatrix transform = getRenderStateTransform( renderState );
126 return setRenderStateTransform( renderState, transform * rTransform );
129 rendering::RenderState& prependToRenderState( rendering::RenderState& renderState,
130 const ::basegfx::B2DHomMatrix& rTransform )
132 ::basegfx::B2DHomMatrix transform = getRenderStateTransform( renderState );
133 return setRenderStateTransform( renderState, rTransform * transform );
136 ::basegfx::B2DHomMatrix& mergeViewAndRenderTransform( ::basegfx::B2DHomMatrix& combinedTransform,
137 const rendering::ViewState& viewState,
138 const rendering::RenderState& renderState )
140 ::basegfx::B2DHomMatrix viewTransform;
142 ::basegfx::unotools::homMatrixFromAffineMatrix( combinedTransform, renderState.AffineTransform );
143 ::basegfx::unotools::homMatrixFromAffineMatrix( viewTransform, viewState.AffineTransform );
145 // this statement performs combinedTransform = viewTransform * combinedTransform
146 combinedTransform *= viewTransform;
148 return combinedTransform;
151 geometry::AffineMatrix2D& setIdentityAffineMatrix2D( geometry::AffineMatrix2D& matrix )
153 matrix.m00 = 1.0;
154 matrix.m01 = 0.0;
155 matrix.m02 = 0.0;
156 matrix.m10 = 0.0;
157 matrix.m11 = 1.0;
158 matrix.m12 = 0.0;
160 return matrix;
163 geometry::Matrix2D& setIdentityMatrix2D( geometry::Matrix2D& matrix )
165 matrix.m00 = 1.0;
166 matrix.m01 = 0.0;
167 matrix.m10 = 0.0;
168 matrix.m11 = 1.0;
170 return matrix;
173 namespace
175 class StandardColorSpace : public cppu::WeakImplHelper< css::rendering::XIntegerBitmapColorSpace >
177 private:
178 uno::Sequence< sal_Int8 > maComponentTags;
179 uno::Sequence< sal_Int32 > maBitCounts;
181 virtual ::sal_Int8 SAL_CALL getType( ) override
183 return rendering::ColorSpaceType::RGB;
185 virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) override
187 return maComponentTags;
189 virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) override
191 return rendering::RenderingIntent::PERCEPTUAL;
193 virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) override
195 return uno::Sequence< beans::PropertyValue >();
197 virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
198 const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
200 // TODO(P3): if we know anything about target
201 // colorspace, this can be greatly sped up
202 uno::Sequence<rendering::ARGBColor> aIntermediate(
203 convertToARGB(deviceColor));
204 return targetColorSpace->convertFromARGB(aIntermediate);
206 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) override
208 const sal_Int32 nLen(deviceColor.getLength());
209 ENSURE_ARG_OR_THROW2(nLen%4==0,
210 "number of channels no multiple of 4",
211 static_cast<rendering::XColorSpace*>(this), 0);
213 uno::Sequence< rendering::RGBColor > aRes(nLen/4);
214 rendering::RGBColor* pOut( aRes.getArray() );
215 for (sal_Int32 i = 0; i < nLen; i += 4)
217 *pOut++ = rendering::RGBColor(deviceColor[i], deviceColor[i+1], deviceColor[i+2]);
219 return aRes;
221 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) override
223 SAL_WARN_IF(!deviceColor.hasElements(), "canvas", "empty deviceColor argument");
224 const sal_Int32 nLen(deviceColor.getLength());
225 ENSURE_ARG_OR_THROW2(nLen%4==0,
226 "number of channels no multiple of 4",
227 static_cast<rendering::XColorSpace*>(this), 0);
229 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
230 rendering::ARGBColor* pOut( aRes.getArray() );
231 for (sal_Int32 i = 0; i < nLen; i += 4)
233 *pOut++ = rendering::ARGBColor(deviceColor[i+3], deviceColor[i], deviceColor[i+1], deviceColor[i+2]);
235 return aRes;
237 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) override
239 const sal_Int32 nLen(deviceColor.getLength());
240 ENSURE_ARG_OR_THROW2(nLen%4==0,
241 "number of channels no multiple of 4",
242 static_cast<rendering::XColorSpace*>(this), 0);
244 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
245 rendering::ARGBColor* pOut( aRes.getArray() );
246 for (sal_Int32 i = 0; i < nLen; i += 4)
248 *pOut++ = rendering::ARGBColor(deviceColor[i+3],
249 deviceColor[i+3] * deviceColor[i],
250 deviceColor[i+3] * deviceColor[i+1],
251 deviceColor[i+3] * deviceColor[i+2]);
253 return aRes;
255 virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
257 uno::Sequence<double> aRes(rgbColor.getLength() * 4);
258 double* pColors=aRes.getArray();
259 for (auto& color : rgbColor)
261 *pColors++ = color.Red;
262 *pColors++ = color.Green;
263 *pColors++ = color.Blue;
264 *pColors++ = 1.0;
266 return aRes;
268 virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
270 uno::Sequence<double> aRes(rgbColor.getLength() * 4);
271 double* pColors=aRes.getArray();
272 for (auto& color : rgbColor)
274 *pColors++ = color.Red;
275 *pColors++ = color.Green;
276 *pColors++ = color.Blue;
277 *pColors++ = color.Alpha;
279 return aRes;
281 virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
283 uno::Sequence<double> aRes(rgbColor.getLength() * 4);
284 double* pColors=aRes.getArray();
285 for (auto& color : rgbColor)
287 *pColors++ = color.Red / color.Alpha;
288 *pColors++ = color.Green / color.Alpha;
289 *pColors++ = color.Blue / color.Alpha;
290 *pColors++ = color.Alpha;
292 return aRes;
295 // XIntegerBitmapColorSpace
296 virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) override
298 return 32;
300 virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) override
302 return maBitCounts;
304 virtual ::sal_Int8 SAL_CALL getEndianness( ) override
306 return util::Endianness::LITTLE;
308 virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
309 const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
311 if( dynamic_cast<StandardColorSpace*>(targetColorSpace.get()) )
313 const sal_Int32 nLen(deviceColor.getLength());
314 ENSURE_ARG_OR_THROW2(nLen%4==0,
315 "number of channels no multiple of 4",
316 static_cast<rendering::XColorSpace*>(this), 0);
318 uno::Sequence<double> aRes(nLen);
319 std::transform(deviceColor.begin(), deviceColor.end(), aRes.getArray(),
320 [](auto c) { return vcl::unotools::toDoubleColor(c); });
321 return aRes;
323 else
325 // TODO(P3): if we know anything about target
326 // colorspace, this can be greatly sped up
327 uno::Sequence<rendering::ARGBColor> aIntermediate(
328 convertIntegerToARGB(deviceColor));
329 return targetColorSpace->convertFromARGB(aIntermediate);
332 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
333 const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) override
335 if( dynamic_cast<StandardColorSpace*>(targetColorSpace.get()) )
337 // it's us, so simply pass-through the data
338 return deviceColor;
340 else
342 // TODO(P3): if we know anything about target
343 // colorspace, this can be greatly sped up
344 uno::Sequence<rendering::ARGBColor> aIntermediate(
345 convertIntegerToARGB(deviceColor));
346 return targetColorSpace->convertIntegerFromARGB(aIntermediate);
349 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
351 const sal_Int32 nLen(deviceColor.getLength());
352 ENSURE_ARG_OR_THROW2(nLen%4==0,
353 "number of channels no multiple of 4",
354 static_cast<rendering::XColorSpace*>(this), 0);
356 uno::Sequence< rendering::RGBColor > aRes(nLen/4);
357 rendering::RGBColor* pOut( aRes.getArray() );
358 for (sal_Int32 i = 0; i < nLen; i += 4)
360 *pOut++ = rendering::RGBColor(
361 vcl::unotools::toDoubleColor(deviceColor[i]),
362 vcl::unotools::toDoubleColor(deviceColor[i+1]),
363 vcl::unotools::toDoubleColor(deviceColor[i+2]));
365 return aRes;
368 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
370 const sal_Int32 nLen(deviceColor.getLength());
371 ENSURE_ARG_OR_THROW2(nLen%4==0,
372 "number of channels no multiple of 4",
373 static_cast<rendering::XColorSpace*>(this), 0);
375 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
376 rendering::ARGBColor* pOut( aRes.getArray() );
377 for (sal_Int32 i = 0; i < nLen; i += 4)
379 *pOut++ = rendering::ARGBColor(
380 vcl::unotools::toDoubleColor(deviceColor[i+3]),
381 vcl::unotools::toDoubleColor(deviceColor[i]),
382 vcl::unotools::toDoubleColor(deviceColor[i+1]),
383 vcl::unotools::toDoubleColor(deviceColor[i+2]));
385 return aRes;
388 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
390 const sal_Int32 nLen(deviceColor.getLength());
391 ENSURE_ARG_OR_THROW2(nLen%4==0,
392 "number of channels no multiple of 4",
393 static_cast<rendering::XColorSpace*>(this), 0);
395 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
396 rendering::ARGBColor* pOut( aRes.getArray() );
397 for (sal_Int32 i = 0; i < nLen; i += 4)
399 const sal_Int8 nAlpha(deviceColor[i+3]);
400 *pOut++ = rendering::ARGBColor(
401 vcl::unotools::toDoubleColor(nAlpha),
402 vcl::unotools::toDoubleColor(nAlpha * deviceColor[i]),
403 vcl::unotools::toDoubleColor(nAlpha * deviceColor[i+1]),
404 vcl::unotools::toDoubleColor(nAlpha * deviceColor[i+2]));
406 return aRes;
409 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
411 uno::Sequence<sal_Int8> aRes(rgbColor.getLength() * 4);
412 sal_Int8* pColors=aRes.getArray();
413 for (auto& color : rgbColor)
415 *pColors++ = vcl::unotools::toByteColor(color.Red);
416 *pColors++ = vcl::unotools::toByteColor(color.Green);
417 *pColors++ = vcl::unotools::toByteColor(color.Blue);
418 *pColors++ = 0;
420 return aRes;
423 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
425 uno::Sequence<sal_Int8> aRes(rgbColor.getLength() * 4);
426 sal_Int8* pColors=aRes.getArray();
427 for (auto& color : rgbColor)
429 *pColors++ = vcl::unotools::toByteColor(color.Red);
430 *pColors++ = vcl::unotools::toByteColor(color.Green);
431 *pColors++ = vcl::unotools::toByteColor(color.Blue);
432 *pColors++ = vcl::unotools::toByteColor(color.Alpha);
434 return aRes;
437 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
439 uno::Sequence<sal_Int8> aRes(rgbColor.getLength() * 4);
440 sal_Int8* pColors=aRes.getArray();
441 for (auto& color : rgbColor)
443 *pColors++ = vcl::unotools::toByteColor(color.Red / color.Alpha);
444 *pColors++ = vcl::unotools::toByteColor(color.Green / color.Alpha);
445 *pColors++ = vcl::unotools::toByteColor(color.Blue / color.Alpha);
446 *pColors++ = vcl::unotools::toByteColor(color.Alpha);
448 return aRes;
451 public:
452 StandardColorSpace() :
453 maComponentTags(4),
454 maBitCounts(4)
456 sal_Int8* pTags = maComponentTags.getArray();
457 sal_Int32* pBitCounts = maBitCounts.getArray();
458 pTags[0] = rendering::ColorComponentTag::RGB_RED;
459 pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
460 pTags[2] = rendering::ColorComponentTag::RGB_BLUE;
461 pTags[3] = rendering::ColorComponentTag::ALPHA;
463 pBitCounts[0] =
464 pBitCounts[1] =
465 pBitCounts[2] =
466 pBitCounts[3] = 8;
470 class StandardNoAlphaColorSpace : public cppu::WeakImplHelper< css::rendering::XIntegerBitmapColorSpace >
472 private:
473 uno::Sequence< sal_Int8 > maComponentTags;
474 uno::Sequence< sal_Int32 > maBitCounts;
476 virtual ::sal_Int8 SAL_CALL getType( ) override
478 return rendering::ColorSpaceType::RGB;
480 virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) override
482 return maComponentTags;
484 virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) override
486 return rendering::RenderingIntent::PERCEPTUAL;
488 virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) override
490 return uno::Sequence< beans::PropertyValue >();
492 virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
493 const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
495 // TODO(P3): if we know anything about target
496 // colorspace, this can be greatly sped up
497 uno::Sequence<rendering::ARGBColor> aIntermediate(
498 convertToARGB(deviceColor));
499 return targetColorSpace->convertFromARGB(aIntermediate);
501 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) override
503 const sal_Int32 nLen(deviceColor.getLength());
504 ENSURE_ARG_OR_THROW2(nLen%4==0,
505 "number of channels no multiple of 4",
506 static_cast<rendering::XColorSpace*>(this), 0);
508 uno::Sequence< rendering::RGBColor > aRes(nLen/4);
509 rendering::RGBColor* pOut( aRes.getArray() );
510 for (sal_Int32 i = 0; i < nLen; i += 4)
512 *pOut++ = rendering::RGBColor(deviceColor[i], deviceColor[i+1], deviceColor[i+2]);
514 return aRes;
516 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) override
518 const sal_Int32 nLen(deviceColor.getLength());
519 ENSURE_ARG_OR_THROW2(nLen%4==0,
520 "number of channels no multiple of 4",
521 static_cast<rendering::XColorSpace*>(this), 0);
523 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
524 rendering::ARGBColor* pOut( aRes.getArray() );
525 for (sal_Int32 i = 0; i < nLen; i += 4)
527 *pOut++ = rendering::ARGBColor(1.0, deviceColor[i], deviceColor[i+1], deviceColor[i+2]);
529 return aRes;
531 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) override
533 const sal_Int32 nLen(deviceColor.getLength());
534 ENSURE_ARG_OR_THROW2(nLen%4==0,
535 "number of channels no multiple of 4",
536 static_cast<rendering::XColorSpace*>(this), 0);
538 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
539 rendering::ARGBColor* pOut( aRes.getArray() );
540 for (sal_Int32 i = 0; i < nLen; i += 4)
542 *pOut++ = rendering::ARGBColor(1.0, deviceColor[i], deviceColor[i+1], deviceColor[i+2]);
544 return aRes;
546 virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
548 uno::Sequence<double> aRes(rgbColor.getLength() * 4);
549 double* pColors=aRes.getArray();
550 for (auto& color : rgbColor)
552 *pColors++ = color.Red;
553 *pColors++ = color.Green;
554 *pColors++ = color.Blue;
555 *pColors++ = 1.0; // the value does not matter
557 return aRes;
559 virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
561 uno::Sequence<double> aRes(rgbColor.getLength() * 4);
562 double* pColors=aRes.getArray();
563 for (auto& color : rgbColor)
565 *pColors++ = color.Red;
566 *pColors++ = color.Green;
567 *pColors++ = color.Blue;
568 *pColors++ = 1.0; // the value does not matter
570 return aRes;
572 virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
574 uno::Sequence<double> aRes(rgbColor.getLength() * 4);
575 double* pColors=aRes.getArray();
576 for (auto& color : rgbColor)
578 *pColors++ = color.Red / color.Alpha;
579 *pColors++ = color.Green / color.Alpha;
580 *pColors++ = color.Blue / color.Alpha;
581 *pColors++ = 1.0; // the value does not matter
583 return aRes;
586 // XIntegerBitmapColorSpace
587 virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) override
589 return 32;
591 virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) override
593 return maBitCounts;
595 virtual ::sal_Int8 SAL_CALL getEndianness( ) override
597 return util::Endianness::LITTLE;
599 virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
600 const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
602 if( dynamic_cast<StandardNoAlphaColorSpace*>(targetColorSpace.get()) )
604 const sal_Int32 nLen(deviceColor.getLength());
605 ENSURE_ARG_OR_THROW2(nLen%4==0,
606 "number of channels no multiple of 4",
607 static_cast<rendering::XColorSpace*>(this), 0);
609 uno::Sequence<double> aRes(nLen);
610 double* pOut( aRes.getArray() );
611 for (sal_Int32 i = 0; i < nLen; i += 4)
613 *pOut++ = vcl::unotools::toDoubleColor(deviceColor[i]);
614 *pOut++ = vcl::unotools::toDoubleColor(deviceColor[i+1]);
615 *pOut++ = vcl::unotools::toDoubleColor(deviceColor[i+2]);
616 *pOut++ = 1.0;
618 return aRes;
620 else
622 // TODO(P3): if we know anything about target
623 // colorspace, this can be greatly sped up
624 uno::Sequence<rendering::ARGBColor> aIntermediate(
625 convertIntegerToARGB(deviceColor));
626 return targetColorSpace->convertFromARGB(aIntermediate);
629 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
630 const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) override
632 if( dynamic_cast<StandardNoAlphaColorSpace*>(targetColorSpace.get()) )
634 // it's us, so simply pass-through the data
635 return deviceColor;
637 else
639 // TODO(P3): if we know anything about target
640 // colorspace, this can be greatly sped up
641 uno::Sequence<rendering::ARGBColor> aIntermediate(
642 convertIntegerToARGB(deviceColor));
643 return targetColorSpace->convertIntegerFromARGB(aIntermediate);
646 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
648 const sal_Int32 nLen(deviceColor.getLength());
649 ENSURE_ARG_OR_THROW2(nLen%4==0,
650 "number of channels no multiple of 4",
651 static_cast<rendering::XColorSpace*>(this), 0);
653 uno::Sequence< rendering::RGBColor > aRes(nLen/4);
654 rendering::RGBColor* pOut( aRes.getArray() );
655 for (sal_Int32 i = 0; i < nLen; i += 4)
657 *pOut++ = rendering::RGBColor(
658 vcl::unotools::toDoubleColor(deviceColor[i]),
659 vcl::unotools::toDoubleColor(deviceColor[i+1]),
660 vcl::unotools::toDoubleColor(deviceColor[i+2]));
662 return aRes;
665 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
667 const sal_Int32 nLen(deviceColor.getLength());
668 ENSURE_ARG_OR_THROW2(nLen%4==0,
669 "number of channels no multiple of 4",
670 static_cast<rendering::XColorSpace*>(this), 0);
672 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
673 rendering::ARGBColor* pOut( aRes.getArray() );
674 for (sal_Int32 i = 0; i < nLen; i += 4)
676 *pOut++ = rendering::ARGBColor(
677 1.0,
678 vcl::unotools::toDoubleColor(deviceColor[i]),
679 vcl::unotools::toDoubleColor(deviceColor[i+1]),
680 vcl::unotools::toDoubleColor(deviceColor[i+2]));
682 return aRes;
685 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
687 const sal_Int32 nLen(deviceColor.getLength());
688 ENSURE_ARG_OR_THROW2(nLen%4==0,
689 "number of channels no multiple of 4",
690 static_cast<rendering::XColorSpace*>(this), 0);
692 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
693 rendering::ARGBColor* pOut( aRes.getArray() );
694 for (sal_Int32 i = 0; i < nLen; i += 4)
696 *pOut++ = rendering::ARGBColor(
697 1.0,
698 vcl::unotools::toDoubleColor(deviceColor[i]),
699 vcl::unotools::toDoubleColor(deviceColor[i+1]),
700 vcl::unotools::toDoubleColor(deviceColor[i+2]));
702 return aRes;
705 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
707 uno::Sequence<sal_Int8> aRes(rgbColor.getLength() * 4);
708 sal_Int8* pColors=aRes.getArray();
709 for (auto& color : rgbColor)
711 *pColors++ = vcl::unotools::toByteColor(color.Red);
712 *pColors++ = vcl::unotools::toByteColor(color.Green);
713 *pColors++ = vcl::unotools::toByteColor(color.Blue);
714 *pColors++ = 1.0;
716 return aRes;
719 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
721 uno::Sequence<sal_Int8> aRes(rgbColor.getLength() * 4);
722 sal_Int8* pColors=aRes.getArray();
723 for (auto& color : rgbColor)
725 *pColors++ = vcl::unotools::toByteColor(color.Red);
726 *pColors++ = vcl::unotools::toByteColor(color.Green);
727 *pColors++ = vcl::unotools::toByteColor(color.Blue);
728 *pColors++ = -1;
730 return aRes;
733 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
735 uno::Sequence<sal_Int8> aRes(rgbColor.getLength() * 4);
736 sal_Int8* pColors=aRes.getArray();
737 for (auto& color : rgbColor)
739 *pColors++ = vcl::unotools::toByteColor(color.Red / color.Alpha);
740 *pColors++ = vcl::unotools::toByteColor(color.Green / color.Alpha);
741 *pColors++ = vcl::unotools::toByteColor(color.Blue / color.Alpha);
742 *pColors++ = -1;
744 return aRes;
747 public:
748 StandardNoAlphaColorSpace() :
749 maComponentTags(3),
750 maBitCounts(3)
752 sal_Int8* pTags = maComponentTags.getArray();
753 sal_Int32* pBitCounts = maBitCounts.getArray();
754 pTags[0] = rendering::ColorComponentTag::RGB_RED;
755 pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
756 pTags[2] = rendering::ColorComponentTag::RGB_BLUE;
758 pBitCounts[0] =
759 pBitCounts[1] =
760 pBitCounts[2] = 8;
766 uno::Reference<rendering::XIntegerBitmapColorSpace> const & getStdColorSpace()
768 static uno::Reference<rendering::XIntegerBitmapColorSpace> SPACE = new StandardColorSpace();
769 return SPACE;
772 uno::Reference<rendering::XIntegerBitmapColorSpace> const & getStdColorSpaceWithoutAlpha()
774 static uno::Reference<rendering::XIntegerBitmapColorSpace> SPACE = new StandardNoAlphaColorSpace();
775 return SPACE;
778 rendering::IntegerBitmapLayout getStdMemoryLayout( const geometry::IntegerSize2D& rBmpSize )
780 rendering::IntegerBitmapLayout aLayout;
782 aLayout.ScanLines = rBmpSize.Height;
783 aLayout.ScanLineBytes = rBmpSize.Width*4;
784 aLayout.ScanLineStride = aLayout.ScanLineBytes;
785 aLayout.PlaneStride = 0;
786 aLayout.ColorSpace = getStdColorSpace();
787 aLayout.Palette.clear();
788 aLayout.IsMsbFirst = false;
790 return aLayout;
793 uno::Sequence<sal_Int8> colorToStdIntSequence( const ::Color& rColor )
795 uno::Sequence<sal_Int8> aRet(4);
796 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 *reinterpret_cast<sal_Int32*>(pCols) = sal_Int32(rColor);
804 #endif
805 return aRet;
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 )
816 ::basegfx::B2DHomMatrix o_transform;
817 if( i_srcRect.isEmpty() )
819 o_transform = i_transformation;
820 return o_transform;
823 // transform by given transformation
824 ::basegfx::B2DRectangle aTransformedRect = calcTransformedRectBounds(
825 i_srcRect,
826 i_transformation );
828 // now move resulting left,top point of bounds to (0,0)
829 const basegfx::B2DHomMatrix aCorrectedTransform(basegfx::utils::createTranslateB2DHomMatrix(
830 -aTransformedRect.getMinX(), -aTransformedRect.getMinY()));
832 // prepend to original transformation
833 o_transform = aCorrectedTransform * i_transformation;
835 return o_transform;
838 ::basegfx::B2DRange calcTransformedRectBounds( const ::basegfx::B2DRange& inRect,
839 const ::basegfx::B2DHomMatrix& transformation )
841 ::basegfx::B2DRange outRect;
843 if( inRect.isEmpty() )
844 return outRect;
846 // transform all four extremal points of the rectangle,
847 // take bounding rect of those.
849 // transform left-top point
850 outRect.expand( transformation * inRect.getMinimum() );
852 // transform bottom-right point
853 outRect.expand( transformation * inRect.getMaximum() );
855 ::basegfx::B2DPoint aPoint;
857 // transform top-right point
858 aPoint.setX( inRect.getMaxX() );
859 aPoint.setY( inRect.getMinY() );
861 aPoint *= transformation;
862 outRect.expand( aPoint );
864 // transform bottom-left point
865 aPoint.setX( inRect.getMinX() );
866 aPoint.setY( inRect.getMaxY() );
868 aPoint *= transformation;
869 outRect.expand( aPoint );
871 // over and out.
872 return outRect;
875 bool isInside( const ::basegfx::B2DRange& rContainedRect,
876 const ::basegfx::B2DRange& rTransformRect,
877 const ::basegfx::B2DHomMatrix& rTransformation )
879 if( rContainedRect.isEmpty() || rTransformRect.isEmpty() )
880 return false;
882 ::basegfx::B2DPolygon aPoly(
883 ::basegfx::utils::createPolygonFromRect( rTransformRect ) );
884 aPoly.transform( rTransformation );
886 return ::basegfx::utils::isInside( aPoly,
887 ::basegfx::utils::createPolygonFromRect(
888 rContainedRect ),
889 true );
892 namespace
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 )
900 const ::basegfx::B2IPoint aSourceTopLeft(
901 io_rSourceArea.getMinimum() );
903 ::basegfx::B2IRange aLocalSourceArea( io_rSourceArea );
905 // clip source area (which must be inside rSourceBounds)
906 aLocalSourceArea.intersect( rSourceBounds );
908 if( aLocalSourceArea.isEmpty() )
909 return false;
911 // calc relative new source area points (relative to orig
912 // source area)
913 const ::basegfx::B2IVector aUpperLeftOffset(
914 aLocalSourceArea.getMinimum()-aSourceTopLeft );
915 const ::basegfx::B2IVector aLowerRightOffset(
916 aLocalSourceArea.getMaximum()-aSourceTopLeft );
918 ::basegfx::B2IRange aLocalDestArea( io_rDestPoint + aUpperLeftOffset,
919 io_rDestPoint + aLowerRightOffset );
921 // clip dest area (which must be inside rDestBounds)
922 aLocalDestArea.intersect( rDestBounds );
924 if( aLocalDestArea.isEmpty() )
925 return false;
927 // calc relative new dest area points (relative to orig
928 // source area)
929 const ::basegfx::B2IVector aDestUpperLeftOffset(
930 aLocalDestArea.getMinimum()-io_rDestPoint );
931 const ::basegfx::B2IVector aDestLowerRightOffset(
932 aLocalDestArea.getMaximum()-io_rDestPoint );
934 io_rSourceArea = ::basegfx::B2IRange( aSourceTopLeft + aDestUpperLeftOffset,
935 aSourceTopLeft + aDestLowerRightOffset );
936 io_rDestPoint = aLocalDestArea.getMinimum();
938 if( o_pDestArea )
939 *o_pDestArea = aLocalDestArea;
941 return true;
945 bool clipScrollArea( ::basegfx::B2IRange& io_rSourceArea,
946 ::basegfx::B2IPoint& io_rDestPoint,
947 std::vector< ::basegfx::B2IRange >& o_ClippedAreas,
948 const ::basegfx::B2IRange& rBounds )
950 ::basegfx::B2IRange aResultingDestArea;
952 // compute full destination area (to determine uninitialized
953 // areas below)
954 const ::basegfx::B2I64Tuple aRange( io_rSourceArea.getRange() );
955 ::basegfx::B2IRange aInputDestArea( io_rDestPoint.getX(),
956 io_rDestPoint.getY(),
957 (io_rDestPoint.getX()
958 + static_cast<sal_Int32>(aRange.getX())),
959 (io_rDestPoint.getY()
960 + static_cast<sal_Int32>(aRange.getY())) );
961 // limit to output area (no point updating outside of it)
962 aInputDestArea.intersect( rBounds );
964 // clip to rBounds
965 if( !clipAreaImpl( &aResultingDestArea,
966 io_rSourceArea,
967 io_rDestPoint,
968 rBounds,
969 rBounds ) )
970 return false;
972 // finally, compute all areas clipped off the total
973 // destination area.
974 ::basegfx::computeSetDifference( o_ClippedAreas,
975 aInputDestArea,
976 aResultingDestArea );
978 return true;
981 ::basegfx::B2IRange spritePixelAreaFromB2DRange( const ::basegfx::B2DRange& rRange )
983 if( rRange.isEmpty() )
984 return ::basegfx::B2IRange();
986 const ::basegfx::B2IPoint aTopLeft( ::basegfx::fround( rRange.getMinX() ),
987 ::basegfx::fround( rRange.getMinY() ) );
988 return ::basegfx::B2IRange( aTopLeft,
989 aTopLeft + ::basegfx::B2IPoint(
990 ::basegfx::fround( rRange.getWidth() ),
991 ::basegfx::fround( rRange.getHeight() ) ) );
994 uno::Sequence< uno::Any >& getDeviceInfo( const uno::Reference< rendering::XCanvas >& i_rxCanvas,
995 uno::Sequence< uno::Any >& o_rxParams )
997 o_rxParams.realloc( 0 );
999 if( !i_rxCanvas.is() )
1000 return o_rxParams;
1004 uno::Reference< rendering::XGraphicDevice > xDevice( i_rxCanvas->getDevice(),
1005 uno::UNO_SET_THROW );
1007 uno::Reference< lang::XServiceInfo > xServiceInfo( xDevice,
1008 uno::UNO_QUERY_THROW );
1009 uno::Reference< beans::XPropertySet > xPropSet( xDevice,
1010 uno::UNO_QUERY_THROW );
1012 o_rxParams = { uno::Any(xServiceInfo->getImplementationName()),
1013 xPropSet->getPropertyValue( u"DeviceHandle"_ustr ) };
1015 catch( const uno::Exception& )
1017 // ignore, but return empty sequence
1020 return o_rxParams;
1023 awt::Rectangle getAbsoluteWindowRect( const awt::Rectangle& rRect,
1024 const uno::Reference< awt::XWindow2 >& xWin )
1026 awt::Rectangle aRetVal( rRect );
1028 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWin);
1029 if( pWindow )
1031 ::Point aPoint( aRetVal.X,
1032 aRetVal.Y );
1034 aPoint = pWindow->OutputToScreenPixel( aPoint );
1036 aRetVal.X = aPoint.X();
1037 aRetVal.Y = aPoint.Y();
1040 return aRetVal;
1043 ::basegfx::B2DPolyPolygon getBoundMarksPolyPolygon( const ::basegfx::B2DRange& rRange )
1045 ::basegfx::B2DPolyPolygon aPolyPoly;
1046 ::basegfx::B2DPolygon aPoly;
1048 const double nX0( rRange.getMinX() );
1049 const double nY0( rRange.getMinY() );
1050 const double nX1( rRange.getMaxX() );
1051 const double nY1( rRange.getMaxY() );
1053 aPoly.append( ::basegfx::B2DPoint( nX0+4,
1054 nY0 ) );
1055 aPoly.append( ::basegfx::B2DPoint( nX0,
1056 nY0 ) );
1057 aPoly.append( ::basegfx::B2DPoint( nX0,
1058 nY0+4 ) );
1059 aPolyPoly.append( aPoly ); aPoly.clear();
1061 aPoly.append( ::basegfx::B2DPoint( nX1-4,
1062 nY0 ) );
1063 aPoly.append( ::basegfx::B2DPoint( nX1,
1064 nY0 ) );
1065 aPoly.append( ::basegfx::B2DPoint( nX1,
1066 nY0+4 ) );
1067 aPolyPoly.append( aPoly ); aPoly.clear();
1069 aPoly.append( ::basegfx::B2DPoint( nX0+4,
1070 nY1 ) );
1071 aPoly.append( ::basegfx::B2DPoint( nX0,
1072 nY1 ) );
1073 aPoly.append( ::basegfx::B2DPoint( nX0,
1074 nY1-4 ) );
1075 aPolyPoly.append( aPoly ); aPoly.clear();
1077 aPoly.append( ::basegfx::B2DPoint( nX1-4,
1078 nY1 ) );
1079 aPoly.append( ::basegfx::B2DPoint( nX1,
1080 nY1 ) );
1081 aPoly.append( ::basegfx::B2DPoint( nX1,
1082 nY1-4 ) );
1083 aPolyPoly.append( aPoly );
1085 return aPolyPoly;
1088 int calcGradientStepCount( ::basegfx::B2DHomMatrix& rTotalTransform,
1089 const rendering::ViewState& viewState,
1090 const rendering::RenderState& renderState,
1091 const rendering::Texture& texture,
1092 int nColorSteps )
1094 // calculate overall texture transformation (directly from
1095 // texture to device space).
1096 ::basegfx::B2DHomMatrix aMatrix;
1098 rTotalTransform.identity();
1099 ::basegfx::unotools::homMatrixFromAffineMatrix( rTotalTransform,
1100 texture.AffineTransform );
1101 ::canvas::tools::mergeViewAndRenderTransform(aMatrix,
1102 viewState,
1103 renderState);
1104 rTotalTransform *= aMatrix; // prepend total view/render transformation
1106 // determine size of gradient in device coordinate system
1107 // (to e.g. determine sensible number of gradient steps)
1108 ::basegfx::B2DPoint aLeftTop( 0.0, 0.0 );
1109 ::basegfx::B2DPoint aLeftBottom( 0.0, 1.0 );
1110 ::basegfx::B2DPoint aRightTop( 1.0, 0.0 );
1111 ::basegfx::B2DPoint aRightBottom( 1.0, 1.0 );
1113 aLeftTop *= rTotalTransform;
1114 aLeftBottom *= rTotalTransform;
1115 aRightTop *= rTotalTransform;
1116 aRightBottom*= rTotalTransform;
1118 // longest line in gradient bound rect
1119 const int nGradientSize(
1120 static_cast<int>(
1121 std::max(
1122 ::basegfx::B2DVector(aRightBottom-aLeftTop).getLength(),
1123 ::basegfx::B2DVector(aRightTop-aLeftBottom).getLength() ) + 1.0 ) );
1125 // typical number for pixel of the same color (strip size)
1126 const int nStripSize( nGradientSize < 50 ? 2 : 4 );
1128 // use at least three steps, and at utmost the number of color
1129 // steps
1130 return std::max( 3,
1131 std::min(
1132 nGradientSize / nStripSize,
1133 nColorSteps ) );
1136 void clipOutDev(const rendering::ViewState& viewState,
1137 const rendering::RenderState& renderState,
1138 OutputDevice& rOutDev,
1139 OutputDevice* p2ndOutDev)
1141 // accumulate non-empty clips into one region
1142 vcl::Region aClipRegion(true);
1144 if( viewState.Clip.is() )
1146 ::basegfx::B2DPolyPolygon aClipPoly(
1147 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(viewState.Clip) );
1149 if( aClipPoly.count() )
1151 // setup non-empty clipping
1152 ::basegfx::B2DHomMatrix aMatrix;
1153 aClipPoly.transform(
1154 ::basegfx::unotools::homMatrixFromAffineMatrix( aMatrix,
1155 viewState.AffineTransform ) );
1157 aClipRegion = vcl::Region::GetRegionFromPolyPolygon( ::tools::PolyPolygon( aClipPoly ) );
1159 else
1161 // clip polygon is empty
1162 aClipRegion.SetEmpty();
1166 if( renderState.Clip.is() )
1168 ::basegfx::B2DPolyPolygon aClipPoly(
1169 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(renderState.Clip) );
1171 ::basegfx::B2DHomMatrix aMatrix;
1172 aClipPoly.transform(
1173 ::canvas::tools::mergeViewAndRenderTransform( aMatrix,
1174 viewState,
1175 renderState ) );
1177 if( aClipPoly.count() )
1179 // setup non-empty clipping
1180 vcl::Region aRegion = vcl::Region::GetRegionFromPolyPolygon( ::tools::PolyPolygon( aClipPoly ) );
1181 aClipRegion.Intersect( aRegion );
1183 else
1185 // clip polygon is empty
1186 aClipRegion.SetEmpty();
1190 // setup accumulated clip region. Note that setting an
1191 // empty clip region denotes "clip everything" on the
1192 // OutputDevice (which is why we translate that into
1193 // SetClipRegion() here). When both view and render clip
1194 // are empty, aClipRegion remains default-constructed,
1195 // i.e. empty, too.
1196 if( aClipRegion.IsNull() )
1198 rOutDev.SetClipRegion();
1200 if( p2ndOutDev )
1201 p2ndOutDev->SetClipRegion();
1203 else
1205 rOutDev.SetClipRegion( aClipRegion );
1207 if( p2ndOutDev )
1208 p2ndOutDev->SetClipRegion( aClipRegion );
1212 void extractExtraFontProperties(const uno::Sequence<beans::PropertyValue>& rExtraFontProperties,
1213 sal_uInt32 &rEmphasisMark)
1215 for(const beans::PropertyValue& rPropVal : rExtraFontProperties)
1217 if (rPropVal.Name == "EmphasisMark")
1218 rPropVal.Value >>= rEmphasisMark;
1222 } // namespace
1224 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */