qskinny/src/nodes/QskStrokeNode.cpp

137 lines
3.7 KiB
C++

/******************************************************************************
* QSkinny - Copyright (C) The authors
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskStrokeNode.h"
#include "QskVertex.h"
#include "QskGradient.h"
#include "QskRgbValue.h"
#include <qpainterpath.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qtriangulatingstroker_p.h>
QSK_QT_PRIVATE_END
static inline bool qskIsPenVisible( const QPen& pen )
{
if ( pen.style() == Qt::NoPen )
return false;
if ( pen.brush().gradient() )
{
// TODO ...
}
else
{
if ( !QskRgb::isVisible( pen.color() ) )
return false;
}
return true;
}
QskStrokeNode::QskStrokeNode()
{
}
QskStrokeNode::~QskStrokeNode() = default;
void QskStrokeNode::updatePath( const QPainterPath& path, const QPen& pen )
{
updatePath( path, QTransform(), pen );
}
void QskStrokeNode::updatePath(
const QPainterPath& path, const QTransform& transform, const QPen& pen )
{
if ( path.isEmpty() || !qskIsPenVisible( pen ) )
{
resetGeometry();
return;
}
if ( auto qGradient = pen.brush().gradient() )
{
const auto r = transform.mapRect( path.boundingRect() );
QskGradient gradient( *qGradient );
gradient.setStretchMode( QskGradient::StretchToSize );
setColoring( r, gradient );
}
else
setColoring( pen.color() );
if ( true ) // For the moment we always update the geometry. TODO ...
{
/*
Unfortunately QTriangulatingStroker does not offer on the fly
transformations - like with qTriangulate. TODO ...
*/
const auto scaledPath = transform.map( path );
auto effectivePen = pen;
if ( !effectivePen.isCosmetic() )
{
const auto scaleFactor = qMin( transform.m11(), transform.m22() );
if ( scaleFactor != 1.0 )
{
effectivePen.setWidth( effectivePen.widthF() * scaleFactor );
effectivePen.setCosmetic( false );
}
}
QTriangulatingStroker stroker;
if ( pen.style() == Qt::SolidLine )
{
// clipRect, renderHint are ignored in QTriangulatingStroker::process
stroker.process( qtVectorPathForPath( scaledPath ), effectivePen, {}, {} );
}
else
{
constexpr QRectF clipRect; // empty rect: no clipping
QDashedStrokeProcessor dashStroker;
dashStroker.process( qtVectorPathForPath( scaledPath ),
effectivePen, clipRect, {} );
const QVectorPath dashedVectorPath( dashStroker.points(),
dashStroker.elementCount(), dashStroker.elementTypes(), 0 );
stroker.process( dashedVectorPath, effectivePen, {}, {} );
}
auto& geometry = *this->geometry();
// 2 vertices for each point
geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
geometry.allocate( stroker.vertexCount() / 2 );
if ( isGeometryColored() )
{
const QskVertex::Color c( pen.color() );
const auto v = stroker.vertices();
auto points = geometry.vertexDataAsColoredPoint2D();
for ( int i = 0; i < geometry.vertexCount(); i++ )
{
const auto j = 2 * i;
points[i].set( v[j], v[j + 1], c.r, c.g, c.b, c.a );
}
}
else
{
memcpy( geometry.vertexData(), stroker.vertices(),
stroker.vertexCount() * sizeof( float ) );
}
geometry.markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
}
}