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

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

trunk: Merged in qt 4.6.2 sources.

File size: 13.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
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 qt-info@nokia.com.
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 memcpy(m_elements.data(), path.points(), count* sizeof(QPointF));
158
159 m_element_types.resize(0);
160 }
161
162 endOutline();
163 return outline();
164}
165
166
167void QOutlineMapper::endOutline()
168{
169 closeSubpath();
170
171 int element_count = m_elements.size();
172
173 if (element_count == 0) {
174 memset(&m_outline, 0, sizeof(m_outline));
175 return;
176 }
177
178 QPointF *elements;
179
180 // Transform the outline
181 if (m_txop == QTransform::TxNone) {
182 elements = m_elements.data();
183 } else {
184 if (m_txop == QTransform::TxTranslate) {
185 for (int i=0; i<m_elements.size(); ++i) {
186 const QPointF &e = m_elements.at(i);
187 m_elements_dev << QPointF(e.x() + m_dx, e.y() + m_dy);
188 }
189 } else if (m_txop == QTransform::TxScale) {
190 for (int i=0; i<m_elements.size(); ++i) {
191 const QPointF &e = m_elements.at(i);
192 m_elements_dev << QPointF(m_m11 * e.x() + m_dx, m_m22 * e.y() + m_dy);
193 }
194 } else if (m_txop < QTransform::TxProject) {
195 for (int i=0; i<m_elements.size(); ++i) {
196 const QPointF &e = m_elements.at(i);
197 m_elements_dev << QPointF(m_m11 * e.x() + m_m21 * e.y() + m_dx,
198 m_m22 * e.y() + m_m12 * e.x() + m_dy);
199 }
200 } else {
201 const QVectorPath vp((qreal *)m_elements.data(), m_elements.size(), m_element_types.size() ? m_element_types.data() : 0);
202 QPainterPath path = vp.convertToPainterPath();
203 path = QTransform(m_m11, m_m12, m_m13, m_m21, m_m22, m_m23, m_dx, m_dy, m_m33).map(path);
204 if (!(m_outline.flags & QT_FT_OUTLINE_EVEN_ODD_FILL))
205 path.setFillRule(Qt::WindingFill);
206 uint old_txop = m_txop;
207 m_txop = QTransform::TxNone;
208 if (path.isEmpty())
209 m_valid = false;
210 else
211 convertPath(path);
212 m_txop = old_txop;
213 return;
214 }
215 elements = m_elements_dev.data();
216 }
217
218 if (m_round_coords) {
219 // round coordinates to match outlines drawn with drawLine_midpoint_i
220 for (int i = 0; i < m_elements.size(); ++i)
221 elements[i] = QPointF(qFloor(elements[i].x() + aliasedCoordinateDelta),
222 qFloor(elements[i].y() + aliasedCoordinateDelta));
223 }
224
225 controlPointRect = boundingRect(elements, element_count);
226
227#ifdef QT_DEBUG_CONVERT
228 printf(" - control point rect (%.2f, %.2f) %.2f x %.2f, clip=(%d,%d, %dx%d)\n",
229 controlPointRect.x(), controlPointRect.y(),
230 controlPointRect.width(), controlPointRect.height(),
231 m_clip_rect.x(), m_clip_rect.y(), m_clip_rect.width(), m_clip_rect.height());
232#endif
233
234
235 // Check for out of dev bounds...
236 const bool do_clip = (controlPointRect.left() < -QT_RASTER_COORD_LIMIT
237 || controlPointRect.right() > QT_RASTER_COORD_LIMIT
238 || controlPointRect.top() < -QT_RASTER_COORD_LIMIT
239 || controlPointRect.bottom() > QT_RASTER_COORD_LIMIT
240 || controlPointRect.width() > QT_RASTER_COORD_LIMIT
241 || controlPointRect.height() > QT_RASTER_COORD_LIMIT);
242
243 if (do_clip) {
244 clipElements(elements, elementTypes(), element_count);
245 } else {
246 convertElements(elements, elementTypes(), element_count);
247 }
248}
249
250void QOutlineMapper::convertElements(const QPointF *elements,
251 const QPainterPath::ElementType *types,
252 int element_count)
253{
254
255 if (types) {
256 // Translate into FT coords
257 const QPointF *e = elements;
258 for (int i=0; i<element_count; ++i) {
259 switch (*types) {
260 case QPainterPath::MoveToElement:
261 {
262 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
263 qreal_to_fixed_26_6(e->y()) };
264 if (i != 0)
265 m_contours << m_points.size() - 1;
266 m_points << pt_fixed;
267 m_tags << QT_FT_CURVE_TAG_ON;
268 }
269 break;
270
271 case QPainterPath::LineToElement:
272 {
273 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
274 qreal_to_fixed_26_6(e->y()) };
275 m_points << pt_fixed;
276 m_tags << QT_FT_CURVE_TAG_ON;
277 }
278 break;
279
280 case QPainterPath::CurveToElement:
281 {
282 QT_FT_Vector cp1_fixed = { qreal_to_fixed_26_6(e->x()),
283 qreal_to_fixed_26_6(e->y()) };
284 ++e;
285 QT_FT_Vector cp2_fixed = { qreal_to_fixed_26_6((e)->x()),
286 qreal_to_fixed_26_6((e)->y()) };
287 ++e;
288 QT_FT_Vector ep_fixed = { qreal_to_fixed_26_6((e)->x()),
289 qreal_to_fixed_26_6((e)->y()) };
290
291 m_points << cp1_fixed << cp2_fixed << ep_fixed;
292 m_tags << QT_FT_CURVE_TAG_CUBIC
293 << QT_FT_CURVE_TAG_CUBIC
294 << QT_FT_CURVE_TAG_ON;
295
296 types += 2;
297 i += 2;
298 }
299 break;
300 default:
301 break;
302 }
303 ++types;
304 ++e;
305 }
306 } else {
307 // Plain polygon...
308 const QPointF *last = elements + element_count;
309 const QPointF *e = elements;
310 while (e < last) {
311 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
312 qreal_to_fixed_26_6(e->y()) };
313 m_points << pt_fixed;
314 m_tags << QT_FT_CURVE_TAG_ON;
315 ++e;
316 }
317 }
318
319 // close the very last subpath
320 m_contours << m_points.size() - 1;
321
322 m_outline.n_contours = m_contours.size();
323 m_outline.n_points = m_points.size();
324
325 m_outline.points = m_points.data();
326 m_outline.tags = m_tags.data();
327 m_outline.contours = m_contours.data();
328
329#ifdef QT_DEBUG_CONVERT
330 printf("QOutlineMapper::endOutline\n");
331
332 printf(" - contours: %d\n", m_outline.n_contours);
333 for (int i=0; i<m_outline.n_contours; ++i) {
334 printf(" - %d\n", m_outline.contours[i]);
335 }
336
337 printf(" - points: %d\n", m_outline.n_points);
338 for (int i=0; i<m_outline.n_points; ++i) {
339 printf(" - %d -- %.2f, %.2f, (%d, %d)\n", i,
340 (double) (m_outline.points[i].x / 64.0),
341 (double) (m_outline.points[i].y / 64.0),
342 (int) m_outline.points[i].x, (int) m_outline.points[i].y);
343 }
344#endif
345}
346
347void QOutlineMapper::clipElements(const QPointF *elements,
348 const QPainterPath::ElementType *types,
349 int element_count)
350{
351 // We could save a bit of time by actually implementing them fully
352 // instead of going through convenience functionallity, but since
353 // this part of code hardly every used, it shouldn't matter.
354
355 QPainterPath path;
356 if (types) {
357 for (int i=0; i<element_count; ++i) {
358 switch (types[i]) {
359 case QPainterPath::MoveToElement:
360 path.moveTo(elements[i]);
361 break;
362
363 case QPainterPath::LineToElement:
364 path.lineTo(elements[i]);
365 break;
366
367 case QPainterPath::CurveToElement:
368 path.cubicTo(elements[i], elements[i+1], elements[i+2]);
369 i += 2;
370 break;
371 default:
372 break;
373 }
374 }
375 } else {
376 path.moveTo(elements[0]);
377 for (int i=1; i<element_count; ++i)
378 path.lineTo(elements[i]);
379 }
380
381 QPainterPath clipPath;
382 clipPath.addRect(m_clip_rect);
383 QPainterPath clippedPath = path.intersected(clipPath);
384 uint old_txop = m_txop;
385 m_txop = QTransform::TxNone;
386 if (clippedPath.isEmpty())
387 m_valid = false;
388 else
389 convertPath(clippedPath);
390 m_txop = old_txop;
391}
392
393QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.