static QTextLine setupLayout(QTextLayout* layout, const TextRun& style) { int flags = style.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; if (style.padding()) flags |= Qt::TextJustificationForced; layout->setFlags(flags); layout->beginLayout(); QTextLine line = layout->createLine(); line.setLineWidth(INT_MAX/256); if (style.padding()) line.setLineWidth(line.naturalTextWidth() + style.padding()); layout->endLayout(); return line; }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const { if (!run.length()) return 0; if (run.length() == 1 && treatAsSpace(run[0])) return QFontMetrics(font()).width(space) + run.padding(); String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); QString string = fromRawDataWithoutRef(sanitized); int w = QFontMetrics(font()).width(string); // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) if (treatAsSpace(run[0])) w -= m_wordSpacing; return w + run.padding(); }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const { if (!run.length()) return 0; const QString string = fixSpacing(qstring(run)); int w = QFontMetrics(font()).width(string); // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) if (treatAsSpace(run[0])) w -= m_wordSpacing; return w + run.padding(); }
static String setupTextDrawing(const Font* font, const TextRun& run, Olympia::Platform::Text::DrawParam* drawParam) { const float scaleFactor = font->primaryFont()->platformData().scaleFactor(); drawParam->m_textOrder = run.rtl() ? Olympia::Platform::Text::ReverseTextOrder : Olympia::Platform::Text::NoTextOrder; drawParam->m_letterspace.m_value = font->letterSpacing() / scaleFactor; if (font->wordSpacing()) { drawParam->m_wordspace.m_mode = Olympia::Platform::Text::WordSpaceAdd; drawParam->m_wordspace.m_size.m_value = font->wordSpacing() / scaleFactor; } String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); if (run.padding()) { // Justifying characters. Text API doesn't have dedicated // functionality for this (yet), so we emulate it for now. const UChar* characters = sanitized.characters(); int gapCount = 0; for (int i = 0; i < sanitized.length(); ++i) { if (characters[i] == space || characters[i] == zeroWidthSpace) ++gapCount; } // wordSpacing() and justification are mutually exclusive, // so we override any previous settings as well. if (gapCount) { drawParam->m_wordspace.m_mode = Olympia::Platform::Text::WordSpaceAdd; drawParam->m_wordspace.m_size.m_value = run.padding() / (gapCount * scaleFactor); } else drawParam->m_wordspace.m_mode = Olympia::Platform::Text::WordSpaceNatural; } return sanitized; }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const { if (!run.length()) return 0; const QString string = fixSpacing(qstring(run)); QTextLayout layout(string, font()); QTextLine line = setupLayout(&layout, run); int w = int(line.naturalTextWidth()); // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) if (treatAsSpace(run[0])) w -= m_wordSpacing; return w + run.padding(); }
void Font::drawComplexText(GraphicsContext* gc, const TextRun& run, const FloatPoint& point, int from, int to) const { if (!run.length()) return; SkCanvas* canvas = gc->platformContext()->canvas(); int textMode = gc->platformContext()->getTextDrawingMode(); bool fill = textMode & cTextFill; bool stroke = (textMode & cTextStroke) && gc->platformContext()->getStrokeStyle() != NoStroke && gc->platformContext()->getStrokeThickness() > 0; if (!fill && !stroke) return; SkPaint strokePaint, fillPaint; if (fill) { gc->platformContext()->setupPaintForFilling(&fillPaint); setupForTextPainting(&fillPaint, gc->fillColor().rgb()); } if (stroke) { gc->platformContext()->setupPaintForStroking(&strokePaint, 0, 0); setupForTextPainting(&strokePaint, gc->strokeColor().rgb()); } TextRunWalker walker(run, point.x(), this); walker.setWordSpacingAdjustment(wordSpacing()); walker.setLetterSpacingAdjustment(letterSpacing()); walker.setPadding(run.padding()); while (walker.nextScriptRun()) { if (fill) { walker.fontPlatformDataForScriptRun()->setupPaint(&fillPaint); adjustTextRenderMode(&fillPaint, gc->platformContext()); canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), fillPaint); } if (stroke) { walker.fontPlatformDataForScriptRun()->setupPaint(&strokePaint); adjustTextRenderMode(&strokePaint, gc->platformContext()); canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), strokePaint); } } }
float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) if (!run.length()) return 0; String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); QString string = fromRawDataWithoutRef(sanitized); int w = QFontMetrics(font()).width(string, -1, Qt::TextBypassShaping); // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) if (treatAsSpace(run[0])) w -= m_wordSpacing; return w + run.padding(); #else Q_ASSERT(false); return 0.0f; #endif }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow*) const { if (run.length() == 0) return run.padding(); const FontPlatformData& fontPlatformData = primaryFont()->platformData(); const float scaleFactor = fontPlatformData.scaleFactor(); Olympia::Platform::Text::Font* font = fontPlatformData.font(); Olympia::Platform::Text::DrawParam drawParam; String sanitized = setupTextDrawing(this, run, &drawParam); // WebKit calls us with plain spaces almost half of the time. // Exit early with a cached value to avoid lots of calls into Text API. if (sanitized.length() == 1 && sanitized[0] == ' ') return primaryFont()->spaceWidth(); #if PLATFORM(EGL) // FIXME: remove after Text API fixes shared context handling if (eglGetCurrentContext() == EGL_NO_CONTEXT) EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); #endif Olympia::Platform::Text::TextMetrics metrics; FontPlatformData::engine()->drawText(0 /* no drawing, only measuring */, *font, sanitized.characters(), sanitized.length(), 0 /*x*/, 0 /*y*/, 0 /* no wrap */, &drawParam, &metrics); if (fallbackFonts && primaryFont()->lineSpacing() < metrics.m_ascent + metrics.m_descent) { FontPlatformData tallerFontPlatformData = fontPlatformData; tallerFontPlatformData.setLineSpacingOverride(metrics.m_ascent, metrics.m_descent); // HACK: We can't generate a cached SimpleFontData from outside of FontCache, // so instead we abuse FontCache::getFontDataForCharacters() to do that. // Safe to use this way because we also pass 0 as string length, // which avoids clashes with possible regular calls of that method. fallbackFonts->add(fontCache()->getFontDataForCharacters(*this, reinterpret_cast<const UChar*>(&tallerFontPlatformData), 0)); } return metrics.m_linearAdvance * scaleFactor; }
Font::CodePath Font::codePath(const TextRun& run) const { if (s_codePath != Auto) return s_codePath; #if PLATFORM(QT) if (run.padding() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing()) return Complex; #endif // Start from 0 since drawing and highlighting also measure the characters before run->from for (int i = 0; i < run.length(); i++) { const UChar c = run[i]; if (c < 0x300) // U+0300 through U+036F Combining diacritical marks continue; if (c <= 0x36F) return Complex; if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha continue; if (c <= 0x05CF) return Complex; if (c < 0x0600) // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar continue; if (c <= 0x1059) return Complex; if (c < 0x1100) // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A) continue; if (c <= 0x11FF) return Complex; if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian continue; if (c <= 0x18AF) return Complex; if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0) continue; if (c <= 0x194F) return Complex; if (c < 0x1E00) // U+1E00 through U+2000 characters with diacritics and stacked diacritics continue; if (c <= 0x2000) return SimpleWithGlyphOverflow; if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols continue; if (c <= 0x20FF) return Complex; if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks continue; if (c <= 0xFE2F) return Complex; } if (typesettingFeatures()) return Complex; return Simple; }
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()); }
static int generateComponents(TextRunComponents* components, const Font &font, const TextRun &run) { int letterSpacing = font.letterSpacing(); int wordSpacing = font.wordSpacing(); int padding = run.padding(); int numSpaces = 0; if (padding) { for (int i = 0; i < run.length(); i++) if (Font::treatAsSpace(run[i])) ++numSpaces; } int offset = 0; if (letterSpacing) { // need to draw every letter on it's own int start = 0; if (Font::treatAsSpace(run[0])) { int add = 0; if (numSpaces) { add = padding/numSpaces; padding -= add; --numSpaces; } components->append(TextRunComponent(1, font, offset)); offset += add + letterSpacing + components->last().m_width; start = 1; } for (int i = 1; i < run.length(); ++i) { uint ch = run[i]; if (isHighSurrogate(ch) && isLowSurrogate(run[i-1])) ch = surrogateToUcs4(ch, run[i-1]); if (isLowSurrogate(ch) || category(ch) == Mark_NonSpacing) continue; if (Font::treatAsSpace(run[i])) { int add = 0; if (i - start > 0) { components->append(TextRunComponent(run.characters() + start, i - start, run, font, offset)); offset += components->last().m_width + letterSpacing; } if (numSpaces) { add = padding/numSpaces; padding -= add; --numSpaces; } components->append(TextRunComponent(1, font, offset)); offset += wordSpacing + add + components->last().m_width + letterSpacing; start = i + 1; continue; } if (i - start > 0) { components->append(TextRunComponent(run.characters() + start, i - start, run, font, offset)); offset += components->last().m_width + letterSpacing; } start = i; } if (run.length() - start > 0) { components->append(TextRunComponent(run.characters() + start, run.length() - start, run, font, offset)); offset += components->last().m_width; } offset += letterSpacing; } else { int start = 0; for (int i = 0; i < run.length(); ++i) { if (Font::treatAsSpace(run[i])) { if (i - start > 0) { components->append(TextRunComponent(run.characters() + start, i - start, run, font, offset)); offset += components->last().m_width; } int add = 0; if (numSpaces) { add = padding/numSpaces; padding -= add; --numSpaces; } components->append(TextRunComponent(1, font, offset)); offset += add + components->last().m_width; if (i) offset += wordSpacing; start = i + 1; } } if (run.length() - start > 0) { components->append(TextRunComponent(run.characters() + start, run.length() - start, run, font, offset)); offset += components->last().m_width; } } return offset; }
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); } }