Coverage Report

Created: 2026-03-31 11:00

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