Index: Source/core/rendering/InlineTextBox.cpp |
diff --git a/Source/core/rendering/InlineTextBox.cpp b/Source/core/rendering/InlineTextBox.cpp |
index 147733f6e5e9c2866b1972466acd9e7d7a515d74..bb253f1ef8c792cbc24d8aa7f6d87b82b6d30b06 100644 |
--- a/Source/core/rendering/InlineTextBox.cpp |
+++ b/Source/core/rendering/InlineTextBox.cpp |
@@ -42,6 +42,7 @@ |
#include "core/rendering/RenderRubyRun.h" |
#include "core/rendering/RenderRubyText.h" |
#include "core/rendering/RenderTheme.h" |
+#include "core/rendering/style/AppliedTextDecoration.h" |
#include "core/rendering/style/ShadowList.h" |
#include "core/rendering/svg/SVGTextRunRenderingContext.h" |
#include "platform/fonts/FontCache.h" |
@@ -749,12 +750,11 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, |
} |
// Paint decorations |
- TextDecoration textDecorations = styleToUse->textDecorationsInEffect(); |
- if (textDecorations != TextDecorationNone && paintInfo.phase != PaintPhaseSelection) { |
+ if (styleToUse->hasAppliedTextDecorations() && paintInfo.phase != PaintPhaseSelection) { |
updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth); |
if (combinedText) |
context->concatCTM(rotation(boxRect, Clockwise)); |
- paintDecoration(context, boxOrigin, textDecorations, textShadow); |
+ paintDecoration(context, boxOrigin, styleToUse, textShadow); |
if (combinedText) |
context->concatCTM(rotation(boxRect, Counterclockwise)); |
} |
@@ -914,8 +914,11 @@ static StrokeStyle textDecorationStyleToStrokeStyle(TextDecorationStyle decorati |
return strokeStyle; |
} |
-static int computeUnderlineOffset(const TextUnderlinePosition underlinePosition, const FontMetrics& fontMetrics, const InlineTextBox* inlineTextBox, const float textDecorationThickness) |
+int InlineTextBox::computeUnderlineOffset(RenderStyle* style, const float textDecorationThickness) |
{ |
+ const TextUnderlinePosition underlinePosition = style->textUnderlinePosition(); |
+ const FontMetrics& fontMetrics = style->fontMetrics(); |
+ |
// Compute the gap between the font and the underline. Use at least one |
// pixel gap, if underline is thick then use a bigger gap. |
int gap = 0; |
@@ -937,10 +940,10 @@ static int computeUnderlineOffset(const TextUnderlinePosition underlinePosition, |
return fontMetrics.ascent() + gap; // Position underline near the alphabetic baseline. |
case TextUnderlinePositionUnder: { |
// Position underline relative to the under edge of the lowest element's content box. |
- const float offset = inlineTextBox->root().maxLogicalTop() - inlineTextBox->logicalTop(); |
+ const float offset = root().maxLogicalTop() - logicalTop(); |
if (offset > 0) |
- return inlineTextBox->logicalHeight() + gap + offset; |
- return inlineTextBox->logicalHeight() + gap; |
+ return logicalHeight() + gap + offset; |
+ return logicalHeight() + gap; |
} |
} |
@@ -1075,34 +1078,95 @@ static bool shouldSetDecorationAntialias(TextDecorationStyle decorationStyle) |
return decorationStyle == TextDecorationStyleDotted || decorationStyle == TextDecorationStyleDashed; |
} |
-static bool shouldSetDecorationAntialias(TextDecorationStyle underline, TextDecorationStyle overline, TextDecorationStyle linethrough) |
+struct DecorationMetadata { |
+ bool linesAreOpaque; |
+ bool setDecorationAntialias; |
+ |
+ DecorationMetadata() |
+ : linesAreOpaque(true) |
+ , setDecorationAntialias(false) |
+ { } |
+}; |
+ |
+static DecorationMetadata getDecorationMetadata(RenderObject::ResolvedDecorationVector& decorations) |
{ |
- return shouldSetDecorationAntialias(underline) || shouldSetDecorationAntialias(overline) || shouldSetDecorationAntialias(linethrough); |
+ DecorationMetadata metadata; |
+ |
+ for (size_t i = 0; i < decorations.size(); ++i) { |
+ const RenderObject::ResolvedDecoration& decoration = decorations[i]; |
+ metadata.linesAreOpaque &= (decoration.color.alpha() == 255); |
+ metadata.setDecorationAntialias |= shouldSetDecorationAntialias(decoration.style); |
+ } |
+ |
+ return metadata; |
} |
-static void paintAppliedDecoration(GraphicsContext* context, FloatPoint start, float width, float doubleOffset, int wavyOffsetFactor, |
- RenderObject::AppliedTextDecoration decoration, float thickness, bool antialiasDecoration, bool isPrinting) |
+struct PaintAppliedDecorationData { |
+ RenderStyle* style; |
+ FloatPoint start; |
+ float width; |
+ float doubleOffset; |
+ float thickness; |
+ bool antialias; |
+ bool isPrinting; |
+ int baseline; |
+ |
+ PaintAppliedDecorationData() |
+ : style(nullptr) |
+ , width(0) |
+ , doubleOffset(0) |
+ , thickness(0) |
+ , antialias(false) |
+ , isPrinting(false) |
+ , baseline(0) |
+ { } |
+}; |
+ |
+static void paintAppliedDecorationStyle(GraphicsContext* context, const RenderObject::ResolvedDecoration& decoration, const PaintAppliedDecorationData& data, int wavyOffsetFactor) |
{ |
context->setStrokeStyle(textDecorationStyleToStrokeStyle(decoration.style)); |
context->setStrokeColor(decoration.color); |
switch (decoration.style) { |
case TextDecorationStyleWavy: |
- strokeWavyTextDecoration(context, start + FloatPoint(0, doubleOffset * wavyOffsetFactor), start + FloatPoint(width, doubleOffset * wavyOffsetFactor), thickness); |
+ strokeWavyTextDecoration(context, data.start + FloatPoint(0, data.doubleOffset * wavyOffsetFactor), data.start + FloatPoint(data.width, data.doubleOffset * wavyOffsetFactor), data.thickness); |
break; |
case TextDecorationStyleDotted: |
case TextDecorationStyleDashed: |
- context->setShouldAntialias(antialiasDecoration); |
+ context->setShouldAntialias(data.antialias); |
// Fall through |
default: |
- context->drawLineForText(start, width, isPrinting); |
+ context->drawLineForText(data.start, data.width, data.isPrinting); |
if (decoration.style == TextDecorationStyleDouble) |
- context->drawLineForText(start + FloatPoint(0, doubleOffset), width, isPrinting); |
+ context->drawLineForText(data.start + FloatPoint(0, data.doubleOffset), data.width, data.isPrinting); |
} |
} |
-void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, TextDecoration deco, const ShadowList* shadowList) |
+void InlineTextBox::paintAppliedDecoration(GraphicsContext* context, const RenderObject::ResolvedDecoration& decoration, const PaintAppliedDecorationData& data) |
+{ |
+ PaintAppliedDecorationData outData = data; |
+ int wavyOffsetFactor = 1; |
+ |
+ switch (decoration.line) { |
+ case TextDecorationUnderline: |
+ outData.start += FloatPoint(0, computeUnderlineOffset(data.style, data.thickness)); |
+ break; |
+ case TextDecorationOverline: |
+ outData.doubleOffset *= -1; |
+ break; |
+ case TextDecorationLineThrough: |
+ outData.start += FloatPoint(0, (2 * data.baseline / 3)); |
+ wavyOffsetFactor = 0; |
+ break; |
+ default: |
+ return; |
+ } |
+ |
+ paintAppliedDecorationStyle(context, decoration, outData, wavyOffsetFactor); |
+} |
+ |
+void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* styleToUse, const ShadowList* shadowList) |
{ |
GraphicsContextStateSaver stateSaver(*context); |
@@ -1118,19 +1182,15 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& |
localOrigin.move(m_logicalWidth - width, 0); |
} |
- // 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); |
+ const Vector<AppliedTextDecoration>& decorations = styleToUse->appliedTextDecorations(); |
+ RenderObject::ResolvedDecorationVector resolvedDecorations; |
+ renderer().resolvedDecorations(isFirstLineStyle(), decorations, resolvedDecorations); |
// Use a special function for underlines to get the positioning exactly right. |
bool isPrinting = textRenderer().document().printing(); |
- bool linesAreOpaque = !isPrinting && (!(deco & TextDecorationUnderline) || underline.color.alpha() == 255) && (!(deco & TextDecorationOverline) || overline.color.alpha() == 255) && (!(deco & TextDecorationLineThrough) || linethrough.color.alpha() == 255); |
+ DecorationMetadata metadata = getDecorationMetadata(resolvedDecorations); |
- RenderStyle* styleToUse = renderer().style(isFirstLineStyle()); |
int baseline = styleToUse->fontMetrics().ascent(); |
size_t shadowCount = shadowList ? shadowList->shadows().size() : 0; |
@@ -1145,11 +1205,10 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& |
context->setStrokeThickness(textDecorationThickness); |
- bool antialiasDecoration = shouldSetDecorationAntialias(overline.style, underline.style, linethrough.style) |
- && RenderBoxModelObject::shouldAntialiasLines(context); |
+ bool antialiasDecoration = metadata.setDecorationAntialias && RenderBoxModelObject::shouldAntialiasLines(context); |
float extraOffset = 0; |
- if (!linesAreOpaque && shadowCount > 1) { |
+ if ((!metadata.linesAreOpaque || isPrinting) && shadowCount > 1) { |
FloatRect clipRect(localOrigin, FloatSize(width, baseline + 2)); |
for (size_t i = shadowCount; i--; ) { |
const ShadowData& s = shadowList->shadows()[i]; |
@@ -1180,20 +1239,19 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& |
context->setShadow(FloatSize(shadowX, shadowY - extraOffset), shadow.blur(), shadow.color()); |
} |
+ PaintAppliedDecorationData data; |
+ data.style = styleToUse; |
+ data.start = localOrigin; |
+ data.width = width; |
// 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); |
- } |
+ data.doubleOffset = textDecorationThickness + 1.f; |
+ data.thickness = textDecorationThickness; |
+ data.antialias = antialiasDecoration; |
+ data.isPrinting = isPrinting; |
+ data.baseline = baseline; |
+ |
+ for (auto decoration = resolvedDecorations.rbegin(); decoration != resolvedDecorations.rend(); ++decoration) |
+ paintAppliedDecoration(context, *decoration, data); |
} |
} |