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

Side by Side Diff: Source/core/rendering/InlineTextBox.cpp

Issue 203273003: Underline Thickness is not uniform (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Fixing comments and adding new test case Created 6 years, 9 months 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 /* 1 /*
2 * (C) 1999 Lars Knoll (knoll@kde.org) 2 * (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2000 Dirk Mueller (mueller@kde.org) 3 * (C) 2000 Dirk Mueller (mueller@kde.org)
4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r ights reserved. 4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r ights reserved.
5 * 5 *
6 * This library is free software; you can redistribute it and/or 6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public 7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either 8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version. 9 * version 2 of the License, or (at your option) any later version.
10 * 10 *
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 #include "wtf/text/StringBuilder.h" 53 #include "wtf/text/StringBuilder.h"
54 54
55 using namespace std; 55 using namespace std;
56 56
57 namespace WebCore { 57 namespace WebCore {
58 58
59 struct SameSizeAsInlineTextBox : public InlineBox { 59 struct SameSizeAsInlineTextBox : public InlineBox {
60 unsigned variables[1]; 60 unsigned variables[1];
61 unsigned short variables2[2]; 61 unsigned short variables2[2];
62 void* pointers[2]; 62 void* pointers[2];
63 float u;
63 }; 64 };
64 65
65 COMPILE_ASSERT(sizeof(InlineTextBox) == sizeof(SameSizeAsInlineTextBox), InlineT extBox_should_stay_small); 66 COMPILE_ASSERT(sizeof(InlineTextBox) == sizeof(SameSizeAsInlineTextBox), InlineT extBox_should_stay_small);
66 67
67 typedef WTF::HashMap<const InlineTextBox*, LayoutRect> InlineTextBoxOverflowMap; 68 typedef WTF::HashMap<const InlineTextBox*, LayoutRect> InlineTextBoxOverflowMap;
68 static InlineTextBoxOverflowMap* gTextBoxesWithOverflow; 69 static InlineTextBoxOverflowMap* gTextBoxesWithOverflow;
69 70
70 static const int misspellingLineThickness = 3; 71 static const int misspellingLineThickness = 3;
71 72
72 void InlineTextBox::destroy() 73 void InlineTextBox::destroy()
(...skipping 670 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 int startOffset = combinedText ? 0 : sPos; 744 int startOffset = combinedText ? 0 : sPos;
744 int endOffset = combinedText ? objectReplacementCharacterTextRun.len gth() : ePos; 745 int endOffset = combinedText ? objectReplacementCharacterTextRun.len gth() : ePos;
745 int paintRunLength = combinedText ? endOffset : length; 746 int paintRunLength = combinedText ? endOffset : length;
746 paintTextWithShadows(context, rendererToUse, combinedText ? combined Text->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffs et, startOffset, endOffset, paintRunLength, emphasisMarkTextOrigin, boxRect, sel ectionShadow, selectionStrokeWidth > 0, isHorizontal()); 747 paintTextWithShadows(context, rendererToUse, combinedText ? combined Text->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffs et, startOffset, endOffset, paintRunLength, emphasisMarkTextOrigin, boxRect, sel ectionShadow, selectionStrokeWidth > 0, isHorizontal());
747 748
748 if (combinedText) 749 if (combinedText)
749 context->concatCTM(rotation(boxRect, Counterclockwise)); 750 context->concatCTM(rotation(boxRect, Counterclockwise));
750 } 751 }
751 } 752 }
752 753
753 // Paint decorations 754 // lets only store decorations style and underline thickness, painting of de coration style will be done later
754 TextDecoration textDecorations = styleToUse->textDecorationsInEffect(); 755 TextDecoration textDecorations = styleToUse->textDecorationsInEffect();
755 if (textDecorations != TextDecorationNone && paintInfo.phase != PaintPhaseSe lection) { 756 if (textDecorations != TextDecorationNone && paintInfo.phase != PaintPhaseSe lection) {
756 updateGraphicsContext(context, textFillColor, textStrokeColor, textStrok eWidth); 757 float textDecorationThickness = styleToUse->fontMetrics().underlineThick ness();
leviw_travelin_and_unemployed 2014/03/21 20:43:08 Don't copy and paste this block of code. If you ne
757 if (combinedText) 758 int fontHeightInt = (int)(styleToUse->fontMetrics().floatHeight() + 0.5) ;
758 context->concatCTM(rotation(boxRect, Clockwise)); 759 if ((textDecorationThickness == 0.f) || (textDecorationThickness >= (fon tHeightInt >> 1)))
759 paintDecoration(context, boxOrigin, textDecorations, textShadow); 760 textDecorationThickness = std::max(1.f, styleToUse->computedFontSize () / 10.f);
760 if (combinedText)
761 context->concatCTM(rotation(boxRect, Counterclockwise));
762 }
763 761
764 if (paintInfo.phase == PaintPhaseForeground) { 762 setDecorationThickness(textDecorationThickness);
765 paintDocumentMarkers(context, boxOrigin, styleToUse, font, false);
766
767 if (useCustomUnderlines) {
768 const Vector<CompositionUnderline>& underlines = renderer().frame()- >inputMethodController().customCompositionUnderlines();
769 size_t numUnderlines = underlines.size();
770
771 for (size_t index = 0; index < numUnderlines; ++index) {
772 const CompositionUnderline& underline = underlines[index];
773
774 if (underline.endOffset <= start())
775 // underline is completely before this run. This might be a n underline that sits
776 // before the first run we draw, or underlines that were wit hin runs we skipped
777 // due to truncation.
778 continue;
779
780 if (underline.startOffset <= end()) {
781 // underline intersects this run. Paint it.
782 paintCompositionUnderline(context, boxOrigin, underline);
783 if (underline.endOffset > end() + 1)
784 // underline also runs into the next run. Bail now, no m ore marker advancement.
785 break;
786 } else
787 // underline is completely after this run, bail. A later ru n will paint it.
788 break;
789 }
790 }
791 } 763 }
792 764
793 if (shouldRotate) 765 if (shouldRotate)
794 context->concatCTM(rotation(boxRect, Counterclockwise)); 766 context->concatCTM(rotation(boxRect, Counterclockwise));
795 } 767 }
796 768
797 void InlineTextBox::selectionStartEnd(int& sPos, int& ePos) 769 void InlineTextBox::selectionStartEnd(int& sPos, int& ePos)
798 { 770 {
799 int startPos, endPos; 771 int startPos, endPos;
800 if (renderer().selectionState() == RenderObject::SelectionInside) { 772 if (renderer().selectionState() == RenderObject::SelectionInside) {
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
1086 context->setShouldAntialias(antialiasDecoration); 1058 context->setShouldAntialias(antialiasDecoration);
1087 // Fall through 1059 // Fall through
1088 default: 1060 default:
1089 context->drawLineForText(start, width, isPrinting); 1061 context->drawLineForText(start, width, isPrinting);
1090 1062
1091 if (decoration.style == TextDecorationStyleDouble) 1063 if (decoration.style == TextDecorationStyleDouble)
1092 context->drawLineForText(start + FloatPoint(0, doubleOffset), width, isPrinting); 1064 context->drawLineForText(start + FloatPoint(0, doubleOffset), width, isPrinting);
1093 } 1065 }
1094 } 1066 }
1095 1067
1096 void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, TextDecoration deco, const ShadowList* shadowList) 1068 void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, TextDecoration deco, const ShadowList* shadowList, float decorationTh ickness)
1097 { 1069 {
1098 GraphicsContextStateSaver stateSaver(*context); 1070 GraphicsContextStateSaver stateSaver(*context);
1099 1071
1100 if (m_truncation == cFullTruncation) 1072 if (m_truncation == cFullTruncation)
1101 return; 1073 return;
1102 1074
1103 FloatPoint localOrigin = boxOrigin; 1075 FloatPoint localOrigin = boxOrigin;
1104 1076
1105 float width = m_logicalWidth; 1077 float width = m_logicalWidth;
1106 if (m_truncation != cNoTruncation) { 1078 if (m_truncation != cNoTruncation) {
(...skipping 15 matching lines...) Expand all
1122 bool linesAreOpaque = !isPrinting && (!(deco & TextDecorationUnderline) || u nderline.color.alpha() == 255) && (!(deco & TextDecorationOverline) || overline. color.alpha() == 255) && (!(deco & TextDecorationLineThrough) || linethrough.col or.alpha() == 255); 1094 bool linesAreOpaque = !isPrinting && (!(deco & TextDecorationUnderline) || u nderline.color.alpha() == 255) && (!(deco & TextDecorationOverline) || overline. color.alpha() == 255) && (!(deco & TextDecorationLineThrough) || linethrough.col or.alpha() == 255);
1123 1095
1124 RenderStyle* styleToUse = renderer().style(isFirstLineStyle()); 1096 RenderStyle* styleToUse = renderer().style(isFirstLineStyle());
1125 int baseline = styleToUse->fontMetrics().ascent(); 1097 int baseline = styleToUse->fontMetrics().ascent();
1126 1098
1127 size_t shadowCount = shadowList ? shadowList->shadows().size() : 0; 1099 size_t shadowCount = shadowList ? shadowList->shadows().size() : 0;
1128 // Set the thick of the line to be 10% (or something else ?)of the computed font size and not less than 1px. 1100 // Set the thick of the line to be 10% (or something else ?)of the computed font size and not less than 1px.
1129 // Using computedFontSize should take care of zoom as well. 1101 // Using computedFontSize should take care of zoom as well.
1130 1102
1131 // Update Underline thickness, in case we have Faulty Font Metrics calculati ng underline thickness by old method. 1103 // Update Underline thickness, in case we have Faulty Font Metrics calculati ng underline thickness by old method.
1132 float textDecorationThickness = styleToUse->fontMetrics().underlineThickness (); 1104 float textDecorationThickness = 0;
1133 int fontHeightInt = (int)(styleToUse->fontMetrics().floatHeight() + 0.5); 1105 if (!decorationThickness) {
leviw_travelin_and_unemployed 2014/03/21 20:43:08 I don't fully understand the case when we have to
1134 if ((textDecorationThickness == 0.f) || (textDecorationThickness >= (fontHei ghtInt >> 1))) 1106 textDecorationThickness = styleToUse->fontMetrics().underlineThickness() ;
1135 textDecorationThickness = std::max(1.f, styleToUse->computedFontSize() / 10.f); 1107 int fontHeightInt = (int)(styleToUse->fontMetrics().floatHeight() + 0.5) ;
1108 if ((textDecorationThickness == 0.f) || (textDecorationThickness >= (fon tHeightInt >> 1)))
1109 textDecorationThickness = std::max(1.f, styleToUse->computedFontSize () / 10.f);
1110 } else {
1111 textDecorationThickness = decorationThickness;
1112 }
1136 1113
1137 context->setStrokeThickness(textDecorationThickness); 1114 context->setStrokeThickness(textDecorationThickness);
1138 1115
1139 bool antialiasDecoration = shouldSetDecorationAntialias(overline.style, unde rline.style, linethrough.style) 1116 bool antialiasDecoration = shouldSetDecorationAntialias(overline.style, unde rline.style, linethrough.style)
1140 && RenderBoxModelObject::shouldAntialiasLines(context); 1117 && RenderBoxModelObject::shouldAntialiasLines(context);
1141 1118
1142 float extraOffset = 0; 1119 float extraOffset = 0;
1143 if (!linesAreOpaque && shadowCount > 1) { 1120 if (!linesAreOpaque && shadowCount > 1) {
1144 FloatRect clipRect(localOrigin, FloatSize(width, baseline + 2)); 1121 FloatRect clipRect(localOrigin, FloatSize(width, baseline + 2));
1145 for (size_t i = shadowCount; i--; ) { 1122 for (size_t i = shadowCount; i--; ) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1181 if (deco & TextDecorationOverline) { 1158 if (deco & TextDecorationOverline) {
1182 paintAppliedDecoration(context, localOrigin, width, -doubleOffset, 1 , overline, textDecorationThickness, antialiasDecoration, isPrinting); 1159 paintAppliedDecoration(context, localOrigin, width, -doubleOffset, 1 , overline, textDecorationThickness, antialiasDecoration, isPrinting);
1183 } 1160 }
1184 if (deco & TextDecorationLineThrough) { 1161 if (deco & TextDecorationLineThrough) {
1185 const float lineThroughOffset = 2 * baseline / 3; 1162 const float lineThroughOffset = 2 * baseline / 3;
1186 paintAppliedDecoration(context, localOrigin + FloatPoint(0, lineThro ughOffset), width, doubleOffset, 0, linethrough, textDecorationThickness, antial iasDecoration, isPrinting); 1163 paintAppliedDecoration(context, localOrigin + FloatPoint(0, lineThro ughOffset), width, doubleOffset, 0, linethrough, textDecorationThickness, antial iasDecoration, isPrinting);
1187 } 1164 }
1188 } 1165 }
1189 } 1166 }
1190 1167
1168 void InlineTextBox::paintDecorationStyle(PaintInfo& paintInfo, const LayoutPoint & paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom, float decorationThickn ess)
leviw_travelin_and_unemployed 2014/03/21 20:43:08 Whoa... This is a *ton* of code duplication, no?
1169 {
1170 if (isLineBreak() || !paintInfo.shouldPaintWithinRoot(&renderer()) || render er().style()->visibility() != VISIBLE
1171 || m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutli ne || !m_len)
1172 return;
1173
1174 ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintP haseChildOutlines);
1175
1176 LayoutUnit logicalLeftSide = logicalLeftVisualOverflow();
1177 LayoutUnit logicalRightSide = logicalRightVisualOverflow();
1178 LayoutUnit logicalStart = logicalLeftSide + (isHorizontal() ? paintOffset.x( ) : paintOffset.y());
1179 LayoutUnit logicalExtent = logicalRightSide - logicalLeftSide;
1180
1181 LayoutUnit paintEnd = isHorizontal() ? paintInfo.rect.maxX() : paintInfo.rec t.maxY();
1182 LayoutUnit paintStart = isHorizontal() ? paintInfo.rect.x() : paintInfo.rect .y();
1183
1184 LayoutPoint adjustedPaintOffset = roundedIntPoint(paintOffset);
1185 bool isPrinting = textRenderer().document().printing();
1186
1187 if (logicalStart >= paintEnd || logicalStart + logicalExtent <= paintStart)
1188 return;
1189
1190 // Determine whether or not we have composition underlines to draw.
1191 bool containsComposition = renderer().node() && renderer().frame()->inputMet hodController().compositionNode() == renderer().node();
1192 bool useCustomUnderlines = containsComposition && renderer().frame()->inputM ethodController().compositionUsesCustomUnderlines();
1193
1194 // Determine whether or not we're selected.
1195 bool haveSelection = !isPrinting && paintInfo.phase != PaintPhaseTextClip && selectionState() != RenderObject::SelectionNone;
1196 if (!haveSelection && paintInfo.phase == PaintPhaseSelection) {
1197 // When only painting the selection, don't bother to paint if there is n one.
1198 return;
1199 }
1200
1201 GraphicsContext* context = paintInfo.context;
1202 RenderObject& rendererToUse = renderer();
1203 RenderStyle* styleToUse = rendererToUse.style(isFirstLineStyle());
1204
1205 // Set our font.
1206 const Font& font = styleToUse->font();
1207 FloatPoint boxOrigin = locationIncludingFlipping();
1208 // FIXME: Shouldn't these offsets be rounded?
1209 boxOrigin.move(adjustedPaintOffset.x().toFloat(), adjustedPaintOffset.y().to Float());
1210 FloatRect boxRect(boxOrigin, LayoutSize(logicalWidth(), logicalHeight()));
1211
1212 TextDecoration deco = styleToUse->textDecorationsInEffect();
1213 const ShadowList* textShadow = (context->printing() || paintInfo.forceBlackT ext()) ? 0 : styleToUse->textShadow();
1214
1215 // Determine the text colors and selection colors.
1216 Color textFillColor;
1217 Color textStrokeColor;
1218 Color emphasisMarkColor;
1219 float textStrokeWidth = styleToUse->textStrokeWidth();
1220
1221 if (paintInfo.forceBlackText()) {
1222 textFillColor = Color::black;
1223 textStrokeColor = Color::black;
1224 emphasisMarkColor = Color::black;
1225 } else {
1226 textFillColor = rendererToUse.resolveColor(styleToUse, CSSPropertyWebkit TextFillColor);
1227
1228 bool forceBackgroundToWhite = false;
1229 if (isPrinting) {
1230 if (styleToUse->printColorAdjust() == PrintColorAdjustEconomy)
1231 forceBackgroundToWhite = true;
1232 if (textRenderer().document().settings() && textRenderer().document( ).settings()->shouldPrintBackgrounds())
1233 forceBackgroundToWhite = false;
1234 }
1235
1236 // Make the text fill color legible against a white background
1237 if (forceBackgroundToWhite)
1238 textFillColor = correctedTextColor(textFillColor, Color::white);
1239
1240 textStrokeColor = rendererToUse.resolveColor(styleToUse, CSSPropertyWebk itTextStrokeColor);
1241
1242 // Make the text stroke color legible against a white background
1243 if (forceBackgroundToWhite)
1244 textStrokeColor = correctedTextColor(textStrokeColor, Color::white);
1245
1246 emphasisMarkColor = rendererToUse.resolveColor(styleToUse, CSSPropertyWe bkitTextEmphasisColor);
1247
1248 // Make the text stroke color legible against a white background
1249 if (forceBackgroundToWhite)
1250 emphasisMarkColor = correctedTextColor(emphasisMarkColor, Color::whi te);
1251 }
1252 updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWid th);
1253 paintDecoration(context, boxOrigin, deco, textShadow, decorationThickness);
1254
1255 if (paintInfo.phase == PaintPhaseForeground) {
1256 paintDocumentMarkers(context, boxOrigin, styleToUse, font, false);
1257
1258 if (useCustomUnderlines) {
1259 const Vector<CompositionUnderline>& underlines = renderer().frame()- >inputMethodController().customCompositionUnderlines();
1260 size_t numUnderlines = underlines.size();
1261
1262 for (size_t index = 0; index < numUnderlines; ++index) {
1263 const CompositionUnderline& underline = underlines[index];
1264
1265 if (underline.endOffset <= start()) {
1266 // underline is completely before this run. This might be an underline that sits
1267 // before the first run we draw, or underlines that were wit hin runs we skipped
1268 // due to truncation.
1269 continue;
1270 }
1271
1272 if (underline.startOffset <= end()) {
1273 // underline intersects this run. Paint it.
1274 paintCompositionUnderline(context, boxOrigin, underline);
1275 if (underline.endOffset > end() + 1) {
1276 // underline also runs into the next run. Bail now, no m ore marker advancement.
1277 break;
1278 }
1279 } else {
1280 // underline is completely after this run, bail. A later run will paint it.
1281 break;
1282 }
1283 }
1284 }
1285 }
1286 }
1287
1288 void InlineTextBox::getPaintDecorationSyle(PaintInfo& paintInfo, const LayoutPoi nt& paintOffset, float * decorationThickness)
1289 {
1290 *decorationThickness = 0;
1291 if (isLineBreak() || !paintInfo.shouldPaintWithinRoot(&renderer()) || render er().style()->visibility() != VISIBLE
1292 || m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutli ne || !m_len)
1293 return;
1294
1295 *decorationThickness = getDecorationThickness();
1296 }
1297
1191 static GraphicsContext::DocumentMarkerLineStyle lineStyleForMarkerType(DocumentM arker::MarkerType markerType) 1298 static GraphicsContext::DocumentMarkerLineStyle lineStyleForMarkerType(DocumentM arker::MarkerType markerType)
1192 { 1299 {
1193 switch (markerType) { 1300 switch (markerType) {
1194 case DocumentMarker::Spelling: 1301 case DocumentMarker::Spelling:
1195 return GraphicsContext::DocumentMarkerSpellingLineStyle; 1302 return GraphicsContext::DocumentMarkerSpellingLineStyle;
1196 case DocumentMarker::Grammar: 1303 case DocumentMarker::Grammar:
1197 return GraphicsContext::DocumentMarkerGrammarLineStyle; 1304 return GraphicsContext::DocumentMarkerGrammarLineStyle;
1198 default: 1305 default:
1199 ASSERT_NOT_REACHED(); 1306 ASSERT_NOT_REACHED();
1200 return GraphicsContext::DocumentMarkerSpellingLineStyle; 1307 return GraphicsContext::DocumentMarkerSpellingLineStyle;
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after
1565 printedCharacters = fprintf(stderr, "\t%s %p", obj.renderName(), &obj); 1672 printedCharacters = fprintf(stderr, "\t%s %p", obj.renderName(), &obj);
1566 const int rendererCharacterOffset = 24; 1673 const int rendererCharacterOffset = 24;
1567 for (; printedCharacters < rendererCharacterOffset; printedCharacters++) 1674 for (; printedCharacters < rendererCharacterOffset; printedCharacters++)
1568 fputc(' ', stderr); 1675 fputc(' ', stderr);
1569 fprintf(stderr, "(%d,%d) \"%s\"\n", start(), start() + len(), value.utf8().d ata()); 1676 fprintf(stderr, "(%d,%d) \"%s\"\n", start(), start() + len(), value.utf8().d ata());
1570 } 1677 }
1571 1678
1572 #endif 1679 #endif
1573 1680
1574 } // namespace WebCore 1681 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698