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

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

Transferred Qt for OS/2 version 3.3.1-rc5 sources from the CVS

  • Property svn:keywords set to Id
File size: 35.9 KB
Line 
1/****************************************************************************
2** $Id: qpixmap_pm.cpp 8 2005-11-16 19:36:46Z 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//@@TODO (dmik): later
98//void QPixmap::initAlphaPixmap( uchar *bytes, int length, BITMAPINFO *bmi )
99//{
100// if ( data->mcp )
101// freeCell( TRUE );
102// if ( !hdc )
103// hdc = alloc_mem_dc( 0, &data->old_hbm );
104//
105// HBITMAP hBitmap = CreateDIBSection( hdc, bmi, DIB_RGB_COLORS, (void**)&data->realAlphaBits, NULL, 0 );
106// if ( bytes )
107// memcpy( data->realAlphaBits, bytes, length );
108//
109// DeleteObject( SelectObject( hdc, data->old_hbm ) );
110// data->old_hbm = (HBITMAP)SelectObject( hdc, hBitmap );
111// DATA_HBM = hBitmap;
112//}
113
114
115void QPixmap::init( int w, int h, int d, bool bitmap, Optimization optim )
116{
117#if defined(QT_CHECK_STATE)
118 if ( qApp->type() == QApplication::Tty ) {
119 qWarning( "QPixmap: Cannot create a QPixmap when no GUI "
120 "is being used" );
121 }
122#endif
123
124 static int serial = 0;
125 int dd = defaultDepth();
126
127 if ( optim == DefaultOptim ) // use default optimization
128 optim = defOptim;
129
130 data = new QPixmapData;
131 Q_CHECK_PTR( data );
132
133 memset( data, 0, sizeof(QPixmapData) );
134 data->count = 1;
135 data->uninit = TRUE;
136 data->bitmap = bitmap;
137 data->ser_no = ++serial;
138 data->optim = optim;
139
140 bool make_null = w == 0 || h == 0; // create null pixmap
141 if ( d == 1 ) // monocrome pixmap
142 data->d = 1;
143 else if ( d < 0 || d == dd ) // compatible pixmap
144 data->d = dd;
145 if ( make_null || w < 0 || h < 0 || data->d == 0 ) {
146 hps = 0;
147 data->hbm = 0;
148#if defined(QT_CHECK_RANGE)
149 if ( !make_null ) // invalid parameters
150 qWarning( "QPixmap: Invalid pixmap parameters" );
151#endif
152 return;
153 }
154 data->w = w;
155 data->h = h;
156
157 hps = alloc_mem_ps( w, h );
158 BITMAPINFOHEADER2 bmh;
159 memset( &bmh, 0, sizeof(BITMAPINFOHEADER2) );
160 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
161 bmh.cx = w;
162 bmh.cy = h;
163 bmh.cPlanes = 1;
164 if ( data->d == dd ) // compatible bitmap
165 bmh.cBitCount = dd;
166 else // monocrome bitmap
167 bmh.cBitCount = 1;
168 data->hbm = GpiCreateBitmap( hps, &bmh, 0, NULL, NULL );
169
170 if ( !data->hbm ) {
171 data->w = 0;
172 data->h = 0;
173 free_mem_ps( hps );
174 hps = 0;
175#if defined(QT_CHECK_NULL)
176 qSystemWarning( "QPixmap: Pixmap allocation failed" );
177#endif
178 return;
179 }
180
181 GpiSetBitmap( hps, data->hbm );
182}
183
184
185void QPixmap::deref()
186{
187 if ( data && data->deref() ) { // last reference lost
188 if ( data->mask ) {
189 delete data->mask;
190 if ( data->maskedHbm ) {
191 GpiDeleteBitmap( data->maskedHbm );
192 data->maskedHbm = 0;
193 }
194 }
195 if ( data->hbm ) {
196 if ( hps )
197 GpiSetBitmap( hps, 0 );
198 GpiDeleteBitmap( data->hbm );
199 data->hbm = 0;
200 }
201 if ( hps ) {
202 free_mem_ps( hps );
203 hps = 0;
204 }
205 delete data;
206 data = 0;
207 }
208}
209
210
211QPixmap::QPixmap( int w, int h, const uchar *bits, bool isXbitmap )
212 : QPaintDevice( QInternal::Pixmap )
213{ // for bitmaps only
214 init( 0, 0, 0, FALSE, NormalOptim );
215 if ( w <= 0 || h <= 0 ) // create null pixmap
216 return;
217
218 data->uninit = FALSE;
219 data->w = w;
220 data->h = h;
221 data->d = 1;
222
223 int bitsbpl = (w+7)/8; // original # bytes per line
224
225 int bpl = ((w + 31) / 32) * 4; // bytes per scanline,
226 // doubleword aligned
227
228 uchar *newbits = new uchar[bpl*h];
229 uchar *p = newbits + bpl*(h - 1); // last scanline
230 int x, y, pad;
231 pad = bpl - bitsbpl;
232 const uchar *f = isXbitmap ? qt_get_bitflip_array() : 0;
233
234 // flip bit order if Xbitmap and flip bitmap top to bottom
235 for ( y=0; y<h; y++ ) {
236 if ( f ) {
237 for ( x=0; x<bitsbpl; x++ )
238 *p++ = f[*bits++];
239 for ( x=0; x<pad; x++ )
240 *p++ = 0;
241 p -= bpl;
242 } else {
243 memcpy( p, bits, bitsbpl );
244 memset( p + bitsbpl, 0, pad );
245 bits += bitsbpl;
246 }
247 p -= bpl;
248 }
249
250 hps = alloc_mem_ps( w, h );
251 // allocate header + 2 palette entries
252 char *bmi_data = new char[ sizeof(BITMAPINFOHEADER2) + 4 * 2 ];
253 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
254 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
255 PULONG pal = (PULONG) (bmi_data + sizeof(BITMAPINFOHEADER2));
256 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
257 bmh.cx = w;
258 bmh.cy = h;
259 bmh.cPlanes = 1;
260 bmh.cBitCount = 1;
261 bmh.cclrUsed = 2;
262 pal[0] = 0;
263 pal[1] = 0x00FFFFFF;
264 data->hbm = GpiCreateBitmap(
265 hps, &bmh, CBM_INIT, (PBYTE) newbits, (PBITMAPINFO2) bmi_data
266 );
267
268 GpiSetBitmap( hps, data->hbm );
269
270 delete [] bmi_data;
271 delete [] newbits;
272 if ( defOptim != NormalOptim )
273 setOptimization( defOptim );
274}
275
276
277void QPixmap::detach()
278{
279 if ( data->uninit || data->count == 1 )
280 data->uninit = FALSE;
281 else
282 *this = copy();
283}
284
285
286int QPixmap::defaultDepth()
287{
288 static int dd = 0;
289 if ( dd == 0 ) {
290 LONG formats [2];
291 GpiQueryDeviceBitmapFormats( qt_display_ps(), 2, formats );
292 dd = formats [0] * formats [1];
293 }
294 return dd;
295}
296
297
298void QPixmap::setOptimization( Optimization optimization )
299{
300 if ( optimization == data->optim )
301 return;
302 detach();
303 data->optim = optimization == DefaultOptim ?
304 defOptim : optimization;
305}
306
307
308void QPixmap::fill( const QColor &fillColor )
309{
310 if ( isNull() )
311 return;
312 detach(); // detach other references
313
314 const ULONG AreaAttrs = ABB_COLOR | ABB_MIX_MODE | ABB_SET | ABB_SYMBOL;
315 AREABUNDLE oldAb;
316 GpiQueryAttrs( hps, PRIM_AREA, AreaAttrs, (PBUNDLE) &oldAb );
317 AREABUNDLE newAb;
318 newAb.lColor = fillColor.pixel();
319 newAb.usMixMode = FM_OVERPAINT;
320 newAb.usSet = LCID_DEFAULT;
321 newAb.usSymbol = PATSYM_SOLID;
322 GpiSetAttrs( hps, PRIM_AREA, AreaAttrs, 0, (PBUNDLE) &newAb );
323 POINTL ptl = { 0, 0 };
324 GpiMove( hps, &ptl );
325 ptl.x = data->w - 1;
326 ptl.y = data->h - 1;
327 GpiBox( hps, DRO_FILL, &ptl, 0, 0 );
328 GpiSetAttrs( hps, PRIM_AREA, AreaAttrs, 0, (PBUNDLE) &newAb );
329}
330
331
332int QPixmap::metric( int m ) const
333{
334 if ( m == QPaintDeviceMetrics::PdmWidth ) {
335 return width();
336 } else if ( m == QPaintDeviceMetrics::PdmHeight ) {
337 return height();
338 } else {
339 LONG val;
340 HDC hdc = GpiQueryDevice( hps );
341 switch ( m ) {
342 case QPaintDeviceMetrics::PdmDpiX:
343 DevQueryCaps( hdc, CAPS_HORIZONTAL_FONT_RES, 1, &val );
344 break;
345 case QPaintDeviceMetrics::PdmDpiY:
346 DevQueryCaps( hdc, CAPS_VERTICAL_FONT_RES, 1, &val );
347 break;
348 case QPaintDeviceMetrics::PdmWidthMM:
349 DevQueryCaps( hdc, CAPS_HORIZONTAL_RESOLUTION, 1, &val );
350 val = width() * 1000 / val;
351 break;
352 case QPaintDeviceMetrics::PdmHeightMM:
353 DevQueryCaps( hdc, CAPS_VERTICAL_RESOLUTION, 1, &val );
354 val = width() * 1000 / val;
355 break;
356 case QPaintDeviceMetrics::PdmNumColors:
357 if (depth() == 1) {
358 // it's a monochrome bitmap
359 val = 1;
360 } else {
361 DevQueryCaps( hdc, CAPS_COLORS, 1, &val );
362 }
363 break;
364 case QPaintDeviceMetrics::PdmDepth:
365 val = depth();
366 break;
367 default:
368 val = 0;
369#if defined(QT_CHECK_RANGE)
370 qWarning( "QPixmap::metric: Invalid metric command" );
371#endif
372 }
373 return val;
374 }
375}
376
377QImage QPixmap::convertToImage() const
378{
379 if ( isNull() )
380 return QImage(); // null image
381
382 int w = width();
383 int h = height();
384 const QBitmap *m = data->realAlphaBits ? 0 : mask();
385 int d = depth();
386 int ncols = 2;
387
388 if ( d > 1 && d <= 8 ) { // set to nearest valid depth
389 d = 8; // 2..7 ==> 8
390 ncols = 256;
391 } else if ( d > 8 ) {
392 d = 32; // > 8 ==> 32
393 ncols = 0;
394 }
395
396 QImage image( w, h, d, ncols, QImage::BigEndian );
397 if ( data->realAlphaBits ) {
398 qWarning( "QPixmap::convertToImage() for pixmaps with alpha is not yet implemented on OS/2" );
399//@@TODO (dmik): later
400//#ifndef Q_OS_TEMP
401// GdiFlush();
402//#endif
403// memcpy( image.bits(), data->realAlphaBits, image.numBytes() );
404// image.setAlphaBuffer( TRUE );
405//
406// // Windows has premultiplied alpha, so revert it
407// uchar *p = image.bits();
408// uchar *end = p + image.numBytes();
409// uchar alphaByte;
410// while ( p < end ) {
411// alphaByte = *(p+3);
412// if ( alphaByte == 0 ) {
413// *p = 255;
414// ++p;
415// *p = 255;
416// ++p;
417// *p = 255;
418// ++p;
419// ++p;
420// } else if ( alphaByte == 255 ) {
421// p += 4;
422// } else {
423// uchar alphaByte2 = alphaByte / 2;
424// *p = ( (int)(*p) * 255 + alphaByte2 ) / alphaByte;
425// ++p;
426// *p = ( (int)(*p) * 255 + alphaByte2 ) / alphaByte;
427// ++p;
428// *p = ( (int)(*p) * 255 + alphaByte2 ) / alphaByte;
429// ++p;
430// ++p;
431// }
432// }
433// return image;
434 }
435
436 // allocate header + ncols palette entries
437 char *bmi_data = new char[ sizeof(BITMAPINFOHEADER2) + 4 * ncols ];
438 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
439 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
440 PULONG pal = (PULONG) (bmi_data + sizeof(BITMAPINFOHEADER2));
441 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
442 bmh.cx = w;
443 bmh.cy = h;
444 bmh.cPlanes = 1;
445 bmh.cBitCount = d;
446 bmh.cclrUsed = ncols;
447 GpiQueryBitmapBits( hps, 0, h, (PBYTE) image.bits(), (PBITMAPINFO2) bmi_data );
448
449 // flip the image top to bottom
450 {
451 int bpl = image.bytesPerLine();
452 uchar *line = new uchar[bpl];
453 uchar *top = image.scanLine( 0 );
454 uchar *bottom = image.scanLine( h - 1 );
455 while( top < bottom ) {
456 memcpy( line, top, bpl );
457 memcpy( top, bottom, bpl );
458 memcpy( bottom, line, bpl );
459 top += bpl;
460 bottom -= bpl;
461 }
462 delete [] line;
463 }
464
465 if ( d == 1 ) {
466 // use a white/black palette for monochrome pixmaps (istead of
467 // black/white supplied by GPI) to make the result of possible
468 // converson to a higher depth compatible with other platforms.
469 if ( m ) {
470 image.setAlphaBuffer( TRUE );
471 image.setColor( 0, qRgba( 255, 255, 255, 0 ) );
472 image.setColor( 1, qRgba( 0, 0, 0, 255 ) );
473 } else {
474 image.setColor( 0, qRgb( 255, 255, 255 ) );
475 image.setColor( 1, qRgb( 0, 0, 0 ) );
476 }
477 } else {
478 for ( int i=0; i<ncols; i++ ) { // copy color table
479 PRGB2 r = (PRGB2) &pal[i];
480 if ( m )
481 image.setColor( i, qRgba(r->bRed,
482 r->bGreen,
483 r->bBlue,255) );
484 else
485 image.setColor( i, qRgb(r->bRed,
486 r->bGreen,
487 r->bBlue) );
488 }
489 }
490
491 delete [] bmi_data;
492
493 if ( d != 1 && m ) {
494 image.setAlphaBuffer(TRUE);
495 QImage msk = m->convertToImage();
496
497 switch ( d ) {
498 case 8: {
499 int used[256];
500 memset( used, 0, sizeof(int)*256 );
501 uchar* p = image.bits();
502 int l = image.numBytes();
503 while (l--) {
504 used[*p++]++;
505 }
506 int trans=0;
507 int bestn=INT_MAX;
508 for ( int i=0; i<256; i++ ) {
509 if ( used[i] < bestn ) {
510 bestn = used[i];
511 trans = i;
512 if ( !bestn )
513 break;
514 }
515 }
516 image.setColor( trans, image.color(trans)&0x00ffffff );
517 for ( int y=0; y<image.height(); y++ ) {
518 uchar* mb = msk.scanLine(y);
519 uchar* ib = image.scanLine(y);
520 uchar bit = 0x80;
521 int i=image.width();
522 while (i--) {
523 if ( !(*mb & bit) )
524 *ib = trans;
525 bit /= 2; if ( !bit ) mb++,bit = 0x80; // ROL
526 ib++;
527 }
528 }
529 } break;
530 case 32: {
531 for ( int y=0; y<image.height(); y++ ) {
532 uchar* mb = msk.scanLine(y);
533 QRgb* ib = (QRgb*)image.scanLine(y);
534 uchar bit = 0x80;
535 int i=image.width();
536 while (i--) {
537 if ( *mb & bit )
538 *ib |= 0xff000000;
539 else
540 *ib &= 0x00ffffff;
541 bit /= 2; if ( !bit ) mb++,bit = 0x80; // ROL
542 ib++;
543 }
544 }
545 } break;
546 }
547 }
548
549 return image;
550}
551
552
553bool QPixmap::convertFromImage( const QImage &img, int conversion_flags )
554{
555 if ( img.isNull() ) {
556#if defined(QT_CHECK_NULL)
557 qWarning( "QPixmap::convertFromImage: Cannot convert a null image" );
558#endif
559 return FALSE;
560 }
561
562 QImage image = img;
563 int d = image.depth();
564 int dd = defaultDepth();
565 bool force_mono = (dd == 1 || isQBitmap() ||
566 (conversion_flags & ColorMode_Mask)==MonoOnly );
567
568 if ( force_mono ) { // must be monochrome
569 if ( d != 1 ) { // dither
570 image = image.convertDepth( 1, conversion_flags );
571 d = 1;
572 }
573 } else { // can be both
574 bool conv8 = FALSE;
575 if ( d > 8 && dd <= 8 ) { // convert to 8 bit
576 if ( (conversion_flags & DitherMode_Mask) == AutoDither )
577 conversion_flags = (conversion_flags & ~DitherMode_Mask)
578 | PreferDither;
579 conv8 = TRUE;
580 } else if ( (conversion_flags & ColorMode_Mask) == ColorOnly ) {
581 conv8 = d == 1; // native depth wanted
582 } else if ( d == 1 ) {
583 if ( image.numColors() == 2 ) {
584//@@TODO (dmik): the code below is necessary to prevent converting
585// 1-bpp images with alpha channel to 8-bpp images. it is currently
586// commented out only for compatibility with Qt/Win32; Qt/OS2 is ready
587// to handle such images properly.
588// QRgb c0 = image.color(0) | ~RGB_MASK; // Auto: convert to best
589// QRgb c1 = image.color(1) | ~RGB_MASK;
590 QRgb c0 = image.color(0); // Auto: convert to best
591 QRgb c1 = image.color(1);
592 conv8 = QMIN(c0,c1) != qRgb(0,0,0) || QMAX(c0,c1) != qRgb(255,255,255);
593 } else {
594 // eg. 1-color monochrome images (they do exist).
595 conv8 = TRUE;
596 }
597 }
598 if ( conv8 ) {
599 image = image.convertDepth( 8, conversion_flags );
600 d = 8;
601 }
602 }
603
604 if ( d == 1 ) { // 1 bit pixmap (bitmap)
605 image = image.convertBitOrder( QImage::BigEndian );
606 }
607
608 bool hasRealAlpha = FALSE;
609 if ( img.hasAlphaBuffer()
610//@@TODO (dmik): remove later.
611// &&
612// ( QApplication::winVersion() != Qt::WV_95 &&
613// QApplication::winVersion() != Qt::WV_NT )
614 ) {
615 if (image.depth() == 8) {
616 const QRgb * const rgb = img.colorTable();
617 for (int i = 0, count = img.numColors(); i < count; ++i) {
618 const int alpha = qAlpha(rgb[i]);
619 if (alpha != 0 && alpha != 0xff) {
620 hasRealAlpha = true;
621 break;
622 }
623 }
624 if (hasRealAlpha) {
625//@@TODO (dmik): also need to convert? guess yes.
626// image = image.convertDepth(32, conversion_flags);
627// d = image.depth();
628 }
629 } else if (image.depth() == 32) {
630 int i = 0;
631 while ( i<image.height() && !hasRealAlpha ) {
632 uchar *p = image.scanLine(i);
633 uchar *end = p + image.bytesPerLine();
634 p += 3;
635 while ( p < end ) {
636 if ( *p!=0 && *p!=0xff ) {
637 hasRealAlpha = TRUE;
638 break;
639 }
640 p += 4;
641 }
642 ++i;
643 }
644 }
645 }
646
647//@@TODO (dmik): temporary code. will be removed when alpha support is done.
648 if ( hasRealAlpha ) {
649 qWarning( "QPixmap::convertFromImage() for images with alpha is not yet implemented on OS/2" );
650 hasRealAlpha = FALSE;
651 }
652
653 int w = image.width();
654 int h = image.height();
655
656 if ( width() == w && height() == h && ( (d == 1 && depth() == 1) ||
657 (d != 1 && depth() != 1) ) ) {
658 if ( data->realAlphaBits && !hasRealAlpha ) {
659//@@TODO (dmik): later
660// // pixmap uses a DIB section, but image has no alpha channel, so we
661// // can't reuse the old pixmap
662// QPixmap pm(w, h, d == 1 ? 1 : -1, data->bitmap, data->optim);
663// *this = pm;
664 } else {
665 // same size etc., use the existing pixmap
666 detach();
667 if ( data->mask ) { // get rid of the mask
668 delete data->mask;
669 data->mask = 0;
670 if ( data->maskedHbm ) {
671 GpiDeleteBitmap( data->maskedHbm );
672 data->maskedHbm = 0;
673 }
674 }
675 }
676 } else {
677 // different size or depth, make a new pixmap
678 QPixmap pm(w, h, d == 1 ? 1 : -1, data->bitmap, data->optim);
679 *this = pm;
680 }
681
682 int ncols = image.numColors();
683
684 // allocate header + ncols palette entries
685 char *bmi_data = new char[ sizeof(BITMAPINFOHEADER2) + 4 * ncols ];
686 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
687 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
688 PULONG pal = (PULONG) (bmi_data + sizeof(BITMAPINFOHEADER2));
689 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
690 bmh.cx = w;
691 bmh.cy = h;
692 bmh.cPlanes = 1;
693 bmh.cBitCount = d;
694 bmh.cclrUsed = ncols;
695 bool doAlloc = ( QApplication::colorSpec() == QApplication::CustomColor
696 && QColor::hPal() );
697
698 if ( d == 1 ) {
699 // always use the black/white palette for monochrome pixmaps;
700 // otherwise GPI can swap 0s and 1s when creating a bitmap.
701 pal [0] = 0;
702 pal [1] = 0x00FFFFFF;
703 } else {
704 for ( int i=0; i<ncols; i++ ) { // copy color table
705 PRGB2 r = (PRGB2) &pal[i];
706 QRgb c = image.color(i);
707 r->bBlue = qBlue( c );
708 r->bGreen = qGreen( c );
709 r->bRed = qRed( c);
710 r->fcOptions = 0;
711 if ( doAlloc ) {
712 QColor cl( c );
713 cl.alloc();
714 }
715 }
716 }
717
718//@@TODO (dmik): later
719//#ifndef Q_OS_TEMP
720// if ( hasRealAlpha ) {
721// initAlphaPixmap( image.bits(), image.numBytes(), bmi );
722//
723// // Windows expects premultiplied alpha
724// uchar *p = image.bits();
725// uchar *b = data->realAlphaBits;
726// uchar *end = p + image.numBytes();
727// uchar alphaByte;
728// while ( p < end ) {
729// alphaByte = *(p+3);
730// if ( alphaByte == 0 ) {
731// *(b++) = 0;
732// *(b++) = 0;
733// *(b++) = 0;
734// b++;
735// p += 4;
736// } else if ( alphaByte == 255 ) {
737// b += 4;
738// p += 4;
739// } else {
740// *(b++) = ( (*(p++)) * (int)alphaByte + 127 ) / 255;
741// *(b++) = ( (*(p++)) * (int)alphaByte + 127 ) / 255;
742// *(b++) = ( (*(p++)) * (int)alphaByte + 127 ) / 255;
743// b++;
744// p++;
745// }
746// }
747// }
748//#else
749 data->realAlphaBits = 0;
750//#endif
751
752 if ( data->realAlphaBits == 0 ) {
753 // flip the image top to bottom
754 image.detach();
755 int bpl = image.bytesPerLine();
756 uchar *line = new uchar[bpl];
757 uchar *top = image.scanLine( 0 );
758 uchar *bottom = image.scanLine( h - 1 );
759 while( top < bottom ) {
760 memcpy( line, top, bpl );
761 memcpy( top, bottom, bpl );
762 memcpy( bottom, line, bpl );
763 top += bpl;
764 bottom -= bpl;
765 }
766 delete [] line;
767 GpiSetBitmapBits( hps, 0, h, (PBYTE) image.bits(), (PBITMAPINFO2) bmi_data );
768 }
769
770 if ( img.hasAlphaBuffer() ) {
771 QBitmap m;
772 m = img.createAlphaMask( conversion_flags );
773 setMask( m );
774 }
775
776 delete [] bmi_data;
777 data->uninit = FALSE;
778
779 return TRUE;
780}
781
782
783QPixmap QPixmap::grabWindow( WId window, int x, int y, int w, int h )
784{
785 RECTL rcl;
786 WinQueryWindowRect( window, &rcl );
787 if ( w <= 0 || h <= 0 ) {
788 if ( w == 0 || h == 0 ) {
789 QPixmap nullPixmap;
790 return nullPixmap;
791 }
792 if ( w < 0 )
793 w = rcl.xRight;
794 if ( h < 0 )
795 h = rcl.yTop;
796 }
797 // flip y coordinate
798 y = rcl.yTop - (y + h);
799 QPixmap pm( w, h );
800 HPS hps = WinGetPS( window );
801 POINTL pnts[] = { {0, 0}, {w, h}, {x, y} };
802 GpiBitBlt( pm.hps, hps, 3, pnts, ROP_SRCCOPY, BBO_IGNORE );
803 WinReleasePS( hps );
804 return pm;
805}
806
807#ifndef QT_NO_PIXMAP_TRANSFORMATION
808QPixmap QPixmap::xForm( const QWMatrix &matrix ) const
809{
810 int w, h; // size of target pixmap
811 int ws, hs; // size of source pixmap
812 uchar *dptr; // data in target pixmap
813 int dbpl, dbytes; // bytes per line/bytes total
814 uchar *sptr; // data in original pixmap
815 int sbpl; // bytes per line in original
816 int bpp; // bits per pixel
817 bool depth1 = depth() == 1;
818
819 if ( isNull() ) // this is a null pixmap
820 return copy();
821
822 ws = width();
823 hs = height();
824
825 QWMatrix mat( matrix.m11(), matrix.m12(), matrix.m21(), matrix.m22(), 0., 0. );
826
827 if ( matrix.m12() == 0.0F && matrix.m21() == 0.0F &&
828 matrix.m11() >= 0.0F && matrix.m22() >= 0.0F ) {
829 if ( mat.m11() == 1.0F && mat.m22() == 1.0F )
830 return *this; // identity matrix
831
832 h = qRound( mat.m22()*hs );
833 w = qRound( mat.m11()*ws );
834 h = QABS( h );
835 w = QABS( w );
836 if ( data->realAlphaBits == 0 ) {
837 QPixmap pm( w, h, depth(), optimization() );
838 POINTL ptls[] = {
839 { 0, 0 }, { w, h },
840 { 0, 0 }, { ws, hs }
841 };
842 GpiBitBlt( pm.hps, hps, 4, ptls, ROP_SRCCOPY, BBO_IGNORE );
843 if ( data->mask ) {
844 QBitmap bm =
845 data->selfmask ? *((QBitmap*)(&pm)) :
846 data->mask->xForm( matrix );
847 pm.setMask( bm );
848 }
849 return pm;
850 }
851 } else {
852 // rotation or shearing
853 QPointArray a( QRect(0,0,ws+1,hs+1) );
854 a = mat.map( a );
855 QRect r = a.boundingRect().normalize();
856 w = r.width()-1;
857 h = r.height()-1;
858 }
859
860 mat = trueMatrix( mat, ws, hs ); // true matrix
861
862 bool invertible;
863 mat = mat.invert( &invertible ); // invert matrix
864
865 if ( h == 0 || w == 0 || !invertible ) { // error, return null pixmap
866 QPixmap pm;
867 pm.data->bitmap = data->bitmap;
868 return pm;
869 }
870
871 if ( data->realAlphaBits ) {
872 bpp = 32;
873 } else {
874 bpp = depth();
875 if ( bpp > 1 && bpp < 8 )
876 bpp = 8;
877 }
878
879 sbpl = ((ws*bpp+31)/32)*4;
880 sptr = new uchar[hs*sbpl];
881 int ncols;
882 if ( bpp <= 8 ) {
883 ncols = 1 << bpp;
884 } else {
885 ncols = 0;
886 }
887
888 // allocate header + ncols palette entries
889 int bmi_data_len = sizeof(BITMAPINFOHEADER2) + 4 * ncols;
890 char *bmi_data = new char[ bmi_data_len ];
891 memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
892 BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
893 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
894 bmh.cx = ws;
895 bmh.cy = hs;
896 bmh.cPlanes = 1;
897 bmh.cBitCount = bpp;
898 bmh.cclrUsed = ncols;
899 if ( depth1 ) {
900 // always use the black/white palette for monochrome pixmaps;
901 // otherwise GPI can swap 0s and 1s when creating a bitmap.
902 PULONG pal = (PULONG) (bmi_data + sizeof(BITMAPINFOHEADER2));
903 pal[0] = 0;
904 pal[1] = 0x00FFFFFF;
905 }
906
907 int result;
908 if ( data->realAlphaBits ) {
909 memcpy( sptr, data->realAlphaBits, sbpl*hs );
910 result = 1;
911 } else {
912 result = GpiQueryBitmapBits( hps, 0, hs, (PBYTE) sptr, (PBITMAPINFO2) bmi_data );
913 }
914
915 if ( !result ) { // error, return null pixmap
916 delete [] sptr;
917 delete [] bmi_data;
918 return QPixmap( 0, 0, 0, data->bitmap, NormalOptim );
919 }
920
921 dbpl = ((w*bpp+31)/32)*4;
922 dbytes = dbpl*h;
923
924 dptr = new uchar[ dbytes ]; // create buffer for bits
925 Q_CHECK_PTR( dptr );
926 if ( depth1 )
927 memset( dptr, 0x00, dbytes );
928 else if ( bpp == 8 )
929 memset( dptr, white.pixel(), dbytes );
930 else if ( data->realAlphaBits )
931 memset( dptr, 0x00, dbytes );
932 else
933 memset( dptr, 0xff, dbytes );
934
935 int xbpl, p_inc;
936 if ( depth1 ) {
937 xbpl = (w+7)/8;
938 p_inc = dbpl - xbpl;
939 } else {
940 xbpl = (w*bpp)/8;
941 p_inc = dbpl - xbpl;
942 }
943
944 // OS/2 stores first image row at the bottom of the pixmap data,
945 // so do xForm starting from the bottom scanline to the top one
946 if ( !qt_xForm_helper( mat, 0, QT_XFORM_TYPE_MSBFIRST, bpp,
947 dptr + dbytes - dbpl, xbpl, p_inc - dbpl * 2, h,
948 sptr + (hs*sbpl) - sbpl, -sbpl, ws, hs ) ) {
949#if defined(QT_CHECK_RANGE)
950 qWarning( "QPixmap::xForm: display not supported (bpp=%d)",bpp);
951#endif
952 QPixmap pm;
953 delete [] sptr;
954 delete [] bmi_data;
955 delete [] dptr;
956 return pm;
957 }
958
959 delete [] sptr;
960
961 QPixmap pm( w, h, depth(), data->bitmap, optimization() );
962 pm.data->uninit = FALSE;
963 bmh.cx = w;
964 bmh.cy = h;
965 if ( data->realAlphaBits ) {
966 qWarning( "QPixmap::xForm() for pixmaps with alpha is not yet implemented on OS/2" );
967/// @todo (dmik) later
968// pm.initAlphaPixmap( dptr, dbytes, bmi );
969 } else {
970 GpiSetBitmapBits( pm.hps, 0, h, (PBYTE) dptr, (PBITMAPINFO2) bmi_data );
971 }
972 delete [] bmi_data;
973 delete [] dptr;
974 if ( data->mask ) {
975 QBitmap bm = data->selfmask ? *((QBitmap*)(&pm)) :
976 data->mask->xForm(matrix);
977 pm.setMask( bm );
978 }
979 return pm;
980}
981#endif // QT_NO_PIXMAP_TRANSFORMATION
982
983/*!
984 \fn HBITMAP QPixmap::hbm() const
985 \internal
986*/
987
988bool QPixmap::hasAlpha() const
989{
990 return data->realAlphaBits || data->mask;
991}
992
993bool QPixmap::hasAlphaChannel() const
994{
995 return data->realAlphaBits != 0;
996}
997
998//@@TODO (dmik): later
999//void QPixmap::convertToAlphaPixmap( bool initAlpha )
1000//{
1001// char bmi_data[sizeof(BITMAPINFO)];
1002// memset( bmi_data, 0, sizeof(BITMAPINFO) );
1003// BITMAPINFO *bmi = (BITMAPINFO*)bmi_data;
1004// BITMAPINFOHEADER *bmh = (BITMAPINFOHEADER*)bmi;
1005// bmh->biSize = sizeof(BITMAPINFOHEADER);
1006// bmh->biWidth = width();
1007// bmh->biHeight = -height(); // top-down bitmap
1008// bmh->biPlanes = 1;
1009// bmh->biBitCount = 32;
1010// bmh->biCompression = BI_RGB;
1011// bmh->biSizeImage = width() * height() * 4;
1012// bmh->biClrUsed = 0;
1013// bmh->biClrImportant = 0;
1014//
1015// QPixmap pm( width(), height(), -1 );
1016// pm.initAlphaPixmap( 0, 0, bmi );
1017//
1018//#ifndef Q_OS_TEMP
1019// GetDIBits( qt_display_dc(), DATA_HBM, 0, height(), pm.data->realAlphaBits, bmi, DIB_RGB_COLORS );
1020// if ( initAlpha ) {
1021// // In bitBlt(), if the destination has an alpha channel and the source
1022// // doesn't have one, we bitBlt() the source with the destination's
1023// // alpha channel. In that case, there is no need to initialize the
1024// // alpha values.
1025// uchar *p = pm.data->realAlphaBits;
1026// uchar *pe = p + bmh->biSizeImage;
1027// if ( mask() ) {
1028// QImage msk = mask()->convertToImage();
1029// int i = 0;
1030// int w = width();
1031// int backgroundIndex = msk.color(0) == Qt::color0.rgb() ? 0 : 1;
1032// while ( p < pe ) {
1033// if ( msk.pixelIndex( i%w, i/w ) == backgroundIndex ) {
1034// *(p++) = 0x00;
1035// *(p++) = 0x00;
1036// *(p++) = 0x00;
1037// *(p++) = 0x00;
1038// } else {
1039// p += 3;
1040// *(p++) = 0xff;
1041// }
1042// ++i;
1043// }
1044// } else {
1045// p += 3;
1046// while ( p < pe ) {
1047// *p = 0xff;
1048// p += 4;
1049// }
1050// }
1051// }
1052//#else
1053// memcpy( pm.data->ppvBits, data->ppvBits, bmh->biSizeImage );
1054//#endif
1055// if ( mask() )
1056// pm.setMask( *mask() );
1057//
1058// *this = pm;
1059//}
1060//
1061//void QPixmap::bitBltAlphaPixmap( QPixmap *dst, int dx, int dy,
1062// const QPixmap *src, int sx, int sy,
1063// int sw, int sh, bool useDstAlpha )
1064//{
1065// if ( sw < 0 )
1066// sw = src->width() - sx;
1067// else
1068// sw = QMIN( src->width()-sx, sw );
1069// sw = QMIN( dst->width()-dx, sw );
1070//
1071// if ( sh < 0 )
1072// sh = src->height() - sy ;
1073// else
1074// sh = QMIN( src->height()-sy, sh );
1075// sh = QMIN( dst->height()-dy, sh );
1076//
1077// if ( sw <= 0 || sh <= 0 )
1078// return;
1079//
1080//#ifndef Q_OS_TEMP
1081// GdiFlush();
1082//#endif
1083// uchar *sBits = src->data->realAlphaBits + ( sy * src->width() + sx ) * 4;
1084// uchar *dBits = dst->data->realAlphaBits + ( dy * dst->width() + dx ) * 4;
1085// int sw4 = sw * 4;
1086// int src4 = src->width() * 4;
1087// int dst4 = dst->width() * 4;
1088// if ( useDstAlpha ) {
1089// // Copy the source pixels premultiplied with the destination's alpha
1090// // channel. The alpha channel remains the destination's alpha channel.
1091// uchar *sCur;
1092// uchar *dCur;
1093// uchar alphaByte;
1094// for ( int i=0; i<sh; i++ ) {
1095// sCur = sBits;
1096// dCur = dBits;
1097// for ( int j=0; j<sw; j++ ) {
1098// alphaByte = *(dCur+3);
1099// if ( alphaByte == 0 || (*(sCur+3)) == 0 ) {
1100// dCur += 4;
1101// sCur += 4;
1102// } else if ( alphaByte == 255 ) {
1103// *(dCur++) = *(sCur++);
1104// *(dCur++) = *(sCur++);
1105// *(dCur++) = *(sCur++);
1106// dCur++;
1107// sCur++;
1108// } else {
1109// *(dCur++) = ( (*(sCur++)) * (int)alphaByte + 127 ) / 255;
1110// *(dCur++) = ( (*(sCur++)) * (int)alphaByte + 127 ) / 255;
1111// *(dCur++) = ( (*(sCur++)) * (int)alphaByte + 127 ) / 255;
1112// dCur++;
1113// sCur++;
1114// }
1115// }
1116// sBits += src4;
1117// dBits += dst4;
1118// }
1119// } else {
1120// // Copy the source into the destination. Use the source's alpha
1121// // channel.
1122// for ( int i=0; i<sh; i++ ) {
1123// memcpy( dBits, sBits, sw4 );
1124// sBits += src4;
1125// dBits += dst4;
1126// }
1127// }
1128//}
1129
1130// Prepares for painting the masked pixmap: precomposes and selects the
1131// masked pixmap into this pixmap's hps. If prepare = FALSE, it does the
1132// cleanup. Currently used from ::bitBlt().
1133void QPixmap::prepareForMasking( bool prepare )
1134{
1135 if ( !data->mask || data->selfmask )
1136 return;
1137 if ( prepare ) {
1138 if ( !data->maskedHbm ) {
1139 GpiSetBitmap( hps, 0 );
1140 BITMAPINFOHEADER2 bmh;
1141 memset( &bmh, 0, sizeof(BITMAPINFOHEADER2) );
1142 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
1143 bmh.cx = data->w;
1144 bmh.cy = data->h;
1145 bmh.cPlanes = 1;
1146 bmh.cBitCount = data->d;
1147 data->maskedHbm = GpiCreateBitmap( hps, &bmh, 0, NULL, NULL );
1148 GpiSetBitmap( hps, data->maskedHbm );
1149 POINTL ptls[] = {
1150 // dst is inclusive
1151 { 0, 0 }, { data->w - 1, data->h - 1 },
1152 { 0, 0 }, { data->w, data->h },
1153 };
1154 GpiWCBitBlt( hps, data->hbm, 4, ptls, ROP_SRCCOPY, BBO_IGNORE );
1155 // dst is exclusive
1156 ptls[1].x++;
1157 ptls[1].y++;
1158 // make transparent pixels black
1159 const ULONG AllImageAttrs =
1160 IBB_COLOR | IBB_BACK_COLOR |
1161 IBB_MIX_MODE | IBB_BACK_MIX_MODE;
1162 IMAGEBUNDLE oldIb;
1163 GpiQueryAttrs( hps, PRIM_IMAGE, AllImageAttrs, (PBUNDLE) &oldIb );
1164 IMAGEBUNDLE newIb = {
1165 CLR_TRUE, CLR_FALSE, FM_OVERPAINT, BM_OVERPAINT
1166 };
1167 GpiSetAttrs( hps, PRIM_IMAGE, AllImageAttrs, 0, (PBUNDLE) &newIb );
1168 GpiBitBlt( hps, data->mask->hps, 3, ptls, ROP_SRCAND, BBO_IGNORE );
1169 GpiSetAttrs( hps, PRIM_IMAGE, AllImageAttrs, 0, (PBUNDLE) &oldIb );
1170 } else {
1171 GpiSetBitmap( hps, data->maskedHbm );
1172 }
1173 } else {
1174 GpiSetBitmap( hps, data->hbm );
1175 // delete the precomposed masked pixmap when memory optimization
1176 // is in force or when no precomosing was done
1177 if (
1178 data->maskedHbm &&
1179 (data->optim != NormalOptim && data->optim != BestOptim)
1180 ) {
1181 GpiDeleteBitmap( data->maskedHbm );
1182 data->maskedHbm = 0;
1183 }
1184 }
1185}
1186
1187void QPixmap::attachHandle( HBITMAP hbm )
1188{
1189 if ( paintingActive() )
1190 return;
1191
1192 BITMAPINFOHEADER bmh;
1193 if (!GpiQueryBitmapParameters( hbm, &bmh ))
1194 return;
1195
1196 if ( !data->uninit && !isNull() ) { // has existing pixmap
1197 deref();
1198 init( 0, 0, 0, FALSE, defOptim );
1199 }
1200
1201 data->uninit = FALSE;
1202 data->w = bmh.cx;
1203 data->h = bmh.cy;
1204 data->d = bmh.cPlanes * bmh.cBitCount;
1205
1206 hps = alloc_mem_ps( bmh.cx, bmh.cy );
1207 data->hbm = hbm;
1208
1209 GpiSetBitmap( hps, data->hbm );
1210}
1211
1212HBITMAP QPixmap::detachHandle()
1213{
1214 if ( paintingActive() )
1215 return 0;
1216
1217 HBITMAP hbm = data->hbm;
1218
1219 // do what deref() will not do after data->hbm is set to 0
1220 if ( hps )
1221 GpiSetBitmap( hps, 0 );
1222
1223 data->hbm = 0;
1224 deref();
1225
1226 return hbm;
1227}
1228
1229Q_EXPORT void copyBlt( QPixmap *dst, int dx, int dy,
1230 const QPixmap *src, int sx, int sy, int sw, int sh )
1231{
1232 if ( ! dst || ! src || sw == 0 || sh == 0 || dst->depth() != src->depth() ) {
1233#ifdef QT_CHECK_NULL
1234 Q_ASSERT( dst != 0 );
1235 Q_ASSERT( src != 0 );
1236#endif
1237 return;
1238 }
1239
1240 // copy mask data
1241 if ( src->data->mask ) {
1242 if ( ! dst->data->mask ) {
1243 dst->data->mask = new QBitmap( dst->width(), dst->height() );
1244
1245 // new masks are fully opaque by default
1246 dst->data->mask->fill( Qt::color1 );
1247 } else if ( dst->data->maskedHbm ) {
1248 // reset the precomposed masked pixmap
1249 GpiDeleteBitmap( dst->data->maskedHbm );
1250 dst->data->maskedHbm = 0;
1251 }
1252
1253 bitBlt( dst->data->mask, dx, dy,
1254 src->data->mask, sx, sy, sw, sh, Qt::CopyROP, TRUE );
1255 }
1256
1257 if ( src->data->realAlphaBits ) {
1258 qWarning( "::copyBlt() for pixmaps with alpha is not yet implemented on OS/2" );
1259//@@TODO (dmik): later
1260// if ( !dst->data->realAlphaBits )
1261// dst->convertToAlphaPixmap();
1262// QPixmap::bitBltAlphaPixmap( dst, dx, dy, src, sx, sy, sw, sh, FALSE );
1263 } else {
1264 // copy pixel data
1265 bitBlt( dst, dx, dy, src, sx, sy, sw, sh, Qt::CopyROP, TRUE );
1266 }
1267}
Note: See TracBrowser for help on using the repository browser.