/* For general Scribus (>=1.3.2) copyright and licensing information please refer to the COPYING file provided with the program. Following this notice may exist a copyright and/or license notice that predates the release of Scribus 1.3.2 for which a new license (GPL+exception) is in place. */ #include #include "scpainterex_cairo.h" #include "sccolorengine.h" #include "util.h" ScPainterEx_Cairo::ScPainterEx_Cairo( cairo_t* context, QRect& rect, ScribusDoc* doc, bool gray ) : ScPainterExBase() { m_doc = doc; m_width = rect.width(); m_height = rect.height(); m_strokeColor = ScColorShade( QColor(0,0,0), 100 ); m_fillColor = ScColorShade( QColor(0,0,0), 100 ); m_fillTrans = 1.0; m_strokeTrans = 1.0; m_fillRule = true; m_fillMode = 1; m_lineWidth = 1.0; m_offset = 0; m_lineEnd = Qt::SquareCap; m_lineJoin = Qt::RoundJoin; m_fillGradient = VGradientEx(VGradientEx::linear); m_strokeGradient = VGradientEx(VGradientEx::linear); // Grayscale conversion parameter m_convertToGray = gray; // Initialization of Windows GDI data m_cr = context; m_positionX = m_positionY = 0; clear(); } ScPainterEx_Cairo::~ScPainterEx_Cairo() { } QColor ScPainterEx_Cairo::transformColor( ScColorShade& colorShade, double trans ) { QColor c, color; c = ScColorEngine::getShadeColor(colorShade.color, m_doc, colorShade.shade); color = qRgba( qRed(c.rgb()), qGreen(c.rgb()), qBlue(c.rgb()), qAlpha(trans * 255)); if ( m_convertToGray ) { int grayLevel; QColor grayColor; grayLevel = 0.3 * color.red() + 0.59 * color.green() + 0.11 * color.blue(); grayColor = qRgba( grayLevel, grayLevel, grayLevel, qAlpha(color.rgb())); color = grayColor; } return color; } void ScPainterEx_Cairo::transformImage(QImage& image) { int rgb, grey; int imageWidth = image.width(); int imageHeight = image.height(); QRgb *pscan; for ( int j = 0; j < imageHeight; j++ ) { pscan = (QRgb *) image.scanLine(j); for (int i = 0; i < imageWidth; i++ ) { rgb = pscan[i]; grey = 0.3 * qRed(rgb) + 0.59 * qGreen(rgb) + 0.11 * qBlue(rgb); pscan[i] = qRgba(grey, grey, grey, qAlpha(rgb)); } } } void ScPainterEx_Cairo::begin() { } void ScPainterEx_Cairo::end() { } void ScPainterEx_Cairo::clear() { /*SolidBrush brush( Color(255,255,255) ); m_graphics->FillRectangle(&brush, 0, 0, m_width, m_height);*/ } void ScPainterEx_Cairo::clear( ScColorShade &c ) { /*QColor color = transformColor( c, 1.0 ); QRgb cs = color.rgb(); SolidBrush brush( Color(qAlpha(cs), qRed(cs), qGreen(cs),qBlue(cs)) ); m_graphics->FillRectangle(&brush, 0, 0, m_width, m_height);*/ } const QMatrix ScPainterEx_Cairo::worldMatrix() { cairo_matrix_t matrix; cairo_get_matrix(m_cr, &matrix); QMatrix mat(matrix.xx, matrix.yx, matrix.xy, matrix.yy, matrix.x0, matrix.y0); return mat; } void ScPainterEx_Cairo::setWorldMatrix( const QMatrix &mat ) { cairo_matrix_t matrix; cairo_matrix_init(&matrix, mat.m11(), mat.m12(), mat.m21(), mat.m22(), mat.dx(), mat.dy()); cairo_set_matrix(m_cr, &matrix); } void ScPainterEx_Cairo::translate( double x, double y ) { cairo_translate(m_cr, x, y); } void ScPainterEx_Cairo::rotate( double r ) { cairo_rotate(m_cr, r * 3.1415927 / 180.0); } void ScPainterEx_Cairo::scale( double x, double y ) { cairo_scale(m_cr, x, y); } void ScPainterEx_Cairo::moveTo( const double &x, const double &y ) { cairo_move_to(m_cr, x, y); } void ScPainterEx_Cairo::lineTo( const double &x, const double &y ) { cairo_line_to(m_cr, x, y); } void ScPainterEx_Cairo::curveTo( FPoint p1, FPoint p2, FPoint p3 ) { cairo_curve_to(m_cr, p1.x(), p1.y(), p2.x(), p2.y(), p3.x(), p3.y() ); } void ScPainterEx_Cairo::newPath() { cairo_new_path( m_cr ); } void ScPainterEx_Cairo::closePath() { cairo_close_path( m_cr); } void ScPainterEx_Cairo::setFillRule( bool fillRule ) { m_fillRule = fillRule; } void ScPainterEx_Cairo::setFillMode( int fill ) { m_fillMode = fill; } void ScPainterEx_Cairo::setGradient(VGradientEx::Type mode, FPoint orig, FPoint vec, FPoint foc) { m_fillGradient.setType(mode); m_fillGradient.setOrigin(orig); m_fillGradient.setVector(vec); m_fillGradient.setFocalPoint(foc); } void ScPainterEx_Cairo::setPattern( ScPattern* pattern, QMatrix& patternTransform ) { m_pattern = pattern; m_patternTransform = patternTransform; } void ScPainterEx_Cairo::fillTextPath() { drawVPath( 0 ); } void ScPainterEx_Cairo::strokeTextPath() { if( m_lineWidth == 0 ) return; drawVPath( 1 ); } void ScPainterEx_Cairo::fillPath() { if( m_fillMode != 0) drawVPath( 0 ); } void ScPainterEx_Cairo::strokePath() { if( m_lineWidth == 0 ) return; drawVPath( 1 ); } ScColorShade ScPainterEx_Cairo::pen() { return m_strokeColor; } ScColorShade ScPainterEx_Cairo::brush() { return m_fillColor; } void ScPainterEx_Cairo::setPen( const ScColorShade &c ) { m_strokeColor = c; } void ScPainterEx_Cairo::setPen( const ScColorShade &c, double w, Qt::PenStyle st, Qt::PenCapStyle ca, Qt::PenJoinStyle jo ) { m_strokeColor = c; m_lineWidth = w; m_lineEnd = ca; m_lineJoin = jo; m_array.clear(); m_offset = 0; getDashArray(st, w, m_array); } void ScPainterEx_Cairo::setLineWidth( double w ) { m_lineWidth = w; } void ScPainterEx_Cairo::setPenOpacity( double op ) { m_strokeTrans = op; } void ScPainterEx_Cairo::setDash(const QVector& array, double ofs) { m_array = array; m_offset = ofs; } void ScPainterEx_Cairo::setBrush( const ScColorShade &c ) { m_fillColor = c; } void ScPainterEx_Cairo::setBrushOpacity( double op ) { m_fillTrans = op; } void ScPainterEx_Cairo::setOpacity( double op ) { m_fillTrans = op; m_strokeTrans = op; } void ScPainterEx_Cairo::setFont( const QFont &f) { m_font = f; } QFont ScPainterEx_Cairo::font() { return m_font; } void ScPainterEx_Cairo::save() { cairo_save(m_cr); } void ScPainterEx_Cairo::restore() { cairo_restore( m_cr ); } void ScPainterEx_Cairo::setRasterOp( int ) { } void ScPainterEx_Cairo::drawVPath( int mode ) { cairo_save( m_cr ); if (mode == 0) { if( m_fillRule ) cairo_set_fill_rule (m_cr, CAIRO_FILL_RULE_EVEN_ODD); else cairo_set_fill_rule (m_cr, CAIRO_FILL_RULE_WINDING); if (m_fillMode == ScPainterExBase::Gradient) { drawGradient( m_fillGradient ); } else { double r, g, b; QColor fillColor = transformColor(m_fillColor, 1.0); fillColor.getRgbF(&r, &g, &b); cairo_set_source_rgba( m_cr, r, g, b, m_fillTrans ); if (m_fillTrans != 1.0) cairo_set_operator(m_cr, CAIRO_OPERATOR_OVER); else cairo_set_operator(m_cr, CAIRO_OPERATOR_SOURCE); cairo_fill_preserve( m_cr ); } } else { double r, g, b; QColor strokeColor = transformColor( m_strokeColor, 1.0 ); strokeColor.getRgbF(&r, &g, &b); cairo_set_source_rgba( m_cr, r, g, b, m_strokeTrans ); cairo_set_line_width( m_cr, m_lineWidth ); if( m_array.count() > 0 ) cairo_set_dash( m_cr, m_array.data(), m_array.count(), static_cast(m_offset)); else cairo_set_dash( m_cr, NULL, 0, 0 ); if (m_strokeTrans != 1.0) cairo_set_operator(m_cr, CAIRO_OPERATOR_OVER); else cairo_set_operator(m_cr, CAIRO_OPERATOR_SOURCE); if( m_lineEnd == Qt::RoundCap ) cairo_set_line_cap (m_cr, CAIRO_LINE_CAP_ROUND); else if( m_lineEnd == Qt::SquareCap ) cairo_set_line_cap (m_cr, CAIRO_LINE_CAP_SQUARE); else if( m_lineEnd == Qt::FlatCap ) cairo_set_line_cap (m_cr, CAIRO_LINE_CAP_BUTT); if( m_lineJoin == Qt::RoundJoin ) cairo_set_line_join( m_cr, CAIRO_LINE_JOIN_ROUND ); else if( m_lineJoin == Qt::BevelJoin ) cairo_set_line_join( m_cr, CAIRO_LINE_JOIN_BEVEL ); else if( m_lineJoin == Qt::MiterJoin ) cairo_set_line_join( m_cr, CAIRO_LINE_JOIN_MITER ); cairo_stroke_preserve( m_cr ); } cairo_set_operator(m_cr, CAIRO_OPERATOR_OVER); cairo_restore( m_cr ); } void ScPainterEx_Cairo::setClipPath() { cairo_clip (m_cr); } void ScPainterEx_Cairo::drawImage( ScImage *image, ScPainterExBase::ImageMode mode ) { QImage qImage(image->qImage()); if (m_convertToGray) transformImage(qImage); cairo_save(m_cr); cairo_set_fill_rule(m_cr, cairo_get_fill_rule(m_cr)); cairo_surface_t *image2 = cairo_image_surface_create_for_data ((uchar*)qImage.bits(), CAIRO_FORMAT_ARGB32, qImage.width(), qImage.height(), qImage.width()*4); cairo_set_source_surface (m_cr, image2, 0, 0); cairo_paint_with_alpha (m_cr, m_fillTrans); cairo_surface_destroy (image2); cairo_restore(m_cr); } void ScPainterEx_Cairo::setupPolygon(FPointArray *points, bool closed) { bool nPath = true, first = true; FPoint np, np1, np2, np3; if (points->size() > 3) { newPath(); for (uint poi=0; poisize()-3; poi += 4) { if (points->point(poi).x() > 900000) { nPath = true; continue; } if (nPath) { np = points->point(poi); if ((!first) && (closed)) cairo_close_path( m_cr ); moveTo( np.x(), np.y() ); nPath = first = false; } np = points->point(poi); np1 = points->point(poi+1); np2 = points->point(poi+3); np3 = points->point(poi+2); if ((np == np1) && (np2 == np3)) lineTo( np3.x(), np3.y() ); else curveTo(np1, np2, np3); } if (closed) cairo_close_path( m_cr ); } } void ScPainterEx_Cairo::drawPolygon() { fillPath(); } void ScPainterEx_Cairo::drawPolyLine() { strokePath(); } void ScPainterEx_Cairo::drawLine(FPoint start, FPoint end) { newPath(); moveTo(start.x(), start.y()); lineTo(end.x(), end.y()); strokePath(); } void ScPainterEx_Cairo::drawRect(double x, double y, double w, double h) { newPath(); moveTo( x, y ); lineTo( x+w, y ); lineTo( x+w, y+h ); lineTo( x, y+h ); lineTo( x, y ); cairo_close_path( m_cr ); fillPath(); strokePath(); } void ScPainterEx_Cairo::drawGradient( VGradientEx& gradient ) { QRect clipPathRect; save(); setClipPath(); getClipPathDimensions( clipPathRect ); if ( gradient.type() == VGradientEx::linear ) drawLinearGradient( gradient, clipPathRect ); else if ( gradient.type() == VGradientEx::radial ) drawCircularGradient( gradient, clipPathRect ); restore(); } void ScPainterEx_Cairo::drawLinearGradient( VGradientEx& gradient, const QRect& rect ) { int index = 0; double r, g, b; QList colorStops = gradient.colorStops(); VColorStopEx* stop = NULL; QColor color; if ( gradient.Stops() < 2 ) return; FPoint p1( gradient.origin().x(), gradient.origin().y() ); FPoint p2( gradient.vector().x(), gradient.vector().y() ); cairo_pattern_t *pat = cairo_pattern_create_linear (p1.x(), p1.y(), p2.x(), p2.y()); bool isFirst = true; double lastStop = 0.0; for( uint index = 0 ; index < gradient.Stops(); index++) { stop = colorStops.at(index); if ((lastStop == stop->rampPoint) && (!isFirst)) continue; isFirst = false; color = transformColor( ScColorShade(stop->color, stop->shade), 1.0 ); color.getRgbF(&r, &g, &b); cairo_pattern_add_color_stop_rgba (pat, stop->rampPoint, r, g, b, stop->opacity); lastStop = stop->rampPoint; } cairo_set_source (m_cr, pat); //cairo_clip_preserve (m_cr); cairo_paint_with_alpha (m_cr, m_fillTrans); cairo_pattern_destroy (pat); } void ScPainterEx_Cairo::drawCircularGradient( VGradientEx& gradient, const QRect& rect ) { int offset = 0; double r, g, b; QList colorStops = gradient.colorStops(); VColorStopEx* stop = NULL; QColor color; FPoint pc( gradient.origin().x(), gradient.origin().y() ); FPoint pf( gradient.focalPoint().x(), gradient.focalPoint().y() ); FPoint pv( gradient.vector().x(), gradient.vector().y() ); double rad = sqrt( pow(pv.x() - pc.x(), 2) + pow(pv.y() - pc.y(), 2) ); cairo_pattern_t* pat = cairo_pattern_create_radial (pc.x(), pc.y(), 0.1, pc.x(), pc.y(), rad); bool isFirst = true; double lastStop = 0.0; for( uint index = 0 ; index < gradient.Stops() ; index++) { stop = colorStops.at(index); if ((lastStop == stop->rampPoint) && (!isFirst)) continue; isFirst = false; color = transformColor( ScColorShade(stop->color, stop->shade), 1.0 ); color.getRgbF(&r, &g, &b); cairo_pattern_add_color_stop_rgba (pat, stop->rampPoint, r, g, b, stop->opacity); lastStop = stop->rampPoint; } cairo_set_source (m_cr, pat); //cairo_clip_preserve (m_cr); cairo_paint_with_alpha (m_cr, m_fillTrans); cairo_pattern_destroy (pat); } void ScPainterEx_Cairo::getClipPathDimensions( QRect& r ) { double left = 0.0, right = 0.0, bottom = 0.0, top = 0.0; cairo_clip_extents(m_cr, &left, &bottom, &right, &top); r.setLeft( left ); r.setRight( right ); r.setBottom( bottom ); r.setTop( top ); }