src/gui/painting/qpainter.cpp
changeset 37 758a864f9613
parent 33 3e2da88830cd
equal deleted inserted replaced
36:ef0373b55136 37:758a864f9613
    88 
    88 
    89 void qt_format_text(const QFont &font,
    89 void qt_format_text(const QFont &font,
    90                     const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect,
    90                     const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect,
    91                     int tabstops, int* tabarray, int tabarraylen,
    91                     int tabstops, int* tabarray, int tabarraylen,
    92                     QPainter *painter);
    92                     QPainter *painter);
       
    93 static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe,
       
    94                                    QTextCharFormat::UnderlineStyle underlineStyle,
       
    95                                    const QTextItem::RenderFlags flags, qreal width,
       
    96                                    const QTextCharFormat &charFormat);
       
    97 // Helper function to calculate left most position, width and flags for decoration drawing
       
    98 static void drawDecorationForGlyphs(QPainter *painter, const glyph_t *glyphArray,
       
    99                                     const QFixedPoint *positions, int glyphCount,
       
   100                                     QFontEngine *fontEngine, const QFont &font,
       
   101                                     const QTextCharFormat &charFormat);
    93 
   102 
    94 static inline QGradient::CoordinateMode coordinateMode(const QBrush &brush)
   103 static inline QGradient::CoordinateMode coordinateMode(const QBrush &brush)
    95 {
   104 {
    96     switch (brush.style()) {
   105     switch (brush.style()) {
    97     case Qt::LinearGradientPattern:
   106     case Qt::LinearGradientPattern:
   685         else
   694         else
   686             s->emulationSpecifier &= ~QPaintEngine::BrushStroke;
   695             s->emulationSpecifier &= ~QPaintEngine::BrushStroke;
   687 
   696 
   688         skip = false;
   697         skip = false;
   689 
   698 
   690         QBrush penBrush = s->pen.brush();
   699         QBrush penBrush = (qpen_style(s->pen) == Qt::NoPen) ? QBrush(Qt::NoBrush) : qpen_brush(s->pen);
   691         Qt::BrushStyle brushStyle = s->brush.style();
   700         Qt::BrushStyle brushStyle = qbrush_style(s->brush);
   692         Qt::BrushStyle penBrushStyle = penBrush.style();
   701         Qt::BrushStyle penBrushStyle = qbrush_style(penBrush);
   693         alpha = (penBrushStyle != Qt::NoBrush
   702         alpha = (penBrushStyle != Qt::NoBrush
   694                  && (penBrushStyle < Qt::LinearGradientPattern && penBrush.color().alpha() != 255)
   703                  && (penBrushStyle < Qt::LinearGradientPattern && penBrush.color().alpha() != 255)
   695                  && !penBrush.isOpaque())
   704                  && !penBrush.isOpaque())
   696                 || (brushStyle != Qt::NoBrush
   705                 || (brushStyle != Qt::NoBrush
   697                     && (brushStyle < Qt::LinearGradientPattern && s->brush.color().alpha() != 255)
   706                     && (brushStyle < Qt::LinearGradientPattern && s->brush.color().alpha() != 255)
  5851     if (d->extended == 0 || !d->state->matrix.isAffine()) {
  5860     if (d->extended == 0 || !d->state->matrix.isAffine()) {
  5852         staticText_d->paintText(topLeftPosition, this);
  5861         staticText_d->paintText(topLeftPosition, this);
  5853         return;
  5862         return;
  5854     }
  5863     }
  5855 
  5864 
  5856     if (d->extended->type() == QPaintEngine::OpenGL2 && !staticText_d->untransformedCoordinates) {
  5865     bool paintEngineSupportsTransformations = d->extended->type() == QPaintEngine::OpenGL2
       
  5866                                            || d->extended->type() == QPaintEngine::OpenVG
       
  5867                                            || d->extended->type() == QPaintEngine::OpenGL;
       
  5868 
       
  5869     if (paintEngineSupportsTransformations && !staticText_d->untransformedCoordinates) {
  5857         staticText_d->untransformedCoordinates = true;
  5870         staticText_d->untransformedCoordinates = true;
  5858         staticText_d->needsRelayout = true;
  5871         staticText_d->needsRelayout = true;
  5859     } else if (d->extended->type() != QPaintEngine::OpenGL2 && staticText_d->untransformedCoordinates) {
  5872     } else if (!paintEngineSupportsTransformations && staticText_d->untransformedCoordinates) {
  5860         staticText_d->untransformedCoordinates = false;
  5873         staticText_d->untransformedCoordinates = false;
  5861         staticText_d->needsRelayout = true;
  5874         staticText_d->needsRelayout = true;
  5862     }
  5875     }
  5863 
  5876 
  5864     // Don't recalculate entire layout because of translation, rather add the dx and dy
  5877     // Don't recalculate entire layout because of translation, rather add the dx and dy
  5893         staticTextNeedsReinit = true;
  5906         staticTextNeedsReinit = true;
  5894     }
  5907     }
  5895 
  5908 
  5896     // Recreate the layout of the static text because the matrix or font has changed
  5909     // Recreate the layout of the static text because the matrix or font has changed
  5897     if (staticTextNeedsReinit)
  5910     if (staticTextNeedsReinit)
  5898         staticText_d->init();    
  5911         staticText_d->init();
  5899 
  5912 
  5900     if (transformedPosition != staticText_d->position) { // Translate to actual position
  5913     if (transformedPosition != staticText_d->position) { // Translate to actual position
  5901         QFixed fx = QFixed::fromReal(transformedPosition.x());
  5914         QFixed fx = QFixed::fromReal(transformedPosition.x());
  5902         QFixed fy = QFixed::fromReal(transformedPosition.y());
  5915         QFixed fy = QFixed::fromReal(transformedPosition.y());
  5903         QFixed oldX = QFixed::fromReal(staticText_d->position.x());
  5916         QFixed oldX = QFixed::fromReal(staticText_d->position.x());
  5921         if (item->color.isValid() && currentColor != item->color) {
  5934         if (item->color.isValid() && currentColor != item->color) {
  5922             setPen(item->color);
  5935             setPen(item->color);
  5923             currentColor = item->color;
  5936             currentColor = item->color;
  5924         }
  5937         }
  5925         d->extended->drawStaticTextItem(item);
  5938         d->extended->drawStaticTextItem(item);
       
  5939 
       
  5940         drawDecorationForGlyphs(this, item->glyphs, item->glyphPositions,
       
  5941                                 item->numGlyphs, item->fontEngine, staticText_d->font,
       
  5942                                 QTextCharFormat());
  5926     }
  5943     }
  5927     if (currentColor != oldPen.color())
  5944     if (currentColor != oldPen.color())
  5928         setPen(oldPen);
  5945         setPen(oldPen);
  5929 
  5946 
  5930     if (!staticText_d->untransformedCoordinates && oldMatrix.isTranslating())
  5947     if (!staticText_d->untransformedCoordinates && oldMatrix.isTranslating())
  6288     QPixmapCache::insert(key, pixmap);
  6305     QPixmapCache::insert(key, pixmap);
  6289 
  6306 
  6290     return pixmap;
  6307     return pixmap;
  6291 }
  6308 }
  6292 
  6309 
  6293 static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QTextItemInt &ti)
  6310 static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe,
  6294 {
  6311                                    QTextCharFormat::UnderlineStyle underlineStyle,
  6295     QTextCharFormat::UnderlineStyle underlineStyle = ti.underlineStyle;
  6312                                    const QTextItem::RenderFlags flags, qreal width,
       
  6313                                    const QTextCharFormat &charFormat)
       
  6314 {
  6296     if (underlineStyle == QTextCharFormat::NoUnderline
  6315     if (underlineStyle == QTextCharFormat::NoUnderline
  6297         && !(ti.flags & (QTextItem::StrikeOut | QTextItem::Overline)))
  6316         && !(flags & (QTextItem::StrikeOut | QTextItem::Overline)))
  6298         return;
  6317         return;
  6299 
       
  6300     QFontEngine *fe = ti.fontEngine;
       
  6301 
  6318 
  6302     const QPen oldPen = painter->pen();
  6319     const QPen oldPen = painter->pen();
  6303     const QBrush oldBrush = painter->brush();
  6320     const QBrush oldBrush = painter->brush();
  6304     painter->setBrush(Qt::NoBrush);
  6321     painter->setBrush(Qt::NoBrush);
  6305     QPen pen = oldPen;
  6322     QPen pen = oldPen;
  6306     pen.setStyle(Qt::SolidLine);
  6323     pen.setStyle(Qt::SolidLine);
  6307     pen.setWidthF(fe->lineThickness().toReal());
  6324     pen.setWidthF(fe->lineThickness().toReal());
  6308     pen.setCapStyle(Qt::FlatCap);
  6325     pen.setCapStyle(Qt::FlatCap);
  6309 
  6326 
  6310     QLineF line(pos.x(), pos.y(), pos.x() + ti.width.toReal(), pos.y());
  6327     QLineF line(pos.x(), pos.y(), pos.x() + width, pos.y());
  6311 
  6328 
  6312     const qreal underlineOffset = fe->underlinePosition().toReal();
  6329     const qreal underlineOffset = fe->underlinePosition().toReal();
  6313     // deliberately ceil the offset to avoid the underline coming too close to
  6330     // deliberately ceil the offset to avoid the underline coming too close to
  6314     // the text above it.
  6331     // the text above it.
  6315     const qreal underlinePos = pos.y() + qCeil(underlineOffset);
  6332     const qreal underlinePos = pos.y() + qCeil(underlineOffset);
  6320 
  6337 
  6321     if (underlineStyle == QTextCharFormat::WaveUnderline) {
  6338     if (underlineStyle == QTextCharFormat::WaveUnderline) {
  6322         painter->save();
  6339         painter->save();
  6323         painter->translate(0, pos.y() + 1);
  6340         painter->translate(0, pos.y() + 1);
  6324 
  6341 
  6325         QColor uc = ti.charFormat.underlineColor();
  6342         QColor uc = charFormat.underlineColor();
  6326         if (uc.isValid())
  6343         if (uc.isValid())
  6327             pen.setColor(uc);
  6344             pen.setColor(uc);
  6328 
  6345 
  6329         // Adapt wave to underlineOffset or pen width, whatever is larger, to make it work on all platforms
  6346         // Adapt wave to underlineOffset or pen width, whatever is larger, to make it work on all platforms
  6330         const QPixmap wave = generateWavyPixmap(qMax(underlineOffset, pen.widthF()), pen);
  6347         const QPixmap wave = generateWavyPixmap(qMax(underlineOffset, pen.widthF()), pen);
  6331         const int descent = (int) ti.descent.toReal();
  6348         const int descent = (int) fe->descent().toReal();
  6332 
  6349 
  6333         painter->setBrushOrigin(painter->brushOrigin().x(), 0);
  6350         painter->setBrushOrigin(painter->brushOrigin().x(), 0);
  6334         painter->fillRect(pos.x(), 0, qCeil(ti.width.toReal()), qMin(wave.height(), descent), wave);
  6351         painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave);
  6335         painter->restore();
  6352         painter->restore();
  6336     } else if (underlineStyle != QTextCharFormat::NoUnderline) {
  6353     } else if (underlineStyle != QTextCharFormat::NoUnderline) {
  6337         QLineF underLine(line.x1(), underlinePos, line.x2(), underlinePos);
  6354         QLineF underLine(line.x1(), underlinePos, line.x2(), underlinePos);
  6338 
  6355 
  6339         QColor uc = ti.charFormat.underlineColor();
  6356         QColor uc = charFormat.underlineColor();
  6340         if (uc.isValid())
  6357         if (uc.isValid())
  6341             pen.setColor(uc);
  6358             pen.setColor(uc);
  6342 
  6359 
  6343         pen.setStyle((Qt::PenStyle)(underlineStyle));
  6360         pen.setStyle((Qt::PenStyle)(underlineStyle));
  6344         painter->setPen(pen);
  6361         painter->setPen(pen);
  6346     }
  6363     }
  6347 
  6364 
  6348     pen.setStyle(Qt::SolidLine);
  6365     pen.setStyle(Qt::SolidLine);
  6349     pen.setColor(oldPen.color());
  6366     pen.setColor(oldPen.color());
  6350 
  6367 
  6351     if (ti.flags & QTextItem::StrikeOut) {
  6368     if (flags & QTextItem::StrikeOut) {
  6352         QLineF strikeOutLine = line;
  6369         QLineF strikeOutLine = line;
  6353         strikeOutLine.translate(0., - fe->ascent().toReal() / 3.);
  6370         strikeOutLine.translate(0., - fe->ascent().toReal() / 3.);
  6354         painter->setPen(pen);
  6371         painter->setPen(pen);
  6355         painter->drawLine(strikeOutLine);
  6372         painter->drawLine(strikeOutLine);
  6356     }
  6373     }
  6357 
  6374 
  6358     if (ti.flags & QTextItem::Overline) {
  6375     if (flags & QTextItem::Overline) {
  6359         QLineF overLine = line;
  6376         QLineF overLine = line;
  6360         overLine.translate(0., - fe->ascent().toReal());
  6377         overLine.translate(0., - fe->ascent().toReal());
  6361         painter->setPen(pen);
  6378         painter->setPen(pen);
  6362         painter->drawLine(overLine);
  6379         painter->drawLine(overLine);
  6363     }
  6380     }
  6364 
  6381 
  6365     painter->setPen(oldPen);
  6382     painter->setPen(oldPen);
  6366     painter->setBrush(oldBrush);
  6383     painter->setBrush(oldBrush);
       
  6384 }
       
  6385 
       
  6386 static void drawDecorationForGlyphs(QPainter *painter, const glyph_t *glyphArray,
       
  6387                                     const QFixedPoint *positions, int glyphCount,
       
  6388                                     QFontEngine *fontEngine, const QFont &font,
       
  6389                                     const QTextCharFormat &charFormat)
       
  6390 {
       
  6391     if (!(font.underline() || font.strikeOut() || font.overline()))
       
  6392         return;
       
  6393 
       
  6394     QFixed leftMost;
       
  6395     QFixed rightMost;
       
  6396     QFixed baseLine;
       
  6397     for (int i=0; i<glyphCount; ++i) {
       
  6398         glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[i]);
       
  6399         if (i == 0 || leftMost > positions[i].x)
       
  6400             leftMost = positions[i].x;
       
  6401 
       
  6402         // We don't support glyphs that do not share a common baseline. If this turns out to
       
  6403         // be a relevant use case, then we need to find clusters of glyphs that share a baseline
       
  6404         // and do a drawTextItemDecorations call per cluster.
       
  6405         if (i == 0 || baseLine < positions[i].y)
       
  6406             baseLine = positions[i].y;
       
  6407 
       
  6408         // We use the advance rather than the actual bounds to match the algorithm in drawText()
       
  6409         if (i == 0 || rightMost < positions[i].x + gm.xoff)
       
  6410             rightMost = positions[i].x + gm.xoff;
       
  6411     }
       
  6412 
       
  6413     QFixed width = rightMost - leftMost;
       
  6414     QTextItem::RenderFlags flags = 0;
       
  6415 
       
  6416     if (font.underline())
       
  6417         flags |= QTextItem::Underline;
       
  6418     if (font.overline())
       
  6419         flags |= QTextItem::Overline;
       
  6420     if (font.strikeOut())
       
  6421         flags |= QTextItem::StrikeOut;
       
  6422 
       
  6423     drawTextItemDecoration(painter, QPointF(leftMost.toReal(), baseLine.toReal()),
       
  6424                            fontEngine,
       
  6425                            font.underline() ? QTextCharFormat::SingleUnderline
       
  6426                                             : QTextCharFormat::NoUnderline, flags,
       
  6427                            width.toReal(), charFormat);
  6367 }
  6428 }
  6368 
  6429 
  6369 void QPainter::drawTextItem(const QPointF &p, const QTextItem &_ti)
  6430 void QPainter::drawTextItem(const QPointF &p, const QTextItem &_ti)
  6370 {
  6431 {
  6371 #ifdef QT_DEBUG_DRAW
  6432 #ifdef QT_DEBUG_DRAW
  6494         if (d->extended)
  6555         if (d->extended)
  6495             d->extended->drawTextItem(p, ti);
  6556             d->extended->drawTextItem(p, ti);
  6496         else
  6557         else
  6497             d->engine->drawTextItem(p, ti);
  6558             d->engine->drawTextItem(p, ti);
  6498     }
  6559     }
  6499     drawTextItemDecoration(this, p, ti);
  6560     drawTextItemDecoration(this, p, ti.fontEngine, ti.underlineStyle, ti.flags, ti.width.toReal(),
       
  6561                            ti.charFormat);
  6500 
  6562 
  6501     if (d->state->renderHints != oldRenderHints) {
  6563     if (d->state->renderHints != oldRenderHints) {
  6502         d->state->renderHints = oldRenderHints;
  6564         d->state->renderHints = oldRenderHints;
  6503         if (d->extended)
  6565         if (d->extended)
  6504             d->extended->renderHintsChanged();
  6566             d->extended->renderHintsChanged();
  8964 void QPainter::drawPixmapFragments(const PixmapFragment *fragments, int fragmentCount,
  9026 void QPainter::drawPixmapFragments(const PixmapFragment *fragments, int fragmentCount,
  8965                                    const QPixmap &pixmap, PixmapFragmentHints hints)
  9027                                    const QPixmap &pixmap, PixmapFragmentHints hints)
  8966 {
  9028 {
  8967     Q_D(QPainter);
  9029     Q_D(QPainter);
  8968 
  9030 
  8969     if (!d->engine)
  9031     if (!d->engine || pixmap.isNull())
  8970         return;
  9032         return;
  8971 
  9033 
  8972 #ifndef QT_NO_DEBUG
  9034 #ifndef QT_NO_DEBUG
  8973     for (int i = 0; i < fragmentCount; ++i) {
  9035     for (int i = 0; i < fragmentCount; ++i) {
  8974         QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
  9036         QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,