QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskClipNode.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskClipNode.h"
7#include "QskBoxBorderMetrics.h"
8#include "QskBoxRenderer.h"
9#include "QskBoxShapeMetrics.h"
10#include "QskFunctions.h"
11#include "QskVertex.h"
12
13#include <qquickwindow.h>
14
15static inline QskHashValue qskMetricsHash(
16 const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border )
17{
18 QskHashValue hash = 13000;
19
20 hash = shape.hash( hash );
21 return border.hash( hash );
22}
23
24static inline void qskSetBoundingRect( QSGClipNode* node, const QRectF& rect )
25{
26 /*
27 Depending on isRectangular: the "scene graph renderer can use
28 scissoring instead of stencil, which is significantly faster."
29
30 However the batch renderer ( qsgbatchrenderer.cpp ) is rounding
31 the clip rectangle to integers and the clip might become too small/large.
32 So we always have to use stencil clipping - even if it might have a negative
33 impact on the performance.
34
35 When isRectangular is set to false the clipRect is not used from the
36 renderer and we use the memory for the storing the bounding rectangle.
37 */
38
39 node->setIsRectangular( false );
40 node->setClipRect( rect );
41}
42
43static inline QskVertex::Line* qskAllocateLines(
44 QSGGeometry& geometry, int lineCount )
45{
46 geometry.allocate( 2 * lineCount ); // 2 points per line
47 return reinterpret_cast< QskVertex::Line* >( geometry.vertexData() );
48}
49
50QskClipNode::QskClipNode()
51 : m_hash( 0 )
52 , m_geometry( QSGGeometry::defaultAttributes_Point2D(), 0 )
53{
54 setGeometry( &m_geometry );
55}
56
57QskClipNode::~QskClipNode()
58{
59}
60
61void QskClipNode::setRect( const QRectF& rect )
62{
63 setRegion( rect, QRectF() );
64}
65
66void QskClipNode::setRegion( const QRectF& rect, const QRectF& excludedRect )
67{
68 if ( rect.isEmpty() )
69 {
70 /*
71 what about rectangles having a width/height
72 of 0 ( f.e lines ) TODO ...
73 */
74 reset();
75 return;
76 }
77
78 const auto innerRect = excludedRect.isEmpty()
79 ? QRectF() : excludedRect.intersected( rect );
80
81 const auto hash = qHashBits( &innerRect, sizeof( innerRect ), 1450 );
82 if ( ( hash == m_hash ) && ( rect == Inherited::clipRect() ) )
83 return;
84
85 qskSetBoundingRect( this, rect );
86 m_hash = hash;
87
88 m_geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
89
90 if ( innerRect.isEmpty() )
91 {
92 const auto l = qskAllocateLines( m_geometry, 2 );
93
94 l[0].setLine( rect.topLeft(), rect.topRight() );
95 l[1].setLine( rect.bottomLeft(), rect.bottomRight() );
96 }
97 else
98 {
99 const auto l = qskAllocateLines( m_geometry, 5 );
100
101 l[0].setLine( rect.topLeft(), innerRect.topLeft() );
102 l[1].setLine( rect.topRight(), innerRect.topRight() );
103 l[2].setLine( rect.bottomRight(), innerRect.bottomRight() );
104 l[3].setLine( rect.bottomLeft(), innerRect.bottomLeft() );
105 l[4] = l[0];
106 }
107
108 m_geometry.markVertexDataDirty();
109 markDirty( QSGNode::DirtyGeometry );
110}
111
112void QskClipNode::setBox( const QQuickWindow* window, const QRectF& rect,
113 const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border )
114{
115 if ( rect.isEmpty() )
116 {
117 reset();
118 return;
119 }
120
121 const auto hash = qskMetricsHash( shape, border );
122 if ( hash == m_hash && rect == boundingRectangle() )
123 return;
124
125 qskSetBoundingRect( this, rect );
126 m_hash = hash;
127
128 QskBoxRenderer renderer( window );
129 renderer.setFillLines( rect, shape, border, m_geometry );
130
131 m_geometry.markVertexDataDirty();
132 markDirty( QSGNode::DirtyGeometry );
133}
134
135void QskClipNode::reset()
136{
137 Inherited::setIsRectangular( true );
138 Inherited::setClipRect( QRectF() );
139
140 if ( m_geometry.vertexData() )
141 {
142 m_geometry.allocate( 0 );
143 m_geometry.markVertexDataDirty();
144 }
145
146 if ( m_hash != 0 )
147 {
148 m_hash = 0;
149 markDirty( QSGNode::DirtyGeometry );
150 }
151}