src/gui/painting/qcssutil.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qcssutil_p.h"
       
    43 #include "private/qcssparser_p.h"
       
    44 #include "qpainter.h"
       
    45 #include <qmath.h>
       
    46 
       
    47 #ifndef QT_NO_CSSPARSER
       
    48 
       
    49 QT_BEGIN_NAMESPACE
       
    50 
       
    51 using namespace QCss;
       
    52 
       
    53 static QPen qPenFromStyle(const QBrush& b, qreal width, BorderStyle s)
       
    54 {
       
    55     Qt::PenStyle ps = Qt::NoPen;
       
    56 
       
    57     switch (s) {
       
    58     case BorderStyle_Dotted:
       
    59         ps  = Qt::DotLine;
       
    60         break;
       
    61     case BorderStyle_Dashed:
       
    62         ps = width == 1 ? Qt::DotLine : Qt::DashLine;
       
    63         break;
       
    64     case BorderStyle_DotDash:
       
    65         ps = Qt::DashDotLine;
       
    66         break;
       
    67     case BorderStyle_DotDotDash:
       
    68         ps = Qt::DashDotDotLine;
       
    69         break;
       
    70     case BorderStyle_Inset:
       
    71     case BorderStyle_Outset:
       
    72     case BorderStyle_Solid:
       
    73         ps = Qt::SolidLine;
       
    74         break;
       
    75     default:
       
    76         break;
       
    77     }
       
    78 
       
    79     return QPen(b, width, ps, Qt::FlatCap);
       
    80 }
       
    81 
       
    82 void qDrawRoundedCorners(QPainter *p, qreal x1, qreal y1, qreal x2, qreal y2,
       
    83                          const QSizeF& r1, const QSizeF& r2,
       
    84                          Edge edge, BorderStyle s, QBrush c)
       
    85 {
       
    86     const qreal pw = (edge == TopEdge || edge == BottomEdge) ? y2-y1 : x2-x1;
       
    87     if (s == BorderStyle_Double) {
       
    88         qreal wby3 = pw/3;
       
    89         switch (edge) {
       
    90         case TopEdge:
       
    91         case BottomEdge:
       
    92             qDrawRoundedCorners(p, x1, y1, x2, y1+wby3, r1, r2, edge, BorderStyle_Solid, c);
       
    93             qDrawRoundedCorners(p, x1, y2-wby3, x2, y2, r1, r2, edge, BorderStyle_Solid, c);
       
    94             break;
       
    95         case LeftEdge:
       
    96             qDrawRoundedCorners(p, x1, y1+1, x1+wby3, y2, r1, r2, LeftEdge, BorderStyle_Solid, c);
       
    97             qDrawRoundedCorners(p, x2-wby3, y1+1, x2, y2, r1, r2, LeftEdge, BorderStyle_Solid, c);
       
    98             break;
       
    99         case RightEdge:
       
   100             qDrawRoundedCorners(p, x1, y1+1, x1+wby3, y2, r1, r2, RightEdge, BorderStyle_Solid, c);
       
   101             qDrawRoundedCorners(p, x2-wby3, y1+1, x2, y2, r1, r2, RightEdge, BorderStyle_Solid, c);
       
   102             break;
       
   103         default:
       
   104             break;
       
   105         }
       
   106         return;
       
   107     } else if (s == BorderStyle_Ridge || s == BorderStyle_Groove) {
       
   108         BorderStyle s1, s2;
       
   109         if (s == BorderStyle_Groove) {
       
   110             s1 = BorderStyle_Inset;
       
   111             s2 = BorderStyle_Outset;
       
   112         } else {
       
   113             s1 = BorderStyle_Outset;
       
   114             s2 = BorderStyle_Inset;
       
   115         }
       
   116         int pwby2 = qRound(pw/2);
       
   117         switch (edge) {
       
   118         case TopEdge:
       
   119             qDrawRoundedCorners(p, x1, y1, x2, y1 + pwby2, r1, r2, TopEdge, s1, c);
       
   120             qDrawRoundedCorners(p, x1, y1 + pwby2, x2, y2, r1, r2, TopEdge, s2, c);
       
   121             break;
       
   122         case BottomEdge:
       
   123             qDrawRoundedCorners(p, x1, y1 + pwby2, x2, y2, r1, r2, BottomEdge, s1, c);
       
   124             qDrawRoundedCorners(p, x1, y1, x2, y2-pwby2, r1, r2, BottomEdge, s2, c);
       
   125             break;
       
   126         case LeftEdge:
       
   127             qDrawRoundedCorners(p, x1, y1, x1 + pwby2, y2, r1, r2, LeftEdge, s1, c);
       
   128             qDrawRoundedCorners(p, x1 + pwby2, y1, x2, y2, r1, r2, LeftEdge, s2, c);
       
   129             break;
       
   130         case RightEdge:
       
   131             qDrawRoundedCorners(p, x1 + pwby2, y1, x2, y2, r1, r2, RightEdge, s1, c);
       
   132             qDrawRoundedCorners(p, x1, y1, x2 - pwby2, y2, r1, r2, RightEdge, s2, c);
       
   133             break;
       
   134         default:
       
   135             break;
       
   136         }
       
   137     } else if ((s == BorderStyle_Outset && (edge == TopEdge || edge == LeftEdge))
       
   138             || (s == BorderStyle_Inset && (edge == BottomEdge || edge == RightEdge)))
       
   139             c = c.color().lighter();
       
   140 
       
   141     p->save();
       
   142     qreal pwby2 = pw/2;
       
   143     p->setBrush(Qt::NoBrush);
       
   144     QPen pen = qPenFromStyle(c, pw, s);
       
   145     pen.setCapStyle(Qt::SquareCap); // this eliminates the offby1 errors that we might hit below
       
   146     p->setPen(pen);
       
   147     switch (edge) {
       
   148     case TopEdge:
       
   149         if (!r1.isEmpty())
       
   150             p->drawArc(QRectF(x1 - r1.width() + pwby2, y1 + pwby2,
       
   151                               2*r1.width() - pw, 2*r1.height() - pw), 135*16, -45*16);
       
   152         if (!r2.isEmpty())
       
   153             p->drawArc(QRectF(x2 - r2.width() + pwby2, y1 + pwby2,
       
   154                        2*r2.width() - pw, 2*r2.height() - pw), 45*16, 45*16);
       
   155         break;
       
   156     case BottomEdge:
       
   157         if (!r1.isEmpty())
       
   158             p->drawArc(QRectF(x1 - r1.width() + pwby2, y2 - 2*r1.height() + pwby2,
       
   159                               2*r1.width() - pw, 2*r1.height() - pw), -90 * 16, -45 * 16);
       
   160         if (!r2.isEmpty())
       
   161             p->drawArc(QRectF(x2 - r2.width() + pwby2, y2 - 2*r2.height() + pwby2,
       
   162                        2*r2.width() - pw, 2*r2.height() - pw), -90 * 16, 45 * 16);
       
   163         break;
       
   164     case LeftEdge:
       
   165         if (!r1.isEmpty())
       
   166             p->drawArc(QRectF(x1 + pwby2, y1 - r1.height() + pwby2,
       
   167                        2*r1.width() - pw, 2*r1.height() - pw), 135*16, 45*16);
       
   168         if (!r2.isEmpty())
       
   169             p->drawArc(QRectF(x1 + pwby2, y2 - r2.height() + pwby2,
       
   170                        2*r2.width() - pw, 2*r2.height() - pw), 180*16, 45*16);
       
   171         break;
       
   172     case RightEdge:
       
   173         if (!r1.isEmpty())
       
   174             p->drawArc(QRectF(x2 - 2*r1.width() + pwby2, y1 - r1.height() + pwby2,
       
   175                        2*r1.width() - pw, 2*r1.height() - pw), 45*16, -45*16);
       
   176         if (!r2.isEmpty())
       
   177             p->drawArc(QRectF(x2 - 2*r2.width() + pwby2, y2 - r2.height() + pwby2,
       
   178                        2*r2.width() - pw, 2*r2.height() - pw), 315*16, 45*16);
       
   179         break;
       
   180     default:
       
   181         break;
       
   182     }
       
   183     p->restore();
       
   184 }
       
   185 
       
   186 
       
   187 void qDrawEdge(QPainter *p, qreal x1, qreal y1, qreal x2, qreal y2, qreal dw1, qreal dw2,
       
   188                QCss::Edge edge, QCss::BorderStyle style, QBrush c)
       
   189 {
       
   190     p->save();
       
   191     const qreal width = (edge == TopEdge || edge == BottomEdge) ? (y2-y1) : (x2-x1);
       
   192 
       
   193     if (width <= 2 && style == BorderStyle_Double)
       
   194         style = BorderStyle_Solid;
       
   195 
       
   196     switch (style) {
       
   197     case BorderStyle_Inset:
       
   198     case BorderStyle_Outset:
       
   199         if ((style == BorderStyle_Outset && (edge == TopEdge || edge == LeftEdge))
       
   200             || (style == BorderStyle_Inset && (edge == BottomEdge || edge == RightEdge)))
       
   201             c = c.color().lighter();
       
   202         // fall through!
       
   203     case BorderStyle_Solid: {
       
   204         p->setPen(Qt::NoPen);
       
   205         p->setBrush(c);
       
   206         if (width == 1 || (dw1 == 0 && dw2 == 0)) {
       
   207             p->drawRect(QRectF(x1, y1, x2-x1, y2-y1));
       
   208         } else { // draw trapezoid
       
   209             QPolygonF quad;
       
   210             switch (edge) {
       
   211             case TopEdge:
       
   212                 quad << QPointF(x1, y1) << QPointF(x1 + dw1, y2)
       
   213                      << QPointF(x2 - dw2, y2) << QPointF(x2, y1);
       
   214                 break;
       
   215             case BottomEdge:
       
   216                 quad << QPointF(x1 + dw1, y1) << QPointF(x1, y2)
       
   217                      << QPointF(x2, y2) << QPointF(x2 - dw2, y1);
       
   218                 break;
       
   219             case LeftEdge:
       
   220                 quad << QPointF(x1, y1) << QPointF(x1, y2)
       
   221                      << QPointF(x2, y2 - dw2) << QPointF(x2, y1 + dw1);
       
   222                 break;
       
   223             case RightEdge:
       
   224                 quad << QPointF(x1, y1 + dw1) << QPointF(x1, y2 - dw2)
       
   225                      << QPointF(x2, y2) << QPointF(x2, y1);
       
   226                 break;
       
   227             default:
       
   228                 break;
       
   229             }
       
   230             p->drawConvexPolygon(quad);
       
   231         }
       
   232         break;
       
   233     }
       
   234     case BorderStyle_Dotted:
       
   235     case BorderStyle_Dashed:
       
   236     case BorderStyle_DotDash:
       
   237     case BorderStyle_DotDotDash:
       
   238         p->setPen(qPenFromStyle(c, width, style));
       
   239         if (width == 1)
       
   240             p->drawLine(QLineF(x1, y1, x2 - 1, y2 - 1));
       
   241         else if (edge == TopEdge || edge == BottomEdge)
       
   242             p->drawLine(QLineF(x1 + width/2, (y1 + y2)/2, x2 - width/2, (y1 + y2)/2));
       
   243         else
       
   244             p->drawLine(QLineF((x1+x2)/2, y1 + width/2, (x1+x2)/2, y2 - width/2));
       
   245         break;
       
   246 
       
   247     case BorderStyle_Double: {
       
   248         int wby3 = qRound(width/3);
       
   249         int dw1by3 = qRound(dw1/3);
       
   250         int dw2by3 = qRound(dw2/3);
       
   251         switch (edge) {
       
   252         case TopEdge:
       
   253             qDrawEdge(p, x1, y1, x2, y1 + wby3, dw1by3, dw2by3, TopEdge, BorderStyle_Solid, c);
       
   254             qDrawEdge(p, x1 + dw1 - dw1by3, y2 - wby3, x2 - dw2 + dw1by3, y2,
       
   255                       dw1by3, dw2by3, TopEdge, BorderStyle_Solid, c);
       
   256             break;
       
   257         case LeftEdge:
       
   258             qDrawEdge(p, x1, y1, x1 + wby3, y2, dw1by3, dw2by3, LeftEdge, BorderStyle_Solid, c);
       
   259             qDrawEdge(p, x2 - wby3, y1 + dw1 - dw1by3, x2, y2 - dw2 + dw2by3, dw1by3, dw2by3,
       
   260                       LeftEdge, BorderStyle_Solid, c);
       
   261             break;
       
   262         case BottomEdge:
       
   263             qDrawEdge(p, x1 + dw1 - dw1by3, y1, x2 - dw2 + dw2by3, y1 + wby3, dw1by3, dw2by3,
       
   264                       BottomEdge, BorderStyle_Solid, c);
       
   265             qDrawEdge(p, x1, y2 - wby3, x2, y2, dw1by3, dw2by3, BottomEdge, BorderStyle_Solid, c);
       
   266             break;
       
   267         case RightEdge:
       
   268             qDrawEdge(p, x2 - wby3, y1, x2, y2, dw1by3, dw2by3, RightEdge, BorderStyle_Solid, c);
       
   269             qDrawEdge(p, x1, y1 + dw1 - dw1by3, x1 + wby3, y2 - dw2 + dw2by3, dw1by3, dw2by3,
       
   270                       RightEdge, BorderStyle_Solid, c);
       
   271             break;
       
   272         default:
       
   273             break;
       
   274         }
       
   275         break;
       
   276     }
       
   277     case BorderStyle_Ridge:
       
   278     case BorderStyle_Groove: {
       
   279         BorderStyle s1, s2;
       
   280         if (style == BorderStyle_Groove) {
       
   281             s1 = BorderStyle_Inset;
       
   282             s2 = BorderStyle_Outset;
       
   283         } else {
       
   284             s1 = BorderStyle_Outset;
       
   285             s2 = BorderStyle_Inset;
       
   286         }
       
   287         int dw1by2 = qFloor(dw1/2), dw2by2 = qFloor(dw2/2);
       
   288         int wby2 = qRound(width/2);
       
   289         switch (edge) {
       
   290         case TopEdge:
       
   291             qDrawEdge(p, x1, y1, x2, y1 + wby2, dw1by2, dw2by2, TopEdge, s1, c);
       
   292             qDrawEdge(p, x1 + dw1by2, y1 + wby2, x2 - dw2by2, y2, dw1by2, dw2by2, TopEdge, s2, c);
       
   293             break;
       
   294         case BottomEdge:
       
   295             qDrawEdge(p, x1, y1 + wby2, x2, y2, dw1by2, dw2by2, BottomEdge, s1, c);
       
   296             qDrawEdge(p, x1 + dw1by2, y1, x2 - dw2by2, y1 + wby2, dw1by2, dw2by2, BottomEdge, s2, c);
       
   297             break;
       
   298         case LeftEdge:
       
   299             qDrawEdge(p, x1, y1, x1 + wby2, y2, dw1by2, dw2by2, LeftEdge, s1, c);
       
   300             qDrawEdge(p, x1 + wby2, y1 + dw1by2, x2, y2 - dw2by2, dw1by2, dw2by2, LeftEdge, s2, c);
       
   301             break;
       
   302         case RightEdge:
       
   303             qDrawEdge(p, x1 + wby2, y1, x2, y2, dw1by2, dw2by2, RightEdge, s1, c);
       
   304             qDrawEdge(p, x1, y1 + dw1by2, x1 + wby2, y2 - dw2by2, dw1by2, dw2by2, RightEdge, s2, c);
       
   305             break;
       
   306         default:
       
   307             break;
       
   308         }
       
   309     }
       
   310     default:
       
   311         break;
       
   312     }
       
   313     p->restore();
       
   314 }
       
   315 
       
   316 void qNormalizeRadii(const QRect &br, const QSize *radii,
       
   317                      QSize *tlr, QSize *trr, QSize *blr, QSize *brr)
       
   318 {
       
   319     *tlr = radii[0].expandedTo(QSize(0, 0));
       
   320     *trr = radii[1].expandedTo(QSize(0, 0));
       
   321     *blr = radii[2].expandedTo(QSize(0, 0));
       
   322     *brr = radii[3].expandedTo(QSize(0, 0));
       
   323     if (tlr->width() + trr->width() > br.width())
       
   324         *tlr = *trr = QSize(0, 0);
       
   325     if (blr->width() + brr->width() > br.width())
       
   326         *blr = *brr = QSize(0, 0);
       
   327     if (tlr->height() + blr->height() > br.height())
       
   328         *tlr = *blr = QSize(0, 0);
       
   329     if (trr->height() + brr->height() > br.height())
       
   330         *trr = *brr = QSize(0, 0);
       
   331 }
       
   332 
       
   333 // Determines if Edge e1 draws over Edge e2. Depending on this trapezoids or rectanges are drawn
       
   334 static bool paintsOver(const QCss::BorderStyle *styles, const QBrush *colors, QCss::Edge e1, QCss::Edge e2)
       
   335 {
       
   336     QCss::BorderStyle s1 = styles[e1];
       
   337     QCss::BorderStyle s2 = styles[e2];
       
   338 
       
   339     if (s2 == BorderStyle_None || colors[e2] == Qt::transparent)
       
   340         return true;
       
   341 
       
   342     if ((s1 == BorderStyle_Solid && s2 == BorderStyle_Solid) && (colors[e1] == colors[e2]))
       
   343         return true;
       
   344 
       
   345     return false;
       
   346 }
       
   347 
       
   348 void qDrawBorder(QPainter *p, const QRect &rect, const QCss::BorderStyle *styles,
       
   349                  const int *borders, const QBrush *colors, const QSize *radii)
       
   350 {
       
   351     const QRectF br(rect);
       
   352     QSize tlr, trr, blr, brr;
       
   353     qNormalizeRadii(rect, radii, &tlr, &trr, &blr, &brr);
       
   354 
       
   355     // Drawn in increasing order of precendence
       
   356     if (styles[BottomEdge] != BorderStyle_None && borders[BottomEdge] > 0) {
       
   357         qreal dw1 = (blr.width() || paintsOver(styles, colors, BottomEdge, LeftEdge)) ? 0 : borders[LeftEdge];
       
   358         qreal dw2 = (brr.width() || paintsOver(styles, colors, BottomEdge, RightEdge)) ? 0 : borders[RightEdge];
       
   359         qreal x1 = br.x() + blr.width();
       
   360         qreal y1 = br.y() + br.height() - borders[BottomEdge];
       
   361         qreal x2 = br.x() + br.width() - brr.width();
       
   362         qreal y2 = br.y() + br.height() ;
       
   363 
       
   364         qDrawEdge(p, x1, y1, x2, y2, dw1, dw2, BottomEdge, styles[BottomEdge], colors[BottomEdge]);
       
   365         if (blr.width() || brr.width())
       
   366             qDrawRoundedCorners(p, x1, y1, x2, y2, blr, brr, BottomEdge, styles[BottomEdge], colors[BottomEdge]);
       
   367     }
       
   368     if (styles[RightEdge] != BorderStyle_None && borders[RightEdge] > 0) {
       
   369         qreal dw1 = (trr.height() || paintsOver(styles, colors, RightEdge, TopEdge)) ? 0 : borders[TopEdge];
       
   370         qreal dw2 = (brr.height() || paintsOver(styles, colors, RightEdge, BottomEdge)) ? 0 : borders[BottomEdge];
       
   371         qreal x1 = br.x() + br.width() - borders[RightEdge];
       
   372         qreal y1 = br.y() + trr.height();
       
   373         qreal x2 = br.x() + br.width();
       
   374         qreal y2 = br.y() + br.height() - brr.height();
       
   375 
       
   376         qDrawEdge(p, x1, y1, x2, y2, dw1, dw2, RightEdge, styles[RightEdge], colors[RightEdge]);
       
   377         if (trr.height() || brr.height())
       
   378             qDrawRoundedCorners(p, x1, y1, x2, y2, trr, brr, RightEdge, styles[RightEdge], colors[RightEdge]);
       
   379     }
       
   380     if (styles[LeftEdge] != BorderStyle_None && borders[LeftEdge] > 0) {
       
   381         qreal dw1 = (tlr.height() || paintsOver(styles, colors, LeftEdge, TopEdge)) ? 0 : borders[TopEdge];
       
   382         qreal dw2 = (blr.height() || paintsOver(styles, colors, LeftEdge, BottomEdge)) ? 0 : borders[BottomEdge];
       
   383         qreal x1 = br.x();
       
   384         qreal y1 = br.y() + tlr.height();
       
   385         qreal x2 = br.x() + borders[LeftEdge];
       
   386         qreal y2 = br.y() + br.height() - blr.height();
       
   387 
       
   388         qDrawEdge(p, x1, y1, x2, y2, dw1, dw2, LeftEdge, styles[LeftEdge], colors[LeftEdge]);
       
   389         if (tlr.height() || blr.height())
       
   390             qDrawRoundedCorners(p, x1, y1, x2, y2, tlr, blr, LeftEdge, styles[LeftEdge], colors[LeftEdge]);
       
   391     }
       
   392     if (styles[TopEdge] != BorderStyle_None && borders[TopEdge] > 0) {
       
   393         qreal dw1 = (tlr.width() || paintsOver(styles, colors, TopEdge, LeftEdge)) ? 0 : borders[LeftEdge];
       
   394         qreal dw2 = (trr.width() || paintsOver(styles, colors, TopEdge, RightEdge)) ? 0 : borders[RightEdge];
       
   395         qreal x1 = br.x() + tlr.width();
       
   396         qreal y1 = br.y();
       
   397         qreal x2 = br.left() + br.width() - trr.width();
       
   398         qreal y2 = br.y() + borders[TopEdge];
       
   399 
       
   400         qDrawEdge(p, x1, y1, x2, y2, dw1, dw2, TopEdge, styles[TopEdge], colors[TopEdge]);
       
   401         if (tlr.width() || trr.width())
       
   402             qDrawRoundedCorners(p, x1, y1, x2, y2, tlr, trr, TopEdge, styles[TopEdge], colors[TopEdge]);
       
   403     }
       
   404 }
       
   405 
       
   406 #endif //QT_NO_CSSPARSER
       
   407 
       
   408 QT_END_NAMESPACE