| 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);
|
| }
|
| }
|
|
|
|
|