Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/drawinglayer/source/attribute/fillgradientattribute.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 <drawinglayer/attribute/fillgradientattribute.hxx>
21
#include <basegfx/utils/bgradient.hxx>
22
23
namespace drawinglayer::attribute
24
{
25
        class ImpFillGradientAttribute
26
        {
27
        public:
28
            // data definitions
29
            double                                  mfBorder;
30
            double                                  mfOffsetX;
31
            double                                  mfOffsetY;
32
            double                                  mfAngle;
33
            basegfx::BColorStops                    maColorStops;
34
            css::awt::GradientStyle                 meStyle;
35
            sal_uInt16                              mnSteps;
36
37
            ImpFillGradientAttribute(
38
                css::awt::GradientStyle eStyle,
39
                double fBorder,
40
                double fOffsetX,
41
                double fOffsetY,
42
                double fAngle,
43
                const basegfx::BColorStops& rColorStops,
44
                sal_uInt16 nSteps)
45
0
            :   mfBorder(fBorder),
46
0
                mfOffsetX(fOffsetX),
47
0
                mfOffsetY(fOffsetY),
48
0
                mfAngle(fAngle),
49
0
                maColorStops(rColorStops), // copy ColorStops
50
0
                meStyle(eStyle),
51
0
                mnSteps(nSteps)
52
0
            {
53
                // Correct the local ColorStops. That will guarantee that the
54
                // content does contain no offsets < 0.0, > 1.0 or double
55
                // ones, also secures sorted arrangement and checks for
56
                // double colors, too (see there for more information).
57
                // This is what the usages of this in primitives need.
58
                // Since FillGradientAttribute is read-only doing this
59
                // once here in the constructor is sufficient
60
0
                maColorStops.sortAndCorrect();
61
62
                // sortAndCorrectColorStops is rigid and can return
63
                // an empty result. To keep things simple, add a single
64
                // fallback value
65
0
                if (maColorStops.empty())
66
0
                {
67
0
                    maColorStops.addStop(0.0, basegfx::BColor());
68
0
                }
69
0
            }
70
71
            ImpFillGradientAttribute()
72
8
            :   mfBorder(0.0),
73
8
                mfOffsetX(0.0),
74
8
                mfOffsetY(0.0),
75
8
                mfAngle(0.0),
76
8
                maColorStops(),
77
8
                meStyle(css::awt::GradientStyle_LINEAR),
78
8
                mnSteps(0)
79
8
            {
80
                // always add a fallback color, see above
81
8
                maColorStops.addStop(0.0, basegfx::BColor());
82
8
            }
83
84
            // data read access
85
0
            css::awt::GradientStyle getStyle() const { return meStyle; }
86
0
            double getBorder() const { return mfBorder; }
87
0
            double getOffsetX() const { return mfOffsetX; }
88
0
            double getOffsetY() const { return mfOffsetY; }
89
0
            double getAngle() const { return mfAngle; }
90
0
            const basegfx::BColorStops& getColorStops() const { return maColorStops; }
91
0
            sal_uInt16 getSteps() const { return mnSteps; }
92
93
            bool operator==(const ImpFillGradientAttribute& rCandidate) const
94
0
            {
95
0
                return (getStyle() == rCandidate.getStyle()
96
0
                    && getBorder() == rCandidate.getBorder()
97
0
                    && getOffsetX() == rCandidate.getOffsetX()
98
0
                    && getOffsetY() == rCandidate.getOffsetY()
99
0
                    && getAngle() == rCandidate.getAngle()
100
0
                    && getColorStops() == rCandidate.getColorStops()
101
0
                    && getSteps() == rCandidate.getSteps());
102
0
            }
103
        };
104
105
        namespace
106
        {
107
            FillGradientAttribute::ImplType& theGlobalDefault()
108
61.1k
            {
109
61.1k
                static FillGradientAttribute::ImplType SINGLETON;
110
61.1k
                return SINGLETON;
111
61.1k
            }
112
        }
113
114
        FillGradientAttribute::FillGradientAttribute(
115
            css::awt::GradientStyle eStyle,
116
            double fBorder,
117
            double fOffsetX,
118
            double fOffsetY,
119
            double fAngle,
120
            const basegfx::BColorStops& rColorStops,
121
            sal_uInt16 nSteps)
122
0
        :   mpFillGradientAttribute(ImpFillGradientAttribute(
123
0
                eStyle, fBorder, fOffsetX, fOffsetY, fAngle, rColorStops, nSteps))
124
0
        {
125
0
        }
126
127
        FillGradientAttribute::FillGradientAttribute()
128
58.1k
        :   mpFillGradientAttribute(theGlobalDefault())
129
58.1k
        {
130
58.1k
        }
131
132
2.17k
        FillGradientAttribute::FillGradientAttribute(const FillGradientAttribute&) = default;
133
134
59.2k
        FillGradientAttribute::FillGradientAttribute(FillGradientAttribute&&) = default;
135
136
119k
        FillGradientAttribute::~FillGradientAttribute() = default;
137
138
        bool FillGradientAttribute::isDefault() const
139
3.02k
        {
140
3.02k
            return mpFillGradientAttribute.same_object(theGlobalDefault());
141
3.02k
        }
142
143
        // MCGR: Check if rendering cannot be handled by old vcl stuff
144
        bool FillGradientAttribute::cannotBeHandledByVCL() const
145
0
        {
146
            // MCGR: If GradientStops are used, use decomposition since vcl is not able
147
            // to render multi-color gradients
148
0
            if (getColorStops().size() != 2)
149
0
            {
150
0
                return true;
151
0
            }
152
153
            // MCGR: If GradientStops do not start and stop at traditional Start/EndColor,
154
            // use decomposition since vcl is not able to render this
155
0
            if (!getColorStops().empty())
156
0
            {
157
0
                if (!basegfx::fTools::equalZero(getColorStops().front().getStopOffset())
158
0
                    || !basegfx::fTools::equal(getColorStops().back().getStopOffset(), 1.0))
159
0
                {
160
0
                    return true;
161
0
                }
162
0
            }
163
164
            // VCL should be able to handle all styles, but for tdf#133477 the VCL result
165
            // is different from processing the gradient manually by drawinglayer
166
            // (and the Writer unittest for it fails). Keep using the drawinglayer code
167
            // until somebody founds out what's wrong and fixes it.
168
0
            if (getStyle() != css::awt::GradientStyle_LINEAR
169
0
                && getStyle() != css::awt::GradientStyle_AXIAL
170
0
                && getStyle() != css::awt::GradientStyle_RADIAL)
171
0
            {
172
0
                return true;
173
0
            }
174
175
0
            return false;
176
0
        }
177
178
0
        FillGradientAttribute& FillGradientAttribute::operator=(const FillGradientAttribute&) = default;
179
180
305
        FillGradientAttribute& FillGradientAttribute::operator=(FillGradientAttribute&&) = default;
181
182
        bool FillGradientAttribute::operator==(const FillGradientAttribute& rCandidate) const
183
385
        {
184
            // tdf#87509 default attr is always != non-default attr, even with same values
185
385
            if(rCandidate.isDefault() != isDefault())
186
0
                return false;
187
188
385
            return rCandidate.mpFillGradientAttribute == mpFillGradientAttribute;
189
385
        }
190
191
        const basegfx::BColorStops& FillGradientAttribute::getColorStops() const
192
0
        {
193
0
            return mpFillGradientAttribute->getColorStops();
194
0
        }
195
196
        double FillGradientAttribute::getBorder() const
197
0
        {
198
0
            return mpFillGradientAttribute->getBorder();
199
0
        }
200
201
        double FillGradientAttribute::getOffsetX() const
202
0
        {
203
0
            return mpFillGradientAttribute->getOffsetX();
204
0
        }
205
206
        double FillGradientAttribute::getOffsetY() const
207
0
        {
208
0
            return mpFillGradientAttribute->getOffsetY();
209
0
        }
210
211
        double FillGradientAttribute::getAngle() const
212
0
        {
213
0
            return mpFillGradientAttribute->getAngle();
214
0
        }
215
216
        css::awt::GradientStyle FillGradientAttribute::getStyle() const
217
0
        {
218
0
            return mpFillGradientAttribute->getStyle();
219
0
        }
220
221
        sal_uInt16 FillGradientAttribute::getSteps() const
222
0
        {
223
0
            return mpFillGradientAttribute->getSteps();
224
0
        }
225
226
        bool FillGradientAttribute::sameDefinitionThanAlpha(const FillGradientAttribute& rAlpha) const
227
0
        {
228
            // entries that are used by all gradient styles
229
0
            if (getStyle() != rAlpha.getStyle()
230
0
                || getBorder() != rAlpha.getBorder()
231
0
                || getSteps() != rAlpha.getSteps())
232
0
            {
233
0
                return false;
234
0
            }
235
236
            // check for offsets if not ignored
237
0
            const bool bIgnoreOffset(css::awt::GradientStyle_LINEAR == getStyle() || css::awt::GradientStyle_AXIAL == getStyle());
238
0
            if (!bIgnoreOffset && (getOffsetX() != rAlpha.getOffsetX() || getOffsetY() != rAlpha.getOffsetY()))
239
0
            {
240
0
                return false;
241
0
            }
242
243
            // check for angle if not ignored
244
0
            const bool bIgnoreAngle(css::awt::GradientStyle_RADIAL == getStyle());
245
0
            if (!bIgnoreAngle && getAngle() != rAlpha.getAngle())
246
0
            {
247
0
                return false;
248
0
            }
249
250
            // check for same count & offsets in the gradients (all except 'colors')
251
0
            if (!getColorStops().sameSizeAndDistances(rAlpha.getColorStops()))
252
0
            {
253
0
                return false;
254
0
            }
255
256
0
            return true;
257
0
        }
258
259
} // end of namespace
260
261
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */