diff --git a/tdegtk/tqtcairopainter.cpp b/tdegtk/tqtcairopainter.cpp index 8f917e1..05e9a0a 100644 --- a/tdegtk/tqtcairopainter.cpp +++ b/tdegtk/tqtcairopainter.cpp @@ -27,9 +27,11 @@ #include "tqimage.h" #include "tqfile.h" #include "tqpaintdevicemetrics.h" + #undef Qt #define CAIRO_PIXEL_OFFSET (0.5) +#define CAIRO_FONT_SIZE_FUDGE_FACTOR (1.4) #define SET_BIT(x, y) (x |= 1 << y) #define TEST_BIT(x, y) ((x & (1 << y)) >> y) @@ -219,7 +221,7 @@ void TQt3CairoPaintDevice::updatePen(bool backgroundStroke) { cairo_set_line_width(m_painter, ((!allow_zero_lw) && (m_pen.width() == 0)) ? 1 : m_pen.width()); TQRgb color = (backgroundStroke)?m_bgColor.rgb():m_pen.color().rgb(); - cairo_set_source_rgba(m_painter, tqRed(color), tqGreen(color), tqBlue(color), tqAlpha(color)); + cairo_set_source_rgba(m_painter, tqRed(color)/255.0, tqGreen(color)/255.0, tqBlue(color)/255.0, tqAlpha(color)/255.0); } void TQt3CairoPaintDevice::updateBrush(bool backgroundStroke, cairo_fill_rule_t fillMethod) { @@ -229,7 +231,7 @@ void TQt3CairoPaintDevice::updateBrush(bool backgroundStroke, cairo_fill_rule_t if (backgroundStroke) { TQRgb color = m_bgColor.rgb(); - cairo_pattern_t* pattern = cairo_pattern_create_rgba(tqRed(color), tqGreen(color), tqBlue(color), tqAlpha(color)); + cairo_pattern_t* pattern = cairo_pattern_create_rgba(tqRed(color)/255.0, tqGreen(color)/255.0, tqBlue(color)/255.0, tqAlpha(color)/255.0); cairo_set_source(m_painter, pattern); cairo_pattern_set_extend(cairo_get_source(m_painter), CAIRO_EXTEND_REPEAT); cairo_pattern_destroy(pattern); @@ -308,7 +310,7 @@ void TQt3CairoPaintDevice::updateBrush(bool backgroundStroke, cairo_fill_rule_t int bit = 7; for (x=0; xcount();i++) { - pointarray->point(i, &x, &y ); + pointarray->point(i, &x, &y); if (first) { cairo_move_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); first = false; @@ -381,7 +386,7 @@ void TQt3CairoPaintDevice::drawPolygon(const TQPointArray* pointarray, bool wind if (m_pen.style() != TQPen::NoPen) { first = true; for (i=0;icount();i++) { - pointarray->point(i, &x, &y ); + pointarray->point(i, &x, &y); if (first) { cairo_move_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); first = false; @@ -537,6 +542,144 @@ void TQt3CairoPaintDevice::drawChord(int x, int y, int w, int h, int a, int alen return; } +void TQt3CairoPaintDevice::pangoSetupTextPath(PangoLayout *layout, const char* text) { + PangoFontDescription *desc; + + pango_layout_set_text(layout, text, -1); + + desc = pango_font_description_new(); + + // FIXME + // overline and a handful of other flags are not supported by Pango! + TQString family = m_font.family(); +// bool bold = m_font.bold(); + bool italic = m_font.italic(); + bool underline = m_font.underline(); +// bool overline = m_font.overline(); + bool strikeout = m_font.strikeOut(); +// bool fixedPitch = m_font.fixedPitch(); + int stretch = m_font.stretch(); + int weight = m_font.weight(); + + int pixelSize = m_font.pixelSize(); + bool usePixelSize = (pixelSize>=0); + float pointSizeFloat = m_font.pointSizeFloat(); + bool usePointSize = (pointSizeFloat>=0); + + TQFont::StyleStrategy qt3fontstrategy = m_font.styleStrategy(); + + PangoWeight pangoWeight; + switch (weight) { + case TQFont::Light: + pangoWeight = PANGO_WEIGHT_LIGHT; + break; + case TQFont::Normal: + pangoWeight = PANGO_WEIGHT_NORMAL; + break; + case TQFont::DemiBold: + pangoWeight = PANGO_WEIGHT_SEMIBOLD; + break; + case TQFont::Bold: + pangoWeight = PANGO_WEIGHT_BOLD; + break; + case TQFont::Black: + pangoWeight = PANGO_WEIGHT_HEAVY; + break; + } + + PangoStretch pangoStretch; + switch (stretch) { + case TQFont::UltraCondensed: + pangoStretch = PANGO_STRETCH_ULTRA_CONDENSED; + break; + case TQFont::ExtraCondensed: + pangoStretch = PANGO_STRETCH_EXTRA_CONDENSED; + break; + case TQFont::Condensed: + pangoStretch = PANGO_STRETCH_CONDENSED; + break; + case TQFont::SemiCondensed: + pangoStretch = PANGO_STRETCH_SEMI_CONDENSED; + break; + case TQFont::Unstretched: + pangoStretch = PANGO_STRETCH_NORMAL; + break; + case TQFont::SemiExpanded: + pangoStretch = PANGO_STRETCH_SEMI_EXPANDED; + break; + case TQFont::Expanded: + pangoStretch = PANGO_STRETCH_EXPANDED; + break; + case TQFont::ExtraExpanded: + pangoStretch = PANGO_STRETCH_EXTRA_EXPANDED; + break; + case TQFont::UltraExpanded: + pangoStretch = PANGO_STRETCH_ULTRA_EXPANDED; + break; + } + + pango_font_description_set_family(desc, family.ascii()); + if (usePixelSize) { + pango_font_description_set_absolute_size(desc, pixelSize*PANGO_SCALE); + } + if (usePointSize) { + pango_font_description_set_absolute_size(desc, pointSizeFloat*PANGO_SCALE*CAIRO_FONT_SIZE_FUDGE_FACTOR); + } + pango_font_description_set_style(desc, (italic)?PANGO_STYLE_ITALIC:PANGO_STYLE_NORMAL); + pango_font_description_set_weight(desc, pangoWeight); + pango_font_description_set_stretch(desc, pangoStretch); + +#if 0 + if (qt3fontstrategy & TQFont::PreferDefault) // FIXME Set Cairo/Pango to follow this hint + if (qt3fontstrategy & TQFont::PreferBitmap) // FIXME Set Cairo/Pango to follow this hint + if (qt3fontstrategy & TQFont::PreferDevice) // FIXME Set Cairo/Pango to follow this hint + if (qt3fontstrategy & TQFont::PreferMatch) // FIXME Set Cairo/Pango to follow this hint + if (qt3fontstrategy & TQFont::PreferQuality) // FIXME Set Cairo/Pango to follow this hint + if (qt3fontstrategy & TQFont::PreferAntialias) // FIXME Set Cairo/Pango to follow this hint + if (qt3fontstrategy & TQFont::NoAntialias) // FIXME Set Cairo/Pango to follow this hint + if (qt3fontstrategy & TQFont::OpenGLCompatible) // FIXME Set Cairo/Pango to follow this hint +#endif + + pango_layout_set_font_description(layout, desc); + + PangoAttrList* attr_list = pango_attr_list_new(); + pango_attr_list_insert(attr_list, pango_attr_underline_new((underline)?PANGO_UNDERLINE_SINGLE:PANGO_UNDERLINE_NONE)); + pango_attr_list_insert(attr_list, pango_attr_strikethrough_new(strikeout)); + pango_layout_set_attributes(layout, attr_list); + pango_attr_list_unref(attr_list); + + pango_font_description_free(desc); +} + +void TQt3CairoPaintDevice::drawText(TQPainter *p, int x, int y, const TQString &str, int pos, int len, TQPainter::TextDirection dir, bool baseline) { + if ((!m_painter) || (!p)) { + return; + } + + PangoLayout *layout; + layout = pango_cairo_create_layout(m_painter); + + TQFont::StyleStrategy qt3fontstrategy = m_font.styleStrategy(); + pangoSetupTextPath(layout, str.utf8()); + + int baseline_y = pango_layout_get_baseline(layout)/PANGO_SCALE; + cairo_new_path(m_painter); + cairo_move_to(m_painter, x, (baseline)?y-baseline_y:y); + updatePen(FALSE); + + pango_cairo_update_layout(m_painter, layout); + pango_cairo_layout_path(m_painter, layout); + + if ((qt3fontstrategy & TQFont::PreferOutline) || (qt3fontstrategy & TQFont::ForceOutline)) { + cairo_stroke_preserve(m_painter); + } + else { + cairo_fill(m_painter); + } + + g_object_unref(layout); +} + /*! \class TQt3CairoPaintDevice tdeqt4painter.h \brief The TQt3CairoPaintDevice class is a paint device that translates @@ -575,8 +718,6 @@ TQt3CairoPaintDevice::~TQt3CairoPaintDevice() bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) { - Q_UNUSED(pt); - unsigned int i; double x; @@ -602,14 +743,6 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) x2 = p[1].point->x(); y2 = p[1].point->y(); } -// if ((c == PdcDrawPolyline) || (c == PdcDrawPolygon) || (c == PdcDrawLineSegments) || (c == PdcDrawCubicBezier)) { -// TQPointArray qt3parray = *p[0].ptarr; -// qt4polygon.resize(qt3parray.count()); -// for (i=0;ix(); y = p[0].rect->y(); @@ -681,7 +814,7 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) } else { #if defined(QT_CHECK_RANGE) - tqWarning( "TQt3CairoPaintDevice::cmd: TQPainter::begin must be called before PdcDrawRect" ); + tqWarning( "TQt3CairoPaintDevice::cmd: TQPainter::begin must be called before PdcDrawRect" ); #endif } break; @@ -730,14 +863,30 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) cairo_restore(m_painter); } break; -#if 0 case PdcDrawLineSegments: - index = 0; - count = -1; - lineCount = (count == -1) ? (qt4polygon.size() - index) / 2 : count; - m_qt4painter->drawLines(qt4polygon.constData() + index * 2, lineCount); + if (m_painter) { + cairo_save(m_painter); + if (p) { + int x; + int y; + int x2; + int y2; + const TQPointArray* pointarray = p[0].ptarr; + if (pointarray) { + if (m_pen.style() != TQPen::NoPen) { + 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); + dualStrokePen(); + } + } + } + } + cairo_restore(m_painter); + } break; -#endif case PdcDrawPolyline: if (p) { drawPolygon(p[0].ptarr, false, false, true); @@ -748,22 +897,56 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) drawPolygon(p[0].ptarr, p[1].ival, true, true); } break; -#if 0 case PdcDrawCubicBezier: - index = 0; - path.moveTo(qt4polygon.at(index)); - path.cubicTo(qt4polygon.at(index+1), qt4polygon.at(index+2), qt4polygon.at(index+3)); - m_qt4painter->strokePath(path, m_qt4painter->pen()); + if (m_painter) { + cairo_save(m_painter); + if (p) { + int x; + int y; + int x2; + int y2; + int x3; + int y3; + int x4; + int y4; + const TQPointArray* pointarray = p[0].ptarr; + if (pointarray) { + if (m_pen.style() != TQPen::NoPen) { + for (i=0;icount();i=i+4) { + pointarray->point(i+0, &x, &y); + 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); + dualStrokePen(); + } + } + } + } + cairo_restore(m_painter); + } break; +#if 0 case PdcDrawText: + // NOTE + // drawText baseline = FALSE for this! m_qt4painter->drawText( qt4point1, qt4string ); break; case PdcDrawTextFormatted: m_qt4painter->drawText( qt4rect, qt4formattedtextflags, qt4string ); break; +#endif case PdcDrawText2: - m_qt4painter->drawText( qt4point1, qt4string ); + if (m_painter) { + 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, 0, -1, TQPainter::Auto, TRUE); + } + } break; +#if 0 case PdcDrawText2Formatted: m_qt4painter->drawText( qt4rect, qt4formattedtextflags, qt4string ); break; @@ -791,6 +974,7 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) m_painter = cairo_create(m_surface); m_pen = TQPen(); m_brush = TQBrush(); + m_brushOrigin = TQPoint(0,0); } break; case PdcEnd: @@ -818,17 +1002,85 @@ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) m_bgColorMode = (TQt::BGMode)p[0].ival; } break; -#if 0 case PdcSetROP: - m_qt4painter->setCompositionMode(qt4compositionmode); + 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); + } break; case PdcSetBrushOrigin: - m_qt4painter->setBrushOrigin( qt4point1 ); + if (p) { + const TQPoint* point = p[0].point; + if (point) { + m_brushOrigin = *point; + } + } break; case PdcSetFont: - m_qt4painter->setFont( qt4font ); + if (p) { + const TQFont* font = p[0].font; + if (font) { + m_font = *font; + } + } break; -#endif case PdcSetPen: if (p) { const TQPen* pen = p[0].pen; diff --git a/tdegtk/tqtcairopainter.h b/tdegtk/tqtcairopainter.h index 7e43468..99a3dc2 100644 --- a/tdegtk/tqtcairopainter.h +++ b/tdegtk/tqtcairopainter.h @@ -27,8 +27,11 @@ #include "ntqcolor.h" #include "ntqpen.h" #include "ntqbrush.h" +#include "ntqfont.h" +#include "ntqpainter.h" #include +#include class Q_EXPORT TQt3CairoPaintDevice : public TQPaintDevice // picture class { @@ -53,6 +56,9 @@ class Q_EXPORT TQt3CairoPaintDevice : public TQPaintDevice // picture class void drawArc(int x, int y, int w, int h, int a, int alen); void drawPie(int x, int y, int w, int h, int a, int alen); void drawChord(int x, int y, int w, int h, int a, int alen); + + void pangoSetupTextPath(PangoLayout *layout, const char* text); + void drawText(TQPainter *p, int x, int y, const TQString &str, int pos, int len, TQPainter::TextDirection dir, bool baseline=TRUE); private: cairo_surface_t *m_surface; @@ -62,6 +68,8 @@ class Q_EXPORT TQt3CairoPaintDevice : public TQPaintDevice // picture class TQt::BGMode m_bgColorMode; TQPen m_pen; TQBrush m_brush; + TQPoint m_brushOrigin; + TQFont m_font; }; #endif // TDEQT4PAINTER_H diff --git a/tests/test-painter.cpp b/tests/test-painter.cpp index f932c83..0fb811c 100644 --- a/tests/test-painter.cpp +++ b/tests/test-painter.cpp @@ -5,29 +5,11 @@ #include "tqtcairopainter.h" -int -main (int argc, char *argv[]) -{ - cairo_surface_t *surface; - cairo_t *cr; - - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 500, 500); -// cr = cairo_create (surface); - -// /* Examples are in 1.0 x 1.0 coordinate space */ -// cairo_scale (cr, 120, 120); -// -// /* Drawing code goes here */ -// cairo_set_line_width (cr, 0.1); -// cairo_set_source_rgb (cr, 0, 0, 0); -// cairo_rectangle (cr, 0.25, 0.25, 0.5, 0.5); -// cairo_stroke (cr); - - // Initialize TQApplication required data structures - new TQApplication(argc, argv, TRUE); +// TQt3 test image only +#include - TQt3CairoPaintDevice pd(surface); - TQPainter p(&pd); +void runTests(TQPaintDevice* pd) { + TQPainter p(pd); // Rectangle tests { @@ -132,13 +114,93 @@ main (int argc, char *argv[]) p.drawChord(100, 450, 200, 100, 45*16, 90*16); } + // Line segment tests + { + TQPointArray a; + int x1 = 10; + int y1 = 400; + + a.setPoints( 4, x1+0, y1+85, x1+75, y1+75, x1+0, y1+95, x1+75, y1+85 ); + p.setPen(TQColor(255,128,0)); + p.drawLineSegments(a); + } + + // Bezier curve tests + { + TQPointArray a; + int x1 = 100; + int y1 = 400; + + a.setPoints( 4, x1+0, y1+85, x1+75, y1+75, x1+0, y1+95, x1+75, y1+85 ); + p.setPen(TQColor(0,128,255)); + p.drawCubicBezier(a); + } + + // Font tests + { + static const char *fonts[] = { "Helvetica", "Courier", "Times", 0 }; + static int sizes[] = { 10, 12, 18, 24, 36, 0 }; + int f = 0; + int y = 0; + while ( fonts[f] ) { + int s = 0; + while ( sizes[s] ) { + TQFont font( fonts[f], sizes[s] ); + p.setFont( font ); + TQFontMetrics fm = p.fontMetrics(); + y += fm.ascent(); + p.drawText( 10, y, "TQt3 renders via Cairo!" ); + y += fm.descent(); + s++; + if (y > 500) { + break; + } + } + f++; + if (y > 500) { + break; + } + } + } + p.end(); +} + +int +main (int argc, char *argv[]) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 500, 500); +// cr = cairo_create (surface); + +// /* Examples are in 1.0 x 1.0 coordinate space */ +// cairo_scale (cr, 120, 120); +// +// /* Drawing code goes here */ +// cairo_set_line_width (cr, 0.1); +// cairo_set_source_rgb (cr, 0, 0, 0); +// cairo_rectangle (cr, 0.25, 0.25, 0.5, 0.5); +// cairo_stroke (cr); + + // Initialize TQApplication required data structures + new TQApplication(argc, argv, TRUE); + + TQt3CairoPaintDevice pd(surface); + runTests(&pd); /* Write output and clean up */ cairo_surface_write_to_png (surface, "stroke.png"); // cairo_destroy (cr); cairo_surface_destroy (surface); + // Render a TQt3 native test image + TQPixmap pm(500, 500); + pm.fill(TQt::black); + runTests(&pm); + pm.save("tqt3.png", "PNG"); + return 0; }