| /**************************************************************************** |
| ** |
| ** Copyright (C) 2015 The Qt Company Ltd. |
| ** Contact: http://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtGui module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL21$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see http://www.qt.io/terms-conditions. For further |
| ** information use the contact form at http://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 2.1 or version 3 as published by the Free |
| ** Software Foundation and appearing in the file LICENSE.LGPLv21 and |
| ** LICENSE.LGPLv3 included in the packaging of this file. Please review the |
| ** following information to ensure the GNU Lesser General Public License |
| ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and |
| ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| ** |
| ** As a special exception, The Qt Company gives you certain additional |
| ** rights. These rights are described in The Qt Company LGPL Exception |
| ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #ifndef QSTROKER_P_H |
| #define QSTROKER_P_H |
| |
| // |
| // W A R N I N G |
| // ------------- |
| // |
| // This file is not part of the Qt API. It exists purely as an |
| // implementation detail. This header file may change from version to |
| // version without notice, or even be removed. |
| // |
| // We mean it. |
| // |
| |
| #include "QtGui/qpainterpath.h" |
| #include "private/qdatabuffer_p.h" |
| #include "private/qnumeric_p.h" |
| |
| QT_BEGIN_NAMESPACE |
| |
| // #define QFIXED_IS_26_6 |
| |
| #if defined QFIXED_IS_26_6 |
| typedef int qfixed; |
| #define qt_real_to_fixed(real) qfixed(real * 64) |
| #define qt_int_to_fixed(real) qfixed(int(real) << 6) |
| #define qt_fixed_to_real(fixed) qreal(fixed / qreal(64)) |
| #define qt_fixed_to_int(fixed) int(fixed >> 6) |
| struct qfixed2d |
| { |
| qfixed x; |
| qfixed y; |
| |
| bool operator==(const qfixed2d &other) const { return x == other.x && y == other.y; } |
| }; |
| #elif defined QFIXED_IS_32_32 |
| typedef qint64 qfixed; |
| #define qt_real_to_fixed(real) qfixed(real * double(qint64(1) << 32)) |
| #define qt_fixed_to_real(fixed) qreal(fixed / double(qint64(1) << 32)) |
| struct qfixed2d |
| { |
| qfixed x; |
| qfixed y; |
| |
| bool operator==(const qfixed2d &other) const { return x == other.x && y == other.y; } |
| }; |
| #elif defined QFIXED_IS_16_16 |
| typedef int qfixed; |
| #define qt_real_to_fixed(real) qfixed(real * qreal(1 << 16)) |
| #define qt_fixed_to_real(fixed) qreal(fixed / qreal(1 << 16)) |
| struct qfixed2d |
| { |
| qfixed x; |
| qfixed y; |
| |
| bool operator==(const qfixed2d &other) const { return x == other.x && y == other.y; } |
| }; |
| #else |
| typedef qreal qfixed; |
| #define qt_real_to_fixed(real) qfixed(real) |
| #define qt_fixed_to_real(fixed) fixed |
| struct qfixed2d |
| { |
| qfixed x; |
| qfixed y; |
| |
| bool operator==(const qfixed2d &other) const { return qFuzzyCompare(x, other.x) |
| && qFuzzyCompare(y, other.y); } |
| }; |
| #endif |
| |
| #define QT_PATH_KAPPA 0.5522847498 |
| |
| QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength, |
| QPointF *controlPoints, int *point_count); |
| |
| qreal qt_t_for_arc_angle(qreal angle); |
| |
| typedef void (*qStrokerMoveToHook)(qfixed x, qfixed y, void *data); |
| typedef void (*qStrokerLineToHook)(qfixed x, qfixed y, void *data); |
| typedef void (*qStrokerCubicToHook)(qfixed c1x, qfixed c1y, |
| qfixed c2x, qfixed c2y, |
| qfixed ex, qfixed ey, |
| void *data); |
| |
| // qtransform.cpp |
| Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale); |
| |
| class Q_GUI_EXPORT QStrokerOps |
| { |
| public: |
| struct Element { |
| QPainterPath::ElementType type; |
| qfixed x; |
| qfixed y; |
| |
| inline bool isMoveTo() const { return type == QPainterPath::MoveToElement; } |
| inline bool isLineTo() const { return type == QPainterPath::LineToElement; } |
| inline bool isCurveTo() const { return type == QPainterPath::CurveToElement; } |
| |
| operator qfixed2d () { qfixed2d pt = { x, y }; return pt; } |
| }; |
| |
| QStrokerOps(); |
| virtual ~QStrokerOps(); |
| |
| void setMoveToHook(qStrokerMoveToHook moveToHook) { m_moveTo = moveToHook; } |
| void setLineToHook(qStrokerLineToHook lineToHook) { m_lineTo = lineToHook; } |
| void setCubicToHook(qStrokerCubicToHook cubicToHook) { m_cubicTo = cubicToHook; } |
| |
| virtual void begin(void *customData); |
| virtual void end(); |
| |
| inline void moveTo(qfixed x, qfixed y); |
| inline void lineTo(qfixed x, qfixed y); |
| inline void cubicTo(qfixed x1, qfixed y1, qfixed x2, qfixed y2, qfixed ex, qfixed ey); |
| |
| void strokePath(const QPainterPath &path, void *data, const QTransform &matrix); |
| void strokePolygon(const QPointF *points, int pointCount, bool implicit_close, |
| void *data, const QTransform &matrix); |
| void strokeEllipse(const QRectF &ellipse, void *data, const QTransform &matrix); |
| |
| QRectF clipRect() const { return m_clip_rect; } |
| void setClipRect(const QRectF &clip) { m_clip_rect = clip; } |
| |
| void setCurveThresholdFromTransform(const QTransform &transform) |
| { |
| qreal scale; |
| qt_scaleForTransform(transform, &scale); |
| m_dashThreshold = scale == 0 ? qreal(0.5) : (qreal(0.5) / scale); |
| } |
| |
| void setCurveThreshold(qfixed threshold) { m_curveThreshold = threshold; } |
| qfixed curveThreshold() const { return m_curveThreshold; } |
| |
| protected: |
| inline void emitMoveTo(qfixed x, qfixed y); |
| inline void emitLineTo(qfixed x, qfixed y); |
| inline void emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey); |
| |
| virtual void processCurrentSubpath() = 0; |
| QDataBuffer<Element> m_elements; |
| |
| QRectF m_clip_rect; |
| qfixed m_curveThreshold; |
| qfixed m_dashThreshold; |
| |
| void *m_customData; |
| qStrokerMoveToHook m_moveTo; |
| qStrokerLineToHook m_lineTo; |
| qStrokerCubicToHook m_cubicTo; |
| |
| }; |
| |
| class Q_GUI_EXPORT QStroker : public QStrokerOps |
| { |
| public: |
| |
| enum LineJoinMode { |
| FlatJoin, |
| SquareJoin, |
| MiterJoin, |
| RoundJoin, |
| RoundCap, |
| SvgMiterJoin |
| }; |
| |
| QStroker(); |
| ~QStroker(); |
| |
| void setStrokeWidth(qfixed width) { m_strokeWidth = width; m_curveThreshold = width >= 1 ? 1.0/width : 0.5;} |
| qfixed strokeWidth() const { return m_strokeWidth; } |
| |
| void setCapStyle(Qt::PenCapStyle capStyle) { m_capStyle = joinModeForCap(capStyle); } |
| Qt::PenCapStyle capStyle() const { return capForJoinMode(m_capStyle); } |
| LineJoinMode capStyleMode() const { return m_capStyle; } |
| |
| void setJoinStyle(Qt::PenJoinStyle style) { m_joinStyle = joinModeForJoin(style); } |
| Qt::PenJoinStyle joinStyle() const { return joinForJoinMode(m_joinStyle); } |
| LineJoinMode joinStyleMode() const { return m_joinStyle; } |
| |
| void setMiterLimit(qfixed length) { m_miterLimit = length; } |
| qfixed miterLimit() const { return m_miterLimit; } |
| |
| void joinPoints(qfixed x, qfixed y, const QLineF &nextLine, LineJoinMode join); |
| inline void emitMoveTo(qfixed x, qfixed y); |
| inline void emitLineTo(qfixed x, qfixed y); |
| inline void emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey); |
| |
| protected: |
| static Qt::PenCapStyle capForJoinMode(LineJoinMode mode); |
| static LineJoinMode joinModeForCap(Qt::PenCapStyle); |
| |
| static Qt::PenJoinStyle joinForJoinMode(LineJoinMode mode); |
| static LineJoinMode joinModeForJoin(Qt::PenJoinStyle joinStyle); |
| |
| virtual void processCurrentSubpath(); |
| |
| qfixed m_strokeWidth; |
| qfixed m_miterLimit; |
| |
| LineJoinMode m_capStyle; |
| LineJoinMode m_joinStyle; |
| |
| qfixed m_back1X; |
| qfixed m_back1Y; |
| |
| qfixed m_back2X; |
| qfixed m_back2Y; |
| }; |
| |
| class Q_GUI_EXPORT QDashStroker : public QStrokerOps |
| { |
| public: |
| QDashStroker(QStroker *stroker); |
| ~QDashStroker(); |
| |
| QStroker *stroker() const { return m_stroker; } |
| |
| static QVector<qfixed> patternForStyle(Qt::PenStyle style); |
| |
| void setDashPattern(const QVector<qfixed> &dashPattern) { m_dashPattern = dashPattern; } |
| QVector<qfixed> dashPattern() const { return m_dashPattern; } |
| |
| void setDashOffset(qreal offset) { m_dashOffset = offset; } |
| qreal dashOffset() const { return m_dashOffset; } |
| |
| virtual void begin(void *data); |
| virtual void end(); |
| |
| inline void setStrokeWidth(qreal width) { m_stroke_width = width; } |
| inline void setMiterLimit(qreal limit) { m_miter_limit = limit; } |
| |
| protected: |
| virtual void processCurrentSubpath(); |
| |
| QStroker *m_stroker; |
| QVector<qfixed> m_dashPattern; |
| qreal m_dashOffset; |
| |
| qreal m_stroke_width; |
| qreal m_miter_limit; |
| }; |
| |
| |
| /******************************************************************************* |
| * QStrokerOps inline membmers |
| */ |
| |
| inline void QStrokerOps::emitMoveTo(qfixed x, qfixed y) |
| { |
| Q_ASSERT(m_moveTo); |
| m_moveTo(x, y, m_customData); |
| } |
| |
| inline void QStrokerOps::emitLineTo(qfixed x, qfixed y) |
| { |
| Q_ASSERT(m_lineTo); |
| m_lineTo(x, y, m_customData); |
| } |
| |
| inline void QStrokerOps::emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey) |
| { |
| Q_ASSERT(m_cubicTo); |
| m_cubicTo(c1x, c1y, c2x, c2y, ex, ey, m_customData); |
| } |
| |
| inline void QStrokerOps::moveTo(qfixed x, qfixed y) |
| { |
| if (m_elements.size()>1) |
| processCurrentSubpath(); |
| m_elements.reset(); |
| Element e = { QPainterPath::MoveToElement, x, y }; |
| m_elements.add(e); |
| } |
| |
| inline void QStrokerOps::lineTo(qfixed x, qfixed y) |
| { |
| Element e = { QPainterPath::LineToElement, x, y }; |
| m_elements.add(e); |
| } |
| |
| inline void QStrokerOps::cubicTo(qfixed x1, qfixed y1, qfixed x2, qfixed y2, qfixed ex, qfixed ey) |
| { |
| Element c1 = { QPainterPath::CurveToElement, x1, y1 }; |
| Element c2 = { QPainterPath::CurveToDataElement, x2, y2 }; |
| Element e = { QPainterPath::CurveToDataElement, ex, ey }; |
| m_elements.add(c1); |
| m_elements.add(c2); |
| m_elements.add(e); |
| } |
| |
| /******************************************************************************* |
| * QStroker inline members |
| */ |
| inline void QStroker::emitMoveTo(qfixed x, qfixed y) |
| { |
| m_back2X = m_back1X; |
| m_back2Y = m_back1Y; |
| m_back1X = x; |
| m_back1Y = y; |
| QStrokerOps::emitMoveTo(x, y); |
| } |
| |
| inline void QStroker::emitLineTo(qfixed x, qfixed y) |
| { |
| m_back2X = m_back1X; |
| m_back2Y = m_back1Y; |
| m_back1X = x; |
| m_back1Y = y; |
| QStrokerOps::emitLineTo(x, y); |
| } |
| |
| inline void QStroker::emitCubicTo(qfixed c1x, qfixed c1y, |
| qfixed c2x, qfixed c2y, |
| qfixed ex, qfixed ey) |
| { |
| if (c2x == ex && c2y == ey) { |
| if (c1x == ex && c1y == ey) { |
| m_back2X = m_back1X; |
| m_back2Y = m_back1Y; |
| } else { |
| m_back2X = c1x; |
| m_back2Y = c1y; |
| } |
| } else { |
| m_back2X = c2x; |
| m_back2Y = c2y; |
| } |
| m_back1X = ex; |
| m_back1Y = ey; |
| QStrokerOps::emitCubicTo(c1x, c1y, c2x, c2y, ex, ey); |
| } |
| |
| /******************************************************************************* |
| * QDashStroker inline members |
| */ |
| inline void QDashStroker::begin(void *data) |
| { |
| if (m_stroker) |
| m_stroker->begin(data); |
| QStrokerOps::begin(data); |
| } |
| |
| inline void QDashStroker::end() |
| { |
| QStrokerOps::end(); |
| if (m_stroker) |
| m_stroker->end(); |
| } |
| |
| QT_END_NAMESPACE |
| |
| #endif // QSTROKER_P_H |