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

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

Issue 2594983002: Don't paint underline or selections over ellipsis in mixed-flow contexts (Closed)
Patch Set: bug 642454 Created 3 years, 11 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 // 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"
(...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after
552 int selectionEnd = 0; 552 int selectionEnd = 0;
553 if (paintSelectedTextOnly || paintSelectedTextSeparately) 553 if (paintSelectedTextOnly || paintSelectedTextSeparately)
554 m_inlineTextBox.selectionStartEnd(selectionStart, selectionEnd); 554 m_inlineTextBox.selectionStartEnd(selectionStart, selectionEnd);
555 555
556 bool respectHyphen = 556 bool respectHyphen =
557 selectionEnd == static_cast<int>(m_inlineTextBox.len()) && 557 selectionEnd == static_cast<int>(m_inlineTextBox.len()) &&
558 m_inlineTextBox.hasHyphen(); 558 m_inlineTextBox.hasHyphen();
559 if (respectHyphen) 559 if (respectHyphen)
560 selectionEnd = textRun.length(); 560 selectionEnd = textRun.length();
561 561
562 bool ltr = m_inlineTextBox.isLeftToRightDirection();
563 bool flowIsLTR =
564 m_inlineTextBox.getLineLayoutItem().style()->isLeftToRightDirection();
562 if (m_inlineTextBox.truncation() != cNoTruncation) { 565 if (m_inlineTextBox.truncation() != cNoTruncation) {
566 // In a mixed-direction flow the ellipsis is at the start of the text
567 // rather than at the end of it.
563 selectionStart = 568 selectionStart =
564 std::min<int>(selectionStart, m_inlineTextBox.truncation()); 569 ltr == flowIsLTR
565 selectionEnd = std::min<int>(selectionEnd, m_inlineTextBox.truncation()); 570 ? std::min<int>(selectionStart, m_inlineTextBox.truncation())
566 length = m_inlineTextBox.truncation(); 571 : std::max<int>(selectionStart, m_inlineTextBox.truncation());
572 selectionEnd =
573 ltr == flowIsLTR
574 ? std::min<int>(selectionEnd, m_inlineTextBox.truncation())
575 : std::max<int>(selectionEnd, m_inlineTextBox.truncation());
576 length = ltr == flowIsLTR ? m_inlineTextBox.truncation() : textRun.length();
567 } 577 }
568 578
569 TextPainter textPainter(context, font, textRun, textOrigin, boxRect, 579 TextPainter textPainter(context, font, textRun, textOrigin, boxRect,
570 m_inlineTextBox.isHorizontal()); 580 m_inlineTextBox.isHorizontal());
571 TextEmphasisPosition emphasisMarkPosition; 581 TextEmphasisPosition emphasisMarkPosition;
572 bool hasTextEmphasis = 582 bool hasTextEmphasis =
573 m_inlineTextBox.getEmphasisMarkPosition(styleToUse, emphasisMarkPosition); 583 m_inlineTextBox.getEmphasisMarkPosition(styleToUse, emphasisMarkPosition);
574 if (hasTextEmphasis) 584 if (hasTextEmphasis)
575 textPainter.setEmphasisMark(styleToUse.textEmphasisMarkString(), 585 textPainter.setEmphasisMark(styleToUse.textEmphasisMarkString(),
576 emphasisMarkPosition); 586 emphasisMarkPosition);
577 if (combinedText) 587 if (combinedText)
578 textPainter.setCombinedText(combinedText); 588 textPainter.setCombinedText(combinedText);
589 if (m_inlineTextBox.truncation() != cNoTruncation && ltr != flowIsLTR)
590 textPainter.setEllipsisOffset(m_inlineTextBox.truncation());
579 591
580 if (!paintSelectedTextOnly) { 592 if (!paintSelectedTextOnly) {
581 int startOffset = 0; 593 int startOffset = 0;
582 int endOffset = length; 594 int endOffset = length;
595 // Where the text and its flow have opposite directions then our offset into
596 // the text given by |truncation| is at the start of the part that will be
597 // visible.
598 if (m_inlineTextBox.truncation() != cNoTruncation && ltr != flowIsLTR) {
599 startOffset = m_inlineTextBox.truncation();
600 endOffset = textRun.length();
601 }
602
583 if (paintSelectedTextSeparately && selectionStart < selectionEnd) { 603 if (paintSelectedTextSeparately && selectionStart < selectionEnd) {
584 startOffset = selectionEnd; 604 startOffset = selectionEnd;
585 endOffset = selectionStart; 605 endOffset = selectionStart;
586 } 606 }
587 // Where the text and its flow have opposite directions then our offset into
588 // the text given by |truncation| is at the start of the part that will be
589 // visible.
590 if (m_inlineTextBox.truncation() != cNoTruncation &&
591 m_inlineTextBox.getLineLayoutItem()
592 .containingBlock()
593 .style()
594 ->isLeftToRightDirection() !=
595 m_inlineTextBox.isLeftToRightDirection()) {
596 startOffset = m_inlineTextBox.truncation();
597 endOffset = textRun.length();
598 }
599 607
600 // FIXME: This cache should probably ultimately be held somewhere else. 608 // FIXME: This cache should probably ultimately be held somewhere else.
601 // A hashmap is convenient to avoid a memory hit when the 609 // A hashmap is convenient to avoid a memory hit when the
602 // RuntimeEnabledFeature is off. 610 // RuntimeEnabledFeature is off.
603 bool textBlobIsCacheable = startOffset == 0 && endOffset == length; 611 bool textBlobIsCacheable = startOffset == 0 && endOffset == length;
604 TextBlobPtr* cachedTextBlob = 0; 612 TextBlobPtr* cachedTextBlob = 0;
605 if (textBlobIsCacheable) 613 if (textBlobIsCacheable)
606 cachedTextBlob = addToTextBlobCache(m_inlineTextBox); 614 cachedTextBlob = addToTextBlobCache(m_inlineTextBox);
607 textPainter.paint(startOffset, endOffset, length, textStyle, 615 textPainter.paint(startOffset, endOffset, length, textStyle,
608 cachedTextBlob); 616 cachedTextBlob);
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after
938 c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue()); 946 c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue());
939 947
940 // If the text is truncated, let the thing being painted in the truncation 948 // If the text is truncated, let the thing being painted in the truncation
941 // draw its own highlight. 949 // draw its own highlight.
942 unsigned start = m_inlineTextBox.start(); 950 unsigned start = m_inlineTextBox.start();
943 int length = m_inlineTextBox.len(); 951 int length = m_inlineTextBox.len();
944 bool ltr = m_inlineTextBox.isLeftToRightDirection(); 952 bool ltr = m_inlineTextBox.isLeftToRightDirection();
945 bool flowIsLTR = 953 bool flowIsLTR =
946 m_inlineTextBox.getLineLayoutItem().style()->isLeftToRightDirection(); 954 m_inlineTextBox.getLineLayoutItem().style()->isLeftToRightDirection();
947 if (m_inlineTextBox.truncation() != cNoTruncation) { 955 if (m_inlineTextBox.truncation() != cNoTruncation) {
948 start = ltr == flowIsLTR ? m_inlineTextBox.start() 956 // In a mixed-direction flow the ellipsis is at the start of the text
949 : m_inlineTextBox.truncation(); 957 // so we need to start after it. Otherwise we just need to make sure
950 length = ltr == flowIsLTR 958 // the end of the text is where the ellipsis starts.
951 ? m_inlineTextBox.truncation() 959 if (ltr != flowIsLTR)
952 : m_inlineTextBox.len() - m_inlineTextBox.truncation(); 960 sPos = std::max<int>(sPos, m_inlineTextBox.truncation());
961 else
962 length = m_inlineTextBox.truncation();
953 } 963 }
954 StringView string(m_inlineTextBox.getLineLayoutItem().text(), start, 964 StringView string(m_inlineTextBox.getLineLayoutItem().text(), start,
955 static_cast<unsigned>(length)); 965 static_cast<unsigned>(length));
956 966
957 StringBuilder charactersWithHyphen; 967 StringBuilder charactersWithHyphen;
958 bool respectHyphen = ePos == length && m_inlineTextBox.hasHyphen(); 968 bool respectHyphen = ePos == length && m_inlineTextBox.hasHyphen();
959 TextRun textRun = m_inlineTextBox.constructTextRun( 969 TextRun textRun = m_inlineTextBox.constructTextRun(
960 style, string, m_inlineTextBox.getLineLayoutItem().textLength() - 970 style, string, m_inlineTextBox.getLineLayoutItem().textLength() -
961 m_inlineTextBox.start(), 971 m_inlineTextBox.start(),
962 respectHyphen ? &charactersWithHyphen : 0); 972 respectHyphen ? &charactersWithHyphen : 0);
(...skipping 18 matching lines...) Expand all
981 int deltaY = roundToInt( 991 int deltaY = roundToInt(
982 m_inlineTextBox.getLineLayoutItem().style()->isFlippedLinesWritingMode() 992 m_inlineTextBox.getLineLayoutItem().style()->isFlippedLinesWritingMode()
983 ? selectionBottom - m_inlineTextBox.logicalBottom() 993 ? selectionBottom - m_inlineTextBox.logicalBottom()
984 : m_inlineTextBox.logicalTop() - selectionTop); 994 : m_inlineTextBox.logicalTop() - selectionTop);
985 int selHeight = std::max(0, roundToInt(selectionBottom - selectionTop)); 995 int selHeight = std::max(0, roundToInt(selectionBottom - selectionTop));
986 996
987 FloatPoint localOrigin(boxRect.x().toFloat(), 997 FloatPoint localOrigin(boxRect.x().toFloat(),
988 (boxRect.y() - deltaY).toFloat()); 998 (boxRect.y() - deltaY).toFloat());
989 LayoutRect selectionRect = LayoutRect( 999 LayoutRect selectionRect = LayoutRect(
990 font.selectionRectForText(textRun, localOrigin, selHeight, sPos, ePos)); 1000 font.selectionRectForText(textRun, localOrigin, selHeight, sPos, ePos));
991 if (m_inlineTextBox.hasWrappedSelectionNewline() 1001 // For line breaks, just painting a selection where the line break itself
992 // For line breaks, just painting a selection where the line break itself 1002 // is rendered is sufficient. Don't select it if there's an ellipsis
993 // is rendered is sufficient. 1003 // there.
994 && !m_inlineTextBox.isLineBreak()) 1004 if (m_inlineTextBox.hasWrappedSelectionNewline() &&
1005 m_inlineTextBox.truncation() == cNoTruncation &&
1006 !m_inlineTextBox.isLineBreak())
995 expandToIncludeNewlineForSelection(selectionRect); 1007 expandToIncludeNewlineForSelection(selectionRect);
996 1008
997 // Line breaks report themselves as having zero width for layout purposes, 1009 // Line breaks report themselves as having zero width for layout purposes,
998 // and so will end up positioned at (0, 0), even though we paint their 1010 // and so will end up positioned at (0, 0), even though we paint their
999 // selection highlight with character width. For RTL then, we have to 1011 // selection highlight with character width. For RTL then, we have to
1000 // explicitly shift the selection rect over to paint in the right location. 1012 // explicitly shift the selection rect over to paint in the right location.
1001 if (!m_inlineTextBox.isLeftToRightDirection() && 1013 if (!m_inlineTextBox.isLeftToRightDirection() &&
1002 m_inlineTextBox.isLineBreak()) 1014 m_inlineTextBox.isLineBreak())
1003 selectionRect.move(-selectionRect.width(), LayoutUnit()); 1015 selectionRect.move(-selectionRect.width(), LayoutUnit());
1004 if (!flowIsLTR && m_inlineTextBox.truncation() != cNoTruncation) 1016 if (!flowIsLTR && !ltr && m_inlineTextBox.truncation() != cNoTruncation)
1005 selectionRect.move(m_inlineTextBox.logicalWidth() - selectionRect.width(), 1017 selectionRect.move(m_inlineTextBox.logicalWidth() - selectionRect.width(),
1006 LayoutUnit()); 1018 LayoutUnit());
1007 1019
1008 context.fillRect(FloatRect(selectionRect), c); 1020 context.fillRect(FloatRect(selectionRect), c);
1009 } 1021 }
1010 1022
1011 void InlineTextBoxPainter::expandToIncludeNewlineForSelection( 1023 void InlineTextBoxPainter::expandToIncludeNewlineForSelection(
1012 LayoutRect& rect) { 1024 LayoutRect& rect) {
1013 FloatRectOutsets outsets = FloatRectOutsets(); 1025 FloatRectOutsets outsets = FloatRectOutsets();
1014 float spaceWidth = m_inlineTextBox.newlineSpaceWidth(); 1026 float spaceWidth = m_inlineTextBox.newlineSpaceWidth();
(...skipping 16 matching lines...) Expand all
1031 GraphicsContextStateSaver stateSaver(context); 1043 GraphicsContextStateSaver stateSaver(context);
1032 1044
1033 LayoutPoint localOrigin(boxOrigin); 1045 LayoutPoint localOrigin(boxOrigin);
1034 1046
1035 LayoutUnit width = m_inlineTextBox.logicalWidth(); 1047 LayoutUnit width = m_inlineTextBox.logicalWidth();
1036 if (m_inlineTextBox.truncation() != cNoTruncation) { 1048 if (m_inlineTextBox.truncation() != cNoTruncation) {
1037 bool ltr = m_inlineTextBox.isLeftToRightDirection(); 1049 bool ltr = m_inlineTextBox.isLeftToRightDirection();
1038 bool flowIsLTR = 1050 bool flowIsLTR =
1039 m_inlineTextBox.getLineLayoutItem().style()->isLeftToRightDirection(); 1051 m_inlineTextBox.getLineLayoutItem().style()->isLeftToRightDirection();
1040 width = LayoutUnit(m_inlineTextBox.getLineLayoutItem().width( 1052 width = LayoutUnit(m_inlineTextBox.getLineLayoutItem().width(
1041 ltr == flowIsLTR ? m_inlineTextBox.start() 1053 ltr == flowIsLTR
1042 : m_inlineTextBox.truncation(), 1054 ? m_inlineTextBox.start()
1055 : m_inlineTextBox.start() + m_inlineTextBox.truncation(),
1043 ltr == flowIsLTR ? m_inlineTextBox.truncation() 1056 ltr == flowIsLTR ? m_inlineTextBox.truncation()
1044 : m_inlineTextBox.len() - m_inlineTextBox.truncation(), 1057 : m_inlineTextBox.len() - m_inlineTextBox.truncation(),
1045 m_inlineTextBox.textPos(), 1058 m_inlineTextBox.textPos(),
1046 flowIsLTR ? TextDirection::Ltr : TextDirection::Rtl, 1059 flowIsLTR ? TextDirection::Ltr : TextDirection::Rtl,
1047 m_inlineTextBox.isFirstLineStyle())); 1060 m_inlineTextBox.isFirstLineStyle()));
1048 if (!flowIsLTR) 1061 if (!flowIsLTR)
1049 localOrigin.move(m_inlineTextBox.logicalWidth() - width, LayoutUnit()); 1062 localOrigin.move(m_inlineTextBox.logicalWidth() - width, LayoutUnit());
1050 } 1063 }
1051 1064
1052 LayoutObject& textBoxLayoutObject = inlineLayoutObject(); 1065 LayoutObject& textBoxLayoutObject = inlineLayoutObject();
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
1276 1289
1277 LayoutRect boxRect(boxOrigin, LayoutSize(m_inlineTextBox.logicalWidth(), 1290 LayoutRect boxRect(boxOrigin, LayoutSize(m_inlineTextBox.logicalWidth(),
1278 m_inlineTextBox.logicalHeight())); 1291 m_inlineTextBox.logicalHeight()));
1279 context.clip(FloatRect(boxRect)); 1292 context.clip(FloatRect(boxRect));
1280 context.drawHighlightForText(font, run, FloatPoint(boxOrigin), 1293 context.drawHighlightForText(font, run, FloatPoint(boxOrigin),
1281 boxRect.height().toInt(), color, 1294 boxRect.height().toInt(), color,
1282 paintOffsets.first, paintOffsets.second); 1295 paintOffsets.first, paintOffsets.second);
1283 } 1296 }
1284 1297
1285 } // namespace blink 1298 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698