1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_vcl.hxx"
24
25 #include <tools/svwin.h>
26 #include <vcl/bitmap.hxx> // for BitmapSystemData
27 #include <vcl/salbtype.hxx>
28 #include <win/wincomp.hxx>
29 #include <win/salgdi.h>
30 #include <win/saldata.hxx>
31 #include <win/salbmp.h>
32 #include <string.h>
33 #include <vcl/timer.hxx>
34 #include <comphelper/broadcasthelper.hxx>
35 #include <map>
36
37 #ifndef min
38 #define min(a,b) (((a) < (b)) ? (a) : (b))
39 #endif
40 #ifndef max
41 #define max(a,b) (((a) > (b)) ? (a) : (b))
42 #endif
43
44 #include <GdiPlus.h>
45
46 // ------------------------------------------------------------------
47 // - Inlines -
48
ImplSetPixel4(const HPBYTE pScanline,long nX,const BYTE cIndex)49 inline void ImplSetPixel4( const HPBYTE pScanline, long nX, const BYTE cIndex )
50 {
51 BYTE& rByte = pScanline[ nX >> 1 ];
52
53 ( nX & 1 ) ? ( rByte &= 0xf0, rByte |= ( cIndex & 0x0f ) ) :
54 ( rByte &= 0x0f, rByte |= ( cIndex << 4 ) );
55 }
56
57 // ------------------------------------------------------------------
58 // Helper class to manage Gdiplus::Bitmap instances inside of
59 // WinSalBitmap
60
61 struct Comparator
62 {
operator ()Comparator63 bool operator()(WinSalBitmap* pA, WinSalBitmap* pB) const
64 {
65 return pA < pB;
66 }
67 };
68
69 typedef ::std::map< WinSalBitmap*, sal_uInt32, Comparator > EntryMap;
70 static const sal_uInt32 nDefaultCycles(60);
71
72 class GdiPlusBuffer : protected comphelper::OBaseMutex, public Timer
73 {
74 private:
75 EntryMap maEntries;
76
77 public:
GdiPlusBuffer()78 GdiPlusBuffer()
79 : Timer(),
80 maEntries()
81 {
82 SetTimeout(1000);
83 Stop();
84 }
85
~GdiPlusBuffer()86 ~GdiPlusBuffer()
87 {
88 Stop();
89 }
90
addEntry(WinSalBitmap & rEntry)91 void addEntry(WinSalBitmap& rEntry)
92 {
93 ::osl::MutexGuard aGuard(m_aMutex);
94 EntryMap::iterator aFound = maEntries.find(&rEntry);
95
96 if(aFound == maEntries.end())
97 {
98 if(maEntries.empty())
99 {
100 Start();
101 }
102
103 maEntries[&rEntry] = nDefaultCycles;
104 }
105 }
106
remEntry(WinSalBitmap & rEntry)107 void remEntry(WinSalBitmap& rEntry)
108 {
109 ::osl::MutexGuard aGuard(m_aMutex);
110 EntryMap::iterator aFound = maEntries.find(&rEntry);
111
112 if(aFound != maEntries.end())
113 {
114 maEntries.erase(aFound);
115
116 if(maEntries.empty())
117 {
118 Stop();
119 }
120 }
121 }
122
touchEntry(WinSalBitmap & rEntry)123 void touchEntry(WinSalBitmap& rEntry)
124 {
125 ::osl::MutexGuard aGuard(m_aMutex);
126 EntryMap::iterator aFound = maEntries.find(&rEntry);
127
128 if(aFound != maEntries.end())
129 {
130 aFound->second = nDefaultCycles;
131 }
132 }
133
134 // from parent Timer
Timeout()135 virtual void Timeout()
136 {
137 ::osl::MutexGuard aGuard(m_aMutex);
138 EntryMap::iterator aIter(maEntries.begin());
139
140 while(aIter != maEntries.end())
141 {
142 if(aIter->second)
143 {
144 aIter->second--;
145 aIter++;
146 }
147 else
148 {
149 EntryMap::iterator aDelete(aIter);
150 WinSalBitmap* pSource = aDelete->first;
151 aIter++;
152 maEntries.erase(aDelete);
153
154 if(maEntries.empty())
155 {
156 Stop();
157 }
158
159 // delete at WinSalBitmap after entry is removed; this
160 // way it would not hurt to call remEntry from there, too
161 if(pSource->maGdiPlusBitmap.get())
162 {
163 pSource->maGdiPlusBitmap.reset();
164 pSource->mpAssociatedAlpha = 0;
165 }
166 }
167 }
168
169 if(!maEntries.empty())
170 {
171 Start();
172 }
173 }
174 };
175
176 // ------------------------------------------------------------------
177 // Global instance of GdiPlusBuffer which manages Gdiplus::Bitmap
178 // instances
179
180 static GdiPlusBuffer aGdiPlusBuffer;
181
182 // ------------------------------------------------------------------
183 // - WinSalBitmap -
184
WinSalBitmap()185 WinSalBitmap::WinSalBitmap()
186 : maSize(),
187 mhDIB(0),
188 mhDDB(0),
189 maGdiPlusBitmap(),
190 mpAssociatedAlpha(0),
191 mnBitCount(0)
192 {
193 }
194
195 // ------------------------------------------------------------------
196
~WinSalBitmap()197 WinSalBitmap::~WinSalBitmap()
198 {
199 Destroy();
200 }
201
202 // ------------------------------------------------------------------
203
Destroy()204 void WinSalBitmap::Destroy()
205 {
206 if(maGdiPlusBitmap.get())
207 {
208 aGdiPlusBuffer.remEntry(*this);
209 }
210
211 if( mhDIB )
212 GlobalFree( mhDIB );
213 else if( mhDDB )
214 DeleteObject( mhDDB );
215
216 maSize = Size();
217 mnBitCount = 0;
218 }
219
220 // ------------------------------------------------------------------
221
ImplGetGdiPlusBitmap(const WinSalBitmap * pAlphaSource) const222 GdiPlusBmpPtr WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource) const
223 {
224 WinSalBitmap* pThat = const_cast< WinSalBitmap* >(this);
225
226 if(maGdiPlusBitmap.get() && pAlphaSource != mpAssociatedAlpha)
227 {
228 // #122350# if associated alpha with which the GDIPlus was constructed has changed
229 // it is necessary to remove it from buffer, reset reference to it and reconstruct
230 pThat->maGdiPlusBitmap.reset();
231 aGdiPlusBuffer.remEntry(const_cast< WinSalBitmap& >(*this));
232 }
233
234 if(maGdiPlusBitmap.get())
235 {
236 aGdiPlusBuffer.touchEntry(const_cast< WinSalBitmap& >(*this));
237 }
238 else
239 {
240 if(maSize.Width() > 0 && maSize.Height() > 0)
241 {
242 if(pAlphaSource)
243 {
244 pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap(*pAlphaSource));
245 pThat->mpAssociatedAlpha = pAlphaSource;
246 }
247 else
248 {
249 pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap());
250 pThat->mpAssociatedAlpha = 0;
251 }
252
253 if(maGdiPlusBitmap.get())
254 {
255 aGdiPlusBuffer.addEntry(*pThat);
256 }
257 }
258 }
259
260 return maGdiPlusBitmap;
261 }
262
263 // ------------------------------------------------------------------
264
ImplCreateGdiPlusBitmap()265 Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap()
266 {
267 Gdiplus::Bitmap* pRetval(0);
268 WinSalBitmap* pSalRGB = const_cast< WinSalBitmap* >(this);
269 WinSalBitmap* pExtraWinSalRGB = 0;
270
271 if(!pSalRGB->ImplGethDIB())
272 {
273 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
274 pExtraWinSalRGB = new WinSalBitmap();
275 pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount());
276 pSalRGB = pExtraWinSalRGB;
277 }
278
279 BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(true);
280 BitmapBuffer* pExtraRGB = 0;
281
282 if(pRGB && BMP_FORMAT_24BIT_TC_BGR != (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN))
283 {
284 // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
285 SalTwoRect aSalTwoRect;
286
287 aSalTwoRect.mnSrcX = aSalTwoRect.mnSrcY = aSalTwoRect.mnDestX = aSalTwoRect.mnDestY = 0;
288 aSalTwoRect.mnSrcWidth = aSalTwoRect.mnDestWidth = pRGB->mnWidth;
289 aSalTwoRect.mnSrcHeight = aSalTwoRect.mnDestHeight = pRGB->mnHeight;
290
291 pExtraRGB = StretchAndConvert(
292 *pRGB,
293 aSalTwoRect,
294 BMP_FORMAT_24BIT_TC_BGR,
295 0);
296
297 pSalRGB->ReleaseBuffer(pRGB, true);
298 pRGB = pExtraRGB;
299 }
300
301 if(pRGB
302 && pRGB->mnWidth > 0
303 && pRGB->mnHeight > 0
304 && BMP_FORMAT_24BIT_TC_BGR == (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN))
305 {
306 const sal_uInt32 nW(pRGB->mnWidth);
307 const sal_uInt32 nH(pRGB->mnHeight);
308
309 pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat24bppRGB);
310
311 if(pRetval)
312 {
313 if ( pRetval->GetLastStatus() == Gdiplus::Ok )
314 {
315 sal_uInt8* pSrcRGB(pRGB->mpBits);
316 const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
317 const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN);
318 const Gdiplus::Rect aAllRect(0, 0, nW, nH);
319 Gdiplus::BitmapData aGdiPlusBitmapData;
320 pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat24bppRGB, &aGdiPlusBitmapData);
321
322 // copy data to Gdiplus::Bitmap; format is BGR here in both cases, so memcpy is possible
323 for(sal_uInt32 y(0); y < nH; y++)
324 {
325 const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
326 sal_uInt8* targetPixels = (sal_uInt8*)aGdiPlusBitmapData.Scan0 + (nYInsert * aGdiPlusBitmapData.Stride);
327
328 memcpy(targetPixels, pSrcRGB, nW * 3);
329 pSrcRGB += nW * 3 + nExtraRGB;
330 }
331
332 pRetval->UnlockBits(&aGdiPlusBitmapData);
333 }
334 else
335 {
336 delete pRetval;
337 pRetval = NULL;
338 }
339 }
340 }
341
342 if(pExtraRGB)
343 {
344 // #123478# shockingly, BitmapBuffer does not free the memory it is controlling
345 // in it's destructor, this *has to be done handish*. Doing it here now
346 delete[] pExtraRGB->mpBits;
347 delete pExtraRGB;
348 }
349 else
350 {
351 pSalRGB->ReleaseBuffer(pRGB, true);
352 }
353
354 if(pExtraWinSalRGB)
355 {
356 delete pExtraWinSalRGB;
357 }
358
359 return pRetval;
360 }
361
362 // ------------------------------------------------------------------
363
ImplCreateGdiPlusBitmap(const WinSalBitmap & rAlphaSource)364 Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap& rAlphaSource)
365 {
366 Gdiplus::Bitmap* pRetval(0);
367 WinSalBitmap* pSalRGB = const_cast< WinSalBitmap* >(this);
368 WinSalBitmap* pExtraWinSalRGB = 0;
369
370 if(!pSalRGB->ImplGethDIB())
371 {
372 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
373 pExtraWinSalRGB = new WinSalBitmap();
374 pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount());
375 pSalRGB = pExtraWinSalRGB;
376 }
377
378 BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(true);
379 BitmapBuffer* pExtraRGB = 0;
380
381 if(pRGB && BMP_FORMAT_24BIT_TC_BGR != (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN))
382 {
383 // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
384 SalTwoRect aSalTwoRect;
385
386 aSalTwoRect.mnSrcX = aSalTwoRect.mnSrcY = aSalTwoRect.mnDestX = aSalTwoRect.mnDestY = 0;
387 aSalTwoRect.mnSrcWidth = aSalTwoRect.mnDestWidth = pRGB->mnWidth;
388 aSalTwoRect.mnSrcHeight = aSalTwoRect.mnDestHeight = pRGB->mnHeight;
389
390 pExtraRGB = StretchAndConvert(
391 *pRGB,
392 aSalTwoRect,
393 BMP_FORMAT_24BIT_TC_BGR,
394 0);
395
396 pSalRGB->ReleaseBuffer(pRGB, true);
397 pRGB = pExtraRGB;
398 }
399
400 WinSalBitmap* pSalA = const_cast< WinSalBitmap* >(&rAlphaSource);
401 WinSalBitmap* pExtraWinSalA = 0;
402
403 if(!pSalA->ImplGethDIB())
404 {
405 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
406 pExtraWinSalA = new WinSalBitmap();
407 pExtraWinSalA->Create(*pSalA, pSalA->GetBitCount());
408 pSalA = pExtraWinSalA;
409 }
410
411 BitmapBuffer* pA = pSalA->AcquireBuffer(true);
412 BitmapBuffer* pExtraA = 0;
413
414 if(pA && BMP_FORMAT_8BIT_PAL != (pA->mnFormat & ~BMP_FORMAT_TOP_DOWN))
415 {
416 // convert alpha bitmap to BMP_FORMAT_8BIT_PAL format if not yet in that format
417 SalTwoRect aSalTwoRect;
418
419 aSalTwoRect.mnSrcX = aSalTwoRect.mnSrcY = aSalTwoRect.mnDestX = aSalTwoRect.mnDestY = 0;
420 aSalTwoRect.mnSrcWidth = aSalTwoRect.mnDestWidth = pA->mnWidth;
421 aSalTwoRect.mnSrcHeight = aSalTwoRect.mnDestHeight = pA->mnHeight;
422 const BitmapPalette& rTargetPalette = Bitmap::GetGreyPalette(256);
423
424 pExtraA = StretchAndConvert(
425 *pA,
426 aSalTwoRect,
427 BMP_FORMAT_8BIT_PAL,
428 &rTargetPalette);
429
430 pSalA->ReleaseBuffer(pA, true);
431 pA = pExtraA;
432 }
433
434 if(pRGB
435 && pA
436 && pRGB->mnWidth > 0
437 && pRGB->mnHeight > 0
438 && pRGB->mnWidth == pA->mnWidth
439 && pRGB->mnHeight == pA->mnHeight
440 && BMP_FORMAT_24BIT_TC_BGR == (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN)
441 && BMP_FORMAT_8BIT_PAL == (pA->mnFormat & ~BMP_FORMAT_TOP_DOWN))
442 {
443 // we have alpha and bitmap in known formats, create GdiPlus Bitmap as 32bit ARGB
444 const sal_uInt32 nW(pRGB->mnWidth);
445 const sal_uInt32 nH(pRGB->mnHeight);
446
447 pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat32bppARGB);
448
449 if(pRetval)
450 {
451 if ( pRetval->GetLastStatus() == Gdiplus::Ok ) // 2nd place to secure with new Gdiplus::Bitmap
452 {
453 sal_uInt8* pSrcRGB(pRGB->mpBits);
454 sal_uInt8* pSrcA(pA->mpBits);
455 const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
456 const sal_uInt32 nExtraA(pA->mnScanlineSize - nW);
457 const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN);
458 const Gdiplus::Rect aAllRect(0, 0, nW, nH);
459 Gdiplus::BitmapData aGdiPlusBitmapData;
460 pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &aGdiPlusBitmapData);
461
462 // copy data to Gdiplus::Bitmap; format is BGRA; need to mix BGR from Bitmap and
463 // A from alpha, so inner loop is needed (who invented BitmapEx..?)
464 for(sal_uInt32 y(0); y < nH; y++)
465 {
466 const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
467 sal_uInt8* targetPixels = (sal_uInt8*)aGdiPlusBitmapData.Scan0 + (nYInsert * aGdiPlusBitmapData.Stride);
468
469 for(sal_uInt32 x(0); x < nW; x++)
470 {
471 *targetPixels++ = *pSrcRGB++;
472 *targetPixels++ = *pSrcRGB++;
473 *targetPixels++ = *pSrcRGB++;
474 *targetPixels++ = 0xff - *pSrcA++;
475 }
476
477 pSrcRGB += nExtraRGB;
478 pSrcA += nExtraA;
479 }
480
481 pRetval->UnlockBits(&aGdiPlusBitmapData);
482 }
483 else
484 {
485 delete pRetval;
486 pRetval = NULL;
487 }
488 }
489 }
490
491 if(pExtraA)
492 {
493 // #123478# shockingly, BitmapBuffer does not free the memory it is controlling
494 // in it's destructor, this *has to be done handish*. Doing it here now
495 delete[] pExtraA->mpBits;
496 delete pExtraA;
497 }
498 else
499 {
500 pSalA->ReleaseBuffer(pA, true);
501 }
502
503 if(pExtraWinSalA)
504 {
505 delete pExtraWinSalA;
506 }
507
508 if(pExtraRGB)
509 {
510 // #123478# shockingly, BitmapBuffer does not free the memory it is controlling
511 // in it's destructor, this *has to be done handish*. Doing it here now
512 delete[] pExtraRGB->mpBits;
513 delete pExtraRGB;
514 }
515 else
516 {
517 pSalRGB->ReleaseBuffer(pRGB, true);
518 }
519
520 if(pExtraWinSalRGB)
521 {
522 delete pExtraWinSalRGB;
523 }
524
525 return pRetval;
526 }
527
528 // ------------------------------------------------------------------
529
Create(HANDLE hBitmap,bool bDIB,bool bCopyHandle)530 bool WinSalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle )
531 {
532 bool bRet = TRUE;
533
534 if( bDIB )
535 mhDIB = (HGLOBAL) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, TRUE ) : hBitmap );
536 else
537 mhDDB = (HBITMAP) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, FALSE ) : hBitmap );
538
539 if( mhDIB )
540 {
541 PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) GlobalLock( mhDIB );
542
543 maSize = Size( pBIH->biWidth, pBIH->biHeight );
544 mnBitCount = pBIH->biBitCount;
545
546 if( mnBitCount )
547 mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
548
549 GlobalUnlock( mhDIB );
550 }
551 else if( mhDDB )
552 {
553 BITMAP aDDBInfo;
554
555 if( WIN_GetObject( mhDDB, sizeof( BITMAP ), &aDDBInfo ) )
556 {
557 maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
558 mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
559
560 if( mnBitCount )
561 {
562 mnBitCount = ( mnBitCount <= 1 ) ? 1 :
563 ( mnBitCount <= 4 ) ? 4 :
564 ( mnBitCount <= 8 ) ? 8 : 24;
565 }
566 }
567 else
568 {
569 mhDDB = 0;
570 bRet = FALSE;
571 }
572 }
573 else
574 bRet = FALSE;
575
576 return bRet;
577 }
578
579 // ------------------------------------------------------------------
580
Create(const Size & rSize,sal_uInt16 nBitCount,const BitmapPalette & rPal)581 bool WinSalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
582 {
583 bool bRet = FALSE;
584
585 mhDIB = ImplCreateDIB( rSize, nBitCount, rPal );
586
587 if( mhDIB )
588 {
589 maSize = rSize;
590 mnBitCount = nBitCount;
591 bRet = TRUE;
592 }
593
594 return bRet;
595 }
596
597 // ------------------------------------------------------------------
598
Create(const SalBitmap & rSSalBitmap)599 bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap )
600 {
601 bool bRet = FALSE;
602 const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
603
604 if ( rSalBitmap.mhDIB || rSalBitmap.mhDDB )
605 {
606 HANDLE hNewHdl = ImplCopyDIBOrDDB( rSalBitmap.mhDIB ? rSalBitmap.mhDIB : rSalBitmap.mhDDB,
607 rSalBitmap.mhDIB != 0 );
608
609 if ( hNewHdl )
610 {
611 if( rSalBitmap.mhDIB )
612 mhDIB = (HGLOBAL) hNewHdl;
613 else if( rSalBitmap.mhDDB )
614 mhDDB = (HBITMAP) hNewHdl;
615
616 maSize = rSalBitmap.maSize;
617 mnBitCount = rSalBitmap.mnBitCount;
618
619 bRet = TRUE;
620 }
621 }
622
623 return bRet;
624 }
625
626 // ------------------------------------------------------------------
627
Create(const SalBitmap & rSSalBmp,SalGraphics * pSGraphics)628 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
629 {
630 bool bRet = FALSE;
631
632 const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
633 WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
634
635 if( rSalBmp.mhDIB )
636 {
637 PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( rSalBmp.mhDIB );
638 PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
639 HDC hDC = pGraphics->getHDC();
640 HBITMAP hNewDDB;
641 BITMAP aDDBInfo;
642 PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI +
643 ImplGetDIBColorCount( rSalBmp.mhDIB ) * sizeof( RGBQUAD );
644
645 if( pBIH->biBitCount == 1 )
646 {
647 hNewDDB = CreateBitmap( pBIH->biWidth, pBIH->biHeight, 1, 1, NULL );
648
649 if( hNewDDB )
650 SetDIBits( hDC, hNewDDB, 0, pBIH->biHeight, pBits, pBI, DIB_RGB_COLORS );
651 }
652 else
653 hNewDDB = CreateDIBitmap( hDC, (PBITMAPINFOHEADER) pBI, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
654
655 GlobalUnlock( rSalBmp.mhDIB );
656
657 if( hNewDDB && WIN_GetObject( hNewDDB, sizeof( BITMAP ), &aDDBInfo ) )
658 {
659 mhDDB = hNewDDB;
660 maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
661 mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
662
663 bRet = TRUE;
664 }
665 else if( hNewDDB )
666 DeleteObject( hNewDDB );
667 }
668
669 return bRet;
670 }
671
672 // ------------------------------------------------------------------
673
Create(const SalBitmap & rSSalBmp,sal_uInt16 nNewBitCount)674 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, sal_uInt16 nNewBitCount )
675 {
676 bool bRet = FALSE;
677
678 const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
679
680 if( rSalBmp.mhDDB )
681 {
682 mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() );
683
684 if( mhDIB )
685 {
686 PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
687 const int nLines = (int) rSalBmp.maSize.Height();
688 HDC hDC = GetDC( 0 );
689 PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI +
690 ImplGetDIBColorCount( mhDIB ) * sizeof( RGBQUAD );
691 SalData* pSalData = GetSalData();
692 HPALETTE hOldPal = 0;
693
694 if ( pSalData->mhDitherPal )
695 {
696 hOldPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
697 RealizePalette( hDC );
698 }
699
700 if( GetDIBits( hDC, rSalBmp.mhDDB, 0, nLines, pBits, pBI, DIB_RGB_COLORS ) == nLines )
701 {
702 GlobalUnlock( mhDIB );
703 maSize = rSalBmp.maSize;
704 mnBitCount = nNewBitCount;
705 bRet = TRUE;
706 }
707 else
708 {
709 GlobalUnlock( mhDIB );
710 GlobalFree( mhDIB );
711 mhDIB = 0;
712 }
713
714 if( hOldPal )
715 SelectPalette( hDC, hOldPal, TRUE );
716
717 ReleaseDC( 0, hDC );
718 }
719 }
720
721 return bRet;
722 }
723
724 // ------------------------------------------------------------------
725
ImplGetDIBColorCount(HGLOBAL hDIB)726 sal_uInt16 WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB )
727 {
728 sal_uInt16 nColors = 0;
729
730 if( hDIB )
731 {
732 PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDIB );
733 PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
734
735 if ( pBIH->biSize != sizeof( BITMAPCOREHEADER ) )
736 {
737 if( pBIH->biBitCount <= 8 )
738 {
739 if ( pBIH->biClrUsed )
740 nColors = (sal_uInt16) pBIH->biClrUsed;
741 else
742 nColors = 1 << pBIH->biBitCount;
743 }
744 }
745 else if( ( (PBITMAPCOREHEADER) pBI )->bcBitCount <= 8 )
746 nColors = 1 << ( (PBITMAPCOREHEADER) pBI )->bcBitCount;
747
748 GlobalUnlock( hDIB );
749 }
750
751 return nColors;
752 }
753
754 // ------------------------------------------------------------------
755
ImplCreateDIB(const Size & rSize,sal_uInt16 nBits,const BitmapPalette & rPal)756 HGLOBAL WinSalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rPal )
757 {
758 DBG_ASSERT( nBits == 1 || nBits == 4 || nBits == 8 || nBits == 16 || nBits == 24, "Unsupported BitCount!" );
759
760 HGLOBAL hDIB = 0;
761
762 if( rSize.Width() <= 0 || rSize.Height() <= 0 )
763 return hDIB;
764
765 // calculate bitmap size in Bytes
766 const sal_uLong nAlignedWidth4Bytes = AlignedWidth4Bytes( nBits * rSize.Width() );
767 const sal_uLong nImageSize = nAlignedWidth4Bytes * rSize.Height();
768 bool bOverflow = (nImageSize / nAlignedWidth4Bytes) != rSize.Height();
769 if( bOverflow )
770 return hDIB;
771
772 // allocate bitmap memory including header and palette
773 const sal_uInt16 nColors = (nBits <= 8) ? (1 << nBits) : 0;
774 const sal_uLong nHeaderSize = sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD );
775 bOverflow = (nHeaderSize + nImageSize) < nImageSize;
776 if( bOverflow )
777 return hDIB;
778
779 hDIB = GlobalAlloc( GHND, nHeaderSize + nImageSize );
780 if( !hDIB )
781 return hDIB;
782
783 PBITMAPINFO pBI = static_cast<PBITMAPINFO>( GlobalLock( hDIB ) );
784 PBITMAPINFOHEADER pBIH = reinterpret_cast<PBITMAPINFOHEADER>( pBI );
785
786 pBIH->biSize = sizeof( BITMAPINFOHEADER );
787 pBIH->biWidth = rSize.Width();
788 pBIH->biHeight = rSize.Height();
789 pBIH->biPlanes = 1;
790 pBIH->biBitCount = nBits;
791 pBIH->biCompression = BI_RGB;
792 pBIH->biSizeImage = nImageSize;
793 pBIH->biXPelsPerMeter = 0;
794 pBIH->biYPelsPerMeter = 0;
795 pBIH->biClrUsed = 0;
796 pBIH->biClrImportant = 0;
797
798 if( nColors )
799 {
800 // copy the palette entries if any
801 const sal_uInt16 nMinCount = Min( nColors, rPal.GetEntryCount() );
802 if( nMinCount )
803 memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof(RGBQUAD) );
804 }
805
806 GlobalUnlock( hDIB );
807
808 return hDIB;
809 }
810
811 // ------------------------------------------------------------------
812
ImplCopyDIBOrDDB(HANDLE hHdl,bool bDIB)813 HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
814 {
815 HANDLE hCopy = 0;
816
817 if ( bDIB && hHdl )
818 {
819 const sal_uLong nSize = GlobalSize( hHdl );
820
821 if ( (hCopy = GlobalAlloc( GHND, nSize )) != 0 )
822 {
823 memcpy( (LPSTR) GlobalLock( hCopy ), (LPSTR) GlobalLock( hHdl ), nSize );
824
825 GlobalUnlock( hCopy );
826 GlobalUnlock( hHdl );
827 }
828 }
829 else if ( hHdl )
830 {
831 BITMAP aBmp;
832
833 // Source-Bitmap nach Groesse befragen
834 WIN_GetObject( hHdl, sizeof( BITMAP ), (LPSTR) &aBmp );
835
836 // Destination-Bitmap erzeugen
837 if ( (hCopy = CreateBitmapIndirect( &aBmp )) != 0 )
838 {
839 HDC hBmpDC = CreateCompatibleDC( 0 );
840 HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hHdl );
841 HDC hCopyDC = CreateCompatibleDC( hBmpDC );
842 HBITMAP hCopyOld = (HBITMAP) SelectObject( hCopyDC, hCopy );
843
844 BitBlt( hCopyDC, 0, 0, aBmp.bmWidth, aBmp.bmHeight, hBmpDC, 0, 0, SRCCOPY );
845
846 SelectObject( hCopyDC, hCopyOld );
847 DeleteDC( hCopyDC );
848
849 SelectObject( hBmpDC, hBmpOld );
850 DeleteDC( hBmpDC );
851 }
852 }
853
854 return hCopy;
855 }
856
857 // ------------------------------------------------------------------
858
AcquireBuffer(bool)859 BitmapBuffer* WinSalBitmap::AcquireBuffer( bool /*bReadOnly*/ )
860 {
861 BitmapBuffer* pBuffer = NULL;
862
863 if( mhDIB )
864 {
865 PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
866 PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
867
868 if( ( pBIH->biCompression == BI_RLE4 ) || ( pBIH->biCompression == BI_RLE8 ) )
869 {
870 Size aSizePix( pBIH->biWidth, pBIH->biHeight );
871 HGLOBAL hNewDIB = ImplCreateDIB( aSizePix, pBIH->biBitCount, BitmapPalette() );
872
873 if( hNewDIB )
874 {
875 PBITMAPINFO pNewBI = (PBITMAPINFO) GlobalLock( hNewDIB );
876 PBITMAPINFOHEADER pNewBIH = (PBITMAPINFOHEADER) pNewBI;
877 const sal_uInt16 nColorCount = ImplGetDIBColorCount( hNewDIB );
878 const sal_uLong nOffset = *(DWORD*) pBI + nColorCount * sizeof( RGBQUAD );
879 BYTE* pOldBits = (PBYTE) pBI + nOffset;
880 BYTE* pNewBits = (PBYTE) pNewBI + nOffset;
881
882 memcpy( pNewBI, pBI, nOffset );
883 pNewBIH->biCompression = 0;
884 ImplDecodeRLEBuffer( pOldBits, pNewBits, aSizePix, pBIH->biCompression == BI_RLE4 );
885
886 GlobalUnlock( mhDIB );
887 GlobalFree( mhDIB );
888 mhDIB = hNewDIB;
889 pBI = pNewBI;
890 pBIH = pNewBIH;
891 }
892 }
893
894 if( pBIH->biPlanes == 1 )
895 {
896 pBuffer = new BitmapBuffer;
897
898 pBuffer->mnFormat = BMP_FORMAT_BOTTOM_UP |
899 ( pBIH->biBitCount == 1 ? BMP_FORMAT_1BIT_MSB_PAL :
900 pBIH->biBitCount == 4 ? BMP_FORMAT_4BIT_MSN_PAL :
901 pBIH->biBitCount == 8 ? BMP_FORMAT_8BIT_PAL :
902 pBIH->biBitCount == 16 ? BMP_FORMAT_16BIT_TC_LSB_MASK :
903 pBIH->biBitCount == 24 ? BMP_FORMAT_24BIT_TC_BGR :
904 pBIH->biBitCount == 32 ? BMP_FORMAT_32BIT_TC_MASK : 0UL );
905
906 if( BMP_SCANLINE_FORMAT( pBuffer->mnFormat ) )
907 {
908 pBuffer->mnWidth = maSize.Width();
909 pBuffer->mnHeight = maSize.Height();
910 pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->biBitCount );
911 pBuffer->mnBitCount = (sal_uInt16) pBIH->biBitCount;
912
913 if( pBuffer->mnBitCount <= 8 )
914 {
915 const sal_uInt16 nPalCount = ImplGetDIBColorCount( mhDIB );
916
917 pBuffer->maPalette.SetEntryCount( nPalCount );
918 memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->bmiColors, nPalCount * sizeof( RGBQUAD ) );
919 pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nPalCount * sizeof( RGBQUAD );
920 }
921 else if( ( pBIH->biBitCount == 16 ) || ( pBIH->biBitCount == 32 ) )
922 {
923 sal_uLong nOffset = 0UL;
924
925 if( pBIH->biCompression == BI_BITFIELDS )
926 {
927 nOffset = 3 * sizeof( RGBQUAD );
928 pBuffer->maColorMask = ColorMask( *(UINT32*) &pBI->bmiColors[ 0 ],
929 *(UINT32*) &pBI->bmiColors[ 1 ],
930 *(UINT32*) &pBI->bmiColors[ 2 ] );
931 }
932 else if( pBIH->biBitCount == 16 )
933 pBuffer->maColorMask = ColorMask( 0x00007c00UL, 0x000003e0UL, 0x0000001fUL );
934 else
935 pBuffer->maColorMask = ColorMask( 0x00ff0000UL, 0x0000ff00UL, 0x000000ffUL );
936
937 pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nOffset;
938 }
939 else
940 pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI;
941 }
942 else
943 {
944 GlobalUnlock( mhDIB );
945 delete pBuffer;
946 pBuffer = NULL;
947 }
948 }
949 else
950 GlobalUnlock( mhDIB );
951 }
952
953 return pBuffer;
954 }
955
956 // ------------------------------------------------------------------
957
ReleaseBuffer(BitmapBuffer * pBuffer,bool bReadOnly)958 void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
959 {
960 if( pBuffer )
961 {
962 if( mhDIB )
963 {
964 if( !bReadOnly && !!pBuffer->maPalette )
965 {
966 PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
967 const sal_uInt16 nCount = pBuffer->maPalette.GetEntryCount();
968 const sal_uInt16 nDIBColorCount = ImplGetDIBColorCount( mhDIB );
969 memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), Min( nDIBColorCount, nCount ) * sizeof( RGBQUAD ) );
970 GlobalUnlock( mhDIB );
971 }
972
973 GlobalUnlock( mhDIB );
974 }
975
976 delete pBuffer;
977 }
978 }
979
980 // ------------------------------------------------------------------
981
ImplDecodeRLEBuffer(const BYTE * pSrcBuf,BYTE * pDstBuf,const Size & rSizePixel,bool bRLE4)982 void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
983 const Size& rSizePixel, bool bRLE4 )
984 {
985 HPBYTE pRLE = (HPBYTE) pSrcBuf;
986 HPBYTE pDIB = (HPBYTE) pDstBuf;
987 HPBYTE pRow = (HPBYTE) pDstBuf;
988 sal_uLong nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) );
989 HPBYTE pLast = pDIB + rSizePixel.Height() * nWidthAl - 1;
990 sal_uLong nCountByte;
991 sal_uLong nRunByte;
992 sal_uLong nX = 0;
993 sal_uLong i;
994 BYTE cTmp;
995 bool bEndDecoding = FALSE;
996
997 if( pRLE && pDIB )
998 {
999 do
1000 {
1001 if( ( nCountByte = *pRLE++ ) == 0 )
1002 {
1003 nRunByte = *pRLE++;
1004
1005 if( nRunByte > 2UL )
1006 {
1007 if( bRLE4 )
1008 {
1009 nCountByte = nRunByte >> 1UL;
1010
1011 for( i = 0; i < nCountByte; i++ )
1012 {
1013 cTmp = *pRLE++;
1014 ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
1015 ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
1016 }
1017
1018 if( nRunByte & 1 )
1019 ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
1020
1021 if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
1022 pRLE++;
1023 }
1024 else
1025 {
1026 memcpy( &pDIB[ nX ], pRLE, nRunByte );
1027 pRLE += nRunByte;
1028 nX += nRunByte;
1029
1030 if( nRunByte & 1 )
1031 pRLE++;
1032 }
1033 }
1034 else if( !nRunByte )
1035 {
1036 pDIB = ( pRow += nWidthAl );
1037 nX = 0UL;
1038 }
1039 else if( nRunByte == 1 )
1040 bEndDecoding = TRUE;
1041 else
1042 {
1043 nX += *pRLE++;
1044 pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
1045 }
1046 }
1047 else
1048 {
1049 cTmp = *pRLE++;
1050
1051 if( bRLE4 )
1052 {
1053 nRunByte = nCountByte >> 1;
1054
1055 for( i = 0; i < nRunByte; i++ )
1056 {
1057 ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
1058 ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
1059 }
1060
1061 if( nCountByte & 1 )
1062 ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
1063 }
1064 else
1065 {
1066 for( i = 0; i < nCountByte; i++ )
1067 pDIB[ nX++ ] = cTmp;
1068 }
1069 }
1070 }
1071 while( !bEndDecoding && ( pDIB <= pLast ) );
1072 }
1073 }
1074
GetSystemData(BitmapSystemData & rData)1075 bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
1076 {
1077 bool bRet = false;
1078 if( mhDIB || mhDDB )
1079 {
1080 bRet = true;
1081 rData.pDIB = mhDIB;
1082 rData.pDDB = mhDDB;
1083 const Size& rSize = GetSize ();
1084 rData.mnWidth = rSize.Width();
1085 rData.mnHeight = rSize.Height();
1086 }
1087 return bRet;
1088 }
1089