Coverage Report

Created: 2026-07-10 11:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/drawinglayer/source/attribute/sdrfillgraphicattribute.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 <algorithm>
23
24
#include <basegfx/point/b2dpoint.hxx>
25
#include <basegfx/range/b2drange.hxx>
26
#include <basegfx/vector/b2dvector.hxx>
27
#include <drawinglayer/attribute/sdrfillgraphicattribute.hxx>
28
#include <drawinglayer/attribute/fillgraphicattribute.hxx>
29
#include <utility>
30
#include <vcl/graph.hxx>
31
32
33
namespace drawinglayer::attribute
34
{
35
        class ImpSdrFillGraphicAttribute
36
        {
37
        public:
38
            // data definitions
39
            Graphic                                 maFillGraphic;
40
            basegfx::B2DVector                      maGraphicLogicSize;
41
            basegfx::B2DVector                      maSize;
42
            basegfx::B2DVector                      maOffset;
43
            basegfx::B2DVector                      maOffsetPosition;
44
            basegfx::B2DVector                      maRectPoint;
45
46
            bool                                    mbTiling : 1;
47
            bool                                    mbStretch : 1;
48
            bool                                    mbLogSize : 1;
49
50
            ImpSdrFillGraphicAttribute(
51
                Graphic aFillGraphic,
52
                const basegfx::B2DVector& rGraphicLogicSize,
53
                const basegfx::B2DVector& rSize,
54
                const basegfx::B2DVector& rOffset,
55
                const basegfx::B2DVector& rOffsetPosition,
56
                const basegfx::B2DVector& rRectPoint,
57
                bool bTiling,
58
                bool bStretch,
59
                bool bLogSize)
60
0
            :   maFillGraphic(std::move(aFillGraphic)),
61
0
                maGraphicLogicSize(rGraphicLogicSize),
62
0
                maSize(rSize),
63
0
                maOffset(rOffset),
64
0
                maOffsetPosition(rOffsetPosition),
65
0
                maRectPoint(rRectPoint),
66
0
                mbTiling(bTiling),
67
0
                mbStretch(bStretch),
68
0
                mbLogSize(bLogSize)
69
0
            {
70
0
            }
71
72
            ImpSdrFillGraphicAttribute()
73
7
            :   mbTiling(false),
74
7
                mbStretch(false),
75
7
                mbLogSize(false)
76
7
            {
77
7
            }
78
79
            // data read access
80
138
            const Graphic& getFillGraphic() const { return maFillGraphic; }
81
0
            const basegfx::B2DVector& getGraphicLogicSize() const { return maGraphicLogicSize; }
82
0
            const basegfx::B2DVector& getSize() const { return maSize; }
83
0
            const basegfx::B2DVector& getOffset() const { return maOffset; }
84
0
            const basegfx::B2DVector& getOffsetPosition() const { return maOffsetPosition; }
85
0
            const basegfx::B2DVector& getRectPoint() const { return maRectPoint; }
86
0
            bool getTiling() const { return mbTiling; }
87
0
            bool getStretch() const { return mbStretch; }
88
89
            bool operator==(const ImpSdrFillGraphicAttribute& rCandidate) const
90
0
            {
91
0
                return (getFillGraphic() == rCandidate.getFillGraphic()
92
0
                    && getGraphicLogicSize() == rCandidate.getGraphicLogicSize()
93
0
                    && getSize() == rCandidate.getSize()
94
0
                    && getOffset() == rCandidate.getOffset()
95
0
                    && getOffsetPosition() == rCandidate.getOffsetPosition()
96
0
                    && getRectPoint() == rCandidate.getRectPoint()
97
0
                    && getTiling() == rCandidate.getTiling()
98
0
                    && getStretch() == rCandidate.getStretch()
99
0
                    && mbLogSize == rCandidate.mbLogSize);
100
0
            }
101
        };
102
103
        namespace
104
        {
105
            SdrFillGraphicAttribute::ImplType& theGlobalDefault()
106
4.72k
            {
107
4.72k
                static SdrFillGraphicAttribute::ImplType SINGLETON;
108
4.72k
                return SINGLETON;
109
4.72k
            }
110
        }
111
112
        SdrFillGraphicAttribute::SdrFillGraphicAttribute(
113
            const Graphic& rFillGraphic,
114
            const basegfx::B2DVector& rGraphicLogicSize,
115
            const basegfx::B2DVector& rSize,
116
            const basegfx::B2DVector& rOffset,
117
            const basegfx::B2DVector& rOffsetPosition,
118
            const basegfx::B2DVector& rRectPoint,
119
            bool bTiling,
120
            bool bStretch,
121
            bool bLogSize)
122
0
        :   mpSdrFillGraphicAttribute(
123
0
                ImpSdrFillGraphicAttribute(
124
0
                    rFillGraphic,
125
0
                    rGraphicLogicSize,
126
0
                    rSize,
127
0
                    rOffset,
128
0
                    rOffsetPosition,
129
0
                    rRectPoint,
130
0
                    bTiling,
131
0
                    bStretch,
132
0
                    bLogSize))
133
0
        {
134
0
        }
135
136
        SdrFillGraphicAttribute::SdrFillGraphicAttribute()
137
1.58k
        :   mpSdrFillGraphicAttribute(theGlobalDefault())
138
1.58k
        {
139
1.58k
        }
140
141
1.57k
        SdrFillGraphicAttribute::SdrFillGraphicAttribute(const SdrFillGraphicAttribute&) = default;
142
143
3.15k
        SdrFillGraphicAttribute::SdrFillGraphicAttribute(SdrFillGraphicAttribute&&) = default;
144
145
6.30k
        SdrFillGraphicAttribute::~SdrFillGraphicAttribute() = default;
146
147
        bool SdrFillGraphicAttribute::isDefault() const
148
3.14k
        {
149
3.14k
            return mpSdrFillGraphicAttribute.same_object(theGlobalDefault());
150
3.14k
        }
151
152
0
        SdrFillGraphicAttribute& SdrFillGraphicAttribute::operator=(const SdrFillGraphicAttribute&) = default;
153
154
0
        SdrFillGraphicAttribute& SdrFillGraphicAttribute::operator=(SdrFillGraphicAttribute&&) = default;
155
156
        bool SdrFillGraphicAttribute::operator==(const SdrFillGraphicAttribute& rCandidate) const
157
390
        {
158
            // tdf#87509 default attr is always != non-default attr, even with same values
159
390
            if(rCandidate.isDefault() != isDefault())
160
0
                return false;
161
162
390
            return rCandidate.mpSdrFillGraphicAttribute == mpSdrFillGraphicAttribute;
163
390
        }
164
165
        const Graphic& SdrFillGraphicAttribute::getFillGraphic() const
166
138
        {
167
138
            return mpSdrFillGraphicAttribute->getFillGraphic();
168
138
        }
169
170
        const basegfx::B2DVector& SdrFillGraphicAttribute::getGraphicLogicSize() const
171
0
        {
172
0
            return mpSdrFillGraphicAttribute->getGraphicLogicSize();
173
0
        }
174
175
        const basegfx::B2DVector& SdrFillGraphicAttribute::getSize() const
176
0
        {
177
0
            return mpSdrFillGraphicAttribute->getSize();
178
0
        }
179
180
        const basegfx::B2DVector& SdrFillGraphicAttribute::getOffset() const
181
0
        {
182
0
            return mpSdrFillGraphicAttribute->getOffset();
183
0
        }
184
185
        const basegfx::B2DVector& SdrFillGraphicAttribute::getOffsetPosition() const
186
0
        {
187
0
            return mpSdrFillGraphicAttribute->getOffsetPosition();
188
0
        }
189
190
        const basegfx::B2DVector& SdrFillGraphicAttribute::getRectPoint() const
191
0
        {
192
0
            return mpSdrFillGraphicAttribute->getRectPoint();
193
0
        }
194
195
        bool SdrFillGraphicAttribute::getTiling() const
196
0
        {
197
0
            return mpSdrFillGraphicAttribute->getTiling();
198
0
        }
199
200
        FillGraphicAttribute SdrFillGraphicAttribute::createFillGraphicAttribute(const basegfx::B2DRange& rRange) const
201
0
        {
202
            // get logical size of bitmap (before possibly expanding it)
203
0
            Graphic aGraphic(getFillGraphic());
204
205
            // init values with defaults for stretched
206
0
            basegfx::B2DPoint aBitmapSize(1.0, 1.0);
207
0
            basegfx::B2DVector aBitmapTopLeft(0.0, 0.0);
208
209
            // are changes needed? When stretched we are already done, all other values will have no influence
210
0
            if(getTiling() || !mpSdrFillGraphicAttribute->getStretch())
211
0
            {
212
                // init values with range sizes
213
0
                const double fRangeWidth(0.0 != rRange.getWidth() ? rRange.getWidth() : 1.0);
214
0
                const double fRangeHeight(0.0 != rRange.getHeight() ? rRange.getHeight() : 1.0);
215
0
                aBitmapSize = basegfx::B2DPoint(fRangeWidth, fRangeHeight);
216
217
                // size changes
218
0
                if(0.0 != getSize().getX())
219
0
                {
220
0
                    if(getSize().getX() < 0.0)
221
0
                    {
222
0
                        aBitmapSize.setX(aBitmapSize.getX() * (getSize().getX() * -0.01));
223
0
                    }
224
0
                    else
225
0
                    {
226
0
                        aBitmapSize.setX(getSize().getX());
227
0
                    }
228
0
                }
229
0
                else
230
0
                {
231
                    // #i124002# use GraphicLogicSize directly, do not try to use GetPrefSize
232
                    // of the graphic, that may not be adapted to the MapMode of the target
233
0
                    aBitmapSize.setX(getGraphicLogicSize().getX());
234
0
                }
235
236
0
                if(0.0 != getSize().getY())
237
0
                {
238
0
                    if(getSize().getY() < 0.0)
239
0
                    {
240
0
                        aBitmapSize.setY(aBitmapSize.getY() * (getSize().getY() * -0.01));
241
0
                    }
242
0
                    else
243
0
                    {
244
0
                        aBitmapSize.setY(getSize().getY());
245
0
                    }
246
0
                }
247
0
                else
248
0
                {
249
                    // #i124002# use GraphicLogicSize directly, do not try to use GetPrefSize
250
                    // of the graphic, that may not be adapted to the MapMode of the target
251
0
                    aBitmapSize.setY(getGraphicLogicSize().getY());
252
0
                }
253
254
                // position changes X
255
0
                if(0.0 == getRectPoint().getX())
256
0
                {
257
0
                    aBitmapTopLeft.setX((fRangeWidth - aBitmapSize.getX()) * 0.5);
258
0
                }
259
0
                else if(1.0 == getRectPoint().getX())
260
0
                {
261
0
                    aBitmapTopLeft.setX(fRangeWidth - aBitmapSize.getX());
262
0
                }
263
264
                // offset positions are only meaningful when tiled
265
0
                if(getTiling() && 0.0 != getOffsetPosition().getX())
266
0
                {
267
0
                    aBitmapTopLeft.setX(aBitmapTopLeft.getX() + (aBitmapSize.getX() * (getOffsetPosition().getX() * 0.01)));
268
0
                }
269
270
                // position changes Y
271
0
                if(0.0 == getRectPoint().getY())
272
0
                {
273
0
                    aBitmapTopLeft.setY((fRangeHeight - aBitmapSize.getY()) * 0.5);
274
0
                }
275
0
                else if(1.0 == getRectPoint().getY())
276
0
                {
277
0
                    aBitmapTopLeft.setY(fRangeHeight - aBitmapSize.getY());
278
0
                }
279
280
                // offset positions are only meaningful when tiled
281
0
                if(getTiling() && 0.0 != getOffsetPosition().getY())
282
0
                {
283
0
                    aBitmapTopLeft.setY(aBitmapTopLeft.getY() + (aBitmapSize.getY() * (getOffsetPosition().getY() * 0.01)));
284
0
                }
285
286
                // apply bitmap size scaling to unit rectangle
287
0
                aBitmapTopLeft.setX(aBitmapTopLeft.getX() / fRangeWidth);
288
0
                aBitmapTopLeft.setY(aBitmapTopLeft.getY() / fRangeHeight);
289
0
                aBitmapSize.setX(aBitmapSize.getX() / fRangeWidth);
290
0
                aBitmapSize.setY(aBitmapSize.getY() / fRangeHeight);
291
0
            }
292
293
            // get offset in percent
294
0
            const double fOffsetX(std::clamp(getOffset().getX() * 0.01, 0.0, 1.0));
295
0
            const double fOffsetY(std::clamp(getOffset().getY() * 0.01, 0.0, 1.0));
296
297
            // create FillGraphicAttribute
298
0
            return FillGraphicAttribute(
299
0
                aGraphic,
300
0
                basegfx::B2DRange(aBitmapTopLeft, aBitmapTopLeft + aBitmapSize),
301
0
                getTiling(),
302
0
                fOffsetX,
303
0
                fOffsetY);
304
0
        }
305
306
} // end of namespace
307
308
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */