| Differences between
and this patch
- a/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayLineBuilder.cpp -4 / +38 lines
Lines 168-183 static float truncateOverflowingDisplayBoxes(const InlineDisplay::Line& displayL a/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayLineBuilder.cpp_sec1
168
    auto width = [&] (auto& displayBox) {
168
    auto width = [&] (auto& displayBox) {
169
        return isHorizontal ? displayBox.width() : displayBox.height();
169
        return isHorizontal ? displayBox.width() : displayBox.height();
170
    };
170
    };
171
    auto truncate = [&] (auto& displayBox, auto visibleWidth, auto canFullyTruncate) {
171
    auto truncate = [&] (auto& displayBox, auto availableWidthForContent, auto canFullyTruncate) {
172
        if (displayBox.isText()) {
172
        if (displayBox.isText()) {
173
            if (!visibleWidth && canFullyTruncate) {
173
            if (availableWidthForContent <= 0 && canFullyTruncate) {
174
                displayBox.setIsFullyTruncated();
174
                displayBox.setIsFullyTruncated();
175
                return isLeftToRightDirection ? left(displayBox) : right(displayBox);
175
                return isLeftToRightDirection ? left(displayBox) : right(displayBox);
176
            }
176
            }
177
178
            auto& inlineTextBox = downcast<InlineTextBox>(displayBox.layoutBox());
177
            auto& inlineTextBox = downcast<InlineTextBox>(displayBox.layoutBox());
179
            auto& textContent = displayBox.text();
178
            auto& textContent = displayBox.text();
180
            auto leftSide = TextUtil::breakWord(inlineTextBox, textContent.start(), textContent.length(), width(displayBox), visibleWidth, { }, displayBox.style().fontCascade());
179
180
            auto handleMismatchingDirectionIfApplicable = [&]() -> std::optional<InlineLayoutUnit> {
181
                // While truncation normally starts at the end of the content and progress backwards, with mismatching direction
182
                // we take a different approach and truncate content the other way around (i.e. ellipsis follows inline direction truncating the beginning of the content).
183
                // <div dir=rtl>some long content</div>
184
                // [...ng content]
185
                auto contentDirection = displayBox.bidiLevel() % 2 ? TextDirection::RTL : TextDirection::LTR;
186
                if (displayBox.layoutBox().parent().style().direction() == contentDirection)
187
                    return { };
188
                auto contentWidth = width(displayBox);
189
                auto availableWidthForTruncatedContent = contentWidth - availableWidthForContent;
190
                auto truncatedSide = TextUtil::breakWord(inlineTextBox, textContent.start(), textContent.length(), width(displayBox), availableWidthForTruncatedContent, { }, displayBox.style().fontCascade());
191
192
                ASSERT(truncatedSide.length < textContent.length());
193
                auto nonTruncatedLength = textContent.length() - truncatedSide.length;
194
                auto nonTruncatedWidth = contentWidth - truncatedSide.logicalWidth;
195
                // TextUtil::breakWord never returns overflowing content (left side) which means the right side is normally wider (by one character) than what we need.  
196
                auto nonTruncatedContentOverflows = truncatedSide.logicalWidth < availableWidthForTruncatedContent;
197
                if (nonTruncatedContentOverflows) {
198
                    auto wouldFullyTruncate = nonTruncatedLength <= 1;
199
                    if (wouldFullyTruncate && canFullyTruncate) {
200
                        nonTruncatedLength = { };
201
                        nonTruncatedWidth = { };
202
                    } else {
203
                        nonTruncatedLength = !wouldFullyTruncate ? nonTruncatedLength - 1 : 1;
204
                        auto nonTruncatedStartPosition = textContent.end() - nonTruncatedLength;
205
                        nonTruncatedWidth = TextUtil::width(inlineTextBox, displayBox.style().fontCascade(), nonTruncatedStartPosition, textContent.end(), { }, TextUtil::UseTrailingWhitespaceMeasuringOptimization::No);
206
                    }
207
                }
208
                nonTruncatedLength ? textContent.setPartiallyVisibleContentLength(nonTruncatedLength) : displayBox.setIsFullyTruncated();
209
                return isLeftToRightDirection ? left(displayBox) + nonTruncatedWidth : right(displayBox) - nonTruncatedWidth;
210
            };
211
            if (auto truncatePosition = handleMismatchingDirectionIfApplicable())
212
                return *truncatePosition;
213
214
            auto leftSide = TextUtil::breakWord(inlineTextBox, textContent.start(), textContent.length(), width(displayBox), availableWidthForContent, { }, displayBox.style().fontCascade());
181
            if (leftSide.length) {
215
            if (leftSide.length) {
182
                textContent.setPartiallyVisibleContentLength(leftSide.length);
216
                textContent.setPartiallyVisibleContentLength(leftSide.length);
183
                return isLeftToRightDirection ? left(displayBox) + leftSide.logicalWidth : right(displayBox) - leftSide.logicalWidth;
217
                return isLeftToRightDirection ? left(displayBox) + leftSide.logicalWidth : right(displayBox) - leftSide.logicalWidth;
- a/Source/WebCore/rendering/TextBoxPainter.cpp -20 / +10 lines
Lines 245-250 void TextBoxPainter<TextBoxPath>::paintForegroundAndDecorations() a/Source/WebCore/rendering/TextBoxPainter.cpp_sec1
245
    auto hasTextDecoration = !m_style.textDecorationsInEffect().isEmpty();
245
    auto hasTextDecoration = !m_style.textDecorationsInEffect().isEmpty();
246
    auto hasHighlightDecoration = m_document.hasHighlight() && !MarkedText::collectForHighlights(m_renderer, m_selectableRange, MarkedText::PaintPhase::Decoration).isEmpty();
246
    auto hasHighlightDecoration = m_document.hasHighlight() && !MarkedText::collectForHighlights(m_renderer, m_selectableRange, MarkedText::PaintPhase::Decoration).isEmpty();
247
    auto hasDecoration = hasTextDecoration || hasHighlightDecoration;
247
    auto hasDecoration = hasTextDecoration || hasHighlightDecoration;
248
    auto hasMismatchingContentDirection = m_renderer.containingBlock()->style().direction() != textBox().direction();
249
    auto hasBackwardTrunctation = m_selectableRange.truncation && hasMismatchingContentDirection;
248
250
249
    auto contentMayNeedStyledMarkedText = [&] {
251
    auto contentMayNeedStyledMarkedText = [&] {
250
        if (hasDecoration)
252
        if (hasDecoration)
Lines 257-265 void TextBoxPainter<TextBoxPath>::paintForegroundAndDecorations() a/Source/WebCore/rendering/TextBoxPainter.cpp_sec2
257
            return true;
259
            return true;
258
        return false;
260
        return false;
259
    };
261
    };
262
    auto startPosition = [&] {
263
        return !hasBackwardTrunctation ? m_selectableRange.clamp(textBox().start()) : textBox().length() - *m_selectableRange.truncation;
264
    };
265
    auto endPosition = [&] {
266
        return !hasBackwardTrunctation ? m_selectableRange.clamp(textBox().end()) : textBox().length();
267
    };
260
    if (!contentMayNeedStyledMarkedText()) {
268
    if (!contentMayNeedStyledMarkedText()) {
261
        auto& lineStyle = m_isFirstLine ? m_renderer.firstLineStyle() : m_renderer.style();
269
        auto& lineStyle = m_isFirstLine ? m_renderer.firstLineStyle() : m_renderer.style();
262
        auto markedText = MarkedText { m_selectableRange.clamp(textBox().start()), m_selectableRange.clamp(textBox().end()), MarkedText::Unmarked };
270
        auto markedText = MarkedText { startPosition(), endPosition(), MarkedText::Unmarked };
263
        auto styledMarkedText = StyledMarkedText { markedText, StyledMarkedText::computeStyleForUnmarkedMarkedText(m_renderer, lineStyle, m_isFirstLine, m_paintInfo) };
271
        auto styledMarkedText = StyledMarkedText { markedText, StyledMarkedText::computeStyleForUnmarkedMarkedText(m_renderer, lineStyle, m_isFirstLine, m_paintInfo) };
264
        paintCompositionForeground(styledMarkedText);
272
        paintCompositionForeground(styledMarkedText);
265
        return;
273
        return;
Lines 268-274 void TextBoxPainter<TextBoxPath>::paintForegroundAndDecorations() a/Source/WebCore/rendering/TextBoxPainter.cpp_sec3
268
    Vector<MarkedText> markedTexts;
276
    Vector<MarkedText> markedTexts;
269
    if (m_paintInfo.phase != PaintPhase::Selection) {
277
    if (m_paintInfo.phase != PaintPhase::Selection) {
270
        // The marked texts for the gaps between document markers and selection are implicitly created by subdividing the entire line.
278
        // The marked texts for the gaps between document markers and selection are implicitly created by subdividing the entire line.
271
        markedTexts.append({ m_selectableRange.clamp(textBox().start()), m_selectableRange.clamp(textBox().end()), MarkedText::Unmarked });
279
        markedTexts.append({ startPosition(), endPosition(), MarkedText::Unmarked });
272
280
273
        if (!m_isPrinting) {
281
        if (!m_isPrinting) {
274
            markedTexts.appendVector(MarkedText::collectForDocumentMarkers(m_renderer, m_selectableRange, MarkedText::PaintPhase::Foreground));
282
            markedTexts.appendVector(MarkedText::collectForDocumentMarkers(m_renderer, m_selectableRange, MarkedText::PaintPhase::Foreground));
Lines 843-867 FloatRect TextBoxPainter<TextBoxPath>::computePaintRect(const LayoutPoint& paint a/Source/WebCore/rendering/TextBoxPainter.cpp_sec4
843
{
851
{
844
    FloatPoint localPaintOffset(paintOffset);
852
    FloatPoint localPaintOffset(paintOffset);
845
853
846
    if (m_selectableRange.truncation) {
847
        if (m_renderer.containingBlock()->style().direction() != textBox().direction()) {
848
            // Make the visible fragment of text hug the edge closest to the rest of the run by moving the origin
849
            // at which we start drawing text.
850
            // e.g. In the case of LTR text truncated in an RTL Context, the correct behavior is:
851
            // |Hello|CBA| -> |...He|CBA|
852
            // In order to draw the fragment "He" aligned to the right edge of it's box, we need to start drawing
853
            // farther to the right.
854
            // NOTE: WebKit's behavior differs from that of IE which appears to just overlay the ellipsis on top of the
855
            // truncated string i.e.  |Hello|CBA| -> |...lo|CBA|
856
            LayoutUnit widthOfVisibleText { m_renderer.width(textBox().start(), *m_selectableRange.truncation, textPosition(), m_isFirstLine) };
857
            LayoutUnit widthOfHiddenText { m_logicalRect.width() - widthOfVisibleText };
858
            LayoutSize truncationOffset(textBox().direction() == TextDirection::LTR ? widthOfHiddenText : -widthOfHiddenText, 0_lu);
859
            localPaintOffset.move(textBox().isHorizontal() ? truncationOffset : truncationOffset.transposedSize());
860
        }
861
    }
862
863
    localPaintOffset.move(0, m_style.isHorizontalWritingMode() ? 0 : -m_logicalRect.height());
854
    localPaintOffset.move(0, m_style.isHorizontalWritingMode() ? 0 : -m_logicalRect.height());
864
865
    auto visualRect = textBox().visualRectIgnoringBlockDirection();
855
    auto visualRect = textBox().visualRectIgnoringBlockDirection();
866
    textBox().formattingContextRoot().flipForWritingMode(visualRect);
856
    textBox().formattingContextRoot().flipForWritingMode(visualRect);
867
857
- a/Source/WebCore/rendering/TextBoxSelectableRange.h +1 lines
Lines 33-38 struct TextBoxSelectableRange { a/Source/WebCore/rendering/TextBoxSelectableRange.h_sec1
33
    const unsigned length;
33
    const unsigned length;
34
    const unsigned additionalLengthAtEnd { 0 };
34
    const unsigned additionalLengthAtEnd { 0 };
35
    const bool isLineBreak { false };
35
    const bool isLineBreak { false };
36
    // FIXME: Consider holding onto the truncation position instead. See webkit.org/b/164999
36
    const std::optional<unsigned> truncation { };
37
    const std::optional<unsigned> truncation { };
37
38
38
    unsigned clamp(unsigned offset) const
39
    unsigned clamp(unsigned offset) const
- a/LayoutTests/TestExpectations -1 lines
Lines 3305-3311 imported/w3c/web-platform-tests/css/css-display/run-in/run-in-text-between-004.x a/LayoutTests/TestExpectations_sec1
3305
imported/w3c/web-platform-tests/css/css-display/run-in/run-in-text-between-005.xht [ ImageOnlyFailure ]
3305
imported/w3c/web-platform-tests/css/css-display/run-in/run-in-text-between-005.xht [ ImageOnlyFailure ]
3306
imported/w3c/web-platform-tests/css/css-ui/text-overflow-027.html [ ImageOnlyFailure ]
3306
imported/w3c/web-platform-tests/css/css-ui/text-overflow-027.html [ ImageOnlyFailure ]
3307
imported/w3c/web-platform-tests/css/css-ui/text-overflow-028.html [ ImageOnlyFailure ]
3307
imported/w3c/web-platform-tests/css/css-ui/text-overflow-028.html [ ImageOnlyFailure ]
3308
imported/w3c/web-platform-tests/css/css-ui/text-overflow-029.html [ ImageOnlyFailure ]
3309
3308
3310
imported/w3c/web-platform-tests/css/mediaqueries/viewport-script-dynamic.html [ ImageOnlyFailure ]
3309
imported/w3c/web-platform-tests/css/mediaqueries/viewport-script-dynamic.html [ ImageOnlyFailure ]
3311
3310

Return to Bug 164999