From c5fe03a88c8c59efd42759b1aef956190b3508cd Mon Sep 17 00:00:00 2001 From: romashin Date: Sat, 19 Apr 2008 18:43:23 +0300 Subject: [PATCH] Added new cairo-qt surface from Vlad's patch New created files moved in sandbox/qt_port.. cairo and gfxQPainterSurface Changes for existing files applyed from 100_qt-qpainter-cairo.diff Fixed building non deb mozilla with build_non_deb.sh script Fixed tab-spaces in new created file cairo-qpainter-surface.cpp --- .../cairo/src/cairo-qpainter-surface.cpp | 1246 +++++++++++++++++ gfx/cairo/cairo/src/cairo-qpainter.h | 71 + gfx/thebes/public/gfxQPainterSurface.h | 62 + gfx/thebes/src/gfxQPainterSurface.cpp | 79 ++ widget/src/qt/nsWidgetFactory.cpp | 10 +- widget/src/qt/nsWindow.cpp | 235 +--- 6 files changed, 1529 insertions(+), 174 deletions(-) create mode 100644 gfx/cairo/cairo/src/cairo-qpainter-surface.cpp create mode 100644 gfx/cairo/cairo/src/cairo-qpainter.h create mode 100644 gfx/thebes/public/gfxQPainterSurface.h create mode 100644 gfx/thebes/src/gfxQPainterSurface.cpp diff --git a/gfx/cairo/cairo/src/cairo-qpainter-surface.cpp b/gfx/cairo/cairo/src/cairo-qpainter-surface.cpp new file mode 100644 index 000000000000..455ca72f0dbe --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-qpainter-surface.cpp @@ -0,0 +1,1246 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Mozilla Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Mozilla Corporation. + * + * Contributor(s): + * Vladimir Vukicevic + */ + +/* Get INT16_MIN etc. as per C99 */ +#define __STDC_LIMIT_MACROS + +#include "cairoint.h" + +#include "cairo-qpainter.h" + +#ifdef CAIRO_HAS_XLIB_XRENDER_SURFACE +#include "cairo-xlib.h" +#include "cairo-xlib-xrender.h" +// I hate X +#undef Status +#undef CursorShape +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define D(x) x +#else +#define D(x) do { } while(0) +#endif + +#ifndef CAIRO_INT_STATUS_SUCCESS +#define CAIRO_INT_STATUS_SUCCESS ((cairo_int_status_t) CAIRO_STATUS_SUCCESS) +#endif + +typedef struct { + cairo_surface_t base; + + QPainter *p; + + /* The pixmap/image constructors will store their objects here */ + QPixmap *pixmap; + QImage *image; + + QRect window; + + cairo_image_surface_t *image_equiv; + +#if defined(Q_WS_X11) && defined(CAIRO_HAS_XLIB_XRENDER_SURFACE) + /* temporary, so that we can share the xlib surface's glyphs code */ + cairo_surface_t *xlib_equiv; +#endif + + cairo_bool_t supports_porter_duff; +} cairo_qpainter_surface_t; + +static cairo_int_status_t +_cairo_qpainter_surface_paint (void *abstract_surface, + cairo_operator_t op, + cairo_pattern_t *source); + +/** + ** Helper methods + **/ +static const char * +_opstr (cairo_operator_t op) +{ + const char *ops[] = { + "CLEAR", + "SOURCE", + "OVER", + "IN", + "OUT", + "ATOP", + "DEST", + "DEST_OVER", + "DEST_IN", + "DEST_OUT", + "DEST_ATOP", + "XOR", + "ADD", + "SATURATE" + }; + + if (op < CAIRO_OPERATOR_CLEAR || op > CAIRO_OPERATOR_SATURATE) + return "(\?\?\?)"; + + return ops[op]; +} + +static QPainter::CompositionMode +_qpainter_compositionmode_from_cairo_op (cairo_operator_t op) +{ + switch (op) { + case CAIRO_OPERATOR_CLEAR: + return QPainter::CompositionMode_Clear; + + case CAIRO_OPERATOR_SOURCE: + return QPainter::CompositionMode_Source; + case CAIRO_OPERATOR_OVER: + return QPainter::CompositionMode_SourceOver; + case CAIRO_OPERATOR_IN: + return QPainter::CompositionMode_SourceIn; + case CAIRO_OPERATOR_OUT: + return QPainter::CompositionMode_SourceOut; + case CAIRO_OPERATOR_ATOP: + return QPainter::CompositionMode_SourceAtop; + + case CAIRO_OPERATOR_DEST: + return QPainter::CompositionMode_Destination; + case CAIRO_OPERATOR_DEST_OVER: + return QPainter::CompositionMode_DestinationOver; + case CAIRO_OPERATOR_DEST_IN: + return QPainter::CompositionMode_DestinationIn; + case CAIRO_OPERATOR_DEST_OUT: + return QPainter::CompositionMode_DestinationOut; + case CAIRO_OPERATOR_DEST_ATOP: + return QPainter::CompositionMode_DestinationAtop; + + case CAIRO_OPERATOR_XOR: + return QPainter::CompositionMode_Xor; + case CAIRO_OPERATOR_ADD: + return QPainter::CompositionMode_SourceOver; // XXX? + case CAIRO_OPERATOR_SATURATE: + return QPainter::CompositionMode_SourceOver; // XXX? + } + + return QPainter::CompositionMode_Source; +} + +static cairo_format_t +_cairo_format_from_qimage_format (QImage::Format fmt) +{ + switch (fmt) { + case QImage::Format_ARGB32_Premultiplied: + return CAIRO_FORMAT_ARGB32; + case QImage::Format_RGB32: + return CAIRO_FORMAT_RGB24; + case QImage::Format_Indexed8: // XXX not quite + return CAIRO_FORMAT_A8; +#ifdef WORDS_BIGENDIAN + case QImage::Format_Mono: +#else + case QImage::Format_MonoLSB: +#endif + return CAIRO_FORMAT_A1; + default: + return CAIRO_FORMAT_A1; + } + + return CAIRO_FORMAT_A1; +} + +static QImage::Format +_qimage_format_from_cairo_format (cairo_format_t fmt) +{ + switch (fmt) { + case CAIRO_FORMAT_ARGB32: + return QImage::Format_ARGB32_Premultiplied; + case CAIRO_FORMAT_RGB24: + return QImage::Format_RGB32; + case CAIRO_FORMAT_A8: + return QImage::Format_Indexed8; // XXX not quite + case CAIRO_FORMAT_A1: +#ifdef WORDS_BIGENDIAN + return QImage::Format_Mono; // XXX think we need to choose between this and LSB +#else + return QImage::Format_MonoLSB; +#endif + } + + return QImage::Format_Mono; +} + +static inline QMatrix +_qmatrix_from_cairo_matrix (const cairo_matrix_t& m) +{ + return QMatrix(m.xx, m.xy, m.yx, m.yy, m.x0, m.y0); +} + +static inline void +_qmatrix_from_cairo_matrix (const cairo_matrix_t& m, QMatrix& qm) +{ + qm.setMatrix(m.xx, m.xy, m.yx, m.yy, m.x0, m.y0); +} + +/** Path conversion **/ +typedef struct _qpainter_path_transform { + QPainterPath *path; + cairo_matrix_t *ctm_inverse; +} qpainter_path_data; + +/* cairo path -> execute in context */ +static cairo_status_t +_cairo_path_to_qpainterpath_move_to (void *closure, cairo_point_t *point) +{ + qpainter_path_data *pdata = (qpainter_path_data *)closure; + double x = _cairo_fixed_to_double (point->x); + double y = _cairo_fixed_to_double (point->y); + + if (pdata->ctm_inverse) + cairo_matrix_transform_point (pdata->ctm_inverse, &x, &y); + + pdata->path->moveTo(x, y); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_path_to_qpainterpath_line_to (void *closure, cairo_point_t *point) +{ + qpainter_path_data *pdata = (qpainter_path_data *)closure; + double x = _cairo_fixed_to_double (point->x); + double y = _cairo_fixed_to_double (point->y); + + if (pdata->ctm_inverse) + cairo_matrix_transform_point (pdata->ctm_inverse, &x, &y); + + pdata->path->lineTo(x, y); + + if (pdata->path->isEmpty()) + pdata->path->moveTo(x, y); + else + pdata->path->lineTo(x, y); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_path_to_qpainterpath_curve_to (void *closure, cairo_point_t *p0, cairo_point_t *p1, cairo_point_t *p2) +{ + qpainter_path_data *pdata = (qpainter_path_data *)closure; + double x0 = _cairo_fixed_to_double (p0->x); + double y0 = _cairo_fixed_to_double (p0->y); + double x1 = _cairo_fixed_to_double (p1->x); + double y1 = _cairo_fixed_to_double (p1->y); + double x2 = _cairo_fixed_to_double (p2->x); + double y2 = _cairo_fixed_to_double (p2->y); + + if (pdata->ctm_inverse) { + cairo_matrix_transform_point (pdata->ctm_inverse, &x0, &y0); + cairo_matrix_transform_point (pdata->ctm_inverse, &x1, &y1); + cairo_matrix_transform_point (pdata->ctm_inverse, &x2, &y2); + } + + pdata->path->cubicTo (x0, y0, x1, y1, x2, y2); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_path_to_qpainterpath_close_path (void *closure) +{ + qpainter_path_data *pdata = (qpainter_path_data *)closure; + + pdata->path->closeSubpath(); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_quartz_cairo_path_to_qpainterpath (cairo_path_fixed_t *path, + QPainterPath *qpath, + cairo_fill_rule_t fill_rule, + cairo_matrix_t *ctm_inverse = NULL) +{ + qpainter_path_data pdata = { qpath, ctm_inverse }; + + qpath->setFillRule (fill_rule == CAIRO_FILL_RULE_WINDING ? Qt::WindingFill : Qt::OddEvenFill); + + return _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + _cairo_path_to_qpainterpath_move_to, + _cairo_path_to_qpainterpath_line_to, + _cairo_path_to_qpainterpath_curve_to, + _cairo_path_to_qpainterpath_close_path, + &pdata); +} + +static cairo_status_t +_cairo_quartz_cairo_path_to_qpainterpath (cairo_path_fixed_t *path, + QPainterPath *qpath, + cairo_matrix_t *ctm_inverse) +{ + return _cairo_quartz_cairo_path_to_qpainterpath (path, qpath, + CAIRO_FILL_RULE_WINDING, + ctm_inverse); +} + +/** + ** Surface backend methods + **/ +static cairo_surface_t * +_cairo_qpainter_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + + D(fprintf(stderr, "q[%p] create_similar: %d %d [%d] -> ", abstract_surface, width, height, content)); + + if (qs->image || content == CAIRO_CONTENT_COLOR_ALPHA) { + fprintf (stderr, "qimage\n"); + return cairo_qpainter_surface_create_with_qimage + (_cairo_format_from_content (content), width, height); + } + + D(fprintf(stderr, "qpixmap\n")); + return cairo_qpainter_surface_create_with_qpixmap (width, height); +} + +static cairo_status_t +_cairo_qpainter_surface_finish (void *abstract_surface) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + + D(fprintf(stderr, "q[%p] finish\n", abstract_surface)); + + /* Only delete p if we created it */ + if (qs->image || qs->pixmap) + delete qs->p; + else + qs->p->restore(); + + if (qs->image_equiv) + cairo_surface_destroy ((cairo_surface_t*) qs->image_equiv); + +#if defined(Q_WS_X11) && defined(CAIRO_HAS_XLIB_XRENDER_SURFACE) + if (qs->xlib_equiv) + cairo_surface_destroy (qs->xlib_equiv); +#endif + + if (qs->image) + delete qs->image; + + if (qs->pixmap) + delete qs->pixmap; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_qpainter_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + + D(fprintf(stderr, "q[%p] acquire_source_image\n", abstract_surface)); + + *image_extra = NULL; + + if (qs->image_equiv) { + *image_out = (cairo_image_surface_t*) + cairo_surface_reference ((cairo_surface_t*) qs->image_equiv); + + return CAIRO_STATUS_SUCCESS; + } + + if (qs->pixmap) { + QImage *qimg = new QImage(qs->pixmap->toImage()); + + *image_out = (cairo_image_surface_t*) + cairo_image_surface_create_for_data (qimg->bits(), + _cairo_format_from_qimage_format (qimg->format()), + qimg->width(), qimg->height(), + qimg->bytesPerLine()); + *image_extra = qimg; + + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_STATUS_NO_MEMORY; +} + +static void +_cairo_qpainter_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + //cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + + D(fprintf(stderr, "q[%p] release_source_image\n", abstract_surface)); + + cairo_surface_destroy ((cairo_surface_t*) image); + + if (image_extra) { + QImage *qimg = (QImage *) image_extra; + delete qimg; + } +} + +static cairo_status_t +_cairo_qpainter_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_int_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_int_t *image_rect, + void **image_extra) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + QImage *qimg = NULL; + + D(fprintf(stderr, "q[%p] acquire_dest_image\n", abstract_surface)); + + *image_extra = NULL; + + if (qs->image_equiv) { + *image_out = (cairo_image_surface_t*) + cairo_surface_reference ((cairo_surface_t*) qs->image_equiv); + + image_rect->x = qs->window.x(); + image_rect->y = qs->window.y(); + image_rect->width = qs->window.width(); + image_rect->height = qs->window.height(); + + return CAIRO_STATUS_SUCCESS; + } + + if (qs->pixmap) { + qimg = new QImage(qs->pixmap->toImage()); + } else { + // Try to figure out what kind of QPaintDevice we have, and + // how we can grab an image from it + QPaintDevice *pd = qs->p->device(); + if (pd->devType() == QInternal::Image) { + qimg = new QImage(((QImage*) pd)->copy()); + } else if (pd->devType() == QInternal::Pixmap) { + qimg = new QImage(((QPixmap*) pd)->toImage()); + } else if (pd->devType() == QInternal::Widget) { + qimg = new QImage(QPixmap::grabWindow(((QWidget*)pd)->winId()).toImage()); + } + } + + if (qimg == NULL) + return CAIRO_STATUS_NO_MEMORY; + + *image_out = (cairo_image_surface_t*) + cairo_image_surface_create_for_data (qimg->bits(), + _cairo_format_from_qimage_format (qimg->format()), + qimg->width(), qimg->height(), + qimg->bytesPerLine()); + *image_extra = qimg; + + image_rect->x = qs->window.x(); + image_rect->y = qs->window.y(); + image_rect->width = qs->window.width(); + image_rect->height = qs->window.height(); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_qpainter_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_int_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_int_t *image_rect, + void *image_extra) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + D(fprintf(stderr, "q[%p] release_dest_image\n", abstract_surface)); + + cairo_surface_destroy ((cairo_surface_t*) image); + + if (image_extra) { + QImage *qimg = (QImage*) image_extra; + + // XXX should I be using setBackgroundMode here instead of setCompositionMode? + if (qs->supports_porter_duff) + qs->p->setCompositionMode (QPainter::CompositionMode_Source); + + qs->p->drawImage (image_rect->x, image_rect->y, *qimg); + + if (qs->supports_porter_duff) + qs->p->setCompositionMode (QPainter::CompositionMode_SourceOver); + + delete qimg; + } +} + +static cairo_status_t +_cairo_qpainter_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + int src_x, + int src_y, + int width, + int height, + cairo_surface_t **clone_out) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + cairo_surface_t *new_surf; + + // For non-image targets, and a CONTENT_COLOR type, use a QPixmap + // Otherwise, create a QImage + if (qs->image == NULL && src->content == CAIRO_CONTENT_COLOR) { + new_surf = cairo_qpainter_surface_create_with_qpixmap + (width, height); + } else { + new_surf = cairo_qpainter_surface_create_with_qimage + (_cairo_format_from_content (src->content), width, height); + } + + if (new_surf->status) + return new_surf->status; + + cairo_pattern_union_t upat; + _cairo_pattern_init_for_surface (&upat.surface, src); + + cairo_matrix_t tx; + cairo_matrix_init_translate (&tx, -src_x, -src_y); + cairo_pattern_set_matrix (&upat.base, &tx); + + cairo_int_status_t status = + _cairo_qpainter_surface_paint (new_surf, CAIRO_OPERATOR_SOURCE, &upat.base); + + _cairo_pattern_fini (&upat.base); + + if (status) { + cairo_surface_destroy (new_surf); + new_surf = NULL; + } + + *clone_out = new_surf; + return (cairo_status_t) status; +} + +static cairo_int_status_t +_cairo_qpainter_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + + extents->x = qs->window.x(); + extents->y = qs->window.y(); + extents->width = qs->window.width(); + extents->height = qs->window.height(); + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_qpainter_surface_intersect_clip_path (void *abstract_surface, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + + D(fprintf(stderr, "q[%p] intersect_clip_path %s\n", abstract_surface, path ? "(path)" : "(clear)")); + + if (!qs->p) + return CAIRO_INT_STATUS_SUCCESS; + + if (path == NULL) { + // How the clip path is reset depends on whether we own p or not + if (qs->pixmap || qs->image) { + // we own p + qs->p->setClipping (false); + } else { + qs->p->restore (); + qs->p->save (); + } + + return CAIRO_INT_STATUS_SUCCESS; + } + + Qt::ClipOperation clipOp = Qt::IntersectClip; + if ((qs->pixmap || qs->image) && !qs->p->hasClipping()) + clipOp = Qt::ReplaceClip; + + QPainterPath qpath; + if (_cairo_quartz_cairo_path_to_qpainterpath (path, &qpath, fill_rule) != CAIRO_STATUS_SUCCESS) + return CAIRO_INT_STATUS_UNSUPPORTED; + + qs->p->setClipPath (qpath, clipOp); + qs->p->setClipping (true); + + // XXX Antialiasing is ignored + + return CAIRO_INT_STATUS_SUCCESS; +} + +/** + ** Brush conversion + **/ + +QBrush * +_qbrush_from_pattern (cairo_pattern_t *pattern) +{ + QBrush *brush = NULL; + + if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { + cairo_solid_pattern_t *solid = (cairo_solid_pattern_t*) pattern; + QColor color; + color.setRgbF(solid->color.red, + solid->color.green, + solid->color.blue, + solid->color.alpha); + + brush = new QBrush(color); + } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t*) pattern; + cairo_surface_t *surface = spattern->surface; + + if (surface->type == CAIRO_SURFACE_TYPE_QPAINTER) { + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t*) surface; + + if (qs->image) { + brush = new QBrush(*qs->image); + } else if (qs->pixmap) { + brush = new QBrush(*qs->pixmap); + } else { + // do something smart + brush = new QBrush(0xff0000ff); + } + } else if (surface->type == CAIRO_SURFACE_TYPE_IMAGE) { + cairo_image_surface_t *isurf = (cairo_image_surface_t*) surface; + brush = new QBrush (QImage ((const uchar *) isurf->data, + isurf->width, + isurf->height, + isurf->stride, + _qimage_format_from_cairo_format (isurf->format))); + } else { + brush = new QBrush(0x0000ffff); + } + + } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || + pattern->type == CAIRO_PATTERN_TYPE_RADIAL) + { + brush = new QBrush(0x00ff00ff); + } + + if (brush && + pattern->type != CAIRO_PATTERN_TYPE_SOLID && + !_cairo_matrix_is_identity(&pattern->matrix)) + { + cairo_matrix_t pm = pattern->matrix; + if (cairo_matrix_invert (&pm) == CAIRO_STATUS_SUCCESS) + brush->setMatrix(_qmatrix_from_cairo_matrix (pm)); + } + + return brush; +} + +QPen * +_qpen_from_pattern_and_style (cairo_pattern_t *source, + cairo_stroke_style_t *style) +{ + QPen *pen; + QBrush *brush; + + brush = _qbrush_from_pattern (source); + + Qt::PenJoinStyle join = Qt::MiterJoin; + Qt::PenCapStyle cap = Qt::SquareCap; + + switch (style->line_cap) { + case CAIRO_LINE_CAP_BUTT: + cap = Qt::FlatCap; + break; + case CAIRO_LINE_CAP_ROUND: + cap = Qt::RoundCap; + break; + case CAIRO_LINE_CAP_SQUARE: + cap = Qt::SquareCap; + break; + } + + switch (style->line_join) { + case CAIRO_LINE_JOIN_MITER: + join = Qt::MiterJoin; + break; + case CAIRO_LINE_JOIN_ROUND: + join = Qt::RoundJoin; + break; + case CAIRO_LINE_JOIN_BEVEL: + join = Qt::BevelJoin; + break; + } + + pen = new QPen (*brush, style->line_width, Qt::SolidLine, cap, join); + + // XXX handle style->dash! + + // I hope that the QPen made a copy... + delete brush; + + return pen; +} + +/** + ** Core drawing operations + **/ + +cairo_int_status_t +_cairo_qpainter_surface_paint (void *abstract_surface, + cairo_operator_t op, + cairo_pattern_t *source) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + + D(fprintf(stderr, "q[%p] paint op:%s\n", abstract_surface, _opstr(op))); + + if (!qs->p) + return CAIRO_INT_STATUS_SUCCESS; + + if (qs->supports_porter_duff) + qs->p->setCompositionMode (_qpainter_compositionmode_from_cairo_op (op)); + + if (source->type == CAIRO_PATTERN_TYPE_SURFACE && + source->extend == CAIRO_EXTEND_NONE && + ((cairo_surface_pattern_t*)source)->surface->type == CAIRO_SURFACE_TYPE_QPAINTER) + { + cairo_qpainter_surface_t *qsSrc = (cairo_qpainter_surface_t*) ((cairo_surface_pattern_t*)source)->surface; + + QMatrix savedMatrix = qs->p->worldMatrix(); + qs->p->setWorldMatrix (_qmatrix_from_cairo_matrix (source->matrix), true); + + if (qsSrc->image) { + qs->p->drawImage (0, 0, *qsSrc->image); + } else if (qsSrc->pixmap) { + qs->p->drawPixmap (0, 0, *qsSrc->pixmap); + } + + qs->p->setWorldMatrix (savedMatrix, false); + } else { + QBrush *brush = _qbrush_from_pattern (source); + + qs->p->fillRect (qs->window, *brush); + + delete brush; + } + + if (qs->supports_porter_duff) + qs->p->setCompositionMode (QPainter::CompositionMode_SourceOver); + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_qpainter_surface_fill (void *abstract_surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + + D(fprintf(stderr, "q[%p] fill op:%s\n", abstract_surface, _opstr(op))); + + if (!qs->p) + return CAIRO_INT_STATUS_SUCCESS; + + QPainterPath qpath; + if (_cairo_quartz_cairo_path_to_qpainterpath (path, &qpath, fill_rule) != CAIRO_STATUS_SUCCESS) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (qs->supports_porter_duff) + qs->p->setCompositionMode (_qpainter_compositionmode_from_cairo_op (op)); + + qs->p->setRenderHint (QPainter::Antialiasing, antialias == CAIRO_ANTIALIAS_NONE ? false : true); + qs->p->setRenderHint (QPainter::SmoothPixmapTransform, source->filter != CAIRO_FILTER_FAST); + + QBrush *brush = _qbrush_from_pattern (source); + + qs->p->fillPath (qpath, *brush); + + delete brush; + + if (qs->supports_porter_duff) + qs->p->setCompositionMode (QPainter::CompositionMode_SourceOver); + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_qpainter_surface_stroke (void *abstract_surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_stroke_style_t *style, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + + D(fprintf(stderr, "q[%p] stroke op:%s\n", abstract_surface, _opstr(op))); + + if (!qs->p) + return CAIRO_INT_STATUS_SUCCESS; + + QPainterPath qpath; + if (_cairo_quartz_cairo_path_to_qpainterpath (path, &qpath, ctm_inverse) != CAIRO_STATUS_SUCCESS) + return CAIRO_INT_STATUS_UNSUPPORTED; + + QMatrix savedMatrix = qs->p->worldMatrix(); + + if (qs->supports_porter_duff) + qs->p->setCompositionMode (_qpainter_compositionmode_from_cairo_op (op)); + + qs->p->setWorldMatrix (_qmatrix_from_cairo_matrix (*ctm), true); + qs->p->setRenderHint (QPainter::Antialiasing, antialias == CAIRO_ANTIALIAS_NONE ? false : true); + qs->p->setRenderHint (QPainter::SmoothPixmapTransform, source->filter != CAIRO_FILTER_FAST); + + QPen *pen = _qpen_from_pattern_and_style (source, style); + + qs->p->setPen(*pen); + qs->p->drawPath (qpath); + qs->p->setPen(Qt::black); + + delete pen; + + qs->p->setWorldMatrix (savedMatrix, false); + + if (qs->supports_porter_duff) + qs->p->setCompositionMode (QPainter::CompositionMode_SourceOver); + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_qpainter_surface_show_glyphs (void *abstract_surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + +#if defined(Q_WS_X11) && defined(CAIRO_HAS_XLIB_XRENDER_SURFACE) + /* If we have an equivalent X surface, let the xlib surface handle this + * until we figure out how to do this natively with Qt. + */ + if (qs->xlib_equiv) { + return (cairo_int_status_t) + _cairo_surface_show_glyphs (qs->xlib_equiv, op, source, glyphs, num_glyphs, scaled_font); + } +#endif + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_qpainter_surface_mask (void *abstract_surface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_pattern_t *mask) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + + D(fprintf(stderr, "q[%p] mask op:%s\n", abstract_surface, _opstr(op))); + + if (!qs->p) + return CAIRO_INT_STATUS_SUCCESS; + + if (mask->type == CAIRO_PATTERN_TYPE_SOLID) { + cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask; + cairo_int_status_t result; + + qs->p->setOpacity (solid_mask->color.alpha); + + result = _cairo_qpainter_surface_paint (abstract_surface, op, source); + + qs->p->setOpacity (1.0); + + return result; + } + + // otherwise skip for now + return CAIRO_INT_STATUS_SUCCESS; +} + +/** + ** XXX this will go away! it's only implemented for now so that we + ** can get some text without show_glyphs being available. + **/ +static cairo_int_status_t +_cairo_qpainter_surface_composite (cairo_operator_t op, + cairo_pattern_t *pattern, + cairo_pattern_t *mask_pattern, + void *abstract_surface, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t *) abstract_surface; + + if (mask_pattern) + return CAIRO_INT_STATUS_UNSUPPORTED; + + D(fprintf(stderr, "q[%p] composite op:%s src:%p [%d %d] dst [%d %d] dim [%d %d]\n", + abstract_surface, _opstr(op), pattern, + src_x, src_y, dst_x, dst_y, width, height)); + + if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { + cairo_solid_pattern_t *solid = (cairo_solid_pattern_t*) pattern; + + QColor color; + color.setRgbF(solid->color.red, + solid->color.green, + solid->color.blue, + solid->color.alpha); + + if (qs->supports_porter_duff) + qs->p->setCompositionMode (_qpainter_compositionmode_from_cairo_op (op)); + + qs->p->fillRect (dst_x, dst_y, width, height, color); + + if (qs->supports_porter_duff) + qs->p->setCompositionMode (QPainter::CompositionMode_SourceOver); + } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t*) pattern; + cairo_surface_t *surface = spattern->surface; + + QImage *qimg = NULL; + QPixmap *qpixmap = NULL; + cairo_bool_t delete_qimg = FALSE; + + if (surface->type == CAIRO_SURFACE_TYPE_IMAGE) { + cairo_image_surface_t *isurf = (cairo_image_surface_t*) surface; + qimg = new QImage ((const uchar *) isurf->data, + isurf->width, + isurf->height, + isurf->stride, + _qimage_format_from_cairo_format (isurf->format)); + delete_qimg = TRUE; + } + + if (surface->type == CAIRO_SURFACE_TYPE_QPAINTER) { + cairo_qpainter_surface_t *qsrc = (cairo_qpainter_surface_t*) surface; + + if (qsrc->image) + qimg = qsrc->image; + else if (qsrc->pixmap) + qpixmap = qsrc->pixmap; + } + + if (!qimg && !qpixmap) + return CAIRO_INT_STATUS_UNSUPPORTED; + + QMatrix savedMatrix = qs->p->worldMatrix(); + if (!_cairo_matrix_is_identity (&pattern->matrix)) { + cairo_matrix_t pm = pattern->matrix; + if (cairo_matrix_invert (&pm) == CAIRO_STATUS_SUCCESS) + qs->p->setWorldMatrix(_qmatrix_from_cairo_matrix (pm), true); + } + + if (qs->supports_porter_duff) + qs->p->setCompositionMode (_qpainter_compositionmode_from_cairo_op (op)); + + if (qimg) + qs->p->drawImage (dst_x, dst_y, *qimg, src_x, src_y, width, height); + else if (qpixmap) + qs->p->drawPixmap (dst_x, dst_y, *qpixmap, src_x, src_y, width, height); + + if (qs->supports_porter_duff) + qs->p->setCompositionMode (QPainter::CompositionMode_SourceOver); + + if (delete_qimg) + delete qimg; + } else { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +/** + ** Backend struct + **/ + +static const struct _cairo_surface_backend cairo_qpainter_surface_backend = { + CAIRO_SURFACE_TYPE_QPAINTER, + _cairo_qpainter_surface_create_similar, + _cairo_qpainter_surface_finish, + _cairo_qpainter_surface_acquire_source_image, + _cairo_qpainter_surface_release_source_image, + _cairo_qpainter_surface_acquire_dest_image, + _cairo_qpainter_surface_release_dest_image, + _cairo_qpainter_surface_clone_similar, + + _cairo_qpainter_surface_composite, /* composite -- XXX temporary! */ + NULL, /* fill_rectangles */ + NULL, /* composite_trapezoids */ + NULL, /* copy_page */ + NULL, /* show_page */ + NULL, /* set_clip_region */ + _cairo_qpainter_surface_intersect_clip_path, + _cairo_qpainter_surface_get_extents, + NULL, /* old_show_glyphs */ + NULL, /* get_font_options */ + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + NULL, /* scaled_font_fini */ + NULL, /* scaled_glyph_fini */ + + _cairo_qpainter_surface_paint, + _cairo_qpainter_surface_mask, + _cairo_qpainter_surface_stroke, + _cairo_qpainter_surface_fill, + _cairo_qpainter_surface_show_glyphs, + + NULL, /* snapshot */ + NULL, /* is_similar */ + NULL, /* reset */ + NULL /* fill_stroke */ +}; + +cairo_surface_t * +cairo_qpainter_surface_create (QPainter *painter) +{ + cairo_qpainter_surface_t *qs; + + qs = (cairo_qpainter_surface_t *) malloc (sizeof(cairo_qpainter_surface_t)); + if (qs == NULL) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + memset (qs, 0, sizeof(cairo_qpainter_surface_t)); + + _cairo_surface_init (&qs->base, &cairo_qpainter_surface_backend, CAIRO_CONTENT_COLOR_ALPHA); + + qs->p = painter; + qs->supports_porter_duff = qs->p->paintEngine()->hasFeature(QPaintEngine::PorterDuff); + + // Save so that we can always get back to the original state + qs->p->save(); + + qs->window = painter->window(); + + D(fprintf(stderr, "qpainter_surface_create: window: [%d %d %d %d] pd:%d\n", + qs->window.x(), qs->window.y(), qs->window.width(), qs->window.height(), + qs->supports_porter_duff)); + + return &qs->base; +} + +cairo_surface_t * +cairo_qpainter_surface_create_with_qimage (cairo_format_t format, + int width, + int height) +{ + cairo_qpainter_surface_t *qs; + + qs = (cairo_qpainter_surface_t *) malloc (sizeof(cairo_qpainter_surface_t)); + if (qs == NULL) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + memset (qs, 0, sizeof(cairo_qpainter_surface_t)); + + _cairo_surface_init (&qs->base, &cairo_qpainter_surface_backend, _cairo_content_from_format (format)); + + QImage *image = new QImage (width, height, _qimage_format_from_cairo_format (format)); + + qs->image = image; + + if (!image->isNull()) { + qs->p = new QPainter(image); + qs->supports_porter_duff = qs->p->paintEngine()->hasFeature(QPaintEngine::PorterDuff); + } + + qs->image_equiv = (cairo_image_surface_t*) + cairo_image_surface_create_for_data (image->bits(), + format, + width, height, + image->bytesPerLine()); + + qs->window = QRect(0, 0, width, height); + + D(fprintf(stderr, "qpainter_surface_create: qimage: [%d %d %d %d] pd:%d\n", + qs->window.x(), qs->window.y(), qs->window.width(), qs->window.height(), + qs->supports_porter_duff)); + + return &qs->base; +} + +cairo_surface_t * +cairo_qpainter_surface_create_with_qpixmap (int width, + int height) +{ + cairo_qpainter_surface_t *qs; + + qs = (cairo_qpainter_surface_t *) malloc (sizeof(cairo_qpainter_surface_t)); + if (qs == NULL) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + memset (qs, 0, sizeof(cairo_qpainter_surface_t)); + + QPixmap *pixmap = new QPixmap (width, height); + + _cairo_surface_init (&qs->base, &cairo_qpainter_surface_backend, + pixmap->hasAlphaChannel() ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR); + + + qs->pixmap = pixmap; + + if (!pixmap->isNull()) { + qs->p = new QPainter(pixmap); + qs->supports_porter_duff = qs->p->paintEngine()->hasFeature(QPaintEngine::PorterDuff); + } + + qs->window = QRect(0, 0, width, height); + + D(fprintf(stderr, "qpainter_surface_create: qpixmap: [%d %d %d %d] pd:%d\n", + qs->window.x(), qs->window.y(), qs->window.width(), qs->window.height(), + qs->supports_porter_duff)); + +#if defined(Q_WS_X11) && defined(CAIRO_HAS_XLIB_XRENDER_SURFACE) + // create an xlib surface pointing at the same thing; this is temporary, + // until we figure out how to implement show_glyphs using Qt calls only. + pixmap->detach(); + Drawable d = (Drawable) pixmap->handle(); + if (d != None) { + const QX11Info &xinfo = pixmap->x11Info(); + qs->xlib_equiv = cairo_xlib_surface_create_with_xrender_format + (xinfo.display(), + d, + ScreenOfDisplay(xinfo.display(), xinfo.screen()), + XRenderFindVisualFormat (xinfo.display(), (Visual*) xinfo.visual()), + pixmap->width(), + pixmap->height()); + } +#endif + + return &qs->base; +} + +QPainter * +cairo_qpainter_surface_get_qpainter (cairo_surface_t *surface) +{ + cairo_qpainter_surface_t *qs = (cairo_qpainter_surface_t*) surface; + + if (surface->type != CAIRO_SURFACE_TYPE_QPAINTER) + return NULL; + + return qs->p; +} + +/* + * TODO: + * + * - Figure out why QBrush isn't working with non-repeated images + * + * - Correct repeat mode; right now, every surface source is EXTEND_REPEAT + * - implement EXTEND_NONE (?? probably need to clip to the extents of the source) + * - implement EXTEND_REFLECT (create temporary and copy 4x, then EXTEND_REPEAT that) + * + * - Implement dashing + * + * - stroke-image failure + * + * - Implement mask() with non-solid masks (probably will need to use a temporary and use IN) + * + * - Implement gradient sources + * + * - Make create_similar smarter -- create QPixmaps in more circumstances + * (e.g. if the pixmap can have alpha) + * + * - Implement show_glyphs() in terms of Qt + * + */ + +void +_cairo_image_surface_write_to_ppm (cairo_image_surface_t *isurf, const char *fn) +{ + char *fmt; + if (isurf->format == CAIRO_FORMAT_ARGB32 || isurf->format == CAIRO_FORMAT_RGB24) + fmt = "P6"; + else if (isurf->format == CAIRO_FORMAT_A8) + fmt = "P5"; + else + return; + + FILE *fp = fopen(fn, "wb"); + if (!fp) + return; + + fprintf (fp, "%s %d %d 255\n", fmt,isurf->width, isurf->height); + for (int j = 0; j < isurf->height; j++) { + unsigned char *row = isurf->data + isurf->stride * j; + for (int i = 0; i < isurf->width; i++) { + if (isurf->format == CAIRO_FORMAT_ARGB32 || isurf->format == CAIRO_FORMAT_RGB24) { + unsigned char r = *row++; + unsigned char g = *row++; + unsigned char b = *row++; + *row++; + putc(r, fp); + putc(g, fp); + putc(b, fp); + } else { + unsigned char a = *row++; + putc(a, fp); + } + } + } + + fclose (fp); + + fprintf (stderr, "Wrote %s\n", fn); +} diff --git a/gfx/cairo/cairo/src/cairo-qpainter.h b/gfx/cairo/cairo/src/cairo-qpainter.h new file mode 100644 index 000000000000..03755e0f9687 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-qpainter.h @@ -0,0 +1,71 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Mozilla Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Mozilla Corporation. + * + * Contributor(s): + * Vladimir Vukicevic + */ + +#ifndef CAIRO_QPAINTER_H +#define CAIRO_QPAINTER_H + +#include + +#if CAIRO_HAS_QPAINTER_SURFACE + +class QPainter; + +CAIRO_BEGIN_DECLS + +cairo_public cairo_surface_t * +cairo_qpainter_surface_create (QPainter *painter); + +cairo_public cairo_surface_t * +cairo_qpainter_surface_create_with_qimage (cairo_format_t format, + int width, + int height); + +cairo_public cairo_surface_t * +cairo_qpainter_surface_create_with_qpixmap (int width, + int height); + +cairo_public QPainter * +cairo_qpainter_surface_get_qpainter (cairo_surface_t *surface); + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_QPAINTER_SURFACE */ + +# error Cairo was not compiled with support for the QPainter backend + +#endif /* CAIRO_HAS_QPAINTER_SURFACE */ + +#endif /* CAIRO_QPAINTER_H_ */ diff --git a/gfx/thebes/public/gfxQPainterSurface.h b/gfx/thebes/public/gfxQPainterSurface.h new file mode 100644 index 000000000000..af566a518f98 --- /dev/null +++ b/gfx/thebes/public/gfxQPainterSurface.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Vladimir Vukicevic + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef GFX_QPAINTERSURFACE_H +#define GFX_QPAINTERSURFACE_H + +#include "gfxASurface.h" +#include "gfxImageSurface.h" + +class QPainter; + +class THEBES_API gfxQPainterSurface : public gfxASurface { +public: + gfxQPainterSurface(QPainter *painter); + gfxQPainterSurface(const gfxIntSize& size, gfxImageFormat format); + gfxQPainterSurface(const gfxIntSize& size); + + gfxQPainterSurface(cairo_surface_t *csurf); + + virtual ~gfxQPainterSurface(); + + QPainter *GetQPainter() { return mPainter; } + +protected: + QPainter *mPainter; +}; + +#endif /* GFX_QPAINTERSURFACE_H */ diff --git a/gfx/thebes/src/gfxQPainterSurface.cpp b/gfx/thebes/src/gfxQPainterSurface.cpp new file mode 100644 index 000000000000..2d53ef1962e4 --- /dev/null +++ b/gfx/thebes/src/gfxQPainterSurface.cpp @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Vladimir Vukicevic + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "gfxQPainterSurface.h" + +#include "cairo-qpainter.h" + +gfxQPainterSurface::gfxQPainterSurface(QPainter *painter) +{ + cairo_surface_t *csurf = cairo_qpainter_surface_create (painter); + + mPainter = painter; + + Init (csurf); +} + +gfxQPainterSurface::gfxQPainterSurface(const gfxIntSize& size, gfxImageFormat format) +{ + cairo_surface_t *csurf = cairo_qpainter_surface_create_with_qimage ((cairo_format_t) format, + size.width, + size.height); + mPainter = cairo_qpainter_surface_get_qpainter (csurf); + + Init (csurf); +} + +gfxQPainterSurface::gfxQPainterSurface(const gfxIntSize& size) +{ + cairo_surface_t *csurf = cairo_qpainter_surface_create_with_qpixmap (size.width, + size.height); + mPainter = cairo_qpainter_surface_get_qpainter (csurf); + + Init (csurf); +} + +gfxQPainterSurface::gfxQPainterSurface(cairo_surface_t *csurf) +{ + mPainter = cairo_qpainter_surface_get_qpainter (csurf); + + Init(csurf, PR_TRUE); +} + +gfxQPainterSurface::~gfxQPainterSurface() +{ +} diff --git a/widget/src/qt/nsWidgetFactory.cpp b/widget/src/qt/nsWidgetFactory.cpp index f532fd08f7b2..85d1a4be2d23 100644 --- a/widget/src/qt/nsWidgetFactory.cpp +++ b/widget/src/qt/nsWidgetFactory.cpp @@ -142,12 +142,6 @@ static const nsModuleComponentInfo components[] = NS_SCREENMANAGER_CID, "@mozilla.org/gfx/screenmanager;1", nsScreenManagerQtConstructor }, -/* - { "Qt Native Scrollbar", - NS_NATIVESCROLLBAR_CID, - "@mozilla.org/widget/nativescrollbar/qt;1", - nsNativeScrollbarConstructor}, -*/ { "Qt Clipboard", NS_CLIPBOARD_CID, "@mozilla.org/widget/clipboard;1", @@ -177,11 +171,13 @@ static const nsModuleComponentInfo components[] = NS_FILEPICKER_CID, "@mozilla.org/filepicker;1", nsFilePickerConstructor }, +*/ +#if 0 { "Native Theme Renderer", NS_THEMERENDERER_CID, "@mozilla.org/chrome/chrome-native-theme;1", nsNativeThemeQtConstructor } -*/ +#endif }; PR_STATIC_CALLBACK(void) diff --git a/widget/src/qt/nsWindow.cpp b/widget/src/qt/nsWindow.cpp index 9e64b12c86cc..d3fca186141a 100644 --- a/widget/src/qt/nsWindow.cpp +++ b/widget/src/qt/nsWindow.cpp @@ -90,14 +90,10 @@ #include "gfxPlatformQt.h" #include "gfxXlibSurface.h" +#include "gfxQPainterSurface.h" #include "gfxContext.h" #include "gfxImageSurface.h" -#ifdef MOZ_ENABLE_GLITZ -#include "gfxGlitzSurface.h" -#include "glitz-glx.h" -#endif - #include #include #include @@ -1032,9 +1028,18 @@ nsWindow::LoseFocus(void) LOGFOCUS((" widget lost focus [%p]\n", (void *)this)); } +static int gDoubleBuffering = -1; + bool nsWindow::OnExposeEvent(QPaintEvent *aEvent) { + if (gDoubleBuffering == -1) { + if (getenv("MOZ_NO_DOUBLEBUFFER")) + gDoubleBuffering = 0; + else + gDoubleBuffering = 1; + } + if (mIsDestroyed) { LOG(("Expose event on destroyed window [%p] window %p\n", (void *)this, mDrawingarea)); @@ -1063,22 +1068,26 @@ nsWindow::OnExposeEvent(QPaintEvent *aEvent) LOGDRAW(("\t%d %d %d %d\n", r.x(), r.y(), r.width(), r.height())); } - nsCOMPtr rc = getter_AddRefs(GetRenderingContext()); - if (NS_UNLIKELY(!rc)) { + QPainter painter(mDrawingarea); + + nsRefPtr targetSurface = new gfxQPainterSurface(&painter); + nsRefPtr ctx = new gfxContext(targetSurface); + + nsCOMPtr rc; + GetDeviceContext()->CreateRenderingContextInstance(*getter_AddRefs(rc)); + if (NS_UNLIKELY(!rc)) return FALSE; - } + + rc->Init(GetDeviceContext(), ctx); PRBool translucent; GetHasTransparentBackground(translucent); nsIntRect boundsRect; - QPixmap* bufferPixmap = nsnull; - nsRefPtr bufferPixmapSurface; updateRegion->GetBoundingBox(&boundsRect.x, &boundsRect.y, &boundsRect.width, &boundsRect.height); // do double-buffering and clipping here - nsRefPtr ctx = rc->ThebesContext(); ctx->Save(); ctx->NewPath(); if (translucent) { @@ -1099,41 +1108,8 @@ nsWindow::OnExposeEvent(QPaintEvent *aEvent) // double buffer if (translucent) { ctx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA); - } else { -#ifdef MOZ_ENABLE_GLITZ + } else if (gDoubleBuffering) { ctx->PushGroup(gfxASurface::CONTENT_COLOR); -#else // MOZ_ENABLE_GLITZ - // Instead of just doing PushGroup we're going to do a little dance - // to ensure that GDK creates the pixmap, so it doesn't go all - // XGetGeometry on us in gdk_pixmap_foreign_new_for_display when we - // paint native themes - - bufferPixmap = new QPixmap(boundsRect.width, boundsRect.height); - if (bufferPixmap) { - bufferPixmapSurface = - new gfxXlibSurface(bufferPixmap->x11Info().display(), - bufferPixmap->handle(), - static_cast(bufferPixmap->x11Info().visual()), - gfxIntSize(boundsRect.width, boundsRect.height)); - if (bufferPixmapSurface) { - bufferPixmapSurface->SetDeviceOffset(gfxPoint(-boundsRect.x, -boundsRect.y)); - nsCOMPtr newRC; - nsresult rv = GetDeviceContext()-> - CreateRenderingContextInstance(*getter_AddRefs(newRC)); - if (NS_FAILED(rv)) { - bufferPixmapSurface = nsnull; - } else { - rv = newRC->Init(GetDeviceContext(), bufferPixmapSurface); - if (NS_FAILED(rv)) { - bufferPixmapSurface = nsnull; - } else { - rc = newRC; - } - } - } - } - -#endif // MOZ_ENABLE_GLITZ } #if 0 @@ -1162,60 +1138,44 @@ nsWindow::OnExposeEvent(QPaintEvent *aEvent) // DispatchEvent can Destroy us (bug 378273), avoid doing any paint // operations below if that happened - it will lead to XError and exit(). - if (NS_LIKELY(!mIsDestroyed)) { - if (status != nsEventStatus_eIgnore) { - if (translucent) { - nsRefPtr pattern = ctx->PopGroup(); - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->SetPattern(pattern); - ctx->Paint(); - - nsRefPtr img = - new gfxImageSurface(gfxIntSize(boundsRect.width, boundsRect.height), - gfxImageSurface::ImageFormatA8); - if (img && !img->CairoStatus()) { - img->SetDeviceOffset(gfxPoint(-boundsRect.x, -boundsRect.y)); - - nsRefPtr imgCtx = new gfxContext(img); - if (imgCtx) { - imgCtx->SetPattern(pattern); - imgCtx->SetOperator(gfxContext::OPERATOR_SOURCE); - imgCtx->Paint(); - } - - UpdateTranslucentWindowAlphaInternal(nsRect(boundsRect.x, boundsRect.y, - boundsRect.width, boundsRect.height), - img->Data(), img->Stride()); - } - } else { -#ifdef MOZ_ENABLE_GLITZ - ctx->PopGroupToSource(); - ctx->Paint(); -#else // MOZ_ENABLE_GLITZ - if (bufferPixmapSurface) { - ctx->SetSource(bufferPixmapSurface); - ctx->Paint(); - } -#endif // MOZ_ENABLE_GLITZ - } - } else { - // ignore - if (translucent) { - ctx->PopGroup(); - } else { -#ifdef MOZ_ENABLE_GLITZ - ctx->PopGroup(); -#endif // MOZ_ENABLE_GLITZ - } - } - - if (bufferPixmap) { - delete bufferPixmap; - } + if (NS_UNLIKELY(mIsDestroyed)) + return ignoreEvent(status); + if (status == nsEventStatus_eIgnore) { ctx->Restore(); + return ignoreEvent(status); } + if (translucent) { + nsRefPtr pattern = ctx->PopGroup(); + ctx->SetOperator(gfxContext::OPERATOR_SOURCE); + ctx->SetPattern(pattern); + ctx->Paint(); + + nsRefPtr img = + new gfxImageSurface(gfxIntSize(boundsRect.width, boundsRect.height), + gfxImageSurface::ImageFormatA8); + if (img && !img->CairoStatus()) { + img->SetDeviceOffset(gfxPoint(-boundsRect.x, -boundsRect.y)); + + nsRefPtr imgCtx = new gfxContext(img); + if (imgCtx) { + imgCtx->SetPattern(pattern); + imgCtx->SetOperator(gfxContext::OPERATOR_SOURCE); + imgCtx->Paint(); + } + + UpdateTranslucentWindowAlphaInternal(nsRect(boundsRect.x, boundsRect.y, + boundsRect.width, boundsRect.height), + img->Data(), img->Stride()); + } + } else if (gDoubleBuffering) { + ctx->PopGroupToSource(); + ctx->Paint(); + } + + ctx->Restore(); + // check the return value! return ignoreEvent(status); } @@ -1799,31 +1759,6 @@ nsWindow::NativeCreate(nsIWidget *aParent, else parent = (QWidget*)aNativeParent; -#ifdef MOZ_ENABLE_GLITZ - GdkVisual* visual = nsnull; - if (gfxPlatform::UseGlitz()) { - nsCOMPtr dc = aContext; - if (!dc) { - nsCOMPtr dc = do_CreateInstance(kDeviceContextCID); - // no parent widget to initialize with - dc->Init(nsnull); - } - - Display* dpy = ; - int defaultScreen = gdk_x11_get_default_screen(); - glitz_drawable_format_t* format = glitz_glx_find_window_format (dpy, defaultScreen, - 0, NULL, 0); - if (format) { - XVisualInfo* vinfo = glitz_glx_get_visual_info_from_format(dpy, defaultScreen, format); - GdkScreen* screen = gdk_display_get_screen(gdk_x11_lookup_xdisplay(dpy), defaultScreen); - visual = gdk_x11_screen_lookup_visual(screen, vinfo->visualid); - } else { - // couldn't find a GLX visual; force Glitz off - gfxPlatform::SetUseGlitz(PR_FALSE); - } - } -#endif - // ok, create our windows mDrawingarea = createQWidget(parent, aInitData); @@ -2714,6 +2649,7 @@ nsWindow::GetThebesSurface() mThebesSurface = nsnull; if (!mThebesSurface) { +#if 0 qint32 x_offset = 0, y_offset = 0; qint32 width = mDrawingarea->width(), height = mDrawingarea->height(); @@ -2721,57 +2657,22 @@ nsWindow::GetThebesSurface() width = PR_MIN(32767, width); height = PR_MIN(32767, height); - if (!gfxPlatform::UseGlitz()) { - mThebesSurface = new gfxXlibSurface - (mDrawingarea->x11Info().display(), - (Drawable)mDrawingarea->handle(), - static_cast(mDrawingarea->x11Info().visual()), - gfxIntSize(width, height)); - // if the surface creation is reporting an error, then - // we don't have a surface to give back - if (mThebesSurface && mThebesSurface->CairoStatus() != 0) - mThebesSurface = nsnull; - } else { -#ifdef MOZ_ENABLE_GLITZ - glitz_surface_t *gsurf; - glitz_drawable_t *gdraw; - - glitz_drawable_format_t *gdformat = glitz_glx_find_window_format (Qt::Key_DISPLAY(), - gdk_x11_get_default_screen(), - 0, NULL, 0); - if (!gdformat) - NS_ERROR("Failed to find glitz drawable format"); - - Display* dpy = Qt::Key_WINDOW_XDISPLAY(d); - Window wnd = Qt::Key_WINDOW_XWINDOW(d); - - gdraw = - glitz_glx_create_drawable_for_window (dpy, - DefaultScreen(dpy), - gdformat, - wnd, - width, - height); - glitz_format_t *gformat = - glitz_find_standard_format (gdraw, GLITZ_STANDARD_RGB24); - gsurf = - glitz_surface_create (gdraw, - gformat, - width, - height, - 0, - NULL); - glitz_surface_attach (gsurf, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR); - - - //fprintf (stderr, "## nsThebesDrawingSurface::Init Glitz DRAWABLE %p (DC: %p)\n", aWidget, aDC); - mThebesSurface = new gfxGlitzSurface (gdraw, gsurf, PR_TRUE); -#endif - } + mThebesSurface = new gfxXlibSurface + (mDrawingarea->x11Info().display(), + (Drawable)mDrawingarea->handle(), + static_cast(mDrawingarea->x11Info().visual()), + gfxIntSize(width, height)); + // if the surface creation is reporting an error, then + // we don't have a surface to give back + if (mThebesSurface && mThebesSurface->CairoStatus() != 0) + mThebesSurface = nsnull; if (mThebesSurface) { mThebesSurface->SetDeviceOffset(gfxPoint(-x_offset, -y_offset)); } +#else + mThebesSurface = new gfxQPainterSurface(gfxIntSize(5,5)); +#endif } return mThebesSurface;