Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/headless/svpbmp.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
#include <sal/log.hxx>
22
23
#include <cstring>
24
#include <headless/svpbmp.hxx>
25
#include <o3tl/safeint.hxx>
26
#include <tools/helpers.hxx>
27
#include <vcl/bitmap.hxx>
28
#include <vcl/CairoFormats.hxx>
29
30
using namespace basegfx;
31
32
SvpSalBitmap::SvpSalBitmap()
33
717k
{
34
717k
}
35
36
SvpSalBitmap::~SvpSalBitmap()
37
717k
{
38
717k
    Destroy();
39
717k
}
40
41
static std::optional<BitmapBuffer> ImplCreateDIB(
42
    const Size& rSize,
43
    vcl::PixelFormat ePixelFormat,
44
    const BitmapPalette& rPal,
45
    bool bClear,
46
    bool bWithoutAlpha)
47
610k
{
48
610k
    if (!rSize.Width() || !rSize.Height())
49
0
        return std::nullopt;
50
51
610k
    std::optional<BitmapBuffer> pDIB(std::in_place);
52
53
610k
    switch (ePixelFormat)
54
610k
    {
55
177k
        case vcl::PixelFormat::N8_BPP:
56
177k
            pDIB->meFormat = ScanlineFormat::N8BitPal;
57
177k
            break;
58
372k
        case vcl::PixelFormat::N24_BPP:
59
372k
            pDIB->meFormat = SVP_24BIT_FORMAT;
60
372k
            break;
61
60.0k
        case vcl::PixelFormat::N32_BPP:
62
#if ENABLE_CAIRO_RGBA
63
            pDIB->meFormat = bWithoutAlpha ? ScanlineFormat::N32BitTcRgbx : SVP_CAIRO_FORMAT;
64
#elif defined OSL_BIGENDIAN
65
            pDIB->meFormat = bWithoutAlpha ? ScanlineFormat::N32BitTcXrgb : SVP_CAIRO_FORMAT;
66
#else
67
60.0k
            pDIB->meFormat = bWithoutAlpha ? ScanlineFormat::N32BitTcBgrx : SVP_CAIRO_FORMAT;
68
60.0k
#endif
69
60.0k
            break;
70
0
        case vcl::PixelFormat::INVALID:
71
0
            assert(false);
72
0
            pDIB->meFormat = SVP_CAIRO_FORMAT;
73
0
            break;
74
610k
    }
75
76
610k
    sal_uInt16 nColors = 0;
77
610k
    if (ePixelFormat <= vcl::PixelFormat::N8_BPP)
78
177k
        nColors = vcl::numberOfColors(ePixelFormat);
79
80
610k
    pDIB->meDirection = ScanlineDirection::TopDown;
81
610k
    pDIB->mnWidth = rSize.Width();
82
610k
    pDIB->mnHeight = rSize.Height();
83
610k
    tools::Long nScanlineBase;
84
610k
    bool bFail = o3tl::checked_multiply<tools::Long>(pDIB->mnWidth, vcl::pixelFormatBitCount(ePixelFormat), nScanlineBase);
85
610k
    if (bFail)
86
0
    {
87
0
        SAL_WARN("vcl.gdi", "checked multiply failed");
88
0
        return std::nullopt;
89
0
    }
90
610k
    pDIB->mnScanlineSize = AlignedWidth4Bytes(nScanlineBase);
91
610k
    if (pDIB->mnScanlineSize < nScanlineBase/8)
92
13
    {
93
13
        SAL_WARN("vcl.gdi", "scanline calculation wraparound");
94
13
        return std::nullopt;
95
13
    }
96
610k
    pDIB->mnBitCount = vcl::pixelFormatBitCount(ePixelFormat);
97
98
610k
    if (nColors)
99
177k
    {
100
177k
        pDIB->maPalette = rPal;
101
177k
        pDIB->maPalette.SetEntryCount( nColors );
102
177k
    }
103
104
610k
    size_t size;
105
610k
    bFail = o3tl::checked_multiply<size_t>(pDIB->mnHeight, pDIB->mnScanlineSize, size);
106
610k
    SAL_WARN_IF(bFail, "vcl.gdi", "checked multiply failed");
107
610k
    if (bFail || size > SAL_MAX_INT32/2)
108
155
    {
109
155
        return std::nullopt;
110
155
    }
111
112
610k
    try
113
610k
    {
114
610k
        pDIB->mpBits = new sal_uInt8[size];
115
#ifdef __SANITIZE_ADDRESS__
116
        if (!pDIB->mpBits)
117
        {   // can only happen with ASAN allocator_may_return_null=1
118
            pDIB.reset();
119
        }
120
        else
121
#endif
122
610k
        if (bClear)
123
602k
        {
124
602k
            std::memset(pDIB->mpBits, 0, size);
125
602k
        }
126
610k
    }
127
610k
    catch (const std::bad_alloc&)
128
610k
    {
129
0
        pDIB.reset();
130
0
    }
131
132
610k
    return pDIB;
133
610k
}
134
135
void SvpSalBitmap::Create(const std::optional<BitmapBuffer>& pBuf)
136
10.3k
{
137
10.3k
    Destroy();
138
10.3k
    moDIB = pBuf;
139
10.3k
}
140
141
bool SvpSalBitmap::ImplCreate(const Size& rSize, vcl::PixelFormat ePixelFormat,
142
                              const BitmapPalette& rPal, bool bClear, bool bWithoutAlpha)
143
610k
{
144
610k
    Destroy();
145
610k
    moDIB = ImplCreateDIB(rSize, ePixelFormat, rPal, bClear, bWithoutAlpha);
146
610k
    return moDIB.has_value();
147
610k
}
148
149
bool SvpSalBitmap::Create(const Size& rSize, vcl::PixelFormat ePixelFormat, const BitmapPalette& rPal)
150
603k
{
151
603k
    return ImplCreate(rSize, ePixelFormat, rPal, true);
152
603k
}
153
154
bool SvpSalBitmap::Create(const SalBitmap& rBmp)
155
94.6k
{
156
94.6k
    Destroy();
157
158
94.6k
    const SvpSalBitmap& rSalBmp = static_cast<const SvpSalBitmap&>(rBmp);
159
160
94.6k
    if (rSalBmp.moDIB)
161
94.5k
    {
162
        // TODO: reference counting...
163
94.5k
        moDIB.emplace( *rSalBmp.moDIB );
164
165
94.5k
        const size_t size = moDIB->mnScanlineSize * moDIB->mnHeight;
166
94.5k
        if (size > SAL_MAX_INT32/2)
167
0
        {
168
0
            moDIB.reset();
169
0
            return false;
170
0
        }
171
172
        // TODO: get rid of this when BitmapBuffer gets copy constructor
173
94.5k
        try
174
94.5k
        {
175
94.5k
            moDIB->mpBits = new sal_uInt8[size];
176
94.5k
            std::memcpy(moDIB->mpBits, rSalBmp.moDIB->mpBits, size);
177
94.5k
        }
178
94.5k
        catch (const std::bad_alloc&)
179
94.5k
        {
180
0
            moDIB.reset();
181
0
        }
182
94.5k
    }
183
184
94.6k
    return !rSalBmp.moDIB.has_value() || moDIB.has_value();
185
94.6k
}
186
187
bool SvpSalBitmap::Create( const SalBitmap& /*rSalBmp*/,
188
                           SalGraphics& /*rGraphics*/ )
189
0
{
190
0
    return false;
191
0
}
192
193
bool SvpSalBitmap::Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& /*xBitmapCanvas*/, Size& /*rSize*/ )
194
0
{
195
0
    return false;
196
0
}
197
198
void SvpSalBitmap::Destroy()
199
1.43M
{
200
1.43M
    if (moDIB.has_value())
201
714k
    {
202
714k
        delete[] moDIB->mpBits;
203
714k
        moDIB.reset();
204
714k
    }
205
1.43M
}
206
207
Size SvpSalBitmap::GetSize() const
208
1.01M
{
209
1.01M
    Size aSize;
210
211
1.01M
    if (moDIB.has_value())
212
1.01M
    {
213
1.01M
        aSize.setWidth( moDIB->mnWidth );
214
1.01M
        aSize.setHeight( moDIB->mnHeight );
215
1.01M
    }
216
217
1.01M
    return aSize;
218
1.01M
}
219
220
ScanlineFormat SvpSalBitmap::GetScanlineFormat() const
221
474k
{
222
474k
    if (!moDIB.has_value())
223
1
        return ScanlineFormat::NONE;
224
474k
    return moDIB->meFormat;
225
474k
}
226
227
BitmapBuffer* SvpSalBitmap::AcquireBuffer(BitmapAccessMode)
228
914k
{
229
914k
    return moDIB ? &*moDIB : nullptr;
230
914k
}
231
232
void SvpSalBitmap::ReleaseBuffer(BitmapBuffer*, BitmapAccessMode nMode)
233
913k
{
234
913k
    if( nMode == BitmapAccessMode::Write )
235
704k
        InvalidateChecksum();
236
913k
}
237
238
bool SvpSalBitmap::GetSystemData( BitmapSystemData& )
239
0
{
240
0
    return false;
241
0
}
242
243
bool SvpSalBitmap::ScalingSupported() const
244
8.28k
{
245
8.28k
    return false;
246
8.28k
}
247
248
bool SvpSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag /*nScaleFlag*/ )
249
0
{
250
0
    return false;
251
0
}
252
253
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */