| 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(); |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |