| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 #include "core/paint/InlineTextBoxPainter.h" | 6 #include "core/paint/InlineTextBoxPainter.h" |
| 7 | 7 |
| 8 #include "core/editing/CompositionUnderline.h" | 8 #include "core/editing/CompositionUnderline.h" |
| 9 #include "core/editing/Editor.h" | 9 #include "core/editing/Editor.h" |
| 10 #include "core/editing/markers/DocumentMarkerController.h" | 10 #include "core/editing/markers/DocumentMarkerController.h" |
| 11 #include "core/editing/markers/RenderedDocumentMarker.h" | 11 #include "core/editing/markers/RenderedDocumentMarker.h" |
| 12 #include "core/frame/LocalFrame.h" | 12 #include "core/frame/LocalFrame.h" |
| 13 #include "core/layout/LayoutBlock.h" | 13 #include "core/layout/LayoutBlock.h" |
| 14 #include "core/layout/LayoutTextCombine.h" | 14 #include "core/layout/LayoutTextCombine.h" |
| 15 #include "core/layout/LayoutTheme.h" | 15 #include "core/layout/LayoutTheme.h" |
| 16 #include "core/layout/api/LineLayoutBox.h" | 16 #include "core/layout/api/LineLayoutBox.h" |
| 17 #include "core/layout/api/LineLayoutText.h" | 17 #include "core/layout/api/LineLayoutText.h" |
| 18 #include "core/layout/line/InlineTextBox.h" | 18 #include "core/layout/line/InlineTextBox.h" |
| 19 #include "core/paint/BoxPainter.h" | 19 #include "core/paint/BoxPainter.h" |
| 20 #include "core/paint/LineLayoutPaintShim.h" | 20 #include "core/paint/LineLayoutPaintShim.h" |
| 21 #include "core/paint/PaintInfo.h" | 21 #include "core/paint/PaintInfo.h" |
| 22 #include "core/paint/TextPainter.h" | 22 #include "core/paint/TextPainter.h" |
| 23 #include "core/style/AppliedTextDecoration.h" |
| 23 #include "platform/graphics/GraphicsContextStateSaver.h" | 24 #include "platform/graphics/GraphicsContextStateSaver.h" |
| 24 #include "platform/graphics/paint/DrawingRecorder.h" | 25 #include "platform/graphics/paint/DrawingRecorder.h" |
| 25 #include "wtf/Optional.h" | 26 #include "wtf/Optional.h" |
| 26 | 27 |
| 27 namespace blink { | 28 namespace blink { |
| 28 | 29 |
| 29 typedef WTF::HashMap<const InlineTextBox*, TextBlobPtr> InlineTextBoxBlobCacheMa
p; | 30 typedef WTF::HashMap<const InlineTextBox*, TextBlobPtr> InlineTextBoxBlobCacheMa
p; |
| 30 static InlineTextBoxBlobCacheMap* gTextBlobCache; | 31 static InlineTextBoxBlobCacheMap* gTextBlobCache; |
| 31 | 32 |
| 32 static const int misspellingLineThickness = 3; | 33 static const int misspellingLineThickness = 3; |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 if ((paintSelectedTextOnly || paintSelectedTextSeparately) && selectionStart
< selectionEnd) { | 225 if ((paintSelectedTextOnly || paintSelectedTextSeparately) && selectionStart
< selectionEnd) { |
| 225 // paint only the text that is selected | 226 // paint only the text that is selected |
| 226 bool textBlobIsCacheable = selectionStart == 0 && selectionEnd == length
; | 227 bool textBlobIsCacheable = selectionStart == 0 && selectionEnd == length
; |
| 227 TextBlobPtr* cachedTextBlob = 0; | 228 TextBlobPtr* cachedTextBlob = 0; |
| 228 if (textBlobIsCacheable) | 229 if (textBlobIsCacheable) |
| 229 cachedTextBlob = addToTextBlobCache(m_inlineTextBox); | 230 cachedTextBlob = addToTextBlobCache(m_inlineTextBox); |
| 230 textPainter.paint(selectionStart, selectionEnd, length, selectionStyle,
cachedTextBlob); | 231 textPainter.paint(selectionStart, selectionEnd, length, selectionStyle,
cachedTextBlob); |
| 231 } | 232 } |
| 232 | 233 |
| 233 // Paint decorations | 234 // Paint decorations |
| 234 TextDecoration textDecorations = styleToUse.textDecorationsInEffect(); | 235 if (styleToUse.textDecorationsInEffect() != TextDecorationNone && !paintSele
ctedTextOnly) { |
| 235 if (textDecorations != TextDecorationNone && !paintSelectedTextOnly) { | |
| 236 GraphicsContextStateSaver stateSaver(context, false); | 236 GraphicsContextStateSaver stateSaver(context, false); |
| 237 TextPainter::updateGraphicsContext(context, textStyle, m_inlineTextBox.i
sHorizontal(), stateSaver); | 237 TextPainter::updateGraphicsContext(context, textStyle, m_inlineTextBox.i
sHorizontal(), stateSaver); |
| 238 if (combinedText) | 238 if (combinedText) |
| 239 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Clockw
ise)); | 239 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Clockw
ise)); |
| 240 paintDecoration(paintInfo, boxOrigin, textDecorations); | 240 paintDecorations(paintInfo, boxOrigin, styleToUse.appliedTextDecorations
()); |
| 241 if (combinedText) | 241 if (combinedText) |
| 242 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Counte
rclockwise)); | 242 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Counte
rclockwise)); |
| 243 } | 243 } |
| 244 | 244 |
| 245 if (paintInfo.phase == PaintPhaseForeground) | 245 if (paintInfo.phase == PaintPhaseForeground) |
| 246 paintDocumentMarkers(context, boxOrigin, styleToUse, font, false); | 246 paintDocumentMarkers(context, boxOrigin, styleToUse, font, false); |
| 247 | 247 |
| 248 if (shouldRotate) | 248 if (shouldRotate) |
| 249 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Counterclo
ckwise)); | 249 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Counterclo
ckwise)); |
| 250 } | 250 } |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 if (offset > 0) | 543 if (offset > 0) |
| 544 return inlineTextBox->logicalHeight() + gap + offset; | 544 return inlineTextBox->logicalHeight() + gap + offset; |
| 545 return inlineTextBox->logicalHeight() + gap; | 545 return inlineTextBox->logicalHeight() + gap; |
| 546 } | 546 } |
| 547 } | 547 } |
| 548 | 548 |
| 549 ASSERT_NOT_REACHED(); | 549 ASSERT_NOT_REACHED(); |
| 550 return fontMetrics.ascent() + gap; | 550 return fontMetrics.ascent() + gap; |
| 551 } | 551 } |
| 552 | 552 |
| 553 static bool shouldSetDecorationAntialias(TextDecorationStyle decorationStyle) | 553 static bool shouldSetDecorationAntialias(const Vector<AppliedTextDecoration>& de
corations) |
| 554 { | 554 { |
| 555 return decorationStyle == TextDecorationStyleDotted || decorationStyle == Te
xtDecorationStyleDashed; | 555 for (const AppliedTextDecoration& decoration : decorations) { |
| 556 } | 556 TextDecorationStyle decorationStyle = decoration.style(); |
| 557 | 557 if (decorationStyle == TextDecorationStyleDotted || decorationStyle == T
extDecorationStyleDashed) |
| 558 static bool shouldSetDecorationAntialias(TextDecorationStyle underline, TextDeco
rationStyle overline, TextDecorationStyle linethrough) | 558 return true; |
| 559 { | 559 } |
| 560 return shouldSetDecorationAntialias(underline) || shouldSetDecorationAntiali
as(overline) || shouldSetDecorationAntialias(linethrough); | 560 return false; |
| 561 } | 561 } |
| 562 | 562 |
| 563 static StrokeStyle textDecorationStyleToStrokeStyle(TextDecorationStyle decorati
onStyle) | 563 static StrokeStyle textDecorationStyleToStrokeStyle(TextDecorationStyle decorati
onStyle) |
| 564 { | 564 { |
| 565 StrokeStyle strokeStyle = SolidStroke; | 565 StrokeStyle strokeStyle = SolidStroke; |
| 566 switch (decorationStyle) { | 566 switch (decorationStyle) { |
| 567 case TextDecorationStyleSolid: | 567 case TextDecorationStyleSolid: |
| 568 strokeStyle = SolidStroke; | 568 strokeStyle = SolidStroke; |
| 569 break; | 569 break; |
| 570 case TextDecorationStyleDouble: | 570 case TextDecorationStyleDouble: |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 699 controlPoint2.setX(x + step); | 699 controlPoint2.setX(x + step); |
| 700 x += 2 * step; | 700 x += 2 * step; |
| 701 path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(x, yA
xis)); | 701 path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(x, yA
xis)); |
| 702 } | 702 } |
| 703 } | 703 } |
| 704 | 704 |
| 705 context.setShouldAntialias(true); | 705 context.setShouldAntialias(true); |
| 706 context.strokePath(path); | 706 context.strokePath(path); |
| 707 } | 707 } |
| 708 | 708 |
| 709 static void paintAppliedDecoration(GraphicsContext& context, FloatPoint start, f
loat width, float doubleOffset, int wavyOffsetFactor, | 709 static void paintAppliedDecoration(GraphicsContext* context, FloatPoint start, f
loat width, float doubleOffset, int wavyOffsetFactor, |
| 710 LayoutObject::AppliedTextDecoration decoration, float thickness, bool antial
iasDecoration, bool isPrinting) | 710 AppliedTextDecoration decoration, float thickness, bool antialiasDecoration,
bool isPrinting) |
| 711 { | 711 { |
| 712 context.setStrokeStyle(textDecorationStyleToStrokeStyle(decoration.style)); | 712 context.setStrokeStyle(textDecorationStyleToStrokeStyle(decoration.style()))
; |
| 713 context.setStrokeColor(decoration.color); | 713 context.setStrokeColor(decoration.color()); |
| 714 | 714 |
| 715 switch (decoration.style) { | 715 switch (decoration.style()) { |
| 716 case TextDecorationStyleWavy: | 716 case TextDecorationStyleWavy: |
| 717 strokeWavyTextDecoration(context, start + FloatPoint(0, doubleOffset * w
avyOffsetFactor), start + FloatPoint(width, doubleOffset * wavyOffsetFactor), th
ickness); | 717 strokeWavyTextDecoration(context, start + FloatPoint(0, doubleOffset * w
avyOffsetFactor), start + FloatPoint(width, doubleOffset * wavyOffsetFactor), th
ickness); |
| 718 break; | 718 break; |
| 719 case TextDecorationStyleDotted: | 719 case TextDecorationStyleDotted: |
| 720 case TextDecorationStyleDashed: | 720 case TextDecorationStyleDashed: |
| 721 context.setShouldAntialias(antialiasDecoration); | 721 context.setShouldAntialias(antialiasDecoration); |
| 722 // Fall through | 722 // Fall through |
| 723 default: | 723 default: |
| 724 context.drawLineForText(FloatPoint(start), width, isPrinting); | 724 context.drawLineForText(FloatPoint(start), width, isPrinting); |
| 725 | 725 |
| 726 if (decoration.style == TextDecorationStyleDouble) | 726 if (decoration.style() == TextDecorationStyleDouble) |
| 727 context.drawLineForText(start + FloatPoint(0, doubleOffset), width,
isPrinting); | 727 context.drawLineForText(start + FloatPoint(0, doubleOffset), width,
isPrinting); |
| 728 } | 728 } |
| 729 } | 729 } |
| 730 | 730 |
| 731 void InlineTextBoxPainter::paintDecoration(const PaintInfo& paintInfo, const Lay
outPoint& boxOrigin, TextDecoration deco) | 731 void InlineTextBoxPainter::paintDecorations(const PaintInfo& paintInfo, const La
youtPoint& boxOrigin, const Vector<AppliedTextDecoration>& decorations) |
| 732 { | 732 { |
| 733 if (m_inlineTextBox.truncation() == cFullTruncation) | 733 if (m_inlineTextBox.truncation() == cFullTruncation) |
| 734 return; | 734 return; |
| 735 | 735 |
| 736 GraphicsContext& context = paintInfo.context; | 736 GraphicsContext& context = paintInfo.context; |
| 737 GraphicsContextStateSaver stateSaver(context); | 737 GraphicsContextStateSaver stateSaver(context); |
| 738 | 738 |
| 739 LayoutPoint localOrigin(boxOrigin); | 739 LayoutPoint localOrigin(boxOrigin); |
| 740 | 740 |
| 741 LayoutUnit width = m_inlineTextBox.logicalWidth(); | 741 LayoutUnit width = m_inlineTextBox.logicalWidth(); |
| 742 if (m_inlineTextBox.truncation() != cNoTruncation) { | 742 if (m_inlineTextBox.truncation() != cNoTruncation) { |
| 743 width = m_inlineTextBox.lineLayoutItem().width(m_inlineTextBox.start(),
m_inlineTextBox.truncation(), m_inlineTextBox.textPos(), m_inlineTextBox.isLeftT
oRightDirection() ? LTR : RTL, m_inlineTextBox.isFirstLineStyle()); | 743 width = m_inlineTextBox.lineLayoutItem().width(m_inlineTextBox.start(),
m_inlineTextBox.truncation(), m_inlineTextBox.textPos(), m_inlineTextBox.isLeftT
oRightDirection() ? LTR : RTL, m_inlineTextBox.isFirstLineStyle()); |
| 744 if (!m_inlineTextBox.isLeftToRightDirection()) | 744 if (!m_inlineTextBox.isLeftToRightDirection()) |
| 745 localOrigin.move(m_inlineTextBox.logicalWidth() - width, 0); | 745 localOrigin.move(m_inlineTextBox.logicalWidth() - width, 0); |
| 746 } | 746 } |
| 747 | 747 |
| 748 // Get the text decoration colors. | |
| 749 LayoutObject::AppliedTextDecoration underline, overline, linethrough; | |
| 750 LayoutObject& textBoxLayoutObject = *LineLayoutPaintShim::layoutObjectFrom(m
_inlineTextBox.lineLayoutItem()); | |
| 751 textBoxLayoutObject.getTextDecorations(deco, underline, overline, linethroug
h, true); | |
| 752 if (m_inlineTextBox.isFirstLineStyle()) | |
| 753 textBoxLayoutObject.getTextDecorations(deco, underline, overline, lineth
rough, true, true); | |
| 754 | |
| 755 // Use a special function for underlines to get the positioning exactly righ
t. | 748 // Use a special function for underlines to get the positioning exactly righ
t. |
| 756 bool isPrinting = paintInfo.isPrinting(); | 749 bool isPrinting = paintInfo.isPrinting(); |
| 757 | 750 |
| 751 LayoutObject& textBoxLayoutObject = *LineLayoutPaintShim::layoutObjectFrom(m
_inlineTextBox.lineLayoutItem()); |
| 758 const ComputedStyle& styleToUse = textBoxLayoutObject.styleRef(m_inlineTextB
ox.isFirstLineStyle()); | 752 const ComputedStyle& styleToUse = textBoxLayoutObject.styleRef(m_inlineTextB
ox.isFirstLineStyle()); |
| 759 float baseline = styleToUse.fontMetrics().ascent(); | 753 float baseline = styleToUse.fontMetrics().ascent(); |
| 760 | 754 |
| 761 // Set the thick of the line to be 10% (or something else ?)of the computed
font size and not less than 1px. | 755 // Set the thick of the line to be 10% (or something else ?)of the computed
font size and not less than 1px. |
| 762 // Using computedFontSize should take care of zoom as well. | 756 // Using computedFontSize should take care of zoom as well. |
| 763 | 757 |
| 764 // Update Underline thickness, in case we have Faulty Font Metrics calculati
ng underline thickness by old method. | 758 // Update Underline thickness, in case we have Faulty Font Metrics calculati
ng underline thickness by old method. |
| 765 float textDecorationThickness = styleToUse.fontMetrics().underlineThickness(
); | 759 float textDecorationThickness = styleToUse.fontMetrics().underlineThickness(
); |
| 766 int fontHeightInt = (int)(styleToUse.fontMetrics().floatHeight() + 0.5); | 760 int fontHeightInt = (int)(styleToUse.fontMetrics().floatHeight() + 0.5); |
| 767 if ((textDecorationThickness == 0.f) || (textDecorationThickness >= (fontHei
ghtInt >> 1))) | 761 if ((textDecorationThickness == 0.f) || (textDecorationThickness >= (fontHei
ghtInt >> 1))) |
| 768 textDecorationThickness = std::max(1.f, styleToUse.computedFontSize() /
10.f); | 762 textDecorationThickness = std::max(1.f, styleToUse.computedFontSize() /
10.f); |
| 769 | 763 |
| 770 context.setStrokeThickness(textDecorationThickness); | 764 context.setStrokeThickness(textDecorationThickness); |
| 771 | 765 |
| 772 bool antialiasDecoration = shouldSetDecorationAntialias(overline.style, unde
rline.style, linethrough.style); | 766 bool antialiasDecoration = shouldSetDecorationAntialias(decorations); |
| 773 | 767 |
| 774 // Offset between lines - always non-zero, so lines never cross each other. | 768 // Offset between lines - always non-zero, so lines never cross each other. |
| 775 float doubleOffset = textDecorationThickness + 1.f; | 769 float doubleOffset = textDecorationThickness + 1.f; |
| 776 | 770 |
| 777 if (deco & TextDecorationUnderline) { | 771 for (const AppliedTextDecoration& decoration : decorations) { |
| 778 const int underlineOffset = computeUnderlineOffset(styleToUse.textUnderl
inePosition(), styleToUse.fontMetrics(), &m_inlineTextBox, textDecorationThickne
ss); | 772 TextDecoration lines = decoration.lines(); |
| 779 paintAppliedDecoration(context, FloatPoint(localOrigin) + FloatPoint(0,
underlineOffset), width.toFloat(), doubleOffset, 1, underline, textDecorationThi
ckness, antialiasDecoration, isPrinting); | 773 if (lines & TextDecorationUnderline) { |
| 780 } | 774 const int underlineOffset = computeUnderlineOffset(styleToUse.textUn
derlinePosition(), styleToUse.fontMetrics(), &m_inlineTextBox, textDecorationThi
ckness); |
| 781 if (deco & TextDecorationOverline) { | 775 paintAppliedDecoration(context, FloatPoint(localOrigin) + FloatPoint
(0, underlineOffset), width.toFloat(), doubleOffset, 1, decoration, textDecorati
onThickness, antialiasDecoration, isPrinting); |
| 782 paintAppliedDecoration(context, FloatPoint(localOrigin), width.toFloat()
, -doubleOffset, 1, overline, textDecorationThickness, antialiasDecoration, isPr
inting); | 776 } |
| 783 } | 777 if (lines & TextDecorationOverline) { |
| 784 if (deco & TextDecorationLineThrough) { | 778 paintAppliedDecoration(context, FloatPoint(localOrigin), width.toFlo
at(), -doubleOffset, 1, decoration, textDecorationThickness, antialiasDecoration
, isPrinting); |
| 785 const float lineThroughOffset = 2 * baseline / 3; | 779 } |
| 786 paintAppliedDecoration(context, FloatPoint(localOrigin) + FloatPoint(0,
lineThroughOffset), width.toFloat(), doubleOffset, 0, linethrough, textDecoratio
nThickness, antialiasDecoration, isPrinting); | 780 if (lines & TextDecorationLineThrough) { |
| 781 const float lineThroughOffset = 2 * baseline / 3; |
| 782 paintAppliedDecoration(context, FloatPoint(localOrigin) + FloatPoint
(0, lineThroughOffset), width.toFloat(), doubleOffset, 0, decoration, textDecora
tionThickness, antialiasDecoration, isPrinting); |
| 783 } |
| 787 } | 784 } |
| 788 } | 785 } |
| 789 | 786 |
| 790 void InlineTextBoxPainter::paintCompositionUnderline(GraphicsContext& context, c
onst LayoutPoint& boxOrigin, const CompositionUnderline& underline) | 787 void InlineTextBoxPainter::paintCompositionUnderline(GraphicsContext& context, c
onst LayoutPoint& boxOrigin, const CompositionUnderline& underline) |
| 791 { | 788 { |
| 792 if (underline.color == Color::transparent) | 789 if (underline.color == Color::transparent) |
| 793 return; | 790 return; |
| 794 | 791 |
| 795 if (m_inlineTextBox.truncation() == cFullTruncation) | 792 if (m_inlineTextBox.truncation() == cFullTruncation) |
| 796 return; | 793 return; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 863 LayoutPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.fontMetri
cs().ascent()); | 860 LayoutPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.fontMetri
cs().ascent()); |
| 864 TextPainter textPainter(context, font, run, textOrigin, boxRect, m_i
nlineTextBox.isHorizontal()); | 861 TextPainter textPainter(context, font, run, textOrigin, boxRect, m_i
nlineTextBox.isHorizontal()); |
| 865 | 862 |
| 866 textPainter.paint(sPos, ePos, length, textStyle, 0); | 863 textPainter.paint(sPos, ePos, length, textStyle, 0); |
| 867 } | 864 } |
| 868 } | 865 } |
| 869 } | 866 } |
| 870 | 867 |
| 871 | 868 |
| 872 } // namespace blink | 869 } // namespace blink |
| OLD | NEW |