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