Implement framework for raster operations

pull/1/head
Timothy Pearson 12 years ago
parent 4038374c67
commit 2cec804e02

@ -36,6 +36,12 @@
#define SET_BIT(x, y) (x |= 1 << y) #define SET_BIT(x, y) (x |= 1 << y)
#define TEST_BIT(x, y) ((x & (1 << y)) >> 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* TQImageToCairoSurface(TQImage origimg) {
cairo_surface_t* ret; cairo_surface_t* ret;
@ -98,24 +104,135 @@ void TQt3CairoPaintDevice::resetIntermediateSurface() {
m_intermediateSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); 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() { void TQt3CairoPaintDevice::transferIntermediateSurface() {
bool overlayMerge = true;
cairo_surface_flush(m_intermediateSurface); 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) { if (!m_clipRegionEnabled) {
// Clipping disabled // Clipping disabled
cairo_set_source_surface(m_devicePainter, m_intermediateSurface, 0, 0); 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); cairo_paint(m_devicePainter);
} }
else { else {
// Clipping enabled // Clipping enabled
cairo_surface_t* maskSurface = TQImageToCairoSurface(m_clipRegion); cairo_surface_t* maskSurface = TQImageToCairoSurface(m_clipRegion);
cairo_mask_surface(m_devicePainter, maskSurface, 0, 0); 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_fill(m_devicePainter);
cairo_surface_destroy(maskSurface); cairo_surface_destroy(maskSurface);
} }
// Clear intermediate surface // Clear intermediate surface
cairo_save(m_painter); 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_set_source_rgba(m_painter, 0.0, 0.0, 0.0, 0.0);
cairo_paint(m_painter); cairo_paint(m_painter);
cairo_restore(m_painter); cairo_restore(m_painter);
@ -1183,6 +1300,7 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p )
m_bgColorMode = TQt::TransparentMode; m_bgColorMode = TQt::TransparentMode;
resetIntermediateSurface(); resetIntermediateSurface();
m_painter = cairo_create(m_intermediateSurface); m_painter = cairo_create(m_intermediateSurface);
cairo_set_operator(m_painter, CAIRO_OPERATOR_OVER);
m_devicePainter = cairo_create(m_surface); m_devicePainter = cairo_create(m_surface);
m_pen = TQPen(); m_pen = TQPen();
m_brush = TQBrush(); 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_worldMatrix);
cairo_matrix_init_identity(&m_viewportMatrix); cairo_matrix_init_identity(&m_viewportMatrix);
setCairoTransformations(); setCairoTransformations();
m_rop = TQPainter::CopyROP;
m_clipRegion = TQImage(); m_clipRegion = TQImage();
m_clipRegionEnabled = false; m_clipRegionEnabled = false;
m_worldMatrixStack.clear(); m_worldMatrixStack.clear();
@ -1230,65 +1349,8 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p )
break; break;
case PdcSetROP: case PdcSetROP:
if ((p) && (m_painter)) { if ((p) && (m_painter)) {
cairo_operator_t cairoCompositionMode = CAIRO_OPERATOR_OVER;
TQt::RasterOp rop = (TQt::RasterOp)p[0].ival; TQt::RasterOp rop = (TQt::RasterOp)p[0].ival;
switch (rop) { m_rop = 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);
} }
break; break;
case PdcSetBrushOrigin: case PdcSetBrushOrigin:

@ -86,6 +86,7 @@ class Q_EXPORT TQt3CairoPaintDevice : public TQPaintDevice // picture class
TQBrush m_brush; TQBrush m_brush;
TQPoint m_brushOrigin; TQPoint m_brushOrigin;
TQFont m_font; TQFont m_font;
TQt::RasterOp m_rop;
TQImage m_clipRegion; TQImage m_clipRegion;
bool m_clipRegionEnabled; bool m_clipRegionEnabled;
TQWMatrixStack m_worldMatrixStack; TQWMatrixStack m_worldMatrixStack;

@ -217,6 +217,15 @@ void runTests(TQPaintDevice* pd) {
TQRegion rectRegion(425,35,50,50); TQRegion rectRegion(425,35,50,50);
p.setClipRegion(rectRegion); p.setClipRegion(rectRegion);
p.fillRect(boundary, TQBrush(TQt::green)); 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); //drawColorWheel(&p, 0.5);

Loading…
Cancel
Save