summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tdegtk/tqtcairopainter.cpp180
-rw-r--r--tdegtk/tqtcairopainter.h1
-rw-r--r--tests/test-painter.cpp9
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);