source: trunk/src/kernel/qpixmap_pm.cpp

Last change on this file was 124, checked in by dmik, 19 years ago

Kernel: Removed the annoying "QPixmap::xForm(): video driver doesn't seem to support the 32-bpp color depth!" warning (SNAP drivers don't report 32-bpp as the supported depth when a lower color depth is specified in Screen settings, but seem to work well when converting to/from 32-bpp).

  • Property svn:keywords set to Id
File size: 45.7 KB
RevLine 
[8]1/****************************************************************************
2** $Id: qpixmap_pm.cpp 124 2006-09-12 21:25:42Z 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;
[59]108 const int dd = defaultDepth();
[8]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;
[59]147 if ( data->d == 1 ) // monocrome bitmap
148 bmh.cBitCount = 1;
149 else // compatible bitmap
[8]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
[56]171 if ( hps )
172 GpiSetBitmap( hps, 0 );
[59]173 if ( data->hasRealAlpha && data->realAlphaBits ) {
174 delete[] data->realAlphaBits;
175 data->realAlphaBits = 0;
176 }
[8]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
[59]210 int bitsbpl = (w + 7) / 8; // original # bytes per line
[8]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 ) {
[59]277 LONG formats[ 2 ];
[8]278 GpiQueryDeviceBitmapFormats( qt_display_ps(), 2, formats );
[59]279 dd = formats[ 0 ] * formats[ 1 ];
[8]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();
[59]371 const QBitmap *m = data->hasRealAlpha ? 0 : mask();
[8]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;
[124]381 // Note: even if trueColorDepth() != 32 here, we don't return hoping
382 // that the video driver can at least convert from/to 32-bpp bitmaps
383 // (which is the case for SNAP that doesn't report 32-bpp as the
384 // supported depth when a lower color depth is specified in Screen
385 // settings, but works well when converting).
[8]386 }
387
388 QImage image( w, h, d, ncols, QImage::BigEndian );
389
390 // allocate header + ncols palette entries
391 char *bmi_data = new char[ sizeof(BITMAPINFOHEADER2) + 4 * ncols ];
392 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
393 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
394 PULONG pal = (PULONG) (bmi_data + sizeof(BITMAPINFOHEADER2));
395 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
396 bmh.cx = w;
397 bmh.cy = h;
398 bmh.cPlanes = 1;
399 bmh.cBitCount = d;
400 bmh.cclrUsed = ncols;
401 GpiQueryBitmapBits( hps, 0, h, (PBYTE) image.bits(), (PBITMAPINFO2) bmi_data );
402
[59]403 if ( data->hasRealAlpha ) {
404 if ( data->realAlphaBits ) {
405 // incorporate the alpha channel to image data
406 // (see comments in convertFromImage() for details)
407 uchar *src = data->realAlphaBits;
408 int y = 0;
409 while ( y < image.height() ) {
410 uchar *dst = image.scanLine( y++ );
411 uchar *end = dst + image.bytesPerLine();
412 dst += 3;
413 while ( dst < end ) {
414 *dst = *(src++);
415 dst += 4;
416 }
417 }
418 }
419 image.setAlphaBuffer( TRUE );
420 }
421
[8]422 // flip the image top to bottom
423 {
424 int bpl = image.bytesPerLine();
425 uchar *line = new uchar[bpl];
426 uchar *top = image.scanLine( 0 );
427 uchar *bottom = image.scanLine( h - 1 );
428 while( top < bottom ) {
429 memcpy( line, top, bpl );
430 memcpy( top, bottom, bpl );
431 memcpy( bottom, line, bpl );
432 top += bpl;
433 bottom -= bpl;
434 }
435 delete [] line;
436 }
437
438 if ( d == 1 ) {
439 // use a white/black palette for monochrome pixmaps (istead of
440 // black/white supplied by GPI) to make the result of possible
441 // converson to a higher depth compatible with other platforms.
442 if ( m ) {
443 image.setAlphaBuffer( TRUE );
444 image.setColor( 0, qRgba( 255, 255, 255, 0 ) );
445 image.setColor( 1, qRgba( 0, 0, 0, 255 ) );
446 } else {
447 image.setColor( 0, qRgb( 255, 255, 255 ) );
448 image.setColor( 1, qRgb( 0, 0, 0 ) );
449 }
450 } else {
451 for ( int i=0; i<ncols; i++ ) { // copy color table
452 PRGB2 r = (PRGB2) &pal[i];
453 if ( m )
454 image.setColor( i, qRgba(r->bRed,
455 r->bGreen,
456 r->bBlue,255) );
457 else
458 image.setColor( i, qRgb(r->bRed,
459 r->bGreen,
460 r->bBlue) );
461 }
462 }
463
464 delete [] bmi_data;
465
466 if ( d != 1 && m ) {
467 image.setAlphaBuffer(TRUE);
468 QImage msk = m->convertToImage();
469
470 switch ( d ) {
471 case 8: {
472 int used[256];
473 memset( used, 0, sizeof(int)*256 );
474 uchar* p = image.bits();
475 int l = image.numBytes();
476 while (l--) {
477 used[*p++]++;
478 }
479 int trans=0;
480 int bestn=INT_MAX;
481 for ( int i=0; i<256; i++ ) {
482 if ( used[i] < bestn ) {
483 bestn = used[i];
484 trans = i;
485 if ( !bestn )
486 break;
487 }
488 }
489 image.setColor( trans, image.color(trans)&0x00ffffff );
490 for ( int y=0; y<image.height(); y++ ) {
491 uchar* mb = msk.scanLine(y);
492 uchar* ib = image.scanLine(y);
493 uchar bit = 0x80;
494 int i=image.width();
495 while (i--) {
496 if ( !(*mb & bit) )
497 *ib = trans;
498 bit /= 2; if ( !bit ) mb++,bit = 0x80; // ROL
499 ib++;
500 }
501 }
502 } break;
503 case 32: {
504 for ( int y=0; y<image.height(); y++ ) {
505 uchar* mb = msk.scanLine(y);
506 QRgb* ib = (QRgb*)image.scanLine(y);
507 uchar bit = 0x80;
508 int i=image.width();
509 while (i--) {
510 if ( *mb & bit )
511 *ib |= 0xff000000;
512 else
513 *ib &= 0x00ffffff;
514 bit /= 2; if ( !bit ) mb++,bit = 0x80; // ROL
515 ib++;
516 }
517 }
518 } break;
519 }
520 }
521
522 return image;
523}
524
525bool QPixmap::convertFromImage( const QImage &img, int conversion_flags )
526{
527 if ( img.isNull() ) {
528#if defined(QT_CHECK_NULL)
529 qWarning( "QPixmap::convertFromImage: Cannot convert a null image" );
530#endif
531 return FALSE;
532 }
533
534 QImage image = img;
535 int d = image.depth();
536 int dd = defaultDepth();
537 bool force_mono = (dd == 1 || isQBitmap() ||
538 (conversion_flags & ColorMode_Mask)==MonoOnly );
539
540 if ( force_mono ) { // must be monochrome
541 if ( d != 1 ) { // dither
542 image = image.convertDepth( 1, conversion_flags );
543 d = 1;
544 }
545 } else { // can be both
546 bool conv8 = FALSE;
547 if ( d > 8 && dd <= 8 ) { // convert to 8 bit
548 if ( (conversion_flags & DitherMode_Mask) == AutoDither )
549 conversion_flags = (conversion_flags & ~DitherMode_Mask)
550 | PreferDither;
551 conv8 = TRUE;
552 } else if ( (conversion_flags & ColorMode_Mask) == ColorOnly ) {
553 conv8 = d == 1; // native depth wanted
554 } else if ( d == 1 ) {
555 if ( image.numColors() == 2 ) {
[59]556 // Note: 1-bpp images other than true black-white cannot be
557 // correctly stored as GPI bitmaps (it doesn't store the palette
558 // for them), so the code below ensures they will be converted
559 // to 8-bpp images first. However, black-white images with alpha
560 // channel will be also converted, though they can be stored
561 // as bitmaps. The correct code to prevent setting conv8 to TRUE
562 // for black-white bitmaps both with and w/o alpha should be:
563 // QRgb c0 = image.color(0) | ~RGB_MASK;
564 // QRgb c1 = image.color(1) | ~RGB_MASK;
565 // but it is left as is solely for compatibility with Qt/Win32
566 // (otherwise we would get visually different pixmaps).
[8]567 QRgb c0 = image.color(0); // Auto: convert to best
568 QRgb c1 = image.color(1);
569 conv8 = QMIN(c0,c1) != qRgb(0,0,0) || QMAX(c0,c1) != qRgb(255,255,255);
570 } else {
571 // eg. 1-color monochrome images (they do exist).
572 conv8 = TRUE;
573 }
574 }
575 if ( conv8 ) {
576 image = image.convertDepth( 8, conversion_flags );
577 d = 8;
578 }
579 }
580
581 if ( d == 1 ) { // 1 bit pixmap (bitmap)
582 image = image.convertBitOrder( QImage::BigEndian );
583 }
584
585 bool hasRealAlpha = FALSE;
[59]586 if ( img.hasAlphaBuffer() ) {
[8]587 if (image.depth() == 8) {
588 const QRgb * const rgb = img.colorTable();
589 for (int i = 0, count = img.numColors(); i < count; ++i) {
590 const int alpha = qAlpha(rgb[i]);
591 if (alpha != 0 && alpha != 0xff) {
592 hasRealAlpha = true;
593 break;
594 }
595 }
596 if (hasRealAlpha) {
[59]597 image = image.convertDepth(32, conversion_flags);
598 d = image.depth();
[8]599 }
600 } else if (image.depth() == 32) {
601 int i = 0;
602 while ( i<image.height() && !hasRealAlpha ) {
603 uchar *p = image.scanLine(i);
604 uchar *end = p + image.bytesPerLine();
605 p += 3;
606 while ( p < end ) {
607 if ( *p!=0 && *p!=0xff ) {
608 hasRealAlpha = TRUE;
609 break;
610 }
611 p += 4;
612 }
613 ++i;
614 }
615 }
616 }
617
618 int w = image.width();
619 int h = image.height();
620
[59]621 if ( width() == w && height() == h &&
622 ( (d == 1 && depth() == 1) ||
623 (d != 1 && depth() != 1 && hasRealAlpha == hasAlphaChannel()) ) ) {
624 // same size etc., use the existing pixmap
625 detach();
626 if ( data->mask ) { // get rid of the mask
627 delete data->mask;
628 data->mask = 0;
629 if ( data->maskedHbm )
630 prepareForMasking( FALSE, TRUE );
631 }
[8]632 } else {
633 // different size or depth, make a new pixmap
[59]634 QPixmap pm( w, h, d == 1 ? 1 : -1, data->bitmap, data->optim );
[8]635 *this = pm;
636 }
637
[124]638 // Note: even if trueColorDepth() != 32 here, we don't return hoping
639 // that the video driver can at least convert from/to 32-bpp bitmaps
640 // (which is the case for SNAP that doesn't report 32-bpp as the
641 // supported depth when a lower color depth is specified in Screen
642 // settings, but works well when converting).
[59]643
[8]644 int ncols = image.numColors();
645
646 // allocate header + ncols palette entries
647 char *bmi_data = new char[ sizeof(BITMAPINFOHEADER2) + 4 * ncols ];
648 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
649 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
650 PULONG pal = (PULONG) (bmi_data + sizeof(BITMAPINFOHEADER2));
651 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
652 bmh.cx = w;
653 bmh.cy = h;
654 bmh.cPlanes = 1;
655 bmh.cBitCount = d;
656 bmh.cclrUsed = ncols;
657 bool doAlloc = ( QApplication::colorSpec() == QApplication::CustomColor
658 && QColor::hPal() );
659
660 if ( d == 1 ) {
661 // always use the black/white palette for monochrome pixmaps;
662 // otherwise GPI can swap 0s and 1s when creating a bitmap.
663 pal [0] = 0;
664 pal [1] = 0x00FFFFFF;
665 } else {
666 for ( int i=0; i<ncols; i++ ) { // copy color table
667 PRGB2 r = (PRGB2) &pal[i];
668 QRgb c = image.color(i);
669 r->bBlue = qBlue( c );
670 r->bGreen = qGreen( c );
[59]671 r->bRed = qRed( c );
[8]672 r->fcOptions = 0;
673 if ( doAlloc ) {
674 QColor cl( c );
675 cl.alloc();
676 }
677 }
678 }
679
[59]680 data->hasRealAlpha = hasRealAlpha;
[8]681
[59]682 // If we have real alpha bits and the default video driver depth is 32-bpp,
683 // we store the alpha channel in the unused high byte of the 32-bit pixel
684 // value to save memory and slightly optimize the performance (QImage already
685 // contains the alpha channel there, so nothing has to be done when setting
686 // bitmap bits). Otherwise we create a separate array to store the alpha
687 // channel from QImage.
688
689 if ( hasRealAlpha && depth() != 32 ) {
690 if ( data->realAlphaBits == 0 ) {
691 // alpha bits buffer doesn't exist yet, create it
692 data->realAlphaBits = new uchar [w * h];
[8]693 }
[59]694 // store alpha bits flipping scan lines top to bottom
695 uchar *dst = data->realAlphaBits + w * (h - 1);
696 int y = 0;
697 while ( y < image.height() ) {
698 uchar *src = image.scanLine( y++ );
699 uchar *end = src + image.bytesPerLine();
700 src += 3;
701 while ( src < end ) {
702 *(dst++) = *src;
703 src += 4;
704 }
705 // go to the previous row
706 dst -= w * 2;
707 }
708 }
709
710 // flip the image top to bottom
711 image.detach();
712 int bpl = image.bytesPerLine();
713 uchar *line = new uchar[bpl];
714 uchar *top = image.scanLine( 0 );
715 uchar *bottom = image.scanLine( h - 1 );
716 while( top < bottom ) {
717 memcpy( line, top, bpl );
718 memcpy( top, bottom, bpl );
719 memcpy( bottom, line, bpl );
720 top += bpl;
721 bottom -= bpl;
[8]722 }
[59]723 delete [] line;
724 GpiSetBitmapBits( hps, 0, h, (PBYTE) image.bits(), (PBITMAPINFO2) bmi_data );
[8]725
726 if ( img.hasAlphaBuffer() ) {
727 QBitmap m;
728 m = img.createAlphaMask( conversion_flags );
[59]729 data->mask = new QBitmap( m );
[8]730 }
731
732 delete [] bmi_data;
733 data->uninit = FALSE;
734
735 return TRUE;
736}
737
738
739QPixmap QPixmap::grabWindow( WId window, int x, int y, int w, int h )
740{
741 RECTL rcl;
742 WinQueryWindowRect( window, &rcl );
743 if ( w <= 0 || h <= 0 ) {
744 if ( w == 0 || h == 0 ) {
745 QPixmap nullPixmap;
746 return nullPixmap;
747 }
748 if ( w < 0 )
749 w = rcl.xRight;
750 if ( h < 0 )
751 h = rcl.yTop;
752 }
753 // flip y coordinate
754 y = rcl.yTop - (y + h);
755 QPixmap pm( w, h );
756 HPS hps = WinGetPS( window );
757 POINTL pnts[] = { {0, 0}, {w, h}, {x, y} };
758 GpiBitBlt( pm.hps, hps, 3, pnts, ROP_SRCCOPY, BBO_IGNORE );
759 WinReleasePS( hps );
760 return pm;
761}
762
763#ifndef QT_NO_PIXMAP_TRANSFORMATION
764QPixmap QPixmap::xForm( const QWMatrix &matrix ) const
765{
766 int w, h; // size of target pixmap
767 int ws, hs; // size of source pixmap
768 uchar *dptr; // data in target pixmap
769 int dbpl, dbytes; // bytes per line/bytes total
770 uchar *sptr; // data in original pixmap
771 int sbpl; // bytes per line in original
772 int bpp; // bits per pixel
773 bool depth1 = depth() == 1;
774
775 if ( isNull() ) // this is a null pixmap
776 return copy();
777
778 ws = width();
779 hs = height();
780
781 QWMatrix mat( matrix.m11(), matrix.m12(), matrix.m21(), matrix.m22(), 0., 0. );
782
783 if ( matrix.m12() == 0.0F && matrix.m21() == 0.0F &&
784 matrix.m11() >= 0.0F && matrix.m22() >= 0.0F ) {
785 if ( mat.m11() == 1.0F && mat.m22() == 1.0F )
786 return *this; // identity matrix
787
788 h = qRound( mat.m22()*hs );
789 w = qRound( mat.m11()*ws );
790 h = QABS( h );
791 w = QABS( w );
[59]792 if ( !data->hasRealAlpha ) {
[8]793 QPixmap pm( w, h, depth(), optimization() );
794 POINTL ptls[] = {
795 { 0, 0 }, { w, h },
796 { 0, 0 }, { ws, hs }
797 };
798 GpiBitBlt( pm.hps, hps, 4, ptls, ROP_SRCCOPY, BBO_IGNORE );
799 if ( data->mask ) {
800 QBitmap bm =
801 data->selfmask ? *((QBitmap*)(&pm)) :
802 data->mask->xForm( matrix );
803 pm.setMask( bm );
804 }
805 return pm;
806 }
807 } else {
808 // rotation or shearing
809 QPointArray a( QRect(0,0,ws+1,hs+1) );
810 a = mat.map( a );
811 QRect r = a.boundingRect().normalize();
812 w = r.width()-1;
813 h = r.height()-1;
814 }
815
816 mat = trueMatrix( mat, ws, hs ); // true matrix
817
818 bool invertible;
819 mat = mat.invert( &invertible ); // invert matrix
820
821 if ( h == 0 || w == 0 || !invertible ) { // error, return null pixmap
822 QPixmap pm;
823 pm.data->bitmap = data->bitmap;
824 return pm;
825 }
826
[59]827 if ( data->hasRealAlpha ) {
[8]828 bpp = 32;
829 } else {
830 bpp = depth();
831 if ( bpp > 1 && bpp < 8 )
832 bpp = 8;
833 }
834
[59]835 sbpl = ((ws * bpp + 31) / 32) * 4;
836 sptr = new uchar[ hs * sbpl ];
[8]837 int ncols;
838 if ( bpp <= 8 ) {
839 ncols = 1 << bpp;
840 } else {
841 ncols = 0;
842 }
843
[124]844 // Note: even if trueColorDepth() != 32 here, we don't return hoping
845 // that the video driver can at least convert from/to 32-bpp bitmaps
846 // (which is the case for SNAP that doesn't report 32-bpp as the
847 // supported depth when a lower color depth is specified in Screen
848 // settings, but works well when converting).
[59]849
[8]850 // allocate header + ncols palette entries
851 int bmi_data_len = sizeof(BITMAPINFOHEADER2) + 4 * ncols;
852 char *bmi_data = new char[ bmi_data_len ];
853 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
854 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
855 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
856 bmh.cx = ws;
857 bmh.cy = hs;
858 bmh.cPlanes = 1;
859 bmh.cBitCount = bpp;
860 bmh.cclrUsed = ncols;
861 if ( depth1 ) {
862 // always use the black/white palette for monochrome pixmaps;
863 // otherwise GPI can swap 0s and 1s when creating a bitmap.
864 PULONG pal = (PULONG) (bmi_data + sizeof(BITMAPINFOHEADER2));
865 pal[0] = 0;
866 pal[1] = 0x00FFFFFF;
867 }
868
[59]869 GpiQueryBitmapBits( hps, 0, hs, (PBYTE) sptr, (PBITMAPINFO2) bmi_data );
870
871 if ( data->hasRealAlpha && data->realAlphaBits ) {
872 // incorporate the alpha channel to image data
873 // (see comments in convertFromImage() for details)
874 int bpx = bpp / 8;
875 int inc = sbpl - bpx * ws;
876 uchar *src = data->realAlphaBits;
877 uchar *dst = sptr + 3; // move to the alpha byte
878 for ( int y = 0; y < hs; ++ y ) {
879 for ( int x = 0; x < ws; ++ x ) {
880 *dst = *(src++);
881 dst += bpx;
882 }
883 dst += inc;
884 }
[8]885 }
[59]886
887 dbpl = ((w * bpp + 31) / 32) * 4;
888 dbytes = dbpl * h;
[8]889
890 dptr = new uchar[ dbytes ]; // create buffer for bits
891 Q_CHECK_PTR( dptr );
892 if ( depth1 )
893 memset( dptr, 0x00, dbytes );
894 else if ( bpp == 8 )
895 memset( dptr, white.pixel(), dbytes );
[59]896 else if ( data->hasRealAlpha )
[8]897 memset( dptr, 0x00, dbytes );
898 else
899 memset( dptr, 0xff, dbytes );
900
901 int xbpl, p_inc;
902 if ( depth1 ) {
[59]903 xbpl = (w + 7) / 8;
[8]904 p_inc = dbpl - xbpl;
905 } else {
[59]906 xbpl = (w * bpp) / 8;
[8]907 p_inc = dbpl - xbpl;
908 }
909
910 // OS/2 stores first image row at the bottom of the pixmap data,
911 // so do xForm starting from the bottom scanline to the top one
912 if ( !qt_xForm_helper( mat, 0, QT_XFORM_TYPE_MSBFIRST, bpp,
913 dptr + dbytes - dbpl, xbpl, p_inc - dbpl * 2, h,
914 sptr + (hs*sbpl) - sbpl, -sbpl, ws, hs ) ) {
915#if defined(QT_CHECK_RANGE)
916 qWarning( "QPixmap::xForm: display not supported (bpp=%d)",bpp);
917#endif
918 QPixmap pm;
919 delete [] sptr;
920 delete [] bmi_data;
921 delete [] dptr;
922 return pm;
923 }
924
925 delete [] sptr;
926
927 QPixmap pm( w, h, depth(), data->bitmap, optimization() );
928 pm.data->uninit = FALSE;
929 bmh.cx = w;
930 bmh.cy = h;
[59]931 GpiSetBitmapBits( pm.hps, 0, h, (PBYTE) dptr, (PBITMAPINFO2) bmi_data );
932
[8]933 if ( data->mask ) {
934 QBitmap bm = data->selfmask ? *((QBitmap*)(&pm)) :
935 data->mask->xForm(matrix);
936 pm.setMask( bm );
937 }
[59]938
939 if ( data->hasRealAlpha ) {
940 pm.data->hasRealAlpha = TRUE;
941 if ( pm.depth() != 32 ) {
942 // we are not able to store the alpha channel in the bitmap bits,
943 // store it separately
944 pm.data->realAlphaBits = new uchar[ w * h ];
945 int bpx = bpp / 8;
946 uchar *dst = pm.data->realAlphaBits;
947 uchar *src = dptr + 3; // move to the alpha byte
948 for ( int y = 0; y < h; ++ y ) {
949 for ( int x = 0; x < w; ++ x ) {
950 *(dst++) = *src;
951 src += bpx;
952 }
953 src += p_inc;
954 }
955 }
956 }
957
958 delete [] bmi_data;
959 delete [] dptr;
960
[8]961 return pm;
962}
963#endif // QT_NO_PIXMAP_TRANSFORMATION
964
965/*!
966 \fn HBITMAP QPixmap::hbm() const
967 \internal
968*/
969
970bool QPixmap::hasAlpha() const
971{
[59]972 return data->hasRealAlpha || data->mask;
[8]973}
974
975bool QPixmap::hasAlphaChannel() const
976{
[59]977 return data->hasRealAlpha;
[8]978}
979
[59]980/**
981 * \internal
982 * If \a prepare is TRUE, prepares for painting a pixmap with mask: precomposes
983 * and selects a masked bitmap (with transparent pixels made black) into this
984 * pixmap's hps. If \a prepare is FALSE, it does the cleanup. If \a force is
985 * TRUE on cleanup, the masked bitmap is destroyed regardless of the
986 * optimization type.
987 *
988 * Currently used in ::bitBlt() and in QPixmap::createIcon().
989 */
990void QPixmap::prepareForMasking( bool prepare, bool force /* = FALSE */ )
[8]991{
992 if ( !data->mask || data->selfmask )
993 return;
994 if ( prepare ) {
995 if ( !data->maskedHbm ) {
996 GpiSetBitmap( hps, 0 );
997 BITMAPINFOHEADER2 bmh;
998 memset( &bmh, 0, sizeof(BITMAPINFOHEADER2) );
999 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
1000 bmh.cx = data->w;
1001 bmh.cy = data->h;
1002 bmh.cPlanes = 1;
1003 bmh.cBitCount = data->d;
1004 data->maskedHbm = GpiCreateBitmap( hps, &bmh, 0, NULL, NULL );
1005 GpiSetBitmap( hps, data->maskedHbm );
1006 POINTL ptls[] = {
1007 // dst is inclusive
1008 { 0, 0 }, { data->w - 1, data->h - 1 },
1009 { 0, 0 }, { data->w, data->h },
1010 };
1011 GpiWCBitBlt( hps, data->hbm, 4, ptls, ROP_SRCCOPY, BBO_IGNORE );
1012 // dst is exclusive
1013 ptls[1].x++;
1014 ptls[1].y++;
1015 // make transparent pixels black
1016 const ULONG AllImageAttrs =
1017 IBB_COLOR | IBB_BACK_COLOR |
1018 IBB_MIX_MODE | IBB_BACK_MIX_MODE;
1019 IMAGEBUNDLE oldIb;
1020 GpiQueryAttrs( hps, PRIM_IMAGE, AllImageAttrs, (PBUNDLE) &oldIb );
1021 IMAGEBUNDLE newIb = {
1022 CLR_TRUE, CLR_FALSE, FM_OVERPAINT, BM_OVERPAINT
1023 };
1024 GpiSetAttrs( hps, PRIM_IMAGE, AllImageAttrs, 0, (PBUNDLE) &newIb );
1025 GpiBitBlt( hps, data->mask->hps, 3, ptls, ROP_SRCAND, BBO_IGNORE );
1026 GpiSetAttrs( hps, PRIM_IMAGE, AllImageAttrs, 0, (PBUNDLE) &oldIb );
1027 } else {
1028 GpiSetBitmap( hps, data->maskedHbm );
1029 }
1030 } else {
1031 GpiSetBitmap( hps, data->hbm );
1032 // delete the precomposed masked pixmap when memory optimization
[59]1033 // is in force (or force is TRUE)
1034 if ( data->maskedHbm && (force || (data->optim != NormalOptim &&
1035 data->optim != BestOptim)) ) {
[8]1036 GpiDeleteBitmap( data->maskedHbm );
1037 data->maskedHbm = 0;
1038 }
1039 }
1040}
1041
[56]1042HPOINTER QPixmap::createIcon( bool pointer, int hotX, int hotY, bool mini )
1043{
1044 HPOINTER icon = NULLHANDLE;
1045
1046 if ( !isNull() ) {
1047 int w = WinQuerySysValue( HWND_DESKTOP, pointer ? SV_CXPOINTER : SV_CXICON );
1048 int h = WinQuerySysValue( HWND_DESKTOP, pointer ? SV_CYPOINTER : SV_CYICON );
1049 if ( mini ) {
1050 w /= 2;
1051 h /= 2;
1052 }
[108]1053
1054 QPixmap pm = *this;
1055
1056#if !defined(QT_PM_NO_ICON_THRESHOLD)
1057 // non-scalable threshold
1058 enum { tmax = 12 };
1059 int tw = w / 4;
1060 int th = h / 4;
1061 // difference
1062 int dw = w - data->w;
1063 int dh = h - data->h;
[56]1064
[108]1065 if ( (tw <= tmax && th <= tmax) &&
1066 ((data->w >= data->h && dw > 0 && dw <= tw) ||
1067 (dh > 0 && dh <= th)) ) {
1068 pm = QPixmap( w, h );
1069 LONG ofsx = dw / 2;
1070 LONG ofsy = dh / 2;
1071 POINTL ptls[] = {
1072 { ofsx, ofsy }, { data->w + ofsx, data->h + ofsy },
1073 { 0, 0 },
1074 };
1075 GpiBitBlt( pm.hps, hps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
1076 QBitmap msk = QBitmap( w, h );
1077 msk.fill( color0 );
1078 if ( data->mask ) {
1079 GpiBitBlt( msk.hps, data->mask->hps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
1080 } else {
1081 GpiBitBlt( msk.hps, NULL, 3, ptls, ROP_ONE, BBO_IGNORE );
1082 }
1083 pm.setMask( msk );
1084 // correct the hot spot
1085 hotX += ofsx;
1086 hotY += ofsy;
1087 } else
1088#endif
1089 {
1090 if ( data->w != w || data->h != h ) {
1091 QImage i = convertToImage();
[56]1092#if !defined(QT_NO_IMAGE_SMOOTHSCALE)
[108]1093 // do smooth resize until icon is two or more times bigger
1094 // than the pixmap
1095 if ( data->w * 2 > w || data->h * 2 > h ) {
1096 pm = QPixmap( i.smoothScale( w, h ) );
1097 } else
[56]1098#endif
[108]1099 {
1100 pm = QPixmap( i.scale( w, h ) );
1101 }
1102 // correct the hot spot
1103 hotX = hotX * w / data->w;
1104 hotY = hotY * h / data->h;
[56]1105 }
1106 }
1107
1108 QBitmap msk( w, h * 2, TRUE );
1109 if ( pm.data->mask ) {
1110 // create AND mask (XOR mask is left zeroed -- it's ok)
1111 POINTL ptls[] = {
1112 { 0, h }, { w, h * 2 },
1113 { 0, 0 }, { w, h },
1114 };
1115 GpiBitBlt( msk.hps, pm.data->mask->hps, 4, ptls, ROP_NOTSRCCOPY, BBO_IGNORE );
1116 pm.prepareForMasking( TRUE );
1117 }
1118
1119 // unselect bitmap handles from hps
1120 GpiSetBitmap( pm.hps, 0 );
1121 GpiSetBitmap( msk.hps, 0 );
1122
[108]1123 // Due to a bug in WinCreatePointerIndirect, it always ignores
1124 // hbmMiniPointer and hbmMiniColor fields, so we use only hbmPointer
1125 // and hbmColor. Thankfully, PM will assign it correctly either to
1126 // the "normal" or to the "mini" slot depending on the actual icon
1127 // width and height.
1128
[56]1129 POINTERINFO info;
1130 info.fPointer = pointer;
1131 info.xHotspot = hotX;
1132 info.yHotspot = hotY;
1133 info.hbmPointer = msk.data->hbm;
1134 info.hbmColor = pm.data->mask ? pm.data->maskedHbm : pm.data->hbm;
1135 info.hbmMiniPointer = 0;
1136 info.hbmMiniColor = 0;
1137 icon = WinCreatePointerIndirect( HWND_DESKTOP, &info );
1138
1139 if ( pm.mask() )
1140 pm.prepareForMasking( FALSE );
1141
1142 GpiSetBitmap( msk.hps, msk.data->hbm );
1143 GpiSetBitmap( pm.hps, pm.data->hbm );
1144 }
1145
1146 return icon;
1147}
1148
[8]1149void QPixmap::attachHandle( HBITMAP hbm )
1150{
1151 if ( paintingActive() )
1152 return;
1153
1154 BITMAPINFOHEADER bmh;
1155 if (!GpiQueryBitmapParameters( hbm, &bmh ))
1156 return;
1157
1158 if ( !data->uninit && !isNull() ) { // has existing pixmap
1159 deref();
1160 init( 0, 0, 0, FALSE, defOptim );
1161 }
1162
1163 data->uninit = FALSE;
1164 data->w = bmh.cx;
1165 data->h = bmh.cy;
1166 data->d = bmh.cPlanes * bmh.cBitCount;
1167
1168 hps = alloc_mem_ps( bmh.cx, bmh.cy );
1169 data->hbm = hbm;
1170
1171 GpiSetBitmap( hps, data->hbm );
1172}
1173
1174HBITMAP QPixmap::detachHandle()
1175{
1176 if ( paintingActive() )
1177 return 0;
1178
1179 HBITMAP hbm = data->hbm;
1180
1181 // do what deref() will not do after data->hbm is set to 0
1182 if ( hps )
1183 GpiSetBitmap( hps, 0 );
1184
1185 data->hbm = 0;
1186 deref();
1187
1188 return hbm;
1189}
1190
[59]1191void QPixmap::unfoldAlphaChannel()
1192{
1193 // do nothing if there is no alpha channel or if it is already unfolded
1194 // (i.e. stored in a separate array)
1195 if ( !data->hasRealAlpha || data->realAlphaBits )
1196 return;
1197
1198 Q_ASSERT( data->d == 32 );
1199 if ( !data->d == 32 )
1200 return;
1201
1202 data->realAlphaBits = new uchar[ data->w * data->h ];
1203
1204 // no space for palette, since the depth is 32-bpp
1205 BITMAPINFOHEADER2 bmh;
1206 memset( &bmh, 0, sizeof(BITMAPINFOHEADER2) );
1207 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
1208 bmh.cx = data->w;
1209 bmh.cy = data->h;
1210 bmh.cPlanes = 1;
1211 bmh.cBitCount = data->d;
1212
1213 int bpl = ((data->d * data->w + 31) / 32) * 4;
1214 uchar *bits = new uchar [bpl * data->h];
1215
1216 GpiQueryBitmapBits( hps, 0, data->h, (PBYTE) bits, (PBITMAPINFO2) &bmh );
1217
1218 int bpx = data->d / 8;
1219 int inc = bpl - bpx * data->w;
1220 uchar *src = bits + 3; // move to the alpha byte
1221 uchar *dst = data->realAlphaBits;
1222 for ( int y = 0; y < data->h; ++ y ) {
1223 for ( int x = 0; x < data->w; ++ x ) {
1224 *(dst++) = *src;
1225 src += bpx;
1226 }
1227 src += inc;
1228 }
1229
1230 delete[] bits;
1231}
1232
1233/**
1234 * \internal
1235 * Converts the pixmap (actually, the pixmap's mask, if any) to the alpha
1236 * channel. Implies #unfoldAlphaChannel().
1237 */
1238void QPixmap::convertToAlpha()
1239{
1240 if ( isNull() || data->hasRealAlpha )
1241 return;
1242
1243 if ( data->mask ) {
1244 // allocate header + 2 palette entries
1245 char *bmi_data = new char[ sizeof(BITMAPINFOHEADER2) + 8 ];
1246 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
1247 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
1248 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
1249 bmh.cx = data->w;
1250 bmh.cy = data->h;
1251 bmh.cPlanes = 1;
1252 bmh.cBitCount = 1;
1253 bmh.cclrUsed = 2;
1254
1255 int bpl = ((data->w + 31) / 32) * 4;
1256 uchar *bits = new uchar [bpl * data->h];
1257
1258 GpiQueryBitmapBits( data->mask->hps, 0, data->h, (PBYTE) bits,
1259 (PBITMAPINFO2) bmi_data );
1260
1261 data->realAlphaBits = new uchar[ data->w * data->h ];
1262
1263 int inc = bpl - data->w / 8;
1264 uchar *src = bits;
1265 uchar *dst = data->realAlphaBits;
1266 uchar m = 0x80;
1267 for ( int y = 0; y < data->h; ++ y ) {
1268 for ( int x = 0; x < data->w; ++ x ) {
1269 *(dst ++) = (*src) & m ? 0xFF : 0x00;
1270 m >>= 1;
1271 if ( !m ) {
1272 m = 0x80;
1273 ++ src;
1274 }
1275 }
1276 src += inc;
1277 }
1278
1279 data->hasRealAlpha = TRUE;
1280
1281 delete[] bits;
1282 delete[] bmi_data;
1283 } else {
1284 data->realAlphaBits = new uchar[ data->w * data->h ];
1285 memset( data->realAlphaBits, 0xFF, data->w * data->h );
1286 data->hasRealAlpha = TRUE;
1287 }
1288}
1289
1290/**
1291 * \internal
1292 * This depth is used when querying and setting bitmap bits for pixmaps
1293 * with alpha channel, either 24 or 32 (depending on the video driver caps).
1294 * \note This depth is not used to create bitmaps (#defaultDepth() is always
1295 * in charge for that purpose).
1296 */
1297//static
1298int QPixmap::trueColorDepth()
1299{
1300 static int tcd = 0;
1301 if ( tcd == 0 ) {
1302 HDC display_dc = GpiQueryDevice( qt_display_ps() );
1303 LONG formatCnt = 0;
1304 DevQueryCaps( display_dc, CAPS_BITMAP_FORMATS, 1, &formatCnt );
1305 LONG *formats = new LONG[ formatCnt * 2 ];
1306 GpiQueryDeviceBitmapFormats( qt_display_ps(), formatCnt * 2, formats );
1307 for( int i = 0; i < formatCnt * 2; i += 2 ) {
1308 if ( formats[ i ] == 1 && formats[ i + 1 ] == 32 ) {
1309 tcd = 32;
1310 break;
1311 }
1312 }
1313 delete[] formats;
1314 // if the 32-bpp format is not supported, we assume the 24-bpp
1315 // format that must be supported by all video drivers
1316 if ( tcd == 0 )
1317 tcd = 24;
1318 }
1319 return tcd;
1320}
1321
[56]1322/*!
1323 \internal
1324
1325 Creates an OS/2 icon or pointer from two given pixmaps.
1326
[108]1327 If either of the pixmaps doesn't match eaxctly to the system-defined icon
1328 or pointer size, it will be scaled to that size without keeping proportions.
1329 However, to avoid scaling of small pixmaps that will most likely make them
1330 unreadable, there is a non-scalable threshold that causes a pixmap to be
1331 centered rather than scaled. The non-scalable threshold value is 1/4 of the
1332 system-defined size but no more than 12 pixels (if more, then the threshold
1333 is not applied). Here are examples of non-scalable pixmap sizes for common
1334 icon/pointer sizes:
1335
1336 icon size non-scalable pixmap sizes
1337 --------- -------------------------
1338 16 px 12..16 px
1339 20 px 15..20 px
1340 32 px 24..32 px
1341 40 px 30..40 px
1342
[56]1343 \param pointer true to create a pointer, false to create an icon
1344 \param hotX X coordinate of the action point within the pointer/icon
1345 \param hotY Y coordinate of the action point within the pointer/icon
1346 \param normal pixmap for a normal-sized pointer/icon
[108]1347 \param mini pixmap for a mini-sized (half-sized) pointer/icon
[56]1348
[59]1349 \return PM handle of the created pointer or 0 in case of any error
1350
[108]1351 \note Due to a bug in WinCreatePointerIndirect, you can specify either a
1352 \a normal pixmap or \a mini pixmap, but not both. If both are specified,
1353 the \a normal will be used so that if its size is equal to or larger than
1354 the normal pointer/icon size (taking the threshold into account), it will
1355 be used as a normal pointer/icon, otherwise as a mini one. PM will use
1356 its own scaling to draw a pointer/icon of the other size when necessary.
1357 This bug may be fixed later.
[59]1358
1359 \warning This function is not portable.
[56]1360*/
1361// static
1362HPOINTER QPixmap::createIcon( bool pointer, int hotX, int hotY,
1363 const QPixmap *normal, const QPixmap *mini )
1364{
1365 // Due to a bug in WinCreatePointerIndirect (it always ignores
1366 // hbmMiniPointer and hbmMiniColor fields), we can specify either a normal
[108]1367 // icon, but not both. This method still accepts pixmaps for both icon
[59]1368 // sizes (assuming that we will find a workaround one day) but uses only
1369 // one of them.
[56]1370
1371 if ( normal && !normal->isNull() ) {
[108]1372 // If the specified normal pixmap is equal to or larger than the normal
1373 // icon size (taking the threshold into account), then we use it to
1374 // create a normal icon, otherwise a mini one.
1375 int w = WinQuerySysValue( HWND_DESKTOP, pointer ? SV_CXPOINTER : SV_CXICON );
1376 int h = WinQuerySysValue( HWND_DESKTOP, pointer ? SV_CYPOINTER : SV_CYICON );
1377#if !defined(QT_PM_NO_ICON_THRESHOLD)
1378 // apply the threshold (see private QPixmap::createIcon() above)
1379 if ( w / 4 <= 12 ) w -= w / 4;
1380 if ( h / 4 <= 12 ) h -= h / 4;
1381#endif
1382 bool mini = normal->width() < w && normal->height() < h;
1383 return const_cast <QPixmap *> (normal)->createIcon( pointer, hotX, hotY, mini );
[56]1384 }
1385
1386 if ( mini && !mini->isNull() )
[108]1387 return const_cast <QPixmap *> (mini)->createIcon( pointer, hotX, hotY, TRUE );
[56]1388
1389 return 0;
1390}
1391
[8]1392Q_EXPORT void copyBlt( QPixmap *dst, int dx, int dy,
1393 const QPixmap *src, int sx, int sy, int sw, int sh )
1394{
1395 if ( ! dst || ! src || sw == 0 || sh == 0 || dst->depth() != src->depth() ) {
1396#ifdef QT_CHECK_NULL
1397 Q_ASSERT( dst != 0 );
1398 Q_ASSERT( src != 0 );
1399#endif
1400 return;
1401 }
[59]1402
1403 if ( sw < 0 )
1404 sw = src->width() - sx;
1405 if ( sh < 0 )
1406 sh = src->height() - sy;
1407
1408 // ensure coordinates are within borders, clip if necessary
1409 if ( sx < 0 || sy < 0 || sx + sw > src->width() || sy + sh > src->height() ||
1410 dx < 0 || dy < 0 || dx + sw > dst->width() || dy + sh > dst->height() )
1411 {
1412 int tx = dx - sx;
1413 int ty = dy - sy;
1414 QRect dr( 0, 0, dst->width(), dst->height() ); // dst rect
1415 QRect sr( tx, ty, src->width(), src->height() ); // src rect in dst coords
1416 QRect bltr( dx, dy, sw, sh ); // blit rect in dst coords
1417 bltr &= (dr & sr);
1418 if (bltr.isEmpty())
1419 return;
1420 dx = bltr.x();
1421 dy = bltr.y();
1422 sx = dx - tx;
1423 sy = dy - ty;
1424 sw = bltr.width();
1425 sh = bltr.height();
1426 }
1427
1428 dst->detach();
1429
[8]1430 // copy mask data
1431 if ( src->data->mask ) {
[59]1432 if ( !dst->data->mask ) {
[8]1433 dst->data->mask = new QBitmap( dst->width(), dst->height() );
1434 // new masks are fully opaque by default
1435 dst->data->mask->fill( Qt::color1 );
1436 } else if ( dst->data->maskedHbm ) {
1437 // reset the precomposed masked pixmap
[59]1438 dst->prepareForMasking( FALSE, TRUE );
[8]1439 }
1440
1441 bitBlt( dst->data->mask, dx, dy,
1442 src->data->mask, sx, sy, sw, sh, Qt::CopyROP, TRUE );
1443 }
[59]1444
1445 // copy alpha bits
1446 if ( src->data->hasRealAlpha ||
1447 (src->data->mask && dst->data->hasRealAlpha) ) {
1448 if ( src->data->hasRealAlpha )
1449 const_cast <QPixmap *> (src)->unfoldAlphaChannel();
1450 else
1451 const_cast <QPixmap *> (src)->convertToAlpha();
1452 if ( dst->data->hasRealAlpha )
1453 dst->unfoldAlphaChannel();
1454 else
1455 dst->convertToAlpha();
1456 uchar *srca = src->data->realAlphaBits + src->width() * sy + sx;
1457 uchar *dsta = dst->data->realAlphaBits + dst->width() * dy + dx;
1458 for ( int y = 0; y < sh; ++ y ) {
1459 memcpy( dsta, srca, sw );
1460 srca += src->width();
1461 dsta += dst->width();
1462 }
[8]1463 }
[59]1464
1465 // copy pixel data
1466 bitBlt( dst, dx, dy, src, sx, sy, sw, sh, Qt::CopyROP, TRUE );
[8]1467}
Note: See TracBrowser for help on using the repository browser.