/**************************************************************************** ** ** Implementation of TQt3CairoPaintDevice class ** ** Copyright (C) 2012 Timothy Pearson. All rights reserved. ** ** This file is part of the TDE Qt4 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 ** Software Foundation and appearing in the files LICENSE.GPL2 ** and LICENSE.GPL3 included in the packaging of this file. ** ** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, ** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted ** herein. ** **********************************************************************/ #include "tqtcairopainter.h" #define TQT_NO_COMPAT_NAMES #include "tqpainter.h" #include "tqpixmap.h" #include "tqbitmap.h" #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) // 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; TQImage img; if (origimg.depth() < 24) { img = origimg.convertDepth(32); } else { img = origimg; } cairo_format_t cairo_format; int depth = img.depth(); if (depth == 32) { cairo_format = CAIRO_FORMAT_ARGB32; } else if (depth == 24) { cairo_format = CAIRO_FORMAT_RGB24; } else { cairo_format = CAIRO_FORMAT_RGB24; } int stride = cairo_format_stride_for_width(cairo_format, img.width()); ret = cairo_image_surface_create_for_data(img.bits(), cairo_format, img.width(), img.height(), stride); return ret; } TQImage CairoSurfaceToTQImage(cairo_surface_t* surface) { cairo_surface_flush(surface); cairo_format_t cairo_format = cairo_image_surface_get_format(surface); int height = cairo_image_surface_get_height(surface); int width = cairo_image_surface_get_width(surface); int depth; if (cairo_format == CAIRO_FORMAT_ARGB32) { depth = 32; } else if (cairo_format == CAIRO_FORMAT_RGB24) { depth = 24; } else { // FIXME // Force Cairo to convert the surface to a format that TQImage can read! printf("[WARNING] Tried to convert a Cairo surface of format %d to a TQImage (NULL image returned!)\n\r", cairo_format); fflush(stdout); return TQImage(); } return TQImage(cairo_image_surface_get_data(surface), width, height, depth, (TQRgb*)NULL, 0, TQImage::BigEndian); } void TQt3CairoPaintDevice::resetIntermediateSurface() { if (m_intermediateSurface) { cairo_surface_destroy(m_intermediateSurface); } int height = cairo_image_surface_get_height(m_surface); int width = cairo_image_surface_get_width(m_surface); 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= TQBrush::Dense1Pattern && bs <= TQBrush::DiagCrossPattern ) { pat = pat_tbl[ bs-TQBrush::Dense1Pattern ]; if ( bs <= TQBrush::Dense7Pattern ) { d = 8; } else if ( bs <= TQBrush::CrossPattern ) { d = 24; } else { d = 16; } } if ( (bs == TQBrush::CustomPattern) || pat ) { TQImage brushImage; if ( pat ) { TQRgb color = m_brush.color().rgb(); brushImage = TQImage(d, d, 32); int x; int y; int byte = 0; int bit = 7; for (x=0; xconvertToImage(); } 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_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); cairo_pattern_destroy(pattern); cairo_surface_destroy(brushSurface); } else { TQRgb color = m_brush.color().rgb(); 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); } } cairo_set_fill_rule(m_painter, fillMethod); } static inline void fix_neg_rect( int *x, int *y, int *w, int *h ) { if ( *w < 0 ) { *w = -*w + 2; *x -= *w - 1; } if ( *h < 0 ) { *h = -*h + 2; *y -= *h - 1; } } void TQt3CairoPaintDevice::drawPolygon(const TQPointArray* pointarray, bool winding, bool fill, bool close) { int i; if (m_painter) { cairo_save(m_painter); if (pointarray) { int x; int y; bool first; if ((m_brush.style() != TQBrush::NoBrush) && fill) { first = true; 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); first = false; } else { cairo_line_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); } } if (close) { cairo_close_path(m_painter); } dualStrokeBrush((winding)?CAIRO_FILL_RULE_EVEN_ODD:CAIRO_FILL_RULE_WINDING); } if (m_pen.style() != TQPen::NoPen) { first = true; 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); first = false; } else { cairo_line_to(m_painter, x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET); } } if (close) { cairo_close_path(m_painter); } dualStrokePen(); } } cairo_restore(m_painter); } } void TQt3CairoPaintDevice::drawRoundRect(int x, int y, int w, int h, int xRnd, int yRnd) { if (!m_painter) { return; } if ( xRnd <= 0 || yRnd <= 0 ) { // Draw normal rectangle TQPDevCmdParam param[2]; int command = PdcDrawRect; TQRect rectangle(x, y, w, h); param[0].rect = &rectangle; cmd(command, NULL, param); return; } if ( xRnd >= 100 ) { // fix ranges xRnd = 99; } if ( yRnd >= 100 ) { yRnd = 99; } if ( w <= 0 || h <= 0 ) { fix_neg_rect( &x, &y, &w, &h ); } w--; h--; int rxx = w*xRnd/200; int ryy = h*yRnd/200; // were there overflows? if ( rxx < 0 ) { rxx = w/200*xRnd; } if ( ryy < 0 ) { ryy = h/200*yRnd; } int rxx2 = 2*rxx; int ryy2 = 2*ryy; TQPointArray a[4]; a[0].makeArc( x, y, rxx2, ryy2, 1*16*90, 16*90 ); a[1].makeArc( x, y+h-ryy2, rxx2, ryy2, 2*16*90, 16*90 ); a[2].makeArc( x+w-rxx2, y+h-ryy2, rxx2, ryy2, 3*16*90, 16*90 ); a[3].makeArc( x+w-rxx2, y, rxx2, ryy2, 0*16*90, 16*90 ); // ### is there a better way to join TQPointArrays? TQPointArray aa; aa.resize( a[0].size() + a[1].size() + a[2].size() + a[3].size() ); uint j = 0; for ( int k=0; k<4; k++ ) { for ( uint i=0; i (360*16) ) { a = a % (360*16); } else if ( a < 0 ) { a = a % (360*16); if ( a < 0 ) { a += (360*16); } } TQPointArray pa; 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; pa.resize(n+2); pa.setPoint(n, cx, cy); // add legs pa.setPoint(n+1, pa.at(0)); // Draw polygon drawPolygon(&pa, false, true, true); return; } void TQt3CairoPaintDevice::drawChord(int x, int y, int w, int h, int a, int alen) { if (!m_painter) { return; } TQPointArray pa; pa.makeArc(x, y, w-1, h-1, a, alen); // arc polygon int n = pa.size(); pa.resize(n+1); pa.setPoint(n, pa.at(0)); // connect endpoints // Draw polygon drawPolygon(&pa, false, true, true); 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); pango_font_description_free(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); if (m_tabStopArrayValid) { pango_layout_set_tabs(layout, m_tabStopArray); } else if (m_tabStopsValid) { pango_layout_set_tabs(layout, m_tabStops); } else { pango_layout_set_tabs(layout, NULL); } } void TQt3CairoPaintDevice::drawText(TQPainter *p, int x, int y, const TQString &str) { 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, y-baseline_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); transferIntermediateSurface(); } void TQt3CairoPaintDevice::drawTextInRect(TQPainter *p, TQRect rect, int textFlags, const TQString &str) { if ((!m_painter) || (!p)) { return; } PangoLayout *layout; layout = pango_cairo_create_layout(m_painter); TQFont::StyleStrategy qt3fontstrategy = m_font.styleStrategy(); pangoSetupTextPath(layout, str.utf8()); pango_layout_set_width(layout, rect.width()*PANGO_SCALE); int fudgedOffsetY = 0; // Layout flags if (textFlags & TQt::SingleLine) { // Pango special case to force rendering of only one line of text 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_clip(m_painter); } if (textFlags & TQt::ExpandTabs) { // FIXME } if (textFlags & TQt::ShowPrefix) { // FIXME } if (textFlags & TQt::WordBreak) { pango_layout_set_wrap(layout, PANGO_WRAP_WORD); } if (textFlags & TQt::BreakAnywhere) { pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); } if (textFlags & TQt::NoAccel) { // FIXME } PangoRectangle inkRect; PangoRectangle logicalRect; pango_layout_get_pixel_extents(layout, &inkRect, &logicalRect); int stockWidth = logicalRect.x + logicalRect.width; int stockHeight = logicalRect.y + logicalRect.height; pango_layout_set_height(layout, rect.height()*PANGO_SCALE); // Position flags if (textFlags & TQt::AlignAuto) { // FIXME } if (textFlags & TQt::AlignLeft) { pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); } if (textFlags & TQt::AlignRight) { pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT); } if (textFlags & TQt::AlignHCenter) { pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); } if (textFlags & TQt::AlignJustify) { // FIXME } if (textFlags & TQt::AlignTop) { fudgedOffsetY = 0; } if (textFlags & TQt::AlignBottom) { fudgedOffsetY = (rect.height()-stockHeight); } if (textFlags & TQt::AlignVCenter) { fudgedOffsetY = ((rect.height()-stockHeight)/2); } cairo_new_path(m_painter); cairo_move_to(m_painter, rect.x(), rect.y() + fudgedOffsetY); 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); } cairo_reset_clip(m_painter); g_object_unref(layout); transferIntermediateSurface(); } void TQt3CairoPaintDevice::setCairoTransformations() { cairo_matrix_t combinedMatrix; cairo_matrix_t tempMatrix; cairo_matrix_init_identity(&combinedMatrix); if (m_worldMatrixEnabled) { cairo_matrix_multiply(&tempMatrix, &combinedMatrix, &m_worldMatrix); combinedMatrix = tempMatrix; } if (m_viewportMatrixEnabled) { cairo_matrix_multiply(&tempMatrix, &combinedMatrix, &m_viewportMatrix); combinedMatrix = tempMatrix; } cairo_set_matrix(m_painter, &combinedMatrix); } /*! \class TQt3CairoPaintDevice tdeqt4painter.h \brief The TQt3CairoPaintDevice class is a paint device that translates Qt paint events to a TQt painter. \ingroup graphics \ingroup shared */ /*! 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) { m_surface = cairosurface; m_worldMatrixStack.setAutoDelete(TRUE); m_tabStops = pango_tab_array_new(0, false); m_tabStopArray = pango_tab_array_new(0, false); } /*! Destroys the TQt3CairoPaintDevice. */ TQt3CairoPaintDevice::~TQt3CairoPaintDevice() { if (m_tabStops) { pango_tab_array_free(m_tabStops); } if (m_tabStopArray) { pango_tab_array_free(m_tabStopArray); } if (m_painter) { cairo_destroy(m_painter); m_painter = NULL; } if (m_devicePainter) { cairo_destroy(m_devicePainter); m_devicePainter = NULL; } if (m_intermediateSurface) { cairo_surface_destroy(m_intermediateSurface); } } /*! \internal Implementation of the function forwarded above to the internal data struct. */ bool TQt3CairoPaintDevice::cmd( int c, TQPainter *pt, TQPDevCmdParam *p ) { unsigned int i; double x; double y; double x2; double y2; double width; double height; int index; int count; int lineCount; // Convert data types if (p) { if ((c == PdcDrawPoint) || (c == PdcMoveTo) || (c == PdcLineTo) || (c == PdcSetBrushOrigin)) { x = p[0].point->x(); y = p[0].point->y(); } if (c == PdcDrawLine) { x = p[0].point->x(); y = p[0].point->y(); x2 = p[1].point->x(); y2 = p[1].point->y(); } if ((c == PdcDrawRect) || (c == PdcDrawRoundRect) || (c == PdcDrawEllipse) || (c == PdcDrawArc) || (c == PdcDrawPie) || (c == PdcDrawChord)) { x = p[0].rect->x(); y = p[0].rect->y(); width = p[0].rect->width(); height = p[0].rect->height(); } } // Perform drawing operation switch ( c ) { // exec cmd case PdcNOP: break; case PdcDrawPoint: 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); updatePen(FALSE); cairo_set_line_cap(m_painter, CAIRO_LINE_CAP_ROUND); cairo_stroke(m_painter); } cairo_restore(m_painter); transferIntermediateSurface(); } break; case PdcMoveTo: 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_restore(m_painter); } break; case PdcLineTo: 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); dualStrokePen(); } cairo_restore(m_painter); } break; case PdcDrawLine: 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); dualStrokePen(); } cairo_restore(m_painter); } break; 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(); } 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)); dualStrokeBrush(CAIRO_FILL_RULE_EVEN_ODD); } cairo_restore(m_painter); } else { #if defined(QT_CHECK_RANGE) tqWarning( "TQt3CairoPaintDevice::cmd: TQPainter::begin must be called before PdcDrawRect" ); #endif } break; case PdcDrawRoundRect: if (m_painter) { cairo_save(m_painter); if (p) { drawRoundRect(x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET, width, height, p[1].ival, p[2].ival); } cairo_restore(m_painter); } break; case PdcDrawEllipse: if (m_painter) { cairo_save(m_painter); if (p) { drawEllipse(x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET, width, height); } cairo_restore(m_painter); } break; case PdcDrawArc: if (m_painter) { cairo_save(m_painter); if (p) { drawArc(x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET, width, height, p[1].ival, p[2].ival); } cairo_restore(m_painter); } break; case PdcDrawPie: if (m_painter) { cairo_save(m_painter); if (p) { drawPie(x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET, width, height, p[1].ival, p[2].ival); } cairo_restore(m_painter); } break; case PdcDrawChord: if (m_painter) { cairo_save(m_painter); if (p) { drawChord(x+CAIRO_PIXEL_OFFSET, y+CAIRO_PIXEL_OFFSET, width, height, p[1].ival, p[2].ival); } cairo_restore(m_painter); } break; case PdcDrawLineSegments: 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; case PdcDrawPolyline: if (p) { drawPolygon(p[0].ptarr, false, false, true); } break; case PdcDrawPolygon: if (p) { drawPolygon(p[0].ptarr, p[1].ival, true, true); } break; case PdcDrawCubicBezier: 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; case PdcDrawText: 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); } cairo_restore(m_painter); } break; case PdcDrawTextFormatted: if (m_painter) { cairo_save(m_painter); if (p) { TQRect rect = *p[0].rect; TQString string = *p[2].str; drawTextInRect(pt, rect, p[1].ival, string); } cairo_restore(m_painter); } break; case PdcDrawText2: 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); } cairo_restore(m_painter); } break; case PdcDrawText2Formatted: if (m_painter) { cairo_save(m_painter); if (p) { TQRect rect = *p[0].rect; TQString string = *p[2].str; drawTextInRect(pt, rect, p[1].ival, string); } cairo_restore(m_painter); } break; case PdcDrawPixmap: if (m_painter) { cairo_save(m_painter); if (p) { TQImage 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()); cairo_fill(m_painter); cairo_surface_destroy(sourceSurface); } cairo_restore(m_painter); transferIntermediateSurface(); } break; case PdcDrawImage: if (m_painter) { cairo_save(m_painter); if (p) { TQRect rect = *p[0].rect; TQImage image = *p[1].image; cairo_surface_t* sourceSurface = TQImageToCairoSurface(image); cairo_rectangle(m_painter, rect.x(), rect.y(), rect.width(), rect.height()); cairo_set_source_surface(m_painter, sourceSurface, rect.x(), rect.y()); cairo_fill(m_painter); cairo_surface_destroy(sourceSurface); } cairo_restore(m_painter); transferIntermediateSurface(); } break; case PdcBegin: if (!m_painter) { m_bgColor = TQColor(0,0,0); 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(); m_brushOrigin = TQPoint(0,0); m_worldMatrixEnabled = false; m_viewportMatrixEnabled = false; 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(); m_tabStopsValid = false; m_tabStopArrayValid = false; } break; case PdcEnd: if (m_painter) { cairo_destroy(m_painter); m_painter = NULL; } if (m_devicePainter) { cairo_destroy(m_devicePainter); m_devicePainter = NULL; } break; case PdcSave: cairo_save(m_painter); break; case PdcRestore: cairo_restore(m_painter); break; case PdcSetBkColor: if (p) { const TQColor* color = p[0].color; if (color) { m_bgColor = *color; } } break; case PdcSetBkMode: if (p) { m_bgColorMode = (TQt::BGMode)p[0].ival; } break; case PdcSetROP: if ((p) && (m_painter)) { TQt::RasterOp rop = (TQt::RasterOp)p[0].ival; m_rop = rop; } break; case PdcSetBrushOrigin: if (p) { const TQPoint* point = p[0].point; if (point) { m_brushOrigin = *point; } } break; case PdcSetFont: if (p) { const TQFont* font = p[0].font; if (font) { m_font = *font; } } break; case PdcSetPen: if (p) { const TQPen* pen = p[0].pen; if (pen) { m_pen = *pen; } } break; case PdcSetBrush: if (p) { const TQBrush* brush = p[0].brush; if (brush) { m_brush = *brush; } } break; case PdcSetTabStops: if (p) { int tabspacing = p[0].ival; if (tabspacing > 0) { // Set up a repeating tab stop pattern pango_tab_array_resize(m_tabStops, 2); pango_tab_array_set_tab(m_tabStops, 0, PANGO_TAB_LEFT, (tabspacing*1)*PANGO_SCALE); pango_tab_array_set_tab(m_tabStops, 1, PANGO_TAB_LEFT, (tabspacing*2)*PANGO_SCALE); m_tabStopsValid = true; } else { pango_tab_array_resize(m_tabStops, 0); m_tabStopsValid = false; } } break; case PdcSetTabArray: if (p) { int tabcount = p[0].ival; if (tabcount > 0) { int* tabarray = p[1].ivec; pango_tab_array_resize(m_tabStopArray, tabcount); int i; for (i=0;iviewport(); int wx = p[0].rect->x(); int wy = p[0].rect->y(); int ww = p[0].rect->width(); int wh = p[0].rect->height(); int vx = viewportRect.x(); int vy = viewportRect.y(); int vw = viewportRect.width(); int vh = viewportRect.height(); double scaleW = (double)vw/(double)ww; double scaleH = (double)vh/(double)wh; cairo_matrix_init(&m_viewportMatrix, scaleW, 0, 0, scaleH, vx - wx*scaleW, vy - wy*scaleH); setCairoTransformations(); } break; case PdcSetViewport: if ((p) && (m_painter) && (pt)) { TQRect windowRect = pt->window(); int wx = windowRect.x(); int wy = windowRect.y(); int ww = windowRect.width(); int wh = windowRect.height(); int vx = p[0].rect->x(); int vy = p[0].rect->y(); int vw = p[0].rect->width(); int vh = p[0].rect->height(); double scaleW = (double)vw/(double)ww; double scaleH = (double)vh/(double)wh; cairo_matrix_init(&m_viewportMatrix, scaleW, 0, 0, scaleH, vx - wx*scaleW, vy - wy*scaleH); setCairoTransformations(); } break; case PdcSetWXform: if ((p) && (m_painter)) { m_worldMatrixEnabled = p[0].ival; setCairoTransformations(); } break; case PdcSetWMatrix: if ((p) && (m_painter)) { const TQWMatrix* tqt3matrix = p[0].matrix; if (tqt3matrix) { if (p[1].ival) { // Combine cairo_matrix_t new_matrix; cairo_matrix_t original_matrix = m_worldMatrix; cairo_matrix_init(&new_matrix, tqt3matrix->m11(), tqt3matrix->m12(), tqt3matrix->m21(), tqt3matrix->m22(), tqt3matrix->dx(), tqt3matrix->dy()); cairo_matrix_multiply(&m_worldMatrix, &original_matrix, &new_matrix); } else { // Replace cairo_matrix_init(&m_worldMatrix, tqt3matrix->m11(), tqt3matrix->m12(), tqt3matrix->m21(), tqt3matrix->m22(), tqt3matrix->dx(), tqt3matrix->dy()); } setCairoTransformations(); } } break; case PdcSaveWMatrix: if (p) { const TQWMatrix* tqt3matrix = p[0].matrix; m_worldMatrixStack.push(new TQWMatrix(*tqt3matrix)); } break; case PdcRestoreWMatrix: if (p) { if (!m_worldMatrixStack.isEmpty()) { TQWMatrix* matrix = m_worldMatrixStack.pop(); // Set world matrix TQPDevCmdParam param[2]; int command = PdcSetWMatrix; param[0].matrix = matrix; param[1].ival = 0; cmd(command, pt, param); delete matrix; } } break; case PdcSetClip: if ((p) && (m_painter)) { m_clipRegionEnabled = p[0].ival; } break; case PdcSetClipRegion: if ((p) && (m_painter)) { // SLOW TQRect tqt3br = p[0].rgn->boundingRect(); if (!tqt3br.isNull()) { m_clipRegion = TQImage(tqt3br.x()+tqt3br.width(), tqt3br.y()+tqt3br.height(), 32); int x; int y; for (x=0; xcontains(point))?0xffffffff:0x00000000); } } m_clipRegionEnabled = true; } else { m_clipRegion = TQImage(); m_clipRegionEnabled = false; } } break; default: #if defined(QT_CHECK_RANGE) tqWarning( "TQt3CairoPaintDevice::cmd: Invalid command %d", c ); #endif } return TRUE; } /*! Internal implementation of the virtual TQPaintDevice::metric() function. Use the TQPaintDeviceMetrics class instead. A picture has the following hard-coded values: dpi=72, numcolors=16777216 and depth=24. \a m is the metric to get. */ int TQt3CairoPaintDevice::metric( int m ) const { int val; if (m_surface) { double x_pixels_per_inch; double y_pixels_per_inch; cairo_format_t format; switch ( m ) { // ### hard coded dpi and color depth values ! case TQPaintDeviceMetrics::PdmWidth: val = cairo_image_surface_get_width(m_surface); break; case TQPaintDeviceMetrics::PdmHeight: val = cairo_image_surface_get_height(m_surface); break; case TQPaintDeviceMetrics::PdmWidthMM: 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); break; case TQPaintDeviceMetrics::PdmHeightMM: 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); break; case TQPaintDeviceMetrics::PdmDpiX: cairo_surface_get_fallback_resolution(m_surface, &x_pixels_per_inch, &y_pixels_per_inch); val = x_pixels_per_inch; break; case TQPaintDeviceMetrics::PdmPhysicalDpiX: cairo_surface_get_fallback_resolution(m_surface, &x_pixels_per_inch, &y_pixels_per_inch); val = x_pixels_per_inch; break; case TQPaintDeviceMetrics::PdmDpiY: cairo_surface_get_fallback_resolution(m_surface, &x_pixels_per_inch, &y_pixels_per_inch); val = y_pixels_per_inch; break; case TQPaintDeviceMetrics::PdmPhysicalDpiY: cairo_surface_get_fallback_resolution(m_surface, &x_pixels_per_inch, &y_pixels_per_inch); val = y_pixels_per_inch; break; case TQPaintDeviceMetrics::PdmNumColors: format = cairo_image_surface_get_format(m_surface); if (format == CAIRO_FORMAT_ARGB32) { val = INT_MAX; } else if (format == CAIRO_FORMAT_RGB24) { val = 16777216; } else if (format == CAIRO_FORMAT_RGB16_565) { val = 65536; } else { val = 65536; } break; case TQPaintDeviceMetrics::PdmDepth: format = cairo_image_surface_get_format(m_surface); if (format == CAIRO_FORMAT_ARGB32) { val = 32; } else if (format == CAIRO_FORMAT_RGB24) { val = 24; } else if (format == CAIRO_FORMAT_RGB16_565) { val = 16; } else { val = 16; } break; default: val = 0; #if defined(QT_CHECK_RANGE) tqWarning( "TQt3CairoPaintDevice::metric: Invalid metric command" ); #endif } } else { val = 0; #if defined(QT_CHECK_RANGE) tqWarning( "TQt3CairoPaintDevice::metric: No Cairo surface available" ); #endif } return val; }