qreal QSvgNode::strokeWidth(QPainter *p) { QPen pen = p->pen(); if (pen.style() == Qt::NoPen || pen.brush().style() == Qt::NoBrush || pen.isCosmetic()) return 0; return pen.widthF(); }
void KoLineBorder::paint(KoShape *shape, QPainter &painter, const KoViewConverter &converter, const QColor &color) { KoShape::applyConversion(painter, converter); QPen pen = d->pen; pen.setColor(color); if (!pen.isCosmetic()) { painter.strokePath(shape->outline(), pen); } }
void KoShapeStroke::Private::paintBorder(KoShape *shape, QPainter &painter, const QPen &pen) const { if (!pen.isCosmetic()) { KoPathShape *pathShape = dynamic_cast<KoPathShape *>(shape); if (pathShape) { QPainterPath path = pathShape->pathStroke(pen); painter.fillPath(path, pen.brush()); return; } painter.strokePath(shape->outline(), pen); } }
void KoLineBorder::paint(KoShape *shape, QPainter &painter, const KoViewConverter &converter) { KoShape::applyConversion(painter, converter); QPen pen = d->pen; if (d->brush.gradient()) pen.setBrush(d->brush); else pen.setColor(d->color); if (!pen.isCosmetic()) painter.strokePath(shape->outline(), pen); }
static bool qwtHasScalablePen( const QPainter *painter ) { const QPen pen = painter->pen(); bool scalablePen = false; if ( pen.style() != Qt::NoPen && pen.brush().style() != Qt::NoBrush ) { scalablePen = !pen.isCosmetic(); if ( !scalablePen && pen.widthF() == 0.0 ) { const QPainter::RenderHints hints = painter->renderHints(); if ( hints.testFlag( QPainter::NonCosmeticDefaultPen ) ) scalablePen = true; } } return scalablePen; }
QPen QwtPainter::scaledPen(const QPen &pen) { #if QT_VERSION < 0x040000 return pen; #else QPen sPen = pen; if ( !pen.isCosmetic() ) { int pw = pen.width(); if ( pw == 0 ) pw = 1; sPen.setWidth(QwtPainter::metricsMap().screenToLayoutX(pw)); sPen.setCosmetic(true); } return sPen; #endif }
void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen, const QRectF &) { const qreal *pts = path.points(); const QPainterPath::ElementType *types = path.elements(); int count = path.elementCount(); if (count < 2) return; float realWidth = qpen_widthf(pen); if (realWidth == 0) realWidth = 1; m_width = realWidth / 2; bool cosmetic = pen.isCosmetic(); if (cosmetic) { m_width = m_width * m_inv_scale; } m_join_style = qpen_joinStyle(pen); m_cap_style = qpen_capStyle(pen); m_vertices.reset(); m_miter_limit = pen.miterLimit() * qpen_widthf(pen); // The curvyness is based on the notion that I originally wanted // roughly one line segment pr 4 pixels. This may seem little, but // because we sample at constantly incrementing B(t) E [0<t<1], we // will get longer segments where the curvature is small and smaller // segments when the curvature is high. // // To get a rough idea of the length of each curve, I pretend that // the curve is a 90 degree arc, whose radius is // qMax(curveBounds.width, curveBounds.height). Based on this // logic we can estimate the length of the outline edges based on // the radius + a pen width and adjusting for scale factors // depending on if the pen is cosmetic or not. // // The curvyness value of PI/14 was based on, // arcLength = 2*PI*r/4 = PI*r/2 and splitting length into somewhere // between 3 and 8 where 5 seemed to be give pretty good results // hence: Q_PI/14. Lower divisors will give more detail at the // direct cost of performance. // simplfy pens that are thin in device size (2px wide or less) if (realWidth < 2.5 && (cosmetic || m_inv_scale == 1)) { if (m_cap_style == Qt::RoundCap) m_cap_style = Qt::SquareCap; if (m_join_style == Qt::RoundJoin) m_join_style = Qt::MiterJoin; m_curvyness_add = 0.5; m_curvyness_mul = CURVE_FLATNESS / m_inv_scale; m_roundness = 1; } else if (cosmetic) { m_curvyness_add = realWidth / 2; m_curvyness_mul = CURVE_FLATNESS; m_roundness = qMax<int>(4, realWidth * CURVE_FLATNESS); } else { m_curvyness_add = m_width; m_curvyness_mul = CURVE_FLATNESS / m_inv_scale; m_roundness = qMax<int>(4, realWidth * m_curvyness_mul); } // Over this level of segmentation, there doesn't seem to be any // benefit, even for huge penWidth if (m_roundness > 24) m_roundness = 24; m_sin_theta = qFastSin(Q_PI / m_roundness); m_cos_theta = qFastCos(Q_PI / m_roundness); const qreal *endPts = pts + (count<<1); const qreal *startPts = 0; Qt::PenCapStyle cap = m_cap_style; if (!types) { // skip duplicate points while((pts + 2) < endPts && pts[0] == pts[2] && pts[1] == pts[3]) pts += 2; if ((pts + 2) == endPts) return; startPts = pts; bool endsAtStart = startPts[0] == *(endPts-2) && startPts[1] == *(endPts-1); if (endsAtStart || path.hasImplicitClose()) m_cap_style = Qt::FlatCap; moveTo(pts); m_cap_style = cap; pts += 2; lineTo(pts); pts += 2; while (pts < endPts) { if (m_cx != pts[0] || m_cy != pts[1]) { join(pts); lineTo(pts); } pts += 2; } endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart); } else { bool endsAtStart = false; while (pts < endPts) { switch (*types) { case QPainterPath::MoveToElement: { if (pts != path.points()) endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart); startPts = pts; int end = (endPts - pts) / 2; int i = 2; // Start looking to ahead since we never have two moveto's in a row while (i<end && types[i] != QPainterPath::MoveToElement) { ++i; } endsAtStart = startPts[0] == pts[i*2 - 2] && startPts[1] == pts[i*2 - 1]; if (endsAtStart || path.hasImplicitClose()) m_cap_style = Qt::FlatCap; moveTo(pts); m_cap_style = cap; pts+=2; ++types; break; } case QPainterPath::LineToElement: if (*(types - 1) != QPainterPath::MoveToElement) join(pts); lineTo(pts); pts+=2; ++types; break; case QPainterPath::CurveToElement: if (*(types - 1) != QPainterPath::MoveToElement) join(pts); cubicTo(pts); pts+=6; types+=3; break; default: Q_ASSERT(false); break; } } endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart); } }
void QDashedStrokeProcessor::process(const QVectorPath &path, const QPen &pen, const QRectF &clip) { const qreal *pts = path.points(); const QPainterPath::ElementType *types = path.elements(); int count = path.elementCount(); bool cosmetic = pen.isCosmetic(); m_points.reset(); m_types.reset(); m_points.reserve(path.elementCount()); m_types.reserve(path.elementCount()); qreal width = qpen_widthf(pen); if (width == 0) width = 1; m_dash_stroker.setDashPattern(pen.dashPattern()); m_dash_stroker.setStrokeWidth(cosmetic ? width * m_inv_scale : width); m_dash_stroker.setDashOffset(pen.dashOffset()); m_dash_stroker.setMiterLimit(pen.miterLimit()); m_dash_stroker.setClipRect(clip); float curvynessAdd, curvynessMul; // simplify pens that are thin in device size (2px wide or less) if (width < 2.5 && (cosmetic || m_inv_scale == 1)) { curvynessAdd = 0.5; curvynessMul = CURVE_FLATNESS / m_inv_scale; } else if (cosmetic) { curvynessAdd= width / 2; curvynessMul= CURVE_FLATNESS; } else { curvynessAdd = width * m_inv_scale; curvynessMul = CURVE_FLATNESS / m_inv_scale; } if (count < 2) return; const qreal *endPts = pts + (count<<1); m_dash_stroker.begin(this); if (!types) { m_dash_stroker.moveTo(pts[0], pts[1]); pts += 2; while (pts < endPts) { m_dash_stroker.lineTo(pts[0], pts[1]); pts += 2; } } else { while (pts < endPts) { switch (*types) { case QPainterPath::MoveToElement: m_dash_stroker.moveTo(pts[0], pts[1]); pts += 2; ++types; break; case QPainterPath::LineToElement: m_dash_stroker.lineTo(pts[0], pts[1]); pts += 2; ++types; break; case QPainterPath::CurveToElement: { QBezier b = QBezier::fromPoints(*(((const QPointF *) pts) - 1), *(((const QPointF *) pts)), *(((const QPointF *) pts) + 1), *(((const QPointF *) pts) + 2)); QRectF bounds = b.bounds(); float rad = qMax(bounds.width(), bounds.height()); int threshold = qMin<float>(64, (rad + curvynessAdd) * curvynessMul); if (threshold < 4) threshold = 4; qreal threshold_minus_1 = threshold - 1; for (int i=0; i<threshold; ++i) { QPointF pt = b.pointAt(i / threshold_minus_1); m_dash_stroker.lineTo(pt.x(), pt.y()); } pts += 6; types += 3; break; } default: break; } } } m_dash_stroker.end(); }
void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) { #ifdef QT_DEBUG_DRAW qDebug() << "QPaintEngineEx::stroke()" << pen; #endif Q_D(QPaintEngineEx); if (path.isEmpty()) return; if (!d->strokeHandler) { d->strokeHandler = new StrokeHandler(path.elementCount()+4); d->stroker.setMoveToHook(qpaintengineex_moveTo); d->stroker.setLineToHook(qpaintengineex_lineTo); d->stroker.setCubicToHook(qpaintengineex_cubicTo); } if (!qpen_fast_equals(pen, d->strokerPen)) { d->strokerPen = pen; d->stroker.setJoinStyle(pen.joinStyle()); d->stroker.setCapStyle(pen.capStyle()); d->stroker.setMiterLimit(pen.miterLimit()); qreal penWidth = pen.widthF(); if (penWidth == 0) d->stroker.setStrokeWidth(1); else d->stroker.setStrokeWidth(penWidth); Qt::PenStyle style = pen.style(); if (style == Qt::SolidLine) { d->activeStroker = &d->stroker; } else if (style == Qt::NoPen) { d->activeStroker = 0; } else { d->dasher.setDashPattern(pen.dashPattern()); d->dasher.setDashOffset(pen.dashOffset()); d->activeStroker = &d->dasher; } } if (!d->activeStroker) { return; } if (pen.style() > Qt::SolidLine) { if (pen.isCosmetic()) { d->activeStroker->setClipRect(d->exDeviceRect); } else { QRectF clipRect = state()->matrix.inverted().mapRect(QRectF(d->exDeviceRect)); d->activeStroker->setClipRect(clipRect); } } const QPainterPath::ElementType *types = path.elements(); const qreal *points = path.points(); int pointCount = path.elementCount(); const qreal *lastPoint = points + (pointCount<<1); d->strokeHandler->types.reset(); d->strokeHandler->pts.reset(); // Some engines might decide to optimize for the non-shape hint later on... uint flags = QVectorPath::WindingFill; if (path.elementCount() > 2) flags |= QVectorPath::NonConvexShapeMask; if (d->stroker.capStyle() == Qt::RoundCap || d->stroker.joinStyle() == Qt::RoundJoin) flags |= QVectorPath::CurvedShapeMask; // ### Perspective Xforms are currently not supported... if (!pen.isCosmetic()) { // We include cosmetic pens in this case to avoid having to // change the current transform. Normal transformed, // non-cosmetic pens will be transformed as part of fill // later, so they are also covered here.. d->activeStroker->setCurveThresholdFromTransform(state()->matrix); d->activeStroker->begin(d->strokeHandler); if (types) { while (points < lastPoint) { switch (*types) { case QPainterPath::MoveToElement: d->activeStroker->moveTo(points[0], points[1]); points += 2; ++types; break; case QPainterPath::LineToElement: d->activeStroker->lineTo(points[0], points[1]); points += 2; ++types; break; case QPainterPath::CurveToElement: d->activeStroker->cubicTo(points[0], points[1], points[2], points[3], points[4], points[5]); points += 6; types += 3; flags |= QVectorPath::CurvedShapeMask; break; default: break; } } if (path.hasImplicitClose()) d->activeStroker->lineTo(path.points()[0], path.points()[1]); } else { d->activeStroker->moveTo(points[0], points[1]); points += 2; while (points < lastPoint) { d->activeStroker->lineTo(points[0], points[1]); points += 2; } if (path.hasImplicitClose()) d->activeStroker->lineTo(path.points()[0], path.points()[1]); } d->activeStroker->end(); if (!d->strokeHandler->types.size()) // an empty path... return; QVectorPath strokePath(d->strokeHandler->pts.data(), d->strokeHandler->types.size(), d->strokeHandler->types.data(), flags); fill(strokePath, pen.brush()); } else { // For cosmetic pens we need a bit of trickery... We to process xform the input points if (state()->matrix.type() >= QTransform::TxProject) { QPainterPath painterPath = state()->matrix.map(path.convertToPainterPath()); d->activeStroker->strokePath(painterPath, d->strokeHandler, QTransform()); } else { d->activeStroker->setCurveThresholdFromTransform(QTransform()); d->activeStroker->begin(d->strokeHandler); if (types) { while (points < lastPoint) { switch (*types) { case QPainterPath::MoveToElement: { QPointF pt = (*(QPointF *) points) * state()->matrix; d->activeStroker->moveTo(pt.x(), pt.y()); points += 2; ++types; break; } case QPainterPath::LineToElement: { QPointF pt = (*(QPointF *) points) * state()->matrix; d->activeStroker->lineTo(pt.x(), pt.y()); points += 2; ++types; break; } case QPainterPath::CurveToElement: { QPointF c1 = ((QPointF *) points)[0] * state()->matrix; QPointF c2 = ((QPointF *) points)[1] * state()->matrix; QPointF e = ((QPointF *) points)[2] * state()->matrix; d->activeStroker->cubicTo(c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y()); points += 6; types += 3; flags |= QVectorPath::CurvedShapeMask; break; } default: break; } } if (path.hasImplicitClose()) { QPointF pt = * ((QPointF *) path.points()) * state()->matrix; d->activeStroker->lineTo(pt.x(), pt.y()); } } else { QPointF p = ((QPointF *)points)[0] * state()->matrix; d->activeStroker->moveTo(p.x(), p.y()); points += 2; while (points < lastPoint) { QPointF p = ((QPointF *)points)[0] * state()->matrix; d->activeStroker->lineTo(p.x(), p.y()); points += 2; } if (path.hasImplicitClose()) d->activeStroker->lineTo(p.x(), p.y()); } d->activeStroker->end(); } QVectorPath strokePath(d->strokeHandler->pts.data(), d->strokeHandler->types.size(), d->strokeHandler->types.data(), flags); QTransform xform = state()->matrix; state()->matrix = QTransform(); transformChanged(); QBrush brush = pen.brush(); if (qbrush_style(brush) != Qt::SolidPattern) brush.setTransform(brush.transform() * xform); fill(strokePath, brush); state()->matrix = xform; transformChanged(); } }
void QDashedStrokeProcessor::process(const QVectorPath &path, const QPen &pen) { const qreal *pts = path.points(); const QPainterPath::ElementType *types = path.elements(); int count = path.elementCount(); m_points.reset(); m_types.reset(); qreal width = qpen_widthf(pen); if (width == 0) width = 1; m_dash_stroker.setDashPattern(pen.dashPattern()); m_dash_stroker.setStrokeWidth(pen.isCosmetic() ? width * m_inv_scale : width); m_dash_stroker.setMiterLimit(pen.miterLimit()); qreal curvyness = sqrt(width) * m_inv_scale / 8; if (count < 2) return; const qreal *endPts = pts + (count<<1); m_dash_stroker.begin(this); if (!types) { m_dash_stroker.moveTo(pts[0], pts[1]); pts += 2; while (pts < endPts) { m_dash_stroker.lineTo(pts[0], pts[1]); pts += 2; } } else { while (pts < endPts) { switch (*types) { case QPainterPath::MoveToElement: m_dash_stroker.moveTo(pts[0], pts[1]); pts += 2; ++types; break; case QPainterPath::LineToElement: m_dash_stroker.lineTo(pts[0], pts[1]); pts += 2; ++types; break; case QPainterPath::CurveToElement: { QBezier b = QBezier::fromPoints(*(((const QPointF *) pts) - 1), *(((const QPointF *) pts)), *(((const QPointF *) pts) + 1), *(((const QPointF *) pts) + 2)); QRectF bounds = b.bounds(); int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * curvyness); if (threshold < 4) threshold = 4; qreal threshold_minus_1 = threshold - 1; for (int i=0; i<threshold; ++i) { QPointF pt = b.pointAt(i / threshold_minus_1); m_dash_stroker.lineTo(pt.x(), pt.y()); } pts += 6; types += 3; break; } default: break; } } } m_dash_stroker.end(); }