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

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: Created 6 years, 9 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
Index: Source/core/rendering/InlineTextBox.cpp
diff --git a/Source/core/rendering/InlineTextBox.cpp b/Source/core/rendering/InlineTextBox.cpp
index dcb093c0379302ef922e0d75d88c12ff06442363..02e4ffa0cfd53df1c6f0c46dcf5eb6e784de9b09 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/AppliedTextDecorationList.h"
#include "core/rendering/style/ShadowList.h"
#include "core/rendering/svg/SVGTextRunRenderingContext.h"
#include "platform/fonts/FontCache.h"
@@ -751,12 +752,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));
}
@@ -916,8 +916,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.
const int gap = std::max<int>(1, ceilf(textDecorationThickness / 2.f));
@@ -928,10 +931,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;
}
}
@@ -1066,34 +1069,71 @@ static bool shouldSetDecorationAntialias(TextDecorationStyle decorationStyle)
return decorationStyle == TextDecorationStyleDotted || decorationStyle == TextDecorationStyleDashed;
}
-static bool shouldSetDecorationAntialias(TextDecorationStyle underline, TextDecorationStyle overline, TextDecorationStyle linethrough)
+static void getDecorationMetaData(const AppliedTextDecorationList* decorations, bool& linesAreOpaque, bool& setDecorationAntialias)
esprehn 2014/03/31 17:41:24 I might use a struct instead of all these out para
{
- return shouldSetDecorationAntialias(underline) || shouldSetDecorationAntialias(overline) || shouldSetDecorationAntialias(linethrough);
+ for (size_t i = 0; i < decorations->size(); ++i) {
esprehn 2014/03/31 17:41:24 Pass decorations by reference.
+ const AppliedTextDecoration& d = decorations->at(i);
+ linesAreOpaque &= (d.color().alpha() == 255);
+ setDecorationAntialias |= shouldSetDecorationAntialias(d.style());
+ }
}
-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;
esprehn 2014/03/31 17:41:24 Do we need a constructor that zero inits this thin
+};
+
+static void paintAppliedDecorationStyle(GraphicsContext* context, const AppliedTextDecoration& decoration, const PaintAppliedDecorationData& d, int wavyOffsetFactor)
esprehn 2014/03/31 17:41:24 Don't use single letter variable names.
{
- context->setStrokeStyle(textDecorationStyleToStrokeStyle(decoration.style));
- context->setStrokeColor(decoration.color);
+ context->setStrokeStyle(textDecorationStyleToStrokeStyle(decoration.style()));
+ context->setStrokeColor(decoration.color());
- switch (decoration.style) {
+ switch (decoration.style()) {
case TextDecorationStyleWavy:
- strokeWavyTextDecoration(context, start + FloatPoint(0, doubleOffset * wavyOffsetFactor), start + FloatPoint(width, doubleOffset * wavyOffsetFactor), thickness);
+ strokeWavyTextDecoration(context, d.start + FloatPoint(0, d.doubleOffset * wavyOffsetFactor), d.start + FloatPoint(d.width, d.doubleOffset * wavyOffsetFactor), d.thickness);
break;
case TextDecorationStyleDotted:
case TextDecorationStyleDashed:
- context->setShouldAntialias(antialiasDecoration);
+ context->setShouldAntialias(d.antialias);
// Fall through
default:
- context->drawLineForText(start, width, isPrinting);
+ context->drawLineForText(d.start, d.width, d.isPrinting);
- if (decoration.style == TextDecorationStyleDouble)
- context->drawLineForText(start + FloatPoint(0, doubleOffset), width, isPrinting);
+ if (decoration.style() == TextDecorationStyleDouble)
+ context->drawLineForText(d.start + FloatPoint(0, d.doubleOffset), d.width, d.isPrinting);
}
}
-void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, TextDecoration deco, const ShadowList* shadowList)
+void InlineTextBox::paintAppliedDecoration(GraphicsContext* context, const AppliedTextDecoration& decoration, const PaintAppliedDecorationData& d)
+{
+ PaintAppliedDecorationData data = d;
+ int wavyOffsetFactor = 1;
+
+ switch (decoration.line()) {
+ case TextDecorationUnderline:
+ data.start += FloatPoint(0, computeUnderlineOffset(d.style, d.thickness));
+ break;
+ case TextDecorationOverline:
+ data.doubleOffset *= -1;
+ break;
+ case TextDecorationLineThrough:
+ data.start += FloatPoint(0, (2 * d.baseline / 3));
+ wavyOffsetFactor = 0;
+ break;
+ default:
+ return;
+ }
+
+ paintAppliedDecorationStyle(context, decoration, data, wavyOffsetFactor);
+}
+
+void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* styleToUse, const ShadowList* shadowList)
{
GraphicsContextStateSaver stateSaver(*context);
@@ -1109,19 +1149,25 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint&
localOrigin.move(m_logicalWidth - width, 0);
}
- // Get the text decoration colors.
- RenderObject::AppliedTextDecoration underline, overline, linethrough;
+ const AppliedTextDecorationList* decorations = styleToUse->appliedTextDecorations();
- renderer().getTextDecorations(deco, underline, overline, linethrough, true);
- if (isFirstLineStyle())
- renderer().getTextDecorations(deco, underline, overline, linethrough, true, true);
+ // If appliedTextUnderline() is true, we must paint an extra underline
+ // before painting the other decorations.
+ AppliedTextDecoration underline;
+ if (styleToUse->appliedTextUnderline()) {
+ Color color = renderer().getUnderlineColor(true, isFirstLineStyle());
esprehn 2014/03/31 17:41:24 this boolean argument is confusing, can we use an
+ underline = AppliedTextDecoration(TextDecorationUnderline, TextDecorationStyleSolid, color);
+ }
// 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);
+ bool linesAreOpaque = !isPrinting;
+ bool setDecorationAntialias = false;
+
+ if (decorations)
+ getDecorationMetaData(decorations, linesAreOpaque, setDecorationAntialias);
- RenderStyle* styleToUse = renderer().style(isFirstLineStyle());
int baseline = styleToUse->fontMetrics().ascent();
size_t shadowCount = shadowList ? shadowList->shadows().size() : 0;
@@ -1136,8 +1182,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint&
context->setStrokeThickness(textDecorationThickness);
- bool antialiasDecoration = shouldSetDecorationAntialias(overline.style, underline.style, linethrough.style)
- && RenderBoxModelObject::shouldAntialiasLines(context);
+ bool antialiasDecoration = setDecorationAntialias && RenderBoxModelObject::shouldAntialiasLines(context);
float extraOffset = 0;
if (!linesAreOpaque && shadowCount > 1) {
@@ -1171,20 +1216,23 @@ 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;
+
+ if (styleToUse->appliedTextUnderline())
+ paintAppliedDecoration(context, underline, data);
+
+ if (decorations)
+ for (size_t i = 0; i < decorations->size(); ++i)
+ paintAppliedDecoration(context, decorations->at(i), data);
}
}

Powered by Google App Engine
This is Rietveld 408576698