diff options
-rw-r--r-- | tdegtk/tqtcairopainter.cpp | 180 | ||||
-rw-r--r-- | tdegtk/tqtcairopainter.h | 1 | ||||
-rw-r--r-- | tests/test-painter.cpp | 9 |
3 files changed, 131 insertions, 59 deletions
diff --git a/tdegtk/tqtcairopainter.cpp b/tdegtk/tqtcairopainter.cpp index 95c86c4..f45bce2 100644 --- a/tdegtk/tqtcairopainter.cpp +++ b/tdegtk/tqtcairopainter.cpp @@ -36,6 +36,12 @@ #define SET_BIT(x, y) (x |= 1 << y) #define TEST_BIT(x, y) ((x & (1 << y)) >> y) +// Little endian +#define ARGB_A_BYTE_NUMBER 3 +#define ARGB_R_BYTE_NUMBER 2 +#define ARGB_G_BYTE_NUMBER 1 +#define ARGB_B_BYTE_NUMBER 0 + cairo_surface_t* TQImageToCairoSurface(TQImage origimg) { cairo_surface_t* ret; @@ -98,24 +104,135 @@ void TQt3CairoPaintDevice::resetIntermediateSurface() { m_intermediateSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); } +inline void standardAlphaToPremultipliedAlpha(unsigned char *a, unsigned char *r, unsigned char *g, unsigned char *b) { + register double alpha_adjust; + + alpha_adjust = (*a / 255.0); + *r = char( *r * alpha_adjust ); + *g = char( *g * alpha_adjust ); + *b = char( *b * alpha_adjust ); + *a = char( *a * 1.0 ); +} + +inline void premultipliedAlphaToStandardAlpha(unsigned char *a, unsigned char *r, unsigned char *g, unsigned char *b) { + register double alpha_adjust; + + alpha_adjust = (*a / 255.0); + *r = char( *r / alpha_adjust ); + *g = char( *g / alpha_adjust ); + *b = char( *b / alpha_adjust ); + *a = char( *a / 1.0 ); +} + void TQt3CairoPaintDevice::transferIntermediateSurface() { + bool overlayMerge = true; cairo_surface_flush(m_intermediateSurface); + + if (m_rop != TQPainter::CopyROP) { + overlayMerge = false; + cairo_surface_flush(m_surface); + cairo_surface_flush(m_intermediateSurface); + register int height = cairo_image_surface_get_height(m_surface); + register int width = cairo_image_surface_get_width(m_surface); + register int stride = cairo_format_stride_for_width(cairo_image_surface_get_format(m_surface), width); + cairo_surface_t *usableDeviceSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + cairo_t *copyPainter = cairo_create(usableDeviceSurface); + cairo_set_source_surface(copyPainter, m_surface, 0, 0); + cairo_set_operator(copyPainter, CAIRO_OPERATOR_SOURCE); + cairo_paint(copyPainter); + cairo_surface_flush(usableDeviceSurface); + cairo_destroy(copyPainter); + unsigned char* device_surface_data = cairo_image_surface_get_data(usableDeviceSurface); + unsigned char* intermediate_surface_data = cairo_image_surface_get_data(m_intermediateSurface); + register int x; + register int y; + register long long offset; + register unsigned char devicePixel_a; + register unsigned char devicePixel_r; + register unsigned char devicePixel_g; + register unsigned char devicePixel_b; + register unsigned char intermediatePixel_a; + register unsigned char intermediatePixel_r; + register unsigned char intermediatePixel_g; + register unsigned char intermediatePixel_b; + register unsigned char combinedPixel_a; + register unsigned char combinedPixel_r; + register unsigned char combinedPixel_g; + register unsigned char combinedPixel_b; + // Execute the desired raster operation + // WARNING + // This is VERY SLOW + for (y=0; y<height; y++) { + for (x=0; x<stride; x=x+4) { + offset = (y*stride)+x; + + // Convert from premultiplied ARGB + premultipliedAlphaToStandardAlpha(intermediate_surface_data+offset+ARGB_A_BYTE_NUMBER, intermediate_surface_data+offset+ARGB_R_BYTE_NUMBER, intermediate_surface_data+offset+ARGB_G_BYTE_NUMBER, intermediate_surface_data+offset+ARGB_B_BYTE_NUMBER); + intermediatePixel_a = (*(intermediate_surface_data+offset+ARGB_A_BYTE_NUMBER)); + intermediatePixel_r = (*(intermediate_surface_data+offset+ARGB_R_BYTE_NUMBER)); + intermediatePixel_g = (*(intermediate_surface_data+offset+ARGB_G_BYTE_NUMBER)); + intermediatePixel_b = (*(intermediate_surface_data+offset+ARGB_B_BYTE_NUMBER)); + if (intermediatePixel_a != 0) { + // Alpha channel of intermediate pixel was set; gather data for bitwise operation + premultipliedAlphaToStandardAlpha(device_surface_data+offset+ARGB_A_BYTE_NUMBER, device_surface_data+offset+ARGB_R_BYTE_NUMBER, device_surface_data+offset+ARGB_G_BYTE_NUMBER, device_surface_data+offset+ARGB_B_BYTE_NUMBER); + devicePixel_a = (*(device_surface_data+offset+ARGB_A_BYTE_NUMBER)); + devicePixel_r = (*(device_surface_data+offset+ARGB_R_BYTE_NUMBER)); + devicePixel_g = (*(device_surface_data+offset+ARGB_G_BYTE_NUMBER)); + devicePixel_b = (*(device_surface_data+offset+ARGB_B_BYTE_NUMBER)); + + // Perform requested bitwise operation + if (m_rop == TQPainter::XorROP) { + combinedPixel_a = devicePixel_a; + combinedPixel_r = devicePixel_r ^ intermediatePixel_r; + combinedPixel_g = devicePixel_g ^ intermediatePixel_g; + combinedPixel_b = devicePixel_b ^ intermediatePixel_b; + } + else { + tqWarning("TQt3CairoPaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", m_rop); + combinedPixel_a = devicePixel_a; + combinedPixel_r = devicePixel_r; + combinedPixel_g = devicePixel_g; + combinedPixel_b = devicePixel_b; + } + + // Convert to premultiplied ARGB + (*(intermediate_surface_data+offset+ARGB_A_BYTE_NUMBER)) = combinedPixel_a; + (*(intermediate_surface_data+offset+ARGB_R_BYTE_NUMBER)) = combinedPixel_r; + (*(intermediate_surface_data+offset+ARGB_G_BYTE_NUMBER)) = combinedPixel_g; + (*(intermediate_surface_data+offset+ARGB_B_BYTE_NUMBER)) = combinedPixel_b; + standardAlphaToPremultipliedAlpha(intermediate_surface_data+offset+ARGB_A_BYTE_NUMBER, intermediate_surface_data+offset+ARGB_R_BYTE_NUMBER, intermediate_surface_data+offset+ARGB_G_BYTE_NUMBER, intermediate_surface_data+offset+ARGB_B_BYTE_NUMBER); + } + else { + // Lossless copy of premultiplied ARGB pixel values + (*(intermediate_surface_data+offset+ARGB_A_BYTE_NUMBER)) = (*(device_surface_data+offset+ARGB_A_BYTE_NUMBER)); + (*(intermediate_surface_data+offset+ARGB_R_BYTE_NUMBER)) = (*(device_surface_data+offset+ARGB_R_BYTE_NUMBER)); + (*(intermediate_surface_data+offset+ARGB_G_BYTE_NUMBER)) = (*(device_surface_data+offset+ARGB_G_BYTE_NUMBER)); + (*(intermediate_surface_data+offset+ARGB_B_BYTE_NUMBER)) = (*(device_surface_data+offset+ARGB_B_BYTE_NUMBER)); + } + } + } + cairo_surface_mark_dirty(m_intermediateSurface); + cairo_surface_destroy(usableDeviceSurface); + } + if (!m_clipRegionEnabled) { // Clipping disabled cairo_set_source_surface(m_devicePainter, m_intermediateSurface, 0, 0); - cairo_set_operator(m_devicePainter, CAIRO_OPERATOR_SOURCE); + cairo_set_operator(m_devicePainter, overlayMerge?CAIRO_OPERATOR_OVER:CAIRO_OPERATOR_SOURCE); cairo_paint(m_devicePainter); } else { // Clipping enabled cairo_surface_t* maskSurface = TQImageToCairoSurface(m_clipRegion); cairo_mask_surface(m_devicePainter, maskSurface, 0, 0); + cairo_set_operator(m_devicePainter, overlayMerge?CAIRO_OPERATOR_OVER:CAIRO_OPERATOR_SOURCE); cairo_fill(m_devicePainter); cairo_surface_destroy(maskSurface); } // Clear intermediate surface cairo_save(m_painter); + cairo_set_operator(m_painter, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(m_painter, 0.0, 0.0, 0.0, 0.0); cairo_paint(m_painter); cairo_restore(m_painter); @@ -1183,6 +1300,7 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) m_bgColorMode = TQt::TransparentMode; resetIntermediateSurface(); m_painter = cairo_create(m_intermediateSurface); + cairo_set_operator(m_painter, CAIRO_OPERATOR_OVER); m_devicePainter = cairo_create(m_surface); m_pen = TQPen(); m_brush = TQBrush(); @@ -1192,6 +1310,7 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) cairo_matrix_init_identity(&m_worldMatrix); cairo_matrix_init_identity(&m_viewportMatrix); setCairoTransformations(); + m_rop = TQPainter::CopyROP; m_clipRegion = TQImage(); m_clipRegionEnabled = false; m_worldMatrixStack.clear(); @@ -1230,65 +1349,8 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) break; case PdcSetROP: if ((p) && (m_painter)) { - cairo_operator_t cairoCompositionMode = CAIRO_OPERATOR_OVER; TQt::RasterOp rop = (TQt::RasterOp)p[0].ival; - switch (rop) { - case TQPainter::CopyROP: - cairoCompositionMode=CAIRO_OPERATOR_OVER; - break; - case TQPainter::OrROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - case TQPainter::XorROP: - // While this is not a 'real' XOR, if the source color is white (1.0) it should work well enough (i.e. reverse itself on a second application)... - cairoCompositionMode=CAIRO_OPERATOR_DIFFERENCE; - break; - case TQPainter::NotAndROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - case TQPainter::NotCopyROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - case TQPainter::NotOrROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - case TQPainter::NotXorROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - case TQPainter::AndROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - case TQPainter::NotROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - case TQPainter::ClearROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - case TQPainter::SetROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - case TQPainter::NopROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - case TQPainter::AndNotROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - case TQPainter::OrNotROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - case TQPainter::NandROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - case TQPainter::NorROP: - tqWarning("TDEQt4PaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", rop); - break; - default: - cairoCompositionMode=CAIRO_OPERATOR_OVER; -#if defined(QT_CHECK_RANGE) - tqWarning( "TDEQt4PaintDevice::cmd: Unhandled raster operation %d", rop ); -#endif - } - cairo_set_operator(m_painter, cairoCompositionMode); + m_rop = rop; } break; case PdcSetBrushOrigin: diff --git a/tdegtk/tqtcairopainter.h b/tdegtk/tqtcairopainter.h index c65036f..404c526 100644 --- a/tdegtk/tqtcairopainter.h +++ b/tdegtk/tqtcairopainter.h @@ -86,6 +86,7 @@ class Q_EXPORT TQt3CairoPaintDevice : public TQPaintDevice // picture class TQBrush m_brush; TQPoint m_brushOrigin; TQFont m_font; + TQt::RasterOp m_rop; TQImage m_clipRegion; bool m_clipRegionEnabled; TQWMatrixStack m_worldMatrixStack; diff --git a/tests/test-painter.cpp b/tests/test-painter.cpp index fe1939f..45e064c 100644 --- a/tests/test-painter.cpp +++ b/tests/test-painter.cpp @@ -217,6 +217,15 @@ void runTests(TQPaintDevice* pd) { TQRegion rectRegion(425,35,50,50); p.setClipRegion(rectRegion); p.fillRect(boundary, TQBrush(TQt::green)); + p.setClipping(false); + } + + // Raster operation tests + { + p.setRasterOp(TQPainter::XorROP); + p.setBrush(TQBrush(TQt::white)); + p.setPen(TQPen()); + p.drawRect(325, 275, 50, 50); } //drawColorWheel(&p, 0.5); |