17242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved.
27242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// Use of this source code is governed by a BSD-style license that can be
37242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// found in the LICENSE file.
47242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
57242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "config.h"
67242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "core/rendering/TextPainter.h"
77242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
87242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "core/CSSPropertyNames.h"
97242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "core/frame/Settings.h"
107242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "core/rendering/InlineTextBox.h"
117242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "core/rendering/RenderCombineText.h"
127242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "core/rendering/RenderObject.h"
137242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "core/rendering/style/RenderStyle.h"
147242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "core/rendering/style/ShadowList.h"
157242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "platform/fonts/Font.h"
167242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "platform/graphics/GraphicsContext.h"
177242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "platform/graphics/GraphicsContextStateSaver.h"
187242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "platform/text/TextRun.h"
197242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "wtf/Assertions.h"
207242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "wtf/unicode/CharacterNames.h"
217242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
227242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccinamespace blink {
237242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
247242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano TucciTextPainter::TextPainter(GraphicsContext* context, const Font& font, const TextRun& run, const FloatPoint& textOrigin, const FloatRect& textBounds, bool horizontal)
257242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    : m_graphicsContext(context)
267242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    , m_font(font)
277242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    , m_run(run)
287242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    , m_textOrigin(textOrigin)
297242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    , m_textBounds(textBounds)
307242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    , m_horizontal(horizontal)
317242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    , m_emphasisMarkOffset(0)
327242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    , m_combinedText(0)
337242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{
347242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
357242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
367242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano TucciTextPainter::~TextPainter()
377242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{
387242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
397242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
407242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccivoid TextPainter::setEmphasisMark(const AtomicString& emphasisMark, TextEmphasisPosition position)
417242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{
427242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    m_emphasisMark = emphasisMark;
437242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
447242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    if (emphasisMark.isNull()) {
457242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        m_emphasisMarkOffset = 0;
467242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    } else if (position == TextEmphasisPositionOver) {
477242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        m_emphasisMarkOffset = -m_font.fontMetrics().ascent() - m_font.emphasisMarkDescent(emphasisMark);
487242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    } else {
497242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        ASSERT(position == TextEmphasisPositionUnder);
507242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        m_emphasisMarkOffset = m_font.fontMetrics().descent() + m_font.emphasisMarkAscent(emphasisMark);
517242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    }
527242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
537242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
547242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccivoid TextPainter::paint(int startOffset, int endOffset, int length, const Style& textStyle, TextBlobPtr* cachedTextBlob)
557242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{
567242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    GraphicsContextStateSaver stateSaver(*m_graphicsContext, false);
577242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    updateGraphicsContext(textStyle, stateSaver);
587242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    paintInternal<PaintText>(startOffset, endOffset, length, cachedTextBlob);
597242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
607242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    if (!m_emphasisMark.isEmpty()) {
617242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (textStyle.emphasisMarkColor != textStyle.fillColor)
627242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            m_graphicsContext->setFillColor(textStyle.emphasisMarkColor);
637242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
647242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (m_combinedText)
657242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            paintEmphasisMarkForCombinedText();
667242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        else
677242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            paintInternal<PaintEmphasisMark>(startOffset, endOffset, length);
687242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    }
697242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
707242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
717242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// static
727242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccivoid TextPainter::updateGraphicsContext(GraphicsContext* context, const Style& textStyle, bool horizontal, GraphicsContextStateSaver& stateSaver)
737242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{
747242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    TextDrawingModeFlags mode = context->textDrawingMode();
757242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    if (textStyle.strokeWidth > 0) {
767242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        TextDrawingModeFlags newMode = mode | TextModeStroke;
777242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (mode != newMode) {
787242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            if (!stateSaver.saved())
797242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci                stateSaver.save();
807242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            context->setTextDrawingMode(newMode);
817242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            mode = newMode;
827242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        }
837242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    }
847242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
857242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    if (mode & TextModeFill && textStyle.fillColor != context->fillColor())
867242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        context->setFillColor(textStyle.fillColor);
877242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
887242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    if (mode & TextModeStroke) {
897242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (textStyle.strokeColor != context->strokeColor())
907242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            context->setStrokeColor(textStyle.strokeColor);
917242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (textStyle.strokeWidth != context->strokeThickness())
927242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            context->setStrokeThickness(textStyle.strokeWidth);
937242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    }
947242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
957242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // Text shadows are disabled when printing. http://crbug.com/258321
967242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    if (textStyle.shadow && !context->printing()) {
977242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (!stateSaver.saved())
987242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            stateSaver.save();
997242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        context->setDrawLooper(textStyle.shadow->createDrawLooper(DrawLooperBuilder::ShadowIgnoresAlpha, horizontal));
1007242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    }
1017242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
1027242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1037242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccistatic Color textColorForWhiteBackground(Color textColor)
1047242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{
1057242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    int distanceFromWhite = differenceSquared(textColor, Color::white);
1067242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // semi-arbitrarily chose 65025 (255^2) value here after a few tests;
1077242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    return distanceFromWhite > 65025 ? textColor : textColor.dark();
1087242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
1097242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1107242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// static
1117242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano TucciTextPainter::Style TextPainter::textPaintingStyle(RenderObject& renderer, RenderStyle* style, bool forceBlackText, bool isPrinting)
1127242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{
1137242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    TextPainter::Style textStyle;
1147242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1157242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    if (forceBlackText) {
1167242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        textStyle.fillColor = Color::black;
1177242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        textStyle.strokeColor = Color::black;
1187242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        textStyle.emphasisMarkColor = Color::black;
1197242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        textStyle.strokeWidth = style->textStrokeWidth();
1207242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        textStyle.shadow = 0;
1217242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    } else {
1227242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        textStyle.fillColor = renderer.resolveColor(style, CSSPropertyWebkitTextFillColor);
1237242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        textStyle.strokeColor = renderer.resolveColor(style, CSSPropertyWebkitTextStrokeColor);
1247242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        textStyle.emphasisMarkColor = renderer.resolveColor(style, CSSPropertyWebkitTextEmphasisColor);
1257242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        textStyle.strokeWidth = style->textStrokeWidth();
1267242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        textStyle.shadow = style->textShadow();
1277242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1287242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        // Adjust text color when printing with a white background.
1297242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        bool forceBackgroundToWhite = false;
1307242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (isPrinting) {
1317242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            if (style->printColorAdjust() == PrintColorAdjustEconomy)
1327242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci                forceBackgroundToWhite = true;
1337242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            if (renderer.document().settings() && renderer.document().settings()->shouldPrintBackgrounds())
1347242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci                forceBackgroundToWhite = false;
1357242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        }
1367242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (forceBackgroundToWhite) {
1377242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            textStyle.fillColor = textColorForWhiteBackground(textStyle.fillColor);
1387242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            textStyle.strokeColor = textColorForWhiteBackground(textStyle.strokeColor);
1397242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            textStyle.emphasisMarkColor = textColorForWhiteBackground(textStyle.emphasisMarkColor);
1407242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        }
1417242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1427242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        // Text shadows are disabled when printing. http://crbug.com/258321
1437242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (isPrinting)
1447242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            textStyle.shadow = 0;
1457242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    }
1467242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1477242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    return textStyle;
1487242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
1497242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1507242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano TucciTextPainter::Style TextPainter::selectionPaintingStyle(RenderObject& renderer, bool haveSelection, bool forceBlackText, bool isPrinting, const TextPainter::Style& textStyle)
1517242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{
1527242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    TextPainter::Style selectionStyle = textStyle;
1537242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1547242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    if (haveSelection) {
1557242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (!forceBlackText) {
1567242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            selectionStyle.fillColor = renderer.selectionForegroundColor();
1577242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            selectionStyle.emphasisMarkColor = renderer.selectionEmphasisMarkColor();
1587242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        }
1597242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1607242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (RenderStyle* pseudoStyle = renderer.getCachedPseudoStyle(SELECTION)) {
1617242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            selectionStyle.strokeColor = forceBlackText ? Color::black : renderer.resolveColor(pseudoStyle, CSSPropertyWebkitTextStrokeColor);
1627242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            selectionStyle.strokeWidth = pseudoStyle->textStrokeWidth();
1637242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            selectionStyle.shadow = forceBlackText ? 0 : pseudoStyle->textShadow();
1647242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        }
1657242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1667242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        // Text shadows are disabled when printing. http://crbug.com/258321
1677242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (isPrinting)
1687242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            selectionStyle.shadow = 0;
1697242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    }
1707242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1717242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    return selectionStyle;
1727242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
1737242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1747242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccistatic bool graphicsContextAllowsTextBlobs(GraphicsContext* context)
1757242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{
1767242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // Text blobs affect the shader coordinate space.
1777242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // FIXME: Fix this, most likely in Skia.
1787242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    return !context->strokeGradient() && !context->strokePattern() && !context->fillGradient() && !context->fillPattern();
1797242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
1807242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1817242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccitemplate <TextPainter::PaintInternalStep step>
1827242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccivoid TextPainter::paintInternalRun(TextRunPaintInfo& textRunPaintInfo, int from, int to, TextBlobPtr* cachedTextBlob)
1837242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{
1847242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    textRunPaintInfo.from = from;
1857242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    textRunPaintInfo.to = to;
1867242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1877242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    if (step == PaintEmphasisMark) {
1887242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        m_graphicsContext->drawEmphasisMarks(m_font, textRunPaintInfo, m_emphasisMark, m_textOrigin + IntSize(0, m_emphasisMarkOffset));
1897242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        return;
1907242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    }
1917242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1927242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    ASSERT(step == PaintText);
1937242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1947242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    TextBlobPtr localTextBlob;
1957242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    TextBlobPtr& textBlob = cachedTextBlob ? *cachedTextBlob : localTextBlob;
1967242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    bool canUseTextBlobs = RuntimeEnabledFeatures::textBlobEnabled() && graphicsContextAllowsTextBlobs(m_graphicsContext);
1977242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1987242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    if (canUseTextBlobs && !textBlob)
1997242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        textBlob = m_font.buildTextBlob(textRunPaintInfo, m_textOrigin, m_graphicsContext->couldUseLCDRenderedText());
2007242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
2017242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    if (canUseTextBlobs && textBlob)
2027242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        m_font.drawTextBlob(m_graphicsContext, textBlob.get(), m_textOrigin.data());
2037242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    else
2047242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        m_graphicsContext->drawText(m_font, textRunPaintInfo, m_textOrigin);
2057242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
2067242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
2077242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccitemplate <TextPainter::PaintInternalStep Step>
2087242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccivoid TextPainter::paintInternal(int startOffset, int endOffset, int truncationPoint, TextBlobPtr* cachedTextBlob)
2097242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{
2107242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // FIXME: We should be able to use cachedTextBlob in more cases.
2117242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    TextRunPaintInfo textRunPaintInfo(m_run);
2127242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    textRunPaintInfo.bounds = m_textBounds;
2137242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    if (startOffset <= endOffset) {
2147242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        paintInternalRun<Step>(textRunPaintInfo, startOffset, endOffset, cachedTextBlob);
2157242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    } else {
2167242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (endOffset > 0)
2177242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            paintInternalRun<Step>(textRunPaintInfo, 0, endOffset);
2187242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (startOffset < truncationPoint)
2197242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            paintInternalRun<Step>(textRunPaintInfo, startOffset, truncationPoint);
2207242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    }
2217242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
2227242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
2237242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccivoid TextPainter::paintEmphasisMarkForCombinedText()
2247242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{
2257242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    ASSERT(m_combinedText);
2267242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    DEFINE_STATIC_LOCAL(TextRun, placeholderTextRun, (&ideographicFullStop, 1));
2277242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    FloatPoint emphasisMarkTextOrigin(m_textBounds.x(), m_textBounds.y() + m_font.fontMetrics().ascent() + m_emphasisMarkOffset);
2287242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    TextRunPaintInfo textRunPaintInfo(placeholderTextRun);
2297242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    textRunPaintInfo.bounds = m_textBounds;
2307242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    m_graphicsContext->concatCTM(InlineTextBox::rotation(m_textBounds, InlineTextBox::Clockwise));
2317242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    m_graphicsContext->drawEmphasisMarks(m_combinedText->originalFont(), textRunPaintInfo, m_emphasisMark, emphasisMarkTextOrigin);
2327242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    m_graphicsContext->concatCTM(InlineTextBox::rotation(m_textBounds, InlineTextBox::Counterclockwise));
2337242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
2347242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
2357242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci} // namespace blink
236