Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(810)

Unified Diff: Source/core/rendering/InlineTextBox.cpp

Issue 219633002: Proper support for multiple text decorations. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Fix jchaffraix' issues. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/rendering/InlineTextBox.h ('k') | Source/core/rendering/RenderObject.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
}
}
« no previous file with comments | « Source/core/rendering/InlineTextBox.h ('k') | Source/core/rendering/RenderObject.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698