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

Last change on this file since 243 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 13.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qoutlinemapper_p.h"
43
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 // ## TODO: this case needs to be plain code polygonal paths
202 QPainterPath path;
203 if (m_element_types.isEmpty()) {
204 if (!m_elements.isEmpty())
205 path.moveTo(m_elements.at(0));
206 for (int i=1; i<m_elements.size(); ++i)
207 path.lineTo(m_elements.at(i));
208 } else {
209 for (int i=0; i<m_elements.size(); ++i) {
210 switch (m_element_types.at(i)) {
211 case QPainterPath::MoveToElement:
212 path.moveTo(m_elements.at(i));
213 break;
214 case QPainterPath::LineToElement:
215 path.lineTo(m_elements.at(i));
216 break;
217 case QPainterPath::CurveToElement:
218 path.cubicTo(m_elements.at(i), m_elements.at(i+1), m_elements.at(i+2));
219 i += 2;
220 break;
221 default:
222 Q_ASSERT(false);
223 break;
224 }
225 }
226 }
227 path = QTransform(m_m11, m_m12, m_m13, m_m21, m_m22, m_m23, m_dx, m_dy, m_m33).map(path);
228 uint old_txop = m_txop;
229 m_txop = QTransform::TxNone;
230 if (path.isEmpty())
231 m_valid = false;
232 else
233 convertPath(path);
234 m_txop = old_txop;
235 return;
236 }
237 elements = m_elements_dev.data();
238 }
239
240 if (m_round_coords) {
241 // round coordinates to match outlines drawn with drawLine_midpoint_i
242 for (int i = 0; i < m_elements.size(); ++i)
243 elements[i] = QPointF(qFloor(elements[i].x() + aliasedCoordinateDelta),
244 qFloor(elements[i].y() + aliasedCoordinateDelta));
245 }
246
247 controlPointRect = boundingRect(elements, element_count);
248
249#ifdef QT_DEBUG_CONVERT
250 printf(" - control point rect (%.2f, %.2f) %.2f x %.2f\n",
251 controlPointRect.x(), controlPointRect.y(),
252 controlPointRect.width(), controlPointRect.height());
253#endif
254
255
256 // Check for out of dev bounds...
257 const bool do_clip = (controlPointRect.left() < -QT_RASTER_COORD_LIMIT
258 || controlPointRect.right() > QT_RASTER_COORD_LIMIT
259 || controlPointRect.top() < -QT_RASTER_COORD_LIMIT
260 || controlPointRect.bottom() > QT_RASTER_COORD_LIMIT);
261
262 if (do_clip) {
263 clipElements(elements, elementTypes(), element_count);
264 } else {
265 convertElements(elements, elementTypes(), element_count);
266 }
267}
268
269void QOutlineMapper::convertElements(const QPointF *elements,
270 const QPainterPath::ElementType *types,
271 int element_count)
272{
273
274 if (types) {
275 // Translate into FT coords
276 const QPointF *e = elements;
277 for (int i=0; i<element_count; ++i) {
278 switch (*types) {
279 case QPainterPath::MoveToElement:
280 {
281 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
282 qreal_to_fixed_26_6(e->y()) };
283 if (i != 0)
284 m_contours << m_points.size() - 1;
285 m_points << pt_fixed;
286 m_tags << QT_FT_CURVE_TAG_ON;
287 }
288 break;
289
290 case QPainterPath::LineToElement:
291 {
292 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
293 qreal_to_fixed_26_6(e->y()) };
294 m_points << pt_fixed;
295 m_tags << QT_FT_CURVE_TAG_ON;
296 }
297 break;
298
299 case QPainterPath::CurveToElement:
300 {
301 QT_FT_Vector cp1_fixed = { qreal_to_fixed_26_6(e->x()),
302 qreal_to_fixed_26_6(e->y()) };
303 ++e;
304 QT_FT_Vector cp2_fixed = { qreal_to_fixed_26_6((e)->x()),
305 qreal_to_fixed_26_6((e)->y()) };
306 ++e;
307 QT_FT_Vector ep_fixed = { qreal_to_fixed_26_6((e)->x()),
308 qreal_to_fixed_26_6((e)->y()) };
309
310 m_points << cp1_fixed << cp2_fixed << ep_fixed;
311 m_tags << QT_FT_CURVE_TAG_CUBIC
312 << QT_FT_CURVE_TAG_CUBIC
313 << QT_FT_CURVE_TAG_ON;
314
315 types += 2;
316 i += 2;
317 }
318 break;
319 default:
320 break;
321 }
322 ++types;
323 ++e;
324 }
325 } else {
326 // Plain polygon...
327 const QPointF *last = elements + element_count;
328 const QPointF *e = elements;
329 while (e < last) {
330 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
331 qreal_to_fixed_26_6(e->y()) };
332 m_points << pt_fixed;
333 m_tags << QT_FT_CURVE_TAG_ON;
334 ++e;
335 }
336 }
337
338 // close the very last subpath
339 m_contours << m_points.size() - 1;
340
341 m_outline.n_contours = m_contours.size();
342 m_outline.n_points = m_points.size();
343
344 m_outline.points = m_points.data();
345 m_outline.tags = m_tags.data();
346 m_outline.contours = m_contours.data();
347
348#ifdef QT_DEBUG_CONVERT
349 printf("QOutlineMapper::endOutline\n");
350
351 printf(" - contours: %d\n", m_outline.n_contours);
352 for (int i=0; i<m_outline.n_contours; ++i) {
353 printf(" - %d\n", m_outline.contours[i]);
354 }
355
356 printf(" - points: %d\n", m_outline.n_points);
357 for (int i=0; i<m_outline.n_points; ++i) {
358 printf(" - %d -- %.2f, %.2f, (%d, %d)\n", i,
359 (double) (m_outline.points[i].x / 64.0),
360 (double) (m_outline.points[i].y / 64.0),
361 (int) m_outline.points[i].x, (int) m_outline.points[i].y);
362 }
363#endif
364}
365
366void QOutlineMapper::clipElements(const QPointF *elements,
367 const QPainterPath::ElementType *types,
368 int element_count)
369{
370 // We could save a bit of time by actually implementing them fully
371 // instead of going through convenience functionallity, but since
372 // this part of code hardly every used, it shouldn't matter.
373
374 QPainterPath path;
375 if (types) {
376 for (int i=0; i<element_count; ++i) {
377 switch (types[i]) {
378 case QPainterPath::MoveToElement:
379 path.moveTo(elements[i]);
380 break;
381
382 case QPainterPath::LineToElement:
383 path.lineTo(elements[i]);
384 break;
385
386 case QPainterPath::CurveToElement:
387 path.cubicTo(elements[i], elements[i+1], elements[i+2]);
388 i += 2;
389 break;
390 default:
391 break;
392 }
393 }
394 } else {
395 path.moveTo(elements[0]);
396 for (int i=1; i<element_count; ++i)
397 path.lineTo(elements[i]);
398 }
399
400 QPainterPath clipPath;
401 clipPath.addRect(m_clip_rect);
402 QPainterPath clippedPath = path.intersected(clipPath);
403 uint old_txop = m_txop;
404 m_txop = QTransform::TxNone;
405 if (clippedPath.isEmpty())
406 m_valid = false;
407 else
408 convertPath(clippedPath);
409 m_txop = old_txop;
410}
411
412QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.