Index: Source/core/rendering/InlineTextBox.cpp |
diff --git a/Source/core/rendering/InlineTextBox.cpp b/Source/core/rendering/InlineTextBox.cpp |
index 5762ce3bd23beaabbc731a1d5c3882d924d9ca70..98c3491b3d444ec8b082af642c61f079995e0a31 100644 |
--- a/Source/core/rendering/InlineTextBox.cpp |
+++ b/Source/core/rendering/InlineTextBox.cpp |
@@ -329,28 +329,6 @@ static Color textColorForWhiteBackground(Color textColor) |
return distanceFromWhite > 65025 ? textColor : textColor.dark(); |
} |
-static void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness) |
-{ |
- TextDrawingModeFlags mode = context->textDrawingMode(); |
- if (strokeThickness > 0) { |
- TextDrawingModeFlags newMode = mode | TextModeStroke; |
- if (mode != newMode) { |
- context->setTextDrawingMode(newMode); |
- mode = newMode; |
- } |
- } |
- |
- if (mode & TextModeFill && fillColor != context->fillColor()) |
- context->setFillColor(fillColor); |
- |
- if (mode & TextModeStroke) { |
- if (strokeColor != context->strokeColor()) |
- context->setStrokeColor(strokeColor); |
- if (strokeThickness != context->strokeThickness()) |
- context->setStrokeThickness(strokeThickness); |
- } |
-} |
- |
bool InlineTextBox::isLineBreak() const |
{ |
return renderer().isBR() || (renderer().style()->preserveNewline() && len() == 1 && (*renderer().text().impl())[start()] == '\n'); |
@@ -372,71 +350,6 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re |
return false; |
} |
-static void paintTextWithShadows(GraphicsContext* context, |
- const Font& font, const TextRun& textRun, |
- const AtomicString& emphasisMark, int emphasisMarkOffset, |
- int startOffset, int endOffset, int truncationPoint, |
- const FloatPoint& textOrigin, const FloatRect& boxRect, |
- const ShadowList* shadowList, bool horizontal) |
-{ |
- // Text shadows are disabled when printing. http://crbug.com/258321 |
- bool hasShadow = shadowList && !context->printing(); |
- if (hasShadow) |
- context->setDrawLooper(shadowList->createDrawLooper(DrawLooperBuilder::ShadowIgnoresAlpha, horizontal)); |
- |
- TextRunPaintInfo textRunPaintInfo(textRun); |
- textRunPaintInfo.bounds = boxRect; |
- if (startOffset <= endOffset) { |
- textRunPaintInfo.from = startOffset; |
- textRunPaintInfo.to = endOffset; |
- if (emphasisMark.isEmpty()) |
- context->drawText(font, textRunPaintInfo, textOrigin); |
- else |
- context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, textOrigin + IntSize(0, emphasisMarkOffset)); |
- } else { |
- if (endOffset > 0) { |
- textRunPaintInfo.from = 0; |
- textRunPaintInfo.to = endOffset; |
- if (emphasisMark.isEmpty()) |
- context->drawText(font, textRunPaintInfo, textOrigin); |
- else |
- context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, textOrigin + IntSize(0, emphasisMarkOffset)); |
- } |
- if (startOffset < truncationPoint) { |
- textRunPaintInfo.from = startOffset; |
- textRunPaintInfo.to = truncationPoint; |
- if (emphasisMark.isEmpty()) |
- context->drawText(font, textRunPaintInfo, textOrigin); |
- else |
- context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, textOrigin + IntSize(0, emphasisMarkOffset)); |
- } |
- } |
- |
- if (hasShadow) |
- context->clearDrawLooper(); |
-} |
- |
-static void paintEmphasisMark(GraphicsContext* context, |
- const AtomicString& emphasisMark, int emphasisMarkOffset, |
- int startOffset, int endOffset, int paintRunLength, |
- const Font& font, Color emphasisMarkColor, Color textStrokeColor, float textStrokeWidth, const ShadowList* textShadow, |
- RenderCombineText* combinedText, const TextRun& textRun, |
- const FloatPoint& textOrigin, const FloatRect& boxRect, bool horizontal) |
-{ |
- ASSERT(!emphasisMark.isEmpty()); |
- updateGraphicsContext(context, emphasisMarkColor, textStrokeColor, textStrokeWidth); |
- |
- if (combinedText) { |
- DEFINE_STATIC_LOCAL(TextRun, objectReplacementCharacterTextRun, (&objectReplacementCharacter, 1)); |
- FloatPoint emphasisMarkTextOrigin(boxRect.x() + boxRect.width() / 2, boxRect.y() + font.fontMetrics().ascent()); |
- context->concatCTM(InlineTextBox::rotation(boxRect, InlineTextBox::Clockwise)); |
- paintTextWithShadows(context, combinedText->originalFont(), objectReplacementCharacterTextRun, emphasisMark, emphasisMarkOffset, 0, 1, 1, emphasisMarkTextOrigin, boxRect, textShadow, horizontal); |
- context->concatCTM(InlineTextBox::rotation(boxRect, InlineTextBox::Counterclockwise)); |
- } else { |
- paintTextWithShadows(context, font, textRun, emphasisMark, emphasisMarkOffset, startOffset, endOffset, paintRunLength, textOrigin, boxRect, textShadow, horizontal); |
- } |
-} |
- |
bool InlineTextBox::getEmphasisMarkPosition(RenderStyle* style, TextEmphasisPosition& emphasisPosition) const |
{ |
// This function returns true if there are text emphasis marks and they are suppressed by ruby text. |
@@ -543,6 +456,107 @@ TextPaintingStyle selectionPaintingStyle(RenderText& renderer, bool haveSelectio |
return selectionStyle; |
} |
+void updateGraphicsContext(GraphicsContext* context, const TextPaintingStyle& textStyle, bool horizontal, GraphicsContextStateSaver& stateSaver) |
+{ |
+ TextDrawingModeFlags mode = context->textDrawingMode(); |
+ if (textStyle.strokeWidth > 0) { |
+ TextDrawingModeFlags newMode = mode | TextModeStroke; |
+ if (mode != newMode) { |
+ if (!stateSaver.saved()) |
+ stateSaver.save(); |
+ context->setTextDrawingMode(newMode); |
+ mode = newMode; |
+ } |
+ } |
+ |
+ if (mode & TextModeFill && textStyle.fillColor != context->fillColor()) |
+ context->setFillColor(textStyle.fillColor); |
+ |
+ if (mode & TextModeStroke) { |
+ if (textStyle.strokeColor != context->strokeColor()) |
+ context->setStrokeColor(textStyle.strokeColor); |
+ if (textStyle.strokeWidth != context->strokeThickness()) |
+ context->setStrokeThickness(textStyle.strokeWidth); |
+ } |
+ |
+ // Text shadows are disabled when printing. http://crbug.com/258321 |
+ if (textStyle.shadow && !context->printing()) { |
+ if (!stateSaver.saved()) |
+ stateSaver.save(); |
+ context->setDrawLooper(textStyle.shadow->createDrawLooper(DrawLooperBuilder::ShadowIgnoresAlpha, horizontal)); |
+ } |
+} |
+ |
+void paintText(GraphicsContext* context, |
+ const Font& font, const TextRun& textRun, |
+ const AtomicString& emphasisMark, int emphasisMarkOffset, |
+ int startOffset, int endOffset, int truncationPoint, |
+ const FloatPoint& textOrigin, const FloatRect& boxRect) |
+{ |
+ TextRunPaintInfo textRunPaintInfo(textRun); |
+ textRunPaintInfo.bounds = boxRect; |
+ if (startOffset <= endOffset) { |
+ textRunPaintInfo.from = startOffset; |
+ textRunPaintInfo.to = endOffset; |
+ if (emphasisMark.isEmpty()) |
+ context->drawText(font, textRunPaintInfo, textOrigin); |
+ else |
+ context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, textOrigin + IntSize(0, emphasisMarkOffset)); |
+ } else { |
+ if (endOffset > 0) { |
+ textRunPaintInfo.from = 0; |
+ textRunPaintInfo.to = endOffset; |
+ if (emphasisMark.isEmpty()) |
+ context->drawText(font, textRunPaintInfo, textOrigin); |
+ else |
+ context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, textOrigin + IntSize(0, emphasisMarkOffset)); |
+ } |
+ if (startOffset < truncationPoint) { |
+ textRunPaintInfo.from = startOffset; |
+ textRunPaintInfo.to = truncationPoint; |
+ if (emphasisMark.isEmpty()) |
+ context->drawText(font, textRunPaintInfo, textOrigin); |
+ else |
+ context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, textOrigin + IntSize(0, emphasisMarkOffset)); |
+ } |
+ } |
+} |
+ |
+inline void paintEmphasisMark(GraphicsContext* context, |
+ const AtomicString& emphasisMark, int emphasisMarkOffset, |
+ int startOffset, int endOffset, int paintRunLength, |
+ const Font& font, RenderCombineText* combinedText, const TextRun& textRun, |
+ const FloatPoint& textOrigin, const FloatRect& boxRect) |
+{ |
+ ASSERT(!emphasisMark.isEmpty()); |
+ |
+ if (combinedText) { |
+ DEFINE_STATIC_LOCAL(TextRun, objectReplacementCharacterTextRun, (&objectReplacementCharacter, 1)); |
+ FloatPoint emphasisMarkTextOrigin(boxRect.x() + boxRect.width() / 2, boxRect.y() + font.fontMetrics().ascent()); |
+ context->concatCTM(InlineTextBox::rotation(boxRect, InlineTextBox::Clockwise)); |
+ paintText(context, combinedText->originalFont(), objectReplacementCharacterTextRun, emphasisMark, emphasisMarkOffset, 0, 1, 1, emphasisMarkTextOrigin, boxRect); |
+ context->concatCTM(InlineTextBox::rotation(boxRect, InlineTextBox::Counterclockwise)); |
+ } else { |
+ paintText(context, font, textRun, emphasisMark, emphasisMarkOffset, startOffset, endOffset, paintRunLength, textOrigin, boxRect); |
+ } |
+} |
+ |
+void paintTextWithEmphasisMark( |
+ GraphicsContext* context, const Font& font, const TextPaintingStyle& textStyle, const TextRun& textRun, |
+ const AtomicString& emphasisMark, int emphasisMarkOffset, int startOffset, int endOffset, int length, |
+ RenderCombineText* combinedText, const FloatPoint& textOrigin, const FloatRect& boxRect, bool horizontal) |
+{ |
+ GraphicsContextStateSaver stateSaver(*context, false); |
+ updateGraphicsContext(context, textStyle, horizontal, stateSaver); |
+ paintText(context, font, textRun, nullAtom, 0, startOffset, endOffset, length, textOrigin, boxRect); |
+ |
+ if (!emphasisMark.isEmpty()) { |
+ if (textStyle.emphasisMarkColor != textStyle.fillColor) |
+ context->setFillColor(textStyle.emphasisMarkColor); |
+ paintEmphasisMark(context, emphasisMark, emphasisMarkOffset, startOffset, endOffset, length, font, combinedText, textRun, textOrigin, boxRect); |
+ } |
+} |
+ |
} // namespace |
void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /*lineTop*/, LayoutUnit /*lineBottom*/) |
@@ -687,36 +701,22 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, |
startOffset = ePos; |
endOffset = sPos; |
} |
- |
- // For stroked painting, we have to change the text drawing mode. It's probably dangerous to leave that mutated as a side |
- // effect, so only when we know we're stroking, do a save/restore. |
- GraphicsContextStateSaver stateSaver(*context, textStyle.strokeWidth > 0); |
- |
- updateGraphicsContext(context, textStyle.fillColor, textStyle.strokeColor, textStyle.strokeWidth); |
- paintTextWithShadows(context, font, textRun, nullAtom, 0, startOffset, endOffset, length, textOrigin, boxRect, textStyle.shadow, isHorizontal()); |
- |
- if (!emphasisMark.isEmpty()) |
- paintEmphasisMark(context, emphasisMark, emphasisMarkOffset, startOffset, endOffset, length, font, textStyle.emphasisMarkColor, textStyle.strokeColor, textStyle.strokeWidth, textStyle.shadow, combinedText, textRun, textOrigin, boxRect, isHorizontal()); |
+ paintTextWithEmphasisMark(context, font, textStyle, textRun, emphasisMark, emphasisMarkOffset, startOffset, endOffset, length, combinedText, textOrigin, boxRect, isHorizontal()); |
} |
if ((paintSelectedTextOnly || paintSelectedTextSeparately) && sPos < ePos) { |
// paint only the text that is selected |
- GraphicsContextStateSaver stateSaver(*context, selectionStyle.strokeWidth > 0); |
- |
- updateGraphicsContext(context, selectionStyle.fillColor, selectionStyle.strokeColor, selectionStyle.strokeWidth); |
- paintTextWithShadows(context, font, textRun, nullAtom, 0, sPos, ePos, length, textOrigin, boxRect, selectionStyle.shadow, isHorizontal()); |
- |
- if (!emphasisMark.isEmpty()) |
- paintEmphasisMark(context, emphasisMark, emphasisMarkOffset, sPos, ePos, length, font, selectionStyle.emphasisMarkColor, selectionStyle.strokeColor, textStyle.strokeWidth, selectionStyle.shadow, combinedText, textRun, textOrigin, boxRect, isHorizontal()); |
+ paintTextWithEmphasisMark(context, font, selectionStyle, textRun, emphasisMark, emphasisMarkOffset, sPos, ePos, length, combinedText, textOrigin, boxRect, isHorizontal()); |
} |
// Paint decorations |
TextDecoration textDecorations = styleToUse->textDecorationsInEffect(); |
- if (textDecorations != TextDecorationNone && paintInfo.phase != PaintPhaseSelection) { |
- updateGraphicsContext(context, textStyle.fillColor, textStyle.strokeColor, textStyle.strokeWidth); |
+ if (textDecorations != TextDecorationNone && !paintSelectedTextOnly) { |
+ GraphicsContextStateSaver stateSaver(*context, false); |
+ updateGraphicsContext(context, textStyle, isHorizontal(), stateSaver); |
if (combinedText) |
context->concatCTM(rotation(boxRect, Clockwise)); |
- paintDecoration(context, boxOrigin, textDecorations, textStyle.shadow); |
+ paintDecoration(context, boxOrigin, textDecorations); |
if (combinedText) |
context->concatCTM(rotation(boxRect, Counterclockwise)); |
} |
@@ -775,7 +775,6 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& b |
if (textColor == c) |
c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue()); |
- |
// If the text is truncated, let the thing being painted in the truncation |
// draw its own highlight. |
int length = m_truncation != cNoTruncation ? m_truncation : m_len; |
@@ -1042,7 +1041,7 @@ static void paintAppliedDecoration(GraphicsContext* context, FloatPoint start, f |
} |
} |
-void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, TextDecoration deco, const ShadowList* shadowList) |
+void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, TextDecoration deco) |
{ |
GraphicsContextStateSaver stateSaver(*context); |
@@ -1060,7 +1059,6 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& |
// Get the text decoration colors. |
RenderObject::AppliedTextDecoration underline, overline, linethrough; |
- |
renderer().getTextDecorations(deco, underline, overline, linethrough, true); |
if (isFirstLineStyle()) |
renderer().getTextDecorations(deco, underline, overline, linethrough, true, true); |
@@ -1068,12 +1066,9 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& |
// Use a special function for underlines to get the positioning exactly right. |
bool isPrinting = renderer().document().printing(); |
- bool linesAreOpaque = !isPrinting && (!(deco & TextDecorationUnderline) || underline.color.alpha() == 255) && (!(deco & TextDecorationOverline) || overline.color.alpha() == 255) && (!(deco & TextDecorationLineThrough) || linethrough.color.alpha() == 255); |
- |
RenderStyle* styleToUse = renderer().style(isFirstLineStyle()); |
int baseline = styleToUse->fontMetrics().ascent(); |
- size_t shadowCount = shadowList ? shadowList->shadows().size() : 0; |
// Set the thick of the line to be 10% (or something else ?)of the computed font size and not less than 1px. |
// Using computedFontSize should take care of zoom as well. |
@@ -1088,52 +1083,19 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& |
bool antialiasDecoration = shouldSetDecorationAntialias(overline.style, underline.style, linethrough.style) |
&& RenderBoxModelObject::shouldAntialiasLines(context); |
- float extraOffset = 0; |
- if (!linesAreOpaque && shadowCount > 1) { |
- FloatRect clipRect(localOrigin, FloatSize(width, baseline + 2)); |
- for (size_t i = shadowCount; i--; ) { |
- const ShadowData& s = shadowList->shadows()[i]; |
- FloatRect shadowRect(localOrigin, FloatSize(width, baseline + 2)); |
- shadowRect.inflate(s.blur()); |
- float shadowX = isHorizontal() ? s.x() : s.y(); |
- float shadowY = isHorizontal() ? s.y() : -s.x(); |
- shadowRect.move(shadowX, shadowY); |
- clipRect.unite(shadowRect); |
- extraOffset = std::max(extraOffset, std::max(0.0f, shadowY) + s.blur()); |
- } |
- context->clip(clipRect); |
- extraOffset += baseline + 2; |
- localOrigin.move(0, extraOffset); |
- } |
- |
- for (size_t i = std::max(static_cast<size_t>(1), shadowCount); i--; ) { |
- // Even if we have no shadows, we still want to run the code below this once. |
- if (i < shadowCount) { |
- if (!i) { |
- // The last set of lines paints normally inside the clip. |
- localOrigin.move(0, -extraOffset); |
- extraOffset = 0; |
- } |
- const ShadowData& shadow = shadowList->shadows()[i]; |
- float shadowX = isHorizontal() ? shadow.x() : shadow.y(); |
- float shadowY = isHorizontal() ? shadow.y() : -shadow.x(); |
- context->setShadow(FloatSize(shadowX, shadowY - extraOffset), shadow.blur(), shadow.color()); |
- } |
+ // Offset between lines - always non-zero, so lines never cross each other. |
+ float doubleOffset = textDecorationThickness + 1.f; |
- // Offset between lines - always non-zero, so lines never cross each other. |
- float doubleOffset = textDecorationThickness + 1.f; |
- |
- if (deco & TextDecorationUnderline) { |
- const int underlineOffset = computeUnderlineOffset(styleToUse->textUnderlinePosition(), styleToUse->fontMetrics(), this, textDecorationThickness); |
- paintAppliedDecoration(context, localOrigin + FloatPoint(0, underlineOffset), width, doubleOffset, 1, underline, textDecorationThickness, antialiasDecoration, isPrinting); |
- } |
- if (deco & TextDecorationOverline) { |
- paintAppliedDecoration(context, localOrigin, width, -doubleOffset, 1, overline, textDecorationThickness, antialiasDecoration, isPrinting); |
- } |
- if (deco & TextDecorationLineThrough) { |
- const float lineThroughOffset = 2 * baseline / 3; |
- paintAppliedDecoration(context, localOrigin + FloatPoint(0, lineThroughOffset), width, doubleOffset, 0, linethrough, textDecorationThickness, antialiasDecoration, isPrinting); |
- } |
+ if (deco & TextDecorationUnderline) { |
+ const int underlineOffset = computeUnderlineOffset(styleToUse->textUnderlinePosition(), styleToUse->fontMetrics(), this, textDecorationThickness); |
+ paintAppliedDecoration(context, localOrigin + FloatPoint(0, underlineOffset), width, doubleOffset, 1, underline, textDecorationThickness, antialiasDecoration, isPrinting); |
+ } |
+ if (deco & TextDecorationOverline) { |
+ paintAppliedDecoration(context, localOrigin, width, -doubleOffset, 1, overline, textDecorationThickness, antialiasDecoration, isPrinting); |
+ } |
+ if (deco & TextDecorationLineThrough) { |
+ const float lineThroughOffset = 2 * baseline / 3; |
+ paintAppliedDecoration(context, localOrigin + FloatPoint(0, lineThroughOffset), width, doubleOffset, 0, linethrough, textDecorationThickness, antialiasDecoration, isPrinting); |
} |
} |