Example #1
0
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();
}
Example #2
0
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);
    }
}
Example #3
0
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);
    }
}
Example #4
0
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);
}
Example #5
0
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;
}
Example #6
0
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
}
Example #7
0
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);
    }
}
Example #8
0
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();
}