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