void TextLabel::drawTextLayout(QPainter *painter, const QTextLayout &layout, const QRect &rect) { if (rect.width() < 1 || rect.height() < 1) { return; } QPixmap pixmap(rect.size()); pixmap.fill(Qt::transparent); QPainter p(&pixmap); p.setPen(painter->pen()); // Create the alpha gradient for the fade out effect QLinearGradient alphaGradient(0, 0, 1, 0); alphaGradient.setCoordinateMode(QGradient::ObjectBoundingMode); if (layout.textOption().textDirection() == Qt::LeftToRight) { alphaGradient.setColorAt(0, QColor(0, 0, 0, 255)); alphaGradient.setColorAt(1, QColor(0, 0, 0, 0)); } else { alphaGradient.setColorAt(0, QColor(0, 0, 0, 0)); alphaGradient.setColorAt(1, QColor(0, 0, 0, 255)); } QFontMetrics fm(layout.font()); int textHeight = layout.lineCount() * fm.lineSpacing(); QPointF position(0, (rect.height() - textHeight) / 2); QList<QRect> fadeRects; int fadeWidth = 30; // Draw each line in the layout for (int i = 0; i < layout.lineCount(); i++) { QTextLine line = layout.lineAt(i); line.draw(&p, position); // Add a fade out rect to the list if the line is too long if (line.naturalTextWidth() > rect.width()) { int x = int(qMin(line.naturalTextWidth(), (qreal)pixmap.width())) - fadeWidth; int y = int(line.position().y() + position.y()); QRect r = QStyle::visualRect(layout.textOption().textDirection(), pixmap.rect(), QRect(x, y, fadeWidth, int(line.height()))); fadeRects.append(r); } } // Reduce the alpha in each fade out rect using the alpha gradient if (!fadeRects.isEmpty()) { p.setCompositionMode(QPainter::CompositionMode_DestinationIn); foreach (const QRect &rect, fadeRects) { p.fillRect(rect, alphaGradient); }
//! [2] void ElidedLabel::paintEvent(QPaintEvent *event) { QFrame::paintEvent(event); QPainter painter(this); QFontMetrics fontMetrics = painter.fontMetrics(); bool didElide = false; int lineSpacing = fontMetrics.lineSpacing(); int y = 0; QTextLayout textLayout(content, painter.font()); textLayout.beginLayout(); forever { QTextLine line = textLayout.createLine(); if (!line.isValid()) break; line.setLineWidth(width()); int nextLineY = y + lineSpacing; if (height() >= nextLineY + lineSpacing) { line.draw(&painter, QPoint(0, y)); y = nextLineY; //! [2] //! [3] } else { QString lastLine = content.mid(line.textStart()); QString elidedLastLine = fontMetrics.elidedText(lastLine, Qt::ElideRight, width()); painter.drawText(QPoint(0, y + fontMetrics.ascent()), elidedLastLine); line = textLayout.createLine(); didElide = line.isValid(); break; } } textLayout.endLayout(); //! [3] //! [4] if (didElide != elided) { elided = didElide; emit elisionChanged(didElide); } }
void ElidedLabel::paintEvent(QPaintEvent *event) { QLabel::paintEvent(event); QPainter painter(this); QFontMetrics fontMetrics = painter.fontMetrics(); QRect cr = contentsRect(); cr.adjust(margin(), margin(), -margin(), -margin()); bool didElide = false; int lineSpacing = fontMetrics.lineSpacing(); int x, y = x =cr.top()+(cr.height()-lineSpacing)/2; QTextLayout textLayout(mContent, painter.font()); textLayout.beginLayout(); forever { QTextLine line = textLayout.createLine(); if (!line.isValid()) break; line.setLineWidth(cr.width()+2*x); int nextLineY = y + lineSpacing; if (cr.height() >= nextLineY + lineSpacing) { line.draw(&painter, QPoint(x, y)); y = nextLineY; } else { QString lastLine = mContent.mid(line.textStart()); QString elidedLastLine = fontMetrics.elidedText(lastLine, Qt::ElideRight, cr.width()); painter.drawText(QPoint(x, y + fontMetrics.ascent()), elidedLastLine); line = textLayout.createLine(); didElide = line.isValid(); break; } } textLayout.endLayout(); if (didElide != mElided) { mElided = didElide; emit elisionChanged(didElide); } }
// FIXME: we need to figure out a way to derive from Fm::FolderItemDelegate to avoid code duplication. void DesktopItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { Q_ASSERT(index.isValid()); QStyleOptionViewItemV4 opt = option; initStyleOption(&opt, index); painter->save(); painter->setClipRect(option.rect); opt.decorationAlignment = Qt::AlignHCenter | Qt::AlignTop; opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter; // draw the icon QIcon::Mode iconMode; if(opt.state & QStyle::State_Enabled) { if(opt.state & QStyle::State_Selected) iconMode = QIcon::Selected; else { iconMode = QIcon::Normal; } } else iconMode = QIcon::Disabled; QPoint iconPos(opt.rect.x() + (opt.rect.width() - opt.decorationSize.width()) / 2, opt.rect.y()); QPixmap pixmap = opt.icon.pixmap(opt.decorationSize, iconMode); painter->drawPixmap(iconPos, pixmap); // draw some emblems for the item if needed // we only support symlink emblem at the moment FmFileInfo* file = static_cast<FmFileInfo*>(index.data(Fm::FolderModel::FileInfoRole).value<void*>()); if(file) { if(fm_file_info_is_symlink(file)) { painter->drawPixmap(iconPos, symlinkIcon_.pixmap(opt.decorationSize / 2, iconMode)); } } // draw text QRectF textRect(opt.rect.x(), opt.rect.y() + opt.decorationSize.height(), opt.rect.width(), opt.rect.height() - opt.decorationSize.height()); QTextLayout layout(opt.text, opt.font); QTextOption textOption; textOption.setAlignment(opt.displayAlignment); textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); textOption.setTextDirection(opt.direction); layout.setTextOption(textOption); qreal height = 0; qreal width = 0; int visibleLines = 0; layout.beginLayout(); QString elidedText; for(;;) { QTextLine line = layout.createLine(); if(!line.isValid()) break; line.setLineWidth(textRect.width()); height += opt.fontMetrics.leading(); line.setPosition(QPointF(0, height)); if((height + line.height() + textRect.y()) > textRect.bottom()) { // if part of this line falls outside the textRect, ignore it and quit. QTextLine lastLine = layout.lineAt(visibleLines - 1); elidedText = opt.text.mid(lastLine.textStart()); elidedText = opt.fontMetrics.elidedText(elidedText, opt.textElideMode, textRect.width()); break; } height += line.height(); width = qMax(width, line.naturalTextWidth()); ++ visibleLines; } layout.endLayout(); QRectF boundRect = layout.boundingRect(); boundRect.setWidth(width); boundRect.moveTo(textRect.x() + (textRect.width() - width)/2, textRect.y()); if((opt.state & QStyle::State_Selected) && opt.widget) { QPalette palette = opt.widget->palette(); // qDebug("w: %f, h:%f, m:%f", boundRect.width(), boundRect.height(), layout.minimumWidth()); painter->fillRect(boundRect, palette.highlight()); } else { // only draw shadow for non-selected items // draw shadow, FIXME: is it possible to use QGraphicsDropShadowEffect here? QPen prevPen = painter->pen(); painter->setPen(QPen(shadowColor_)); for(int i = 0; i < visibleLines; ++i) { QTextLine line = layout.lineAt(i); if(i == (visibleLines - 1) && !elidedText.isEmpty()) { // the last line, draw elided text QPointF pos(textRect.x() + line.position().x() + 1, textRect.y() + line.y() + line.ascent() + 1); painter->drawText(pos, elidedText); } else { line.draw(painter, textRect.topLeft() + QPointF(1, 1)); } } painter->setPen(prevPen); } // draw text for(int i = 0; i < visibleLines; ++i) { QTextLine line = layout.lineAt(i); if(i == (visibleLines - 1) && !elidedText.isEmpty()) { // the last line, draw elided text QPointF pos(textRect.x() + line.position().x(), textRect.y() + line.y() + line.ascent()); painter->drawText(pos, elidedText); } else { line.draw(painter, textRect.topLeft()); } } if(opt.state & QStyle::State_HasFocus) { // FIXME: draw focus rect } painter->restore(); }
void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const { if (to < 0) to = run.length(); QPainter *p = ctx->platformContext(); if (ctx->textDrawingMode() & cTextFill) { if (ctx->fillGradient()) { QBrush brush(*ctx->fillGradient()->platformGradient()); brush.setTransform(ctx->fillGradient()->gradientSpaceTransform()); p->setPen(QPen(brush, 0)); } else if (ctx->fillPattern()) { TransformationMatrix affine; p->setPen(QPen(QBrush(ctx->fillPattern()->createPlatformPattern(affine)), 0)); } else p->setPen(QColor(ctx->fillColor())); } if (ctx->textDrawingMode() & cTextStroke) { if (ctx->strokeGradient()) { QBrush brush(*ctx->strokeGradient()->platformGradient()); brush.setTransform(ctx->strokeGradient()->gradientSpaceTransform()); p->setPen(QPen(brush, ctx->strokeThickness())); } else if (ctx->strokePattern()) { TransformationMatrix affine; p->setPen(QPen(QBrush(ctx->strokePattern()->createPlatformPattern(affine)), ctx->strokeThickness())); } else p->setPen(QPen(QColor(ctx->strokeColor()), ctx->strokeThickness())); } const QString string = fixSpacing(qstring(run)); // text shadow IntSize shadowSize; int shadowBlur; Color shadowColor; bool hasShadow = ctx->textDrawingMode() == cTextFill && ctx->getShadow(shadowSize, shadowBlur, shadowColor); if (from > 0 || to < run.length()) { QTextLayout layout(string, font()); QTextLine line = setupLayout(&layout, run); float x1 = line.cursorToX(from); float x2 = line.cursorToX(to); if (x2 < x1) qSwap(x1, x2); QFontMetrics fm(font()); int ascent = fm.ascent(); QRectF clip(point.x() + x1, point.y() - ascent, x2 - x1, fm.height()); if (hasShadow) { // TODO: when blur support is added, the clip will need to account // for the blur radius qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0; if (shadowSize.width() > 0) dx2 = shadowSize.width(); else dx1 = -shadowSize.width(); if (shadowSize.height() > 0) dy2 = shadowSize.height(); else dy1 = -shadowSize.height(); // expand the clip rect to include the text shadow as well clip.adjust(dx1, dx2, dy1, dy2); } p->save(); p->setClipRect(clip.toRect()); QPointF pt(point.x(), point.y() - ascent); if (hasShadow) { p->save(); p->setPen(QColor(shadowColor)); p->translate(shadowSize.width(), shadowSize.height()); line.draw(p, pt); p->restore(); } line.draw(p, pt); p->restore(); return; } p->setFont(font()); QPointF pt(point.x(), point.y()); int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; if (hasShadow) { // TODO: text shadow blur support p->save(); p->setPen(QColor(shadowColor)); p->translate(shadowSize.width(), shadowSize.height()); p->drawText(pt, string, flags, run.padding()); p->restore(); } if (ctx->textDrawingMode() & cTextStroke) { QPainterPath path; path.addText(pt, font(), string); p->strokePath(path, p->pen()); } if (ctx->textDrawingMode() & cTextFill) p->drawText(pt, string, flags, run.padding()); }
// if painter is nullptr, the method calculate the bounding rectangle of the text and save it to textRect void FolderItemDelegate::drawText(QPainter* painter, QStyleOptionViewItemV4& opt, QRectF& textRect) const { QTextLayout layout(opt.text, opt.font); QTextOption textOption; textOption.setAlignment(opt.displayAlignment); textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); textOption.setTextDirection(opt.direction); layout.setTextOption(textOption); qreal height = 0; qreal width = 0; int visibleLines = 0; layout.beginLayout(); QString elidedText; for(;;) { QTextLine line = layout.createLine(); if(!line.isValid()) break; line.setLineWidth(textRect.width()); height += opt.fontMetrics.leading(); line.setPosition(QPointF(0, height)); if((height + line.height() + textRect.y()) > textRect.bottom()) { // if part of this line falls outside the textRect, ignore it and quit. QTextLine lastLine = layout.lineAt(visibleLines - 1); elidedText = opt.text.mid(lastLine.textStart()); elidedText = opt.fontMetrics.elidedText(elidedText, opt.textElideMode, textRect.width()); if(visibleLines == 1) // this is the only visible line width = textRect.width(); break; } height += line.height(); width = qMax(width, line.naturalTextWidth()); ++ visibleLines; } layout.endLayout(); // draw background for selected item QRectF boundRect = layout.boundingRect(); //qDebug() << "bound rect: " << boundRect << "width: " << width; boundRect.setWidth(width); boundRect.moveTo(textRect.x() + (textRect.width() - width)/2, textRect.y()); if(!painter) { // no painter, calculate the bounding rect only textRect = boundRect; return; } QPalette::ColorGroup cg = opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if(opt.state & QStyle::State_Selected) { painter->fillRect(boundRect, opt.palette.highlight()); painter->setPen(opt.palette.color(cg, QPalette::HighlightedText)); } else painter->setPen(opt.palette.color(cg, QPalette::Text)); // draw text for(int i = 0; i < visibleLines; ++i) { QTextLine line = layout.lineAt(i); if(i == (visibleLines - 1) && !elidedText.isEmpty()) { // the last line, draw elided text QPointF pos(textRect.x() + line.position().x(), textRect.y() + line.y() + line.ascent()); painter->drawText(pos, elidedText); } else { line.draw(painter, textRect.topLeft()); } } if(opt.state & QStyle::State_HasFocus) { // draw focus rect QStyleOptionFocusRect o; o.QStyleOption::operator=(opt); o.rect = boundRect.toRect(); // subElementRect(SE_ItemViewItemFocusRect, vopt, widget); o.state |= QStyle::State_KeyboardFocusChange; o.state |= QStyle::State_Item; QPalette::ColorGroup cg = (opt.state & QStyle::State_Enabled) ? QPalette::Normal : QPalette::Disabled; o.backgroundColor = opt.palette.color(cg, (opt.state & QStyle::State_Selected) ? QPalette::Highlight : QPalette::Window); if (const QWidget* widget = opt.widget) { QStyle* style = widget->style() ? widget->style() : qApp->style(); style->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter, widget); } } }
static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to, const QFont& font, bool isComplexText) { if (to < 0) to = run.length(); QPainter *p = ctx->platformContext(); QPen textFillPen; if (ctx->textDrawingMode() & TextModeFill) textFillPen = fillPenForContext(ctx); QPen textStrokePen; if (ctx->textDrawingMode() & TextModeStroke) textStrokePen = strokePenForContext(ctx); String sanitized = Font::normalizeSpaces(run.characters(), run.length()); QString string = fromRawDataWithoutRef(sanitized); QPointF pt(point.x(), point.y()); if (from > 0 || to < run.length()) { if (isComplexText) { QTextLayout layout(string, font); QTextLine line = setupLayout(&layout, run); float x1 = line.cursorToX(from); float x2 = line.cursorToX(to); if (x2 < x1) qSwap(x1, x2); QFontMetrics fm(font); int ascent = fm.ascent(); QRectF boundingRect(point.x() + x1, point.y() - ascent, x2 - x1, fm.height()); QRectF clip = boundingRect; ContextShadow* ctxShadow = ctx->contextShadow(); if (ctxShadow->m_type != ContextShadow::NoShadow) { qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0; if (ctxShadow->offset().x() > 0) dx2 = ctxShadow->offset().x(); else dx1 = -ctxShadow->offset().x(); if (ctxShadow->offset().y() > 0) dy2 = ctxShadow->offset().y(); else dy1 = -ctxShadow->offset().y(); // expand the clip rect to include the text shadow as well clip.adjust(dx1, dx2, dy1, dy2); clip.adjust(-ctxShadow->m_blurDistance, -ctxShadow->m_blurDistance, ctxShadow->m_blurDistance, ctxShadow->m_blurDistance); } p->save(); p->setClipRect(clip.toRect(), Qt::IntersectClip); pt.setY(pt.y() - ascent); if (ctxShadow->m_type != ContextShadow::NoShadow) { ContextShadow* ctxShadow = ctx->contextShadow(); if (!ctxShadow->mustUseContextShadow(ctx)) { p->save(); p->setPen(ctxShadow->m_color); p->translate(ctxShadow->offset()); line.draw(p, pt); p->restore(); } else { QPainter* shadowPainter = ctxShadow->beginShadowLayer(ctx, boundingRect); if (shadowPainter) { // Since it will be blurred anyway, we don't care about render hints. shadowPainter->setFont(p->font()); shadowPainter->setPen(ctxShadow->m_color); line.draw(shadowPainter, pt); ctxShadow->endShadowLayer(ctx); } } } p->setPen(textFillPen); line.draw(p, pt); p->restore(); return; } int skipWidth = QFontMetrics(font).width(string, from, Qt::TextBypassShaping); pt.setX(pt.x() + skipWidth); string = fromRawDataWithoutRef(sanitized, from, to - from); } p->setFont(font); int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; if (!isComplexText && !(ctx->textDrawingMode() & TextModeStroke)) flags |= Qt::TextBypassShaping; QPainterPath textStrokePath; if (ctx->textDrawingMode() & TextModeStroke) textStrokePath.addText(pt, font, string); ContextShadow* ctxShadow = ctx->contextShadow(); if (ctxShadow->m_type != ContextShadow::NoShadow) { if (ctx->textDrawingMode() & TextModeFill) { if (ctxShadow->m_type != ContextShadow::BlurShadow) { p->save(); p->setPen(ctxShadow->m_color); p->translate(ctxShadow->offset()); p->drawText(pt, string, flags, run.expansion()); p->restore(); } else { QFontMetrics fm(font); QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string, -1, flags), fm.height()); QPainter* shadowPainter = ctxShadow->beginShadowLayer(ctx, boundingRect); if (shadowPainter) { // Since it will be blurred anyway, we don't care about render hints. shadowPainter->setFont(p->font()); shadowPainter->setPen(ctxShadow->m_color); shadowPainter->drawText(pt, string, flags, run.expansion()); ctxShadow->endShadowLayer(ctx); } } } else if (ctx->textDrawingMode() & TextModeStroke) { if (ctxShadow->m_type != ContextShadow::BlurShadow) { p->translate(ctxShadow->offset()); p->strokePath(textStrokePath, QPen(ctxShadow->m_color)); p->translate(-ctxShadow->offset()); } else { QFontMetrics fm(font); QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string, -1, flags), fm.height()); QPainter* shadowPainter = ctxShadow->beginShadowLayer(ctx, boundingRect); if (shadowPainter) { // Since it will be blurred anyway, we don't care about render hints. shadowPainter->setFont(p->font()); shadowPainter->strokePath(textStrokePath, QPen(ctxShadow->m_color)); ctxShadow->endShadowLayer(ctx); } } } } if (ctx->textDrawingMode() & TextModeStroke) p->strokePath(textStrokePath, textStrokePen); if (ctx->textDrawingMode() & TextModeFill) { QPen previousPen = p->pen(); p->setPen(textFillPen); p->drawText(pt, string, flags, run.expansion()); p->setPen(previousPen); } }
void ListViewDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const { QStyleOptionViewItemV4 opt = option; initStyleOption ( &opt, index ); painter->save(); painter->setClipRect ( opt.rect ); opt.features |= QStyleOptionViewItem::WrapText; opt.text = index.data().toString(); opt.textElideMode = Qt::ElideRight; opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter; QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); //const int iconSize = style->pixelMetric(QStyle::PM_IconViewIconSize); const int iconSize = 48; QRect iconbox = opt.rect; const int textMargin = style->pixelMetric ( QStyle::PM_FocusFrameHMargin, 0, opt.widget ) + 1; QRect textRect = opt.rect; QRect textHighlightRect = textRect; // clip the decoration on top, remove width padding textRect.adjust ( textMargin,iconSize + textMargin + 5,-textMargin,0 ); textHighlightRect.adjust ( 0,iconSize + 5,0,0 ); // draw background { QSize textSize = viewItemTextSize ( &opt ); QPalette::ColorGroup cg; QStyleOptionViewItemV4 opt2(opt); if((opt.widget && opt.widget->isEnabled()) || (opt.state & QStyle::State_Enabled)) { if(! ( opt.state & QStyle::State_Active )) cg = QPalette::Inactive; else cg = QPalette::Normal; } else { cg = QPalette::Disabled; } opt2.palette.setCurrentColorGroup(cg); // fill in background, if any if ( opt.backgroundBrush.style() != Qt::NoBrush ) { QPointF oldBO = painter->brushOrigin(); painter->setBrushOrigin ( opt.rect.topLeft() ); painter->fillRect ( opt.rect, opt.backgroundBrush ); painter->setBrushOrigin ( oldBO ); } if ( opt.showDecorationSelected ) { drawSelectionRect(painter,opt2, opt.rect); drawFocusRect(painter,opt2, opt.rect); //painter->fillRect ( opt.rect, opt.palette.brush ( cg, QPalette::Highlight ) ); } else { //if ( opt.state & QStyle::State_Selected ) { //QRect textRect = subElementRect ( QStyle::SE_ItemViewItemText, opt, opt.widget ); //painter->fillRect ( textHighlightRect, opt.palette.brush ( cg, QPalette::Highlight ) ); drawSelectionRect(painter,opt2, textHighlightRect); drawFocusRect(painter,opt2, textHighlightRect); } } } // draw the icon { QIcon::Mode mode = QIcon::Normal; if ( ! ( opt.state & QStyle::State_Enabled ) ) mode = QIcon::Disabled; else if ( opt.state & QStyle::State_Selected ) mode = QIcon::Selected; QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off; iconbox.setHeight ( iconSize ); opt.icon.paint ( painter, iconbox, Qt::AlignCenter, mode, state ); } // set the text colors QPalette::ColorGroup cg = opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if ( cg == QPalette::Normal && ! ( opt.state & QStyle::State_Active ) ) cg = QPalette::Inactive; if ( opt.state & QStyle::State_Selected ) { painter->setPen ( opt.palette.color ( cg, QPalette::HighlightedText ) ); } else { painter->setPen ( opt.palette.color ( cg, QPalette::Text ) ); } // draw the text QTextOption textOption; textOption.setWrapMode ( QTextOption::WrapAtWordBoundaryOrAnywhere ); textOption.setTextDirection ( opt.direction ); textOption.setAlignment ( QStyle::visualAlignment ( opt.direction, opt.displayAlignment ) ); QTextLayout textLayout; textLayout.setTextOption ( textOption ); textLayout.setFont ( opt.font ); textLayout.setText ( opt.text ); qreal width, height; viewItemTextLayout ( textLayout, iconbox.width(), height, width ); const int lineCount = textLayout.lineCount(); const QRect layoutRect = QStyle::alignedRect ( opt.direction, opt.displayAlignment, QSize ( iconbox.width(), int ( height ) ), textRect ); const QPointF position = layoutRect.topLeft(); for ( int i = 0; i < lineCount; ++i ) { const QTextLine line = textLayout.lineAt ( i ); line.draw ( painter, position ); } painter->restore(); }
static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to, const QFont& font, bool isComplexText) { if (to < 0) to = run.length(); QPainter *p = ctx->platformContext(); QPen textFillPen; if (ctx->textDrawingMode() & cTextFill) { if (ctx->fillGradient()) { QBrush brush(*ctx->fillGradient()->platformGradient()); brush.setTransform(ctx->fillGradient()->gradientSpaceTransform()); textFillPen = QPen(brush, 0); } else if (ctx->fillPattern()) { AffineTransform affine; textFillPen = QPen(QBrush(ctx->fillPattern()->createPlatformPattern(affine)), 0); } else textFillPen = QPen(QColor(ctx->fillColor())); } QPen textStrokePen; if (ctx->textDrawingMode() & cTextStroke) { if (ctx->strokeGradient()) { QBrush brush(*ctx->strokeGradient()->platformGradient()); brush.setTransform(ctx->strokeGradient()->gradientSpaceTransform()); textStrokePen = QPen(brush, ctx->strokeThickness()); } else if (ctx->strokePattern()) { AffineTransform affine; QBrush brush(ctx->strokePattern()->createPlatformPattern(affine)); textStrokePen = QPen(brush, ctx->strokeThickness()); } else textStrokePen = QPen(QColor(ctx->strokeColor()), ctx->strokeThickness()); } String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); QString string = fromRawDataWithoutRef(sanitized); QPointF pt(point.x(), point.y()); // text shadow IntSize shadowSize; int shadowBlur; Color shadowColor; bool hasShadow = ctx->textDrawingMode() == cTextFill && ctx->getShadow(shadowSize, shadowBlur, shadowColor); if (from > 0 || to < run.length()) { if (isComplexText) { QTextLayout layout(string, font); QTextLine line = setupLayout(&layout, run); float x1 = line.cursorToX(from); float x2 = line.cursorToX(to); if (x2 < x1) qSwap(x1, x2); QFontMetrics fm(font); int ascent = fm.ascent(); QRectF clip(fm.boundingRect(string)); if (hasShadow) { // TODO: when blur support is added, the clip will need to account // for the blur radius qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0; if (shadowSize.width() > 0) dx2 = shadowSize.width(); else dx1 = -shadowSize.width(); if (shadowSize.height() > 0) dy2 = shadowSize.height(); else dy1 = -shadowSize.height(); // expand the clip rect to include the text shadow as well clip.adjust(dx1, dx2, dy1, dy2); } p->save(); //p->setClipRect(clip.toRect(), Qt::IntersectClip); pt.setY(pt.y() - ascent); if (hasShadow) { p->save(); p->setPen(QColor(shadowColor)); p->translate(shadowSize.width(), shadowSize.height()); line.draw(p, pt); p->restore(); } p->setPen(textFillPen); line.draw(p, pt); p->restore(); return; } #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) int skipWidth = QFontMetrics(font).width(string, from, Qt::TextBypassShaping); pt.setX(pt.x() + skipWidth); string = fromRawDataWithoutRef(sanitized, from, to - from); #endif } p->setFont(font); int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) // See QWebPagePrivate::QWebPagePrivate() where the default path is set to Complex for Qt 4.6 and earlier. if (!isComplexText) flags |= Qt::TextBypassShaping; #endif QFontMetrics fm(font); QRectF clip(pt.x(), pt.y()-fm.ascent(), fm.width(string, -1, flags), fm.height()); if (hasShadow) { // TODO: text shadow blur support p->save(); p->translate(shadowSize.width(), shadowSize.height()); //p->setClipRect(clip, Qt::IntersectClip); p->setPen(QColor(shadowColor)); p->drawText(pt, string, flags, run.padding()); p->restore(); } if (ctx->textDrawingMode() & cTextStroke) { QPainterPath path; path.addText(pt, font, string); p->save(); //p->setClipRect(clip, Qt::IntersectClip); p->setPen(textStrokePen); p->strokePath(path, p->pen()); p->restore(); } if (ctx->textDrawingMode() & cTextFill) { p->save(); //p->setClipRect(clip, Qt::IntersectClip); p->setPen(textFillPen); p->drawText(pt, string, flags, run.padding()); p->restore(); } }
void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const { if (to < 0) to = run.length(); QPainter *p = ctx->platformContext(); Color color = ctx->fillColor(); p->setPen(QColor(color)); QString string = qstring(run); // text shadow IntSize shadowSize; int shadowBlur; Color shadowColor; bool hasShadow = ctx->textDrawingMode() == cTextFill && ctx->getShadow(shadowSize, shadowBlur, shadowColor); if (from > 0 || to < run.length()) { QTextLayout layout(string, font()); QTextLine line = setupLayout(&layout, run); float x1 = line.cursorToX(from); float x2 = line.cursorToX(to); if (x2 < x1) qSwap(x1, x2); QFontMetrics fm(font()); int ascent = fm.ascent(); QRectF clip(point.x() + x1, point.y() - ascent, x2 - x1, fm.height()); if (hasShadow) { // TODO: when blur support is added, the clip will need to account // for the blur radius qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0; if (shadowSize.width() > 0) dx2 = shadowSize.width(); else dx1 = -shadowSize.width(); if (shadowSize.height() > 0) dy2 = shadowSize.height(); else dy1 = -shadowSize.height(); // expand the clip rect to include the text shadow as well clip.adjust(dx1, dx2, dy1, dy2); } p->save(); p->setClipRect(clip.toRect()); QPointF pt(point.x(), point.y() - ascent); if (hasShadow) { p->save(); p->setPen(QColor(shadowColor)); p->translate(shadowSize.width(), shadowSize.height()); line.draw(p, pt); p->restore(); } line.draw(p, pt); p->restore(); return; } p->setFont(font()); QPointF pt(point.x(), point.y()); int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; if (hasShadow) { // TODO: text shadow blur support p->save(); p->setPen(QColor(shadowColor)); p->translate(shadowSize.width(), shadowSize.height()); p->drawText(pt, string, flags, run.padding()); p->restore(); } p->drawText(pt, string, flags, run.padding()); }
static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to, const QFont& font, bool isComplexText) { if (to < 0) to = run.length(); QPainter *p = ctx->platformContext(); QPen textFillPen; if (ctx->textDrawingMode() & TextModeFill) { if (ctx->fillGradient()) { QBrush brush(*ctx->fillGradient()->platformGradient()); brush.setTransform(ctx->fillGradient()->gradientSpaceTransform()); textFillPen = QPen(brush, 0); } else if (ctx->fillPattern()) { AffineTransform affine; textFillPen = QPen(QBrush(ctx->fillPattern()->createPlatformPattern(affine)), 0); } else textFillPen = QPen(QColor(ctx->fillColor())); } QPen textStrokePen; if (ctx->textDrawingMode() & TextModeStroke) { if (ctx->strokeGradient()) { QBrush brush(*ctx->strokeGradient()->platformGradient()); brush.setTransform(ctx->strokeGradient()->gradientSpaceTransform()); textStrokePen = QPen(brush, ctx->strokeThickness()); } else if (ctx->strokePattern()) { AffineTransform affine; QBrush brush(ctx->strokePattern()->createPlatformPattern(affine)); textStrokePen = QPen(brush, ctx->strokeThickness()); } else textStrokePen = QPen(QColor(ctx->strokeColor()), ctx->strokeThickness()); } String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); QString string = fromRawDataWithoutRef(sanitized); QPointF pt(point.x(), point.y()); if (from > 0 || to < run.length()) { if (isComplexText) { QTextLayout layout(string, font); QTextLine line = setupLayout(&layout, run); float x1 = line.cursorToX(from); float x2 = line.cursorToX(to); if (x2 < x1) qSwap(x1, x2); QFontMetrics fm(font); int ascent = fm.ascent(); QRectF boundingRect(point.x() + x1, point.y() - ascent, x2 - x1, fm.height()); QRectF clip = boundingRect; ContextShadow* ctxShadow = ctx->contextShadow(); if (ctxShadow->m_type != ContextShadow::NoShadow) { qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0; if (ctxShadow->offset().x() > 0) dx2 = ctxShadow->offset().x(); else dx1 = -ctxShadow->offset().x(); if (ctxShadow->offset().y() > 0) dy2 = ctxShadow->offset().y(); else dy1 = -ctxShadow->offset().y(); // expand the clip rect to include the text shadow as well clip.adjust(dx1, dx2, dy1, dy2); clip.adjust(-ctxShadow->m_blurDistance, -ctxShadow->m_blurDistance, ctxShadow->m_blurDistance, ctxShadow->m_blurDistance); } p->save(); p->setClipRect(clip.toRect(), Qt::IntersectClip); pt.setY(pt.y() - ascent); if (ctxShadow->m_type != ContextShadow::NoShadow) { ContextShadow* ctxShadow = ctx->contextShadow(); if (!ctxShadow->mustUseContextShadow(p)) { p->save(); p->setPen(ctxShadow->m_color); p->translate(ctxShadow->offset()); line.draw(p, pt); p->restore(); } else { QPainter* shadowPainter = ctxShadow->beginShadowLayer(p, boundingRect); if (shadowPainter) { // Since it will be blurred anyway, we don't care about render hints. shadowPainter->setFont(p->font()); shadowPainter->setPen(ctxShadow->m_color); line.draw(shadowPainter, pt); ctxShadow->endShadowLayer(p); } } } p->setPen(textFillPen); line.draw(p, pt); p->restore(); return; } #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) int skipWidth = QFontMetrics(font).width(string, from, Qt::TextBypassShaping); pt.setX(pt.x() + skipWidth); string = fromRawDataWithoutRef(sanitized, from, to - from); #endif } p->setFont(font); int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) // See QWebPagePrivate::QWebPagePrivate() where the default path is set to Complex for Qt 4.6 and earlier. if (!isComplexText && !(ctx->textDrawingMode() & TextModeStroke)) flags |= Qt::TextBypassShaping; #endif QPainterPath textStrokePath; if (ctx->textDrawingMode() & TextModeStroke) textStrokePath.addText(pt, font, string); ContextShadow* ctxShadow = ctx->contextShadow(); if (ctxShadow->m_type != ContextShadow::NoShadow) { if (ctx->textDrawingMode() & TextModeFill) { if (ctxShadow->m_type != ContextShadow::BlurShadow) { p->save(); p->setPen(ctxShadow->m_color); p->translate(ctxShadow->offset()); p->drawText(pt, string, flags, run.padding()); p->restore(); } else { QFontMetrics fm(font); #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string, -1, flags), fm.height()); #else QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string), fm.height()); #endif QPainter* shadowPainter = ctxShadow->beginShadowLayer(p, boundingRect); if (shadowPainter) { // Since it will be blurred anyway, we don't care about render hints. shadowPainter->setFont(p->font()); shadowPainter->setPen(ctxShadow->m_color); shadowPainter->drawText(pt, string, flags, run.padding()); ctxShadow->endShadowLayer(p); } } } else if (ctx->textDrawingMode() & TextModeStroke) { if (ctxShadow->m_type != ContextShadow::BlurShadow) { p->translate(ctxShadow->offset()); p->strokePath(textStrokePath, QPen(ctxShadow->m_color)); p->translate(-ctxShadow->offset()); } else { QFontMetrics fm(font); #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string, -1, flags), fm.height()); #else QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string), fm.height()); #endif QPainter* shadowPainter = ctxShadow->beginShadowLayer(p, boundingRect); if (shadowPainter) { // Since it will be blurred anyway, we don't care about render hints. shadowPainter->setFont(p->font()); shadowPainter->strokePath(textStrokePath, QPen(ctxShadow->m_color)); ctxShadow->endShadowLayer(p); } } } } if (ctx->textDrawingMode() & TextModeStroke) p->strokePath(textStrokePath, textStrokePen); if (ctx->textDrawingMode() & TextModeFill) { QPen previousPen = p->pen(); p->setPen(textFillPen); p->drawText(pt, string, flags, run.padding()); p->setPen(previousPen); } }