xref: /AOO41X/main/vcl/win/source/gdi/salbmp.cxx (revision d327e58a21b15b860afd29f26e7ba444af09287b)
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