source: trunk/src/gui/painting/qoutlinemapper.cpp@ 938

Last change on this file since 938 was 846, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 13.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qoutlinemapper_p.h"
43#include <private/qpainterpath_p.h>
44#include "qmath.h"
45
46#include <stdlib.h>
47
48QT_BEGIN_NAMESPACE
49
50static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
51
52#define qreal_to_fixed_26_6(f) (int(f * 64))
53
54
55
56
57static const QRectF boundingRect(const QPointF *points, int pointCount)
58{
59 const QPointF *e = points;
60 const QPointF *last = points + pointCount;
61 qreal minx, maxx, miny, maxy;
62 minx = maxx = e->x();
63 miny = maxy = e->y();
64 while (++e < last) {
65 if (e->x() < minx)
66 minx = e->x();
67 else if (e->x() > maxx)
68 maxx = e->x();
69 if (e->y() < miny)
70 miny = e->y();
71 else if (e->y() > maxy)
72 maxy = e->y();
73 }
74 return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
75}
76
77
78QT_FT_Outline *QOutlineMapper::convertPath(const QPainterPath &path)
79{
80 Q_ASSERT(!path.isEmpty());
81 int elmCount = path.elementCount();
82#ifdef QT_DEBUG_CONVERT
83 printf("QOutlineMapper::convertPath(), size=%d\n", elmCount);
84#endif
85 beginOutline(path.fillRule());
86
87 for (int index=0; index<elmCount; ++index) {
88 const QPainterPath::Element &elm = path.elementAt(index);
89
90 switch (elm.type) {
91
92 case QPainterPath::MoveToElement:
93 if (index == elmCount - 1)
94 continue;
95 moveTo(elm);
96 break;
97
98 case QPainterPath::LineToElement:
99 lineTo(elm);
100 break;
101
102 case QPainterPath::CurveToElement:
103 curveTo(elm, path.elementAt(index + 1), path.elementAt(index + 2));
104 index += 2;
105 break;
106
107 default:
108 break; // This will never hit..
109 }
110 }
111
112 endOutline();
113 return outline();
114}
115
116QT_FT_Outline *QOutlineMapper::convertPath(const QVectorPath &path)
117{
118 int count = path.elementCount();
119
120#ifdef QT_DEBUG_CONVERT
121 printf("QOutlineMapper::convertPath(VP), size=%d\n", count);
122#endif
123 beginOutline(path.hasWindingFill() ? Qt::WindingFill : Qt::OddEvenFill);
124
125 if (path.elements()) {
126 // TODO: if we do closing of subpaths in convertElements instead we
127 // could avoid this loop
128 const QPainterPath::ElementType *elements = path.elements();
129 const QPointF *points = reinterpret_cast<const QPointF *>(path.points());
130
131 for (int index = 0; index < count; ++index) {
132 switch (elements[index]) {
133 case QPainterPath::MoveToElement:
134 if (index == count - 1)
135 continue;
136 moveTo(points[index]);
137 break;
138
139 case QPainterPath::LineToElement:
140 lineTo(points[index]);
141 break;
142
143 case QPainterPath::CurveToElement:
144 curveTo(points[index], points[index+1], points[index+2]);
145 index += 2;
146 break;
147
148 default:
149 break; // This will never hit..
150 }
151 }
152
153 } else {
154 // ### We can kill this copying and just use the buffer straight...
155
156 m_elements.resize(count);
157 if (count)
158 memcpy(m_elements.data(), path.points(), count* sizeof(QPointF));
159
160 m_element_types.resize(0);
161 }
162
163 endOutline();
164 return outline();
165}
166
167
168void QOutlineMapper::endOutline()
169{
170 closeSubpath();
171
172 int element_count = m_elements.size();
173
174 if (element_count == 0) {
175 memset(&m_outline, 0, sizeof(m_outline));
176 return;
177 }
178
179 QPointF *elements;
180
181 // Transform the outline
182 if (m_txop == QTransform::TxNone) {
183 elements = m_elements.data();
184 } else {
185 if (m_txop == QTransform::TxTranslate) {
186 for (int i=0; i<m_elements.size(); ++i) {
187 const QPointF &e = m_elements.at(i);
188 m_elements_dev << QPointF(e.x() + m_dx, e.y() + m_dy);
189 }
190 } else if (m_txop == QTransform::TxScale) {
191 for (int i=0; i<m_elements.size(); ++i) {
192 const QPointF &e = m_elements.at(i);
193 m_elements_dev << QPointF(m_m11 * e.x() + m_dx, m_m22 * e.y() + m_dy);
194 }
195 } else if (m_txop < QTransform::TxProject) {
196 for (int i=0; i<m_elements.size(); ++i) {
197 const QPointF &e = m_elements.at(i);
198 m_elements_dev << QPointF(m_m11 * e.x() + m_m21 * e.y() + m_dx,
199 m_m22 * e.y() + m_m12 * e.x() + m_dy);
200 }
201 } else {
202 const QVectorPath vp((qreal *)m_elements.data(), m_elements.size(), m_element_types.size() ? m_element_types.data() : 0);
203 QPainterPath path = vp.convertToPainterPath();
204 path = QTransform(m_m11, m_m12, m_m13, m_m21, m_m22, m_m23, m_dx, m_dy, m_m33).map(path);
205 if (!(m_outline.flags & QT_FT_OUTLINE_EVEN_ODD_FILL))
206 path.setFillRule(Qt::WindingFill);
207 uint old_txop = m_txop;
208 m_txop = QTransform::TxNone;
209 if (path.isEmpty())
210 m_valid = false;
211 else
212 convertPath(path);
213 m_txop = old_txop;
214 return;
215 }
216 elements = m_elements_dev.data();
217 }
218
219 if (m_round_coords) {
220 // round coordinates to match outlines drawn with drawLine_midpoint_i
221 for (int i = 0; i < m_elements.size(); ++i)
222 elements[i] = QPointF(qFloor(elements[i].x() + aliasedCoordinateDelta),
223 qFloor(elements[i].y() + aliasedCoordinateDelta));
224 }
225
226 controlPointRect = boundingRect(elements, element_count);
227
228#ifdef QT_DEBUG_CONVERT
229 printf(" - control point rect (%.2f, %.2f) %.2f x %.2f, clip=(%d,%d, %dx%d)\n",
230 controlPointRect.x(), controlPointRect.y(),
231 controlPointRect.width(), controlPointRect.height(),
232 m_clip_rect.x(), m_clip_rect.y(), m_clip_rect.width(), m_clip_rect.height());
233#endif
234
235
236 // Check for out of dev bounds...
237 const bool do_clip = !m_in_clip_elements && ((controlPointRect.left() < -QT_RASTER_COORD_LIMIT
238 || controlPointRect.right() > QT_RASTER_COORD_LIMIT
239 || controlPointRect.top() < -QT_RASTER_COORD_LIMIT
240 || controlPointRect.bottom() > QT_RASTER_COORD_LIMIT
241 || controlPointRect.width() > QT_RASTER_COORD_LIMIT