Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/include/drawinglayer/primitive2d/svggradientprimitive2d.hxx
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
#pragma once
21
22
#include <drawinglayer/drawinglayerdllapi.h>
23
#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
24
#include <basegfx/color/bcolor.hxx>
25
#include <basegfx/polygon/b2dpolypolygon.hxx>
26
#include <basegfx/matrix/b2dhommatrix.hxx>
27
#include <drawinglayer/primitive2d/primitivetools2d.hxx>
28
#include <vector>
29
30
31
// SvgGradientEntry class
32
33
namespace drawinglayer::primitive2d
34
{
35
        /// a single GradientStop defining a color and opacity at a distance
36
        class SvgGradientEntry
37
        {
38
        private:
39
            double              mfOffset;
40
            basegfx::BColor     maColor;
41
            double              mfOpacity;
42
43
        public:
44
            SvgGradientEntry(double fOffset, const basegfx::BColor& rColor, double fOpacity)
45
166
            :   mfOffset(fOffset),
46
166
                maColor(rColor),
47
166
                mfOpacity(fOpacity)
48
166
            {
49
166
            }
50
51
212
            double getOffset() const { return mfOffset; }
52
0
            const basegfx::BColor& getColor() const { return maColor; }
53
160
            double getOpacity() const { return mfOpacity; }
54
55
            bool operator==(const SvgGradientEntry& rCompare) const
56
0
            {
57
0
                return (getOffset() == rCompare.getOffset()
58
0
                    && getColor() == rCompare.getColor()
59
0
                    && getOpacity() == rCompare.getOpacity());
60
0
            }
61
62
            bool operator<(const SvgGradientEntry& rCompare) const
63
53
            {
64
53
                return getOffset() < rCompare.getOffset();
65
53
            }
66
        };
67
68
        typedef ::std::vector< SvgGradientEntry > SvgGradientEntryVector;
69
70
        // SvgGradientHelper class
71
72
        enum class SpreadMethod
73
        {
74
            Pad,
75
            Reflect,
76
            Repeat
77
        };
78
79
        /*  helper for linear and radial gradient, both get derived from this
80
            to share common definitions and functionality
81
         **/
82
        class SAL_LOPLUGIN_ANNOTATE("crosscast") SvgGradientHelper
83
        {
84
        private:
85
            /// the extra gradient transform
86
            basegfx::B2DHomMatrix       maGradientTransform;
87
88
            /// geometric definition, the geometry to be filled
89
            basegfx::B2DPolyPolygon     maPolyPolygon;
90
91
            /// the gradient definition
92
            SvgGradientEntryVector      maGradientEntries;
93
94
            // internal helper for case SpreadMethod::Reflect
95
            SvgGradientEntryVector      maMirroredGradientEntries;
96
97
            /// start and/or center point
98
            basegfx::B2DPoint           maStart;
99
100
            /// how to spread
101
            SpreadMethod                maSpreadMethod;
102
103
            bool                        mbCreatesContent : 1;
104
            bool                        mbSingleEntry : 1;
105
            bool                        mbFullyOpaque : 1;
106
107
            // true = interpret in unit coordinate system -> object aspect ratio will scale result
108
            // false = interpret in object coordinate system -> object aspect ratio will not scale result
109
            // (related to SVG's gradientUnits (userSpaceOnUse|objectBoundingBox)
110
            bool                        mbUseUnitCoordinates : 1;
111
112
            /// local helpers
113
            const SvgGradientEntryVector& getMirroredGradientEntries() const;
114
            void createMirroredGradientEntries();
115
            const SvgGradientEntry& FindEntryLessOrEqual(sal_Int32& rInt, const double fFrac) const;
116
            const SvgGradientEntry& FindEntryMore(sal_Int32& rInt,const double fFrac) const;
117
118
        protected:
119
            /// local helpers
120
            Primitive2DReference createSingleGradientEntryFill() const;
121
            virtual void createAtom(
122
                Primitive2DContainer& rTargetColor,
123
                Primitive2DContainer& rTargetOpacity,
124
                const SvgGradientEntry& rFrom,
125
                const SvgGradientEntry& rTo,
126
                sal_Int32 nOffsetFrom,
127
                sal_Int32 nOffsetTo) const = 0;
128
            void createRun(
129
                Primitive2DContainer& rTargetColor,
130
                Primitive2DContainer& rTargetOpacity,
131
                double fStart,
132
                double fEnd) const;
133
            virtual void checkPreconditions();
134
            Primitive2DReference createResult(
135
                Primitive2DContainer aTargetColor,
136
                Primitive2DContainer aTargetOpacity,
137
                const basegfx::B2DHomMatrix& rUnitGradientToObject,
138
                bool bInvert = false) const;
139
140
0
            void setSingleEntry() { mbSingleEntry = true; }
141
0
            bool getFullyOpaque() const { return mbFullyOpaque; }
142
143
        public:
144
53
            bool getCreatesContent() const { return mbCreatesContent; }
145
0
            bool getSingleEntry() const { return mbSingleEntry; }
146
147
            /// constructor
148
            SvgGradientHelper(
149
                basegfx::B2DHomMatrix aGradientTransform,
150
                basegfx::B2DPolyPolygon aPolyPolygon,
151
                SvgGradientEntryVector&& rGradientEntries,
152
                const basegfx::B2DPoint& rStart,
153
                bool bUseUnitCoordinates,
154
                SpreadMethod aSpreadMethod);
155
            virtual ~SvgGradientHelper();
156
157
            /// data read access
158
0
            const basegfx::B2DHomMatrix& getGradientTransform() const { return maGradientTransform; }
159
105
            const basegfx::B2DPolyPolygon& getPolyPolygon() const { return maPolyPolygon; }
160
53
            const SvgGradientEntryVector& getGradientEntries() const { return maGradientEntries; }
161
0
            const basegfx::B2DPoint& getStart() const { return maStart; }
162
0
            bool getUseUnitCoordinates() const { return mbUseUnitCoordinates; }
163
0
            SpreadMethod getSpreadMethod() const { return maSpreadMethod; }
164
165
            /// compare operator
166
            bool operator==(const SvgGradientHelper& rSvgGradientHelper) const;
167
168
            /// create transformation from UnitGrandient to ObjectTransform
169
            virtual basegfx::B2DHomMatrix createUnitGradientToObjectTransformation() const = 0;
170
        };
171
172
        /// the basic linear gradient primitive
173
        class DRAWINGLAYER_DLLPUBLIC SvgLinearGradientPrimitive2D final : public BufferedDecompositionPrimitive2D, public SvgGradientHelper
174
        {
175
        private:
176
            /// the end point for linear gradient
177
            basegfx::B2DPoint                       maEnd;
178
179
            /// local helpers
180
            virtual void createAtom(
181
                Primitive2DContainer& rTargetColor,
182
                Primitive2DContainer& rTargetOpacity,
183
                const SvgGradientEntry& rFrom,
184
                const SvgGradientEntry& rTo,
185
                sal_Int32 nOffsetFrom,
186
                sal_Int32 nOffsetTo) const override;
187
            virtual void checkPreconditions() override;
188
189
            /// local decomposition.
190
            virtual Primitive2DReference create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const override;
191
192
        public:
193
            /// constructor
194
            SvgLinearGradientPrimitive2D(
195
                const basegfx::B2DHomMatrix& rGradientTransform,
196
                const basegfx::B2DPolyPolygon& rPolyPolygon,
197
                SvgGradientEntryVector&& rGradientEntries,
198
                const basegfx::B2DPoint& rStart,
199
                const basegfx::B2DPoint& rEnd,
200
                bool bUseUnitCoordinates,
201
                SpreadMethod aSpreadMethod);
202
            virtual ~SvgLinearGradientPrimitive2D() override;
203
204
            /// data read access
205
0
            const basegfx::B2DPoint& getEnd() const { return maEnd; }
206
207
            /// compare operator
208
            virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
209
210
            /// get range
211
            virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
212
213
            /// provide unique ID
214
            virtual sal_uInt32 getPrimitive2DID() const override;
215
216
            /// create transformation from UnitGrandient to ObjectTransform
217
            virtual basegfx::B2DHomMatrix createUnitGradientToObjectTransformation() const override;
218
        };
219
220
        /// the basic radial gradient primitive
221
        class DRAWINGLAYER_DLLPUBLIC SvgRadialGradientPrimitive2D final : public BufferedDecompositionPrimitive2D, public SvgGradientHelper
222
        {
223
        private:
224
            /// the geometric definition
225
            double                                  mfRadius;
226
227
            /// Focal only used when focal is set at all, see constructors
228
            basegfx::B2DPoint                       maFocal;
229
            double                                  maFocalLength;
230
231
            /// local helpers
232
            virtual void createAtom(
233
                Primitive2DContainer& rTargetColor,
234
                Primitive2DContainer& rTargetOpacity,
235
                const SvgGradientEntry& rFrom,
236
                const SvgGradientEntry& rTo,
237
                sal_Int32 nOffsetFrom,
238
                sal_Int32 nOffsetTo) const override;
239
            virtual void checkPreconditions() override;
240
241
            /// local decomposition.
242
            virtual Primitive2DReference create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const override;
243
244
        public:
245
            /// constructor
246
            SvgRadialGradientPrimitive2D(
247
                const basegfx::B2DHomMatrix& rGradientTransform,
248
                const basegfx::B2DPolyPolygon& rPolyPolygon,
249
                SvgGradientEntryVector&& rGradientEntries,
250
                const basegfx::B2DPoint& rStart,
251
                double fRadius,
252
                bool bUseUnitCoordinates,
253
                SpreadMethod aSpreadMethod,
254
                const basegfx::B2DPoint* pFocal);
255
            virtual ~SvgRadialGradientPrimitive2D() override;
256
257
            /// data read access
258
0
            double getRadius() const { return mfRadius; }
259
0
            const basegfx::B2DPoint& getFocal() const { return maFocal; }
260
0
            bool isFocalSet() const { return !maFocal.equal(getStart()); }
261
262
            /// compare operator
263
            virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
264
265
            /// get range
266
            virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
267
268
            /// provide unique ID
269
            virtual sal_uInt32 getPrimitive2DID() const override;
270
271
            /// create transformation from UnitGrandient to ObjectTransform
272
            virtual basegfx::B2DHomMatrix createUnitGradientToObjectTransformation() const override;
273
        };
274
275
        // SvgLinearAtomPrimitive2D class
276
277
        /*  basic primitive for a single linear GradientRun in unit coordinates.
278
            It's derived from DiscreteMetricDependentPrimitive2D to allow view-dependent
279
            decompositions allowing reduced color steps
280
         **/
281
        class SvgLinearAtomPrimitive2D final : public DiscreteMetricDependentPrimitive2D
282
        {
283
        private:
284
            /// the geometric definition in unit coordinates
285
            basegfx::BColor             maColorA;
286
            basegfx::BColor             maColorB;
287
            double                      mfOffsetA;
288
            double                      mfOffsetB;
289
290
            /// local decomposition.
291
            virtual Primitive2DReference create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const override;
292
293
        public:
294
            /// constructor
295
            SvgLinearAtomPrimitive2D(
296
                const basegfx::BColor& aColorA, double fOffsetA,
297
                const basegfx::BColor& aColorB, double fOffsetB);
298
299
            /// data read access
300
0
            const basegfx::BColor& getColorA() const { return maColorA; }
301
0
            const basegfx::BColor& getColorB() const { return maColorB; }
302
0
            double getOffsetA() const { return mfOffsetA; }
303
0
            double getOffsetB() const { return mfOffsetB; }
304
305
            /// compare operator
306
            virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
307
308
            /// provide unique ID
309
            virtual sal_uInt32 getPrimitive2DID() const override;
310
        };
311
312
        // SvgRadialAtomPrimitive2D class
313
314
        /*  basic primitive for a single radial GradientRun in unit coordinates.
315
            It's derived from DiscreteMetricDependentPrimitive2D to allow view-dependent
316
            decompositions allowing reduced color steps
317
         **/
318
        class SvgRadialAtomPrimitive2D final : public DiscreteMetricDependentPrimitive2D
319
        {
320
        private:
321
            /// the geometric definition in unit coordinates
322
            basegfx::BColor             maColorA;
323
            basegfx::BColor             maColorB;
324
            double                      mfScaleA;
325
            double                      mfScaleB;
326
327
            // helper to hold translation vectors when given (for focal)
328
            struct VectorPair
329
            {
330
                basegfx::B2DVector          maTranslateA;
331
                basegfx::B2DVector          maTranslateB;
332
333
                VectorPair(const basegfx::B2DVector& rTranslateA, const basegfx::B2DVector& rTranslateB)
334
0
                :   maTranslateA(rTranslateA),
335
0
                    maTranslateB(rTranslateB)
336
0
                {
337
0
                }
338
            };
339
340
            /// Only used when focal is set
341
            std::unique_ptr<VectorPair> mpTranslate;
342
343
            /// local decomposition.
344
            virtual Primitive2DReference create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const override;
345
346
        public:
347
            /// constructor
348
            SvgRadialAtomPrimitive2D(
349
                const basegfx::BColor& aColorA, double fScaleA, const basegfx::B2DVector& rTranslateA,
350
                const basegfx::BColor& aColorB, double fScaleB, const basegfx::B2DVector& rTranslateB);
351
            SvgRadialAtomPrimitive2D(
352
                const basegfx::BColor& aColorA, double fScaleA,
353
                const basegfx::BColor& aColorB, double fScaleB);
354
            virtual ~SvgRadialAtomPrimitive2D() override;
355
356
            /// data read access
357
0
            const basegfx::BColor& getColorA() const { return maColorA; }
358
0
            const basegfx::BColor& getColorB() const { return maColorB; }
359
0
            double getScaleA() const { return mfScaleA; }
360
0
            double getScaleB() const { return mfScaleB; }
361
0
            bool isTranslateSet() const { return (nullptr != mpTranslate); }
362
0
            basegfx::B2DVector getTranslateA() const { if(mpTranslate) return mpTranslate->maTranslateA; return basegfx::B2DVector(); }
363
0
            basegfx::B2DVector getTranslateB() const { if(mpTranslate) return mpTranslate->maTranslateB; return basegfx::B2DVector(); }
364
365
            /// compare operator
366
            virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
367
368
            /// provide unique ID
369
            virtual sal_uInt32 getPrimitive2DID() const override;
370
        };
371
} // end of namespace drawinglayer::primitive2d
372
373
374
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */