source: trunk/src/kernel/qpixmap_pm.cpp@ 59

Last change on this file since 59 was 59, checked in by dmik, 20 years ago

Implemented alpha blending for pixmaps.
Improved blitting of masked pixmaps.

  • Property svn:keywords set to Id
File size: 42.8 KB
Line 
1/****************************************************************************
2** $Id: qpixmap_pm.cpp 59 2006-01-29 19:56:21Z dmik $
3**
4** Implementation of QPixmap class for OS/2
5**
6** Copyright (C) 1992-2002 Trolltech AS. All rights reserved.
7** Copyright (C) 2004 Norman ASA. Initial OS/2 Port.
8** Copyright (C) 2005 netlabs.org. Further OS/2 Development.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qbitmap.h"
39#include "qimage.h"
40#include "qpaintdevicemetrics.h"
41#include "qwmatrix.h"
42#include "qapplication.h"
43#include "qapplication_p.h"
44#include "qt_os2.h"
45
46extern const uchar *qt_get_bitflip_array(); // defined in qimage.cpp
47
48static inline HPS alloc_mem_ps( int w, int h, HPS compat = 0 )
49{
50 HDC hdcCompat = 0;
51 if ( compat )
52 hdcCompat = GpiQueryDevice( compat );
53
54 static const PSZ hdcData[4] = { "Display", NULL, NULL, NULL };
55 HDC hdc = DevOpenDC( 0, OD_MEMORY, "*", 4, (PDEVOPENDATA) hdcData, hdcCompat );
56 if ( !hdc ) {
57#if defined(QT_CHECK_NULL)
58 qSystemWarning( "alloc_mem_dc: DevOpenDC failed!" );
59#endif
60 return 0;
61 }
62 SIZEL size = { w, h };
63 HPS hps = GpiCreatePS( 0, hdc, &size, PU_PELS | GPIA_ASSOC | GPIT_MICRO );
64 if ( !hps ) {
65#if defined(QT_CHECK_NULL)
66 qSystemWarning( "alloc_mem_dc: GpiCreatePS failed!" );
67#endif
68 return 0;
69 }
70 if ( QColor::hPal() ) {
71 GpiSelectPalette( hps, QColor::hPal() );
72 } else {
73 // direct RGB mode
74 GpiCreateLogColorTable( hps, 0, LCOLF_RGB, 0, 0, NULL );
75 }
76 return hps;
77}
78
79static inline void free_mem_ps( HPS hps )
80{
81 HDC hdc = GpiQueryDevice( hps );
82 GpiAssociate( hps, 0 );
83 GpiDestroyPS( hps );
84 DevCloseDC( hdc );
85}
86
87extern HPS qt_alloc_mem_ps( int w, int h, HPS compat = 0 )
88{
89 return alloc_mem_ps( w, h, compat );
90}
91
92extern void qt_free_mem_ps( HPS hps )
93{
94 free_mem_ps( hps );
95}
96
97
98void QPixmap::init( int w, int h, int d, bool bitmap, Optimization optim )
99{
100#if defined(QT_CHECK_STATE)
101 if ( qApp->type() == QApplication::Tty ) {
102 qWarning( "QPixmap: Cannot create a QPixmap when no GUI "
103 "is being used" );
104 }
105#endif
106
107 static int serial = 0;
108 const int dd = defaultDepth();
109
110 if ( optim == DefaultOptim ) // use default optimization
111 optim = defOptim;
112
113 data = new QPixmapData;
114 Q_CHECK_PTR( data );
115
116 memset( data, 0, sizeof(QPixmapData) );
117 data->count = 1;
118 data->uninit = TRUE;
119 data->bitmap = bitmap;
120 data->ser_no = ++serial;
121 data->optim = optim;
122
123 bool make_null = w == 0 || h == 0; // create null pixmap
124 if ( d == 1 ) // monocrome pixmap
125 data->d = 1;
126 else if ( d < 0 || d == dd ) // compatible pixmap
127 data->d = dd;
128 if ( make_null || w < 0 || h < 0 || data->d == 0 ) {
129 hps = 0;
130 data->hbm = 0;
131#if defined(QT_CHECK_RANGE)
132 if ( !make_null ) // invalid parameters
133 qWarning( "QPixmap: Invalid pixmap parameters" );
134#endif
135 return;
136 }
137 data->w = w;
138 data->h = h;
139
140 hps = alloc_mem_ps( w, h );
141 BITMAPINFOHEADER2 bmh;
142 memset( &bmh, 0, sizeof(BITMAPINFOHEADER2) );
143 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
144 bmh.cx = w;
145 bmh.cy = h;
146 bmh.cPlanes = 1;
147 if ( data->d == 1 ) // monocrome bitmap
148 bmh.cBitCount = 1;
149 else // compatible bitmap
150 bmh.cBitCount = dd;
151 data->hbm = GpiCreateBitmap( hps, &bmh, 0, NULL, NULL );
152
153 if ( !data->hbm ) {
154 data->w = 0;
155 data->h = 0;
156 free_mem_ps( hps );
157 hps = 0;
158#if defined(QT_CHECK_NULL)
159 qSystemWarning( "QPixmap: Pixmap allocation failed" );
160#endif
161 return;
162 }
163
164 GpiSetBitmap( hps, data->hbm );
165}
166
167
168void QPixmap::deref()
169{
170 if ( data && data->deref() ) { // last reference lost
171 if ( hps )
172 GpiSetBitmap( hps, 0 );
173 if ( data->hasRealAlpha && data->realAlphaBits ) {
174 delete[] data->realAlphaBits;
175 data->realAlphaBits = 0;
176 }
177 if ( data->mask ) {
178 delete data->mask;
179 if ( data->maskedHbm ) {
180 GpiDeleteBitmap( data->maskedHbm );
181 data->maskedHbm = 0;
182 }
183 }
184 if ( data->hbm ) {
185 GpiDeleteBitmap( data->hbm );
186 data->hbm = 0;
187 }
188 if ( hps ) {
189 free_mem_ps( hps );
190 hps = 0;
191 }
192 delete data;
193 data = 0;
194 }
195}
196
197
198QPixmap::QPixmap( int w, int h, const uchar *bits, bool isXbitmap )
199 : QPaintDevice( QInternal::Pixmap )
200{ // for bitmaps only
201 init( 0, 0, 0, FALSE, NormalOptim );
202 if ( w <= 0 || h <= 0 ) // create null pixmap
203 return;
204
205 data->uninit = FALSE;
206 data->w = w;
207 data->h = h;
208 data->d = 1;
209
210 int bitsbpl = (w + 7) / 8; // original # bytes per line
211
212 int bpl = ((w + 31) / 32) * 4; // bytes per scanline,
213 // doubleword aligned
214
215 uchar *newbits = new uchar[bpl*h];
216 uchar *p = newbits + bpl*(h - 1); // last scanline
217 int x, y, pad;
218 pad = bpl - bitsbpl;
219 const uchar *f = isXbitmap ? qt_get_bitflip_array() : 0;
220
221 // flip bit order if Xbitmap and flip bitmap top to bottom
222 for ( y=0; y<h; y++ ) {
223 if ( f ) {
224 for ( x=0; x<bitsbpl; x++ )
225 *p++ = f[*bits++];
226 for ( x=0; x<pad; x++ )
227 *p++ = 0;
228 p -= bpl;
229 } else {
230 memcpy( p, bits, bitsbpl );
231 memset( p + bitsbpl, 0, pad );
232 bits += bitsbpl;
233 }
234 p -= bpl;
235 }
236
237 hps = alloc_mem_ps( w, h );
238 // allocate header + 2 palette entries
239 char *bmi_data = new char[ sizeof(BITMAPINFOHEADER2) + 4 * 2 ];
240 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
241 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
242 PULONG pal = (PULONG) (bmi_data + sizeof(BITMAPINFOHEADER2));
243 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
244 bmh.cx = w;
245 bmh.cy = h;
246 bmh.cPlanes = 1;
247 bmh.cBitCount = 1;
248 bmh.cclrUsed = 2;
249 pal[0] = 0;
250 pal[1] = 0x00FFFFFF;
251 data->hbm = GpiCreateBitmap(
252 hps, &bmh, CBM_INIT, (PBYTE) newbits, (PBITMAPINFO2) bmi_data
253 );
254
255 GpiSetBitmap( hps, data->hbm );
256
257 delete [] bmi_data;
258 delete [] newbits;
259 if ( defOptim != NormalOptim )
260 setOptimization( defOptim );
261}
262
263
264void QPixmap::detach()
265{
266 if ( data->uninit || data->count == 1 )
267 data->uninit = FALSE;
268 else
269 *this = copy();
270}
271
272
273int QPixmap::defaultDepth()
274{
275 static int dd = 0;
276 if ( dd == 0 ) {
277 LONG formats[ 2 ];
278 GpiQueryDeviceBitmapFormats( qt_display_ps(), 2, formats );
279 dd = formats[ 0 ] * formats[ 1 ];
280 }
281 return dd;
282}
283
284
285void QPixmap::setOptimization( Optimization optimization )
286{
287 if ( optimization == data->optim )
288 return;
289 detach();
290 data->optim = optimization == DefaultOptim ?
291 defOptim : optimization;
292}
293
294
295void QPixmap::fill( const QColor &fillColor )
296{
297 if ( isNull() )
298 return;
299 detach(); // detach other references
300
301 const ULONG AreaAttrs = ABB_COLOR | ABB_MIX_MODE | ABB_SET | ABB_SYMBOL;
302 AREABUNDLE oldAb;
303 GpiQueryAttrs( hps, PRIM_AREA, AreaAttrs, (PBUNDLE) &oldAb );
304 AREABUNDLE newAb;
305 newAb.lColor = fillColor.pixel();
306 newAb.usMixMode = FM_OVERPAINT;
307 newAb.usSet = LCID_DEFAULT;
308 newAb.usSymbol = PATSYM_SOLID;
309 GpiSetAttrs( hps, PRIM_AREA, AreaAttrs, 0, (PBUNDLE) &newAb );
310 POINTL ptl = { 0, 0 };
311 GpiMove( hps, &ptl );
312 ptl.x = data->w - 1;
313 ptl.y = data->h - 1;
314 GpiBox( hps, DRO_FILL, &ptl, 0, 0 );
315 GpiSetAttrs( hps, PRIM_AREA, AreaAttrs, 0, (PBUNDLE) &newAb );
316}
317
318
319int QPixmap::metric( int m ) const
320{
321 if ( m == QPaintDeviceMetrics::PdmWidth ) {
322 return width();
323 } else if ( m == QPaintDeviceMetrics::PdmHeight ) {
324 return height();
325 } else {
326 LONG val;
327 HDC hdc = GpiQueryDevice( hps );
328 switch ( m ) {
329 case QPaintDeviceMetrics::PdmDpiX:
330 DevQueryCaps( hdc, CAPS_HORIZONTAL_FONT_RES, 1, &val );
331 break;
332 case QPaintDeviceMetrics::PdmDpiY:
333 DevQueryCaps( hdc, CAPS_VERTICAL_FONT_RES, 1, &val );
334 break;
335 case QPaintDeviceMetrics::PdmWidthMM:
336 DevQueryCaps( hdc, CAPS_HORIZONTAL_RESOLUTION, 1, &val );
337 val = width() * 1000 / val;
338 break;
339 case QPaintDeviceMetrics::PdmHeightMM:
340 DevQueryCaps( hdc, CAPS_VERTICAL_RESOLUTION, 1, &val );
341 val = width() * 1000 / val;
342 break;
343 case QPaintDeviceMetrics::PdmNumColors:
344 if (depth() == 1) {
345 // it's a monochrome bitmap
346 val = 1;
347 } else {
348 DevQueryCaps( hdc, CAPS_COLORS, 1, &val );
349 }
350 break;
351 case QPaintDeviceMetrics::PdmDepth:
352 val = depth();
353 break;
354 default:
355 val = 0;
356#if defined(QT_CHECK_RANGE)
357 qWarning( "QPixmap::metric: Invalid metric command" );
358#endif
359 }
360 return val;
361 }
362}
363
364QImage QPixmap::convertToImage() const
365{
366 if ( isNull() )
367 return QImage(); // null image
368
369 int w = width();
370 int h = height();
371 const QBitmap *m = data->hasRealAlpha ? 0 : mask();
372 int d = depth();
373 int ncols = 2;
374
375 if ( d > 1 && d <= 8 ) { // set to nearest valid depth
376 d = 8; // 2..7 ==> 8
377 ncols = 256;
378 } else if ( d > 8 ) {
379 d = 32; // > 8 ==> 32
380 ncols = 0;
381#if defined QT_CHECK_RANGE
382 if ( trueColorDepth() != 32 )
383 qWarning( "QPixmap::convertToImage(): video driver doesn't seem to "
384 "support the 32-bpp color depth!" );
385 // don't return since we still hope the driver can at least convert
386 // from/to 32-bpp bitmaps
387#endif
388 }
389
390 QImage image( w, h, d, ncols, QImage::BigEndian );
391
392 // allocate header + ncols palette entries
393 char *bmi_data = new char[ sizeof(BITMAPINFOHEADER2) + 4 * ncols ];
394 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
395 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
396 PULONG pal = (PULONG) (bmi_data + sizeof(BITMAPINFOHEADER2));
397 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
398 bmh.cx = w;
399 bmh.cy = h;
400 bmh.cPlanes = 1;
401 bmh.cBitCount = d;
402 bmh.cclrUsed = ncols;
403 GpiQueryBitmapBits( hps, 0, h, (PBYTE) image.bits(), (PBITMAPINFO2) bmi_data );
404
405 if ( data->hasRealAlpha ) {
406 if ( data->realAlphaBits ) {
407 // incorporate the alpha channel to image data
408 // (see comments in convertFromImage() for details)
409 uchar *src = data->realAlphaBits;
410 int y = 0;
411 while ( y < image.height() ) {
412 uchar *dst = image.scanLine( y++ );
413 uchar *end = dst + image.bytesPerLine();
414 dst += 3;
415 while ( dst < end ) {
416 *dst = *(src++);
417 dst += 4;
418 }
419 }
420 }
421 image.setAlphaBuffer( TRUE );
422 }
423
424 // flip the image top to bottom
425 {
426 int bpl = image.bytesPerLine();
427 uchar *line = new uchar[bpl];
428 uchar *top = image.scanLine( 0 );
429 uchar *bottom = image.scanLine( h - 1 );
430 while( top < bottom ) {
431 memcpy( line, top, bpl );
432 memcpy( top, bottom, bpl );
433 memcpy( bottom, line, bpl );
434 top += bpl;
435 bottom -= bpl;
436 }
437 delete [] line;
438 }
439
440 if ( d == 1 ) {
441 // use a white/black palette for monochrome pixmaps (istead of
442 // black/white supplied by GPI) to make the result of possible
443 // converson to a higher depth compatible with other platforms.
444 if ( m ) {
445 image.setAlphaBuffer( TRUE );
446 image.setColor( 0, qRgba( 255, 255, 255, 0 ) );
447 image.setColor( 1, qRgba( 0, 0, 0, 255 ) );
448 } else {
449 image.setColor( 0, qRgb( 255, 255, 255 ) );
450 image.setColor( 1, qRgb( 0, 0, 0 ) );
451 }
452 } else {
453 for ( int i=0; i<ncols; i++ ) { // copy color table
454 PRGB2 r = (PRGB2) &pal[i];
455 if ( m )
456 image.setColor( i, qRgba(r->bRed,
457 r->bGreen,
458 r->bBlue,255) );
459 else
460 image.setColor( i, qRgb(r->bRed,
461 r->bGreen,
462 r->bBlue) );
463 }
464 }
465
466 delete [] bmi_data;
467
468 if ( d != 1 && m ) {
469 image.setAlphaBuffer(TRUE);
470 QImage msk = m->convertToImage();
471
472 switch ( d ) {
473 case 8: {
474 int used[256];
475 memset( used, 0, sizeof(int)*256 );
476 uchar* p = image.bits();
477 int l = image.numBytes();
478 while (l--) {
479 used[*p++]++;
480 }
481 int trans=0;
482 int bestn=INT_MAX;
483 for ( int i=0; i<256; i++ ) {
484 if ( used[i] < bestn ) {
485 bestn = used[i];
486 trans = i;
487 if ( !bestn )
488 break;
489 }
490 }
491 image.setColor( trans, image.color(trans)&0x00ffffff );
492 for ( int y=0; y<image.height(); y++ ) {
493 uchar* mb = msk.scanLine(y);
494 uchar* ib = image.scanLine(y);
495 uchar bit = 0x80;
496 int i=image.width();
497 while (i--) {
498 if ( !(*mb & bit) )
499 *ib = trans;
500 bit /= 2; if ( !bit ) mb++,bit = 0x80; // ROL
501 ib++;
502 }
503 }
504 } break;
505 case 32: {
506 for ( int y=0; y<image.height(); y++ ) {
507 uchar* mb = msk.scanLine(y);
508 QRgb* ib = (QRgb*)image.scanLine(y);
509 uchar bit = 0x80;
510 int i=image.width();
511 while (i--) {
512 if ( *mb & bit )
513 *ib |= 0xff000000;
514 else
515 *ib &= 0x00ffffff;
516 bit /= 2; if ( !bit ) mb++,bit = 0x80; // ROL
517 ib++;
518 }
519 }
520 } break;
521 }
522 }
523
524 return image;
525}
526
527bool QPixmap::convertFromImage( const QImage &img, int conversion_flags )
528{
529 if ( img.isNull() ) {
530#if defined(QT_CHECK_NULL)
531 qWarning( "QPixmap::convertFromImage: Cannot convert a null image" );
532#endif
533 return FALSE;
534 }
535
536 QImage image = img;
537 int d = image.depth();
538 int dd = defaultDepth();
539 bool force_mono = (dd == 1 || isQBitmap() ||
540 (conversion_flags & ColorMode_Mask)==MonoOnly );
541
542 if ( force_mono ) { // must be monochrome
543 if ( d != 1 ) { // dither
544 image = image.convertDepth( 1, conversion_flags );
545 d = 1;
546 }
547 } else { // can be both
548 bool conv8 = FALSE;
549 if ( d > 8 && dd <= 8 ) { // convert to 8 bit
550 if ( (conversion_flags & DitherMode_Mask) == AutoDither )
551 conversion_flags = (conversion_flags & ~DitherMode_Mask)
552 | PreferDither;
553 conv8 = TRUE;
554 } else if ( (conversion_flags & ColorMode_Mask) == ColorOnly ) {
555 conv8 = d == 1; // native depth wanted
556 } else if ( d == 1 ) {
557 if ( image.numColors() == 2 ) {
558 // Note: 1-bpp images other than true black-white cannot be
559 // correctly stored as GPI bitmaps (it doesn't store the palette
560 // for them), so the code below ensures they will be converted
561 // to 8-bpp images first. However, black-white images with alpha
562 // channel will be also converted, though they can be stored
563 // as bitmaps. The correct code to prevent setting conv8 to TRUE
564 // for black-white bitmaps both with and w/o alpha should be:
565 // QRgb c0 = image.color(0) | ~RGB_MASK;
566 // QRgb c1 = image.color(1) | ~RGB_MASK;
567 // but it is left as is solely for compatibility with Qt/Win32
568 // (otherwise we would get visually different pixmaps).
569 QRgb c0 = image.color(0); // Auto: convert to best
570 QRgb c1 = image.color(1);
571 conv8 = QMIN(c0,c1) != qRgb(0,0,0) || QMAX(c0,c1) != qRgb(255,255,255);
572 } else {
573 // eg. 1-color monochrome images (they do exist).
574 conv8 = TRUE;
575 }
576 }
577 if ( conv8 ) {
578 image = image.convertDepth( 8, conversion_flags );
579 d = 8;
580 }
581 }
582
583 if ( d == 1 ) { // 1 bit pixmap (bitmap)
584 image = image.convertBitOrder( QImage::BigEndian );
585 }
586
587 bool hasRealAlpha = FALSE;
588 if ( img.hasAlphaBuffer() ) {
589 if (image.depth() == 8) {
590 const QRgb * const rgb = img.colorTable();
591 for (int i = 0, count = img.numColors(); i < count; ++i) {
592 const int alpha = qAlpha(rgb[i]);
593 if (alpha != 0 && alpha != 0xff) {
594 hasRealAlpha = true;
595 break;
596 }
597 }
598 if (hasRealAlpha) {
599 image = image.convertDepth(32, conversion_flags);
600 d = image.depth();
601 }
602 } else if (image.depth() == 32) {
603 int i = 0;
604 while ( i<image.height() && !hasRealAlpha ) {
605 uchar *p = image.scanLine(i);
606 uchar *end = p + image.bytesPerLine();
607 p += 3;
608 while ( p < end ) {
609 if ( *p!=0 && *p!=0xff ) {
610 hasRealAlpha = TRUE;
611 break;
612 }
613 p += 4;
614 }
615 ++i;
616 }
617 }
618 }
619
620 int w = image.width();
621 int h = image.height();
622
623 if ( width() == w && height() == h &&
624 ( (d == 1 && depth() == 1) ||
625 (d != 1 && depth() != 1 && hasRealAlpha == hasAlphaChannel()) ) ) {
626 // same size etc., use the existing pixmap
627 detach();
628 if ( data->mask ) { // get rid of the mask
629 delete data->mask;
630 data->mask = 0;
631 if ( data->maskedHbm )
632 prepareForMasking( FALSE, TRUE );
633 }
634 } else {
635 // different size or depth, make a new pixmap
636 QPixmap pm( w, h, d == 1 ? 1 : -1, data->bitmap, data->optim );
637 *this = pm;
638 }
639
640#if defined QT_CHECK_RANGE
641 if ( d == 32 && trueColorDepth() != 32 )
642 qWarning( "QPixmap::convertFromImage(): video driver doesn't seem to "
643 "support the 32-bpp color depth!" );
644 // don't return since we still hope the driver can at least convert
645 // from/to 32-bpp bitmaps
646#endif
647
648 int ncols = image.numColors();
649
650 // allocate header + ncols palette entries
651 char *bmi_data = new char[ sizeof(BITMAPINFOHEADER2) + 4 * ncols ];
652 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
653 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
654 PULONG pal = (PULONG) (bmi_data + sizeof(BITMAPINFOHEADER2));
655 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
656 bmh.cx = w;
657 bmh.cy = h;
658 bmh.cPlanes = 1;
659 bmh.cBitCount = d;
660 bmh.cclrUsed = ncols;
661 bool doAlloc = ( QApplication::colorSpec() == QApplication::CustomColor
662 && QColor::hPal() );
663
664 if ( d == 1 ) {
665 // always use the black/white palette for monochrome pixmaps;
666 // otherwise GPI can swap 0s and 1s when creating a bitmap.
667 pal [0] = 0;
668 pal [1] = 0x00FFFFFF;
669 } else {
670 for ( int i=0; i<ncols; i++ ) { // copy color table
671 PRGB2 r = (PRGB2) &pal[i];
672 QRgb c = image.color(i);
673 r->bBlue = qBlue( c );
674 r->bGreen = qGreen( c );
675 r->bRed = qRed( c );
676 r->fcOptions = 0;
677 if ( doAlloc ) {
678 QColor cl( c );
679 cl.alloc();
680 }
681 }
682 }
683
684 data->hasRealAlpha = hasRealAlpha;
685
686 // If we have real alpha bits and the default video driver depth is 32-bpp,
687 // we store the alpha channel in the unused high byte of the 32-bit pixel
688 // value to save memory and slightly optimize the performance (QImage already
689 // contains the alpha channel there, so nothing has to be done when setting
690 // bitmap bits). Otherwise we create a separate array to store the alpha
691 // channel from QImage.
692
693 if ( hasRealAlpha && depth() != 32 ) {
694 if ( data->realAlphaBits == 0 ) {
695 // alpha bits buffer doesn't exist yet, create it
696 data->realAlphaBits = new uchar [w * h];
697 }
698 // store alpha bits flipping scan lines top to bottom
699 uchar *dst = data->realAlphaBits + w * (h - 1);
700 int y = 0;
701 while ( y < image.height() ) {
702 uchar *src = image.scanLine( y++ );
703 uchar *end = src + image.bytesPerLine();
704 src += 3;
705 while ( src < end ) {
706 *(dst++) = *src;
707 src += 4;
708 }
709 // go to the previous row
710 dst -= w * 2;
711 }
712 }
713
714 // flip the image top to bottom
715 image.detach();
716 int bpl = image.bytesPerLine();
717 uchar *line = new uchar[bpl];
718 uchar *top = image.scanLine( 0 );
719 uchar *bottom = image.scanLine( h - 1 );
720 while( top < bottom ) {
721 memcpy( line, top, bpl );
722 memcpy( top, bottom, bpl );
723 memcpy( bottom, line, bpl );
724 top += bpl;
725 bottom -= bpl;
726 }
727 delete [] line;
728 GpiSetBitmapBits( hps, 0, h, (PBYTE) image.bits(), (PBITMAPINFO2) bmi_data );
729
730 if ( img.hasAlphaBuffer() ) {
731 QBitmap m;
732 m = img.createAlphaMask( conversion_flags );
733 data->mask = new QBitmap( m );
734 }
735
736 delete [] bmi_data;
737 data->uninit = FALSE;
738
739 return TRUE;
740}
741
742
743QPixmap QPixmap::grabWindow( WId window, int x, int y, int w, int h )
744{
745 RECTL rcl;
746 WinQueryWindowRect( window, &rcl );
747 if ( w <= 0 || h <= 0 ) {
748 if ( w == 0 || h == 0 ) {
749 QPixmap nullPixmap;
750 return nullPixmap;
751 }
752 if ( w < 0 )
753 w = rcl.xRight;
754 if ( h < 0 )
755 h = rcl.yTop;
756 }
757 // flip y coordinate
758 y = rcl.yTop - (y + h);
759 QPixmap pm( w, h );
760 HPS hps = WinGetPS( window );
761 POINTL pnts[] = { {0, 0}, {w, h}, {x, y} };
762 GpiBitBlt( pm.hps, hps, 3, pnts, ROP_SRCCOPY, BBO_IGNORE );
763 WinReleasePS( hps );
764 return pm;
765}
766
767#ifndef QT_NO_PIXMAP_TRANSFORMATION
768QPixmap QPixmap::xForm( const QWMatrix &matrix ) const
769{
770 int w, h; // size of target pixmap
771 int ws, hs; // size of source pixmap
772 uchar *dptr; // data in target pixmap
773 int dbpl, dbytes; // bytes per line/bytes total
774 uchar *sptr; // data in original pixmap
775 int sbpl; // bytes per line in original
776 int bpp; // bits per pixel
777 bool depth1 = depth() == 1;
778
779 if ( isNull() ) // this is a null pixmap
780 return copy();
781
782 ws = width();
783 hs = height();
784
785 QWMatrix mat( matrix.m11(), matrix.m12(), matrix.m21(), matrix.m22(), 0., 0. );
786
787 if ( matrix.m12() == 0.0F && matrix.m21() == 0.0F &&
788 matrix.m11() >= 0.0F && matrix.m22() >= 0.0F ) {
789 if ( mat.m11() == 1.0F && mat.m22() == 1.0F )
790 return *this; // identity matrix
791
792 h = qRound( mat.m22()*hs );
793 w = qRound( mat.m11()*ws );
794 h = QABS( h );
795 w = QABS( w );
796 if ( !data->hasRealAlpha ) {
797 QPixmap pm( w, h, depth(), optimization() );
798 POINTL ptls[] = {
799 { 0, 0 }, { w, h },
800 { 0, 0 }, { ws, hs }
801 };
802 GpiBitBlt( pm.hps, hps, 4, ptls, ROP_SRCCOPY, BBO_IGNORE );
803 if ( data->mask ) {
804 QBitmap bm =
805 data->selfmask ? *((QBitmap*)(&pm)) :
806 data->mask->xForm( matrix );
807 pm.setMask( bm );
808 }
809 return pm;
810 }
811 } else {
812 // rotation or shearing
813 QPointArray a( QRect(0,0,ws+1,hs+1) );
814 a = mat.map( a );
815 QRect r = a.boundingRect().normalize();
816 w = r.width()-1;
817 h = r.height()-1;
818 }
819
820 mat = trueMatrix( mat, ws, hs ); // true matrix
821
822 bool invertible;
823 mat = mat.invert( &invertible ); // invert matrix
824
825 if ( h == 0 || w == 0 || !invertible ) { // error, return null pixmap
826 QPixmap pm;
827 pm.data->bitmap = data->bitmap;
828 return pm;
829 }
830
831 if ( data->hasRealAlpha ) {
832 bpp = 32;
833 } else {
834 bpp = depth();
835 if ( bpp > 1 && bpp < 8 )
836 bpp = 8;
837 }
838
839 sbpl = ((ws * bpp + 31) / 32) * 4;
840 sptr = new uchar[ hs * sbpl ];
841 int ncols;
842 if ( bpp <= 8 ) {
843 ncols = 1 << bpp;
844 } else {
845 ncols = 0;
846 }
847
848#if defined QT_CHECK_RANGE
849 if ( bpp == 32 && trueColorDepth() != 32 )
850 qWarning( "QPixmap::xForm(): video driver doesn't seem to "
851 "support the 32-bpp color depth!" );
852 // don't return since we still hope the driver can at least convert
853 // from/to 32-bpp bitmaps
854#endif
855
856 // allocate header + ncols palette entries
857 int bmi_data_len = sizeof(BITMAPINFOHEADER2) + 4 * ncols;
858 char *bmi_data = new char[ bmi_data_len ];
859 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
860 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
861 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
862 bmh.cx = ws;
863 bmh.cy = hs;
864 bmh.cPlanes = 1;
865 bmh.cBitCount = bpp;
866 bmh.cclrUsed = ncols;
867 if ( depth1 ) {
868 // always use the black/white palette for monochrome pixmaps;
869 // otherwise GPI can swap 0s and 1s when creating a bitmap.
870 PULONG pal = (PULONG) (bmi_data + sizeof(BITMAPINFOHEADER2));
871 pal[0] = 0;
872 pal[1] = 0x00FFFFFF;
873 }
874
875 GpiQueryBitmapBits( hps, 0, hs, (PBYTE) sptr, (PBITMAPINFO2) bmi_data );
876
877 if ( data->hasRealAlpha && data->realAlphaBits ) {
878 // incorporate the alpha channel to image data
879 // (see comments in convertFromImage() for details)
880 int bpx = bpp / 8;
881 int inc = sbpl - bpx * ws;
882 uchar *src = data->realAlphaBits;
883 uchar *dst = sptr + 3; // move to the alpha byte
884 for ( int y = 0; y < hs; ++ y ) {
885 for ( int x = 0; x < ws; ++ x ) {
886 *dst = *(src++);
887 dst += bpx;
888 }
889 dst += inc;
890 }
891 }
892
893 dbpl = ((w * bpp + 31) / 32) * 4;
894 dbytes = dbpl * h;
895
896 dptr = new uchar[ dbytes ]; // create buffer for bits
897 Q_CHECK_PTR( dptr );
898 if ( depth1 )
899 memset( dptr, 0x00, dbytes );
900 else if ( bpp == 8 )
901 memset( dptr, white.pixel(), dbytes );
902 else if ( data->hasRealAlpha )
903 memset( dptr, 0x00, dbytes );
904 else
905 memset( dptr, 0xff, dbytes );
906
907 int xbpl, p_inc;
908 if ( depth1 ) {
909 xbpl = (w + 7) / 8;
910 p_inc = dbpl - xbpl;
911 } else {
912 xbpl = (w * bpp) / 8;
913 p_inc = dbpl - xbpl;
914 }
915
916 // OS/2 stores first image row at the bottom of the pixmap data,
917 // so do xForm starting from the bottom scanline to the top one
918 if ( !qt_xForm_helper( mat, 0, QT_XFORM_TYPE_MSBFIRST, bpp,
919 dptr + dbytes - dbpl, xbpl, p_inc - dbpl * 2, h,
920 sptr + (hs*sbpl) - sbpl, -sbpl, ws, hs ) ) {
921#if defined(QT_CHECK_RANGE)
922 qWarning( "QPixmap::xForm: display not supported (bpp=%d)",bpp);
923#endif
924 QPixmap pm;
925 delete [] sptr;
926 delete [] bmi_data;
927 delete [] dptr;
928 return pm;
929 }
930
931 delete [] sptr;
932
933 QPixmap pm( w, h, depth(), data->bitmap, optimization() );
934 pm.data->uninit = FALSE;
935 bmh.cx = w;
936 bmh.cy = h;
937 GpiSetBitmapBits( pm.hps, 0, h, (PBYTE) dptr, (PBITMAPINFO2) bmi_data );
938
939 if ( data->mask ) {
940 QBitmap bm = data->selfmask ? *((QBitmap*)(&pm)) :
941 data->mask->xForm(matrix);
942 pm.setMask( bm );
943 }
944
945 if ( data->hasRealAlpha ) {
946 pm.data->hasRealAlpha = TRUE;
947 if ( pm.depth() != 32 ) {
948 // we are not able to store the alpha channel in the bitmap bits,
949 // store it separately
950 pm.data->realAlphaBits = new uchar[ w * h ];
951 int bpx = bpp / 8;
952 uchar *dst = pm.data->realAlphaBits;
953 uchar *src = dptr + 3; // move to the alpha byte
954 for ( int y = 0; y < h; ++ y ) {
955 for ( int x = 0; x < w; ++ x ) {
956 *(dst++) = *src;
957 src += bpx;
958 }
959 src += p_inc;
960 }
961 }
962 }
963
964 delete [] bmi_data;
965 delete [] dptr;
966
967 return pm;
968}
969#endif // QT_NO_PIXMAP_TRANSFORMATION
970
971/*!
972 \fn HBITMAP QPixmap::hbm() const
973 \internal
974*/
975
976bool QPixmap::hasAlpha() const
977{
978 return data->hasRealAlpha || data->mask;
979}
980
981bool QPixmap::hasAlphaChannel() const
982{
983 return data->hasRealAlpha;
984}
985
986/**
987 * \internal
988 * If \a prepare is TRUE, prepares for painting a pixmap with mask: precomposes
989 * and selects a masked bitmap (with transparent pixels made black) into this
990 * pixmap's hps. If \a prepare is FALSE, it does the cleanup. If \a force is
991 * TRUE on cleanup, the masked bitmap is destroyed regardless of the
992 * optimization type.
993 *
994 * Currently used in ::bitBlt() and in QPixmap::createIcon().
995 */
996void QPixmap::prepareForMasking( bool prepare, bool force /* = FALSE */ )
997{
998 if ( !data->mask || data->selfmask )
999 return;
1000 if ( prepare ) {
1001 if ( !data->maskedHbm ) {
1002 GpiSetBitmap( hps, 0 );
1003 BITMAPINFOHEADER2 bmh;
1004 memset( &bmh, 0, sizeof(BITMAPINFOHEADER2) );
1005 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
1006 bmh.cx = data->w;
1007 bmh.cy = data->h;
1008 bmh.cPlanes = 1;
1009 bmh.cBitCount = data->d;
1010 data->maskedHbm = GpiCreateBitmap( hps, &bmh, 0, NULL, NULL );
1011 GpiSetBitmap( hps, data->maskedHbm );
1012 POINTL ptls[] = {
1013 // dst is inclusive
1014 { 0, 0 }, { data->w - 1, data->h - 1 },
1015 { 0, 0 }, { data->w, data->h },
1016 };
1017 GpiWCBitBlt( hps, data->hbm, 4, ptls, ROP_SRCCOPY, BBO_IGNORE );
1018 // dst is exclusive
1019 ptls[1].x++;
1020 ptls[1].y++;
1021 // make transparent pixels black
1022 const ULONG AllImageAttrs =
1023 IBB_COLOR | IBB_BACK_COLOR |
1024 IBB_MIX_MODE | IBB_BACK_MIX_MODE;
1025 IMAGEBUNDLE oldIb;
1026 GpiQueryAttrs( hps, PRIM_IMAGE, AllImageAttrs, (PBUNDLE) &oldIb );
1027 IMAGEBUNDLE newIb = {
1028 CLR_TRUE, CLR_FALSE, FM_OVERPAINT, BM_OVERPAINT
1029 };
1030 GpiSetAttrs( hps, PRIM_IMAGE, AllImageAttrs, 0, (PBUNDLE) &newIb );
1031 GpiBitBlt( hps, data->mask->hps, 3, ptls, ROP_SRCAND, BBO_IGNORE );
1032 GpiSetAttrs( hps, PRIM_IMAGE, AllImageAttrs, 0, (PBUNDLE) &oldIb );
1033 } else {
1034 GpiSetBitmap( hps, data->maskedHbm );
1035 }
1036 } else {
1037 GpiSetBitmap( hps, data->hbm );
1038 // delete the precomposed masked pixmap when memory optimization
1039 // is in force (or force is TRUE)
1040 if ( data->maskedHbm && (force || (data->optim != NormalOptim &&
1041 data->optim != BestOptim)) ) {
1042 GpiDeleteBitmap( data->maskedHbm );
1043 data->maskedHbm = 0;
1044 }
1045 }
1046}
1047
1048HPOINTER QPixmap::createIcon( bool pointer, int hotX, int hotY, bool mini )
1049{
1050 HPOINTER icon = NULLHANDLE;
1051
1052 if ( !isNull() ) {
1053 int w = WinQuerySysValue( HWND_DESKTOP, pointer ? SV_CXPOINTER : SV_CXICON );
1054 int h = WinQuerySysValue( HWND_DESKTOP, pointer ? SV_CYPOINTER : SV_CYICON );
1055 if ( mini ) {
1056 w /= 2;
1057 h /= 2;
1058 }
1059
1060 QPixmap pm = *this;
1061 if ( data->w != w || data->h != h ) {
1062#if !defined(QT_NO_IMAGE_SMOOTHSCALE)
1063 // do smooth resize until icon is two or more times bigger
1064 // than the pixmap
1065 if ( data->w * 2 > w || data->h * 2 > h ) {
1066 QImage i = convertToImage();
1067 pm = QPixmap( i.smoothScale( w, h ) );
1068 } else
1069#endif
1070 {
1071 pm = QPixmap( w, h );
1072 POINTL ptls[] = {
1073 { 0, 0 }, { w, h },
1074 { 0, 0 }, { data->w, data->h },
1075 };
1076 GpiBitBlt( pm.hps, hps, 4, ptls, ROP_SRCCOPY, BBO_IGNORE );
1077 }
1078 }
1079
1080 QBitmap msk( w, h * 2, TRUE );
1081 if ( pm.data->mask ) {
1082 // create AND mask (XOR mask is left zeroed -- it's ok)
1083 POINTL ptls[] = {
1084 { 0, h }, { w, h * 2 },
1085 { 0, 0 }, { w, h },
1086 };
1087 GpiBitBlt( msk.hps, pm.data->mask->hps, 4, ptls, ROP_NOTSRCCOPY, BBO_IGNORE );
1088 pm.prepareForMasking( TRUE );
1089 }
1090
1091 // unselect bitmap handles from hps
1092 GpiSetBitmap( pm.hps, 0 );
1093 GpiSetBitmap( msk.hps, 0 );
1094
1095 POINTERINFO info;
1096 info.fPointer = pointer;
1097 info.xHotspot = hotX;
1098 info.yHotspot = hotY;
1099 info.hbmPointer = msk.data->hbm;
1100 info.hbmColor = pm.data->mask ? pm.data->maskedHbm : pm.data->hbm;
1101 info.hbmMiniPointer = 0;
1102 info.hbmMiniColor = 0;
1103 icon = WinCreatePointerIndirect( HWND_DESKTOP, &info );
1104
1105 if ( pm.mask() )
1106 pm.prepareForMasking( FALSE );
1107
1108 GpiSetBitmap( msk.hps, msk.data->hbm );
1109 GpiSetBitmap( pm.hps, pm.data->hbm );
1110 }
1111
1112 return icon;
1113}
1114
1115void QPixmap::attachHandle( HBITMAP hbm )
1116{
1117 if ( paintingActive() )
1118 return;
1119
1120 BITMAPINFOHEADER bmh;
1121 if (!GpiQueryBitmapParameters( hbm, &bmh ))
1122 return;
1123
1124 if ( !data->uninit && !isNull() ) { // has existing pixmap
1125 deref();
1126 init( 0, 0, 0, FALSE, defOptim );
1127 }
1128
1129 data->uninit = FALSE;
1130 data->w = bmh.cx;
1131 data->h = bmh.cy;
1132 data->d = bmh.cPlanes * bmh.cBitCount;
1133
1134 hps = alloc_mem_ps( bmh.cx, bmh.cy );
1135 data->hbm = hbm;
1136
1137 GpiSetBitmap( hps, data->hbm );
1138}
1139
1140HBITMAP QPixmap::detachHandle()
1141{
1142 if ( paintingActive() )
1143 return 0;
1144
1145 HBITMAP hbm = data->hbm;
1146
1147 // do what deref() will not do after data->hbm is set to 0
1148 if ( hps )
1149 GpiSetBitmap( hps, 0 );
1150
1151 data->hbm = 0;
1152 deref();
1153
1154 return hbm;
1155}
1156
1157void QPixmap::unfoldAlphaChannel()
1158{
1159 // do nothing if there is no alpha channel or if it is already unfolded
1160 // (i.e. stored in a separate array)
1161 if ( !data->hasRealAlpha || data->realAlphaBits )
1162 return;
1163
1164 Q_ASSERT( data->d == 32 );
1165 if ( !data->d == 32 )
1166 return;
1167
1168 data->realAlphaBits = new uchar[ data->w * data->h ];
1169
1170 // no space for palette, since the depth is 32-bpp
1171 BITMAPINFOHEADER2 bmh;
1172 memset( &bmh, 0, sizeof(BITMAPINFOHEADER2) );
1173 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
1174 bmh.cx = data->w;
1175 bmh.cy = data->h;
1176 bmh.cPlanes = 1;
1177 bmh.cBitCount = data->d;
1178
1179 int bpl = ((data->d * data->w + 31) / 32) * 4;
1180 uchar *bits = new uchar [bpl * data->h];
1181
1182 GpiQueryBitmapBits( hps, 0, data->h, (PBYTE) bits, (PBITMAPINFO2) &bmh );
1183
1184 int bpx = data->d / 8;
1185 int inc = bpl - bpx * data->w;
1186 uchar *src = bits + 3; // move to the alpha byte
1187 uchar *dst = data->realAlphaBits;
1188 for ( int y = 0; y < data->h; ++ y ) {
1189 for ( int x = 0; x < data->w; ++ x ) {
1190 *(dst++) = *src;
1191 src += bpx;
1192 }
1193 src += inc;
1194 }
1195
1196 delete[] bits;
1197}
1198
1199/**
1200 * \internal
1201 * Converts the pixmap (actually, the pixmap's mask, if any) to the alpha
1202 * channel. Implies #unfoldAlphaChannel().
1203 */
1204void QPixmap::convertToAlpha()
1205{
1206 if ( isNull() || data->hasRealAlpha )
1207 return;
1208
1209 if ( data->mask ) {
1210 // allocate header + 2 palette entries
1211 char *bmi_data = new char[ sizeof(BITMAPINFOHEADER2) + 8 ];
1212 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
1213 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
1214 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
1215 bmh.cx = data->w;
1216 bmh.cy = data->h;
1217 bmh.cPlanes = 1;
1218 bmh.cBitCount = 1;
1219 bmh.cclrUsed = 2;
1220
1221 int bpl = ((data->w + 31) / 32) * 4;
1222 uchar *bits = new uchar [bpl * data->h];
1223
1224 GpiQueryBitmapBits( data->mask->hps, 0, data->h, (PBYTE) bits,
1225 (PBITMAPINFO2) bmi_data );
1226
1227 data->realAlphaBits = new uchar[ data->w * data->h ];
1228
1229 int inc = bpl - data->w / 8;
1230 uchar *src = bits;
1231 uchar *dst = data->realAlphaBits;
1232 uchar m = 0x80;
1233 for ( int y = 0; y < data->h; ++ y ) {
1234 for ( int x = 0; x < data->w; ++ x ) {
1235 *(dst ++) = (*src) & m ? 0xFF : 0x00;
1236 m >>= 1;
1237 if ( !m ) {
1238 m = 0x80;
1239 ++ src;
1240 }
1241 }
1242 src += inc;
1243 }
1244
1245 data->hasRealAlpha = TRUE;
1246
1247 delete[] bits;
1248 delete[] bmi_data;
1249 } else {
1250 data->realAlphaBits = new uchar[ data->w * data->h ];
1251 memset( data->realAlphaBits, 0xFF, data->w * data->h );
1252 data->hasRealAlpha = TRUE;
1253 }
1254}
1255
1256/**
1257 * \internal
1258 * This depth is used when querying and setting bitmap bits for pixmaps
1259 * with alpha channel, either 24 or 32 (depending on the video driver caps).
1260 * \note This depth is not used to create bitmaps (#defaultDepth() is always
1261 * in charge for that purpose).
1262 */
1263//static
1264int QPixmap::trueColorDepth()
1265{
1266 static int tcd = 0;
1267 if ( tcd == 0 ) {
1268 HDC display_dc = GpiQueryDevice( qt_display_ps() );
1269 LONG formatCnt = 0;
1270 DevQueryCaps( display_dc, CAPS_BITMAP_FORMATS, 1, &formatCnt );
1271 LONG *formats = new LONG[ formatCnt * 2 ];
1272 GpiQueryDeviceBitmapFormats( qt_display_ps(), formatCnt * 2, formats );
1273 for( int i = 0; i < formatCnt * 2; i += 2 ) {
1274 if ( formats[ i ] == 1 && formats[ i + 1 ] == 32 ) {
1275 tcd = 32;
1276 break;
1277 }
1278 }
1279 delete[] formats;
1280 // if the 32-bpp format is not supported, we assume the 24-bpp
1281 // format that must be supported by all video drivers
1282 if ( tcd == 0 )
1283 tcd = 24;
1284 }
1285 return tcd;
1286}
1287
1288/*!
1289 \internal
1290
1291 Creates an OS/2 icon or pointer from two given pixmaps.
1292
1293 \param pointer true to create a pointer, false to create an icon
1294 \param hotX X coordinate of the action point within the pointer/icon
1295 \param hotY Y coordinate of the action point within the pointer/icon
1296 \param normal pixmap for a normal-sized pointer/icon
1297 \param mini pixmap for a mini-sized pointer/icon
1298
1299 \return PM handle of the created pointer or 0 in case of any error
1300
1301 \note Due to a bug in WinCreatePointerIndirect, you can specify either
1302 \a normal pixmap or \a mini pixmap, but not both (if both are specified,
1303 \a normal will be used). PM will use scaling to draw a pointer of the
1304 other size when necessary. This bug may be fixed later.
1305
1306 \warning This function is not portable.
1307*/
1308// static
1309HPOINTER QPixmap::createIcon( bool pointer, int hotX, int hotY,
1310 const QPixmap *normal, const QPixmap *mini )
1311{
1312 // Due to a bug in WinCreatePointerIndirect (it always ignores
1313 // hbmMiniPointer and hbmMiniColor fields), we can specify either a normal
1314 // icon, but not both. This methods still accepts pixmaps for both icon
1315 // sizes (assuming that we will find a workaround one day) but uses only
1316 // one of them.
1317
1318 if ( normal && !normal->isNull() ) {
1319#ifdef QT_CHECK_RANGE
1320 if ( mini && !mini->isNull() )
1321 qWarning( "QPixmap::createIcon(): due to a bug in WinCreatePointerIndirect "
1322 "either a normal or a mini pixmap should be specified, "
1323 "but not both. Will use a normal pixmap." );
1324#endif
1325 return const_cast <QPixmap *> (normal)->createIcon( pointer, hotX, hotY, false );
1326 }
1327
1328 if ( mini && !mini->isNull() )
1329 return const_cast <QPixmap *> (mini)->createIcon( pointer, hotX, hotY, true );
1330
1331 return 0;
1332}
1333
1334Q_EXPORT void copyBlt( QPixmap *dst, int dx, int dy,
1335 const QPixmap *src, int sx, int sy, int sw, int sh )
1336{
1337 if ( ! dst || ! src || sw == 0 || sh == 0 || dst->depth() != src->depth() ) {
1338#ifdef QT_CHECK_NULL
1339 Q_ASSERT( dst != 0 );
1340 Q_ASSERT( src != 0 );
1341#endif
1342 return;
1343 }
1344
1345 if ( sw < 0 )
1346 sw = src->width() - sx;
1347 if ( sh < 0 )
1348 sh = src->height() - sy;
1349
1350 // ensure coordinates are within borders, clip if necessary
1351 if ( sx < 0 || sy < 0 || sx + sw > src->width() || sy + sh > src->height() ||
1352 dx < 0 || dy < 0 || dx + sw > dst->width() || dy + sh > dst->height() )
1353 {
1354 int tx = dx - sx;
1355 int ty = dy - sy;
1356 QRect dr( 0, 0, dst->width(), dst->height() ); // dst rect
1357 QRect sr( tx, ty, src->width(), src->height() ); // src rect in dst coords
1358 QRect bltr( dx, dy, sw, sh ); // blit rect in dst coords
1359 bltr &= (dr & sr);
1360 if (bltr.isEmpty())
1361 return;
1362 dx = bltr.x();
1363 dy = bltr.y();
1364 sx = dx - tx;
1365 sy = dy - ty;
1366 sw = bltr.width();
1367 sh = bltr.height();
1368 }
1369
1370 dst->detach();
1371
1372 // copy mask data
1373 if ( src->data->mask ) {
1374 if ( !dst->data->mask ) {
1375 dst->data->mask = new QBitmap( dst->width(), dst->height() );
1376 // new masks are fully opaque by default
1377 dst->data->mask->fill( Qt::color1 );
1378 } else if ( dst->data->maskedHbm ) {
1379 // reset the precomposed masked pixmap
1380 dst->prepareForMasking( FALSE, TRUE );
1381 }
1382
1383 bitBlt( dst->data->mask, dx, dy,
1384 src->data->mask, sx, sy, sw, sh, Qt::CopyROP, TRUE );
1385 }
1386
1387 // copy alpha bits
1388 if ( src->data->hasRealAlpha ||
1389 (src->data->mask && dst->data->hasRealAlpha) ) {
1390 if ( src->data->hasRealAlpha )
1391 const_cast <QPixmap *> (src)->unfoldAlphaChannel();
1392 else
1393 const_cast <QPixmap *> (src)->convertToAlpha();
1394 if ( dst->data->hasRealAlpha )
1395 dst->unfoldAlphaChannel();
1396 else
1397 dst->convertToAlpha();
1398 uchar *srca = src->data->realAlphaBits + src->width() * sy + sx;
1399 uchar *dsta = dst->data->realAlphaBits + dst->width() * dy + dx;
1400 for ( int y = 0; y < sh; ++ y ) {
1401 memcpy( dsta, srca, sw );
1402 srca += src->width();
1403 dsta += dst->width();
1404 }
1405 }
1406
1407 // copy pixel data
1408 bitBlt( dst, dx, dy, src, sx, sy, sw, sh, Qt::CopyROP, TRUE );
1409}
Note: See TracBrowser for help on using the repository browser.