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.
1894 lines
56 KiB
1894 lines
56 KiB
/****************************************************************************
|
|
**
|
|
** Implementation of TQt3CairoPaintDevice class
|
|
**
|
|
** Copyright (C) 2012 Timothy Pearson. All rights reserved.
|
|
**
|
|
** This file is part of the TDE GTK3 style interface
|
|
**
|
|
** This file may be used under the terms of the GNU General
|
|
** Public License versions 2.0 or 3.0 as published by the Free
|
|
** 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_PEN_PIXEL_OFFSET (0.5)
|
|
#define CAIRO_BRUSH_PIXEL_OFFSET (0.0)
|
|
#define CAIRO_FONT_SIZE_FUDGE_FACTOR (1.4)
|
|
|
|
#define SET_BIT(x, y) (x |= 1 << y)
|
|
#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
|
|
|
|
inline int cairoPainterRectSubtraction(TQPen* pen) {
|
|
return ((pen->style() != TQt::NoPen) && ((pen->width() == 0) || (pen->width() == 1))) ? 1 : 0;
|
|
}
|
|
|
|
inline void standardAlphaToPremultipliedAlpha(unsigned char *a, unsigned char *r, unsigned char *g, unsigned char *b) {
|
|
register double alpha_adjust;
|
|
|
|
alpha_adjust = (*a / 255.0);
|
|
*r = char( *r * alpha_adjust );
|
|
*g = char( *g * alpha_adjust );
|
|
*b = char( *b * alpha_adjust );
|
|
*a = char( *a * 1.0 );
|
|
}
|
|
|
|
inline void premultipliedAlphaToStandardAlpha(unsigned char *a, unsigned char *r, unsigned char *g, unsigned char *b) {
|
|
register double alpha_adjust;
|
|
|
|
alpha_adjust = (*a / 255.0);
|
|
*r = char( *r / alpha_adjust );
|
|
*g = char( *g / alpha_adjust );
|
|
*b = char( *b / alpha_adjust );
|
|
*a = char( *a / 1.0 );
|
|
}
|
|
|
|
cairo_surface_t* TQImageToCairoSurface(TQImage origimg) {
|
|
cairo_surface_t* ret;
|
|
|
|
TQImage img;
|
|
if (origimg.depth() < 24) {
|
|
img = origimg.convertDepth(32);
|
|
}
|
|
else {
|
|
img = origimg;
|
|
}
|
|
|
|
int depth = img.depth();
|
|
if (depth == 32) {
|
|
// Convert ARGB to premultiplied ARGB
|
|
// SLOW
|
|
int x;
|
|
int y;
|
|
for (x=0; x<img.width(); x++) {
|
|
for (y=0; y<img.height(); y++) {
|
|
unsigned int pixel = img.pixel(x, y);
|
|
unsigned char a = (pixel & 0xff000000) >> 24;
|
|
unsigned char r = (pixel & 0x00ff0000) >> 16;
|
|
unsigned char g = (pixel & 0x0000ff00) >> 8;
|
|
unsigned char b = (pixel & 0x000000ff) >> 0;
|
|
standardAlphaToPremultipliedAlpha(&a, &r, &g, &b);
|
|
pixel = (a << 24) | (r << 16) | (g << 8) | (b << 0);
|
|
img.setPixel(x, y, pixel);
|
|
}
|
|
}
|
|
}
|
|
|
|
cairo_format_t cairo_format;
|
|
if (depth == 32) {
|
|
cairo_format = CAIRO_FORMAT_ARGB32;
|
|
}
|
|
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);
|
|
}
|
|
|
|
updateSurfaceDimensions();
|
|
int height = m_height;
|
|
int width = m_width;
|
|
m_intermediateSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
|
}
|
|
|
|
// FIXME
|
|
// transferIntermediateSurface should only be used when clipping is active or ROP != CopyROP
|
|
// Cairo however does not allow the target surface of a context to be switched, effectively preventing
|
|
// direct drawing with dynamic switching to and from the intermediate surface on clip or ROP set/unset
|
|
// See upstream Cairo bug report https://bugs.freedesktop.org/show_bug.cgi?id=57289
|
|
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);
|
|
updateSurfaceDimensions();
|
|
register int height = m_height;
|
|
register int width = m_width;
|
|
register int stride = cairo_format_stride_for_width(cairo_image_surface_get_format(m_surface), width);
|
|
cairo_surface_t *usableDeviceSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
|
cairo_t *copyPainter = cairo_create(usableDeviceSurface);
|
|
cairo_set_source_surface(copyPainter, m_surface, 0, 0);
|
|
cairo_set_operator(copyPainter, CAIRO_OPERATOR_SOURCE);
|
|
cairo_paint(copyPainter);
|
|
cairo_surface_flush(usableDeviceSurface);
|
|
cairo_destroy(copyPainter);
|
|
unsigned char* device_surface_data = cairo_image_surface_get_data(usableDeviceSurface);
|
|
unsigned char* intermediate_surface_data = cairo_image_surface_get_data(m_intermediateSurface);
|
|
register int x;
|
|
register int y;
|
|
register long long offset;
|
|
register unsigned char devicePixel_a;
|
|
register unsigned char devicePixel_r;
|
|
register unsigned char devicePixel_g;
|
|
register unsigned char devicePixel_b;
|
|
register unsigned char intermediatePixel_a;
|
|
register unsigned char intermediatePixel_r;
|
|
register unsigned char intermediatePixel_g;
|
|
register unsigned char intermediatePixel_b;
|
|
register unsigned char combinedPixel_a;
|
|
register unsigned char combinedPixel_r;
|
|
register unsigned char combinedPixel_g;
|
|
register unsigned char combinedPixel_b;
|
|
// Execute the desired raster operation
|
|
// WARNING
|
|
// This is VERY SLOW
|
|
for (y=0; y<height; y++) {
|
|
for (x=0; x<stride; x=x+4) {
|
|
offset = (y*stride)+x;
|
|
|
|
// Convert from premultiplied ARGB
|
|
premultipliedAlphaToStandardAlpha(intermediate_surface_data+offset+ARGB_A_BYTE_NUMBER, intermediate_surface_data+offset+ARGB_R_BYTE_NUMBER, intermediate_surface_data+offset+ARGB_G_BYTE_NUMBER, intermediate_surface_data+offset+ARGB_B_BYTE_NUMBER);
|
|
intermediatePixel_a = (*(intermediate_surface_data+offset+ARGB_A_BYTE_NUMBER));
|
|
intermediatePixel_r = (*(intermediate_surface_data+offset+ARGB_R_BYTE_NUMBER));
|
|
intermediatePixel_g = (*(intermediate_surface_data+offset+ARGB_G_BYTE_NUMBER));
|
|
intermediatePixel_b = (*(intermediate_surface_data+offset+ARGB_B_BYTE_NUMBER));
|
|
if (intermediatePixel_a != 0) {
|
|
// Alpha channel of intermediate pixel was set; gather data for bitwise operation
|
|
premultipliedAlphaToStandardAlpha(device_surface_data+offset+ARGB_A_BYTE_NUMBER, device_surface_data+offset+ARGB_R_BYTE_NUMBER, device_surface_data+offset+ARGB_G_BYTE_NUMBER, device_surface_data+offset+ARGB_B_BYTE_NUMBER);
|
|
devicePixel_a = (*(device_surface_data+offset+ARGB_A_BYTE_NUMBER));
|
|
devicePixel_r = (*(device_surface_data+offset+ARGB_R_BYTE_NUMBER));
|
|
devicePixel_g = (*(device_surface_data+offset+ARGB_G_BYTE_NUMBER));
|
|
devicePixel_b = (*(device_surface_data+offset+ARGB_B_BYTE_NUMBER));
|
|
|
|
// Perform requested bitwise operation
|
|
if (m_rop == TQPainter::OrROP) {
|
|
combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00;
|
|
combinedPixel_r = devicePixel_r | intermediatePixel_r;
|
|
combinedPixel_g = devicePixel_g | intermediatePixel_g;
|
|
combinedPixel_b = devicePixel_b | intermediatePixel_b;
|
|
}
|
|
else if (m_rop == TQPainter::XorROP) {
|
|
combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00;
|
|
combinedPixel_r = devicePixel_r ^ intermediatePixel_r;
|
|
combinedPixel_g = devicePixel_g ^ intermediatePixel_g;
|
|
combinedPixel_b = devicePixel_b ^ intermediatePixel_b;
|
|
}
|
|
else if (m_rop == TQPainter::NotAndROP) {
|
|
combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00;
|
|
combinedPixel_r = devicePixel_r & (~intermediatePixel_r);
|
|
combinedPixel_g = devicePixel_g & (~intermediatePixel_g);
|
|
combinedPixel_b = devicePixel_b & (~intermediatePixel_b);
|
|
}
|
|
else if (m_rop == TQPainter::NotCopyROP) {
|
|
combinedPixel_a = intermediatePixel_a;
|
|
combinedPixel_r = ~intermediatePixel_r;
|
|
combinedPixel_g = ~intermediatePixel_g;
|
|
combinedPixel_b = ~intermediatePixel_b;
|
|
}
|
|
else if (m_rop == TQPainter::NotOrROP) {
|
|
combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00;
|
|
combinedPixel_r = devicePixel_r | (~intermediatePixel_r);
|
|
combinedPixel_g = devicePixel_g | (~intermediatePixel_g);
|
|
combinedPixel_b = devicePixel_b | (~intermediatePixel_b);
|
|
}
|
|
else if (m_rop == TQPainter::NotXorROP) {
|
|
combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00;
|
|
combinedPixel_r = devicePixel_r ^ (~intermediatePixel_r);
|
|
combinedPixel_g = devicePixel_g ^ (~intermediatePixel_g);
|
|
combinedPixel_b = devicePixel_b ^ (~intermediatePixel_b);
|
|
}
|
|
else if (m_rop == TQPainter::AndROP) {
|
|
combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00;
|
|
combinedPixel_r = devicePixel_r & intermediatePixel_r;
|
|
combinedPixel_g = devicePixel_g & intermediatePixel_g;
|
|
combinedPixel_b = devicePixel_b & intermediatePixel_b;
|
|
}
|
|
else if (m_rop == TQPainter::NotROP) {
|
|
combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00;
|
|
combinedPixel_r = ~devicePixel_r;
|
|
combinedPixel_g = ~devicePixel_g;
|
|
combinedPixel_b = ~devicePixel_b;
|
|
}
|
|
else if (m_rop == TQPainter::ClearROP) {
|
|
combinedPixel_a = 0x0;
|
|
combinedPixel_r = 0x0;
|
|
combinedPixel_g = 0x0;
|
|
combinedPixel_b = 0x0;
|
|
}
|
|
else if (m_rop == TQPainter::SetROP) {
|
|
combinedPixel_a = 0xff;
|
|
combinedPixel_r = 0xff;
|
|
combinedPixel_g = 0xff;
|
|
combinedPixel_b = 0xff;
|
|
}
|
|
else if (m_rop == TQPainter::NopROP) {
|
|
combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00;
|
|
combinedPixel_r = devicePixel_r;
|
|
combinedPixel_g = devicePixel_g;
|
|
combinedPixel_b = devicePixel_b;
|
|
}
|
|
else if (m_rop == TQPainter::AndNotROP) {
|
|
combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00;
|
|
combinedPixel_r = (~devicePixel_r) & intermediatePixel_r;
|
|
combinedPixel_g = (~devicePixel_g) & intermediatePixel_g;
|
|
combinedPixel_b = (~devicePixel_b) & intermediatePixel_b;
|
|
}
|
|
else if (m_rop == TQPainter::OrNotROP) {
|
|
combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00;
|
|
combinedPixel_r = (~devicePixel_r) | intermediatePixel_r;
|
|
combinedPixel_g = (~devicePixel_g) | intermediatePixel_g;
|
|
combinedPixel_b = (~devicePixel_b) | intermediatePixel_b;
|
|
}
|
|
else if (m_rop == TQPainter::NandROP) {
|
|
combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00;
|
|
combinedPixel_r = ~(devicePixel_r & intermediatePixel_r);
|
|
combinedPixel_g = ~(devicePixel_g & intermediatePixel_g);
|
|
combinedPixel_b = ~(devicePixel_b & intermediatePixel_b);
|
|
}
|
|
else if (m_rop == TQPainter::NorROP) {
|
|
combinedPixel_a = ((devicePixel_a != 0) || (intermediatePixel_a != 0))?0xff:0x00;
|
|
combinedPixel_r = ~(devicePixel_r | intermediatePixel_r);
|
|
combinedPixel_g = ~(devicePixel_g | intermediatePixel_g);
|
|
combinedPixel_b = ~(devicePixel_b | intermediatePixel_b);
|
|
}
|
|
else {
|
|
tqWarning("TQt3CairoPaintDevice::cmd: Unhandled raster operation [Was attempting to use raster operation %d\n\r", m_rop);
|
|
combinedPixel_a = devicePixel_a;
|
|
combinedPixel_r = devicePixel_r;
|
|
combinedPixel_g = devicePixel_g;
|
|
combinedPixel_b = devicePixel_b;
|
|
}
|
|
|
|
// Convert to premultiplied ARGB
|
|
(*(intermediate_surface_data+offset+ARGB_A_BYTE_NUMBER)) = combinedPixel_a;
|
|
(*(intermediate_surface_data+offset+ARGB_R_BYTE_NUMBER)) = combinedPixel_r;
|
|
(*(intermediate_surface_data+offset+ARGB_G_BYTE_NUMBER)) = combinedPixel_g;
|
|
(*(intermediate_surface_data+offset+ARGB_B_BYTE_NUMBER)) = combinedPixel_b;
|
|
standardAlphaToPremultipliedAlpha(intermediate_surface_data+offset+ARGB_A_BYTE_NUMBER, intermediate_surface_data+offset+ARGB_R_BYTE_NUMBER, intermediate_surface_data+offset+ARGB_G_BYTE_NUMBER, intermediate_surface_data+offset+ARGB_B_BYTE_NUMBER);
|
|
}
|
|
else {
|
|
// Lossless copy of premultiplied ARGB pixel values
|
|
(*(intermediate_surface_data+offset+ARGB_A_BYTE_NUMBER)) = (*(device_surface_data+offset+ARGB_A_BYTE_NUMBER));
|
|
(*(intermediate_surface_data+offset+ARGB_R_BYTE_NUMBER)) = (*(device_surface_data+offset+ARGB_R_BYTE_NUMBER));
|
|
(*(intermediate_surface_data+offset+ARGB_G_BYTE_NUMBER)) = (*(device_surface_data+offset+ARGB_G_BYTE_NUMBER));
|
|
(*(intermediate_surface_data+offset+ARGB_B_BYTE_NUMBER)) = (*(device_surface_data+offset+ARGB_B_BYTE_NUMBER));
|
|
}
|
|
}
|
|
}
|
|
cairo_surface_mark_dirty(m_intermediateSurface);
|
|
cairo_surface_destroy(usableDeviceSurface);
|
|
}
|
|
|
|
if (!m_clipRegionEnabled) {
|
|
// Clipping disabled
|
|
cairo_set_source_surface(m_devicePainter, m_intermediateSurface, m_offsetX, m_offsetY);
|
|
cairo_set_operator(m_devicePainter, overlayMerge?CAIRO_OPERATOR_OVER:CAIRO_OPERATOR_SOURCE);
|
|
cairo_paint(m_devicePainter);
|
|
}
|
|
else {
|
|
// Clipping enabled
|
|
cairo_surface_t* maskSurface = TQImageToCairoSurface(m_clipRegion);
|
|
cairo_set_source_surface(m_devicePainter, m_intermediateSurface, m_offsetX, m_offsetY);
|
|
cairo_set_operator(m_devicePainter, overlayMerge?CAIRO_OPERATOR_OVER:CAIRO_OPERATOR_SOURCE);
|
|
|
|
// Clipping enabled
|
|
if (m_worldMatrixEnabled || m_viewportMatrixEnabled) {
|
|
// The mask needs to be transformed before application
|
|
cairo_surface_t* maskSurface = TQImageToCairoSurface(m_clipRegion);
|
|
cairo_surface_t *transformedMaskSurface;
|
|
cairo_t *cr2;
|
|
int maxSize;
|
|
int w = cairo_image_surface_get_width(maskSurface);
|
|
int h = cairo_image_surface_get_height(maskSurface);
|
|
if (w>h) {
|
|
maxSize = w*2;
|
|
}
|
|
else {
|
|
maxSize = h*2;
|
|
}
|
|
transformedMaskSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, maxSize, maxSize);
|
|
cr2 = cairo_create(transformedMaskSurface);
|
|
setCairoTransformations(cr2);
|
|
cairo_set_source_surface (cr2, maskSurface, 0, 0);
|
|
cairo_set_operator(cr2, CAIRO_OPERATOR_SOURCE);
|
|
cairo_paint(cr2);
|
|
|
|
// Paint intermediate surface to final surface through mask
|
|
cairo_set_source_surface(m_devicePainter, m_intermediateSurface, m_offsetX, m_offsetY);
|
|
cairo_set_operator(m_devicePainter, overlayMerge?CAIRO_OPERATOR_OVER:CAIRO_OPERATOR_SOURCE);
|
|
cairo_mask_surface(m_devicePainter, transformedMaskSurface, m_offsetX, m_offsetY);
|
|
cairo_surface_destroy(transformedMaskSurface);
|
|
}
|
|
else {
|
|
// Paint intermediate surface to final surface through mask
|
|
cairo_surface_t* maskSurface = TQImageToCairoSurface(m_clipRegion);
|
|
cairo_set_source_surface(m_devicePainter, m_intermediateSurface, m_offsetX, m_offsetY);
|
|
cairo_set_operator(m_devicePainter, overlayMerge?CAIRO_OPERATOR_OVER:CAIRO_OPERATOR_SOURCE);
|
|
cairo_mask_surface(m_devicePainter, maskSurface, m_offsetX, m_offsetY);
|
|
}
|
|
cairo_surface_destroy(maskSurface);
|
|
}
|
|
|
|
// Clear intermediate surface
|
|
cairo_save(m_painter);
|
|
cairo_set_operator(m_painter, CAIRO_OPERATOR_SOURCE);
|
|
cairo_set_source_rgba(m_painter, 0.0, 0.0, 0.0, 0.0);
|
|
cairo_paint(m_painter);
|
|
cairo_restore(m_painter);
|
|
|
|
m_transferNeeded = false;
|
|
}
|
|
|
|
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);
|
|
m_transferNeeded = true;
|
|
}
|
|
|
|
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);
|
|
m_transferNeeded = true;
|
|
}
|
|
|
|
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()+1, m_brushOrigin.y());
|
|
cairo_pattern_set_matrix(pattern, &brush_translation_matrix);
|
|
cairo_set_source(m_painter, pattern);
|
|
cairo_pattern_set_extend(cairo_get_source(m_painter), CAIRO_EXTEND_REPEAT);
|
|
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_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET);
|
|
first = false;
|
|
}
|
|
else {
|
|
cairo_line_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_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_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET);
|
|
first = false;
|
|
}
|
|
else {
|
|
cairo_line_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_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;
|
|
}
|
|
|
|
w=w+2;
|
|
h=h+2;
|
|
|
|
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+1, h+1, 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)+1;
|
|
cy = (y+h/2)+1;
|
|
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, h, 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!
|
|
// https://bugzilla.gnome.org/show_bug.cgi?id=577190
|
|
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);
|
|
|
|
m_transferNeeded = true;
|
|
}
|
|
|
|
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_PEN_PIXEL_OFFSET, rect.y()+CAIRO_PEN_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);
|
|
|
|
m_transferNeeded = true;
|
|
}
|
|
|
|
void TQt3CairoPaintDevice::setCairoTransformations(cairo_t* cr, bool forceDisable) {
|
|
cairo_matrix_t combinedMatrix;
|
|
cairo_matrix_t tempMatrix;
|
|
|
|
cairo_matrix_init_identity(&combinedMatrix);
|
|
if (!forceDisable) {
|
|
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(cr, &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, int x, int y, int width, int height, cairo_t *overridepainter )
|
|
: TQPaintDevice( TQInternal::Picture | TQInternal::ExternalDevice )
|
|
{
|
|
init();
|
|
|
|
m_offsetX = x;
|
|
m_offsetY = y;
|
|
if (width >= 0) {
|
|
m_width = width;
|
|
}
|
|
if (height >= 0) {
|
|
m_height = height;
|
|
}
|
|
if (overridepainter) {
|
|
m_overridePainter = overridepainter;
|
|
m_surface = cairo_get_group_target(overridepainter);
|
|
}
|
|
else {
|
|
m_surface = cairosurface;
|
|
}
|
|
m_worldMatrixStack.setAutoDelete(TRUE);
|
|
|
|
m_tabStops = pango_tab_array_new(0, false);
|
|
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);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Initializes all data structures
|
|
*/
|
|
void TQt3CairoPaintDevice::init() {
|
|
m_width = -1;
|
|
m_height = -1;
|
|
m_offsetX = 0;
|
|
m_offsetY = 0;
|
|
|
|
m_intermediateSurface = NULL;
|
|
m_painter = NULL;
|
|
m_devicePainter = NULL;
|
|
m_overridePainter = NULL;
|
|
m_tabStops = NULL;
|
|
m_tabStopArray = NULL;
|
|
|
|
m_transferNeeded = false;
|
|
}
|
|
|
|
void TQt3CairoPaintDevice::updateSurfaceDimensions() const {
|
|
if ((m_width < 0) || (m_height < 0)) {
|
|
m_width = cairo_image_surface_get_width(m_surface);
|
|
m_height = cairo_image_surface_get_height(m_surface);
|
|
}
|
|
if ((m_width < 1) || (m_height < 1)) {
|
|
printf("[WARNING] Cairo surface height or width less than 0; drawing will not be possible!\n\r"); fflush(stdout);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
Implementation of the function forwarded above to the internal data struct.
|
|
*/
|
|
|
|
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_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET);
|
|
cairo_line_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET);
|
|
updatePen(FALSE);
|
|
cairo_set_line_cap(m_painter, CAIRO_LINE_CAP_ROUND);
|
|
cairo_stroke(m_painter);
|
|
}
|
|
cairo_restore(m_painter);
|
|
m_transferNeeded = true;
|
|
}
|
|
break;
|
|
case PdcMoveTo:
|
|
if (m_painter) {
|
|
cairo_save(m_painter);
|
|
if (m_pen.style() != TQPen::NoPen) {
|
|
cairo_move_to(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_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_PEN_PIXEL_OFFSET, y2+CAIRO_PEN_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_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET);
|
|
cairo_line_to(m_painter, x2+CAIRO_PEN_PIXEL_OFFSET, y2+CAIRO_PEN_PIXEL_OFFSET);
|
|
dualStrokePen();
|
|
}
|
|
cairo_restore(m_painter);
|
|
}
|
|
break;
|
|
case PdcDrawRect:
|
|
if (m_painter) {
|
|
cairo_save(m_painter);
|
|
int adjustment = cairoPainterRectSubtraction(&m_pen);
|
|
if (m_brush.style() != TQBrush::NoBrush) {
|
|
int line_width = m_pen.width();
|
|
cairo_rectangle(m_painter, x+line_width+CAIRO_BRUSH_PIXEL_OFFSET, y+line_width+CAIRO_BRUSH_PIXEL_OFFSET, width-(line_width*2)-adjustment, height-(line_width*2)-adjustment);
|
|
dualStrokeBrush(CAIRO_FILL_RULE_EVEN_ODD);
|
|
}
|
|
if (m_pen.style() != TQPen::NoPen) {
|
|
cairo_rectangle(m_painter, x+CAIRO_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET, width-adjustment, height-adjustment);
|
|
dualStrokePen();
|
|
}
|
|
cairo_restore(m_painter);
|
|
}
|
|
else {
|
|
#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);
|
|
int adjustment = cairoPainterRectSubtraction(&m_pen);
|
|
if (p) {
|
|
drawRoundRect(x, y, width-adjustment, height-adjustment, p[1].ival, p[2].ival);
|
|
}
|
|
cairo_restore(m_painter);
|
|
}
|
|
break;
|
|
case PdcDrawEllipse:
|
|
if (m_painter) {
|
|
cairo_save(m_painter);
|
|
int adjustment = cairoPainterRectSubtraction(&m_pen);
|
|
if (p) {
|
|
drawEllipse(x, y, width-adjustment, height-adjustment);
|
|
}
|
|
cairo_restore(m_painter);
|
|
}
|
|
break;
|
|
case PdcDrawArc:
|
|
if (m_painter) {
|
|
cairo_save(m_painter);
|
|
int adjustment = cairoPainterRectSubtraction(&m_pen);
|
|
if (p) {
|
|
drawArc(x, y, width-adjustment, height-adjustment, p[1].ival, p[2].ival);
|
|
}
|
|
cairo_restore(m_painter);
|
|
}
|
|
break;
|
|
case PdcDrawPie:
|
|
if (m_painter) {
|
|
cairo_save(m_painter);
|
|
int adjustment = cairoPainterRectSubtraction(&m_pen);
|
|
if (p) {
|
|
drawPie(x, y, width-adjustment, height-adjustment, p[1].ival, p[2].ival);
|
|
}
|
|
cairo_restore(m_painter);
|
|
}
|
|
break;
|
|
case PdcDrawChord:
|
|
if (m_painter) {
|
|
cairo_save(m_painter);
|
|
int adjustment = cairoPainterRectSubtraction(&m_pen);
|
|
if (p) {
|
|
drawChord(x, y, width-adjustment, height-adjustment, 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_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET);
|
|
cairo_line_to(m_painter, x2+CAIRO_PEN_PIXEL_OFFSET, y2+CAIRO_PEN_PIXEL_OFFSET);
|
|
dualStrokePen();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
cairo_restore(m_painter);
|
|
}
|
|
break;
|
|
case PdcDrawPolyline:
|
|
if (p) {
|
|
drawPolygon(p[0].ptarr, false, false, false);
|
|
}
|
|
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_PEN_PIXEL_OFFSET, y+CAIRO_PEN_PIXEL_OFFSET);
|
|
cairo_curve_to(m_painter, x2+CAIRO_PEN_PIXEL_OFFSET, y2+CAIRO_PEN_PIXEL_OFFSET, x3+CAIRO_PEN_PIXEL_OFFSET, y3+CAIRO_PEN_PIXEL_OFFSET, x4+CAIRO_PEN_PIXEL_OFFSET, y4+CAIRO_PEN_PIXEL_OFFSET);
|
|
dualStrokePen();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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_PEN_PIXEL_OFFSET, p[0].rect->y()+CAIRO_PEN_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_PEN_PIXEL_OFFSET, p[0].rect->y()+CAIRO_PEN_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;
|
|
const TQBitmap* bitmap = dynamic_cast<const TQBitmap*>(p[1].pixmap);
|
|
if (bitmap) {
|
|
TQPixmap mergedPixmap = TQPixmap(bitmap->width(), bitmap->height());
|
|
mergedPixmap.fill(m_pen.color());
|
|
mergedPixmap.setMask(*bitmap);
|
|
sourceImage = mergedPixmap.convertToImage();
|
|
}
|
|
else {
|
|
sourceImage = p[1].pixmap->convertToImage();
|
|
}
|
|
cairo_surface_t* sourceSurface = TQImageToCairoSurface(sourceImage);
|
|
cairo_rectangle(m_painter, p[0].rect->x(), p[0].rect->y(), p[0].rect->width(), p[0].rect->height());
|
|
cairo_set_source_surface(m_painter, sourceSurface, p[0].rect->x(), p[0].rect->y());
|
|
cairo_fill(m_painter);
|
|
cairo_surface_destroy(sourceSurface);
|
|
}
|
|
cairo_restore(m_painter);
|
|
m_transferNeeded = true;
|
|
}
|
|
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);
|
|
m_transferNeeded = true;
|
|
}
|
|
break;
|
|
case PdcBegin:
|
|
if (!m_painter) {
|
|
m_transferNeeded = false;
|
|
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);
|
|
if (m_overridePainter) {
|
|
m_devicePainter = m_overridePainter;
|
|
}
|
|
else {
|
|
m_devicePainter = cairo_create(m_surface);
|
|
}
|
|
cairo_set_antialias(m_devicePainter, CAIRO_ANTIALIAS_NONE);
|
|
m_pen = TQPen();
|
|
m_brush = TQBrush();
|
|
m_brushOrigin = TQPoint(0,0);
|
|
m_worldMatrixEnabled = false;
|
|
m_viewportMatrixEnabled = false;
|
|
cairo_matrix_init_identity(&m_worldMatrix);
|
|
cairo_matrix_init_identity(&m_viewportMatrix);
|
|
setCairoTransformations(m_painter);
|
|
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) {
|
|
if (m_transferNeeded) {
|
|
transferIntermediateSurface();
|
|
}
|
|
cairo_destroy(m_painter);
|
|
m_painter = NULL;
|
|
}
|
|
if (m_devicePainter) {
|
|
if (!m_overridePainter) {
|
|
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)) {
|
|
if (m_transferNeeded) {
|
|
transferIntermediateSurface();
|
|
}
|
|
|
|
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;i<tabcount;i++) {
|
|
pango_tab_array_set_tab(m_tabStopArray, i, PANGO_TAB_LEFT, tabarray[i]*PANGO_SCALE);
|
|
}
|
|
m_tabStopArrayValid = true;
|
|
}
|
|
else {
|
|
pango_tab_array_resize(m_tabStopArray, 0);
|
|
m_tabStopArrayValid = false;
|
|
}
|
|
}
|
|
break;
|
|
case PdcSetVXform:
|
|
if ((p) && (m_painter)) {
|
|
m_viewportMatrixEnabled = p[0].ival;
|
|
setCairoTransformations(m_painter);
|
|
}
|
|
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(m_painter);
|
|
}
|
|
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(m_painter);
|
|
}
|
|
break;
|
|
case PdcSetWXform:
|
|
if ((p) && (m_painter)) {
|
|
m_worldMatrixEnabled = p[0].ival;
|
|
setCairoTransformations(m_painter);
|
|
}
|
|
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(m_painter);
|
|
}
|
|
}
|
|
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)) {
|
|
if (m_transferNeeded) {
|
|
transferIntermediateSurface();
|
|
}
|
|
m_clipRegionEnabled = p[0].ival;
|
|
}
|
|
break;
|
|
case PdcSetClipRegion:
|
|
if ((p) && (m_painter)) {
|
|
if (m_transferNeeded) {
|
|
transferIntermediateSurface();
|
|
}
|
|
// 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;
|
|
case PdcFlush:
|
|
case PdcFlushRegion:
|
|
if (m_transferNeeded) {
|
|
transferIntermediateSurface();
|
|
}
|
|
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:
|
|
updateSurfaceDimensions();
|
|
val = m_width;
|
|
break;
|
|
case TQPaintDeviceMetrics::PdmHeight:
|
|
updateSurfaceDimensions();
|
|
val = m_height;
|
|
break;
|
|
case TQPaintDeviceMetrics::PdmWidthMM:
|
|
updateSurfaceDimensions();
|
|
cairo_surface_get_fallback_resolution(m_surface, &x_pixels_per_inch, &y_pixels_per_inch);
|
|
val = ((m_width/x_pixels_per_inch)*25.4);
|
|
break;
|
|
case TQPaintDeviceMetrics::PdmHeightMM:
|
|
updateSurfaceDimensions();
|
|
cairo_surface_get_fallback_resolution(m_surface, &x_pixels_per_inch, &y_pixels_per_inch);
|
|
val = ((m_height/y_pixels_per_inch)*25.4);
|
|
break;
|
|
case TQPaintDeviceMetrics::PdmDpiX:
|
|
cairo_surface_get_fallback_resolution(m_surface, &x_pixels_per_inch, &y_pixels_per_inch);
|
|
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;
|
|
}
|
|
|