File: | home/maarten/src/libreoffice/core/vcl/source/bitmap/bitmap.cxx |
Warning: | line 606, column 95 Use of zero-allocated memory |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 <osl/diagnose.h> | |||
21 | #include <tools/helpers.hxx> | |||
22 | #include <vcl/bitmap.hxx> | |||
23 | #include <vcl/bitmapaccess.hxx> | |||
24 | #include <vcl/outdev.hxx> | |||
25 | ||||
26 | #include <svdata.hxx> | |||
27 | #include <salinst.hxx> | |||
28 | #include <salbmp.hxx> | |||
29 | #include <bitmapwriteaccess.hxx> | |||
30 | ||||
31 | #include <algorithm> | |||
32 | #include <memory> | |||
33 | ||||
34 | #ifdef DBG_UTIL | |||
35 | #include <cstdlib> | |||
36 | #include <tools/stream.hxx> | |||
37 | #include <vcl/graphicfilter.hxx> | |||
38 | #endif | |||
39 | ||||
40 | Bitmap::Bitmap() | |||
41 | { | |||
42 | } | |||
43 | ||||
44 | Bitmap::Bitmap(const Bitmap& rBitmap) | |||
45 | : mxSalBmp(rBitmap.mxSalBmp) | |||
46 | , maPrefMapMode(rBitmap.maPrefMapMode) | |||
47 | , maPrefSize(rBitmap.maPrefSize) | |||
48 | { | |||
49 | } | |||
50 | ||||
51 | Bitmap::Bitmap(std::shared_ptr<SalBitmap> const & pSalBitmap) | |||
52 | : mxSalBmp(pSalBitmap) | |||
53 | , maPrefMapMode(MapMode(MapUnit::MapPixel)) | |||
54 | , maPrefSize(mxSalBmp->GetSize()) | |||
55 | { | |||
56 | } | |||
57 | ||||
58 | Bitmap::Bitmap( const Size& rSizePixel, sal_uInt16 nBitCount, const BitmapPalette* pPal ) | |||
59 | { | |||
60 | if (!(rSizePixel.Width() && rSizePixel.Height())) | |||
61 | return; | |||
62 | ||||
63 | BitmapPalette aPal; | |||
64 | BitmapPalette* pRealPal = nullptr; | |||
65 | ||||
66 | if( nBitCount <= 8 ) | |||
67 | { | |||
68 | if( !pPal ) | |||
69 | { | |||
70 | if( 1 == nBitCount ) | |||
71 | { | |||
72 | aPal.SetEntryCount( 2 ); | |||
73 | aPal[ 0 ] = COL_BLACK; | |||
74 | aPal[ 1 ] = COL_WHITE; | |||
75 | } | |||
76 | else if( ( 4 == nBitCount ) || ( 8 == nBitCount ) ) | |||
77 | { | |||
78 | aPal.SetEntryCount( 1 << nBitCount ); | |||
79 | aPal[ 0 ] = COL_BLACK; | |||
80 | aPal[ 1 ] = COL_BLUE; | |||
81 | aPal[ 2 ] = COL_GREEN; | |||
82 | aPal[ 3 ] = COL_CYAN; | |||
83 | aPal[ 4 ] = COL_RED; | |||
84 | aPal[ 5 ] = COL_MAGENTA; | |||
85 | aPal[ 6 ] = COL_BROWN; | |||
86 | aPal[ 7 ] = COL_GRAY; | |||
87 | aPal[ 8 ] = COL_LIGHTGRAY; | |||
88 | aPal[ 9 ] = COL_LIGHTBLUE; | |||
89 | aPal[ 10 ] = COL_LIGHTGREEN; | |||
90 | aPal[ 11 ] = COL_LIGHTCYAN; | |||
91 | aPal[ 12 ] = COL_LIGHTRED; | |||
92 | aPal[ 13 ] = COL_LIGHTMAGENTA; | |||
93 | aPal[ 14 ] = COL_YELLOW; | |||
94 | aPal[ 15 ] = COL_WHITE; | |||
95 | ||||
96 | // Create dither palette | |||
97 | if( 8 == nBitCount ) | |||
98 | { | |||
99 | sal_uInt16 nActCol = 16; | |||
100 | ||||
101 | for( sal_uInt16 nB = 0; nB < 256; nB += 51 ) | |||
102 | for( sal_uInt16 nG = 0; nG < 256; nG += 51 ) | |||
103 | for( sal_uInt16 nR = 0; nR < 256; nR += 51 ) | |||
104 | aPal[ nActCol++ ] = BitmapColor( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) ); | |||
105 | ||||
106 | // Set standard Office colors | |||
107 | aPal[ nActCol++ ] = BitmapColor( 0, 184, 255 ); | |||
108 | } | |||
109 | } | |||
110 | } | |||
111 | else | |||
112 | pRealPal = const_cast<BitmapPalette*>(pPal); | |||
113 | } | |||
114 | ||||
115 | mxSalBmp = ImplGetSVData()->mpDefInst->CreateSalBitmap(); | |||
116 | mxSalBmp->Create( rSizePixel, nBitCount, pRealPal ? *pRealPal : aPal ); | |||
117 | } | |||
118 | ||||
119 | #ifdef DBG_UTIL | |||
120 | ||||
121 | namespace | |||
122 | { | |||
123 | void savePNG(const OUString& sWhere, const Bitmap& rBmp) | |||
124 | { | |||
125 | SvFileStream aStream(sWhere, StreamMode::WRITE | StreamMode::TRUNC); | |||
126 | GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); | |||
127 | rFilter.compressAsPNG(BitmapEx(rBmp), aStream); | |||
128 | } | |||
129 | } | |||
130 | ||||
131 | #endif | |||
132 | ||||
133 | Bitmap::~Bitmap() | |||
134 | { | |||
135 | #ifdef DBG_UTIL | |||
136 | // VCL_DUMP_BMP_PATH should be like C:/bmpDump.png or ~/bmpDump.png | |||
137 | static const OUString sDumpPath(OUString::createFromAscii(std::getenv("VCL_DUMP_BMP_PATH"))); | |||
138 | // Stepping into the dtor of a bitmap you need, and setting the volatile variable to true in | |||
139 | // debugger, would dump the bitmap in question | |||
140 | static volatile bool save(false); | |||
141 | if (!sDumpPath.isEmpty() && save) | |||
142 | { | |||
143 | save = false; | |||
144 | savePNG(sDumpPath, *this); | |||
145 | } | |||
146 | #endif | |||
147 | } | |||
148 | ||||
149 | const BitmapPalette& Bitmap::GetGreyPalette( int nEntries ) | |||
150 | { | |||
151 | // Create greyscale palette with 2, 4, 16 or 256 entries | |||
152 | switch (nEntries) | |||
153 | { | |||
154 | case 2: | |||
155 | { | |||
156 | static const BitmapPalette aGreyPalette2 = [] { | |||
157 | BitmapPalette aPalette(2); | |||
158 | aPalette[0] = BitmapColor(0, 0, 0); | |||
159 | aPalette[1] = BitmapColor(255, 255, 255); | |||
160 | return aPalette; | |||
161 | }(); | |||
162 | ||||
163 | return aGreyPalette2; | |||
164 | } | |||
165 | case 4: | |||
166 | { | |||
167 | static const BitmapPalette aGreyPalette4 = [] { | |||
168 | BitmapPalette aPalette(4); | |||
169 | aPalette[0] = BitmapColor(0, 0, 0); | |||
170 | aPalette[1] = BitmapColor(85, 85, 85); | |||
171 | aPalette[2] = BitmapColor(170, 170, 170); | |||
172 | aPalette[3] = BitmapColor(255, 255, 255); | |||
173 | return aPalette; | |||
174 | }(); | |||
175 | ||||
176 | return aGreyPalette4; | |||
177 | } | |||
178 | case 16: | |||
179 | { | |||
180 | static const BitmapPalette aGreyPalette16 = [] { | |||
181 | sal_uInt8 cGrey = 0; | |||
182 | sal_uInt8 const cGreyInc = 17; | |||
183 | ||||
184 | BitmapPalette aPalette(16); | |||
185 | ||||
186 | for (sal_uInt16 i = 0; i < 16; ++i, cGrey += cGreyInc) | |||
187 | aPalette[i] = BitmapColor(cGrey, cGrey, cGrey); | |||
188 | ||||
189 | return aPalette; | |||
190 | }(); | |||
191 | ||||
192 | return aGreyPalette16; | |||
193 | } | |||
194 | case 256: | |||
195 | { | |||
196 | static const BitmapPalette aGreyPalette256 = [] { | |||
197 | BitmapPalette aPalette(256); | |||
198 | ||||
199 | for (sal_uInt16 i = 0; i < 256; ++i) | |||
200 | aPalette[i] = BitmapColor(static_cast<sal_uInt8>(i), static_cast<sal_uInt8>(i), | |||
201 | static_cast<sal_uInt8>(i)); | |||
202 | ||||
203 | return aPalette; | |||
204 | }(); | |||
205 | ||||
206 | return aGreyPalette256; | |||
207 | } | |||
208 | } | |||
209 | OSL_FAIL("Bitmap::GetGreyPalette: invalid entry count (2/4/16/256 allowed)")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/bitmap/bitmap.cxx" ":" "209" ": "), "%s", "Bitmap::GetGreyPalette: invalid entry count (2/4/16/256 allowed)" ); } } while (false); | |||
210 | return GetGreyPalette(2); | |||
211 | } | |||
212 | ||||
213 | bool BitmapPalette::IsGreyPaletteAny() const | |||
214 | { | |||
215 | const int nEntryCount = GetEntryCount(); | |||
216 | if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping | |||
217 | return true; | |||
218 | // See above: only certain entry values will result in a valid call to GetGreyPalette | |||
219 | if( nEntryCount == 2 || nEntryCount == 4 || nEntryCount == 16 || nEntryCount == 256 ) | |||
220 | { | |||
221 | const BitmapPalette& rGreyPalette = Bitmap::GetGreyPalette( nEntryCount ); | |||
222 | if( rGreyPalette == *this ) | |||
223 | return true; | |||
224 | } | |||
225 | ||||
226 | bool bRet = false; | |||
227 | // TODO: is it worth to compare the entries for the general case? | |||
228 | if (nEntryCount == 2) | |||
229 | { | |||
230 | const BitmapColor& rCol0(maBitmapColor[0]); | |||
231 | const BitmapColor& rCol1(maBitmapColor[1]); | |||
232 | bRet = rCol0.GetRed() == rCol0.GetGreen() && rCol0.GetRed() == rCol0.GetBlue() && | |||
233 | rCol1.GetRed() == rCol1.GetGreen() && rCol1.GetRed() == rCol1.GetBlue(); | |||
234 | } | |||
235 | return bRet; | |||
236 | } | |||
237 | ||||
238 | bool BitmapPalette::IsGreyPalette8Bit() const | |||
239 | { | |||
240 | const int nEntryCount = GetEntryCount(); | |||
241 | if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping | |||
242 | return true; | |||
243 | if( nEntryCount != 256 ) | |||
244 | return false; | |||
245 | for (sal_uInt16 i = 0; i < 256; ++i) | |||
246 | { | |||
247 | if( maBitmapColor[i] != BitmapColor(i, i, i)) | |||
248 | return false; | |||
249 | } | |||
250 | return true; | |||
251 | } | |||
252 | ||||
253 | Bitmap& Bitmap::operator=( const Bitmap& rBitmap ) | |||
254 | { | |||
255 | if (this == &rBitmap) | |||
256 | return *this; | |||
257 | ||||
258 | maPrefSize = rBitmap.maPrefSize; | |||
259 | maPrefMapMode = rBitmap.maPrefMapMode; | |||
260 | mxSalBmp = rBitmap.mxSalBmp; | |||
261 | ||||
262 | return *this; | |||
263 | } | |||
264 | ||||
265 | Bitmap& Bitmap::operator=( Bitmap&& rBitmap ) noexcept | |||
266 | { | |||
267 | maPrefSize = std::move(rBitmap.maPrefSize); | |||
268 | maPrefMapMode = std::move(rBitmap.maPrefMapMode); | |||
269 | mxSalBmp = std::move(rBitmap.mxSalBmp); | |||
270 | ||||
271 | return *this; | |||
272 | } | |||
273 | ||||
274 | bool Bitmap::operator==( const Bitmap& rBmp ) const | |||
275 | { | |||
276 | if (rBmp.mxSalBmp == mxSalBmp) // Includes both are nullptr | |||
277 | return true; | |||
278 | if (!rBmp.mxSalBmp || !mxSalBmp) | |||
279 | return false; | |||
280 | if (rBmp.mxSalBmp->GetSize() != mxSalBmp->GetSize() || | |||
281 | rBmp.mxSalBmp->GetBitCount() != mxSalBmp->GetBitCount()) | |||
282 | return false; | |||
283 | BitmapChecksum aChecksum1, aChecksum2; | |||
284 | rBmp.mxSalBmp->GetChecksum(aChecksum1); | |||
285 | mxSalBmp->GetChecksum(aChecksum2); | |||
286 | // If the bitmaps can't calculate a checksum, best to regard them as different. | |||
287 | if (aChecksum1 == 0 || aChecksum2 == 0) | |||
288 | return false; | |||
289 | return aChecksum1 == aChecksum2; | |||
290 | } | |||
291 | ||||
292 | void Bitmap::SetEmpty() | |||
293 | { | |||
294 | maPrefMapMode = MapMode(); | |||
295 | maPrefSize = Size(); | |||
296 | mxSalBmp.reset(); | |||
297 | } | |||
298 | ||||
299 | Size Bitmap::GetSizePixel() const | |||
300 | { | |||
301 | return( mxSalBmp ? mxSalBmp->GetSize() : Size() ); | |||
302 | } | |||
303 | ||||
304 | sal_uInt16 Bitmap::GetBitCount() const | |||
305 | { | |||
306 | if (!mxSalBmp) | |||
307 | return 0; | |||
308 | ||||
309 | sal_uInt16 nBitCount = mxSalBmp->GetBitCount(); | |||
310 | if (nBitCount <= 1) | |||
311 | return 1; | |||
312 | if (nBitCount <= 4) | |||
313 | return 4; | |||
314 | if (nBitCount <= 8) | |||
315 | return 8; | |||
316 | if (nBitCount <= 24) | |||
317 | return 24; | |||
318 | if (nBitCount <= 32) | |||
319 | return 32; | |||
320 | return 0; | |||
321 | } | |||
322 | ||||
323 | bool Bitmap::HasGreyPaletteAny() const | |||
324 | { | |||
325 | const sal_uInt16 nBitCount = GetBitCount(); | |||
326 | bool bRet = nBitCount == 1; | |||
327 | ||||
328 | ScopedInfoAccess pIAcc(const_cast<Bitmap&>(*this)); | |||
329 | ||||
330 | if( pIAcc ) | |||
331 | { | |||
332 | bRet = pIAcc->HasPalette() && pIAcc->GetPalette().IsGreyPaletteAny(); | |||
333 | } | |||
334 | ||||
335 | return bRet; | |||
336 | } | |||
337 | ||||
338 | bool Bitmap::HasGreyPalette8Bit() const | |||
339 | { | |||
340 | bool bRet = false; | |||
341 | ScopedInfoAccess pIAcc(const_cast<Bitmap&>(*this)); | |||
342 | ||||
343 | if( pIAcc ) | |||
344 | { | |||
345 | bRet = pIAcc->HasPalette() && pIAcc->GetPalette().IsGreyPalette8Bit(); | |||
346 | } | |||
347 | ||||
348 | return bRet; | |||
349 | } | |||
350 | ||||
351 | BitmapChecksum Bitmap::GetChecksum() const | |||
352 | { | |||
353 | BitmapChecksum nRet = 0; | |||
354 | ||||
355 | if( mxSalBmp ) | |||
356 | { | |||
357 | mxSalBmp->GetChecksum(nRet); | |||
358 | ||||
359 | if (!nRet) | |||
360 | { | |||
361 | // nRet == 0 => probably, we were not able to acquire | |||
362 | // the buffer in SalBitmap::updateChecksum; | |||
363 | // so, we need to update the imp bitmap for this bitmap instance | |||
364 | // as we do in BitmapInfoAccess::ImplCreate | |||
365 | std::shared_ptr<SalBitmap> xNewImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap()); | |||
366 | if (xNewImpBmp->Create(*mxSalBmp, GetBitCount())) | |||
367 | { | |||
368 | Bitmap* pThis = const_cast<Bitmap*>(this); | |||
369 | pThis->mxSalBmp = xNewImpBmp; | |||
370 | mxSalBmp->GetChecksum(nRet); | |||
371 | } | |||
372 | } | |||
373 | } | |||
374 | ||||
375 | return nRet; | |||
376 | } | |||
377 | ||||
378 | void Bitmap::ImplMakeUnique() | |||
379 | { | |||
380 | if (mxSalBmp && mxSalBmp.use_count() > 1) | |||
381 | { | |||
382 | std::shared_ptr<SalBitmap> xOldImpBmp = mxSalBmp; | |||
383 | mxSalBmp = ImplGetSVData()->mpDefInst->CreateSalBitmap(); | |||
384 | (void)mxSalBmp->Create(*xOldImpBmp); | |||
385 | } | |||
386 | } | |||
387 | ||||
388 | void Bitmap::ReassignWithSize(const Bitmap& rBitmap) | |||
389 | { | |||
390 | const Size aOldSizePix(GetSizePixel()); | |||
391 | const Size aNewSizePix(rBitmap.GetSizePixel()); | |||
392 | const MapMode aOldMapMode(maPrefMapMode); | |||
393 | Size aNewPrefSize; | |||
394 | ||||
395 | if ((aOldSizePix != aNewSizePix) && aOldSizePix.Width() && aOldSizePix.Height()) | |||
396 | { | |||
397 | aNewPrefSize.setWidth(FRound(maPrefSize.Width() * aNewSizePix.Width() / aOldSizePix.Width())); | |||
398 | aNewPrefSize.setHeight(FRound(maPrefSize.Height() * aNewSizePix.Height() / aOldSizePix.Height())); | |||
399 | } | |||
400 | else | |||
401 | { | |||
402 | aNewPrefSize = maPrefSize; | |||
403 | } | |||
404 | ||||
405 | *this = rBitmap; | |||
406 | ||||
407 | maPrefSize = aNewPrefSize; | |||
408 | maPrefMapMode = aOldMapMode; | |||
409 | } | |||
410 | ||||
411 | ||||
412 | void Bitmap::ImplSetSalBitmap(const std::shared_ptr<SalBitmap>& xImpBmp) | |||
413 | { | |||
414 | mxSalBmp = xImpBmp; | |||
415 | } | |||
416 | ||||
417 | BitmapInfoAccess* Bitmap::AcquireInfoAccess() | |||
418 | { | |||
419 | std::unique_ptr<BitmapInfoAccess> pInfoAccess(new BitmapInfoAccess( *this )); | |||
420 | ||||
421 | if( !*pInfoAccess ) | |||
422 | { | |||
423 | return nullptr; | |||
424 | } | |||
425 | ||||
426 | return pInfoAccess.release(); | |||
427 | } | |||
428 | ||||
429 | BitmapReadAccess* Bitmap::AcquireReadAccess() | |||
430 | { | |||
431 | std::unique_ptr<BitmapReadAccess> pReadAccess(new BitmapReadAccess( *this )); | |||
432 | ||||
433 | if( !*pReadAccess ) | |||
434 | { | |||
435 | return nullptr; | |||
436 | } | |||
437 | ||||
438 | return pReadAccess.release(); | |||
439 | } | |||
440 | ||||
441 | BitmapWriteAccess* Bitmap::AcquireWriteAccess() | |||
442 | { | |||
443 | std::unique_ptr<BitmapWriteAccess> pWriteAccess(new BitmapWriteAccess( *this )); | |||
444 | ||||
445 | if( !*pWriteAccess ) | |||
446 | { | |||
447 | return nullptr; | |||
448 | } | |||
449 | ||||
450 | return pWriteAccess.release(); | |||
451 | } | |||
452 | ||||
453 | void Bitmap::ReleaseAccess( BitmapInfoAccess* pBitmapAccess ) | |||
454 | { | |||
455 | delete pBitmapAccess; | |||
456 | } | |||
457 | ||||
458 | bool Bitmap::Crop( const tools::Rectangle& rRectPixel ) | |||
459 | { | |||
460 | const Size aSizePix( GetSizePixel() ); | |||
461 | tools::Rectangle aRect( rRectPixel ); | |||
462 | bool bRet = false; | |||
463 | ||||
464 | aRect.Intersection( tools::Rectangle( Point(), aSizePix ) ); | |||
465 | ||||
466 | if( !aRect.IsEmpty() && aSizePix != aRect.GetSize()) | |||
467 | { | |||
468 | ScopedReadAccess pReadAcc(*this); | |||
469 | ||||
470 | if( pReadAcc ) | |||
471 | { | |||
472 | const tools::Rectangle aNewRect( Point(), aRect.GetSize() ); | |||
473 | Bitmap aNewBmp( aNewRect.GetSize(), GetBitCount(), &pReadAcc->GetPalette() ); | |||
474 | BitmapScopedWriteAccess pWriteAcc(aNewBmp); | |||
475 | ||||
476 | if( pWriteAcc ) | |||
477 | { | |||
478 | const long nOldX = aRect.Left(); | |||
479 | const long nOldY = aRect.Top(); | |||
480 | const long nNewWidth = aNewRect.GetWidth(); | |||
481 | const long nNewHeight = aNewRect.GetHeight(); | |||
482 | ||||
483 | for( long nY = 0, nY2 = nOldY; nY < nNewHeight; nY++, nY2++ ) | |||
484 | { | |||
485 | Scanline pScanline = pWriteAcc->GetScanline(nY); | |||
486 | Scanline pScanlineRead = pReadAcc->GetScanline(nY2); | |||
487 | for( long nX = 0, nX2 = nOldX; nX < nNewWidth; nX++, nX2++ ) | |||
488 | pWriteAcc->SetPixelOnData( pScanline, nX, pReadAcc->GetPixelFromData( pScanlineRead, nX2 ) ); | |||
489 | } | |||
490 | ||||
491 | pWriteAcc.reset(); | |||
492 | bRet = true; | |||
493 | } | |||
494 | ||||
495 | pReadAcc.reset(); | |||
496 | ||||
497 | if( bRet ) | |||
498 | ReassignWithSize( aNewBmp ); | |||
499 | } | |||
500 | } | |||
501 | ||||
502 | return bRet; | |||
503 | }; | |||
504 | ||||
505 | bool Bitmap::CopyPixel( const tools::Rectangle& rRectDst, | |||
506 | const tools::Rectangle& rRectSrc, const Bitmap* pBmpSrc ) | |||
507 | { | |||
508 | const Size aSizePix( GetSizePixel() ); | |||
509 | tools::Rectangle aRectDst( rRectDst ); | |||
510 | bool bRet = false; | |||
511 | ||||
512 | aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) ); | |||
513 | ||||
514 | if( !aRectDst.IsEmpty() ) | |||
| ||||
515 | { | |||
516 | if( pBmpSrc && ( pBmpSrc->mxSalBmp != mxSalBmp ) ) | |||
517 | { | |||
518 | Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc); | |||
519 | const Size aCopySizePix( pSrc->GetSizePixel() ); | |||
520 | tools::Rectangle aRectSrc( rRectSrc ); | |||
521 | const sal_uInt16 nSrcBitCount = pBmpSrc->GetBitCount(); | |||
522 | const sal_uInt16 nDstBitCount = GetBitCount(); | |||
523 | ||||
524 | if( nSrcBitCount
| |||
525 | { | |||
526 | int nNextIndex = 0; | |||
527 | ||||
528 | if (nSrcBitCount == 24) | |||
529 | Convert( BmpConversion::N24Bit ); | |||
530 | else if (nSrcBitCount == 8) | |||
531 | { | |||
532 | Convert( BmpConversion::N8BitColors ); | |||
533 | nNextIndex = 16; | |||
534 | } | |||
535 | else if (nSrcBitCount == 4) | |||
536 | { | |||
537 | Convert( BmpConversion::N4BitColors ); | |||
538 | nNextIndex = 2; | |||
539 | } | |||
540 | ||||
541 | if( nNextIndex ) | |||
542 | { | |||
543 | ScopedReadAccess pSrcAcc(*pSrc); | |||
544 | BitmapScopedWriteAccess pDstAcc(*this); | |||
545 | ||||
546 | if( pSrcAcc && pDstAcc ) | |||
547 | { | |||
548 | const int nSrcCount = pDstAcc->GetPaletteEntryCount(); | |||
549 | const int nDstCount = 1 << nDstBitCount; | |||
550 | ||||
551 | for (int i = 0; ( i < nSrcCount ) && ( nNextIndex < nSrcCount ); ++i) | |||
552 | { | |||
553 | const BitmapColor& rSrcCol = pSrcAcc->GetPaletteColor( static_cast<sal_uInt16>(i) ); | |||
554 | ||||
555 | bool bFound = false; | |||
556 | ||||
557 | for (int j = 0; j < nDstCount; ++j) | |||
558 | { | |||
559 | if( rSrcCol == pDstAcc->GetPaletteColor( static_cast<sal_uInt16>(j) ) ) | |||
560 | { | |||
561 | bFound = true; | |||
562 | break; | |||
563 | } | |||
564 | } | |||
565 | ||||
566 | if( !bFound ) | |||
567 | pDstAcc->SetPaletteColor( static_cast<sal_uInt16>(nNextIndex++), rSrcCol ); | |||
568 | } | |||
569 | } | |||
570 | } | |||
571 | } | |||
572 | ||||
573 | aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) ); | |||
574 | ||||
575 | if( !aRectSrc.IsEmpty() ) | |||
576 | { | |||
577 | ScopedReadAccess pReadAcc(*pSrc); | |||
578 | ||||
579 | if( pReadAcc ) | |||
580 | { | |||
581 | BitmapScopedWriteAccess pWriteAcc(*this); | |||
582 | ||||
583 | if( pWriteAcc ) | |||
584 | { | |||
585 | const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() ); | |||
586 | const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() ); | |||
587 | const long nSrcEndX = aRectSrc.Left() + nWidth; | |||
588 | const long nSrcEndY = aRectSrc.Top() + nHeight; | |||
589 | long nDstY = aRectDst.Top(); | |||
590 | ||||
591 | if( pReadAcc->HasPalette() && pWriteAcc->HasPalette() ) | |||
592 | { | |||
593 | const sal_uInt16 nCount = pReadAcc->GetPaletteEntryCount(); | |||
594 | std::unique_ptr<sal_uInt8[]> pMap(new sal_uInt8[ nCount ]); | |||
595 | ||||
596 | // Create index map for the color table, as the bitmap should be copied | |||
597 | // retaining it's color information relatively well | |||
598 | for( sal_uInt16 i = 0; i < nCount; i++ ) | |||
599 | pMap[ i ] = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex( pReadAcc->GetPaletteColor( i ) )); | |||
600 | ||||
601 | for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ ) | |||
602 | { | |||
603 | Scanline pScanline = pWriteAcc->GetScanline(nDstY); | |||
604 | Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY); | |||
605 | for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ ) | |||
606 | pWriteAcc->SetPixelOnData( pScanline, nDstX, BitmapColor( pMap[ pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ] )); | |||
| ||||
607 | } | |||
608 | } | |||
609 | else if( pReadAcc->HasPalette() ) | |||
610 | { | |||
611 | for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ ) | |||
612 | { | |||
613 | Scanline pScanline = pWriteAcc->GetScanline(nDstY); | |||
614 | Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY); | |||
615 | for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ ) | |||
616 | pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPaletteColor( pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ) ); | |||
617 | } | |||
618 | } | |||
619 | else | |||
620 | for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ ) | |||
621 | { | |||
622 | Scanline pScanline = pWriteAcc->GetScanline(nDstY); | |||
623 | Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY); | |||
624 | for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ ) | |||
625 | pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) ); | |||
626 | } | |||
627 | ||||
628 | pWriteAcc.reset(); | |||
629 | bRet = ( nWidth > 0 ) && ( nHeight > 0 ); | |||
630 | } | |||
631 | ||||
632 | pReadAcc.reset(); | |||
633 | } | |||
634 | } | |||
635 | } | |||
636 | else | |||
637 | { | |||
638 | tools::Rectangle aRectSrc( rRectSrc ); | |||
639 | ||||
640 | aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) ); | |||
641 | ||||
642 | if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) ) | |||
643 | { | |||
644 | BitmapScopedWriteAccess pWriteAcc(*this); | |||
645 | ||||
646 | if( pWriteAcc ) | |||
647 | { | |||
648 | const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() ); | |||
649 | const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() ); | |||
650 | const long nSrcX = aRectSrc.Left(); | |||
651 | const long nSrcY = aRectSrc.Top(); | |||
652 | const long nSrcEndX1 = nSrcX + nWidth - 1; | |||
653 | const long nSrcEndY1 = nSrcY + nHeight - 1; | |||
654 | const long nDstX = aRectDst.Left(); | |||
655 | const long nDstY = aRectDst.Top(); | |||
656 | const long nDstEndX1 = nDstX + nWidth - 1; | |||
657 | const long nDstEndY1 = nDstY + nHeight - 1; | |||
658 | ||||
659 | if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) ) | |||
660 | { | |||
661 | for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ ) | |||
662 | { | |||
663 | Scanline pScanline = pWriteAcc->GetScanline(nYN); | |||
664 | Scanline pScanlineSrc = pWriteAcc->GetScanline(nY); | |||
665 | for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ ) | |||
666 | pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) ); | |||
667 | } | |||
668 | } | |||
669 | else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) ) | |||
670 | { | |||
671 | for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- ) | |||
672 | { | |||
673 | Scanline pScanline = pWriteAcc->GetScanline(nYN); | |||
674 | Scanline pScanlineSrc = pWriteAcc->GetScanline(nY); | |||
675 | for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ ) | |||
676 | pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) ); | |||
677 | } | |||
678 | } | |||
679 | else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) ) | |||
680 | { | |||
681 | for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ ) | |||
682 | { | |||
683 | Scanline pScanline = pWriteAcc->GetScanline(nYN); | |||
684 | Scanline pScanlineSrc = pWriteAcc->GetScanline(nY); | |||
685 | for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- ) | |||
686 | pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) ); | |||
687 | } | |||
688 | } | |||
689 | else | |||
690 | { | |||
691 | for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- ) | |||
692 | { | |||
693 | Scanline pScanline = pWriteAcc->GetScanline(nYN); | |||
694 | Scanline pScanlineSrc = pWriteAcc->GetScanline(nY); | |||
695 | for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- ) | |||
696 | pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) ); | |||
697 | } | |||
698 | } | |||
699 | ||||
700 | pWriteAcc.reset(); | |||
701 | bRet = true; | |||
702 | } | |||
703 | } | |||
704 | } | |||
705 | } | |||
706 | ||||
707 | return bRet; | |||
708 | } | |||
709 | ||||
710 | bool Bitmap::CopyPixel_AlphaOptimized( const tools::Rectangle& rRectDst, const tools::Rectangle& rRectSrc, | |||
711 | const Bitmap* pBmpSrc ) | |||
712 | { | |||
713 | // Note: this code is copied from Bitmap::CopyPixel but avoids any palette lookups | |||
714 | // This optimization is possible because the palettes of AlphaMasks are always identical (8bit GreyPalette, see ctor) | |||
715 | const Size aSizePix( GetSizePixel() ); | |||
716 | tools::Rectangle aRectDst( rRectDst ); | |||
717 | bool bRet = false; | |||
718 | ||||
719 | aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) ); | |||
720 | ||||
721 | if( !aRectDst.IsEmpty() ) | |||
722 | { | |||
723 | if( pBmpSrc && ( pBmpSrc->mxSalBmp != mxSalBmp ) ) | |||
724 | { | |||
725 | Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc); | |||
726 | const Size aCopySizePix( pSrc->GetSizePixel() ); | |||
727 | tools::Rectangle aRectSrc( rRectSrc ); | |||
728 | ||||
729 | aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) ); | |||
730 | ||||
731 | if( !aRectSrc.IsEmpty() ) | |||
732 | { | |||
733 | ScopedReadAccess pReadAcc(*pSrc); | |||
734 | ||||
735 | if( pReadAcc ) | |||
736 | { | |||
737 | BitmapScopedWriteAccess pWriteAcc(*this); | |||
738 | ||||
739 | if( pWriteAcc ) | |||
740 | { | |||
741 | const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() ); | |||
742 | const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() ); | |||
743 | const long nSrcEndX = aRectSrc.Left() + nWidth; | |||
744 | const long nSrcEndY = aRectSrc.Top() + nHeight; | |||
745 | long nDstY = aRectDst.Top(); | |||
746 | ||||
747 | for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++) | |||
748 | { | |||
749 | Scanline pScanline = pWriteAcc->GetScanline(nDstY); | |||
750 | Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY); | |||
751 | for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ ) | |||
752 | pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) ); | |||
753 | } | |||
754 | ||||
755 | pWriteAcc.reset(); | |||
756 | bRet = ( nWidth > 0 ) && ( nHeight > 0 ); | |||
757 | } | |||
758 | ||||
759 | pReadAcc.reset(); | |||
760 | } | |||
761 | } | |||
762 | } | |||
763 | else | |||
764 | { | |||
765 | tools::Rectangle aRectSrc( rRectSrc ); | |||
766 | ||||
767 | aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) ); | |||
768 | ||||
769 | if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) ) | |||
770 | { | |||
771 | BitmapScopedWriteAccess pWriteAcc(*this); | |||
772 | ||||
773 | if( pWriteAcc ) | |||
774 | { | |||
775 | const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() ); | |||
776 | const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() ); | |||
777 | const long nSrcX = aRectSrc.Left(); | |||
778 | const long nSrcY = aRectSrc.Top(); | |||
779 | const long nSrcEndX1 = nSrcX + nWidth - 1; | |||
780 | const long nSrcEndY1 = nSrcY + nHeight - 1; | |||
781 | const long nDstX = aRectDst.Left(); | |||
782 | const long nDstY = aRectDst.Top(); | |||
783 | const long nDstEndX1 = nDstX + nWidth - 1; | |||
784 | const long nDstEndY1 = nDstY + nHeight - 1; | |||
785 | ||||
786 | if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) ) | |||
787 | { | |||
788 | for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ ) | |||
789 | { | |||
790 | Scanline pScanline = pWriteAcc->GetScanline(nYN); | |||
791 | Scanline pScanlineSrc = pWriteAcc->GetScanline(nY); | |||
792 | for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ ) | |||
793 | pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) ); | |||
794 | } | |||
795 | } | |||
796 | else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) ) | |||
797 | { | |||
798 | for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- ) | |||
799 | { | |||
800 | Scanline pScanline = pWriteAcc->GetScanline(nYN); | |||
801 | Scanline pScanlineSrc = pWriteAcc->GetScanline(nY); | |||
802 | for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ ) | |||
803 | pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) ); | |||
804 | } | |||
805 | } | |||
806 | else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) ) | |||
807 | { | |||
808 | for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ ) | |||
809 | { | |||
810 | Scanline pScanline = pWriteAcc->GetScanline(nYN); | |||
811 | Scanline pScanlineSrc = pWriteAcc->GetScanline(nY); | |||
812 | for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- ) | |||
813 | pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) ); | |||
814 | } | |||
815 | } | |||
816 | else | |||
817 | { | |||
818 | for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- ) | |||
819 | { | |||
820 | Scanline pScanline = pWriteAcc->GetScanline(nYN); | |||
821 | Scanline pScanlineSrc = pWriteAcc->GetScanline(nY); | |||
822 | for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- ) | |||
823 | pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) ); | |||
824 | } | |||
825 | } | |||
826 | ||||
827 | pWriteAcc.reset(); | |||
828 | bRet = true; | |||
829 | } | |||
830 | } | |||
831 | } | |||
832 | } | |||
833 | ||||
834 | return bRet; | |||
835 | ||||
836 | } | |||
837 | ||||
838 | bool Bitmap::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor ) | |||
839 | { | |||
840 | bool bRet = false; | |||
841 | ||||
842 | if( nDX || nDY ) | |||
843 | { | |||
844 | const Size aSizePixel( GetSizePixel() ); | |||
845 | const long nWidth = aSizePixel.Width(); | |||
846 | const long nHeight = aSizePixel.Height(); | |||
847 | const Size aNewSize( nWidth + nDX, nHeight + nDY ); | |||
848 | ScopedReadAccess pReadAcc(*this); | |||
849 | ||||
850 | if( pReadAcc ) | |||
851 | { | |||
852 | BitmapPalette aBmpPal( pReadAcc->GetPalette() ); | |||
853 | Bitmap aNewBmp( aNewSize, GetBitCount(), &aBmpPal ); | |||
854 | BitmapScopedWriteAccess pWriteAcc(aNewBmp); | |||
855 | ||||
856 | if( pWriteAcc ) | |||
857 | { | |||
858 | BitmapColor aColor; | |||
859 | const long nNewX = nWidth; | |||
860 | const long nNewY = nHeight; | |||
861 | const long nNewWidth = pWriteAcc->Width(); | |||
862 | const long nNewHeight = pWriteAcc->Height(); | |||
863 | long nX; | |||
864 | long nY; | |||
865 | ||||
866 | if( pInitColor ) | |||
867 | aColor = pWriteAcc->GetBestMatchingColor( *pInitColor ); | |||
868 | ||||
869 | for( nY = 0; nY < nHeight; nY++ ) | |||
870 | { | |||
871 | pWriteAcc->CopyScanline( nY, *pReadAcc ); | |||
872 | ||||
873 | if( pInitColor && nDX ) | |||
874 | { | |||
875 | Scanline pScanline = pWriteAcc->GetScanline(nY); | |||
876 | for( nX = nNewX; nX < nNewWidth; nX++ ) | |||
877 | pWriteAcc->SetPixelOnData( pScanline, nX, aColor ); | |||
878 | } | |||
879 | } | |||
880 | ||||
881 | if( pInitColor && nDY ) | |||
882 | for( nY = nNewY; nY < nNewHeight; nY++ ) | |||
883 | { | |||
884 | Scanline pScanline = pWriteAcc->GetScanline(nY); | |||
885 | for( nX = 0; nX < nNewWidth; nX++ ) | |||
886 | pWriteAcc->SetPixelOnData( pScanline, nX, aColor ); | |||
887 | } | |||
888 | ||||
889 | pWriteAcc.reset(); | |||
890 | bRet = true; | |||
891 | } | |||
892 | ||||
893 | pReadAcc.reset(); | |||
894 | ||||
895 | if (bRet) | |||
896 | ReassignWithSize(aNewBmp); | |||
897 | } | |||
898 | } | |||
899 | ||||
900 | return bRet; | |||
901 | } | |||
902 | ||||
903 | Bitmap Bitmap::CreateDisplayBitmap( OutputDevice* pDisplay ) const | |||
904 | { | |||
905 | Bitmap aDispBmp( *this ); | |||
906 | ||||
907 | SalGraphics* pDispGraphics = pDisplay->GetGraphics(); | |||
908 | ||||
909 | if( mxSalBmp && pDispGraphics ) | |||
910 | { | |||
911 | std::shared_ptr<SalBitmap> xImpDispBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap()); | |||
912 | if (xImpDispBmp->Create(*mxSalBmp, pDispGraphics)) | |||
913 | aDispBmp.ImplSetSalBitmap(xImpDispBmp); | |||
914 | } | |||
915 | ||||
916 | return aDispBmp; | |||
917 | } | |||
918 | ||||
919 | bool Bitmap::GetSystemData( BitmapSystemData& rData ) const | |||
920 | { | |||
921 | return mxSalBmp && mxSalBmp->GetSystemData(rData); | |||
922 | } | |||
923 | ||||
924 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |