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

Last change on this file since 1034 was 846, checked in by Dmitry A. Kuminov, 14 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 (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 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
242 || controlPointRect.height() > QT_RASTER_COORD_LIMIT));
243
244 if (do_clip) {
245 clipElements(elements, elementTypes(), element_count);
246 } else {
247 convertElements(elements, elementTypes(), element_count);
248 }
249}
250
251void QOutlineMapper::convertElements(const QPointF *elements,
252 const QPainterPath::ElementType *types,
253 int element_count)
254{
255
256 if (types) {
257 // Translate into FT coords
258 const QPointF *e = elements;
259 for (int i=0; i<element_count; ++i) {
260 switch (*types) {
261 case QPainterPath::MoveToElement:
262 {
263 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
264 qreal_to_fixed_26_6(e->y()) };
265 if (i != 0)
266 m_contours << m_points.size() - 1;
267 m_points << pt_fixed;
268 m_tags << QT_FT_CURVE_TAG_ON;
269 }
270 break;
271
272 case QPainterPath::LineToElement:
273 {
274 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
275 qreal_to_fixed_26_6(e->y()) };
276 m_points << pt_fixed;
277 m_tags << QT_FT_CURVE_TAG_ON;
278 }
279 break;
280
281 case QPainterPath::CurveToElement:
282 {
283 QT_FT_Vector cp1_fixed = { qreal_to_fixed_26_6(e->x()),
284 qreal_to_fixed_26_6(e->y()) };
285 ++e;
286 QT_FT_Vector cp2_fixed = { qreal_to_fixed_26_6((e)->x()),
287 qreal_to_fixed_26_6((e)->y()) };
288 ++e;
289 QT_FT_Vector ep_fixed = { qreal_to_fixed_26_6((e)->x()),
290 qreal_to_fixed_26_6((e)->y()) };
291
292 m_points << cp1_fixed << cp2_fixed << ep_fixed;
293 m_tags << QT_FT_CURVE_TAG_CUBIC
294 << QT_FT_CURVE_TAG_CUBIC
295 << QT_FT_CURVE_TAG_ON;
296
297 types += 2;
298 i += 2;
299 }
300 break;
301 default:
302 break;
303 }
304 ++types;
305 ++e;
306 }
307 } else {
308 // Plain polygon...
309 const QPointF *last = elements + element_count;
310 const QPointF *e = elements;
311 while (e < last) {
312 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
313 qreal_to_fixed_26_6(e->y()) };
314 m_points << pt_fixed;
315 m_tags << QT_FT_CURVE_TAG_ON;
316 ++e;
317 }
318 }
319
320 // close the very last subpath
321 m_contours << m_points.size() - 1;
322
323 m_outline.n_contours = m_contours.size();
324 m_outline.n_points = m_points.size();
325
326 m_outline.points = m_points.data();
327 m_outline.tags = m_tags.data();
328 m_outline.contours = m_contours.data();
329
330#ifdef QT_DEBUG_CONVERT
331 printf("QOutlineMapper::endOutline\n");
332
333 printf(" - contours: %d\n", m_outline.n_contours);
334 for (int i=0; i<m_outline.n_contours; ++i) {
335 printf(" - %d\n", m_outline.contours[i]);
336 }
337
338 printf(" - points: %d\n", m_outline.n_points);
339 for (int i=0; i<m_outline.n_points; ++i) {
340 printf(" - %d -- %.2f, %.2f, (%d, %d)\n", i,
341 (double) (m_outline.points[i].x / 64.0),
342 (double) (m_outline.points[i].y / 64.0),
343 (int) m_outline.points[i].x, (int) m_outline.points[i].y);
344 }
345#endif
346}
347
348void QOutlineMapper::clipElements(const QPointF *elements,
349 const QPainterPath::ElementType *types,
350 int element_count)
351{
352 // We could save a bit of time by actually implementing them fully
353 // instead of going through convenience functionallity, but since
354 // this part of code hardly every used, it shouldn't matter.
355
356 m_in_clip_elements = true;
357
358 QPainterPath path;
359
360 if (!(m_outline.flags & QT_FT_OUTLINE_EVEN_ODD_FILL))
361 path.setFillRule(Qt::WindingFill);
362
363 if (types) {
364 for (int i=0; i<element_count; ++i) {
365 switch (types[i]) {
366 case QPainterPath::MoveToElement:
367 path.moveTo(elements[i]);
368 break;
369
370 case QPainterPath::LineToElement:
371 path.lineTo(elements[i]);
372 break;
373
374 case QPainterPath::CurveToElement:
375 path.cubicTo(elements[i], elements[i+1], elements[i+2]);
376 i += 2;
377 break;
378 default:
379 break;
380 }
381 }
382 } else {
383 path.moveTo(elements[0]);
384 for (int i=1; i<element_count; ++i)
385 path.lineTo(elements[i]);
386 }
387
388 QPainterPath clipPath;
389 clipPath.addRect(m_clip_rect);
390 QPainterPath clippedPath = path.intersected(clipPath);
391 uint old_txop = m_txop;
392 m_txop = QTransform::TxNone;
393 if (clippedPath.isEmpty())
394 m_valid = false;
395 else
396 convertPath(clippedPath);
397 m_txop = old_txop;
398
399 m_in_clip_elements = false;
400}
401
402QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.