| Index: third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
|
| diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
|
| index 74ab1cdcb364fac4aa096e894b0cafe327e13678..8782e0b7c67e0e0a1aee1efedb9b4b85148ef5ab 100644
|
| --- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
|
| +++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
|
| @@ -22,6 +22,327 @@
|
|
|
| namespace blink {
|
|
|
| +static int computeUnderlineOffset(const TextUnderlinePosition underlinePosition,
|
| + const FontMetrics& fontMetrics,
|
| + const InlineTextBox* inlineTextBox,
|
| + const float textDecorationThickness) {
|
| + // 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;
|
| +
|
| + // Underline position of zero means draw underline on Baseline Position,
|
| + // in Blink we need at least 1-pixel gap to adding following check.
|
| + // Positive underline Position means underline should be drawn above baselin e
|
| + // and negative value means drawing below baseline, negating the value as in
|
| + // Blink
|
| + // downward Y-increases.
|
| +
|
| + if (fontMetrics.underlinePosition())
|
| + gap = -fontMetrics.underlinePosition();
|
| + else
|
| + gap = std::max<int>(1, ceilf(textDecorationThickness / 2.f));
|
| +
|
| + // FIXME: We support only horizontal text for now.
|
| + switch (underlinePosition) {
|
| + case TextUnderlinePositionAuto:
|
| + 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 LayoutUnit offset =
|
| + inlineTextBox->root().maxLogicalTop() - inlineTextBox->logicalTop();
|
| + if (offset > 0)
|
| + return (inlineTextBox->logicalHeight() + gap + offset).toInt();
|
| + return (inlineTextBox->logicalHeight() + gap).toInt();
|
| + }
|
| + }
|
| +
|
| + NOTREACHED();
|
| + return fontMetrics.ascent() + gap;
|
| +}
|
| +
|
| +static bool shouldSetDecorationAntialias(
|
| + const Vector<AppliedTextDecoration>& decorations) {
|
| + for (const AppliedTextDecoration& decoration : decorations) {
|
| + TextDecorationStyle decorationStyle = decoration.style();
|
| + if (decorationStyle == TextDecorationStyleDotted ||
|
| + decorationStyle == TextDecorationStyleDashed)
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +static StrokeStyle textDecorationStyleToStrokeStyle(
|
| + TextDecorationStyle decorationStyle) {
|
| + StrokeStyle strokeStyle = SolidStroke;
|
| + switch (decorationStyle) {
|
| + case TextDecorationStyleSolid:
|
| + strokeStyle = SolidStroke;
|
| + break;
|
| + case TextDecorationStyleDouble:
|
| + strokeStyle = DoubleStroke;
|
| + break;
|
| + case TextDecorationStyleDotted:
|
| + strokeStyle = DottedStroke;
|
| + break;
|
| + case TextDecorationStyleDashed:
|
| + strokeStyle = DashedStroke;
|
| + break;
|
| + case TextDecorationStyleWavy:
|
| + strokeStyle = WavyStroke;
|
| + break;
|
| + }
|
| +
|
| + return strokeStyle;
|
| +}
|
| +
|
| +static void adjustStepToDecorationLength(float& step,
|
| + float& controlPointDistance,
|
| + float length) {
|
| + DCHECK_GT(step, 0);
|
| +
|
| + if (length <= 0)
|
| + return;
|
| +
|
| + unsigned stepCount = static_cast<unsigned>(length / step);
|
| +
|
| + // Each Bezier curve starts at the same pixel that the previous one
|
| + // ended. We need to subtract (stepCount - 1) pixels when calculating the
|
| + // length covered to account for that.
|
| + float uncoveredLength = length - (stepCount * step - (stepCount - 1));
|
| + float adjustment = uncoveredLength / stepCount;
|
| + step += adjustment;
|
| + controlPointDistance += adjustment;
|
| +}
|
| +
|
| +class AppliedDecorationPainter final {
|
| + STACK_ALLOCATED();
|
| +
|
| + public:
|
| + AppliedDecorationPainter(GraphicsContext& context,
|
| + FloatPoint startPoint,
|
| + float width,
|
| + const AppliedTextDecoration& decoration,
|
| + float thickness,
|
| + float doubleOffset,
|
| + int wavyOffsetFactor,
|
| + bool antialiasDecoration)
|
| + : m_context(context),
|
| + m_startPoint(startPoint),
|
| + m_width(width),
|
| + m_decoration(decoration),
|
| + m_thickness(thickness),
|
| + m_doubleOffset(doubleOffset),
|
| + m_wavyOffsetFactor(wavyOffsetFactor),
|
| + m_shouldAntialias(antialiasDecoration){};
|
| +
|
| + void paint();
|
| + FloatRect decorationBounds();
|
| +
|
| + private:
|
| + void strokeWavyTextDecoration();
|
| +
|
| + Path prepareWavyStrokePath();
|
| + Path prepareDottedDashedStrokePath();
|
| +
|
| + GraphicsContext& m_context;
|
| + FloatPoint m_startPoint;
|
| + float m_width;
|
| + const AppliedTextDecoration& m_decoration;
|
| + float m_thickness;
|
| + const float m_doubleOffset;
|
| + const int m_wavyOffsetFactor;
|
| + bool m_shouldAntialias;
|
| +};
|
| +
|
| +Path AppliedDecorationPainter::prepareDottedDashedStrokePath() {
|
| + // These coordinate transforms need to match what's happening in
|
| + // GraphicsContext's drawLineForText and drawLine.
|
| + int y = floorf(m_startPoint.y() + std::max<float>(m_thickness / 2.0f, 0.5f));
|
| + Path strokePath;
|
| + FloatPoint roundedStartPoint(m_startPoint.x(), y);
|
| + FloatPoint roundedEndPoint(roundedStartPoint + FloatPoint(m_width, 0));
|
| + m_context.adjustLineToPixelBoundaries(roundedStartPoint, roundedEndPoint,
|
| + roundf(m_thickness),
|
| + m_context.getStrokeStyle());
|
| + strokePath.moveTo(roundedStartPoint);
|
| + strokePath.addLineTo(roundedEndPoint);
|
| + return strokePath;
|
| +}
|
| +
|
| +FloatRect AppliedDecorationPainter::decorationBounds() {
|
| + StrokeData strokeData;
|
| + strokeData.setThickness(m_thickness);
|
| +
|
| + switch (m_decoration.style()) {
|
| + case TextDecorationStyleDotted:
|
| + case TextDecorationStyleDashed: {
|
| + strokeData.setStyle(
|
| + textDecorationStyleToStrokeStyle(m_decoration.style()));
|
| + return prepareDottedDashedStrokePath().strokeBoundingRect(
|
| + strokeData, Path::BoundsType::Exact);
|
| + }
|
| + case TextDecorationStyleWavy:
|
| + return prepareWavyStrokePath().strokeBoundingRect(
|
| + strokeData, Path::BoundsType::Exact);
|
| + break;
|
| + case TextDecorationStyleDouble:
|
| + if (m_doubleOffset > 0) {
|
| + return FloatRect(m_startPoint.x(), m_startPoint.y(), m_width,
|
| + m_doubleOffset + m_thickness);
|
| + }
|
| + return FloatRect(m_startPoint.x(), m_startPoint.y() + m_doubleOffset,
|
| + m_width, -m_doubleOffset + m_thickness);
|
| + break;
|
| + case TextDecorationStyleSolid:
|
| + return FloatRect(m_startPoint.x(), m_startPoint.y(), m_width,
|
| + m_thickness);
|
| + default:
|
| + break;
|
| + }
|
| + NOTREACHED();
|
| + return FloatRect();
|
| +}
|
| +
|
| +void AppliedDecorationPainter::paint() {
|
| + m_context.setStrokeStyle(
|
| + textDecorationStyleToStrokeStyle(m_decoration.style()));
|
| + m_context.setStrokeColor(m_decoration.color());
|
| +
|
| + switch (m_decoration.style()) {
|
| + case TextDecorationStyleWavy:
|
| + strokeWavyTextDecoration();
|
| + break;
|
| + case TextDecorationStyleDotted:
|
| + case TextDecorationStyleDashed:
|
| + m_context.setShouldAntialias(m_shouldAntialias);
|
| + // Fall through
|
| + default:
|
| + m_context.drawLineForText(m_startPoint, m_width);
|
| +
|
| + if (m_decoration.style() == TextDecorationStyleDouble) {
|
| + m_context.drawLineForText(m_startPoint + FloatPoint(0, m_doubleOffset),
|
| + m_width);
|
| + }
|
| + }
|
| +}
|
| +
|
| +void AppliedDecorationPainter::strokeWavyTextDecoration() {
|
| + m_context.setShouldAntialias(true);
|
| + m_context.strokePath(prepareWavyStrokePath());
|
| +}
|
| +
|
| +/*
|
| + * Prepare a path for a cubic Bezier curve and repeat the same pattern long the
|
| + * the decoration's axis. The start point (p1), controlPoint1, controlPoint2
|
| + * and end point (p2) of the Bezier curve form a diamond shape:
|
| + *
|
| + * step
|
| + * |-----------|
|
| + *
|
| + * controlPoint1
|
| + * +
|
| + *
|
| + *
|
| + * . .
|
| + * . .
|
| + * . .
|
| + * (x1, y1) p1 + . + p2 (x2, y2) - <--- Decoration's axis
|
| + * . . |
|
| + * . . |
|
| + * . . | controlPointDistance
|
| + * |
|
| + * |
|
| + * + -
|
| + * controlPoint2
|
| + *
|
| + * |-----------|
|
| + * step
|
| + */
|
| +Path AppliedDecorationPainter::prepareWavyStrokePath() {
|
| + FloatPoint p1(m_startPoint +
|
| + FloatPoint(0, m_doubleOffset * m_wavyOffsetFactor));
|
| + FloatPoint p2(m_startPoint +
|
| + FloatPoint(m_width, m_doubleOffset * m_wavyOffsetFactor));
|
| +
|
| + m_context.adjustLineToPixelBoundaries(p1, p2, m_thickness,
|
| + m_context.getStrokeStyle());
|
| +
|
| + Path path;
|
| + path.moveTo(p1);
|
| +
|
| + // Distance between decoration's axis and Bezier curve's control points.
|
| + // The height of the curve is based on this distance. Use a minimum of 6
|
| + // pixels distance since
|
| + // the actual curve passes approximately at half of that distance, that is 3
|
| + // pixels.
|
| + // The minimum height of the curve is also approximately 3 pixels. Increases
|
| + // the curve's height
|
| + // as strockThickness increases to make the curve looks better.
|
| + float controlPointDistance = 3 * std::max<float>(2, m_thickness);
|
| +
|
| + // Increment used to form the diamond shape between start point (p1), control
|
| + // points and end point (p2) along the axis of the decoration. Makes the
|
| + // curve wider as strockThickness increases to make the curve looks better.
|
| + float step = 2 * std::max<float>(2, m_thickness);
|
| +
|
| + bool isVerticalLine = (p1.x() == p2.x());
|
| +
|
| + if (isVerticalLine) {
|
| + DCHECK(p1.x() == p2.x());
|
| +
|
| + float xAxis = p1.x();
|
| + float y1;
|
| + float y2;
|
| +
|
| + if (p1.y() < p2.y()) {
|
| + y1 = p1.y();
|
| + y2 = p2.y();
|
| + } else {
|
| + y1 = p2.y();
|
| + y2 = p1.y();
|
| + }
|
| +
|
| + adjustStepToDecorationLength(step, controlPointDistance, y2 - y1);
|
| + FloatPoint controlPoint1(xAxis + controlPointDistance, 0);
|
| + FloatPoint controlPoint2(xAxis - controlPointDistance, 0);
|
| +
|
| + for (float y = y1; y + 2 * step <= y2;) {
|
| + controlPoint1.setY(y + step);
|
| + controlPoint2.setY(y + step);
|
| + y += 2 * step;
|
| + path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(xAxis, y));
|
| + }
|
| + } else {
|
| + DCHECK(p1.y() == p2.y());
|
| +
|
| + float yAxis = p1.y();
|
| + float x1;
|
| + float x2;
|
| +
|
| + if (p1.x() < p2.x()) {
|
| + x1 = p1.x();
|
| + x2 = p2.x();
|
| + } else {
|
| + x1 = p2.x();
|
| + x2 = p1.x();
|
| + }
|
| +
|
| + adjustStepToDecorationLength(step, controlPointDistance, x2 - x1);
|
| + FloatPoint controlPoint1(0, yAxis + controlPointDistance);
|
| + FloatPoint controlPoint2(0, yAxis - controlPointDistance);
|
| +
|
| + for (float x = x1; x + 2 * step <= x2;) {
|
| + controlPoint1.setX(x + step);
|
| + controlPoint2.setX(x + step);
|
| + x += 2 * step;
|
| + path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(x, yAxis));
|
| + }
|
| + }
|
| + return path;
|
| +}
|
| +
|
| typedef WTF::HashMap<const InlineTextBox*, TextBlobPtr>
|
| InlineTextBoxBlobCacheMap;
|
| static InlineTextBoxBlobCacheMap* gTextBlobCache;
|
| @@ -288,11 +609,14 @@ void InlineTextBoxPainter::paint(const PaintInfo& paintInfo,
|
| if (styleToUse.textDecorationsInEffect() != TextDecorationNone &&
|
| !paintSelectedTextOnly) {
|
| GraphicsContextStateSaver stateSaver(context, false);
|
| +
|
| TextPainter::updateGraphicsContext(
|
| context, textStyle, m_inlineTextBox.isHorizontal(), stateSaver);
|
| +
|
| if (combinedText)
|
| context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Clockwise));
|
| - paintDecorations(paintInfo, boxOrigin, styleToUse.appliedTextDecorations());
|
| + paintDecorations(textPainter, paintInfo, boxOrigin,
|
| + styleToUse.appliedTextDecorations());
|
| if (combinedText)
|
| context.concatCTM(
|
| TextPainter::rotation(boxRect, TextPainter::Counterclockwise));
|
| @@ -683,240 +1007,8 @@ void InlineTextBoxPainter::expandToIncludeNewlineForSelection(
|
| rect.expand(outsets);
|
| }
|
|
|
| -static int computeUnderlineOffset(const TextUnderlinePosition underlinePosition,
|
| - const FontMetrics& fontMetrics,
|
| - const InlineTextBox* inlineTextBox,
|
| - const float textDecorationThickness) {
|
| - // 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;
|
| -
|
| - // Underline position of zero means draw underline on Baseline Position,
|
| - // in Blink we need at least 1-pixel gap to adding following check.
|
| - // Positive underline Position means underline should be drawn above baselin e
|
| - // and negative value means drawing below baseline, negating the value as in
|
| - // Blink downward Y-increases.
|
| -
|
| - if (fontMetrics.underlinePosition())
|
| - gap = -fontMetrics.underlinePosition();
|
| - else
|
| - gap = std::max<int>(1, ceilf(textDecorationThickness / 2.f));
|
| -
|
| - // FIXME: We support only horizontal text for now.
|
| - switch (underlinePosition) {
|
| - case TextUnderlinePositionAuto:
|
| - 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 LayoutUnit offset =
|
| - inlineTextBox->root().maxLogicalTop() - inlineTextBox->logicalTop();
|
| - if (offset > 0)
|
| - return (inlineTextBox->logicalHeight() + gap + offset).toInt();
|
| - return (inlineTextBox->logicalHeight() + gap).toInt();
|
| - }
|
| - }
|
| -
|
| - ASSERT_NOT_REACHED();
|
| - return fontMetrics.ascent() + gap;
|
| -}
|
| -
|
| -static bool shouldSetDecorationAntialias(
|
| - const Vector<AppliedTextDecoration>& decorations) {
|
| - for (const AppliedTextDecoration& decoration : decorations) {
|
| - TextDecorationStyle decorationStyle = decoration.style();
|
| - if (decorationStyle == TextDecorationStyleDotted ||
|
| - decorationStyle == TextDecorationStyleDashed)
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -static StrokeStyle textDecorationStyleToStrokeStyle(
|
| - TextDecorationStyle decorationStyle) {
|
| - StrokeStyle strokeStyle = SolidStroke;
|
| - switch (decorationStyle) {
|
| - case TextDecorationStyleSolid:
|
| - strokeStyle = SolidStroke;
|
| - break;
|
| - case TextDecorationStyleDouble:
|
| - strokeStyle = DoubleStroke;
|
| - break;
|
| - case TextDecorationStyleDotted:
|
| - strokeStyle = DottedStroke;
|
| - break;
|
| - case TextDecorationStyleDashed:
|
| - strokeStyle = DashedStroke;
|
| - break;
|
| - case TextDecorationStyleWavy:
|
| - strokeStyle = WavyStroke;
|
| - break;
|
| - }
|
| -
|
| - return strokeStyle;
|
| -}
|
| -
|
| -static void adjustStepToDecorationLength(float& step,
|
| - float& controlPointDistance,
|
| - float length) {
|
| - DCHECK_GT(step, 0);
|
| -
|
| - if (length <= 0)
|
| - return;
|
| -
|
| - unsigned stepCount = static_cast<unsigned>(length / step);
|
| -
|
| - // Each Bezier curve starts at the same pixel that the previous one
|
| - // ended. We need to subtract (stepCount - 1) pixels when calculating the
|
| - // length covered to account for that.
|
| - float uncoveredLength = length - (stepCount * step - (stepCount - 1));
|
| - float adjustment = uncoveredLength / stepCount;
|
| - step += adjustment;
|
| - controlPointDistance += adjustment;
|
| -}
|
| -
|
| -/*
|
| - * Draw one cubic Bezier curve and repeat the same pattern long the the
|
| - * decoration's axis. The start point (p1), controlPoint1, controlPoint2 and
|
| - * end point (p2) of the Bezier curve form a diamond shape:
|
| - *
|
| - * step
|
| - * |-----------|
|
| - *
|
| - * controlPoint1
|
| - * +
|
| - *
|
| - *
|
| - * . .
|
| - * . .
|
| - * . .
|
| - * (x1, y1) p1 + . + p2 (x2, y2) - <--- Decoration's axis
|
| - * . . |
|
| - * . . |
|
| - * . . | controlPointDistance
|
| - * |
|
| - * |
|
| - * + -
|
| - * controlPoint2
|
| - *
|
| - * |-----------|
|
| - * step
|
| - */
|
| -static void strokeWavyTextDecoration(GraphicsContext& context,
|
| - FloatPoint p1,
|
| - FloatPoint p2,
|
| - float strokeThickness) {
|
| - context.adjustLineToPixelBoundaries(p1, p2, strokeThickness,
|
| - context.getStrokeStyle());
|
| -
|
| - Path path;
|
| - path.moveTo(p1);
|
| -
|
| - // Distance between decoration's axis and Bezier curve's control points.
|
| - // The height of the curve is based on this distance. Use a minimum of 6
|
| - // pixels distance since the actual curve passes approximately at half of that
|
| - // distance, that is 3 pixels. The minimum height of the curve is also
|
| - // approximately 3 pixels. Increases the curve's height
|
| - // as strockThickness increases to make the curve looks better.
|
| - float controlPointDistance = 3 * std::max<float>(2, strokeThickness);
|
| -
|
| - // Increment used to form the diamond shape between start point (p1), control
|
| - // points and end point (p2) along the axis of the decoration. Makes the
|
| - // curve wider as strockThickness increases to make the curve looks better.
|
| - float step = 2 * std::max<float>(2, strokeThickness);
|
| -
|
| - bool isVerticalLine = (p1.x() == p2.x());
|
| -
|
| - if (isVerticalLine) {
|
| - DCHECK(p1.x() == p2.x());
|
| -
|
| - float xAxis = p1.x();
|
| - float y1;
|
| - float y2;
|
| -
|
| - if (p1.y() < p2.y()) {
|
| - y1 = p1.y();
|
| - y2 = p2.y();
|
| - } else {
|
| - y1 = p2.y();
|
| - y2 = p1.y();
|
| - }
|
| -
|
| - adjustStepToDecorationLength(step, controlPointDistance, y2 - y1);
|
| - FloatPoint controlPoint1(xAxis + controlPointDistance, 0);
|
| - FloatPoint controlPoint2(xAxis - controlPointDistance, 0);
|
| -
|
| - for (float y = y1; y + 2 * step <= y2;) {
|
| - controlPoint1.setY(y + step);
|
| - controlPoint2.setY(y + step);
|
| - y += 2 * step;
|
| - path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(xAxis, y));
|
| - }
|
| - } else {
|
| - DCHECK(p1.y() == p2.y());
|
| -
|
| - float yAxis = p1.y();
|
| - float x1;
|
| - float x2;
|
| -
|
| - if (p1.x() < p2.x()) {
|
| - x1 = p1.x();
|
| - x2 = p2.x();
|
| - } else {
|
| - x1 = p2.x();
|
| - x2 = p1.x();
|
| - }
|
| -
|
| - adjustStepToDecorationLength(step, controlPointDistance, x2 - x1);
|
| - FloatPoint controlPoint1(0, yAxis + controlPointDistance);
|
| - FloatPoint controlPoint2(0, yAxis - controlPointDistance);
|
| -
|
| - for (float x = x1; x + 2 * step <= x2;) {
|
| - controlPoint1.setX(x + step);
|
| - controlPoint2.setX(x + step);
|
| - x += 2 * step;
|
| - path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(x, yAxis));
|
| - }
|
| - }
|
| -
|
| - context.setShouldAntialias(true);
|
| - context.strokePath(path);
|
| -}
|
| -
|
| -static void paintAppliedDecoration(GraphicsContext& context,
|
| - FloatPoint start,
|
| - float width,
|
| - float doubleOffset,
|
| - int wavyOffsetFactor,
|
| - AppliedTextDecoration decoration,
|
| - float thickness,
|
| - bool antialiasDecoration,
|
| - bool isPrinting) {
|
| - 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);
|
| - break;
|
| - case TextDecorationStyleDotted:
|
| - case TextDecorationStyleDashed:
|
| - context.setShouldAntialias(antialiasDecoration);
|
| - // Fall through
|
| - default:
|
| - context.drawLineForText(FloatPoint(start), width, isPrinting);
|
| -
|
| - if (decoration.style() == TextDecorationStyleDouble)
|
| - context.drawLineForText(start + FloatPoint(0, doubleOffset), width,
|
| - isPrinting);
|
| - }
|
| -}
|
| -
|
| void InlineTextBoxPainter::paintDecorations(
|
| + TextPainter& textPainter,
|
| const PaintInfo& paintInfo,
|
| const LayoutPoint& boxOrigin,
|
| const Vector<AppliedTextDecoration>& decorations) {
|
| @@ -944,15 +1036,13 @@ void InlineTextBoxPainter::paintDecorations(
|
| localOrigin.move(m_inlineTextBox.logicalWidth() - width, LayoutUnit());
|
| }
|
|
|
| - // Use a special function for underlines to get the positioning exactly right.
|
| - bool isPrinting = paintInfo.isPrinting();
|
| -
|
| LayoutObject& textBoxLayoutObject = inlineLayoutObject();
|
| +
|
| const ComputedStyle& styleToUse =
|
| textBoxLayoutObject.styleRef(m_inlineTextBox.isFirstLineStyle());
|
| const SimpleFontData* fontData = styleToUse.font().primaryFont();
|
| DCHECK(fontData);
|
| - float baseline = fontData ? fontData->getFontMetrics().ascent() : 0;
|
| + float baseline = fontData ? fontData->getFontMetrics().floatAscent() : 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
|
| @@ -977,29 +1067,55 @@ void InlineTextBoxPainter::paintDecorations(
|
|
|
| // Offset between lines - always non-zero, so lines never cross each other.
|
| float doubleOffset = textDecorationThickness + 1.f;
|
| + bool skipIntercepts =
|
| + styleToUse.getTextDecorationSkip() & TextDecorationSkipInk;
|
|
|
| for (const AppliedTextDecoration& decoration : decorations) {
|
| TextDecoration lines = decoration.lines();
|
| - if (lines & TextDecorationUnderline && fontData) {
|
| + if ((lines & TextDecorationUnderline) && fontData) {
|
| const int underlineOffset = computeUnderlineOffset(
|
| styleToUse.getTextUnderlinePosition(), fontData->getFontMetrics(),
|
| &m_inlineTextBox, textDecorationThickness);
|
| - paintAppliedDecoration(
|
| + AppliedDecorationPainter decorationPainter(
|
| context, FloatPoint(localOrigin) + FloatPoint(0, underlineOffset),
|
| - width.toFloat(), doubleOffset, 1, decoration, textDecorationThickness,
|
| - antialiasDecoration, isPrinting);
|
| + width.toFloat(), decoration, textDecorationThickness, doubleOffset, 1,
|
| + antialiasDecoration);
|
| + if (skipIntercepts) {
|
| + textPainter.clipDecorationsStripe(
|
| + -baseline + decorationPainter.decorationBounds().y() -
|
| + FloatPoint(localOrigin).y(),
|
| + decorationPainter.decorationBounds().height(),
|
| + textDecorationThickness);
|
| + }
|
| + decorationPainter.paint();
|
| }
|
| if (lines & TextDecorationOverline) {
|
| - paintAppliedDecoration(
|
| - context, FloatPoint(localOrigin), width.toFloat(), -doubleOffset, 1,
|
| - decoration, textDecorationThickness, antialiasDecoration, isPrinting);
|
| + AppliedDecorationPainter decorationPainter(
|
| + context, FloatPoint(localOrigin), width.toFloat(), decoration,
|
| + textDecorationThickness, -doubleOffset, 1, antialiasDecoration);
|
| + if (skipIntercepts) {
|
| + textPainter.clipDecorationsStripe(
|
| + -baseline + decorationPainter.decorationBounds().y() -
|
| + FloatPoint(localOrigin).y(),
|
| + decorationPainter.decorationBounds().height(),
|
| + textDecorationThickness);
|
| + }
|
| + decorationPainter.paint();
|
| }
|
| if (lines & TextDecorationLineThrough) {
|
| const float lineThroughOffset = 2 * baseline / 3;
|
| - paintAppliedDecoration(
|
| + AppliedDecorationPainter decorationPainter(
|
| context, FloatPoint(localOrigin) + FloatPoint(0, lineThroughOffset),
|
| - width.toFloat(), doubleOffset, 0, decoration, textDecorationThickness,
|
| - antialiasDecoration, isPrinting);
|
| + width.toFloat(), decoration, textDecorationThickness, doubleOffset, 0,
|
| + antialiasDecoration);
|
| + if (skipIntercepts) {
|
| + textPainter.clipDecorationsStripe(
|
| + -baseline + decorationPainter.decorationBounds().y() -
|
| + FloatPoint(localOrigin).y(),
|
| + decorationPainter.decorationBounds().height(),
|
| + textDecorationThickness);
|
| + }
|
| + decorationPainter.paint();
|
| }
|
| }
|
| }
|
| @@ -1081,7 +1197,7 @@ void InlineTextBoxPainter::paintCompositionUnderline(
|
| boxOrigin.x() + start,
|
| (boxOrigin.y() + m_inlineTextBox.logicalHeight() - lineThickness)
|
| .toFloat()),
|
| - width, m_inlineTextBox.getLineLayoutItem().document().printing());
|
| + width);
|
| }
|
|
|
| void InlineTextBoxPainter::paintTextMatchMarkerForeground(
|
|
|