/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtOpenGL module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** 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 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtriangulatingstroker_p.h" #include QT_BEGIN_NAMESPACE #define CURVE_FLATNESS Q_PI / 8 void QTriangulatingStroker::endCapOrJoinClosed(const qreal *start, const qreal *cur, bool implicitClose, bool endsAtStart) { if (endsAtStart) { join(start + 2); } else if (implicitClose) { join(start); lineTo(start); join(start+2); } else { endCap(cur); } } void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen) { 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(4, realWidth * CURVE_FLATNESS); } else { m_curvyness_add = m_width; m_curvyness_mul = CURVE_FLATNESS / m_inv_scale; m_roundness = qMax(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; Qt::PenCapStyle cap = m_cap_style; if (!types) { startPts = pts; bool endsAtStart = startPts[0] == *(endPts-2) && startPts[1] == *(endPts-1); Qt::PenCapStyle cap = m_cap_style; if (endsAtStart || path.hasImplicitClose()) m_cap_style = Qt::FlatCap; moveTo(pts); m_cap_style = cap; pts += 2; lineTo(pts); pts += 2; while (pts < endPts) { join(pts); lineTo(pts); pts += 2; } endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart); } else { bool endsAtStart; while (pts < endPts) { switch (*types) { case QPainterPath::MoveToElement: { if (pts != path.points()) endCapOrJoinClosed(startPts, pts, 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(64, (rad + m_curvyness_add) * m_curvyness_mul); if (threshold < 4) threshold = 4; qreal threshold_minus_1 = threshold - 1; float vx, vy; float cx = m_cx, cy = m_cy; float x, y; for (int i=1; iaddElement(QPainterPath::MoveToElement, x, y); } static void qdashprocessor_lineTo(qreal x, qreal y, void *data) { ((QDashedStrokeProcessor *) data)->addElement(QPainterPath::LineToElement, x, y); } static void qdashprocessor_cubicTo(qreal, qreal, qreal, qreal, qreal, qreal, void *) { Q_ASSERT(0); // The dasher should not produce curves... } QDashedStrokeProcessor::QDashedStrokeProcessor() : m_dash_stroker(0), m_inv_scale(1) { m_dash_stroker.setMoveToHook(qdashprocessor_moveTo); m_dash_stroker.setLineToHook(qdashprocessor_lineTo); m_dash_stroker.setCubicToHook(qdashprocessor_cubicTo); } 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 = pen.width(); if (width == 0) width = 1; m_dash_stroker.setDashPattern(pen.dashPattern()); m_dash_stroker.setStrokeWidth(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(64, qMax(bounds.width(), bounds.height()) * curvyness); if (threshold < 4) threshold = 4; qreal threshold_minus_1 = threshold - 1; for (int i=0; i