Chromium Code Reviews| 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 c38e8de6367fa8ced0c3b31eacfaa9566c72efcb..36a7077fbe1bee8be329708d7a4a1dab2ed4d800 100644 |
| --- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp |
| +++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp |
| @@ -21,6 +21,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. |
|
eae
2016/10/13 18:18:54
Is this CSS or device pixels? If CSS pixel we prob
|
| + 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 |
|
eae
2016/10/13 18:18:54
odd line-wrapping.
|
| + // 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. |
|
eae
2016/10/13 18:18:54
Is this still accurate? The test case includes ver
drott
2016/10/13 18:39:29
All good questions and remarks... This code is old
|
| + 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(TextDecorationStyle decorationStyle) { |
| + return decorationStyle == TextDecorationStyleDotted || |
| + decorationStyle == TextDecorationStyleDashed; |
| +} |
| + |
| +static bool shouldSetDecorationAntialias(TextDecorationStyle underline, |
| + TextDecorationStyle overline, |
| + TextDecorationStyle linethrough) { |
| + return shouldSetDecorationAntialias(underline) || |
| + shouldSetDecorationAntialias(overline) || |
| + shouldSetDecorationAntialias(linethrough); |
| +} |
| + |
| +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, |
| + LayoutObject::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; |
| + LayoutObject::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, 0)); |
| + |
| + 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 |
|
eae
2016/10/13 18:18:54
Odd line wrapping again here and below on line 280
|
| + // 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; |
| @@ -281,15 +602,30 @@ void InlineTextBoxPainter::paint(const PaintInfo& paintInfo, |
| cachedTextBlob); |
| } |
| + // If styleToUse has text-decoration-skip: ink;, then we need to compute ink |
| + // skips here, pass them to paintDecoration, or pass the textrun or to |
| + // paintDecoration. We probably need a new interface on Font.h that works |
| + // on a TextRunPaintInfo to retrieve the skip intervals. |
| + |
| + // On the other hand, we can compute different skip intervals based on the |
| + // height and width of the underline or line-through, so it is probably |
| + // better to compute them inside paintDecoration, where the underline |
| + // positions are determined. |
| + |
| // Paint decorations |
| TextDecoration textDecorations = styleToUse.textDecorationsInEffect(); |
| if (textDecorations != TextDecorationNone && !paintSelectedTextOnly) { |
| GraphicsContextStateSaver stateSaver(context, false); |
| + |
| TextPainter::updateGraphicsContext( |
| context, textStyle, m_inlineTextBox.isHorizontal(), stateSaver); |
| + |
| + // The matrix transform for the case of combinedText reverts the current |
| + // rotation that is used for the combined painting of the text and |
| + // restores painting along the baseline axis of the text. |
| if (combinedText) |
| context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Clockwise)); |
| - paintDecoration(paintInfo, boxOrigin, textDecorations); |
| + paintDecoration(textPainter, paintInfo, boxOrigin, textDecorations); |
| if (combinedText) |
| context.concatCTM( |
| TextPainter::rotation(boxRect, TextPainter::Counterclockwise)); |
| @@ -676,243 +1012,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(TextDecorationStyle decorationStyle) { |
| - return decorationStyle == TextDecorationStyleDotted || |
| - decorationStyle == TextDecorationStyleDashed; |
| -} |
| - |
| -static bool shouldSetDecorationAntialias(TextDecorationStyle underline, |
| - TextDecorationStyle overline, |
| - TextDecorationStyle linethrough) { |
| - return shouldSetDecorationAntialias(underline) || |
| - shouldSetDecorationAntialias(overline) || |
| - shouldSetDecorationAntialias(linethrough); |
| -} |
| - |
| -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) { |
| - ASSERT(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) { |
| - ASSERT(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 { |
| - ASSERT(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, |
| - LayoutObject::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::paintDecoration(const PaintInfo& paintInfo, |
| +void InlineTextBoxPainter::paintDecoration(TextPainter& textPainter, |
| + const PaintInfo& paintInfo, |
| const LayoutPoint& boxOrigin, |
| TextDecoration deco) { |
| if (m_inlineTextBox.truncation() == cFullTruncation) |
| @@ -948,12 +1049,9 @@ void InlineTextBoxPainter::paintDecoration(const PaintInfo& paintInfo, |
| textBoxLayoutObject.getTextDecorations(deco, underline, overline, |
| linethrough, true, true); |
| - // Use a special function for underlines to get the positioning exactly right. |
| - bool isPrinting = paintInfo.isPrinting(); |
| - |
| const ComputedStyle& styleToUse = |
| textBoxLayoutObject.styleRef(m_inlineTextBox.isFirstLineStyle()); |
| - float baseline = styleToUse.getFontMetrics().ascent(); |
| + float baseline = styleToUse.getFontMetrics().floatAscent(); |
| // 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 |
| @@ -976,27 +1074,53 @@ void InlineTextBoxPainter::paintDecoration(const PaintInfo& paintInfo, |
| // Offset between lines - always non-zero, so lines never cross each other. |
| float doubleOffset = textDecorationThickness + 1.f; |
| + bool skipIntercepts = |
| + styleToUse.getTextDecorationSkip() & TextDecorationSkipInk; |
| if (deco & TextDecorationUnderline) { |
| const int underlineOffset = computeUnderlineOffset( |
| styleToUse.getTextUnderlinePosition(), styleToUse.getFontMetrics(), |
| &m_inlineTextBox, textDecorationThickness); |
| - paintAppliedDecoration( |
| + AppliedDecorationPainter decorationPainter( |
| context, FloatPoint(localOrigin) + FloatPoint(0, underlineOffset), |
| - width.toFloat(), doubleOffset, 1, underline, textDecorationThickness, |
| - antialiasDecoration, isPrinting); |
| + width.toFloat(), underline, textDecorationThickness, doubleOffset, 1, |
| + antialiasDecoration); |
| + if (skipIntercepts) { |
| + textPainter.clipDecorationsStripe( |
| + -baseline + decorationPainter.decorationBounds().y() - |
| + FloatPoint(localOrigin).y(), |
| + decorationPainter.decorationBounds().height(), |
| + textDecorationThickness); |
| + } |
| + decorationPainter.paint(); |
| } |
| if (deco & TextDecorationOverline) { |
| - paintAppliedDecoration(context, FloatPoint(localOrigin), width.toFloat(), |
| - -doubleOffset, 1, overline, textDecorationThickness, |
| - antialiasDecoration, isPrinting); |
| + AppliedDecorationPainter decorationPainter( |
| + context, FloatPoint(localOrigin), width.toFloat(), overline, |
| + textDecorationThickness, -doubleOffset, 1, antialiasDecoration); |
| + if (skipIntercepts) { |
| + textPainter.clipDecorationsStripe( |
| + -baseline + decorationPainter.decorationBounds().y() - |
| + FloatPoint(localOrigin).y(), |
| + decorationPainter.decorationBounds().height(), |
| + textDecorationThickness); |
| + } |
| + decorationPainter.paint(); |
| } |
| if (deco & TextDecorationLineThrough) { |
| const float lineThroughOffset = 2 * baseline / 3; |
| - paintAppliedDecoration( |
| + AppliedDecorationPainter decorationPainter( |
| context, FloatPoint(localOrigin) + FloatPoint(0, lineThroughOffset), |
| - width.toFloat(), doubleOffset, 0, linethrough, textDecorationThickness, |
| - antialiasDecoration, isPrinting); |
| + width.toFloat(), linethrough, textDecorationThickness, doubleOffset, 0, |
| + antialiasDecoration); |
| + if (skipIntercepts) { |
| + textPainter.clipDecorationsStripe( |
| + -baseline + decorationPainter.decorationBounds().y() - |
| + FloatPoint(localOrigin).y(), |
| + decorationPainter.decorationBounds().height(), |
| + textDecorationThickness); |
| + } |
| + decorationPainter.paint(); |
| } |
| } |
| @@ -1074,7 +1198,7 @@ void InlineTextBoxPainter::paintCompositionUnderline( |
| boxOrigin.x() + start, |
| (boxOrigin.y() + m_inlineTextBox.logicalHeight() - lineThickness) |
| .toFloat()), |
| - width, m_inlineTextBox.getLineLayoutItem().document().printing()); |
| + width); |
| } |
| void InlineTextBoxPainter::paintTextMatchMarkerForeground( |