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

Side by Side Diff: third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp

Issue 2497963002: Add support for multiple text decorations with same line positioning (Closed)
Patch Set: Update slimming paint expectations Created 4 years, 1 month 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 unified diff | Download patch
OLDNEW
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 "core/paint/InlineTextBoxPainter.h" 5 #include "core/paint/InlineTextBoxPainter.h"
6 6
7 #include "core/editing/CompositionUnderline.h" 7 #include "core/editing/CompositionUnderline.h"
8 #include "core/editing/Editor.h" 8 #include "core/editing/Editor.h"
9 #include "core/editing/markers/DocumentMarkerController.h" 9 #include "core/editing/markers/DocumentMarkerController.h"
10 #include "core/frame/LocalFrame.h" 10 #include "core/frame/LocalFrame.h"
11 #include "core/layout/LayoutTextCombine.h" 11 #include "core/layout/LayoutTextCombine.h"
12 #include "core/layout/LayoutTheme.h" 12 #include "core/layout/LayoutTheme.h"
13 #include "core/layout/api/LineLayoutAPIShim.h" 13 #include "core/layout/api/LineLayoutAPIShim.h"
14 #include "core/layout/api/LineLayoutBox.h" 14 #include "core/layout/api/LineLayoutBox.h"
15 #include "core/layout/line/InlineTextBox.h" 15 #include "core/layout/line/InlineTextBox.h"
16 #include "core/paint/PaintInfo.h" 16 #include "core/paint/PaintInfo.h"
17 #include "core/paint/TextPainter.h" 17 #include "core/paint/TextPainter.h"
18 #include "core/style/AppliedTextDecoration.h"
18 #include "platform/graphics/GraphicsContextStateSaver.h" 19 #include "platform/graphics/GraphicsContextStateSaver.h"
19 #include "platform/graphics/paint/DrawingRecorder.h" 20 #include "platform/graphics/paint/DrawingRecorder.h"
20 #include "wtf/Optional.h" 21 #include "wtf/Optional.h"
21 22
22 namespace blink { 23 namespace blink {
23 24
24 typedef WTF::HashMap<const InlineTextBox*, TextBlobPtr> 25 typedef WTF::HashMap<const InlineTextBox*, TextBlobPtr>
25 InlineTextBoxBlobCacheMap; 26 InlineTextBoxBlobCacheMap;
26 static InlineTextBoxBlobCacheMap* gTextBlobCache; 27 static InlineTextBoxBlobCacheMap* gTextBlobCache;
27 28
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 // paint only the text that is selected 278 // paint only the text that is selected
278 bool textBlobIsCacheable = selectionStart == 0 && selectionEnd == length; 279 bool textBlobIsCacheable = selectionStart == 0 && selectionEnd == length;
279 TextBlobPtr* cachedTextBlob = 0; 280 TextBlobPtr* cachedTextBlob = 0;
280 if (textBlobIsCacheable) 281 if (textBlobIsCacheable)
281 cachedTextBlob = addToTextBlobCache(m_inlineTextBox); 282 cachedTextBlob = addToTextBlobCache(m_inlineTextBox);
282 textPainter.paint(selectionStart, selectionEnd, length, selectionStyle, 283 textPainter.paint(selectionStart, selectionEnd, length, selectionStyle,
283 cachedTextBlob); 284 cachedTextBlob);
284 } 285 }
285 286
286 // Paint decorations 287 // Paint decorations
287 TextDecoration textDecorations = styleToUse.textDecorationsInEffect(); 288 if (styleToUse.textDecorationsInEffect() != TextDecorationNone &&
288 if (textDecorations != TextDecorationNone && !paintSelectedTextOnly) { 289 !paintSelectedTextOnly) {
289 GraphicsContextStateSaver stateSaver(context, false); 290 GraphicsContextStateSaver stateSaver(context, false);
290 TextPainter::updateGraphicsContext( 291 TextPainter::updateGraphicsContext(
291 context, textStyle, m_inlineTextBox.isHorizontal(), stateSaver); 292 context, textStyle, m_inlineTextBox.isHorizontal(), stateSaver);
292 if (combinedText) 293 if (combinedText)
293 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Clockwise)); 294 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Clockwise));
294 paintDecoration(paintInfo, boxOrigin, textDecorations); 295 paintDecorations(paintInfo, boxOrigin, styleToUse.appliedTextDecorations());
295 if (combinedText) 296 if (combinedText)
296 context.concatCTM( 297 context.concatCTM(
297 TextPainter::rotation(boxRect, TextPainter::Counterclockwise)); 298 TextPainter::rotation(boxRect, TextPainter::Counterclockwise));
298 } 299 }
299 300
300 if (paintInfo.phase == PaintPhaseForeground) 301 if (paintInfo.phase == PaintPhaseForeground)
301 paintDocumentMarkers(paintInfo, boxOrigin, styleToUse, font, 302 paintDocumentMarkers(paintInfo, boxOrigin, styleToUse, font,
302 DocumentMarkerPaintPhase::Foreground); 303 DocumentMarkerPaintPhase::Foreground);
303 304
304 if (shouldRotate) 305 if (shouldRotate)
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after
714 if (offset > 0) 715 if (offset > 0)
715 return (inlineTextBox->logicalHeight() + gap + offset).toInt(); 716 return (inlineTextBox->logicalHeight() + gap + offset).toInt();
716 return (inlineTextBox->logicalHeight() + gap).toInt(); 717 return (inlineTextBox->logicalHeight() + gap).toInt();
717 } 718 }
718 } 719 }
719 720
720 ASSERT_NOT_REACHED(); 721 ASSERT_NOT_REACHED();
721 return fontMetrics.ascent() + gap; 722 return fontMetrics.ascent() + gap;
722 } 723 }
723 724
724 static bool shouldSetDecorationAntialias(TextDecorationStyle decorationStyle) { 725 static bool shouldSetDecorationAntialias(
725 return decorationStyle == TextDecorationStyleDotted || 726 const Vector<AppliedTextDecoration>& decorations) {
726 decorationStyle == TextDecorationStyleDashed; 727 for (const AppliedTextDecoration& decoration : decorations) {
727 } 728 TextDecorationStyle decorationStyle = decoration.style();
728 729 if (decorationStyle == TextDecorationStyleDotted ||
729 static bool shouldSetDecorationAntialias(TextDecorationStyle underline, 730 decorationStyle == TextDecorationStyleDashed)
730 TextDecorationStyle overline, 731 return true;
731 TextDecorationStyle linethrough) { 732 }
732 return shouldSetDecorationAntialias(underline) || 733 return false;
733 shouldSetDecorationAntialias(overline) ||
734 shouldSetDecorationAntialias(linethrough);
735 } 734 }
736 735
737 static StrokeStyle textDecorationStyleToStrokeStyle( 736 static StrokeStyle textDecorationStyleToStrokeStyle(
738 TextDecorationStyle decorationStyle) { 737 TextDecorationStyle decorationStyle) {
739 StrokeStyle strokeStyle = SolidStroke; 738 StrokeStyle strokeStyle = SolidStroke;
740 switch (decorationStyle) { 739 switch (decorationStyle) {
741 case TextDecorationStyleSolid: 740 case TextDecorationStyleSolid:
742 strokeStyle = SolidStroke; 741 strokeStyle = SolidStroke;
743 break; 742 break;
744 case TextDecorationStyleDouble: 743 case TextDecorationStyleDouble:
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
878 controlPoint2.setX(x + step); 877 controlPoint2.setX(x + step);
879 x += 2 * step; 878 x += 2 * step;
880 path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(x, yAxis)); 879 path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(x, yAxis));
881 } 880 }
882 } 881 }
883 882
884 context.setShouldAntialias(true); 883 context.setShouldAntialias(true);
885 context.strokePath(path); 884 context.strokePath(path);
886 } 885 }
887 886
888 static void paintAppliedDecoration( 887 static void paintAppliedDecoration(GraphicsContext& context,
889 GraphicsContext& context, 888 FloatPoint start,
890 FloatPoint start, 889 float width,
891 float width, 890 float doubleOffset,
892 float doubleOffset, 891 int wavyOffsetFactor,
893 int wavyOffsetFactor, 892 AppliedTextDecoration decoration,
894 LayoutObject::AppliedTextDecoration decoration, 893 float thickness,
895 float thickness, 894 bool antialiasDecoration,
896 bool antialiasDecoration, 895 bool isPrinting) {
897 bool isPrinting) { 896 context.setStrokeStyle(textDecorationStyleToStrokeStyle(decoration.style()));
898 context.setStrokeStyle(textDecorationStyleToStrokeStyle(decoration.style)); 897 context.setStrokeColor(decoration.color());
899 context.setStrokeColor(decoration.color);
900 898
901 switch (decoration.style) { 899 switch (decoration.style()) {
902 case TextDecorationStyleWavy: 900 case TextDecorationStyleWavy:
903 strokeWavyTextDecoration( 901 strokeWavyTextDecoration(
904 context, start + FloatPoint(0, doubleOffset * wavyOffsetFactor), 902 context, start + FloatPoint(0, doubleOffset * wavyOffsetFactor),
905 start + FloatPoint(width, doubleOffset * wavyOffsetFactor), 903 start + FloatPoint(width, doubleOffset * wavyOffsetFactor),
906 thickness); 904 thickness);
907 break; 905 break;
908 case TextDecorationStyleDotted: 906 case TextDecorationStyleDotted:
909 case TextDecorationStyleDashed: 907 case TextDecorationStyleDashed:
910 context.setShouldAntialias(antialiasDecoration); 908 context.setShouldAntialias(antialiasDecoration);
911 // Fall through 909 // Fall through
912 default: 910 default:
913 context.drawLineForText(FloatPoint(start), width, isPrinting); 911 context.drawLineForText(FloatPoint(start), width, isPrinting);
914 912
915 if (decoration.style == TextDecorationStyleDouble) 913 if (decoration.style() == TextDecorationStyleDouble)
916 context.drawLineForText(start + FloatPoint(0, doubleOffset), width, 914 context.drawLineForText(start + FloatPoint(0, doubleOffset), width,
917 isPrinting); 915 isPrinting);
918 } 916 }
919 } 917 }
920 918
921 void InlineTextBoxPainter::paintDecoration(const PaintInfo& paintInfo, 919 void InlineTextBoxPainter::paintDecorations(
922 const LayoutPoint& boxOrigin, 920 const PaintInfo& paintInfo,
923 TextDecoration deco) { 921 const LayoutPoint& boxOrigin,
922 const Vector<AppliedTextDecoration>& decorations) {
924 if (m_inlineTextBox.truncation() == cFullTruncation) 923 if (m_inlineTextBox.truncation() == cFullTruncation)
925 return; 924 return;
926 925
927 GraphicsContext& context = paintInfo.context; 926 GraphicsContext& context = paintInfo.context;
928 GraphicsContextStateSaver stateSaver(context); 927 GraphicsContextStateSaver stateSaver(context);
929 928
930 LayoutPoint localOrigin(boxOrigin); 929 LayoutPoint localOrigin(boxOrigin);
931 930
932 LayoutUnit width = m_inlineTextBox.logicalWidth(); 931 LayoutUnit width = m_inlineTextBox.logicalWidth();
933 if (m_inlineTextBox.truncation() != cNoTruncation) { 932 if (m_inlineTextBox.truncation() != cNoTruncation) {
934 bool ltr = m_inlineTextBox.isLeftToRightDirection(); 933 bool ltr = m_inlineTextBox.isLeftToRightDirection();
935 bool flowIsLTR = 934 bool flowIsLTR =
936 m_inlineTextBox.getLineLayoutItem().style()->isLeftToRightDirection(); 935 m_inlineTextBox.getLineLayoutItem().style()->isLeftToRightDirection();
937 width = LayoutUnit(m_inlineTextBox.getLineLayoutItem().width( 936 width = LayoutUnit(m_inlineTextBox.getLineLayoutItem().width(
938 ltr == flowIsLTR ? m_inlineTextBox.start() 937 ltr == flowIsLTR ? m_inlineTextBox.start()
939 : m_inlineTextBox.truncation(), 938 : m_inlineTextBox.truncation(),
940 ltr == flowIsLTR ? m_inlineTextBox.truncation() 939 ltr == flowIsLTR ? m_inlineTextBox.truncation()
941 : m_inlineTextBox.len() - m_inlineTextBox.truncation(), 940 : m_inlineTextBox.len() - m_inlineTextBox.truncation(),
942 m_inlineTextBox.textPos(), flowIsLTR ? LTR : RTL, 941 m_inlineTextBox.textPos(), flowIsLTR ? LTR : RTL,
943 m_inlineTextBox.isFirstLineStyle())); 942 m_inlineTextBox.isFirstLineStyle()));
944 if (!flowIsLTR) 943 if (!flowIsLTR)
945 localOrigin.move(m_inlineTextBox.logicalWidth() - width, LayoutUnit()); 944 localOrigin.move(m_inlineTextBox.logicalWidth() - width, LayoutUnit());
946 } 945 }
947 946
948 // Get the text decoration colors.
949 LayoutObject::AppliedTextDecoration underline, overline, linethrough;
950 LayoutObject& textBoxLayoutObject = inlineLayoutObject();
951 textBoxLayoutObject.getTextDecorations(deco, underline, overline, linethrough,
952 true);
953 if (m_inlineTextBox.isFirstLineStyle())
954 textBoxLayoutObject.getTextDecorations(deco, underline, overline,
955 linethrough, true, true);
956
957 // Use a special function for underlines to get the positioning exactly right. 947 // Use a special function for underlines to get the positioning exactly right.
958 bool isPrinting = paintInfo.isPrinting(); 948 bool isPrinting = paintInfo.isPrinting();
959 949
950 LayoutObject& textBoxLayoutObject = inlineLayoutObject();
960 const ComputedStyle& styleToUse = 951 const ComputedStyle& styleToUse =
961 textBoxLayoutObject.styleRef(m_inlineTextBox.isFirstLineStyle()); 952 textBoxLayoutObject.styleRef(m_inlineTextBox.isFirstLineStyle());
962 const SimpleFontData* fontData = styleToUse.font().primaryFont(); 953 const SimpleFontData* fontData = styleToUse.font().primaryFont();
963 DCHECK(fontData); 954 DCHECK(fontData);
964 float baseline = fontData ? fontData->getFontMetrics().ascent() : 0; 955 float baseline = fontData ? fontData->getFontMetrics().ascent() : 0;
965 956
966 // Set the thick of the line to be 10% (or something else ?)of the computed 957 // Set the thick of the line to be 10% (or something else ?)of the computed
967 // font size and not less than 1px. Using computedFontSize should take care 958 // font size and not less than 1px. Using computedFontSize should take care
968 // of zoom as well. 959 // of zoom as well.
969 960
970 // Update Underline thickness, in case we have Faulty Font Metrics calculating 961 // Update Underline thickness, in case we have Faulty Font Metrics calculating
971 // underline thickness by old method. 962 // underline thickness by old method.
972 float textDecorationThickness = 0.0; 963 float textDecorationThickness = 0.0;
973 int fontHeightInt = 0; 964 int fontHeightInt = 0;
974 if (fontData) { 965 if (fontData) {
975 textDecorationThickness = fontData->getFontMetrics().underlineThickness(); 966 textDecorationThickness = fontData->getFontMetrics().underlineThickness();
976 fontHeightInt = (int)(fontData->getFontMetrics().floatHeight() + 0.5); 967 fontHeightInt = (int)(fontData->getFontMetrics().floatHeight() + 0.5);
977 } 968 }
978 if ((textDecorationThickness == 0.f) || 969 if ((textDecorationThickness == 0.f) ||
979 (textDecorationThickness >= (fontHeightInt >> 1))) 970 (textDecorationThickness >= (fontHeightInt >> 1)))
980 textDecorationThickness = 971 textDecorationThickness =
981 std::max(1.f, styleToUse.computedFontSize() / 10.f); 972 std::max(1.f, styleToUse.computedFontSize() / 10.f);
982 973
983 context.setStrokeThickness(textDecorationThickness); 974 context.setStrokeThickness(textDecorationThickness);
984 975
985 bool antialiasDecoration = shouldSetDecorationAntialias( 976 bool antialiasDecoration = shouldSetDecorationAntialias(decorations);
986 overline.style, underline.style, linethrough.style);
987 977
988 // Offset between lines - always non-zero, so lines never cross each other. 978 // Offset between lines - always non-zero, so lines never cross each other.
989 float doubleOffset = textDecorationThickness + 1.f; 979 float doubleOffset = textDecorationThickness + 1.f;
990 980
991 if ((deco & TextDecorationUnderline) && fontData) { 981 for (const AppliedTextDecoration& decoration : decorations) {
992 const int underlineOffset = computeUnderlineOffset( 982 TextDecoration lines = decoration.lines();
993 styleToUse.getTextUnderlinePosition(), fontData->getFontMetrics(), 983 if (lines & TextDecorationUnderline && fontData) {
994 &m_inlineTextBox, textDecorationThickness); 984 const int underlineOffset = computeUnderlineOffset(
995 paintAppliedDecoration( 985 styleToUse.getTextUnderlinePosition(), fontData->getFontMetrics(),
996 context, FloatPoint(localOrigin) + FloatPoint(0, underlineOffset), 986 &m_inlineTextBox, textDecorationThickness);
997 width.toFloat(), doubleOffset, 1, underline, textDecorationThickness, 987 paintAppliedDecoration(
998 antialiasDecoration, isPrinting); 988 context, FloatPoint(localOrigin) + FloatPoint(0, underlineOffset),
999 } 989 width.toFloat(), doubleOffset, 1, decoration, textDecorationThickness,
1000 if (deco & TextDecorationOverline) { 990 antialiasDecoration, isPrinting);
1001 paintAppliedDecoration(context, FloatPoint(localOrigin), width.toFloat(), 991 }
1002 -doubleOffset, 1, overline, textDecorationThickness, 992 if (lines & TextDecorationOverline) {
1003 antialiasDecoration, isPrinting); 993 paintAppliedDecoration(
1004 } 994 context, FloatPoint(localOrigin), width.toFloat(), -doubleOffset, 1,
1005 if (deco & TextDecorationLineThrough) { 995 decoration, textDecorationThickness, antialiasDecoration, isPrinting);
1006 const float lineThroughOffset = 2 * baseline / 3; 996 }
1007 paintAppliedDecoration( 997 if (lines & TextDecorationLineThrough) {
1008 context, FloatPoint(localOrigin) + FloatPoint(0, lineThroughOffset), 998 const float lineThroughOffset = 2 * baseline / 3;
1009 width.toFloat(), doubleOffset, 0, linethrough, textDecorationThickness, 999 paintAppliedDecoration(
1010 antialiasDecoration, isPrinting); 1000 context, FloatPoint(localOrigin) + FloatPoint(0, lineThroughOffset),
1001 width.toFloat(), doubleOffset, 0, decoration, textDecorationThickness,
1002 antialiasDecoration, isPrinting);
1003 }
1011 } 1004 }
1012 } 1005 }
1013 1006
1014 void InlineTextBoxPainter::paintCompositionUnderline( 1007 void InlineTextBoxPainter::paintCompositionUnderline(
1015 GraphicsContext& context, 1008 GraphicsContext& context,
1016 const LayoutPoint& boxOrigin, 1009 const LayoutPoint& boxOrigin,
1017 const CompositionUnderline& underline) { 1010 const CompositionUnderline& underline) {
1018 if (underline.color() == Color::transparent) 1011 if (underline.color() == Color::transparent)
1019 return; 1012 return;
1020 1013
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
1158 GraphicsContextStateSaver stateSaver(context); 1151 GraphicsContextStateSaver stateSaver(context);
1159 1152
1160 LayoutRect boxRect(boxOrigin, LayoutSize(m_inlineTextBox.logicalWidth(), 1153 LayoutRect boxRect(boxOrigin, LayoutSize(m_inlineTextBox.logicalWidth(),
1161 m_inlineTextBox.logicalHeight())); 1154 m_inlineTextBox.logicalHeight()));
1162 context.clip(FloatRect(boxRect)); 1155 context.clip(FloatRect(boxRect));
1163 context.drawHighlightForText(font, run, FloatPoint(boxOrigin), 1156 context.drawHighlightForText(font, run, FloatPoint(boxOrigin),
1164 boxRect.height().toInt(), color, sPos, ePos); 1157 boxRect.height().toInt(), color, sPos, ePos);
1165 } 1158 }
1166 1159
1167 } // namespace blink 1160 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698