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