Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/drawinglayer/source/texture/texture3d.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 <texture/texture3d.hxx>
25
#include <vcl/BitmapReadAccess.hxx>
26
#include <primitive3d/hatchtextureprimitive3d.hxx>
27
#include <sal/log.hxx>
28
29
namespace drawinglayer::texture
30
{
31
        GeoTexSvxMono::GeoTexSvxMono(
32
            const basegfx::BColor& rSingleColor,
33
            double fOpacity)
34
0
        :   maSingleColor(rSingleColor),
35
0
            mfOpacity(fOpacity)
36
0
        {
37
0
        }
38
39
        bool GeoTexSvxMono::operator==(const GeoTexSvx& rGeoTexSvx) const
40
0
        {
41
0
            const GeoTexSvxMono* pCompare = dynamic_cast< const GeoTexSvxMono* >(&rGeoTexSvx);
42
43
0
            return (pCompare
44
0
                && maSingleColor == pCompare->maSingleColor
45
0
                && mfOpacity == pCompare->mfOpacity);
46
0
        }
47
48
        void GeoTexSvxMono::modifyBColor(const basegfx::B2DPoint& /*rUV*/, basegfx::BColor& rBColor, double& /*rfOpacity*/) const
49
0
        {
50
0
            rBColor = maSingleColor;
51
0
        }
52
53
        void GeoTexSvxMono::modifyOpacity(const basegfx::B2DPoint& /*rUV*/, double& rfOpacity) const
54
0
        {
55
0
            rfOpacity = mfOpacity;
56
0
        }
57
58
59
        GeoTexSvxBitmap::GeoTexSvxBitmap(
60
            const Bitmap& rBitmap,
61
            const basegfx::B2DRange& rRange)
62
0
        :   maBitmap(rBitmap),
63
0
            maTopLeft(rRange.getMinimum()),
64
0
            maSize(rRange.getRange()),
65
0
            mfMulX(0.0),
66
0
            mfMulY(0.0)
67
0
        {
68
0
            if (!maBitmap.IsEmpty())
69
0
                mpReadBitmap = maBitmap;
70
0
            SAL_WARN_IF(!mpReadBitmap, "drawinglayer", "GeoTexSvxBitmap: Got no read access to Bitmap");
71
0
            if (mpReadBitmap)
72
0
            {
73
0
                mfMulX = static_cast<double>(mpReadBitmap->Width()) / maSize.getX();
74
0
                mfMulY = static_cast<double>(mpReadBitmap->Height()) / maSize.getY();
75
0
            }
76
77
0
            if(maSize.getX() <= 1.0)
78
0
            {
79
0
                maSize.setX(1.0);
80
0
            }
81
82
0
            if(maSize.getY() <= 1.0)
83
0
            {
84
0
                maSize.setY(1.0);
85
0
            }
86
0
        }
87
88
        GeoTexSvxBitmap::~GeoTexSvxBitmap()
89
0
        {
90
0
        }
91
92
        bool GeoTexSvxBitmap::impIsValid(const basegfx::B2DPoint& rUV, sal_Int32& rX, sal_Int32& rY) const
93
0
        {
94
0
            if(mpReadBitmap)
95
0
            {
96
0
                rX = static_cast<sal_Int32>((rUV.getX() - maTopLeft.getX()) * mfMulX);
97
98
0
                if(rX >= 0 && rX < mpReadBitmap->Width())
99
0
                {
100
0
                    rY = static_cast<sal_Int32>((rUV.getY() - maTopLeft.getY()) * mfMulY);
101
102
0
                    return (rY >= 0 && rY < mpReadBitmap->Height());
103
0
                }
104
0
            }
105
106
0
            return false;
107
0
        }
108
109
        void GeoTexSvxBitmap::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& rfOpacity) const
110
0
        {
111
0
            sal_Int32 nX, nY;
112
113
0
            if(impIsValid(rUV, nX, nY))
114
0
            {
115
0
                const double fConvertColor(1.0 / 255.0);
116
0
                const BitmapColor aBMCol(mpReadBitmap->GetColor(nY, nX));
117
0
                const basegfx::BColor aBSource(
118
0
                    static_cast<double>(aBMCol.GetRed()) * fConvertColor,
119
0
                    static_cast<double>(aBMCol.GetGreen()) * fConvertColor,
120
0
                    static_cast<double>(aBMCol.GetBlue()) * fConvertColor);
121
122
0
                rBColor = aBSource;
123
124
0
                if (maBitmap.HasAlpha())
125
0
                {
126
                    // when we have alpha, make use of it
127
0
                    const sal_uInt8 aAlpha(aBMCol.GetAlpha());
128
129
0
                    rfOpacity = (static_cast<double>(aAlpha) * (1.0 / 255.0));
130
0
                }
131
0
                else
132
0
                {
133
0
                    rfOpacity = 1.0;
134
0
                }
135
0
            }
136
0
            else
137
0
            {
138
0
                rfOpacity = 0.0;
139
0
            }
140
0
        }
141
142
        void GeoTexSvxBitmap::modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const
143
0
        {
144
0
            sal_Int32 nX, nY;
145
146
0
            if(impIsValid(rUV, nX, nY))
147
0
            {
148
0
                const BitmapColor aBMCol(mpReadBitmap->GetColor(nY, nX));
149
0
                if (maBitmap.HasAlpha())
150
0
                {
151
                    // this texture has an alpha part, use it
152
0
                    const sal_uInt8 aAlpha(aBMCol.GetAlpha());
153
0
                    const double fNewOpacity(static_cast<double>(aAlpha) * (1.0 / 255.0));
154
155
0
                    rfOpacity = 1.0 - ((1.0 - fNewOpacity) * (1.0 - rfOpacity));
156
0
                }
157
0
                else
158
0
                {
159
                    // this texture is a color bitmap used as transparence map
160
0
                    const Color aColor(aBMCol.GetRed(), aBMCol.GetGreen(), aBMCol.GetBlue());
161
162
0
                    rfOpacity = (static_cast<double>(0xff - aColor.GetLuminance()) * (1.0 / 255.0));
163
0
                }
164
0
            }
165
0
            else
166
0
            {
167
0
                rfOpacity = 0.0;
168
0
            }
169
0
        }
170
171
172
        basegfx::B2DPoint GeoTexSvxBitmapTiled::impGetCorrected(const basegfx::B2DPoint& rUV) const
173
0
        {
174
0
            double fX(rUV.getX() - maTopLeft.getX());
175
0
            double fY(rUV.getY() - maTopLeft.getY());
176
177
0
            if(mbUseOffsetX)
178
0
            {
179
0
                const sal_Int32 nCol(static_cast< sal_Int32 >((fY < 0.0 ? maSize.getY() -fY : fY) / maSize.getY()));
180
181
0
                if(nCol % 2)
182
0
                {
183
0
                    fX += mfOffsetX * maSize.getX();
184
0
                }
185
0
            }
186
0
            else if(mbUseOffsetY)
187
0
            {
188
0
                const sal_Int32 nRow(static_cast< sal_Int32 >((fX < 0.0 ? maSize.getX() -fX : fX) / maSize.getX()));
189
190
0
                if(nRow % 2)
191
0
                {
192
0
                    fY += mfOffsetY * maSize.getY();
193
0
                }
194
0
            }
195
196
0
            fX = fmod(fX, maSize.getX());
197
0
            fY = fmod(fY, maSize.getY());
198
199
0
            if(fX < 0.0)
200
0
            {
201
0
                fX += maSize.getX();
202
0
            }
203
204
0
            if(fY < 0.0)
205
0
            {
206
0
                fY += maSize.getY();
207
0
            }
208
209
0
            return basegfx::B2DPoint(fX + maTopLeft.getX(), fY + maTopLeft.getY());
210
0
        }
211
212
        GeoTexSvxBitmapTiled::GeoTexSvxBitmapTiled(
213
            const Bitmap& rBitmap,
214
            const basegfx::B2DRange& rRange,
215
            double fOffsetX,
216
            double fOffsetY)
217
0
        :   GeoTexSvxBitmap(rBitmap, rRange),
218
0
            mfOffsetX(std::clamp(fOffsetX, 0.0, 1.0)),
219
0
            mfOffsetY(std::clamp(fOffsetY, 0.0, 1.0)),
220
0
            mbUseOffsetX(!basegfx::fTools::equalZero(mfOffsetX)),
221
0
            mbUseOffsetY(!mbUseOffsetX && !basegfx::fTools::equalZero(mfOffsetY))
222
0
        {
223
0
        }
224
225
        void GeoTexSvxBitmapTiled::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& rfOpacity) const
226
0
        {
227
0
            if(mpReadBitmap)
228
0
            {
229
0
                GeoTexSvxBitmap::modifyBColor(impGetCorrected(rUV), rBColor, rfOpacity);
230
0
            }
231
0
        }
232
233
        void GeoTexSvxBitmapTiled::modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const
234
0
        {
235
0
            if(mpReadBitmap)
236
0
            {
237
0
                GeoTexSvxBitmap::modifyOpacity(impGetCorrected(rUV), rfOpacity);
238
0
            }
239
0
        }
240
241
242
        GeoTexSvxMultiHatch::GeoTexSvxMultiHatch(
243
            const primitive3d::HatchTexturePrimitive3D& rPrimitive,
244
            double fLogicPixelSize)
245
0
        :   mfLogicPixelSize(fLogicPixelSize)
246
0
        {
247
0
            const attribute::FillHatchAttribute& rHatch(rPrimitive.getHatch());
248
0
            const basegfx::B2DRange aOutlineRange(0.0, 0.0, rPrimitive.getTextureSize().getX(), rPrimitive.getTextureSize().getY());
249
0
            const double fAngleA(rHatch.getAngle());
250
0
            maColor = rHatch.getColor();
251
0
            mbFillBackground = rHatch.isFillBackground();
252
0
            mp0.reset( new GeoTexSvxHatch(
253
0
                aOutlineRange,
254
0
                aOutlineRange,
255
0
                rHatch.getDistance(),
256
0
                fAngleA) );
257
258
0
            if(attribute::HatchStyle::Double == rHatch.getStyle() || attribute::HatchStyle::Triple == rHatch.getStyle())
259
0
            {
260
0
                mp1.reset( new GeoTexSvxHatch(
261
0
                    aOutlineRange,
262
0
                    aOutlineRange,
263
0
                    rHatch.getDistance(),
264
0
                    fAngleA + M_PI_2) );
265
0
            }
266
267
0
            if(attribute::HatchStyle::Triple == rHatch.getStyle())
268
0
            {
269
0
                mp2.reset( new GeoTexSvxHatch(
270
0
                    aOutlineRange,
271
0
                    aOutlineRange,
272
0
                    rHatch.getDistance(),
273
0
                    fAngleA + M_PI_4) );
274
0
            }
275
0
        }
276
277
        GeoTexSvxMultiHatch::~GeoTexSvxMultiHatch()
278
0
        {
279
0
        }
280
281
        bool GeoTexSvxMultiHatch::impIsOnHatch(const basegfx::B2DPoint& rUV) const
282
0
        {
283
0
            if(mp0->getDistanceToHatch(rUV) < mfLogicPixelSize)
284
0
            {
285
0
                return true;
286
0
            }
287
288
0
            if(mp1 && mp1->getDistanceToHatch(rUV) < mfLogicPixelSize)
289
0
            {
290
0
                return true;
291
0
            }
292
293
0
            if(mp2 && mp2->getDistanceToHatch(rUV) < mfLogicPixelSize)
294
0
            {
295
0
                return true;
296
0
            }
297
298
0
            return false;
299
0
        }
300
301
        void GeoTexSvxMultiHatch::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& rfOpacity) const
302
0
        {
303
0
            if(impIsOnHatch(rUV))
304
0
            {
305
0
                rBColor = maColor;
306
0
            }
307
0
            else if(!mbFillBackground)
308
0
            {
309
0
                rfOpacity = 0.0;
310
0
            }
311
0
        }
312
313
        void GeoTexSvxMultiHatch::modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const
314
0
        {
315
0
            if(mbFillBackground || impIsOnHatch(rUV))
316
0
            {
317
0
                rfOpacity = 1.0;
318
0
            }
319
0
            else
320
0
            {
321
0
                rfOpacity = 0.0;
322
0
            }
323
0
        }
324
325
} // end of namespace
326
327
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */