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 
25 #include <headless/svpbmp.hxx>
26 #include <headless/svpgdi.hxx>
27 #include <headless/svpinst.hxx>
28 
29 #include <basegfx/vector/b2ivector.hxx>
30 #include <basegfx/range/b2ibox.hxx>
31 #include <o3tl/safeint.hxx>
32 #include <osl/endian.h>
33 
34 #include <tools/helpers.hxx>
35 #include <vcl/bitmap.hxx>
36 
37 using namespace basegfx;
38 
~SvpSalBitmap()39 SvpSalBitmap::~SvpSalBitmap()
40 {
41     Destroy();
42 }
43 
ImplCreateDIB(const Size & rSize,sal_uInt16 nBitCount,const BitmapPalette & rPal)44 static std::unique_ptr<BitmapBuffer> ImplCreateDIB(
45     const Size& rSize,
46     sal_uInt16 nBitCount,
47     const BitmapPalette& rPal)
48 {
49     assert(
50           (nBitCount ==  0
51         || nBitCount ==  1
52         || nBitCount ==  4
53         || nBitCount ==  8
54         || nBitCount == 24
55         || nBitCount == 32)
56         && "Unsupported BitCount!");
57 
58     if (!rSize.Width() || !rSize.Height())
59         return nullptr;
60 
61     std::unique_ptr<BitmapBuffer> pDIB;
62 
63     try
64     {
65         pDIB.reset(new BitmapBuffer);
66     }
67     catch (const std::bad_alloc&)
68     {
69         return nullptr;
70     }
71 
72     const sal_uInt16 nColors = ( nBitCount <= 8 ) ? ( 1 << nBitCount ) : 0;
73 
74     switch (nBitCount)
75     {
76         case 1:
77             pDIB->mnFormat = ScanlineFormat::N1BitLsbPal;
78             break;
79         case 4:
80             pDIB->mnFormat = ScanlineFormat::N4BitMsnPal;
81             break;
82         case 8:
83             pDIB->mnFormat = ScanlineFormat::N8BitPal;
84             break;
85         case 24:
86             pDIB->mnFormat = SVP_24BIT_FORMAT;
87             break;
88         default:
89             nBitCount = 32;
90             [[fallthrough]];
91         case 32:
92             pDIB->mnFormat = SVP_CAIRO_FORMAT;
93             break;
94     }
95 
96     pDIB->mnFormat |= ScanlineFormat::TopDown;
97     pDIB->mnWidth = rSize.Width();
98     pDIB->mnHeight = rSize.Height();
99     long nScanlineBase;
100     bool bFail = o3tl::checked_multiply<long>(pDIB->mnWidth, nBitCount, nScanlineBase);
101     if (bFail)
102     {
103         SAL_WARN("vcl.gdi", "checked multiply failed");
104         return nullptr;
105     }
106     pDIB->mnScanlineSize = AlignedWidth4Bytes(nScanlineBase);
107     if (pDIB->mnScanlineSize < nScanlineBase/8)
108     {
109         SAL_WARN("vcl.gdi", "scanline calculation wraparound");
110         return nullptr;
111     }
112     pDIB->mnBitCount = nBitCount;
113 
114     if( nColors )
115     {
116         pDIB->maPalette = rPal;
117         pDIB->maPalette.SetEntryCount( nColors );
118     }
119 
120     size_t size;
121     bFail = o3tl::checked_multiply<size_t>(pDIB->mnHeight, pDIB->mnScanlineSize, size);
122     SAL_WARN_IF(bFail, "vcl.gdi", "checked multiply failed");
123     if (bFail || size > SAL_MAX_INT32/2)
124     {
125         return nullptr;
126     }
127 
128     try
129     {
130         pDIB->mpBits = new sal_uInt8[size];
131 #ifdef __SANITIZE_ADDRESS__
132         if (!pDIB->mpBits)
133         {   // can only happen with ASAN allocator_may_return_null=1
134             pDIB.reset();
135         }
136         else
137 #endif
138         {
139             std::memset(pDIB->mpBits, 0, size);
140         }
141     }
142     catch (const std::bad_alloc&)
143     {
144         pDIB.reset();
145     }
146 
147     return pDIB;
148 }
149 
Create(std::unique_ptr<BitmapBuffer> pBuf)150 void SvpSalBitmap::Create(std::unique_ptr<BitmapBuffer> pBuf)
151 {
152     Destroy();
153     mpDIB = std::move(pBuf);
154 }
155 
Create(const Size & rSize,sal_uInt16 nBitCount,const BitmapPalette & rPal)156 bool SvpSalBitmap::Create(const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal)
157 {
158     Destroy();
159     mpDIB = ImplCreateDIB( rSize, nBitCount, rPal );
160     return mpDIB != nullptr;
161 }
162 
Create(const SalBitmap & rBmp)163 bool SvpSalBitmap::Create(const SalBitmap& rBmp)
164 {
165     Destroy();
166 
167     const SvpSalBitmap& rSalBmp = static_cast<const SvpSalBitmap&>(rBmp);
168 
169     if (rSalBmp.mpDIB)
170     {
171         // TODO: reference counting...
172         mpDIB.reset(new BitmapBuffer( *rSalBmp.mpDIB ));
173 
174         const size_t size = mpDIB->mnScanlineSize * mpDIB->mnHeight;
175         if (size > SAL_MAX_INT32/2)
176         {
177             mpDIB.reset();
178             return false;
179         }
180 
181         // TODO: get rid of this when BitmapBuffer gets copy constructor
182         try
183         {
184             mpDIB->mpBits = new sal_uInt8[size];
185             std::memcpy(mpDIB->mpBits, rSalBmp.mpDIB->mpBits, size);
186         }
187         catch (const std::bad_alloc&)
188         {
189             mpDIB.reset();
190         }
191     }
192 
193     return !rSalBmp.mpDIB || (mpDIB != nullptr);
194 }
195 
Create(const SalBitmap &,SalGraphics *)196 bool SvpSalBitmap::Create( const SalBitmap& /*rSalBmp*/,
197                            SalGraphics* /*pGraphics*/ )
198 {
199     return false;
200 }
201 
Create(const SalBitmap &,sal_uInt16)202 bool SvpSalBitmap::Create( const SalBitmap& /*rSalBmp*/,
203                            sal_uInt16 /*nNewBitCount*/ )
204 {
205     return false;
206 }
207 
Create(const css::uno::Reference<css::rendering::XBitmapCanvas> &,Size &,bool)208 bool SvpSalBitmap::Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& /*xBitmapCanvas*/, Size& /*rSize*/, bool /*bMask*/ )
209 {
210     return false;
211 }
212 
Destroy()213 void SvpSalBitmap::Destroy()
214 {
215     if (mpDIB)
216     {
217         delete[] mpDIB->mpBits;
218         mpDIB.reset();
219     }
220 }
221 
GetSize() const222 Size SvpSalBitmap::GetSize() const
223 {
224     Size aSize;
225 
226     if (mpDIB)
227     {
228         aSize.setWidth( mpDIB->mnWidth );
229         aSize.setHeight( mpDIB->mnHeight );
230     }
231 
232     return aSize;
233 }
234 
GetBitCount() const235 sal_uInt16 SvpSalBitmap::GetBitCount() const
236 {
237     sal_uInt16 nBitCount;
238 
239     if (mpDIB)
240         nBitCount = mpDIB->mnBitCount;
241     else
242         nBitCount = 0;
243 
244     return nBitCount;
245 }
246 
AcquireBuffer(BitmapAccessMode)247 BitmapBuffer* SvpSalBitmap::AcquireBuffer(BitmapAccessMode)
248 {
249     return mpDIB.get();
250 }
251 
ReleaseBuffer(BitmapBuffer *,BitmapAccessMode nMode)252 void SvpSalBitmap::ReleaseBuffer(BitmapBuffer*, BitmapAccessMode nMode)
253 {
254     if( nMode == BitmapAccessMode::Write )
255         InvalidateChecksum();
256 }
257 
GetSystemData(BitmapSystemData &)258 bool SvpSalBitmap::GetSystemData( BitmapSystemData& )
259 {
260     return false;
261 }
262 
ScalingSupported() const263 bool SvpSalBitmap::ScalingSupported() const
264 {
265     return false;
266 }
267 
Scale(const double &,const double &,BmpScaleFlag)268 bool SvpSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag /*nScaleFlag*/ )
269 {
270     return false;
271 }
272 
Replace(const::Color &,const::Color &,sal_uInt8)273 bool SvpSalBitmap::Replace( const ::Color& /*rSearchColor*/, const ::Color& /*rReplaceColor*/, sal_uInt8 /*nTol*/ )
274 {
275     return false;
276 }
277 
278 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
279