From 623f11f6000cb2f05f51c81e7a1c6fc02ce21907 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Mon, 15 Oct 2012 13:02:37 -0500 Subject: [PATCH] Fix pixel imperfection, image drawing, and clipping problems Update test suite --- tdegtk/tqtcairopainter.cpp | 267 +++++++++++++++++++++++++------------ tdegtk/tqtcairopainter.h | 22 +-- tests/test-painter.cpp | 28 +++- 3 files changed, 223 insertions(+), 94 deletions(-) diff --git a/tdegtk/tqtcairopainter.cpp b/tdegtk/tqtcairopainter.cpp index 44b1895..c19a736 100644 --- a/tdegtk/tqtcairopainter.cpp +++ b/tdegtk/tqtcairopainter.cpp @@ -4,7 +4,7 @@ ** ** Copyright (C) 2012 Timothy Pearson. All rights reserved. ** -** This file is part of the TDE Qt4 style interface +** This file is part of the TDE GTK3 style interface ** ** This file may be used under the terms of the GNU General ** Public License versions 2.0 or 3.0 as published by the Free @@ -30,7 +30,8 @@ #undef Qt -#define CAIRO_PIXEL_OFFSET (0.5) +#define CAIRO_PEN_PIXEL_OFFSET (0.5) +#define CAIRO_BRUSH_PIXEL_OFFSET (0.0) #define CAIRO_FONT_SIZE_FUDGE_FACTOR (1.4) #define SET_BIT(x, y) (x |= 1 << y) @@ -42,6 +43,30 @@ #define ARGB_G_BYTE_NUMBER 1 #define ARGB_B_BYTE_NUMBER 0 +inline int cairoPainterRectSubtraction(TQPen* pen) { + return ((pen->style() != TQt::NoPen) && ((pen->width() == 0) || (pen->width() == 1))) ? 1 : 0; +} + +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 ); +} + cairo_surface_t* TQImageToCairoSurface(TQImage origimg) { cairo_surface_t* ret; @@ -53,8 +78,27 @@ cairo_surface_t* TQImageToCairoSurface(TQImage origimg) { img = origimg; } - cairo_format_t cairo_format; int depth = img.depth(); + if (depth == 32) { + // Convert ARGB to premultiplied ARGB + // SLOW + int x; + int y; + for (x=0; x> 24; + unsigned char r = (pixel & 0x00ff0000) >> 16; + unsigned char g = (pixel & 0x0000ff00) >> 8; + unsigned char b = (pixel & 0x000000ff) >> 0; + standardAlphaToPremultipliedAlpha(&a, &r, &g, &b); + pixel = (a << 24) | (r << 16) | (g << 8) | (b << 0); + img.setPixel(x, y, pixel); + } + } + } + + cairo_format_t cairo_format; if (depth == 32) { cairo_format = CAIRO_FORMAT_ARGB32; } @@ -99,31 +143,12 @@ void TQt3CairoPaintDevice::resetIntermediateSurface() { cairo_surface_destroy(m_intermediateSurface); } - int height = cairo_image_surface_get_height(m_surface); - int width = cairo_image_surface_get_width(m_surface); + updateSurfaceDimensions(); + int height = m_height; + int width = m_width; 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); @@ -132,8 +157,9 @@ void TQt3CairoPaintDevice::transferIntermediateSurface() { 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); + updateSurfaceDimensions(); + register int height = m_height; + register int width = m_width; 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); @@ -182,19 +208,19 @@ void TQt3CairoPaintDevice::transferIntermediateSurface() { // Perform requested bitwise operation if (m_rop == TQPainter::OrROP) { - combinedPixel_a = devicePixel_a; + combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00; combinedPixel_r = devicePixel_r | intermediatePixel_r; combinedPixel_g = devicePixel_g | intermediatePixel_g; combinedPixel_b = devicePixel_b | intermediatePixel_b; } else if (m_rop == TQPainter::XorROP) { - combinedPixel_a = devicePixel_a; + combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00; combinedPixel_r = devicePixel_r ^ intermediatePixel_r; combinedPixel_g = devicePixel_g ^ intermediatePixel_g; combinedPixel_b = devicePixel_b ^ intermediatePixel_b; } else if (m_rop == TQPainter::NotAndROP) { - combinedPixel_a = devicePixel_a; + combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00; combinedPixel_r = devicePixel_r & (~intermediatePixel_r); combinedPixel_g = devicePixel_g & (~intermediatePixel_g); combinedPixel_b = devicePixel_b & (~intermediatePixel_b); @@ -206,25 +232,25 @@ void TQt3CairoPaintDevice::transferIntermediateSurface() { combinedPixel_b = ~intermediatePixel_b; } else if (m_rop == TQPainter::NotOrROP) { - combinedPixel_a = devicePixel_a; + combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00; combinedPixel_r = devicePixel_r | (~intermediatePixel_r); combinedPixel_g = devicePixel_g | (~intermediatePixel_g); combinedPixel_b = devicePixel_b | (~intermediatePixel_b); } else if (m_rop == TQPainter::NotXorROP) { - combinedPixel_a = devicePixel_a; + combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00; combinedPixel_r = devicePixel_r ^ (~intermediatePixel_r); combinedPixel_g = devicePixel_g ^ (~intermediatePixel_g); combinedPixel_b = devicePixel_b ^ (~intermediatePixel_b); } else if (m_rop == TQPainter::AndROP) { - combinedPixel_a = devicePixel_a; + combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00; combinedPixel_r = devicePixel_r & intermediatePixel_r; combinedPixel_g = devicePixel_g & intermediatePixel_g; combinedPixel_b = devicePixel_b & intermediatePixel_b; } else if (m_rop == TQPainter::NotROP) { - combinedPixel_a = devicePixel_a; + combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00; combinedPixel_r = ~devicePixel_r; combinedPixel_g = ~devicePixel_g; combinedPixel_b = ~devicePixel_b; @@ -242,31 +268,31 @@ void TQt3CairoPaintDevice::transferIntermediateSurface() { combinedPixel_b = 0xff; } else if (m_rop == TQPainter::NopROP) { - combinedPixel_a = devicePixel_a; + combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00; combinedPixel_r = devicePixel_r; combinedPixel_g = devicePixel_g; combinedPixel_b = devicePixel_b; } else if (m_rop == TQPainter::AndNotROP) { - combinedPixel_a = devicePixel_a; + combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00; combinedPixel_r = (~devicePixel_r) & intermediatePixel_r; combinedPixel_g = (~devicePixel_g) & intermediatePixel_g; combinedPixel_b = (~devicePixel_b) & intermediatePixel_b; } else if (m_rop == TQPainter::OrNotROP) { - combinedPixel_a = devicePixel_a; + combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00; combinedPixel_r = (~devicePixel_r) | intermediatePixel_r; combinedPixel_g = (~devicePixel_g) | intermediatePixel_g; combinedPixel_b = (~devicePixel_b) | intermediatePixel_b; } else if (m_rop == TQPainter::NandROP) { - combinedPixel_a = devicePixel_a; + combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00; combinedPixel_r = ~(devicePixel_r & intermediatePixel_r); combinedPixel_g = ~(devicePixel_g & intermediatePixel_g); combinedPixel_b = ~(devicePixel_b & intermediatePixel_b); } else if (m_rop == TQPainter::NorROP) { - combinedPixel_a = devicePixel_a; + combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00; combinedPixel_r = ~(devicePixel_r | intermediatePixel_r); combinedPixel_g = ~(devicePixel_g | intermediatePixel_g); combinedPixel_b = ~(devicePixel_b | intermediatePixel_b); @@ -308,9 +334,9 @@ void TQt3CairoPaintDevice::transferIntermediateSurface() { else { // Clipping enabled cairo_surface_t* maskSurface = TQImageToCairoSurface(m_clipRegion); - cairo_mask_surface(m_devicePainter, maskSurface, 0, 0); + cairo_set_source_surface(m_devicePainter, m_intermediateSurface, 0, 0); cairo_set_operator(m_devicePainter, overlayMerge?CAIRO_OPERATOR_OVER:CAIRO_OPERATOR_SOURCE); - cairo_fill(m_devicePainter); + cairo_mask_surface(m_devicePainter, maskSurface, 0, 0); cairo_surface_destroy(maskSurface); } @@ -564,7 +590,7 @@ void TQt3CairoPaintDevice::updateBrush(bool backgroundStroke, cairo_fill_rule_t cairo_surface_t* brushSurface = TQImageToCairoSurface(brushImage); cairo_pattern_t* pattern = cairo_pattern_create_for_surface(brushSurface); cairo_matrix_t brush_translation_matrix; - cairo_matrix_init_translate(&brush_translation_matrix, m_brushOrigin.x(), m_brushOrigin.y()); + cairo_matrix_init_translate(&brush_translation_matrix, m_brushOrigin.x()+1, m_brushOrigin.y()); cairo_pattern_set_matrix(pattern, &brush_translation_matrix); cairo_set_source(m_painter, pattern); cairo_pattern_set_extend(cairo_get_source(m_painter), CAIRO_EXTEND_REPEAT); @@ -607,11 +633,11 @@ void TQt3CairoPaintDevice::drawPolygon(const TQPointArray* pointarray, bool wind for (i=0;icount();i++) { pointarray->point(i, &x, &y); if (first) { - cairo_move_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); + cairo_move_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET); first = false; } else { - cairo_line_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); + cairo_line_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET); } } if (close) { @@ -624,11 +650,11 @@ void TQt3CairoPaintDevice::drawPolygon(const TQPointArray* pointarray, bool wind for (i=0;icount();i++) { pointarray->point(i, &x, &y); if (first) { - cairo_move_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); + cairo_move_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET); first = false; } else { - cairo_line_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); + cairo_line_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET); } } if (close) { @@ -646,6 +672,9 @@ void TQt3CairoPaintDevice::drawRoundRect(int x, int y, int w, int h, int xRnd, i return; } + w=w+2; + h=h+2; + if ( xRnd <= 0 || yRnd <= 0 ) { // Draw normal rectangle TQPDevCmdParam param[2]; @@ -664,7 +693,7 @@ void TQt3CairoPaintDevice::drawRoundRect(int x, int y, int w, int h, int xRnd, i } if ( w <= 0 || h <= 0 ) { - fix_neg_rect( &x, &y, &w, &h ); + fix_neg_rect( &x, &y, &w, &h ); } w--; h--; @@ -707,7 +736,7 @@ void TQt3CairoPaintDevice::drawEllipse(int x, int y, int w, int h) { } TQPointArray a; - a.makeArc(x, y, w, h, 0, 360*16); + a.makeArc(x, y, w+1, h+1, 0, 360*16); // Draw polygon drawPolygon(&a, false, true, true); @@ -749,8 +778,8 @@ void TQt3CairoPaintDevice::drawPie(int x, int y, int w, int h, int a, int alen) pa.makeArc(x, y, w, h, a, alen); // arc polyline int n = pa.size(); int cx, cy; - cx = x+w/2; - cy = y+h/2; + cx = (x+w/2)+1; + cy = (y+h/2)+1; pa.resize(n+2); pa.setPoint(n, cx, cy); // add legs pa.setPoint(n+1, pa.at(0)); @@ -767,7 +796,7 @@ void TQt3CairoPaintDevice::drawChord(int x, int y, int w, int h, int a, int alen } TQPointArray pa; - pa.makeArc(x, y, w-1, h-1, a, alen); // arc polygon + pa.makeArc(x, y, w, h, a, alen); // arc polygon int n = pa.size(); pa.resize(n+1); pa.setPoint(n, pa.at(0)); // connect endpoints @@ -787,6 +816,7 @@ void TQt3CairoPaintDevice::pangoSetupTextPath(PangoLayout *layout, const char* t // FIXME // overline and a handful of other flags are not supported by Pango! + // https://bugzilla.gnome.org/show_bug.cgi?id=577190 TQString family = m_font.family(); // bool bold = m_font.bold(); bool italic = m_font.italic(); @@ -948,7 +978,7 @@ void TQt3CairoPaintDevice::drawTextInRect(TQPainter *p, TQRect rect, int textFla pango_layout_set_height(layout, 0); } if (!(textFlags & TQt::DontClip)) { - cairo_rectangle(m_painter, rect.x()+CAIRO_PIXEL_OFFSET, rect.y()+CAIRO_PIXEL_OFFSET, rect.width(), rect.height()); + cairo_rectangle(m_painter, rect.x()+CAIRO_PEN_PIXEL_OFFSET, rect.y()+CAIRO_PEN_PIXEL_OFFSET, rect.width(), rect.height()); cairo_clip(m_painter); } if (textFlags & TQt::ExpandTabs) { @@ -1053,10 +1083,24 @@ void TQt3CairoPaintDevice::setCairoTransformations() { Constructs TQt3CairoPaintDevice on an existing QPainter */ -TQt3CairoPaintDevice::TQt3CairoPaintDevice( cairo_surface_t *cairosurface ) - : TQPaintDevice( TQInternal::Picture | TQInternal::ExternalDevice ), m_intermediateSurface(NULL), m_painter(NULL), m_devicePainter(NULL), m_tabStops(NULL), m_tabStopArray(NULL) +TQt3CairoPaintDevice::TQt3CairoPaintDevice( cairo_surface_t *cairosurface, int width, int height, cairo_t *overridepainter ) + : TQPaintDevice( TQInternal::Picture | TQInternal::ExternalDevice ) { - m_surface = cairosurface; + init(); + + if (width >= 0) { + m_width = width; + } + if (height >= 0) { + m_height = width; + } + if (overridepainter) { + m_overridePainter = overridepainter; + m_surface = cairo_get_group_target(overridepainter); + } + else { + m_surface = cairosurface; + } m_worldMatrixStack.setAutoDelete(TRUE); m_tabStops = pango_tab_array_new(0, false); @@ -1088,6 +1132,31 @@ TQt3CairoPaintDevice::~TQt3CairoPaintDevice() } } +/*! + Initializes all data structures +*/ +void TQt3CairoPaintDevice::init() { + m_width = -1; + m_height = -1; + + m_intermediateSurface = NULL; + m_painter = NULL; + m_devicePainter = NULL; + m_overridePainter = NULL; + m_tabStops = NULL; + m_tabStopArray = NULL; +} + +void TQt3CairoPaintDevice::updateSurfaceDimensions() const { + if ((m_width < 0) || (m_height < 0)) { + m_width = cairo_image_surface_get_width(m_surface); + m_height = cairo_image_surface_get_height(m_surface); + } + if ((m_width < 1) || (m_height < 1)) { + printf("[WARNING] Cairo surface height or width less than 0; drawing will not be possible!\n\r"); fflush(stdout); + } +} + /*! \internal Implementation of the function forwarded above to the internal data struct. @@ -1136,8 +1205,8 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) if (m_painter) { cairo_save(m_painter); if (m_pen.style() != TQPen::NoPen) { - cairo_move_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); - cairo_line_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); + cairo_move_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET); + cairo_line_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET); updatePen(FALSE); cairo_set_line_cap(m_painter, CAIRO_LINE_CAP_ROUND); cairo_stroke(m_painter); @@ -1150,7 +1219,7 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) if (m_painter) { cairo_save(m_painter); if (m_pen.style() != TQPen::NoPen) { - cairo_move_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); + cairo_move_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET); } cairo_restore(m_painter); } @@ -1159,7 +1228,7 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) if (m_painter) { cairo_save(m_painter); if (m_pen.style() != TQPen::NoPen) { - cairo_line_to(m_painter, x2+CAIRO_PIXEL_OFFSET, y2+CAIRO_PIXEL_OFFSET); + cairo_line_to(m_painter, x2+CAIRO_PEN_PIXEL_OFFSET, y2+CAIRO_PEN_PIXEL_OFFSET); dualStrokePen(); } cairo_restore(m_painter); @@ -1169,8 +1238,8 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) if (m_painter) { cairo_save(m_painter); if (m_pen.style() != TQPen::NoPen) { - cairo_move_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); - cairo_line_to(m_painter, x2+CAIRO_PIXEL_OFFSET, y2+CAIRO_PIXEL_OFFSET); + cairo_move_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET); + cairo_line_to(m_painter, x2+CAIRO_PEN_PIXEL_OFFSET, y2+CAIRO_PEN_PIXEL_OFFSET); dualStrokePen(); } cairo_restore(m_painter); @@ -1179,15 +1248,16 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) case PdcDrawRect: if (m_painter) { cairo_save(m_painter); - if (m_pen.style() != TQPen::NoPen) { - cairo_rectangle(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET, width, height); - dualStrokePen(); - } + int adjustment = cairoPainterRectSubtraction(&m_pen); if (m_brush.style() != TQBrush::NoBrush) { int line_width = m_pen.width(); - cairo_rectangle(m_painter, x+line_width+CAIRO_PIXEL_OFFSET, y+line_width+CAIRO_PIXEL_OFFSET, width-(line_width*2), height-(line_width*2)); + cairo_rectangle(m_painter, x+line_width+CAIRO_BRUSH_PIXEL_OFFSET, y+line_width+CAIRO_BRUSH_PIXEL_OFFSET, width-(line_width*2)-adjustment, height-(line_width*2)-adjustment); dualStrokeBrush(CAIRO_FILL_RULE_EVEN_ODD); } + if (m_pen.style() != TQPen::NoPen) { + cairo_rectangle(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET, width-adjustment, height-adjustment); + dualStrokePen(); + } cairo_restore(m_painter); } else { @@ -1199,8 +1269,9 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) case PdcDrawRoundRect: if (m_painter) { cairo_save(m_painter); + int adjustment = cairoPainterRectSubtraction(&m_pen); if (p) { - drawRoundRect(x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET, width, height, p[1].ival, p[2].ival); + drawRoundRect(x, y, width-adjustment, height-adjustment, p[1].ival, p[2].ival); } cairo_restore(m_painter); } @@ -1208,8 +1279,9 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) case PdcDrawEllipse: if (m_painter) { cairo_save(m_painter); + int adjustment = cairoPainterRectSubtraction(&m_pen); if (p) { - drawEllipse(x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET, width, height); + drawEllipse(x, y, width-adjustment, height-adjustment); } cairo_restore(m_painter); } @@ -1217,8 +1289,9 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) case PdcDrawArc: if (m_painter) { cairo_save(m_painter); + int adjustment = cairoPainterRectSubtraction(&m_pen); if (p) { - drawArc(x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET, width, height, p[1].ival, p[2].ival); + drawArc(x, y, width-adjustment, height-adjustment, p[1].ival, p[2].ival); } cairo_restore(m_painter); } @@ -1226,8 +1299,9 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) case PdcDrawPie: if (m_painter) { cairo_save(m_painter); + int adjustment = cairoPainterRectSubtraction(&m_pen); if (p) { - drawPie(x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET, width, height, p[1].ival, p[2].ival); + drawPie(x, y, width-adjustment, height-adjustment, p[1].ival, p[2].ival); } cairo_restore(m_painter); } @@ -1235,8 +1309,9 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) case PdcDrawChord: if (m_painter) { cairo_save(m_painter); + int adjustment = cairoPainterRectSubtraction(&m_pen); if (p) { - drawChord(x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET, width, height, p[1].ival, p[2].ival); + drawChord(x, y, width-adjustment, height-adjustment, p[1].ival, p[2].ival); } cairo_restore(m_painter); } @@ -1255,8 +1330,8 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) for (i=0;icount();i=i+2) { pointarray->point(i+0, &x, &y); pointarray->point(i+1, &x2, &y2); - cairo_move_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); - cairo_line_to(m_painter, x2+CAIRO_PIXEL_OFFSET, y2+CAIRO_PIXEL_OFFSET); + cairo_move_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET); + cairo_line_to(m_painter, x2+CAIRO_PEN_PIXEL_OFFSET, y2+CAIRO_PEN_PIXEL_OFFSET); dualStrokePen(); } } @@ -1267,7 +1342,7 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) break; case PdcDrawPolyline: if (p) { - drawPolygon(p[0].ptarr, false, false, true); + drawPolygon(p[0].ptarr, false, false, false); } break; case PdcDrawPolygon: @@ -1295,8 +1370,8 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) pointarray->point(i+1, &x2, &y2); pointarray->point(i+2, &x3, &y3); pointarray->point(i+3, &x4, &y4); - cairo_move_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); - cairo_curve_to(m_painter, x2+CAIRO_PIXEL_OFFSET, y2+CAIRO_PIXEL_OFFSET, x3+CAIRO_PIXEL_OFFSET, y3+CAIRO_PIXEL_OFFSET, x4+CAIRO_PIXEL_OFFSET, y4+CAIRO_PIXEL_OFFSET); + cairo_move_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET); + cairo_curve_to(m_painter, x2+CAIRO_PEN_PIXEL_OFFSET, y2+CAIRO_PEN_PIXEL_OFFSET, x3+CAIRO_PEN_PIXEL_OFFSET, y3+CAIRO_PEN_PIXEL_OFFSET, x4+CAIRO_PEN_PIXEL_OFFSET, y4+CAIRO_PEN_PIXEL_OFFSET); dualStrokePen(); } } @@ -1310,7 +1385,7 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) cairo_save(m_painter); if (p) { TQString string = *p[1].str; - drawText(pt, p[0].rect->x()+CAIRO_PIXEL_OFFSET, p[0].rect->y()+CAIRO_PIXEL_OFFSET, string); + drawText(pt, p[0].rect->x()+CAIRO_PEN_PIXEL_OFFSET, p[0].rect->y()+CAIRO_PEN_PIXEL_OFFSET, string); } cairo_restore(m_painter); } @@ -1331,7 +1406,7 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) cairo_save(m_painter); if (p) { TQString string = *p[1].str; - drawText(pt, p[0].rect->x()+CAIRO_PIXEL_OFFSET, p[0].rect->y()+CAIRO_PIXEL_OFFSET, string); + drawText(pt, p[0].rect->x()+CAIRO_PEN_PIXEL_OFFSET, p[0].rect->y()+CAIRO_PEN_PIXEL_OFFSET, string); } cairo_restore(m_painter); } @@ -1351,7 +1426,17 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) if (m_painter) { cairo_save(m_painter); if (p) { - TQImage sourceImage = p[1].pixmap->convertToImage(); + TQImage sourceImage; + const TQBitmap* bitmap = dynamic_cast(p[1].pixmap); + if (bitmap) { + TQPixmap mergedPixmap = TQPixmap(bitmap->width(), bitmap->height()); + mergedPixmap.fill(m_pen.color()); + mergedPixmap.setMask(*bitmap); + sourceImage = mergedPixmap.convertToImage(); + } + else { + sourceImage = p[1].pixmap->convertToImage(); + } cairo_surface_t* sourceSurface = TQImageToCairoSurface(sourceImage); cairo_rectangle(m_painter, p[0].rect->x(), p[0].rect->y(), p[0].rect->width(), p[0].rect->height()); cairo_set_source_surface(m_painter, sourceSurface, p[0].rect->x(), p[0].rect->y()); @@ -1385,7 +1470,13 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) resetIntermediateSurface(); m_painter = cairo_create(m_intermediateSurface); cairo_set_operator(m_painter, CAIRO_OPERATOR_OVER); - m_devicePainter = cairo_create(m_surface); + if (m_overridePainter) { + m_devicePainter = m_overridePainter; + } + else { + m_devicePainter = cairo_create(m_surface); + } + cairo_set_antialias(m_devicePainter, CAIRO_ANTIALIAS_NONE); m_pen = TQPen(); m_brush = TQBrush(); m_brushOrigin = TQPoint(0,0); @@ -1408,7 +1499,9 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) m_painter = NULL; } if (m_devicePainter) { - cairo_destroy(m_devicePainter); + if (!m_overridePainter) { + cairo_destroy(m_devicePainter); + } m_devicePainter = NULL; } break; @@ -1650,18 +1743,22 @@ int TQt3CairoPaintDevice::metric( int m ) const switch ( m ) { // ### hard coded dpi and color depth values ! case TQPaintDeviceMetrics::PdmWidth: - val = cairo_image_surface_get_width(m_surface); + updateSurfaceDimensions(); + val = m_width; break; case TQPaintDeviceMetrics::PdmHeight: - val = cairo_image_surface_get_height(m_surface); + updateSurfaceDimensions(); + val = m_height; break; case TQPaintDeviceMetrics::PdmWidthMM: + updateSurfaceDimensions(); cairo_surface_get_fallback_resolution(m_surface, &x_pixels_per_inch, &y_pixels_per_inch); - val = ((cairo_image_surface_get_width(m_surface)/x_pixels_per_inch)*25.4); + val = ((m_width/x_pixels_per_inch)*25.4); break; case TQPaintDeviceMetrics::PdmHeightMM: + updateSurfaceDimensions(); cairo_surface_get_fallback_resolution(m_surface, &x_pixels_per_inch, &y_pixels_per_inch); - val = ((cairo_image_surface_get_height(m_surface)/y_pixels_per_inch)*25.4); + val = ((m_height/y_pixels_per_inch)*25.4); break; case TQPaintDeviceMetrics::PdmDpiX: cairo_surface_get_fallback_resolution(m_surface, &x_pixels_per_inch, &y_pixels_per_inch); diff --git a/tdegtk/tqtcairopainter.h b/tdegtk/tqtcairopainter.h index 404c526..20a03d3 100644 --- a/tdegtk/tqtcairopainter.h +++ b/tdegtk/tqtcairopainter.h @@ -4,7 +4,7 @@ ** ** Copyright (C) 2012 Timothy Pearson. All rights reserved. ** -** This file is part of the TDE Qt4 style interface +** This file is part of the TDE GTK3 style interface ** ** This file may be used under the terms of the GNU General ** Public License versions 2.0 or 3.0 as published by the Free @@ -18,8 +18,8 @@ ** **********************************************************************/ -#ifndef TDEQT4PAINTER_H -#define TDEQT4PAINTER_H +#ifndef TQTCAIROPAINTER_H +#define TQTCAIROPAINTER_H #define TQT_NO_COMPAT_NAMES #include "ntqpaintdevice.h" @@ -40,14 +40,16 @@ typedef TQPtrStack TQWMatrixStack; class Q_EXPORT TQt3CairoPaintDevice : public TQPaintDevice // picture class { public: - TQt3CairoPaintDevice( cairo_surface_t * ); + TQt3CairoPaintDevice( cairo_surface_t *, int width = -1, int height = -1, cairo_t *overridepainter = NULL ); ~TQt3CairoPaintDevice(); - + protected: bool cmd( int, TQPainter *, TQPDevCmdParam * ); int metric( int ) const; - + private: + void init(); + void updateSurfaceDimensions() const; void resetIntermediateSurface(); void transferIntermediateSurface(); @@ -69,12 +71,16 @@ class Q_EXPORT TQt3CairoPaintDevice : public TQPaintDevice // picture class void drawTextInRect(TQPainter *p, TQRect rect, int textFlags, const TQString &str); void setCairoTransformations(); - + private: + mutable int m_width; + mutable int m_height; + cairo_surface_t *m_surface; cairo_surface_t *m_intermediateSurface; cairo_t *m_painter; cairo_t *m_devicePainter; + cairo_t *m_overridePainter; cairo_matrix_t m_worldMatrix; cairo_matrix_t m_viewportMatrix; bool m_worldMatrixEnabled; @@ -97,4 +103,4 @@ class Q_EXPORT TQt3CairoPaintDevice : public TQPaintDevice // picture class bool m_tabStopArrayValid; }; -#endif // TDEQT4PAINTER_H +#endif // TQTCAIROPAINTER_H diff --git a/tests/test-painter.cpp b/tests/test-painter.cpp index 45e064c..3c21432 100644 --- a/tests/test-painter.cpp +++ b/tests/test-painter.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "tqtcairopainter.h" @@ -36,6 +37,14 @@ void drawColorWheel(TQPainter *p, double scale) void runTests(TQPaintDevice* pd) { TQPainter p(pd); + // Background + { + p.setPen( TQt::NoPen ); + TQBrush brush(TQColor(0,0,0), TQBrush::SolidPattern); + p.setBrush(brush); + p.drawRect(0,0,1000,1000); + } + // Rectangle tests { p.setPen(TQPen(TQt::red, 1)); @@ -44,8 +53,9 @@ void runTests(TQPaintDevice* pd) { p.setBrush( brush ); // set the yellow brush p.setPen( TQt::NoPen ); // do not draw outline p.drawRect( 0,0, 25,25 ); // draw filled rectangle + p.drawRect( 452,400, 25,25 ); // draw filled rectangle TQBrush brush2( TQt::green, TQBrush::SolidPattern ); // green pattern - p.setBrush( brush2 ); // set the yellow brush + p.setBrush( brush2 ); // set the green brush p.setPen( TQt::NoPen ); // do not draw outline p.drawRect( 40,30, 200,100 ); // draw filled rectangle p.setBrush( TQt::NoBrush ); // do not fill @@ -100,6 +110,9 @@ void runTests(TQPaintDevice* pd) { p.setBrush(TQBrush()); p.setPen(TQPen(TQt::blue, 1)); p.drawRoundRect(80, 150, 50, 50); + p.setBrush(TQt::green); + p.setPen(TQPen()); + p.drawRoundRect(150, 150, 50, 50); } // Ellipse tests @@ -110,6 +123,9 @@ void runTests(TQPaintDevice* pd) { p.setBrush(TQBrush()); p.setPen(TQPen(TQt::blue, 1)); p.drawEllipse(80, 220, 50, 50); + p.setBrush(TQt::green); + p.setPen(TQPen()); + p.drawEllipse(150, 220, 50, 50); } // Arc tests @@ -161,6 +177,7 @@ void runTests(TQPaintDevice* pd) { p.drawCubicBezier(a); } +#if 1 // Pixmap tests { TQPixmap pixmap("open.png"); @@ -172,7 +189,9 @@ void runTests(TQPaintDevice* pd) { TQImage image("open.png"); p.drawImage(350, 10, image, 0, 0, -1, -1); } +#endif +#if 0 // Font tests { p.setPen(TQColor(0,128,255)); @@ -208,6 +227,7 @@ void runTests(TQPaintDevice* pd) { //p.drawText( TQRect(0, 250, 250, 150), TQt::BreakAnywhere | TQt::AlignCenter, TQString("TQt3 renders via Cairo!") ); //p.drawText( TQRect(0, 250, 250, 150), TQt::BreakAnywhere | TQt::AlignHCenter | TQt::AlignBottom, TQString("TQt3 renders via Cairo!") ); } +#endif // Clipping tests { @@ -226,11 +246,17 @@ void runTests(TQPaintDevice* pd) { p.setBrush(TQBrush(TQt::white)); p.setPen(TQPen()); p.drawRect(325, 275, 50, 50); + p.setRasterOp(TQPainter::CopyROP); } //drawColorWheel(&p, 0.5); //drawColorWheel(&p, 1.0); + TQColorGroup cg; + cg.setColor(TQColorGroup::Background, TQColor(128,128,128)); + cg.setColor(TQColorGroup::Foreground, TQColor(0,0,0)); + tqApp->style().drawPrimitive(TQStyle::PE_ExclusiveIndicator, &p, TQRect(400, 400, 16, 16), cg, TQStyle::Style_Down); + p.end(); }