Coverage Report

Created: 2026-10-14 09:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/bitmap/salbmp.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 <salbmp.hxx>
21
#include <o3tl/enumarray.hxx>
22
#include <vcl/BitmapColor.hxx>
23
#include <rtl/crc.h>
24
#include <algorithm>
25
26
static BitmapChecksum scanlineChecksum(BitmapChecksum nCrc, const sal_uInt8* bits, int lineBitsCount, sal_uInt8 extraBitsMask)
27
21.8k
{
28
21.8k
    if( lineBitsCount / 8 > 0 )
29
21.8k
        nCrc = rtl_crc32( nCrc, bits, lineBitsCount / 8 );
30
21.8k
    if( extraBitsMask != 0 )
31
0
    {
32
0
        sal_uInt8 extraByte = bits[ lineBitsCount / 8 ] & extraBitsMask;
33
0
        nCrc = rtl_crc32( nCrc, &extraByte, 1 );
34
0
    }
35
21.8k
    return nCrc;
36
21.8k
}
37
38
void SalBitmap::updateChecksum() const
39
43.4k
{
40
43.4k
    if (mbChecksumValid)
41
36.5k
        return;
42
43
6.82k
    BitmapChecksum nCrc = 0;
44
6.82k
    SalBitmap* pThis = const_cast<SalBitmap*>(this);
45
6.82k
    BitmapBuffer* pBuf = pThis->AcquireBuffer(BitmapAccessMode::Read);
46
6.82k
    if (pBuf)
47
6.82k
    {
48
6.82k
        nCrc = pBuf->maPalette.GetChecksum();
49
6.82k
        const int lineBitsCount = pBuf->mnWidth * pBuf->mnBitCount;
50
        // With 1bpp/4bpp format we need to check only used bits in the last byte.
51
6.82k
        if (pBuf->meDirection == ScanlineDirection::TopDown)
52
6.82k
        {
53
6.82k
            if( pBuf->mnScanlineSize == lineBitsCount / 8 )
54
6.68k
                nCrc = rtl_crc32(nCrc, pBuf->mpBits, pBuf->mnScanlineSize * pBuf->mnHeight);
55
140
            else // Do not include padding with undefined content in the checksum.
56
21.9k
                for( tools::Long y = 0; y < pBuf->mnHeight; ++y )
57
21.8k
                    nCrc = scanlineChecksum(nCrc, pBuf->mpBits + y * pBuf->mnScanlineSize, lineBitsCount, 0);
58
6.82k
        }
59
0
        else // Compute checksum in the order of scanlines, to make it consistent between different bitmap implementations.
60
0
        {
61
0
            for( tools::Long y = pBuf->mnHeight - 1; y >= 0; --y )
62
0
                nCrc = scanlineChecksum(nCrc, pBuf->mpBits + y * pBuf->mnScanlineSize, lineBitsCount, 0);
63
0
        }
64
6.82k
        pThis->ReleaseBuffer(pBuf, BitmapAccessMode::Read);
65
6.82k
        pThis->mnChecksum = nCrc;
66
6.82k
        pThis->mbChecksumValid = true;
67
6.82k
    }
68
0
    else
69
0
    {
70
0
        pThis->mbChecksumValid = false;
71
0
    }
72
6.82k
}
73
74
sal_uInt16 SalBitmap::GetBitCount() const
75
388k
{
76
388k
    switch (GetScanlineFormat())
77
388k
    {
78
1
        case ScanlineFormat::NONE: return 0;
79
154k
        case ScanlineFormat::N8BitPal: return 8;
80
120k
        case ScanlineFormat::N24BitTcBgr: return 24;
81
0
        case ScanlineFormat::N24BitTcRgb: return 24;
82
0
        case ScanlineFormat::N32BitTcAbgr:
83
0
        case ScanlineFormat::N32BitTcXbgr:
84
0
        case ScanlineFormat::N32BitTcArgb:
85
0
        case ScanlineFormat::N32BitTcXrgb:
86
30.0k
        case ScanlineFormat::N32BitTcBgra:
87
112k
        case ScanlineFormat::N32BitTcBgrx:
88
112k
        case ScanlineFormat::N32BitTcRgba:
89
112k
        case ScanlineFormat::N32BitTcRgbx:
90
112k
            return 32;
91
0
        default: abort();
92
388k
    }
93
388k
}
94
95
namespace
96
{
97
98
class ImplPixelFormat
99
{
100
protected:
101
    const sal_uInt8* mpData;
102
public:
103
    static ImplPixelFormat* GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette );
104
105
0
    virtual void StartLine( const sal_uInt8* pLine ) { mpData = pLine; }
106
    virtual const BitmapColor& ReadPixel() = 0;
107
0
    virtual ~ImplPixelFormat() { }
108
};
109
110
class ImplPixelFormat8 : public ImplPixelFormat
111
{
112
private:
113
    const BitmapPalette& mrPalette;
114
115
public:
116
    explicit ImplPixelFormat8( const BitmapPalette& rPalette )
117
0
    : mrPalette( rPalette )
118
0
    {
119
0
    }
120
    virtual const BitmapColor& ReadPixel() override
121
0
    {
122
0
        assert( mrPalette.GetEntryCount() > *mpData );
123
0
        return mrPalette[ *mpData++ ];
124
0
    }
125
};
126
127
class ImplPixelFormat4 : public ImplPixelFormat
128
{
129
private:
130
    const BitmapPalette& mrPalette;
131
    sal_uInt32 mnX;
132
    sal_uInt32 mnShift;
133
134
public:
135
    explicit ImplPixelFormat4( const BitmapPalette& rPalette )
136
0
        : mrPalette( rPalette )
137
0
        , mnX(0)
138
0
        , mnShift(4)
139
0
    {
140
0
    }
141
    virtual void StartLine( const sal_uInt8* pLine ) override
142
0
    {
143
0
        mpData = pLine;
144
0
        mnX = 0;
145
0
        mnShift = 4;
146
0
    }
147
    virtual const BitmapColor& ReadPixel() override
148
0
    {
149
0
        sal_uInt32 nIdx = ( mpData[mnX >> 1] >> mnShift) & 0x0f;
150
0
        assert( mrPalette.GetEntryCount() > nIdx );
151
0
        const BitmapColor& rColor = mrPalette[nIdx];
152
0
        mnX++;
153
0
        mnShift ^= 4;
154
0
        return rColor;
155
0
    }
156
};
157
158
class ImplPixelFormat1 : public ImplPixelFormat
159
{
160
private:
161
    const BitmapPalette& mrPalette;
162
    sal_uInt32 mnX;
163
164
public:
165
    explicit ImplPixelFormat1( const BitmapPalette& rPalette )
166
0
        : mrPalette(rPalette)
167
0
        , mnX(0)
168
0
    {
169
0
    }
170
    virtual void StartLine( const sal_uInt8* pLine ) override
171
0
    {
172
0
        mpData = pLine;
173
0
        mnX = 0;
174
0
    }
175
    virtual const BitmapColor& ReadPixel() override
176
0
    {
177
0
        const BitmapColor& rColor = mrPalette[ (mpData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1];
178
0
        mnX++;
179
0
        return rColor;
180
0
    }
181
};
182
183
ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette )
184
0
{
185
0
    switch( nBits )
186
0
    {
187
0
    case 1: return new ImplPixelFormat1( rPalette );
188
0
    case 4: return new ImplPixelFormat4( rPalette );
189
0
    case 8: return new ImplPixelFormat8( rPalette );
190
0
    }
191
192
0
    return nullptr;
193
0
}
194
195
} // namespace
196
197
std::unique_ptr< sal_uInt8[] > SalBitmap::convertDataBitCount( const sal_uInt8* src,
198
    int width, int height, int bitCount, int bytesPerRow, const BitmapPalette& palette, BitConvert type )
199
0
{
200
0
    assert( bitCount == 4 || bitCount == 8 );
201
0
    static const o3tl::enumarray<BitConvert, int> bpp = { 1, 4, 4 };
202
0
    std::unique_ptr< sal_uInt8[] > data( new sal_uInt8[width * height * bpp[ type ]] );
203
204
0
    if(type == BitConvert::A8 && bitCount == 8 && palette.IsGreyPalette8Bit())
205
0
    { // no actual data conversion
206
0
        for( int y = 0; y < height; ++y )
207
0
            std::copy_n(src + y * bytesPerRow, width, data.get() + y * width);
208
0
        return data;
209
0
    }
210
211
0
    std::unique_ptr<ImplPixelFormat> pSrcFormat(ImplPixelFormat::GetFormat(bitCount, palette));
212
213
0
    const sal_uInt8* pSrcData = src;
214
0
    sal_uInt8* pDstData = data.get();
215
216
0
    sal_uInt32 nY = height;
217
0
    while( nY-- )
218
0
    {
219
0
        pSrcFormat->StartLine( pSrcData );
220
221
0
        sal_uInt32 nX = width;
222
0
        switch( type )
223
0
        {
224
0
            case BitConvert::A8 :
225
0
                while( nX-- )
226
0
                {
227
0
                    const BitmapColor& c = pSrcFormat->ReadPixel();
228
0
                    *pDstData++ = c.GetBlue();
229
0
                }
230
0
                break;
231
0
            case BitConvert::BGRA :
232
0
                while( nX-- )
233
0
                {
234
0
                    const BitmapColor& c = pSrcFormat->ReadPixel();
235
0
                    *pDstData++ = c.GetBlue();
236
0
                    *pDstData++ = c.GetGreen();
237
0
                    *pDstData++ = c.GetRed();
238
0
                    *pDstData++ = 0xff;
239
0
                }
240
0
                break;
241
0
            case BitConvert::RGBA :
242
0
                while( nX-- )
243
0
                {
244
0
                    const BitmapColor& c = pSrcFormat->ReadPixel();
245
0
                    *pDstData++ = c.GetRed();
246
0
                    *pDstData++ = c.GetGreen();
247
0
                    *pDstData++ = c.GetBlue();
248
0
                    *pDstData++ = 0xff;
249
0
                }
250
0
                break;
251
0
        }
252
253
0
        pSrcData += bytesPerRow;
254
0
    }
255
0
    return data;
256
0
}
257
258
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */