1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
85 rendering::ViewState
& initViewState( rendering::ViewState
& viewState
)
87 // setup identity transform
88 setIdentityAffineMatrix2D( viewState
.AffineTransform
);
89 viewState
.Clip
.clear();
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
);
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
);
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
)
163 geometry::Matrix2D
& setIdentityMatrix2D( geometry::Matrix2D
& matrix
)
175 class StandardColorSpace
: public cppu::WeakImplHelper
< css::rendering::XIntegerBitmapColorSpace
>
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]);
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]);
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]);
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
;
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
;
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
;
295 // XIntegerBitmapColorSpace
296 virtual ::sal_Int32 SAL_CALL
getBitsPerPixel( ) override
300 virtual uno::Sequence
< ::sal_Int32
> SAL_CALL
getComponentBitCounts( ) override
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
); });
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
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]));
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]));
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]));
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
);
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
);
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
);
452 StandardColorSpace() :
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
;
470 class StandardNoAlphaColorSpace
: public cppu::WeakImplHelper
< css::rendering::XIntegerBitmapColorSpace
>
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]);
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]);
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]);
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
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
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
586 // XIntegerBitmapColorSpace
587 virtual ::sal_Int32 SAL_CALL
getBitsPerPixel( ) override
591 virtual uno::Sequence
< ::sal_Int32
> SAL_CALL
getComponentBitCounts( ) override
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]);
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
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]));
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(
678 vcl::unotools::toDoubleColor(deviceColor
[i
]),
679 vcl::unotools::toDoubleColor(deviceColor
[i
+1]),
680 vcl::unotools::toDoubleColor(deviceColor
[i
+2]));
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(
698 vcl::unotools::toDoubleColor(deviceColor
[i
]),
699 vcl::unotools::toDoubleColor(deviceColor
[i
+1]),
700 vcl::unotools::toDoubleColor(deviceColor
[i
+2]));
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
);
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
);
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
);
748 StandardNoAlphaColorSpace() :
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
;
766 uno::Reference
<rendering::XIntegerBitmapColorSpace
> const & getStdColorSpace()
768 static uno::Reference
<rendering::XIntegerBitmapColorSpace
> SPACE
= new StandardColorSpace();
772 uno::Reference
<rendering::XIntegerBitmapColorSpace
> const & getStdColorSpaceWithoutAlpha()
774 static uno::Reference
<rendering::XIntegerBitmapColorSpace
> SPACE
= new StandardNoAlphaColorSpace();
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;
793 uno::Sequence
<sal_Int8
> colorToStdIntSequence( const ::Color
& rColor
)
795 uno::Sequence
<sal_Int8
> aRet(4);
796 sal_Int8
* pCols( aRet
.getArray() );
798 pCols
[0] = rColor
.GetRed();
799 pCols
[1] = rColor
.GetGreen();
800 pCols
[2] = rColor
.GetBlue();
801 pCols
[3] = rColor
.GetAlpha();
803 *reinterpret_cast<sal_Int32
*>(pCols
) = sal_Int32(rColor
);
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
;
823 // transform by given transformation
824 ::basegfx::B2DRectangle aTransformedRect
= calcTransformedRectBounds(
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
;
838 ::basegfx::B2DRange
calcTransformedRectBounds( const ::basegfx::B2DRange
& inRect
,
839 const ::basegfx::B2DHomMatrix
& transformation
)
841 ::basegfx::B2DRange outRect
;
843 if( inRect
.isEmpty() )
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
);
875 bool isInside( const ::basegfx::B2DRange
& rContainedRect
,
876 const ::basegfx::B2DRange
& rTransformRect
,
877 const ::basegfx::B2DHomMatrix
& rTransformation
)
879 if( rContainedRect
.isEmpty() || rTransformRect
.isEmpty() )
882 ::basegfx::B2DPolygon
aPoly(
883 ::basegfx::utils::createPolygonFromRect( rTransformRect
) );
884 aPoly
.transform( rTransformation
);
886 return ::basegfx::utils::isInside( aPoly
,
887 ::basegfx::utils::createPolygonFromRect(
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() )
911 // calc relative new source area points (relative to orig
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() )
927 // calc relative new dest area points (relative to orig
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();
939 *o_pDestArea
= aLocalDestArea
;
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
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
);
965 if( !clipAreaImpl( &aResultingDestArea
,
972 // finally, compute all areas clipped off the total
974 ::basegfx::computeSetDifference( o_ClippedAreas
,
976 aResultingDestArea
);
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() )
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
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
);
1031 ::Point
aPoint( aRetVal
.X
,
1034 aPoint
= pWindow
->OutputToScreenPixel( aPoint
);
1036 aRetVal
.X
= aPoint
.X();
1037 aRetVal
.Y
= aPoint
.Y();
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,
1055 aPoly
.append( ::basegfx::B2DPoint( nX0
,
1057 aPoly
.append( ::basegfx::B2DPoint( nX0
,
1059 aPolyPoly
.append( aPoly
); aPoly
.clear();
1061 aPoly
.append( ::basegfx::B2DPoint( nX1
-4,
1063 aPoly
.append( ::basegfx::B2DPoint( nX1
,
1065 aPoly
.append( ::basegfx::B2DPoint( nX1
,
1067 aPolyPoly
.append( aPoly
); aPoly
.clear();
1069 aPoly
.append( ::basegfx::B2DPoint( nX0
+4,
1071 aPoly
.append( ::basegfx::B2DPoint( nX0
,
1073 aPoly
.append( ::basegfx::B2DPoint( nX0
,
1075 aPolyPoly
.append( aPoly
); aPoly
.clear();
1077 aPoly
.append( ::basegfx::B2DPoint( nX1
-4,
1079 aPoly
.append( ::basegfx::B2DPoint( nX1
,
1081 aPoly
.append( ::basegfx::B2DPoint( nX1
,
1083 aPolyPoly
.append( aPoly
);
1088 int calcGradientStepCount( ::basegfx::B2DHomMatrix
& rTotalTransform
,
1089 const rendering::ViewState
& viewState
,
1090 const rendering::RenderState
& renderState
,
1091 const rendering::Texture
& texture
,
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
,
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(
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
1132 nGradientSize
/ nStripSize
,
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
) );
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
,
1177 if( aClipPoly
.count() )
1179 // setup non-empty clipping
1180 vcl::Region aRegion
= vcl::Region::GetRegionFromPolyPolygon( ::tools::PolyPolygon( aClipPoly
) );
1181 aClipRegion
.Intersect( aRegion
);
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,
1196 if( aClipRegion
.IsNull() )
1198 rOutDev
.SetClipRegion();
1201 p2ndOutDev
->SetClipRegion();
1205 rOutDev
.SetClipRegion( aClipRegion
);
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
;
1224 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */