1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QOUTLINEMAPPER_P_H
41 #define QOUTLINEMAPPER_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <QtGui/private/qtguiglobal_p.h>
55 #include <QtCore/qrect.h>
56 
57 #include <QtGui/qtransform.h>
58 #include <QtGui/qpainterpath.h>
59 
60 #define QT_FT_BEGIN_HEADER
61 #define QT_FT_END_HEADER
62 
63 #include <private/qrasterdefs_p.h>
64 #include <private/qdatabuffer_p.h>
65 #include "qpaintengineex_p.h"
66 
67 QT_BEGIN_NAMESPACE
68 
69 // This limitations comes from qgrayraster.c. Any higher and
70 // rasterization of shapes will produce incorrect results.
71 const int QT_RASTER_COORD_LIMIT = 32767;
72 
73 //#define QT_DEBUG_CONVERT
74 
75 Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
76 
77 /********************************************************************************
78  * class QOutlineMapper
79  *
80  * Used to map between QPainterPath and the QT_FT_Outline structure used by the
81  * freetype scanconvertor.
82  *
83  * The outline mapper uses a path iterator to get points from the path,
84  * so that it is possible to transform the points as they are converted. The
85  * callback can be a noop, translate or full-fledged xform. (Tests indicated
86  * that using a C callback was low cost).
87  */
88 class QOutlineMapper
89 {
90 public:
QOutlineMapper()91     QOutlineMapper() :
92         m_element_types(0),
93         m_elements(0),
94         m_points(0),
95         m_tags(0),
96         m_contours(0),
97         m_in_clip_elements(false)
98     {
99     }
100 
101     /*!
102       Sets up the matrix to be used for conversion. This also
103       sets up the qt_path_iterator function that is used as a callback
104       to get points.
105     */
setMatrix(const QTransform & m)106     void setMatrix(const QTransform &m)
107     {
108         m_transform = m;
109 
110         qreal scale;
111         qt_scaleForTransform(m, &scale);
112         m_curve_threshold = scale == 0 ? qreal(0.25) : (qreal(0.25) / scale);
113     }
114 
beginOutline(Qt::FillRule fillRule)115     void beginOutline(Qt::FillRule fillRule)
116     {
117 #ifdef QT_DEBUG_CONVERT
118         printf("QOutlineMapper::beginOutline rule=%d\n", fillRule);
119 #endif
120         m_valid = true;
121         m_elements.reset();
122         m_element_types.reset();
123         m_points.reset();
124         m_tags.reset();
125         m_contours.reset();
126         m_outline.flags = fillRule == Qt::WindingFill
127                           ? QT_FT_OUTLINE_NONE
128                           : QT_FT_OUTLINE_EVEN_ODD_FILL;
129         m_subpath_start = 0;
130     }
131 
132     void endOutline();
133 
134     void clipElements(const QPointF *points, const QPainterPath::ElementType *types, int count);
135 
136     void convertElements(const QPointF *points, const QPainterPath::ElementType *types, int count);
137 
moveTo(const QPointF & pt)138     inline void moveTo(const QPointF &pt) {
139 #ifdef QT_DEBUG_CONVERT
140         printf("QOutlineMapper::moveTo() (%f, %f)\n", pt.x(), pt.y());
141 #endif
142         closeSubpath();
143         m_subpath_start = m_elements.size();
144         m_elements << pt;
145         m_element_types << QPainterPath::MoveToElement;
146     }
147 
lineTo(const QPointF & pt)148     inline void lineTo(const QPointF &pt) {
149 #ifdef QT_DEBUG_CONVERT
150         printf("QOutlineMapper::lineTo() (%f, %f)\n", pt.x(), pt.y());
151 #endif
152         m_elements.add(pt);
153         m_element_types << QPainterPath::LineToElement;
154     }
155 
156     void curveTo(const QPointF &cp1, const QPointF &cp2, const QPointF &ep);
157 
closeSubpath()158     inline void closeSubpath() {
159         int element_count = m_elements.size();
160         if (element_count > 0) {
161             if (m_elements.at(element_count-1) != m_elements.at(m_subpath_start)) {
162 #ifdef QT_DEBUG_CONVERT
163                 printf(" - implicitly closing\n");
164 #endif
165                 // Put the object on the stack to avoid the odd case where
166                 // lineTo reallocs the databuffer and the QPointF & will
167                 // be invalidated.
168                 QPointF pt = m_elements.at(m_subpath_start);
169 
170                 // only do lineTo if we have element_type array...
171                 if (m_element_types.size())
172                     lineTo(pt);
173                 else
174                     m_elements << pt;
175 
176             }
177         }
178     }
179 
outline()180     QT_FT_Outline *outline() {
181         if (m_valid)
182             return &m_outline;
183         return nullptr;
184     }
185 
186     QT_FT_Outline *convertPath(const QPainterPath &path);
187     QT_FT_Outline *convertPath(const QVectorPath &path);
188 
elementTypes()189     inline QPainterPath::ElementType *elementTypes() const { return m_element_types.size() == 0 ? nullptr : m_element_types.data(); }
190 
191 public:
192     QDataBuffer<QPainterPath::ElementType> m_element_types;
193     QDataBuffer<QPointF> m_elements;
194     QDataBuffer<QT_FT_Vector> m_points;
195     QDataBuffer<char> m_tags;
196     QDataBuffer<int> m_contours;
197 
198     QRect m_clip_rect;
199     QRectF controlPointRect; // only valid after endOutline()
200 
201     QT_FT_Outline m_outline;
202 
203     int m_subpath_start;
204 
205     QTransform m_transform;
206 
207     qreal m_curve_threshold;
208 
209     bool m_valid;
210     bool m_in_clip_elements;
211 };
212 
213 QT_END_NAMESPACE
214 
215 #endif // QOUTLINEMAPPER_P_H
216