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, |