Ignore:
Timestamp:
Jan 29, 2006, 8:56:21 PM (20 years ago)
Author:
dmik
Message:

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kernel/qpixmap_pm.cpp

    r56 r59  
    9595}
    9696
    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 
    11497
    11598void QPixmap::init( int w, int h, int d, bool bitmap, Optimization optim )
     
    123106
    124107    static int serial = 0;
    125     int dd = defaultDepth();
     108    const int dd = defaultDepth();
    126109
    127110    if ( optim == DefaultOptim )                // use default optimization
     
    162145    bmh.cy = h;
    163146    bmh.cPlanes = 1;
    164     if ( data->d == dd )                        // compatible bitmap
     147    if ( data->d == 1 )                         // monocrome bitmap
     148        bmh.cBitCount = 1;
     149    else                                        // compatible bitmap
    165150        bmh.cBitCount = dd;
    166     else                                        // monocrome bitmap
    167         bmh.cBitCount = 1;
    168151    data->hbm = GpiCreateBitmap( hps, &bmh, 0, NULL, NULL );
    169152
     
    188171        if ( hps )
    189172            GpiSetBitmap( hps, 0 );
     173        if ( data->hasRealAlpha && data->realAlphaBits ) {
     174            delete[] data->realAlphaBits;
     175            data->realAlphaBits = 0;
     176        }
    190177        if ( data->mask ) {
    191178            delete data->mask;
     
    221208    data->d = 1;
    222209
    223     int bitsbpl = (w+7)/8;                      // original # bytes per line
     210    int bitsbpl = (w + 7) / 8;                  // original # bytes per line
    224211
    225212    int bpl = ((w + 31) / 32) * 4;              // bytes per scanline,
     
    288275    static int dd = 0;
    289276    if ( dd == 0 ) {
    290         LONG formats [2];
     277        LONG formats[ 2 ];
    291278        GpiQueryDeviceBitmapFormats( qt_display_ps(), 2, formats );
    292         dd = formats [0] * formats [1];
     279        dd = formats[ 0 ] * formats[ 1 ];
    293280    }
    294281    return dd;
     
    382369    int w = width();
    383370    int h = height();
    384     const QBitmap *m = data->realAlphaBits ? 0 : mask();
     371    const QBitmap *m = data->hasRealAlpha ? 0 : mask();
    385372    int d = depth();
    386373    int ncols = 2;
     
    392379        d = 32;                                 //   > 8  ==> 32
    393380        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           
    394388    }
    395389
    396390    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     }
    435391
    436392    // allocate header + ncols palette entries
     
    447403    GpiQueryBitmapBits( hps, 0, h, (PBYTE) image.bits(), (PBITMAPINFO2) bmi_data );
    448404
     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   
    449424    // flip the image top to bottom
    450425    {
     
    550525}
    551526
    552 
    553527bool QPixmap::convertFromImage( const QImage &img, int conversion_flags )
    554528{
     
    582556        } else if ( d == 1 ) {
    583557            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;
     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).
    590569                QRgb c0 = image.color(0);       // Auto: convert to best
    591570                QRgb c1 = image.color(1);
     
    607586
    608587    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     ) {
     588    if ( img.hasAlphaBuffer() ) {
    615589        if (image.depth() == 8) {
    616590            const QRgb * const rgb = img.colorTable();
     
    623597            }
    624598            if (hasRealAlpha) {
    625 //@@TODO (dmik): also need to convert? guess yes.
    626 //              image = image.convertDepth(32, conversion_flags);
    627 //              d = image.depth();
     599                image = image.convertDepth(32, conversion_flags);
     600                d = image.depth();
    628601            }
    629602        } else if (image.depth() == 32) {
     
    645618    }
    646619
    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 
    653620    int w = image.width();
    654621    int h = image.height();
    655622
    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         }
     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        }
    676634    } else {
    677635        // different size or depth, make a new pixmap
    678         QPixmap pm(w, h, d == 1 ? 1 : -1, data->bitmap, data->optim);
     636        QPixmap pm( w, h, d == 1 ? 1 : -1, data->bitmap, data->optim );
    679637        *this = pm;
    680638    }
     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           
    681647
    682648    int   ncols    = image.numColors();
     
    707673            r->bBlue = qBlue( c );
    708674            r->bGreen = qGreen( c );
    709             r->bRed = qRed( c);
     675            r->bRed = qRed( c );
    710676            r->fcOptions = 0;
    711677            if ( doAlloc ) {
     
    716682    }
    717683
    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     }
     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 );
    769729
    770730    if ( img.hasAlphaBuffer() ) {
    771731        QBitmap m;
    772732        m = img.createAlphaMask( conversion_flags );
    773         setMask( m );
     733        data->mask = new QBitmap( m );
    774734    }
    775735
     
    834794        h = QABS( h );
    835795        w = QABS( w );
    836         if ( data->realAlphaBits == 0 ) {
     796        if ( !data->hasRealAlpha ) {
    837797            QPixmap pm( w, h, depth(), optimization() );
    838798            POINTL ptls[] = {
     
    869829    }
    870830
    871     if ( data->realAlphaBits ) {
     831    if ( data->hasRealAlpha ) {
    872832        bpp = 32;
    873833    } else {
     
    877837    }
    878838
    879     sbpl = ((ws*bpp+31)/32)*4;
    880     sptr = new uchar[hs*sbpl];
     839    sbpl = ((ws * bpp + 31) / 32) * 4;
     840    sptr = new uchar[ hs * sbpl ];
    881841    int ncols;
    882842    if ( bpp <= 8 ) {
     
    886846    }
    887847
     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   
    888856    // allocate header + ncols palette entries
    889857    int bmi_data_len = sizeof(BITMAPINFOHEADER2) + 4 * ncols;
     
    905873    }
    906874
    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;
     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;
    923895
    924896    dptr = new uchar[ dbytes ];                 // create buffer for bits
     
    928900    else if ( bpp == 8 )
    929901        memset( dptr, white.pixel(), dbytes );
    930     else if ( data->realAlphaBits )
     902    else if ( data->hasRealAlpha )
    931903        memset( dptr, 0x00, dbytes );
    932904    else
     
    935907    int   xbpl, p_inc;
    936908    if ( depth1 ) {
    937         xbpl  = (w+7)/8;
     909        xbpl  = (w + 7) / 8;
    938910        p_inc = dbpl - xbpl;
    939911    } else {
    940         xbpl  = (w*bpp)/8;
     912        xbpl  = (w * bpp) / 8;
    941913        p_inc = dbpl - xbpl;
    942914    }
     
    963935    bmh.cx = w;
    964936    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;
     937    GpiSetBitmapBits( pm.hps, 0, h, (PBYTE) dptr, (PBITMAPINFO2) bmi_data );
     938   
    974939    if ( data->mask ) {
    975940        QBitmap bm = data->selfmask ? *((QBitmap*)(&pm)) :
     
    977942        pm.setMask( bm );
    978943    }
     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   
    979967    return pm;
    980968}
     
    988976bool QPixmap::hasAlpha() const
    989977{
    990     return data->realAlphaBits || data->mask;
     978    return data->hasRealAlpha || data->mask;
    991979}
    992980
    993981bool QPixmap::hasAlphaChannel() const
    994982{
    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 (with transparent pixels made black) into this pixmap's hps.
    1132 // If prepare = FALSE, it does the cleanup. Currently used in ::bitBlt()
    1133 // and in QPixmap::createIcon().
    1134 void QPixmap::prepareForMasking( bool prepare )
     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 */ )
    1135997{
    1136998    if ( !data->mask || data->selfmask )
     
    11751037        GpiSetBitmap( hps, data->hbm );
    11761038        // delete the precomposed masked pixmap when memory optimization
    1177         // is in force or when no precomosing was done
    1178         if (
    1179             data->maskedHbm &&
    1180             (data->optim != NormalOptim && data->optim != BestOptim)
    1181         ) {
     1039        // is in force (or force is TRUE)
     1040        if ( data->maskedHbm && (force || (data->optim != NormalOptim &&
     1041                                           data->optim != BestOptim)) ) {
    11821042            GpiDeleteBitmap( data->maskedHbm );
    11831043            data->maskedHbm = 0;
     
    12951155}
    12961156
     1157void QPixmap::unfoldAlphaChannel()
     1158{
     1159    // do nothing if there is no alpha channel or if it is already unfolded
     1160    // (i.e. stored in a separate array)
     1161    if ( !data->hasRealAlpha || data->realAlphaBits )
     1162        return;
     1163
     1164    Q_ASSERT( data->d == 32 );
     1165    if ( !data->d == 32 )
     1166        return;
     1167   
     1168    data->realAlphaBits = new uchar[ data->w * data->h ];
     1169   
     1170    // no space for palette, since the depth is 32-bpp
     1171    BITMAPINFOHEADER2 bmh;
     1172    memset( &bmh, 0, sizeof(BITMAPINFOHEADER2) );
     1173    bmh.cbFix = sizeof(BITMAPINFOHEADER2);
     1174    bmh.cx = data->w;
     1175    bmh.cy = data->h;
     1176    bmh.cPlanes = 1;
     1177    bmh.cBitCount = data->d;
     1178   
     1179    int bpl = ((data->d * data->w + 31) / 32) * 4;
     1180    uchar *bits = new uchar [bpl * data->h];
     1181   
     1182    GpiQueryBitmapBits( hps, 0, data->h, (PBYTE) bits, (PBITMAPINFO2) &bmh );
     1183
     1184    int bpx = data->d / 8;
     1185    int inc = bpl - bpx * data->w;
     1186    uchar *src = bits + 3; // move to the alpha byte
     1187    uchar *dst = data->realAlphaBits;
     1188    for ( int y = 0; y < data->h; ++ y ) {
     1189        for ( int x = 0; x < data->w; ++ x ) {
     1190            *(dst++) = *src;
     1191            src += bpx;
     1192        }
     1193        src += inc;
     1194    }
     1195   
     1196    delete[] bits;
     1197}
     1198
     1199/**
     1200 *  \internal
     1201 *  Converts the pixmap (actually, the pixmap's mask, if any) to the alpha
     1202 *  channel. Implies #unfoldAlphaChannel().
     1203 */
     1204void QPixmap::convertToAlpha()
     1205{
     1206    if ( isNull() || data->hasRealAlpha )
     1207        return;
     1208   
     1209    if ( data->mask ) {
     1210        // allocate header + 2 palette entries
     1211        char *bmi_data = new char[ sizeof(BITMAPINFOHEADER2) + 8 ];
     1212        memset( bmi_data, 0, sizeof(BITMAPINFOHEADER2) );
     1213        BITMAPINFOHEADER2 &bmh = *(PBITMAPINFOHEADER2) bmi_data;
     1214        bmh.cbFix = sizeof(BITMAPINFOHEADER2);
     1215        bmh.cx = data->w;
     1216        bmh.cy = data->h;
     1217        bmh.cPlanes = 1;
     1218        bmh.cBitCount = 1;
     1219        bmh.cclrUsed = 2;
     1220       
     1221        int bpl = ((data->w + 31) / 32) * 4;
     1222        uchar *bits = new uchar [bpl * data->h];
     1223       
     1224        GpiQueryBitmapBits( data->mask->hps, 0, data->h, (PBYTE) bits,
     1225                            (PBITMAPINFO2) bmi_data );
     1226
     1227        data->realAlphaBits = new uchar[ data->w * data->h ];
     1228
     1229        int inc = bpl - data->w / 8;
     1230        uchar *src = bits;
     1231        uchar *dst = data->realAlphaBits;
     1232        uchar m = 0x80;
     1233        for ( int y = 0; y < data->h; ++ y ) {
     1234            for ( int x = 0; x < data->w; ++ x ) {
     1235                *(dst ++) = (*src) & m ? 0xFF : 0x00;
     1236                m >>= 1;
     1237                if ( !m ) {
     1238                    m = 0x80;
     1239                    ++ src;
     1240                }
     1241            }
     1242            src += inc;
     1243        }
     1244       
     1245        data->hasRealAlpha = TRUE;
     1246       
     1247        delete[] bits;
     1248        delete[] bmi_data;
     1249    } else {
     1250        data->realAlphaBits = new uchar[ data->w * data->h ];
     1251        memset( data->realAlphaBits, 0xFF, data->w * data->h );
     1252        data->hasRealAlpha = TRUE;
     1253    }
     1254}
     1255
     1256/**
     1257 *  \internal
     1258 *  This depth is used when querying and setting bitmap bits for pixmaps
     1259 *  with alpha channel, either 24 or 32 (depending on the video driver caps).
     1260 *  \note This depth is not used to create bitmaps (#defaultDepth() is always
     1261 *  in charge for that purpose).
     1262 */
     1263//static
     1264int QPixmap::trueColorDepth()
     1265{
     1266    static int tcd = 0;
     1267    if ( tcd == 0 ) {
     1268        HDC display_dc = GpiQueryDevice( qt_display_ps() );
     1269        LONG formatCnt = 0;
     1270        DevQueryCaps( display_dc, CAPS_BITMAP_FORMATS, 1, &formatCnt );
     1271        LONG *formats = new LONG[ formatCnt * 2 ];
     1272        GpiQueryDeviceBitmapFormats( qt_display_ps(), formatCnt * 2, formats );
     1273        for( int i = 0; i < formatCnt * 2; i += 2 ) {
     1274            if ( formats[ i ] == 1 && formats[ i + 1 ] == 32 ) {
     1275                tcd = 32;
     1276                break;
     1277            }
     1278        }
     1279        delete[] formats;
     1280        // if the 32-bpp format is not supported, we assume the 24-bpp
     1281        // format that must be supported by all video drivers
     1282        if ( tcd == 0 )
     1283            tcd = 24;
     1284    }
     1285    return tcd;
     1286}
     1287
    12971288/*!
    12981289    \internal
     
    13061297    \param mini pixmap for a mini-sized pointer/icon
    13071298   
     1299    \return PM handle of the created pointer or 0 in case of any error
     1300   
    13081301    \note Due to a bug in WinCreatePointerIndirect, you can specify either
    13091302    \a normal pixmap or \a mini pixmap, but not both (if both are specified,
    1310     \a normal will be used). This may be fixed later.
     1303    \a normal will be used). PM will use scaling to draw a pointer of the
     1304    other size when necessary. This bug may be fixed later.
     1305   
     1306    \warning This function is not portable.   
    13111307*/
    13121308// static
     
    13161312    // Due to a bug in WinCreatePointerIndirect (it always ignores
    13171313    // hbmMiniPointer and hbmMiniColor fields), we can specify either a normal
    1318     // icon (and get a mini icon autocreated by PM) or a mini icon (with a
    1319     // normal icon autocreated by PM), but not both. This methods still accepts
    1320     // pixmaps for both icon sizes (assuming that we will find a workaround one
    1321     // day) but uses only one of them.
     1314    // icon, but not both. This methods still accepts pixmaps for both icon
     1315    // sizes (assuming that we will find a workaround one day) but uses only
     1316    // one of them.
    13221317   
    13231318    if ( normal && !normal->isNull() ) {
     
    13471342        return;
    13481343    }
    1349 
     1344   
     1345    if ( sw < 0 )
     1346        sw = src->width() - sx;
     1347    if ( sh < 0 )
     1348        sh = src->height() - sy;
     1349   
     1350    // ensure coordinates are within borders, clip if necessary
     1351    if ( sx < 0 || sy < 0 || sx + sw > src->width() || sy + sh > src->height() ||
     1352         dx < 0 || dy < 0 || dx + sw > dst->width() || dy + sh > dst->height() )
     1353    {
     1354        int tx = dx - sx;
     1355        int ty = dy - sy;
     1356        QRect dr( 0, 0, dst->width(), dst->height() ); // dst rect
     1357        QRect sr( tx, ty, src->width(), src->height() ); // src rect in dst coords
     1358        QRect bltr( dx, dy, sw, sh ); // blit rect in dst coords
     1359        bltr &= (dr & sr);
     1360        if (bltr.isEmpty())
     1361            return;
     1362        dx = bltr.x();
     1363        dy = bltr.y();
     1364        sx = dx - tx;
     1365        sy = dy - ty;
     1366        sw = bltr.width();
     1367        sh = bltr.height();
     1368    }
     1369   
     1370    dst->detach();
     1371       
    13501372    // copy mask data
    13511373    if ( src->data->mask ) {
    1352         if ( ! dst->data->mask ) {
     1374        if ( !dst->data->mask ) {
    13531375            dst->data->mask = new QBitmap( dst->width(), dst->height() );
    1354 
    13551376            // new masks are fully opaque by default
    13561377            dst->data->mask->fill( Qt::color1 );
    13571378        } else if ( dst->data->maskedHbm ) {
    13581379            // reset the precomposed masked pixmap
    1359             GpiDeleteBitmap( dst->data->maskedHbm );
    1360             dst->data->maskedHbm = 0;
     1380            dst->prepareForMasking( FALSE, TRUE );
    13611381        }
    13621382
     
    13641384                src->data->mask, sx, sy, sw, sh, Qt::CopyROP, TRUE );
    13651385    }
    1366 
    1367     if ( src->data->realAlphaBits ) {
    1368         qWarning( "::copyBlt() for pixmaps with alpha is not yet implemented on OS/2" );
    1369 //@@TODO (dmik): later
    1370 //      if ( !dst->data->realAlphaBits )
    1371 //          dst->convertToAlphaPixmap();
    1372 //      QPixmap::bitBltAlphaPixmap( dst, dx, dy, src, sx, sy, sw, sh, FALSE );
    1373     } else {
    1374         // copy pixel data
    1375         bitBlt( dst, dx, dy, src, sx, sy, sw, sh, Qt::CopyROP, TRUE );
    1376     }
    1377 }
     1386   
     1387    // copy alpha bits
     1388    if ( src->data->hasRealAlpha ||
     1389         (src->data->mask && dst->data->hasRealAlpha) ) {
     1390        if ( src->data->hasRealAlpha )
     1391            const_cast <QPixmap *> (src)->unfoldAlphaChannel();
     1392        else
     1393            const_cast <QPixmap *> (src)->convertToAlpha();
     1394        if ( dst->data->hasRealAlpha )
     1395            dst->unfoldAlphaChannel();
     1396        else
     1397            dst->convertToAlpha();
     1398        uchar *srca = src->data->realAlphaBits + src->width() * sy + sx;
     1399        uchar *dsta = dst->data->realAlphaBits + dst->width() * dy + dx;
     1400        for ( int y = 0; y < sh; ++ y ) {
     1401            memcpy( dsta, srca, sw );
     1402            srca += src->width();
     1403            dsta += dst->width();
     1404        }
     1405    }
     1406   
     1407    // copy pixel data
     1408    bitBlt( dst, dx, dy, src, sx, sy, sw, sh, Qt::CopyROP, TRUE );
     1409}
Note: See TracChangeset for help on using the changeset viewer.