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

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

Widgets: Added the non-scaling threshold when setting a top-level widgets's icon. This allows to avoid scaling pixmaps close to the target icon size (e.g. 16x16 to 20x20) to give them a better look (such pixmaps are centered instead of scaling).

  • Property svn:keywords set to Id
File size: 45.7 KB
Line 
1/****************************************************************************
2** $Id: qpixmap_pm.cpp 108 2006-07-30 09:27:57Z 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
1062#if !defined(QT_PM_NO_ICON_THRESHOLD)
1063 // non-scalable threshold
1064 enum { tmax = 12 };
1065 int tw = w / 4;
1066 int th = h / 4;
1067 // difference
1068 int dw = w - data->w;
1069 int dh = h - data->h;
1070
1071 if ( (tw <= tmax && th <= tmax) &&
1072 ((data->w >= data->h && dw > 0 && dw <= tw) ||
1073 (dh > 0 && dh <= th)) ) {
1074 pm = QPixmap( w, h );
1075 LONG ofsx = dw / 2;
1076 LONG ofsy = dh / 2;
1077 POINTL ptls[] = {
1078 { ofsx, ofsy }, { data->w + ofsx, data->h + ofsy },
1079 { 0, 0 },
1080 };
1081 GpiBitBlt( pm.hps, hps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
1082 QBitmap msk = QBitmap( w, h );
1083 msk.fill( color0 );
1084 if ( data->mask ) {
1085 GpiBitBlt( msk.hps, data->mask->hps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
1086 } else {
1087 GpiBitBlt( msk.hps, NULL, 3, ptls, ROP_ONE, BBO_IGNORE );
1088 }
1089 pm.setMask( msk );
1090 // correct the hot spot
1091 hotX += ofsx;
1092 hotY += ofsy;
1093 } else
1094#endif
1095 {
1096 if ( data->w != w || data->h != h ) {
1097 QImage i = convertToImage();
1098#if !defined(QT_NO_IMAGE_SMOOTHSCALE)
1099 // do smooth resize until icon is two or more times bigger
1100 // than the pixmap
1101 if ( data->w * 2 > w || data->h * 2 > h ) {
1102 pm = QPixmap( i.smoothScale( w, h ) );
1103 } else
1104#endif
1105 {
1106 pm = QPixmap( i.scale( w, h ) );
1107 }
1108 // correct the hot spot
1109 hotX = hotX * w / data->w;
1110 hotY = hotY * h / data->h;
1111 }
1112 }
1113
1114 QBitmap msk( w, h * 2, TRUE );
1115 if ( pm.data->mask ) {
1116 // create AND mask (XOR mask is left zeroed -- it's ok)
1117 POINTL ptls[] = {
1118 { 0, h }, { w, h * 2 },
1119 { 0, 0 }, { w, h },
1120 };
1121 GpiBitBlt( msk.hps, pm.data->mask->hps, 4, ptls, ROP_NOTSRCCOPY, BBO_IGNORE );
1122 pm.prepareForMasking( TRUE );
1123 }
1124
1125 // unselect bitmap handles from hps
1126 GpiSetBitmap( pm.hps, 0 );
1127 GpiSetBitmap( msk.hps, 0 );
1128
1129 // Due to a bug in WinCreatePointerIndirect, it always ignores
1130 // hbmMiniPointer and hbmMiniColor fields, so we use only hbmPointer
1131 // and hbmColor. Thankfully, PM will assign it correctly either to
1132 // the "normal" or to the "mini" slot depending on the actual icon
1133 // width and height.
1134
1135 POINTERINFO info;
1136 info.fPointer = pointer;
1137 info.xHotspot = hotX;
1138 info.yHotspot = hotY;
1139 info.hbmPointer = msk.data->hbm;
1140 info.hbmColor = pm.data->mask ? pm.data->maskedHbm : pm.data->hbm;
1141 info.hbmMiniPointer = 0;
1142 info.hbmMiniColor = 0;
1143 icon = WinCreatePointerIndirect( HWND_DESKTOP, &info );
1144
1145 if ( pm.mask() )
1146 pm.prepareForMasking( FALSE );
1147
1148 GpiSetBitmap( msk.hps, msk.data->hbm );
1149 GpiSetBitmap( pm.hps, pm.data->hbm );
1150 }
1151
1152 return icon;
1153}
1154
1155void QPixmap::attachHandle( HBITMAP hbm )
1156{
1157 if ( paintingActive() )
1158 return;
1159
1160 BITMAPINFOHEADER bmh;
1161 if (!GpiQueryBitmapParameters( hbm, &bmh ))
1162 return;
1163
1164 if ( !data->uninit && !isNull() ) { // has existing pixmap
1165 deref();
1166 init( 0, 0, 0, FALSE, defOptim );
1167 }
1168
1169 data->uninit = FALSE;
1170 data->w = bmh.cx;
1171 data->h = bmh.cy;
1172 data->d = bmh.cPlanes * bmh.cBitCount;
1173
1174 hps = alloc_mem_ps( bmh.cx, bmh.cy );
1175 data->hbm = hbm;
1176
1177 GpiSetBitmap( hps, data->hbm );
1178}
1179
1180HBITMAP QPixmap::detachHandle()
1181{
1182 if ( paintingActive() )
1183 return 0;
1184
1185 HBITMAP hbm = data->hbm;
1186
1187 // do what deref() will not do after data->hbm is set to 0
1188 if ( hps )
1189 GpiSetBitmap( hps, 0 );
1190
1191 data->hbm = 0;
1192 deref();
1193
1194 return hbm;
1195}
1196
1197void QPixmap::unfoldAlphaChannel()
1198{
1199 // do nothing if there is no alpha channel or if it is already unfolded
1200 // (i.e. stored in a separate array)
1201 if ( !data->hasRealAlpha || data->realAlphaBits )
1202 return;
1203
1204 Q_ASSERT( data->d == 32 );
1205 if ( !data->d == 32 )
1206 return;
1207
1208 data->realAlphaBits = new uchar[ data->w * data->h ];
1209
1210 // no space for palette, since the depth is 32-bpp
1211 BITMAPINFOHEADER2 bmh;
1212 memset( &bmh, 0, sizeof(BITMAPINFOHEADER2) );
1213 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
1214 bmh.cx = data->w;
1215 bmh.cy = data->h;
1216 bmh.cPlanes = 1;
1217 bmh.cBitCount = data->d;
1218
1219 int bpl = ((data->d * data->w + 31) / 32) * 4;
1220 uchar *bits = new uchar [bpl * data->h];
1221
1222 GpiQueryBitmapBits( hps, 0, data->h, (PBYTE) bits, (PBITMAPINFO2) &bmh );
1223
1224 int bpx = data->d / 8;
1225 int inc = bpl - bpx * data->w;
1226 uchar *src = bits + 3; // move to the alpha byte
1227 uchar *dst = data->realAlphaBits;
1228 for ( int y = 0; y < data->h; ++ y ) {
1229 for ( int x = 0; x < data->w; ++ x ) {
1230 *(dst++) = *src;
1231 src += bpx;
1232 }
1233 src += inc;
1234 }
1235
1236 delete[] bits;
1237}
1238
1239/**
1240 * \internal
1241 * Converts the pixmap (actually, the pixmap's mask, if any) to the alpha
1242 * channel. Implies #unfoldAlphaChannel().
1243 */
1244void QPixmap::convertToAlpha()
1245{
1246 if ( isNull() || data->hasRealAlpha )
1247 return;
1248
1249 if ( data->mask ) {
1250 // allocate header + 2 palette entries
1251 char *bmi_data = new char[ sizeof(BITMAPINFOHEADER2) + 8 ];
1252 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
1253 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
1254 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
1255 bmh.cx = data->w;
1256 bmh.cy = data->h;
1257 bmh.cPlanes = 1;
1258 bmh.cBitCount = 1;
1259 bmh.cclrUsed = 2;
1260
1261 int bpl = ((data->w + 31) / 32) * 4;
1262 uchar *bits = new uchar [bpl * data->h];
1263
1264 GpiQueryBitmapBits( data->mask->hps, 0, data->h, (PBYTE) bits,
1265 (PBITMAPINFO2) bmi_data );
1266
1267 data->realAlphaBits = new uchar[ data->w * data->h ];
1268
1269 int inc = bpl - data->w / 8;
1270 uchar *src = bits;
1271 uchar *dst = data->realAlphaBits;
1272 uchar m = 0x80;
1273 for ( int y = 0; y < data->h; ++ y ) {
1274 for ( int x = 0; x < data->w; ++ x ) {
1275 *(dst ++) = (*src) & m ? 0xFF : 0x00;
1276 m >>= 1;
1277 if ( !m ) {
1278 m = 0x80;
1279 ++ src;
1280 }
1281 }
1282 src += inc;
1283 }
1284
1285 data->hasRealAlpha = TRUE;
1286
1287 delete[] bits;
1288 delete[] bmi_data;
1289 } else {
1290 data->realAlphaBits = new uchar[ data->w * data->h ];
1291 memset( data->realAlphaBits, 0xFF, data->w * data->h );
1292 data->hasRealAlpha = TRUE;
1293 }
1294}
1295
1296/**
1297 * \internal
1298 * This depth is used when querying and setting bitmap bits for pixmaps
1299 * with alpha channel, either 24 or 32 (depending on the video driver caps).
1300 * \note This depth is not used to create bitmaps (#defaultDepth() is always
1301 * in charge for that purpose).
1302 */
1303//static
1304int QPixmap::trueColorDepth()
1305{
1306 static int tcd = 0;
1307 if ( tcd == 0 ) {
1308 HDC display_dc = GpiQueryDevice( qt_display_ps() );
1309 LONG formatCnt = 0;
1310 DevQueryCaps( display_dc, CAPS_BITMAP_FORMATS, 1, &formatCnt );
1311 LONG *formats = new LONG[ formatCnt * 2 ];
1312 GpiQueryDeviceBitmapFormats( qt_display_ps(), formatCnt * 2, formats );
1313 for( int i = 0; i < formatCnt * 2; i += 2 ) {
1314 if ( formats[ i ] == 1 && formats[ i + 1 ] == 32 ) {
1315 tcd = 32;
1316 break;
1317 }
1318 }
1319 delete[] formats;
1320 // if the 32-bpp format is not supported, we assume the 24-bpp
1321 // format that must be supported by all video drivers
1322 if ( tcd == 0 )
1323 tcd = 24;
1324 }
1325 return tcd;
1326}
1327
1328/*!
1329 \internal
1330
1331 Creates an OS/2 icon or pointer from two given pixmaps.
1332
1333 If either of the pixmaps doesn't match eaxctly to the system-defined icon
1334 or pointer size, it will be scaled to that size without keeping proportions.
1335 However, to avoid scaling of small pixmaps that will most likely make them
1336 unreadable, there is a non-scalable threshold that causes a pixmap to be
1337 centered rather than scaled. The non-scalable threshold value is 1/4 of the
1338 system-defined size but no more than 12 pixels (if more, then the threshold
1339 is not applied). Here are examples of non-scalable pixmap sizes for common
1340 icon/pointer sizes:
1341
1342 icon size non-scalable pixmap sizes
1343 --------- -------------------------
1344 16 px 12..16 px
1345 20 px 15..20 px
1346 32 px 24..32 px
1347 40 px 30..40 px
1348
1349 \param pointer true to create a pointer, false to create an icon
1350 \param hotX X coordinate of the action point within the pointer/icon
1351 \param hotY Y coordinate of the action point within the pointer/icon
1352 \param normal pixmap for a normal-sized pointer/icon
1353 \param mini pixmap for a mini-sized (half-sized) pointer/icon
1354
1355 \return PM handle of the created pointer or 0 in case of any error
1356
1357 \note Due to a bug in WinCreatePointerIndirect, you can specify either a
1358 \a normal pixmap or \a mini pixmap, but not both. If both are specified,
1359 the \a normal will be used so that if its size is equal to or larger than
1360 the normal pointer/icon size (taking the threshold into account), it will
1361 be used as a normal pointer/icon, otherwise as a mini one. PM will use
1362 its own scaling to draw a pointer/icon of the other size when necessary.
1363 This bug may be fixed later.
1364
1365 \warning This function is not portable.
1366*/
1367// static
1368HPOINTER QPixmap::createIcon( bool pointer, int hotX, int hotY,
1369 const QPixmap *normal, const QPixmap *mini )
1370{
1371 // Due to a bug in WinCreatePointerIndirect (it always ignores
1372 // hbmMiniPointer and hbmMiniColor fields), we can specify either a normal
1373 // icon, but not both. This method still accepts pixmaps for both icon
1374 // sizes (assuming that we will find a workaround one day) but uses only
1375 // one of them.
1376
1377 if ( normal && !normal->isNull() ) {
1378 // If the specified normal pixmap is equal to or larger than the normal
1379 // icon size (taking the threshold into account), then we use it to
1380 // create a normal icon, otherwise a mini one.
1381 int w = WinQuerySysValue( HWND_DESKTOP, pointer ? SV_CXPOINTER : SV_CXICON );
1382 int h = WinQuerySysValue( HWND_DESKTOP, pointer ? SV_CYPOINTER : SV_CYICON );
1383#if !defined(QT_PM_NO_ICON_THRESHOLD)
1384 // apply the threshold (see private QPixmap::createIcon() above)
1385 if ( w / 4 <= 12 ) w -= w / 4;
1386 if ( h / 4 <= 12 ) h -= h / 4;
1387#endif
1388 bool mini = normal->width() < w && normal->height() < h;
1389 return const_cast <QPixmap *> (normal)->createIcon( pointer, hotX, hotY, mini );
1390 }
1391
1392 if ( mini && !mini->isNull() )
1393 return const_cast <QPixmap *> (mini)->createIcon( pointer, hotX, hotY, TRUE );
1394
1395 return 0;
1396}
1397
1398Q_EXPORT void copyBlt( QPixmap *dst, int dx, int dy,
1399 const QPixmap *src, int sx, int sy, int sw, int sh )
1400{
1401 if ( ! dst || ! src || sw == 0 || sh == 0 || dst->depth() != src->depth() ) {
1402#ifdef QT_CHECK_NULL
1403 Q_ASSERT( dst != 0 );
1404 Q_ASSERT( src != 0 );
1405#endif
1406 return;
1407 }
1408
1409 if ( sw < 0 )
1410 sw = src->width() - sx;
1411 if ( sh < 0 )
1412 sh = src->height() - sy;
1413
1414 // ensure coordinates are within borders, clip if necessary
1415 if ( sx < 0 || sy < 0 || sx + sw > src->width() || sy + sh > src->height() ||
1416 dx < 0 || dy < 0 || dx + sw > dst->width() || dy + sh > dst->height() )
1417 {
1418 int tx = dx - sx;
1419 int ty = dy - sy;
1420 QRect dr( 0, 0, dst->width(), dst->height() ); // dst rect
1421 QRect sr( tx, ty, src->width(), src->height() ); // src rect in dst coords
1422 QRect bltr( dx, dy, sw, sh ); // blit rect in dst coords
1423 bltr &= (dr & sr);
1424 if (bltr.isEmpty())
1425 return;
1426 dx = bltr.x();
1427 dy = bltr.y();
1428 sx = dx - tx;
1429 sy = dy - ty;
1430 sw = bltr.width();
1431 sh = bltr.height();
1432 }
1433
1434 dst->detach();
1435
1436 // copy mask data
1437 if ( src->data->mask ) {
1438 if ( !dst->data->mask ) {
1439 dst->data->mask = new QBitmap( dst->width(), dst->height() );
1440 // new masks are fully opaque by default
1441 dst->data->mask->fill( Qt::color1 );
1442 } else if ( dst->data->maskedHbm ) {
1443 // reset the precomposed masked pixmap
1444 dst->prepareForMasking( FALSE, TRUE );
1445 }
1446
1447 bitBlt( dst->data->mask, dx, dy,
1448 src->data->mask, sx, sy, sw, sh, Qt::CopyROP, TRUE );
1449 }
1450
1451 // copy alpha bits
1452 if ( src->data->hasRealAlpha ||
1453 (src->data->mask && dst->data->hasRealAlpha) ) {
1454 if ( src->data->hasRealAlpha )
1455 const_cast <QPixmap *> (src)->unfoldAlphaChannel();
1456 else
1457 const_cast <QPixmap *> (src)->convertToAlpha();
1458 if ( dst->data->hasRealAlpha )
1459 dst->unfoldAlphaChannel();
1460 else
1461 dst->convertToAlpha();
1462 uchar *srca = src->data->realAlphaBits + src->width() * sy + sx;
1463 uchar *dsta = dst->data->realAlphaBits + dst->width() * dy + dx;
1464 for ( int y = 0; y < sh; ++ y ) {
1465 memcpy( dsta, srca, sw );
1466 srca += src->width();
1467 dsta += dst->width();
1468 }
1469 }
1470
1471 // copy pixel data
1472 bitBlt( dst, dx, dy, src, sx, sy, sw, sh, Qt::CopyROP, TRUE );
1473}
Note: See TracBrowser for help on using the repository browser.