You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1548 lines
43 KiB
1548 lines
43 KiB
/****************************************************************************
|
|
**
|
|
** 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)
|
|
|
|
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);
|
|
}
|
|
|
|
void TQt3CairoPaintDevice::transferIntermediateSurface() {
|
|
cairo_surface_flush(m_intermediateSurface);
|
|
if (!m_clipRegionEnabled) {
|
|
// Clipping disabled
|
|
cairo_set_source_surface(m_devicePainter, m_intermediateSurface, 0, 0);
|
|
cairo_set_operator(m_devicePainter, CAIRO_OPERATOR_SOURCE);
|
|
cairo_paint(m_devicePainter);
|
|
}
|
|
else {
|
|
// Clipping enabled
|
|
cairo_surface_t* maskSurface = TQImageToCairoSurface(m_clipRegion);
|
|
cairo_mask_surface(m_devicePainter, maskSurface, 0, 0);
|
|
cairo_fill(m_devicePainter);
|
|
cairo_surface_destroy(maskSurface);
|
|
}
|
|
|
|
// Clear intermediate surface
|
|
cairo_save(m_painter);
|
|
cairo_set_source_rgba(m_painter, 0.0, 0.0, 0.0, 0.0);
|
|
cairo_paint(m_painter);
|
|
cairo_restore(m_painter);
|
|
}
|
|
|
|
void TQt3CairoPaintDevice::dualStrokePen() {
|
|
if (m_bgColorMode == TQt::OpaqueMode) {
|
|
// Draw background
|
|
cairo_save(m_painter);
|
|
updatePen(TRUE);
|
|
cairo_stroke(m_painter);
|
|
cairo_restore(m_painter);
|
|
}
|
|
// Draw foreground
|
|
updatePen(FALSE);
|
|
cairo_stroke(m_painter);
|
|
transferIntermediateSurface();
|
|
}
|
|
|
|
void TQt3CairoPaintDevice::dualStrokeBrush(cairo_fill_rule_t fillMethod) {
|
|
if (m_bgColorMode == TQt::OpaqueMode) {
|
|
// Draw background
|
|
cairo_save(m_painter);
|
|
updateBrush(TRUE, fillMethod);
|
|
cairo_fill(m_painter);
|
|
cairo_restore(m_painter);
|
|
}
|
|
// Draw foreground
|
|
updateBrush(FALSE, fillMethod);
|
|
cairo_fill(m_painter);
|
|
transferIntermediateSurface();
|
|
}
|
|
|
|
void TQt3CairoPaintDevice::updatePen(bool backgroundStroke) {
|
|
if (!m_painter) {
|
|
return;
|
|
}
|
|
|
|
int ps = m_pen.style();
|
|
|
|
double dashes[10]; // custom pen dashes
|
|
int dash_len = 0; // length of dash list
|
|
int dash_offset = 0;
|
|
cairo_line_cap_t cp = CAIRO_LINE_CAP_BUTT;
|
|
cairo_line_join_t jn = CAIRO_LINE_JOIN_MITER;
|
|
|
|
/*
|
|
We are emulating Windows here. Windows treats m_pen.width() == 1
|
|
(or 0) as a very special case. The fudge variable unifies this
|
|
case with the general case.
|
|
*/
|
|
int dot = m_pen.width(); // width of a dot
|
|
int fudge = 1;
|
|
//bool allow_zero_lw = TRUE;
|
|
bool allow_zero_lw = FALSE;
|
|
if ( dot <= 1 ) {
|
|
dot = 3;
|
|
fudge = 2;
|
|
}
|
|
|
|
switch( ps ) {
|
|
case TQPainter::NoPen:
|
|
case TQPainter::SolidLine:
|
|
break;
|
|
case TQPainter::DashLine:
|
|
dashes[0] = fudge * 3 * dot;
|
|
dashes[1] = fudge * dot;
|
|
dash_len = 2;
|
|
allow_zero_lw = FALSE;
|
|
break;
|
|
case TQPainter::DotLine:
|
|
dashes[0] = dot;
|
|
dashes[1] = dot;
|
|
dash_len = 2;
|
|
allow_zero_lw = FALSE;
|
|
break;
|
|
case TQPainter::DashDotLine:
|
|
dashes[0] = 3 * dot;
|
|
dashes[1] = fudge * dot;
|
|
dashes[2] = dot;
|
|
dashes[3] = fudge * dot;
|
|
dash_len = 4;
|
|
allow_zero_lw = FALSE;
|
|
break;
|
|
case TQPainter::DashDotDotLine:
|
|
dashes[0] = 3 * dot;
|
|
dashes[1] = dot;
|
|
dashes[2] = dot;
|
|
dashes[3] = dot;
|
|
dashes[4] = dot;
|
|
dashes[5] = dot;
|
|
dash_len = 6;
|
|
allow_zero_lw = FALSE;
|
|
break;
|
|
case TQPainter::FineDotLine:
|
|
dot = 1;
|
|
dashes[0] = dot;
|
|
dashes[1] = dot;
|
|
dash_len = 2;
|
|
allow_zero_lw = FALSE;
|
|
}
|
|
Q_ASSERT( dash_len <= (int) sizeof(dashes) );
|
|
|
|
switch ( m_pen.capStyle() ) {
|
|
case TQPainter::SquareCap:
|
|
cp = CAIRO_LINE_CAP_SQUARE;
|
|
break;
|
|
case TQPainter::RoundCap:
|
|
cp = CAIRO_LINE_CAP_ROUND;
|
|
break;
|
|
case TQPainter::FlatCap:
|
|
default:
|
|
cp = CAIRO_LINE_CAP_BUTT;
|
|
break;
|
|
}
|
|
|
|
switch ( m_pen.joinStyle() ) {
|
|
case TQPainter::BevelJoin:
|
|
jn = CAIRO_LINE_JOIN_BEVEL;
|
|
break;
|
|
case TQPainter::RoundJoin:
|
|
jn = CAIRO_LINE_JOIN_ROUND;
|
|
break;
|
|
case TQPainter::MiterJoin:
|
|
default:
|
|
jn = CAIRO_LINE_JOIN_MITER;
|
|
break;
|
|
}
|
|
|
|
if (backgroundStroke) {
|
|
dash_len = 0;
|
|
|
|
}
|
|
|
|
cairo_set_dash(m_painter, dashes, dash_len, dash_offset);
|
|
cairo_set_line_cap(m_painter, cp);
|
|
cairo_set_line_join(m_painter, jn);
|
|
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)/255.0, tqGreen(color)/255.0, tqBlue(color)/255.0, tqAlpha(color)/255.0);
|
|
}
|
|
|
|
void TQt3CairoPaintDevice::updateBrush(bool backgroundStroke, cairo_fill_rule_t fillMethod) {
|
|
if (!m_painter) {
|
|
return;
|
|
}
|
|
|
|
if (backgroundStroke) {
|
|
TQRgb color = m_bgColor.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);
|
|
}
|
|
else {
|
|
static const uchar dense1_pat[] = { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff };
|
|
static const uchar dense2_pat[] = { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff };
|
|
static const uchar dense3_pat[] = { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee };
|
|
static const uchar dense4_pat[] = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa };
|
|
static const uchar dense5_pat[] = { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 };
|
|
static const uchar dense6_pat[] = { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 };
|
|
static const uchar dense7_pat[] = { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 };
|
|
static const uchar hor_pat[] = { // horizontal pattern
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
static const uchar ver_pat[] = { // vertical pattern
|
|
0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20,
|
|
0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20,
|
|
0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20,
|
|
0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20,
|
|
0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20,
|
|
0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20 };
|
|
static const uchar cross_pat[] = { // cross pattern
|
|
0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0xff, 0xff, 0xff,
|
|
0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20,
|
|
0x08, 0x82, 0x20, 0xff, 0xff, 0xff, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20,
|
|
0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0xff, 0xff, 0xff,
|
|
0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20,
|
|
0x08, 0x82, 0x20, 0xff, 0xff, 0xff, 0x08, 0x82, 0x20, 0x08, 0x82, 0x20 };
|
|
static const uchar bdiag_pat[] = { // backward diagonal pattern
|
|
0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01,
|
|
0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04,
|
|
0x02, 0x02, 0x01, 0x01, 0x80, 0x80, 0x40, 0x40 };
|
|
static const uchar fdiag_pat[] = { // forward diagonal pattern
|
|
0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40,
|
|
0x80, 0x80, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10,
|
|
0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x01, 0x01 };
|
|
static const uchar dcross_pat[] = { // diagonal cross pattern
|
|
0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x14, 0x14, 0x22, 0x22, 0x41, 0x41,
|
|
0x80, 0x80, 0x41, 0x41, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x14, 0x14,
|
|
0x22, 0x22, 0x41, 0x41, 0x80, 0x80, 0x41, 0x41 };
|
|
static const uchar * const pat_tbl[] = {
|
|
dense1_pat, dense2_pat, dense3_pat, dense4_pat, dense5_pat,
|
|
dense6_pat, dense7_pat,
|
|
hor_pat, ver_pat, cross_pat, bdiag_pat, fdiag_pat, dcross_pat };
|
|
|
|
int bs = m_brush.style();
|
|
|
|
const uchar *pat = 0; // pattern
|
|
int d = 0; // defalt pattern size: d*d
|
|
if ( bs >= 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; x<d; x++) {
|
|
for (y=0; y<d; y++) {
|
|
brushImage.setPixel(y, x, (TEST_BIT(pat[byte], bit))?color:0x00000000);
|
|
bit--;
|
|
if (bit < 0) {
|
|
bit = 7;
|
|
byte++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
TQPixmap *pm;
|
|
pm = m_brush.pixmap();
|
|
brushImage = pm->convertToImage();
|
|
}
|
|
|
|
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;i<pointarray->count();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;i<pointarray->count();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<a[k].size(); i++ ) {
|
|
aa.setPoint( j, a[k].point(i) );
|
|
j++;
|
|
}
|
|
}
|
|
|
|
// Draw polygon
|
|
drawPolygon(&aa, false, true, true);
|
|
|
|
return;
|
|
}
|
|
|
|
void TQt3CairoPaintDevice::drawEllipse(int x, int y, int w, int h) {
|
|
if (!m_painter) {
|
|
return;
|
|
}
|
|
|
|
TQPointArray a;
|
|
a.makeArc(x, y, w, h, 0, 360*16);
|
|
|
|
// Draw polygon
|
|
drawPolygon(&a, false, true, true);
|
|
|
|
return;
|
|
}
|
|
|
|
void TQt3CairoPaintDevice::drawArc(int x, int y, int w, int h, int a, int alen) {
|
|
if (!m_painter) {
|
|
return;
|
|
}
|
|
|
|
TQPointArray pa;
|
|
pa.makeArc(x, y, w, h, a, alen); // arc polyline
|
|
|
|
// Draw polygon
|
|
drawPolygon(&pa, false, false, false);
|
|
|
|
return;
|
|
}
|
|
|
|
void TQt3CairoPaintDevice::drawPie(int x, int y, int w, int h, int a, int alen) {
|
|
if (!m_painter) {
|
|
return;
|
|
}
|
|
|
|
// Make sure "a" is 0..360*16, as otherwise a*4 may overflow 16 bits.
|
|
if ( a > (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);
|
|
|
|
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) {
|
|
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_surface = cairosurface;
|
|
m_worldMatrixStack.setAutoDelete(TRUE);
|
|
}
|
|
|
|
/*!
|
|
Destroys the TQt3CairoPaintDevice.
|
|
*/
|
|
TQt3CairoPaintDevice::~TQt3CairoPaintDevice()
|
|
{
|
|
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;i<pointarray->count();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;i<pointarray->count();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);
|
|
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_clipRegion = TQImage();
|
|
m_clipRegionEnabled = false;
|
|
m_worldMatrixStack.clear();
|
|
}
|
|
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)) {
|
|
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:
|
|
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;
|
|
#if 0
|
|
case PdcSetTabStops:
|
|
s >> i_16;
|
|
painter->setTabStops( i_16 );
|
|
break;
|
|
case PdcSetTabArray:
|
|
s >> i_16;
|
|
if ( i_16 == 0 ) {
|
|
painter->setTabArray( 0 );
|
|
} else {
|
|
int *ta = new int[i_16];
|
|
TQ_CHECK_PTR( ta );
|
|
for ( int i=0; i<i_16; i++ ) {
|
|
s >> i1_16;
|
|
ta[i] = i1_16;
|
|
}
|
|
painter->setTabArray( ta );
|
|
delete [] ta;
|
|
}
|
|
break;
|
|
#endif
|
|
case PdcSetVXform:
|
|
if ((p) && (m_painter)) {
|
|
m_viewportMatrixEnabled = p[0].ival;
|
|
setCairoTransformations();
|
|
}
|
|
break;
|
|
case PdcSetWindow:
|
|
if ((p) && (m_painter) && (pt)) {
|
|
TQRect viewportRect = pt->viewport();
|
|
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; x<m_clipRegion.width(); x++) {
|
|
for (y=0; y<m_clipRegion.height(); y++) {
|
|
TQPoint point(x,y);
|
|
m_clipRegion.setPixel(x, y, (p[0].rgn->contains(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;
|
|
}
|
|
|