1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qdrawutil.h"
43 #include "qbitmap.h"
44 #include "qpixmapcache.h"
45 #include "qapplication.h"
46 #include "qpainter.h"
47 #include "qpalette.h"
48 #include <private/qpaintengineex_p.h>
49 #include <qvarlengtharray.h>
50 #include <qmath.h>
51 #include <private/qstylehelper_p.h>
52 
53 QT_BEGIN_NAMESPACE
54 
55 /*!
56     \headerfile <qdrawutil.h>
57     \title Drawing Utility Functions
58 
59     \sa QPainter
60 */
61 
62 /*!
63     \fn void qDrawShadeLine(QPainter *painter, int x1, int y1, int x2, int y2,
64                      const QPalette &palette, bool sunken,
65                      int lineWidth, int midLineWidth)
66     \relates <qdrawutil.h>
67 
68     Draws a horizontal (\a y1 == \a y2) or vertical (\a x1 == \a x2)
69     shaded line using the given \a painter.  Note that nothing is
70     drawn if \a y1 != \a y2 and \a x1 != \a x2 (i.e. the line is
71     neither horizontal nor vertical).
72 
73     The provided \a palette specifies the shading colors (\l
74     {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
75     {QPalette::mid()}{middle} colors).  The given \a lineWidth
76     specifies the line width for each of the lines; it is not the
77     total line width. The given \a midLineWidth specifies the width of
78     a middle line drawn in the QPalette::mid() color.
79 
80     The line appears sunken if \a sunken is true, otherwise raised.
81 
82     \warning This function does not look at QWidget::style() or
83     QApplication::style().  Use the drawing functions in QStyle to
84     make widgets that follow the current GUI style.
85 
86 
87     Alternatively you can use a QFrame widget and apply the
88     QFrame::setFrameStyle() function to display a shaded line:
89 
90     \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 0
91 
92     \sa qDrawShadeRect(), qDrawShadePanel(), QStyle
93 */
94 
qDrawShadeLine(QPainter * p,int x1,int y1,int x2,int y2,const QPalette & pal,bool sunken,int lineWidth,int midLineWidth)95 void qDrawShadeLine(QPainter *p, int x1, int y1, int x2, int y2,
96                      const QPalette &pal, bool sunken,
97                      int lineWidth, int midLineWidth)
98 {
99     if (!(p && lineWidth >= 0 && midLineWidth >= 0))        {
100         qWarning("qDrawShadeLine: Invalid parameters");
101         return;
102     }
103     int tlw = lineWidth*2 + midLineWidth;        // total line width
104     QPen oldPen = p->pen();                        // save pen
105     if (sunken)
106         p->setPen(pal.color(QPalette::Dark));
107     else
108         p->setPen(pal.light().color());
109     QPolygon a;
110     int i;
111     if (y1 == y2) {                                // horizontal line
112         int y = y1 - tlw/2;
113         if (x1 > x2) {                        // swap x1 and x2
114             int t = x1;
115             x1 = x2;
116             x2 = t;
117         }
118         x2--;
119         for (i=0; i<lineWidth; i++) {                // draw top shadow
120             a.setPoints(3, x1+i, y+tlw-1-i,
121                          x1+i, y+i,
122                          x2-i, y+i);
123             p->drawPolyline(a);
124         }
125         if (midLineWidth > 0) {
126             p->setPen(pal.mid().color());
127             for (i=0; i<midLineWidth; i++)        // draw lines in the middle
128                 p->drawLine(x1+lineWidth, y+lineWidth+i,
129                              x2-lineWidth, y+lineWidth+i);
130         }
131         if (sunken)
132             p->setPen(pal.light().color());
133         else
134             p->setPen(pal.dark().color());
135         for (i=0; i<lineWidth; i++) {                // draw bottom shadow
136             a.setPoints(3, x1+i, y+tlw-i-1,
137                          x2-i, y+tlw-i-1,
138                          x2-i, y+i+1);
139             p->drawPolyline(a);
140         }
141     }
142     else if (x1 == x2) {                        // vertical line
143         int x = x1 - tlw/2;
144         if (y1 > y2) {                        // swap y1 and y2
145             int t = y1;
146             y1 = y2;
147             y2 = t;
148         }
149         y2--;
150         for (i=0; i<lineWidth; i++) {                // draw left shadow
151             a.setPoints(3, x+i, y2,
152                          x+i, y1+i,
153                          x+tlw-1, y1+i);
154             p->drawPolyline(a);
155         }
156         if (midLineWidth > 0) {
157             p->setPen(pal.mid().color());
158             for (i=0; i<midLineWidth; i++)        // draw lines in the middle
159                 p->drawLine(x+lineWidth+i, y1+lineWidth, x+lineWidth+i, y2);
160         }
161         if (sunken)
162             p->setPen(pal.light().color());
163         else
164             p->setPen(pal.dark().color());
165         for (i=0; i<lineWidth; i++) {                // draw right shadow
166             a.setPoints(3, x+lineWidth, y2-i,
167                          x+tlw-i-1, y2-i,
168                          x+tlw-i-1, y1+lineWidth);
169             p->drawPolyline(a);
170         }
171     }
172     p->setPen(oldPen);
173 }
174 
175 /*!
176     \fn void qDrawShadeRect(QPainter *painter, int x, int y, int width, int height,
177                      const QPalette &palette, bool sunken,
178                      int lineWidth, int midLineWidth,
179                      const QBrush *fill)
180     \relates <qdrawutil.h>
181 
182     Draws the shaded rectangle beginning at (\a x, \a y) with the
183     given \a width and \a height using the provided \a painter.
184 
185     The provide \a palette specifies the shading colors (\l
186     {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
187     {QPalette::mid()}{middle} colors.  The given \a lineWidth
188     specifies the line width for each of the lines; it is not the
189     total line width.  The \a midLineWidth specifies the width of a
190     middle line drawn in the QPalette::mid() color.  The rectangle's
191     interior is filled with the \a fill brush unless \a fill is 0.
192 
193     The rectangle appears sunken if \a sunken is true, otherwise
194     raised.
195 
196     \warning This function does not look at QWidget::style() or
197     QApplication::style(). Use the drawing functions in QStyle to make
198     widgets that follow the current GUI style.
199 
200     Alternatively you can use a QFrame widget and apply the
201     QFrame::setFrameStyle() function to display a shaded rectangle:
202 
203     \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 1
204 
205     \sa qDrawShadeLine(), qDrawShadePanel(), qDrawPlainRect(), QStyle
206 */
207 
qDrawShadeRect(QPainter * p,int x,int y,int w,int h,const QPalette & pal,bool sunken,int lineWidth,int midLineWidth,const QBrush * fill)208 void qDrawShadeRect(QPainter *p, int x, int y, int w, int h,
209                      const QPalette &pal, bool sunken,
210                      int lineWidth, int midLineWidth,
211                      const QBrush *fill)
212 {
213     if (w == 0 || h == 0)
214         return;
215     if (! (w > 0 && h > 0 && lineWidth >= 0 && midLineWidth >= 0)) {
216         qWarning("qDrawShadeRect: Invalid parameters");
217         return;
218     }
219     QPen oldPen = p->pen();
220     if (sunken)
221         p->setPen(pal.dark().color());
222     else
223         p->setPen(pal.light().color());
224     int x1=x, y1=y, x2=x+w-1, y2=y+h-1;
225 
226     if (lineWidth == 1 && midLineWidth == 0) {// standard shade rectangle
227         p->drawRect(x1, y1, w-2, h-2);
228         if (sunken)
229             p->setPen(pal.light().color());
230         else
231             p->setPen(pal.dark().color());
232         QLineF lines[4] = { QLineF(x1+1, y1+1, x2-2, y1+1),
233                             QLineF(x1+1, y1+2, x1+1, y2-2),
234                             QLineF(x1, y2, x2, y2),
235                             QLineF(x2,y1, x2,y2-1) };
236         p->drawLines(lines, 4);              // draw bottom/right lines
237     } else {                                        // more complicated
238         int m = lineWidth+midLineWidth;
239         int i, j=0, k=m;
240         for (i=0; i<lineWidth; i++) {                // draw top shadow
241             QLineF lines[4] = { QLineF(x1+i, y2-i, x1+i, y1+i),
242                                 QLineF(x1+i, y1+i, x2-i, y1+i),
243                                 QLineF(x1+k, y2-k, x2-k, y2-k),
244                                 QLineF(x2-k, y2-k, x2-k, y1+k) };
245             p->drawLines(lines, 4);
246             k++;
247         }
248         p->setPen(pal.mid().color());
249         j = lineWidth*2;
250         for (i=0; i<midLineWidth; i++) {        // draw lines in the middle
251             p->drawRect(x1+lineWidth+i, y1+lineWidth+i, w-j-1, h-j-1);
252             j += 2;
253         }
254         if (sunken)
255             p->setPen(pal.light().color());
256         else
257             p->setPen(pal.dark().color());
258         k = m;
259         for (i=0; i<lineWidth; i++) {                // draw bottom shadow
260             QLineF lines[4] = { QLineF(x1+1+i, y2-i, x2-i, y2-i),
261                                 QLineF(x2-i, y2-i, x2-i, y1+i+1),
262                                 QLineF(x1+k, y2-k, x1+k, y1+k),
263                                 QLineF(x1+k, y1+k, x2-k, y1+k) };
264             p->drawLines(lines, 4);
265             k++;
266         }
267     }
268     if (fill) {
269         QBrush oldBrush = p->brush();
270         int tlw = lineWidth + midLineWidth;
271         p->setPen(Qt::NoPen);
272         p->setBrush(*fill);
273         p->drawRect(x+tlw, y+tlw, w-2*tlw, h-2*tlw);
274         p->setBrush(oldBrush);
275     }
276     p->setPen(oldPen);                        // restore pen
277 }
278 
279 
280 /*!
281     \fn void qDrawShadePanel(QPainter *painter, int x, int y, int width, int height,
282                       const QPalette &palette, bool sunken,
283                       int lineWidth, const QBrush *fill)
284     \relates <qdrawutil.h>
285 
286     Draws the shaded panel beginning at (\a x, \a y) with the given \a
287     width and \a height using the provided \a painter and the given \a
288     lineWidth.
289 
290     The given \a palette specifies the shading colors (\l
291     {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
292     {QPalette::mid()}{middle} colors).  The panel's interior is filled
293     with the \a fill brush unless \a fill is 0.
294 
295     The panel appears sunken if \a sunken is true, otherwise raised.
296 
297     \warning This function does not look at QWidget::style() or
298     QApplication::style(). Use the drawing functions in QStyle to make
299     widgets that follow the current GUI style.
300 
301     Alternatively you can use a QFrame widget and apply the
302     QFrame::setFrameStyle() function to display a shaded panel:
303 
304     \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 2
305 
306     \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle
307 */
308 
qDrawShadePanel(QPainter * p,int x,int y,int w,int h,const QPalette & pal,bool sunken,int lineWidth,const QBrush * fill)309 void qDrawShadePanel(QPainter *p, int x, int y, int w, int h,
310                       const QPalette &pal, bool sunken,
311                       int lineWidth, const QBrush *fill)
312 {
313     if (w == 0 || h == 0)
314         return;
315     if (!(w > 0 && h > 0 && lineWidth >= 0)) {
316         qWarning("qDrawShadePanel: Invalid parameters");
317     }
318     QColor shade = pal.dark().color();
319     QColor light = pal.light().color();
320     if (fill) {
321         if (fill->color() == shade)
322             shade = pal.shadow().color();
323         if (fill->color() == light)
324             light = pal.midlight().color();
325     }
326     QPen oldPen = p->pen();                        // save pen
327     QVector<QLineF> lines;
328     lines.reserve(2*lineWidth);
329 
330     if (sunken)
331         p->setPen(shade);
332     else
333         p->setPen(light);
334     int x1, y1, x2, y2;
335     int i;
336     x1 = x;
337     y1 = y2 = y;
338     x2 = x+w-2;
339     for (i=0; i<lineWidth; i++) {                // top shadow
340         lines << QLineF(x1, y1++, x2--, y2++);
341     }
342     x2 = x1;
343     y1 = y+h-2;
344     for (i=0; i<lineWidth; i++) {                // left shado
345         lines << QLineF(x1++, y1, x2++, y2--);
346     }
347     p->drawLines(lines);
348     lines.clear();
349     if (sunken)
350         p->setPen(light);
351     else
352         p->setPen(shade);
353     x1 = x;
354     y1 = y2 = y+h-1;
355     x2 = x+w-1;
356     for (i=0; i<lineWidth; i++) {                // bottom shadow
357         lines << QLineF(x1++, y1--, x2, y2--);
358     }
359     x1 = x2;
360     y1 = y;
361     y2 = y+h-lineWidth-1;
362     for (i=0; i<lineWidth; i++) {                // right shadow
363         lines << QLineF(x1--, y1++, x2--, y2);
364     }
365     p->drawLines(lines);
366     if (fill)                                // fill with fill color
367         p->fillRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2, *fill);
368     p->setPen(oldPen);                        // restore pen
369 }
370 
371 
372 /*!
373   \internal
374   This function draws a rectangle with two pixel line width.
375   It is called from qDrawWinButton() and qDrawWinPanel().
376 
377   c1..c4 and fill are used:
378 
379     1 1 1 1 1 2
380     1 3 3 3 4 2
381     1 3 F F 4 2
382     1 3 F F 4 2
383     1 4 4 4 4 2
384     2 2 2 2 2 2
385 */
386 
qDrawWinShades(QPainter * p,int x,int y,int w,int h,const QColor & c1,const QColor & c2,const QColor & c3,const QColor & c4,const QBrush * fill)387 static void qDrawWinShades(QPainter *p,
388                            int x, int y, int w, int h,
389                            const QColor &c1, const QColor &c2,
390                            const QColor &c3, const QColor &c4,
391                            const QBrush *fill)
392 {
393     if (w < 2 || h < 2)                        // can't do anything with that
394         return;
395     QPen oldPen = p->pen();
396     QPoint a[3] = { QPoint(x, y+h-2), QPoint(x, y), QPoint(x+w-2, y) };
397     p->setPen(c1);
398     p->drawPolyline(a, 3);
399     QPoint b[3] = { QPoint(x, y+h-1), QPoint(x+w-1, y+h-1), QPoint(x+w-1, y) };
400     p->setPen(c2);
401     p->drawPolyline(b, 3);
402     if (w > 4 && h > 4) {
403         QPoint c[3] = { QPoint(x+1, y+h-3), QPoint(x+1, y+1), QPoint(x+w-3, y+1) };
404         p->setPen(c3);
405         p->drawPolyline(c, 3);
406         QPoint d[3] = { QPoint(x+1, y+h-2), QPoint(x+w-2, y+h-2), QPoint(x+w-2, y+1) };
407         p->setPen(c4);
408         p->drawPolyline(d, 3);
409         if (fill)
410             p->fillRect(QRect(x+2, y+2, w-4, h-4), *fill);
411     }
412     p->setPen(oldPen);
413 }
414 
415 
416 /*!
417     \fn void qDrawWinButton(QPainter *painter, int x, int y, int width, int height,
418                      const QPalette &palette, bool sunken,
419                      const QBrush *fill)
420     \relates <qdrawutil.h>
421 
422     Draws the Windows-style button specified by the given point (\a x,
423     \a y}, \a width and \a height using the provided \a painter with a
424     line width of 2 pixels. The button's interior is filled with the
425     \a{fill} brush unless \a fill is 0.
426 
427     The given \a palette specifies the shading colors (\l
428     {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
429     {QPalette::mid()}{middle} colors).
430 
431     The button appears sunken if \a sunken is true, otherwise raised.
432 
433     \warning This function does not look at QWidget::style() or
434     QApplication::style()-> Use the drawing functions in QStyle to make
435     widgets that follow the current GUI style.
436 
437     \sa qDrawWinPanel(), QStyle
438 */
439 
qDrawWinButton(QPainter * p,int x,int y,int w,int h,const QPalette & pal,bool sunken,const QBrush * fill)440 void qDrawWinButton(QPainter *p, int x, int y, int w, int h,
441                      const QPalette &pal, bool sunken,
442                      const QBrush *fill)
443 {
444     if (sunken)
445         qDrawWinShades(p, x, y, w, h,
446                        pal.shadow().color(), pal.light().color(), pal.dark().color(),
447                        pal.button().color(), fill);
448     else
449         qDrawWinShades(p, x, y, w, h,
450                        pal.light().color(), pal.shadow().color(), pal.button().color(),
451                        pal.dark().color(), fill);
452 }
453 
454 /*!
455     \fn void qDrawWinPanel(QPainter *painter, int x, int y, int width, int height,
456                     const QPalette &palette, bool        sunken,
457                     const QBrush *fill)
458     \relates <qdrawutil.h>
459 
460     Draws the Windows-style panel specified by the given point(\a x,
461     \a y), \a width and \a height using the provided \a painter with a
462     line width of 2 pixels. The button's interior is filled with the
463     \a fill brush unless \a fill is 0.
464 
465     The given \a palette specifies the shading colors.  The panel
466     appears sunken if \a sunken is true, otherwise raised.
467 
468     \warning This function does not look at QWidget::style() or
469     QApplication::style(). Use the drawing functions in QStyle to make
470     widgets that follow the current GUI style.
471 
472     Alternatively you can use a QFrame widget and apply the
473     QFrame::setFrameStyle() function to display a shaded panel:
474 
475     \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 3
476 
477     \sa qDrawShadePanel(), qDrawWinButton(), QStyle
478 */
479 
qDrawWinPanel(QPainter * p,int x,int y,int w,int h,const QPalette & pal,bool sunken,const QBrush * fill)480 void qDrawWinPanel(QPainter *p, int x, int y, int w, int h,
481                     const QPalette &pal, bool        sunken,
482                     const QBrush *fill)
483 {
484     if (sunken)
485         qDrawWinShades(p, x, y, w, h,
486                         pal.dark().color(), pal.light().color(), pal.shadow().color(),
487                        pal.midlight().color(), fill);
488     else
489         qDrawWinShades(p, x, y, w, h,
490                        pal.light().color(), pal.shadow().color(), pal.midlight().color(),
491                        pal.dark().color(), fill);
492 }
493 
494 /*!
495     \fn void qDrawPlainRect(QPainter *painter, int x, int y, int width, int height, const QColor &lineColor,
496                      int lineWidth, const QBrush *fill)
497     \relates <qdrawutil.h>
498 
499     Draws the plain rectangle beginning at (\a x, \a y) with the given
500     \a width and \a height, using the specified \a painter, \a lineColor
501     and \a lineWidth. The rectangle's interior is filled with the \a
502     fill brush unless \a fill is 0.
503 
504     \warning This function does not look at QWidget::style() or
505     QApplication::style(). Use the drawing functions in QStyle to make
506     widgets that follow the current GUI style.
507 
508     Alternatively you can use a QFrame widget and apply the
509     QFrame::setFrameStyle() function to display a plain rectangle:
510 
511     \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 4
512 
513     \sa qDrawShadeRect(), QStyle
514 */
515 
qDrawPlainRect(QPainter * p,int x,int y,int w,int h,const QColor & c,int lineWidth,const QBrush * fill)516 void qDrawPlainRect(QPainter *p, int x, int y, int w, int h, const QColor &c,
517                      int lineWidth, const QBrush *fill)
518 {
519     if (w == 0 || h == 0)
520         return;
521     if (!(w > 0 && h > 0 && lineWidth >= 0)) {
522         qWarning("qDrawPlainRect: Invalid parameters");
523     }
524     QPen   oldPen   = p->pen();
525     QBrush oldBrush = p->brush();
526     p->setPen(c);
527     p->setBrush(Qt::NoBrush);
528     for (int i=0; i<lineWidth; i++)
529         p->drawRect(x+i, y+i, w-i*2 - 1, h-i*2 - 1);
530     if (fill) {                                // fill with fill color
531         p->setPen(Qt::NoPen);
532         p->setBrush(*fill);
533         p->drawRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2);
534     }
535     p->setPen(oldPen);
536     p->setBrush(oldBrush);
537 }
538 
539 /*****************************************************************************
540   Overloaded functions.
541  *****************************************************************************/
542 
543 /*!
544     \fn void qDrawShadeLine(QPainter *painter, const QPoint &p1, const QPoint &p2,
545              const QPalette &palette, bool sunken, int lineWidth, int midLineWidth)
546     \relates <qdrawutil.h>
547     \overload
548 
549     Draws a horizontal or vertical shaded line between \a p1 and \a p2
550     using the given \a painter.  Note that nothing is drawn if the line
551     between the points would be neither horizontal nor vertical.
552 
553     The provided \a palette specifies the shading colors (\l
554     {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
555     {QPalette::mid()}{middle} colors).  The given \a lineWidth
556     specifies the line width for each of the lines; it is not the
557     total line width. The given \a midLineWidth specifies the width of
558     a middle line drawn in the QPalette::mid() color.
559 
560     The line appears sunken if \a sunken is true, otherwise raised.
561 
562     \warning This function does not look at QWidget::style() or
563     QApplication::style().  Use the drawing functions in QStyle to
564     make widgets that follow the current GUI style.
565 
566 
567     Alternatively you can use a QFrame widget and apply the
568     QFrame::setFrameStyle() function to display a shaded line:
569 
570     \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 5
571 
572     \sa qDrawShadeRect(), qDrawShadePanel(), QStyle
573 */
574 
qDrawShadeLine(QPainter * p,const QPoint & p1,const QPoint & p2,const QPalette & pal,bool sunken,int lineWidth,int midLineWidth)575 void qDrawShadeLine(QPainter *p, const QPoint &p1, const QPoint &p2,
576                      const QPalette &pal, bool sunken,
577                      int lineWidth, int midLineWidth)
578 {
579     qDrawShadeLine(p, p1.x(), p1.y(), p2.x(), p2.y(), pal, sunken,
580                     lineWidth, midLineWidth);
581 }
582 
583 /*!
584     \fn void qDrawShadeRect(QPainter *painter, const QRect &rect, const QPalette &palette,
585              bool sunken, int lineWidth, int midLineWidth, const QBrush *fill)
586     \relates <qdrawutil.h>
587     \overload
588 
589     Draws the shaded rectangle specified by \a rect using the given \a painter.
590 
591     The provide \a palette specifies the shading colors (\l
592     {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
593     {QPalette::mid()}{middle} colors.  The given \a lineWidth
594     specifies the line width for each of the lines; it is not the
595     total line width.  The \a midLineWidth specifies the width of a
596     middle line drawn in the QPalette::mid() color.  The rectangle's
597     interior is filled with the \a fill brush unless \a fill is 0.
598 
599     The rectangle appears sunken if \a sunken is true, otherwise
600     raised.
601 
602     \warning This function does not look at QWidget::style() or
603     QApplication::style(). Use the drawing functions in QStyle to make
604     widgets that follow the current GUI style.
605 
606     Alternatively you can use a QFrame widget and apply the
607     QFrame::setFrameStyle() function to display a shaded rectangle:
608 
609     \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 6
610 
611     \sa qDrawShadeLine(), qDrawShadePanel(), qDrawPlainRect(), QStyle
612 */
613 
qDrawShadeRect(QPainter * p,const QRect & r,const QPalette & pal,bool sunken,int lineWidth,int midLineWidth,const QBrush * fill)614 void qDrawShadeRect(QPainter *p, const QRect &r,
615                      const QPalette &pal, bool sunken,
616                      int lineWidth, int midLineWidth,
617                      const QBrush *fill)
618 {
619     qDrawShadeRect(p, r.x(), r.y(), r.width(), r.height(), pal, sunken,
620                     lineWidth, midLineWidth, fill);
621 }
622 
623 /*!
624     \fn void qDrawShadePanel(QPainter *painter, const QRect &rect, const QPalette &palette,
625              bool sunken, int lineWidth, const QBrush *fill)
626     \relates <qdrawutil.h>
627     \overload
628 
629     Draws the shaded panel at the rectangle specified by \a rect using the
630     given \a painter and the given \a lineWidth.
631 
632     The given \a palette specifies the shading colors (\l
633     {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
634     {QPalette::mid()}{middle} colors).  The panel's interior is filled
635     with the \a fill brush unless \a fill is 0.
636 
637     The panel appears sunken if \a sunken is true, otherwise raised.
638 
639     \warning This function does not look at QWidget::style() or
640     QApplication::style(). Use the drawing functions in QStyle to make
641     widgets that follow the current GUI style.
642 
643     Alternatively you can use a QFrame widget and apply the
644     QFrame::setFrameStyle() function to display a shaded panel:
645 
646     \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 7
647 
648     \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle
649 */
650 
qDrawShadePanel(QPainter * p,const QRect & r,const QPalette & pal,bool sunken,int lineWidth,const QBrush * fill)651 void qDrawShadePanel(QPainter *p, const QRect &r,
652                       const QPalette &pal, bool sunken,
653                       int lineWidth, const QBrush *fill)
654 {
655     qDrawShadePanel(p, r.x(), r.y(), r.width(), r.height(), pal, sunken,
656                      lineWidth, fill);
657 }
658 
659 /*!
660     \fn void qDrawWinButton(QPainter *painter, const QRect &rect, const QPalette &palette,
661              bool sunken, const QBrush *fill)
662     \relates <qdrawutil.h>
663     \overload
664 
665     Draws the Windows-style button at the rectangle specified by \a rect using
666     the given \a painter with a line width of 2 pixels. The button's interior
667     is filled with the \a{fill} brush unless \a fill is 0.
668 
669     The given \a palette specifies the shading colors (\l
670     {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
671     {QPalette::mid()}{middle} colors).
672 
673     The button appears sunken if \a sunken is true, otherwise raised.
674 
675     \warning This function does not look at QWidget::style() or
676     QApplication::style()-> Use the drawing functions in QStyle to make
677     widgets that follow the current GUI style.
678 
679     \sa qDrawWinPanel(), QStyle
680 */
681 
qDrawWinButton(QPainter * p,const QRect & r,const QPalette & pal,bool sunken,const QBrush * fill)682 void qDrawWinButton(QPainter *p, const QRect &r,
683                      const QPalette &pal, bool sunken, const QBrush *fill)
684 {
685     qDrawWinButton(p, r.x(), r.y(), r.width(), r.height(), pal, sunken, fill);
686 }
687 
688 /*!
689     \fn void qDrawWinPanel(QPainter *painter, const QRect &rect, const QPalette &palette,
690              bool sunken, const QBrush *fill)
691     \overload
692 
693     Draws the Windows-style panel at the rectangle specified by \a rect using
694     the given \a painter with a line width of 2 pixels. The button's interior
695     is filled with the \a fill brush unless \a fill is 0.
696 
697     The given \a palette specifies the shading colors.  The panel
698     appears sunken if \a sunken is true, otherwise raised.
699 
700     \warning This function does not look at QWidget::style() or
701     QApplication::style(). Use the drawing functions in QStyle to make
702     widgets that follow the current GUI style.
703 
704     Alternatively you can use a QFrame widget and apply the
705     QFrame::setFrameStyle() function to display a shaded panel:
706 
707     \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 8
708 
709     \sa qDrawShadePanel(), qDrawWinButton(), QStyle
710 */
711 
qDrawWinPanel(QPainter * p,const QRect & r,const QPalette & pal,bool sunken,const QBrush * fill)712 void qDrawWinPanel(QPainter *p, const QRect &r,
713                     const QPalette &pal, bool sunken, const QBrush *fill)
714 {
715     qDrawWinPanel(p, r.x(), r.y(), r.width(), r.height(), pal, sunken, fill);
716 }
717 
718 /*!
719     \fn void qDrawPlainRect(QPainter *painter, const QRect &rect, const QColor &lineColor, int lineWidth, const QBrush *fill)
720     \relates <qdrawutil.h>
721     \overload
722 
723     Draws the plain rectangle specified by \a rect using the given \a painter,
724     \a lineColor and \a lineWidth. The rectangle's interior is filled with the
725     \a fill brush unless \a fill is 0.
726 
727     \warning This function does not look at QWidget::style() or
728     QApplication::style(). Use the drawing functions in QStyle to make
729     widgets that follow the current GUI style.
730 
731     Alternatively you can use a QFrame widget and apply the
732     QFrame::setFrameStyle() function to display a plain rectangle:
733 
734     \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 9
735 
736     \sa qDrawShadeRect(), QStyle
737 */
738 
qDrawPlainRect(QPainter * p,const QRect & r,const QColor & c,int lineWidth,const QBrush * fill)739 void qDrawPlainRect(QPainter *p, const QRect &r, const QColor &c,
740                      int lineWidth, const QBrush *fill)
741 {
742     qDrawPlainRect(p, r.x(), r.y(), r.width(), r.height(), c,
743                     lineWidth, fill);
744 }
745 
746 #ifdef QT3_SUPPORT
qDrawWinArrow(QPainter * p,Qt::ArrowType type,bool down,int x,int y,int w,int h,const QPalette & pal,bool enabled)747 static void qDrawWinArrow(QPainter *p, Qt::ArrowType type, bool down,
748                            int x, int y, int w, int h,
749                            const QPalette &pal, bool enabled)
750 {
751     QPolygon a;                                // arrow polygon
752     switch (type) {
753     case Qt::UpArrow:
754         a.setPoints(7, -3,1, 3,1, -2,0, 2,0, -1,-1, 1,-1, 0,-2);
755         break;
756     case Qt::DownArrow:
757         a.setPoints(7, -3,-1, 3,-1, -2,0, 2,0, -1,1, 1,1, 0,2);
758         break;
759     case Qt::LeftArrow:
760         a.setPoints(7, 1,-3, 1,3, 0,-2, 0,2, -1,-1, -1,1, -2,0);
761         break;
762     case Qt::RightArrow:
763         a.setPoints(7, -1,-3, -1,3, 0,-2, 0,2, 1,-1, 1,1, 2,0);
764         break;
765     default:
766         break;
767     }
768     if (a.isEmpty())
769         return;
770 
771     if (down) {
772         x++;
773         y++;
774     }
775 
776     QPen savePen = p->pen();                        // save current pen
777     if (down)
778         p->setBrushOrigin(p->brushOrigin() + QPoint(1,1));
779     p->fillRect(x, y, w, h, pal.brush(QPalette::Button));
780     if (down)
781         p->setBrushOrigin(p->brushOrigin() - QPoint(1,1));
782     if (enabled) {
783         a.translate(x+w/2, y+h/2);
784         p->setPen(pal.foreground().color());
785         p->drawLine(a.at(0), a.at(1));
786         p->drawLine(a.at(2), a.at(2));
787         p->drawPoint(a[6]);
788     } else {
789         a.translate(x+w/2+1, y+h/2+1);
790         p->setPen(pal.light().color());
791         p->drawLine(a.at(0), a.at(1));
792         p->drawLine(a.at(2), a.at(2));
793         p->drawPoint(a[6]);
794         a.translate(-1, -1);
795         p->setPen(pal.mid().color());
796         p->drawLine(a.at(0), a.at(1));
797         p->drawLine(a.at(2), a.at(2));
798         p->drawPoint(a[6]);
799     }
800     p->setPen(savePen);                        // restore pen
801 }
802 #endif // QT3_SUPPORT
803 
804 #if defined(Q_CC_MSVC)
805 #pragma warning(disable: 4244)
806 #endif
807 
808 #ifdef QT3_SUPPORT
809 #ifndef QT_NO_STYLE_MOTIF
810 // motif arrows look the same whether they are used or not
811 // is this correct?
qDrawMotifArrow(QPainter * p,Qt::ArrowType type,bool down,int x,int y,int w,int h,const QPalette & pal,bool)812 static void qDrawMotifArrow(QPainter *p, Qt::ArrowType type, bool down,
813                              int x, int y, int w, int h,
814                              const QPalette &pal, bool)
815 {
816     QPolygon bFill;                                // fill polygon
817     QPolygon bTop;                                // top shadow.
818     QPolygon bBot;                                // bottom shadow.
819     QPolygon bLeft;                                // left shadow.
820     QTransform matrix;                            // xform matrix
821     bool vertical = type == Qt::UpArrow || type == Qt::DownArrow;
822     bool horizontal = !vertical;
823     int         dim = w < h ? w : h;
824     int         colspec = 0x0000;                        // color specification array
825 
826     if (dim < 2)                                // too small arrow
827         return;
828 
829     if (dim > 3) {
830         if (dim > 6)
831             bFill.resize(dim & 1 ? 3 : 4);
832         bTop.resize((dim/2)*2);
833         bBot.resize(dim & 1 ? dim + 1 : dim);
834         bLeft.resize(dim > 4 ? 4 : 2);
835         bLeft.putPoints(0, 2, 0,0, 0,dim-1);
836         if (dim > 4)
837             bLeft.putPoints(2, 2, 1,2, 1,dim-3);
838         bTop.putPoints(0, 4, 1,0, 1,1, 2,1, 3,1);
839         bBot.putPoints(0, 4, 1,dim-1, 1,dim-2, 2,dim-2, 3,dim-2);
840 
841         for(int i=0; i<dim/2-2 ; i++) {
842             bTop.putPoints(i*2+4, 2, 2+i*2,2+i, 5+i*2, 2+i);
843             bBot.putPoints(i*2+4, 2, 2+i*2,dim-3-i, 5+i*2,dim-3-i);
844         }
845         if (dim & 1)                                // odd number size: extra line
846             bBot.putPoints(dim-1, 2, dim-3,dim/2, dim-1,dim/2);
847         if (dim > 6) {                        // dim>6: must fill interior
848             bFill.putPoints(0, 2, 1,dim-3, 1,2);
849             if (dim & 1)                        // if size is an odd number
850                 bFill.setPoint(2, dim - 3, dim / 2);
851             else
852                 bFill.putPoints(2, 2, dim-4,dim/2-1, dim-4,dim/2);
853         }
854     }
855     else {
856         if (dim == 3) {                        // 3x3 arrow pattern
857             bLeft.setPoints(4, 0,0, 0,2, 1,1, 1,1);
858             bTop .setPoints(2, 1,0, 1,0);
859             bBot .setPoints(2, 1,2, 2,1);
860         }
861         else {                                        // 2x2 arrow pattern
862             bLeft.setPoints(2, 0,0, 0,1);
863             bTop .setPoints(2, 1,0, 1,0);
864             bBot .setPoints(2, 1,1, 1,1);
865         }
866     }
867 
868     if (type == Qt::UpArrow || type == Qt::LeftArrow) {
869         matrix.translate(x, y);
870         if (vertical) {
871             matrix.translate(0, h - 1);
872             matrix.rotate(-90);
873         } else {
874             matrix.translate(w - 1, h - 1);
875             matrix.rotate(180);
876         }
877         if (down)
878             colspec = horizontal ? 0x2334 : 0x2343;
879         else
880             colspec = horizontal ? 0x1443 : 0x1434;
881     }
882     else if (type == Qt::DownArrow || type == Qt::RightArrow) {
883         matrix.translate(x, y);
884         if (vertical) {
885             matrix.translate(w-1, 0);
886             matrix.rotate(90);
887         }
888         if (down)
889             colspec = horizontal ? 0x2443 : 0x2434;
890         else
891             colspec = horizontal ? 0x1334 : 0x1343;
892     }
893 
894     const QColor *cols[5];
895     cols[0] = 0;
896     cols[1] = &pal.button().color();
897     cols[2] = &pal.mid().color();
898     cols[3] = &pal.light().color();
899     cols[4] = &pal.dark().color();
900 #define CMID        *cols[(colspec>>12) & 0xf]
901 #define CLEFT        *cols[(colspec>>8) & 0xf]
902 #define CTOP        *cols[(colspec>>4) & 0xf]
903 #define CBOT        *cols[colspec & 0xf]
904 
905     QPen     savePen   = p->pen();                // save current pen
906     QBrush   saveBrush = p->brush();                // save current brush
907     QTransform wxm = p->transform();
908     QPen     pen(Qt::NoPen);
909     const QBrush &brush = pal.brush(QPalette::Button);
910 
911     p->setPen(pen);
912     p->setBrush(brush);
913     p->setTransform(matrix, true);                // set transformation matrix
914     p->drawPolygon(bFill);                        // fill arrow
915     p->setBrush(Qt::NoBrush);                        // don't fill
916 
917     p->setPen(CLEFT);
918     p->drawLines(bLeft);
919     p->setPen(CTOP);
920     p->drawLines(bTop);
921     p->setPen(CBOT);
922     p->drawLines(bBot);
923 
924     p->setTransform(wxm);
925     p->setBrush(saveBrush);                        // restore brush
926     p->setPen(savePen);                        // restore pen
927 
928 #undef CMID
929 #undef CLEFT
930 #undef CTOP
931 #undef CBOT
932 }
933 #endif // QT_NO_STYLE_MOTIF
934 
qItemRect(QPainter * p,Qt::GUIStyle gs,int x,int y,int w,int h,int flags,bool enabled,const QPixmap * pixmap,const QString & text,int len)935 QRect qItemRect(QPainter *p, Qt::GUIStyle gs,
936                 int x, int y, int w, int h,
937                 int flags,
938                 bool enabled,
939                 const QPixmap *pixmap,
940                 const QString& text, int len)
941 {
942     QRect result;
943 
944     if (pixmap) {
945         if ((flags & Qt::AlignVCenter) == Qt::AlignVCenter)
946             y += h/2 - pixmap->height()/2;
947         else if ((flags & Qt::AlignBottom) == Qt::AlignBottom)
948             y += h - pixmap->height();
949         if ((flags & Qt::AlignRight) == Qt::AlignRight)
950             x += w - pixmap->width();
951         else if ((flags & Qt::AlignHCenter) == Qt::AlignHCenter)
952             x += w/2 - pixmap->width()/2;
953         else if ((flags & Qt::AlignLeft) != Qt::AlignLeft && QApplication::isRightToLeft())
954             x += w - pixmap->width();
955         result = QRect(x, y, pixmap->width(), pixmap->height());
956     } else if (!text.isNull() && p) {
957         result = p->boundingRect(QRect(x, y, w, h), flags, text.left(len));
958         if (gs == Qt::WindowsStyle && !enabled) {
959             result.setWidth(result.width()+1);
960             result.setHeight(result.height()+1);
961         }
962     } else {
963         result = QRect(x, y, w, h);
964     }
965 
966     return result;
967 }
968 
qDrawArrow(QPainter * p,Qt::ArrowType type,Qt::GUIStyle style,bool down,int x,int y,int w,int h,const QPalette & pal,bool enabled)969 void qDrawArrow(QPainter *p, Qt::ArrowType type, Qt::GUIStyle style, bool down,
970                  int x, int y, int w, int h,
971                  const QPalette &pal, bool enabled)
972 {
973     switch (style) {
974         case Qt::WindowsStyle:
975             qDrawWinArrow(p, type, down, x, y, w, h, pal, enabled);
976             break;
977 #ifndef QT_NO_STYLE_MOTIF
978         case Qt::MotifStyle:
979             qDrawMotifArrow(p, type, down, x, y, w, h, pal, enabled);
980             break;
981 #endif
982         default:
983             qWarning("qDrawArrow: Requested unsupported GUI style");
984     }
985 }
986 
qDrawItem(QPainter * p,Qt::GUIStyle gs,int x,int y,int w,int h,int flags,const QPalette & pal,bool enabled,const QPixmap * pixmap,const QString & text,int len,const QColor * penColor)987 void qDrawItem(QPainter *p, Qt::GUIStyle gs,
988                 int x, int y, int w, int h,
989                 int flags,
990                 const QPalette &pal, bool enabled,
991                 const QPixmap *pixmap,
992                 const QString& text, int len , const QColor* penColor)
993 {
994     p->setPen(penColor?*penColor:pal.foreground().color());
995     if (pixmap) {
996         QPixmap  pm(*pixmap);
997         bool clip = (flags & Qt::TextDontClip) == 0;
998         if (clip) {
999             if (pm.width() < w && pm.height() < h)
1000                 clip = false;
1001             else
1002                 p->setClipRect(x, y, w, h);
1003         }
1004         if ((flags & Qt::AlignVCenter) == Qt::AlignVCenter)
1005             y += h/2 - pm.height()/2;
1006         else if ((flags & Qt::AlignBottom) == Qt::AlignBottom)
1007             y += h - pm.height();
1008         if ((flags & Qt::AlignRight) == Qt::AlignRight)
1009             x += w - pm.width();
1010         else if ((flags & Qt::AlignHCenter) == Qt::AlignHCenter)
1011             x += w/2 - pm.width()/2;
1012         else if (((flags & Qt::AlignLeft) != Qt::AlignLeft) && QApplication::isRightToLeft()) // Qt::AlignAuto && rightToLeft
1013             x += w - pm.width();
1014 
1015         if (!enabled) {
1016             if (pm.hasAlphaChannel()) {                        // pixmap with a mask
1017                 pm = pm.mask();
1018             } else if (pm.depth() == 1) {        // monochrome pixmap, no mask
1019                 ;
1020 #ifndef QT_NO_IMAGE_HEURISTIC_MASK
1021             } else {                                // color pixmap, no mask
1022                 QString k = QLatin1Literal("$qt-drawitem")
1023                               % HexString<qint64>(pm.cacheKey());
1024 
1025                 if (!QPixmapCache::find(k, pm)) {
1026                     pm = pm.createHeuristicMask();
1027                     pm.setMask((QBitmap&)pm);
1028                     QPixmapCache::insert(k, pm);
1029                 }
1030 #endif
1031             }
1032             if (gs == Qt::WindowsStyle) {
1033                 p->setPen(pal.light().color());
1034                 p->drawPixmap(x+1, y+1, pm);
1035                 p->setPen(pal.text().color());
1036             }
1037         }
1038         p->drawPixmap(x, y, pm);
1039         if (clip)
1040             p->setClipping(false);
1041     } else if (!text.isNull()) {
1042         if (gs == Qt::WindowsStyle && !enabled) {
1043             p->setPen(pal.light().color());
1044             p->drawText(x+1, y+1, w, h, flags, text.left(len));
1045             p->setPen(pal.text().color());
1046         }
1047         p->drawText(x, y, w, h, flags, text.left(len));
1048     }
1049 }
1050 
1051 #endif
1052 
1053 /*!
1054     \class QTileRules
1055     \since 4.6
1056 
1057     Holds the rules used to draw a pixmap or image split into nine segments,
1058     similar to \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}.
1059 
1060     \sa Qt::TileRule, QMargins
1061 */
1062 
1063 /*! \fn QTileRules::QTileRules(Qt::TileRule horizontalRule, Qt::TileRule verticalRule)
1064   Constructs a QTileRules with the given \a horizontalRule and
1065   \a verticalRule.
1066  */
1067 
1068 /*! \fn QTileRules::QTileRules(Qt::TileRule rule)
1069   Constructs a QTileRules with the given \a rule used for both
1070   the horizontal rule and the vertical rule.
1071  */
1072 
1073 /*!
1074     \fn void qDrawBorderPixmap(QPainter *painter, const QRect &target, const QMargins &margins, const QPixmap &pixmap)
1075     \relates <qdrawutil.h>
1076     \since 4.6
1077     \overload
1078 
1079     \brief The qDrawBorderPixmap function is for drawing a pixmap into
1080     the margins of a rectangle.
1081 
1082     Draws the given \a pixmap into the given \a target rectangle, using the
1083     given \a painter. The pixmap will be split into nine segments and drawn
1084     according to the \a margins structure.
1085 */
1086 
1087 typedef QVarLengthArray<QRectF, 16> QRectFArray;
1088 
1089 /*!
1090     \since 4.6
1091 
1092     Draws the indicated \a sourceRect rectangle from the given \a pixmap into
1093     the given \a targetRect rectangle, using the given \a painter. The pixmap
1094     will be split into nine segments according to the given \a targetMargins
1095     and \a sourceMargins structures. Finally, the pixmap will be drawn
1096     according to the given \a rules.
1097 
1098     This function is used to draw a scaled pixmap, similar to
1099     \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}
1100 
1101     \sa Qt::TileRule, QTileRules, QMargins
1102 */
1103 
qDrawBorderPixmap(QPainter * painter,const QRect & targetRect,const QMargins & targetMargins,const QPixmap & pixmap,const QRect & sourceRect,const QMargins & sourceMargins,const QTileRules & rules,QDrawBorderPixmap::DrawingHints hints)1104 void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargins &targetMargins,
1105                        const QPixmap &pixmap, const QRect &sourceRect,const QMargins &sourceMargins,
1106                        const QTileRules &rules, QDrawBorderPixmap::DrawingHints hints)
1107 {
1108     if (!painter->isActive()) {
1109         qWarning("qDrawBorderPixmap: Painter not active");
1110         return;
1111     }
1112 
1113     QRectFArray sourceData[2];
1114     QRectFArray targetData[2];
1115 
1116     // source center
1117     const int sourceCenterTop = sourceRect.top() + sourceMargins.top();
1118     const int sourceCenterLeft = sourceRect.left() + sourceMargins.left();
1119     const int sourceCenterBottom = sourceRect.bottom() - sourceMargins.bottom() + 1;
1120     const int sourceCenterRight = sourceRect.right() - sourceMargins.right() + 1;
1121     const int sourceCenterWidth = sourceCenterRight - sourceCenterLeft;
1122     const int sourceCenterHeight = sourceCenterBottom - sourceCenterTop;
1123     // target center
1124     const int targetCenterTop = targetRect.top() + targetMargins.top();
1125     const int targetCenterLeft = targetRect.left() + targetMargins.left();
1126     const int targetCenterBottom = targetRect.bottom() - targetMargins.bottom() + 1;
1127     const int targetCenterRight = targetRect.right() - targetMargins.right() + 1;
1128     const int targetCenterWidth = targetCenterRight - targetCenterLeft;
1129     const int targetCenterHeight = targetCenterBottom - targetCenterTop;
1130 
1131     QVarLengthArray<qreal, 16> xTarget; // x-coordinates of target rectangles
1132     QVarLengthArray<qreal, 16> yTarget; // y-coordinates of target rectangles
1133 
1134     int columns = 3;
1135     int rows = 3;
1136     if (rules.horizontal != Qt::StretchTile && sourceCenterWidth != 0)
1137         columns = qMax(3, 2 + qCeil(targetCenterWidth / qreal(sourceCenterWidth)));
1138     if (rules.vertical != Qt::StretchTile && sourceCenterHeight != 0)
1139         rows = qMax(3, 2 + qCeil(targetCenterHeight / qreal(sourceCenterHeight)));
1140 
1141     xTarget.resize(columns + 1);
1142     yTarget.resize(rows + 1);
1143 
1144     bool oldAA = painter->testRenderHint(QPainter::Antialiasing);
1145     if (painter->paintEngine()->type() != QPaintEngine::OpenGL
1146         && painter->paintEngine()->type() != QPaintEngine::OpenGL2
1147         && oldAA && painter->combinedTransform().type() != QTransform::TxNone) {
1148         painter->setRenderHint(QPainter::Antialiasing, false);
1149     }
1150 
1151     xTarget[0] = targetRect.left();
1152     xTarget[1] = targetCenterLeft;
1153     xTarget[columns - 1] = targetCenterRight;
1154     xTarget[columns] = targetRect.left() + targetRect.width();
1155 
1156     yTarget[0] = targetRect.top();
1157     yTarget[1] = targetCenterTop;
1158     yTarget[rows - 1] = targetCenterBottom;
1159     yTarget[rows] = targetRect.top() + targetRect.height();
1160 
1161     qreal dx = targetCenterWidth;
1162     qreal dy = targetCenterHeight;
1163 
1164     switch (rules.horizontal) {
1165     case Qt::StretchTile:
1166         dx = targetCenterWidth;
1167         break;
1168     case Qt::RepeatTile:
1169         dx = sourceCenterWidth;
1170         break;
1171     case Qt::RoundTile:
1172         dx = targetCenterWidth / qreal(columns - 2);
1173         break;
1174     }
1175 
1176     for (int i = 2; i < columns - 1; ++i)
1177         xTarget[i] = xTarget[i - 1] + dx;
1178 
1179     switch (rules.vertical) {
1180     case Qt::StretchTile:
1181         dy = targetCenterHeight;
1182         break;
1183     case Qt::RepeatTile:
1184         dy = sourceCenterHeight;
1185         break;
1186     case Qt::RoundTile:
1187         dy = targetCenterHeight / qreal(rows - 2);
1188         break;
1189     }
1190 
1191     for (int i = 2; i < rows - 1; ++i)
1192         yTarget[i] = yTarget[i - 1] + dy;
1193 
1194     // corners
1195     if (targetMargins.top() > 0 && targetMargins.left() > 0 && sourceMargins.top() > 0 && sourceMargins.left() > 0) { // top left
1196         int index = bool(hints & QDrawBorderPixmap::OpaqueTopLeft);
1197         sourceData[index].append(QRectF(sourceRect.topLeft(), QSizeF(sourceMargins.left(), sourceMargins.top())));
1198         targetData[index].append(QRectF(QPointF(xTarget[0], yTarget[0]), QPointF(xTarget[1], yTarget[1])));
1199     }
1200     if (targetMargins.top() > 0 && targetMargins.right() > 0 && sourceMargins.top() > 0 && sourceMargins.right() > 0) { // top right
1201         int index = bool(hints & QDrawBorderPixmap::OpaqueTopRight);
1202         sourceData[index].append(QRectF(QPointF(sourceCenterRight, sourceRect.top()), QSizeF(sourceMargins.right(), sourceMargins.top())));
1203         targetData[index].append(QRectF(QPointF(xTarget[columns-1], yTarget[0]), QPointF(xTarget[columns], yTarget[1])));
1204     }
1205     if (targetMargins.bottom() > 0 && targetMargins.left() > 0 && sourceMargins.bottom() > 0 && sourceMargins.left() > 0) { // bottom left
1206         int index = bool(hints & QDrawBorderPixmap::OpaqueBottomLeft);
1207         sourceData[index].append(QRectF(QPointF(sourceRect.left(), sourceCenterBottom), QSizeF(sourceMargins.left(), sourceMargins.bottom())));
1208         targetData[index].append(QRectF(QPointF(xTarget[0], yTarget[rows - 1]), QPointF(xTarget[1], yTarget[rows])));
1209     }
1210     if (targetMargins.bottom() > 0 && targetMargins.right() > 0 && sourceMargins.bottom() > 0 && sourceMargins.right() > 0) { // bottom right
1211         int index = bool(hints & QDrawBorderPixmap::OpaqueBottomRight);
1212         sourceData[index].append(QRectF(QPointF(sourceCenterRight, sourceCenterBottom), QSizeF(sourceMargins.right(), sourceMargins.bottom())));
1213         targetData[index].append(QRectF(QPointF(xTarget[columns - 1], yTarget[rows - 1]), QPointF(xTarget[columns], yTarget[rows])));
1214     }
1215 
1216     // horizontal edges
1217     if (targetCenterWidth > 0 && sourceCenterWidth > 0) {
1218         if (targetMargins.top() > 0 && sourceMargins.top() > 0) { // top
1219             int index = bool(hints & QDrawBorderPixmap::OpaqueTop);
1220             for (int i = 1; i < columns - 1; ++i) {
1221                 if (rules.horizontal == Qt::RepeatTile && i == columns - 2) {
1222                     sourceData[index].append(QRectF(QPointF(sourceCenterLeft, sourceRect.top()), QSizeF(xTarget[i + 1] - xTarget[i], sourceMargins.top())));
1223                 } else {
1224                     sourceData[index].append(QRectF(QPointF(sourceCenterLeft, sourceRect.top()), QSizeF(sourceCenterWidth, sourceMargins.top())));
1225                 }
1226                 targetData[index].append(QRectF(QPointF(xTarget[i], yTarget[0]), QPointF(xTarget[i + 1], yTarget[1])));
1227             }
1228         }
1229         if (targetMargins.bottom() > 0 && sourceMargins.bottom() > 0) { // bottom
1230             int index = bool(hints & QDrawBorderPixmap::OpaqueBottom);
1231             for (int i = 1; i < columns - 1; ++i) {
1232                 if (rules.horizontal == Qt::RepeatTile && i == columns - 2) {
1233                     sourceData[index].append(QRectF(QPointF(sourceCenterLeft, sourceCenterBottom), QSizeF(xTarget[i + 1] - xTarget[i], sourceMargins.bottom())));
1234                 } else {
1235                     sourceData[index].append(QRectF(QPointF(sourceCenterLeft, sourceCenterBottom), QSizeF(sourceCenterWidth, sourceMargins.bottom())));
1236                 }
1237                 targetData[index].append(QRectF(QPointF(xTarget[i], yTarget[rows - 1]), QPointF(xTarget[i + 1], yTarget[rows])));
1238             }
1239         }
1240     }
1241 
1242     // vertical edges
1243     if (targetCenterHeight > 0 && sourceCenterHeight > 0) {
1244         if (targetMargins.left() > 0 && sourceMargins.left() > 0) { // left
1245             int index = bool(hints & QDrawBorderPixmap::OpaqueLeft);
1246             for (int i = 1; i < rows - 1; ++i) {
1247                 if (rules.vertical == Qt::RepeatTile && i == rows - 2) {
1248                     sourceData[index].append(QRectF(QPointF(sourceRect.left(), sourceCenterTop), QSizeF(sourceMargins.left(), yTarget[i + 1] - yTarget[i])));
1249                 } else {
1250                     sourceData[index].append(QRectF(QPointF(sourceRect.left(), sourceCenterTop), QSizeF(sourceMargins.left(), sourceCenterHeight)));
1251                 }
1252                 targetData[index].append(QRectF(QPointF(xTarget[0], yTarget[i]), QPointF(xTarget[1], yTarget[i + 1])));
1253             }
1254         }
1255         if (targetMargins.right() > 0 && sourceMargins.right() > 0) { // right
1256             int index = bool(hints & QDrawBorderPixmap::OpaqueRight);
1257             for (int i = 1; i < rows - 1; ++i) {
1258                 if (rules.vertical == Qt::RepeatTile && i == rows - 2) {
1259                     sourceData[index].append(QRectF(QPointF(sourceCenterRight, sourceCenterTop), QSizeF(sourceMargins.right(), yTarget[i + 1] - yTarget[i])));
1260                 } else {
1261                     sourceData[index].append(QRectF(QPointF(sourceCenterRight, sourceCenterTop), QSizeF(sourceMargins.right(), sourceCenterHeight)));
1262                 }
1263                 targetData[index].append(QRectF(QPointF(xTarget[columns - 1], yTarget[i]), QPointF(xTarget[columns], yTarget[i + 1])));
1264             }
1265         }
1266     }
1267 
1268     // center
1269     if (targetCenterWidth > 0 && targetCenterHeight > 0 && sourceCenterWidth > 0 && sourceCenterHeight > 0) {
1270         int index = bool(hints & QDrawBorderPixmap::OpaqueCenter);
1271         for (int j = 1; j < rows - 1; ++j) {
1272             qreal sourceHeight = (rules.vertical == Qt::RepeatTile && j == rows - 2) ? yTarget[j + 1] - yTarget[j] : sourceCenterHeight;
1273             for (int i = 1; i < columns - 1; ++i) {
1274                 qreal sourceWidth = (rules.horizontal == Qt::RepeatTile && i == columns - 2) ? xTarget[i + 1] - xTarget[i] : sourceCenterWidth;
1275                 sourceData[index].append(QRectF(QPointF(sourceCenterLeft, sourceCenterTop), QSizeF(sourceWidth, sourceHeight)));
1276                 targetData[index].append(QRectF(QPointF(xTarget[i], yTarget[j]), QPointF(xTarget[i + 1], yTarget[j + 1])));
1277             }
1278         }
1279     }
1280 
1281     for (int i = 0; i < 2; ++i) {
1282         if (sourceData[i].size())
1283             painter->drawPixmapFragments(targetData[i].data(), sourceData[i].data(), sourceData[i].size(), pixmap, i == 1 ? QPainter::OpaqueHint : QPainter::PixmapFragmentHint(0));
1284     }
1285 
1286     if (oldAA)
1287         painter->setRenderHint(QPainter::Antialiasing, true);
1288 }
1289 
1290 QT_END_NAMESPACE
1291