src/gui/painting/qoutlinemapper.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 "qoutlinemapper_p.h"
       
    43 #include <private/qpainterpath_p.h>
       
    44 #include "qmath.h"
       
    45 
       
    46 #include <stdlib.h>
       
    47 
       
    48 QT_BEGIN_NAMESPACE
       
    49 
       
    50 static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
       
    51 
       
    52 #define qreal_to_fixed_26_6(f) (int(f * 64))
       
    53 
       
    54 
       
    55 
       
    56 
       
    57 static const QRectF boundingRect(const QPointF *points, int pointCount)
       
    58 {
       
    59     const QPointF *e = points;
       
    60     const QPointF *last = points + pointCount;
       
    61     qreal minx, maxx, miny, maxy;
       
    62     minx = maxx = e->x();
       
    63     miny = maxy = e->y();
       
    64     while (++e < last) {
       
    65         if (e->x() < minx)
       
    66             minx = e->x();
       
    67         else if (e->x() > maxx)
       
    68             maxx = e->x();
       
    69         if (e->y() < miny)
       
    70             miny = e->y();
       
    71         else if (e->y() > maxy)
       
    72             maxy = e->y();
       
    73     }
       
    74     return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
       
    75 }
       
    76 
       
    77 
       
    78 QT_FT_Outline *QOutlineMapper::convertPath(const QPainterPath &path)
       
    79 {
       
    80     Q_ASSERT(!path.isEmpty());
       
    81     int elmCount = path.elementCount();
       
    82 #ifdef QT_DEBUG_CONVERT
       
    83     printf("QOutlineMapper::convertPath(), size=%d\n", elmCount);
       
    84 #endif
       
    85     beginOutline(path.fillRule());
       
    86 
       
    87     for (int index=0; index<elmCount; ++index) {
       
    88         const QPainterPath::Element &elm = path.elementAt(index);
       
    89 
       
    90         switch (elm.type) {
       
    91 
       
    92         case QPainterPath::MoveToElement:
       
    93             if (index == elmCount - 1)
       
    94                 continue;
       
    95             moveTo(elm);
       
    96             break;
       
    97 
       
    98         case QPainterPath::LineToElement:
       
    99             lineTo(elm);
       
   100             break;
       
   101 
       
   102         case QPainterPath::CurveToElement:
       
   103             curveTo(elm, path.elementAt(index + 1), path.elementAt(index + 2));
       
   104             index += 2;
       
   105             break;
       
   106 
       
   107         default:
       
   108             break; // This will never hit..
       
   109         }
       
   110     }
       
   111 
       
   112     endOutline();
       
   113     return outline();
       
   114 }
       
   115 
       
   116 QT_FT_Outline *QOutlineMapper::convertPath(const QVectorPath &path)
       
   117 {
       
   118     int count = path.elementCount();
       
   119 
       
   120 #ifdef QT_DEBUG_CONVERT
       
   121     printf("QOutlineMapper::convertPath(VP), size=%d\n", count);
       
   122 #endif
       
   123     beginOutline(path.hasWindingFill() ? Qt::WindingFill : Qt::OddEvenFill);
       
   124 
       
   125     if (path.elements()) {
       
   126         // TODO: if we do closing of subpaths in convertElements instead we
       
   127         // could avoid this loop
       
   128         const QPainterPath::ElementType *elements = path.elements();
       
   129         const QPointF *points = reinterpret_cast<const QPointF *>(path.points());
       
   130 
       
   131         for (int index = 0; index < count; ++index) {
       
   132             switch (elements[index]) {
       
   133                 case QPainterPath::MoveToElement:
       
   134                     if (index == count - 1)
       
   135                         continue;
       
   136                     moveTo(points[index]);
       
   137                     break;
       
   138 
       
   139                 case QPainterPath::LineToElement:
       
   140                     lineTo(points[index]);
       
   141                     break;
       
   142 
       
   143                 case QPainterPath::CurveToElement:
       
   144                     curveTo(points[index], points[index+1], points[index+2]);
       
   145                     index += 2;
       
   146                     break;
       
   147 
       
   148                 default:
       
   149                     break; // This will never hit..
       
   150             }
       
   151         }
       
   152 
       
   153     } else {
       
   154         // ### We can kill this copying and just use the buffer straight...
       
   155 
       
   156         m_elements.resize(count);
       
   157         memcpy(m_elements.data(), path.points(), count* sizeof(QPointF));
       
   158 
       
   159         m_element_types.resize(0);
       
   160     }
       
   161 
       
   162     endOutline();
       
   163     return outline();
       
   164 }
       
   165 
       
   166 
       
   167 void QOutlineMapper::endOutline()
       
   168 {
       
   169     closeSubpath();
       
   170 
       
   171     int element_count = m_elements.size();
       
   172 
       
   173     if (element_count == 0) {
       
   174         memset(&m_outline, 0, sizeof(m_outline));
       
   175         return;
       
   176     }
       
   177 
       
   178     QPointF *elements;
       
   179 
       
   180     // Transform the outline
       
   181     if (m_txop == QTransform::TxNone) {
       
   182         elements = m_elements.data();
       
   183     } else {
       
   184         if (m_txop == QTransform::TxTranslate) {
       
   185             for (int i=0; i<m_elements.size(); ++i) {
       
   186                 const QPointF &e = m_elements.at(i);
       
   187                 m_elements_dev << QPointF(e.x() + m_dx, e.y() + m_dy);
       
   188             }
       
   189         } else if (m_txop == QTransform::TxScale) {
       
   190             for (int i=0; i<m_elements.size(); ++i) {
       
   191                 const QPointF &e = m_elements.at(i);
       
   192                 m_elements_dev << QPointF(m_m11 * e.x() + m_dx, m_m22 * e.y() + m_dy);
       
   193             }
       
   194         } else if (m_txop < QTransform::TxProject) {
       
   195             for (int i=0; i<m_elements.size(); ++i) {
       
   196                 const QPointF &e = m_elements.at(i);
       
   197                 m_elements_dev << QPointF(m_m11 * e.x() + m_m21 * e.y() + m_dx,
       
   198                                           m_m22 * e.y() + m_m12 * e.x() + m_dy);
       
   199             }
       
   200         } else {
       
   201             const QVectorPath vp((qreal *)m_elements.data(), m_elements.size(), m_element_types.size() ? m_element_types.data() : 0);
       
   202             QPainterPath path = vp.convertToPainterPath();
       
   203             path = QTransform(m_m11, m_m12, m_m13, m_m21, m_m22, m_m23, m_dx, m_dy, m_m33).map(path);
       
   204             if (!(m_outline.flags & QT_FT_OUTLINE_EVEN_ODD_FILL))
       
   205                 path.setFillRule(Qt::WindingFill);
       
   206             uint old_txop = m_txop;
       
   207             m_txop = QTransform::TxNone;
       
   208             if (path.isEmpty())
       
   209                 m_valid = false;
       
   210             else
       
   211                 convertPath(path);
       
   212             m_txop = old_txop;
       
   213             return;
       
   214         }
       
   215         elements = m_elements_dev.data();
       
   216     }
       
   217 
       
   218     if (m_round_coords) {
       
   219         // round coordinates to match outlines drawn with drawLine_midpoint_i
       
   220         for (int i = 0; i < m_elements.size(); ++i)
       
   221             elements[i] = QPointF(qFloor(elements[i].x() + aliasedCoordinateDelta),
       
   222                                   qFloor(elements[i].y() + aliasedCoordinateDelta));
       
   223     }
       
   224 
       
   225     controlPointRect = boundingRect(elements, element_count);
       
   226 
       
   227 #ifdef QT_DEBUG_CONVERT
       
   228     printf(" - control point rect (%.2f, %.2f) %.2f x %.2f\n",
       
   229            controlPointRect.x(), controlPointRect.y(),
       
   230            controlPointRect.width(), controlPointRect.height());
       
   231 #endif
       
   232 
       
   233 
       
   234     // Check for out of dev bounds...
       
   235     const bool do_clip = (controlPointRect.left() < -QT_RASTER_COORD_LIMIT
       
   236                           || controlPointRect.right() > QT_RASTER_COORD_LIMIT
       
   237                           || controlPointRect.top() < -QT_RASTER_COORD_LIMIT
       
   238                           || controlPointRect.bottom() > QT_RASTER_COORD_LIMIT);
       
   239 
       
   240     if (do_clip) {
       
   241         clipElements(elements, elementTypes(), element_count);
       
   242     } else {
       
   243         convertElements(elements, elementTypes(), element_count);
       
   244     }
       
   245 }
       
   246 
       
   247 void QOutlineMapper::convertElements(const QPointF *elements,
       
   248                                        const QPainterPath::ElementType *types,
       
   249                                        int element_count)
       
   250 {
       
   251 
       
   252     if (types) {
       
   253         // Translate into FT coords
       
   254         const QPointF *e = elements;
       
   255         for (int i=0; i<element_count; ++i) {
       
   256             switch (*types) {
       
   257             case QPainterPath::MoveToElement:
       
   258                 {
       
   259                     QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
       
   260                                               qreal_to_fixed_26_6(e->y()) };
       
   261                     if (i != 0)
       
   262                         m_contours << m_points.size() - 1;
       
   263                     m_points << pt_fixed;
       
   264                     m_tags <<  QT_FT_CURVE_TAG_ON;
       
   265                 }
       
   266                 break;
       
   267 
       
   268             case QPainterPath::LineToElement:
       
   269                 {
       
   270                     QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
       
   271                                               qreal_to_fixed_26_6(e->y()) };
       
   272                     m_points << pt_fixed;
       
   273                     m_tags << QT_FT_CURVE_TAG_ON;
       
   274                 }
       
   275                 break;
       
   276 
       
   277             case QPainterPath::CurveToElement:
       
   278                 {
       
   279                     QT_FT_Vector cp1_fixed = { qreal_to_fixed_26_6(e->x()),
       
   280                                                qreal_to_fixed_26_6(e->y()) };
       
   281                     ++e;
       
   282                     QT_FT_Vector cp2_fixed = { qreal_to_fixed_26_6((e)->x()),
       
   283                                                qreal_to_fixed_26_6((e)->y()) };
       
   284                     ++e;
       
   285                     QT_FT_Vector ep_fixed = { qreal_to_fixed_26_6((e)->x()),
       
   286                                               qreal_to_fixed_26_6((e)->y()) };
       
   287 
       
   288                     m_points << cp1_fixed << cp2_fixed << ep_fixed;
       
   289                     m_tags << QT_FT_CURVE_TAG_CUBIC
       
   290                            << QT_FT_CURVE_TAG_CUBIC
       
   291                            << QT_FT_CURVE_TAG_ON;
       
   292 
       
   293                     types += 2;
       
   294                     i += 2;
       
   295                 }
       
   296                 break;
       
   297             default:
       
   298                 break;
       
   299             }
       
   300             ++types;
       
   301             ++e;
       
   302         }
       
   303     } else {
       
   304         // Plain polygon...
       
   305         const QPointF *last = elements + element_count;
       
   306         const QPointF *e = elements;
       
   307         while (e < last) {
       
   308             QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
       
   309                                       qreal_to_fixed_26_6(e->y()) };
       
   310             m_points << pt_fixed;
       
   311             m_tags << QT_FT_CURVE_TAG_ON;
       
   312             ++e;
       
   313         }
       
   314     }
       
   315 
       
   316     // close the very last subpath
       
   317     m_contours << m_points.size() - 1;
       
   318 
       
   319     m_outline.n_contours = m_contours.size();
       
   320     m_outline.n_points = m_points.size();
       
   321 
       
   322     m_outline.points = m_points.data();
       
   323     m_outline.tags = m_tags.data();
       
   324     m_outline.contours = m_contours.data();
       
   325 
       
   326 #ifdef QT_DEBUG_CONVERT
       
   327     printf("QOutlineMapper::endOutline\n");
       
   328 
       
   329     printf(" - contours: %d\n", m_outline.n_contours);
       
   330     for (int i=0; i<m_outline.n_contours; ++i) {
       
   331         printf("   - %d\n", m_outline.contours[i]);
       
   332     }
       
   333 
       
   334     printf(" - points: %d\n", m_outline.n_points);
       
   335     for (int i=0; i<m_outline.n_points; ++i) {
       
   336         printf("   - %d -- %.2f, %.2f, (%d, %d)\n", i,
       
   337                (double) (m_outline.points[i].x / 64.0),
       
   338                (double) (m_outline.points[i].y / 64.0),
       
   339                (int) m_outline.points[i].x, (int) m_outline.points[i].y);
       
   340     }
       
   341 #endif
       
   342 }
       
   343 
       
   344 void QOutlineMapper::clipElements(const QPointF *elements,
       
   345                                     const QPainterPath::ElementType *types,
       
   346                                     int element_count)
       
   347 {
       
   348     // We could save a bit of time by actually implementing them fully
       
   349     // instead of going through convenience functionallity, but since
       
   350     // this part of code hardly every used, it shouldn't matter.
       
   351 
       
   352     QPainterPath path;
       
   353     if (types) {
       
   354         for (int i=0; i<element_count; ++i) {
       
   355             switch (types[i]) {
       
   356             case QPainterPath::MoveToElement:
       
   357                 path.moveTo(elements[i]);
       
   358                 break;
       
   359 
       
   360             case QPainterPath::LineToElement:
       
   361                 path.lineTo(elements[i]);
       
   362                 break;
       
   363 
       
   364             case QPainterPath::CurveToElement:
       
   365                 path.cubicTo(elements[i], elements[i+1], elements[i+2]);
       
   366                 i += 2;
       
   367                 break;
       
   368             default:
       
   369                 break;
       
   370             }
       
   371         }
       
   372     } else {
       
   373         path.moveTo(elements[0]);
       
   374         for (int i=1; i<element_count; ++i)
       
   375             path.lineTo(elements[i]);
       
   376     }
       
   377 
       
   378     QPainterPath clipPath;
       
   379     clipPath.addRect(m_clip_rect);
       
   380     QPainterPath clippedPath = path.intersected(clipPath);
       
   381     uint old_txop = m_txop;
       
   382     m_txop = QTransform::TxNone;
       
   383     if (clippedPath.isEmpty())
       
   384         m_valid = false;
       
   385     else
       
   386         convertPath(clippedPath);
       
   387     m_txop = old_txop;
       
   388 }
       
   389 
       
   390 QT_END_NAMESPACE