| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "config.h" | |
| 6 #include "core/rendering/TextPainter.h" | |
| 7 | |
| 8 #include "core/CSSPropertyNames.h" | |
| 9 #include "core/frame/Settings.h" | |
| 10 #include "core/rendering/InlineTextBox.h" | |
| 11 #include "core/rendering/RenderCombineText.h" | |
| 12 #include "core/rendering/RenderObject.h" | |
| 13 #include "core/rendering/style/RenderStyle.h" | |
| 14 #include "core/rendering/style/ShadowList.h" | |
| 15 #include "platform/fonts/Font.h" | |
| 16 #include "platform/graphics/GraphicsContext.h" | |
| 17 #include "platform/graphics/GraphicsContextStateSaver.h" | |
| 18 #include "platform/text/TextRun.h" | |
| 19 #include "wtf/Assertions.h" | |
| 20 #include "wtf/unicode/CharacterNames.h" | |
| 21 | |
| 22 namespace blink { | |
| 23 | |
| 24 TextPainter::TextPainter(GraphicsContext* context, const Font& font, const TextR
un& run, const FloatPoint& textOrigin, const FloatRect& textBounds, bool horizon
tal) | |
| 25 : m_graphicsContext(context) | |
| 26 , m_font(font) | |
| 27 , m_run(run) | |
| 28 , m_textOrigin(textOrigin) | |
| 29 , m_textBounds(textBounds) | |
| 30 , m_horizontal(horizontal) | |
| 31 , m_emphasisMarkOffset(0) | |
| 32 , m_combinedText(0) | |
| 33 { | |
| 34 } | |
| 35 | |
| 36 TextPainter::~TextPainter() | |
| 37 { | |
| 38 } | |
| 39 | |
| 40 void TextPainter::setEmphasisMark(const AtomicString& emphasisMark, TextEmphasis
Position position) | |
| 41 { | |
| 42 m_emphasisMark = emphasisMark; | |
| 43 | |
| 44 if (emphasisMark.isNull()) { | |
| 45 m_emphasisMarkOffset = 0; | |
| 46 } else if (position == TextEmphasisPositionOver) { | |
| 47 m_emphasisMarkOffset = -m_font.fontMetrics().ascent() - m_font.emphasisM
arkDescent(emphasisMark); | |
| 48 } else { | |
| 49 ASSERT(position == TextEmphasisPositionUnder); | |
| 50 m_emphasisMarkOffset = m_font.fontMetrics().descent() + m_font.emphasisM
arkAscent(emphasisMark); | |
| 51 } | |
| 52 } | |
| 53 | |
| 54 void TextPainter::paint(int startOffset, int endOffset, int length, const Style&
textStyle, TextBlobPtr* cachedTextBlob) | |
| 55 { | |
| 56 GraphicsContextStateSaver stateSaver(*m_graphicsContext, false); | |
| 57 updateGraphicsContext(textStyle, stateSaver); | |
| 58 paintInternal<PaintText>(startOffset, endOffset, length, cachedTextBlob); | |
| 59 | |
| 60 if (!m_emphasisMark.isEmpty()) { | |
| 61 if (textStyle.emphasisMarkColor != textStyle.fillColor) | |
| 62 m_graphicsContext->setFillColor(textStyle.emphasisMarkColor); | |
| 63 | |
| 64 if (m_combinedText) | |
| 65 paintEmphasisMarkForCombinedText(); | |
| 66 else | |
| 67 paintInternal<PaintEmphasisMark>(startOffset, endOffset, length); | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 // static | |
| 72 void TextPainter::updateGraphicsContext(GraphicsContext* context, const Style& t
extStyle, bool horizontal, GraphicsContextStateSaver& stateSaver) | |
| 73 { | |
| 74 TextDrawingModeFlags mode = context->textDrawingMode(); | |
| 75 if (textStyle.strokeWidth > 0) { | |
| 76 TextDrawingModeFlags newMode = mode | TextModeStroke; | |
| 77 if (mode != newMode) { | |
| 78 if (!stateSaver.saved()) | |
| 79 stateSaver.save(); | |
| 80 context->setTextDrawingMode(newMode); | |
| 81 mode = newMode; | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 if (mode & TextModeFill && textStyle.fillColor != context->fillColor()) | |
| 86 context->setFillColor(textStyle.fillColor); | |
| 87 | |
| 88 if (mode & TextModeStroke) { | |
| 89 if (textStyle.strokeColor != context->strokeColor()) | |
| 90 context->setStrokeColor(textStyle.strokeColor); | |
| 91 if (textStyle.strokeWidth != context->strokeThickness()) | |
| 92 context->setStrokeThickness(textStyle.strokeWidth); | |
| 93 } | |
| 94 | |
| 95 // Text shadows are disabled when printing. http://crbug.com/258321 | |
| 96 if (textStyle.shadow && !context->printing()) { | |
| 97 if (!stateSaver.saved()) | |
| 98 stateSaver.save(); | |
| 99 context->setDrawLooper(textStyle.shadow->createDrawLooper(DrawLooperBuil
der::ShadowIgnoresAlpha, horizontal)); | |
| 100 } | |
| 101 } | |
| 102 | |
| 103 static Color textColorForWhiteBackground(Color textColor) | |
| 104 { | |
| 105 int distanceFromWhite = differenceSquared(textColor, Color::white); | |
| 106 // semi-arbitrarily chose 65025 (255^2) value here after a few tests; | |
| 107 return distanceFromWhite > 65025 ? textColor : textColor.dark(); | |
| 108 } | |
| 109 | |
| 110 // static | |
| 111 TextPainter::Style TextPainter::textPaintingStyle(RenderObject& renderer, Render
Style* style, bool forceBlackText, bool isPrinting) | |
| 112 { | |
| 113 TextPainter::Style textStyle; | |
| 114 | |
| 115 if (forceBlackText) { | |
| 116 textStyle.fillColor = Color::black; | |
| 117 textStyle.strokeColor = Color::black; | |
| 118 textStyle.emphasisMarkColor = Color::black; | |
| 119 textStyle.strokeWidth = style->textStrokeWidth(); | |
| 120 textStyle.shadow = 0; | |
| 121 } else { | |
| 122 textStyle.fillColor = renderer.resolveColor(style, CSSPropertyWebkitText
FillColor); | |
| 123 textStyle.strokeColor = renderer.resolveColor(style, CSSPropertyWebkitTe
xtStrokeColor); | |
| 124 textStyle.emphasisMarkColor = renderer.resolveColor(style, CSSPropertyWe
bkitTextEmphasisColor); | |
| 125 textStyle.strokeWidth = style->textStrokeWidth(); | |
| 126 textStyle.shadow = style->textShadow(); | |
| 127 | |
| 128 // Adjust text color when printing with a white background. | |
| 129 bool forceBackgroundToWhite = false; | |
| 130 if (isPrinting) { | |
| 131 if (style->printColorAdjust() == PrintColorAdjustEconomy) | |
| 132 forceBackgroundToWhite = true; | |
| 133 if (renderer.document().settings() && renderer.document().settings()
->shouldPrintBackgrounds()) | |
| 134 forceBackgroundToWhite = false; | |
| 135 } | |
| 136 if (forceBackgroundToWhite) { | |
| 137 textStyle.fillColor = textColorForWhiteBackground(textStyle.fillColo
r); | |
| 138 textStyle.strokeColor = textColorForWhiteBackground(textStyle.stroke
Color); | |
| 139 textStyle.emphasisMarkColor = textColorForWhiteBackground(textStyle.
emphasisMarkColor); | |
| 140 } | |
| 141 | |
| 142 // Text shadows are disabled when printing. http://crbug.com/258321 | |
| 143 if (isPrinting) | |
| 144 textStyle.shadow = 0; | |
| 145 } | |
| 146 | |
| 147 return textStyle; | |
| 148 } | |
| 149 | |
| 150 TextPainter::Style TextPainter::selectionPaintingStyle(RenderObject& renderer, b
ool haveSelection, bool forceBlackText, bool isPrinting, const TextPainter::Styl
e& textStyle) | |
| 151 { | |
| 152 TextPainter::Style selectionStyle = textStyle; | |
| 153 | |
| 154 if (haveSelection) { | |
| 155 if (!forceBlackText) { | |
| 156 selectionStyle.fillColor = renderer.selectionForegroundColor(); | |
| 157 selectionStyle.emphasisMarkColor = renderer.selectionEmphasisMarkCol
or(); | |
| 158 } | |
| 159 | |
| 160 if (RenderStyle* pseudoStyle = renderer.getCachedPseudoStyle(SELECTION))
{ | |
| 161 selectionStyle.strokeColor = forceBlackText ? Color::black : rendere
r.resolveColor(pseudoStyle, CSSPropertyWebkitTextStrokeColor); | |
| 162 selectionStyle.strokeWidth = pseudoStyle->textStrokeWidth(); | |
| 163 selectionStyle.shadow = forceBlackText ? 0 : pseudoStyle->textShadow
(); | |
| 164 } | |
| 165 | |
| 166 // Text shadows are disabled when printing. http://crbug.com/258321 | |
| 167 if (isPrinting) | |
| 168 selectionStyle.shadow = 0; | |
| 169 } | |
| 170 | |
| 171 return selectionStyle; | |
| 172 } | |
| 173 | |
| 174 template <TextPainter::PaintInternalStep step> | |
| 175 void TextPainter::paintInternalRun(TextRunPaintInfo& textRunPaintInfo, int from,
int to) | |
| 176 { | |
| 177 textRunPaintInfo.from = from; | |
| 178 textRunPaintInfo.to = to; | |
| 179 | |
| 180 if (step == PaintEmphasisMark) { | |
| 181 m_graphicsContext->drawEmphasisMarks(m_font, textRunPaintInfo, m_emphasi
sMark, | |
| 182 m_textOrigin + IntSize(0, m_emphasisMarkOffset)); | |
| 183 } else { | |
| 184 ASSERT(step == PaintText); | |
| 185 m_graphicsContext->drawText(m_font, textRunPaintInfo, m_textOrigin); | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 template <TextPainter::PaintInternalStep Step> | |
| 190 void TextPainter::paintInternal(int startOffset, int endOffset, int truncationPo
int, TextBlobPtr* cachedTextBlob) | |
| 191 { | |
| 192 TextRunPaintInfo textRunPaintInfo(m_run); | |
| 193 textRunPaintInfo.bounds = m_textBounds; | |
| 194 if (startOffset <= endOffset) { | |
| 195 // FIXME: We should be able to use cachedTextBlob in more cases. | |
| 196 textRunPaintInfo.cachedTextBlob = cachedTextBlob; | |
| 197 paintInternalRun<Step>(textRunPaintInfo, startOffset, endOffset); | |
| 198 } else { | |
| 199 if (endOffset > 0) | |
| 200 paintInternalRun<Step>(textRunPaintInfo, 0, endOffset); | |
| 201 if (startOffset < truncationPoint) | |
| 202 paintInternalRun<Step>(textRunPaintInfo, startOffset, truncationPoin
t); | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 void TextPainter::paintEmphasisMarkForCombinedText() | |
| 207 { | |
| 208 ASSERT(m_combinedText); | |
| 209 DEFINE_STATIC_LOCAL(TextRun, placeholderTextRun, (&ideographicFullStop, 1)); | |
| 210 FloatPoint emphasisMarkTextOrigin(m_textBounds.x(), m_textBounds.y() + m_fon
t.fontMetrics().ascent() + m_emphasisMarkOffset); | |
| 211 TextRunPaintInfo textRunPaintInfo(placeholderTextRun); | |
| 212 textRunPaintInfo.bounds = m_textBounds; | |
| 213 m_graphicsContext->concatCTM(InlineTextBox::rotation(m_textBounds, InlineTex
tBox::Clockwise)); | |
| 214 m_graphicsContext->drawEmphasisMarks(m_combinedText->originalFont(), textRun
PaintInfo, m_emphasisMark, emphasisMarkTextOrigin); | |
| 215 m_graphicsContext->concatCTM(InlineTextBox::rotation(m_textBounds, InlineTex
tBox::Counterclockwise)); | |
| 216 } | |
| 217 | |
| 218 } // namespace blink | |
| OLD | NEW |