Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */