Title: [281731] trunk
Revision
281731
Author
[email protected]
Date
2021-08-27 20:20:21 -0700 (Fri, 27 Aug 2021)

Log Message

The simple text codepath does not handle unpaired surrogates
https://bugs.webkit.org/show_bug.cgi?id=229392

Reviewed by Alan Bujtas.

Source/WebCore:

The simple text codepath was taking an early return if it encountered an unpaired surrogate.
This essentially ends up being data loss, because everything after that surrogate is just gone.
The other browsers render the unpaired surrogate, and the text after it too.

Removing the early return uncovered a preexisting bug, where word-break: break-all would cause
both RenderText::computePreferredLogicalWidths() and BreakingContext::handleText() to try to
break in between two adjacent joining surrogates.

Because both fixes depend on each other to be observable, this patch does both together.

Test: fast/text/unpaired-surrogate.html

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* WebCore.xcodeproj/xcshareddata/xcschemes/WebCore.xcscheme:
* platform/graphics/FontCascade.cpp:
(WebCore::FontCascade::getEmphasisMarkGlyphData const):
* platform/graphics/SurrogatePairAwareTextIterator.cpp: Removed.
* platform/graphics/SurrogatePairAwareTextIterator.h:
(WebCore::SurrogatePairAwareTextIterator::SurrogatePairAwareTextIterator):
(WebCore::SurrogatePairAwareTextIterator::consume):
(WebCore::SurrogatePairAwareTextIterator::currentIndex const):
(WebCore::SurrogatePairAwareTextIterator::characters const): Deleted.
* platform/graphics/WidthIterator.cpp:
(WebCore::WidthIterator::advanceInternal):
* platform/graphics/freetype/SimpleFontDataFreeType.cpp:
* rendering/InlineIterator.h:
(WebCore::InlineIterator::incrementByCodePointInTextNode):
* rendering/RenderText.cpp:
(WebCore::RenderText::computePreferredLogicalWidths):
* rendering/line/BreakingContext.h:
(WebCore::BreakingContext::handleText):

LayoutTests:

* fast/text/unpaired-surrogate-expected-mismatch.html: Added.
* fast/text/unpaired-surrogate.html: Added.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (281730 => 281731)


--- trunk/LayoutTests/ChangeLog	2021-08-28 02:09:00 UTC (rev 281730)
+++ trunk/LayoutTests/ChangeLog	2021-08-28 03:20:21 UTC (rev 281731)
@@ -1,3 +1,13 @@
+2021-08-27  Myles C. Maxfield  <[email protected]>
+
+        The simple text codepath does not handle unpaired surrogates
+        https://bugs.webkit.org/show_bug.cgi?id=229392
+
+        Reviewed by Alan Bujtas.
+
+        * fast/text/unpaired-surrogate-expected-mismatch.html: Added.
+        * fast/text/unpaired-surrogate.html: Added.
+
 2021-08-27  Eric Carlson  <[email protected]>
 
         [ Catalina EWS ] media/track/track-disabled-addcue.html is flaky crashing

Added: trunk/LayoutTests/fast/text/unpaired-surrogate-expected-mismatch.html (0 => 281731)


--- trunk/LayoutTests/fast/text/unpaired-surrogate-expected-mismatch.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/unpaired-surrogate-expected-mismatch.html	2021-08-28 03:20:21 UTC (rev 281731)
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<div id="target" style="font-size: 100px;">a</div>
+</body>
+</html>

Added: trunk/LayoutTests/fast/text/unpaired-surrogate.html (0 => 281731)


--- trunk/LayoutTests/fast/text/unpaired-surrogate.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/unpaired-surrogate.html	2021-08-28 03:20:21 UTC (rev 281731)
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<div id="target" style="font-size: 100px;"></div>
+<script>
+let target = document.getElementById("target");
+target.textContent = 'a\uD800b';
+</script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (281730 => 281731)


--- trunk/Source/WebCore/ChangeLog	2021-08-28 02:09:00 UTC (rev 281730)
+++ trunk/Source/WebCore/ChangeLog	2021-08-28 03:20:21 UTC (rev 281731)
@@ -1,3 +1,43 @@
+2021-08-27  Myles C. Maxfield  <[email protected]>
+
+        The simple text codepath does not handle unpaired surrogates
+        https://bugs.webkit.org/show_bug.cgi?id=229392
+
+        Reviewed by Alan Bujtas.
+
+        The simple text codepath was taking an early return if it encountered an unpaired surrogate.
+        This essentially ends up being data loss, because everything after that surrogate is just gone.
+        The other browsers render the unpaired surrogate, and the text after it too.
+
+        Removing the early return uncovered a preexisting bug, where word-break: break-all would cause
+        both RenderText::computePreferredLogicalWidths() and BreakingContext::handleText() to try to
+        break in between two adjacent joining surrogates.
+
+        Because both fixes depend on each other to be observable, this patch does both together.
+
+        Test: fast/text/unpaired-surrogate.html
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * WebCore.xcodeproj/xcshareddata/xcschemes/WebCore.xcscheme:
+        * platform/graphics/FontCascade.cpp:
+        (WebCore::FontCascade::getEmphasisMarkGlyphData const):
+        * platform/graphics/SurrogatePairAwareTextIterator.cpp: Removed.
+        * platform/graphics/SurrogatePairAwareTextIterator.h:
+        (WebCore::SurrogatePairAwareTextIterator::SurrogatePairAwareTextIterator):
+        (WebCore::SurrogatePairAwareTextIterator::consume):
+        (WebCore::SurrogatePairAwareTextIterator::currentIndex const):
+        (WebCore::SurrogatePairAwareTextIterator::characters const): Deleted.
+        * platform/graphics/WidthIterator.cpp:
+        (WebCore::WidthIterator::advanceInternal):
+        * platform/graphics/freetype/SimpleFontDataFreeType.cpp:
+        * rendering/InlineIterator.h:
+        (WebCore::InlineIterator::incrementByCodePointInTextNode):
+        * rendering/RenderText.cpp:
+        (WebCore::RenderText::computePreferredLogicalWidths):
+        * rendering/line/BreakingContext.h:
+        (WebCore::BreakingContext::handleText):
+
 2021-08-27  Simon Fraser  <[email protected]>
 
         Define ENABLE_CONTENT_CHANGE_OBSERVER for IOS_FAMILY and use it to wrap content observation code

Modified: trunk/Source/WebCore/Sources.txt (281730 => 281731)


--- trunk/Source/WebCore/Sources.txt	2021-08-28 02:09:00 UTC (rev 281730)
+++ trunk/Source/WebCore/Sources.txt	2021-08-28 03:20:21 UTC (rev 281731)
@@ -1959,7 +1959,6 @@
 platform/graphics/ShadowBlur.cpp
 platform/graphics/SourceBufferPrivate.cpp
 platform/graphics/StringTruncator.cpp
-platform/graphics/SurrogatePairAwareTextIterator.cpp
 platform/graphics/TextRun.cpp
 platform/graphics/TextTrackRepresentation.cpp
 platform/graphics/TrackPrivateBase.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (281730 => 281731)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-08-28 02:09:00 UTC (rev 281730)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-08-28 03:20:21 UTC (rev 281731)
@@ -262,7 +262,6 @@
 		08641D4812142F7D008DE9F6 /* RenderImageResourceStyleImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 08641D4612142F7D008DE9F6 /* RenderImageResourceStyleImage.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		086BBD0F136039C2008B15D8 /* Glyph.h in Headers */ = {isa = PBXBuildFile; fileRef = 086BBD0E136039C2008B15D8 /* Glyph.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0873B86B136064EA00A522C2 /* GlyphPage.h in Headers */ = {isa = PBXBuildFile; fileRef = 0873B86A136064EA00A522C2 /* GlyphPage.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		087558C613B4A57D00F49307 /* SurrogatePairAwareTextIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 087558C413B4A57D00F49307 /* SurrogatePairAwareTextIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0885067F11DA045B00182B98 /* PaintInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0885067D11DA045B00182B98 /* PaintInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0885068011DA045B00182B98 /* PaintPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0885067E11DA045B00182B98 /* PaintPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		088A0E0C126EF1DB00978F7A /* SVGPropertyTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 088A0E03126EF1DB00978F7A /* SVGPropertyTraits.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -6073,7 +6072,6 @@
 		08641D4612142F7D008DE9F6 /* RenderImageResourceStyleImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderImageResourceStyleImage.h; sourceTree = "<group>"; };
 		086BBD0E136039C2008B15D8 /* Glyph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Glyph.h; sourceTree = "<group>"; };
 		0873B86A136064EA00A522C2 /* GlyphPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GlyphPage.h; sourceTree = "<group>"; };
-		087558C313B4A57D00F49307 /* SurrogatePairAwareTextIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SurrogatePairAwareTextIterator.cpp; sourceTree = "<group>"; };
 		087558C413B4A57D00F49307 /* SurrogatePairAwareTextIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SurrogatePairAwareTextIterator.h; sourceTree = "<group>"; };
 		0885067D11DA045B00182B98 /* PaintInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PaintInfo.h; sourceTree = "<group>"; };
 		0885067E11DA045B00182B98 /* PaintPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PaintPhase.h; sourceTree = "<group>"; };
@@ -26743,7 +26741,6 @@
 				7C83DE851D04CBD400FEBCF3 /* SpringSolver.h */,
 				B23540F00D00782E002382FA /* StringTruncator.cpp */,
 				B23540F10D00782E002382FA /* StringTruncator.h */,
-				087558C313B4A57D00F49307 /* SurrogatePairAwareTextIterator.cpp */,
 				087558C413B4A57D00F49307 /* SurrogatePairAwareTextIterator.h */,
 				3BB6B80F22A7D311003A2A69 /* TabSize.h */,
 				376DCCE013B4F966002EBEFC /* TextRun.cpp */,
@@ -34768,7 +34765,6 @@
 				93B2D8160F9920D2006AE6B2 /* SuddenTermination.h in Headers */,
 				97C078501165D5BE003A32EF /* SuffixTree.h in Headers */,
 				97627B9814FB5424002CDCA1 /* Supplementable.h in Headers */,
-				087558C613B4A57D00F49307 /* SurrogatePairAwareTextIterator.h in Headers */,
 				62C1217D11AB9E77003C462C /* SuspendableTimer.h in Headers */,
 				B22279740D00BF220071B782 /* SVGAElement.h in Headers */,
 				24D912B113CA9A1F00D21915 /* SVGAltGlyphDefElement.h in Headers */,

Modified: trunk/Source/WebCore/platform/graphics/FontCascade.cpp (281730 => 281731)


--- trunk/Source/WebCore/platform/graphics/FontCascade.cpp	2021-08-28 02:09:00 UTC (rev 281730)
+++ trunk/Source/WebCore/platform/graphics/FontCascade.cpp	2021-08-28 03:20:21 UTC (rev 281731)
@@ -33,7 +33,6 @@
 #include "GraphicsContext.h"
 #include "InMemoryDisplayList.h"
 #include "LayoutRect.h"
-#include "SurrogatePairAwareTextIterator.h"
 #include "TextRun.h"
 #include "WidthIterator.h"
 #include <wtf/MainThread.h>
@@ -1194,10 +1193,9 @@
 
     UChar32 character;
     if (!mark.is8Bit()) {
-        SurrogatePairAwareTextIterator iterator(mark.characters16(), 0, mark.length(), mark.length());
-        unsigned clusterLength;
-        if (!iterator.consume(character, clusterLength))
-            return std::nullopt;
+        size_t i = 0;
+        U16_NEXT(mark.characters16(), i, mark.length(), character);
+        ASSERT(U16_IS_SINGLE(character)); // The CSS parser replaces unpaired surrogates with the object replacement character.
     } else
         character = mark[0];
 

Deleted: trunk/Source/WebCore/platform/graphics/SurrogatePairAwareTextIterator.cpp (281730 => 281731)


--- trunk/Source/WebCore/platform/graphics/SurrogatePairAwareTextIterator.cpp	2021-08-28 02:09:00 UTC (rev 281730)
+++ trunk/Source/WebCore/platform/graphics/SurrogatePairAwareTextIterator.cpp	2021-08-28 03:20:21 UTC (rev 281731)
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2003-2019 Apple Inc. All rights reserved.
- * Copyright (C) 2008 Holger Hans Peter Freyther
- * Copyright (C) Research In Motion Limited 2011. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB.  If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "SurrogatePairAwareTextIterator.h"
-
-#include <unicode/unorm2.h>
-
-namespace WebCore {
-
-SurrogatePairAwareTextIterator::SurrogatePairAwareTextIterator(const UChar* characters, unsigned currentIndex, unsigned lastIndex, unsigned endIndex)
-    : m_characters(characters)
-    , m_currentIndex(currentIndex)
-    , m_lastIndex(lastIndex)
-    , m_endIndex(endIndex)
-{
-}
-
-bool SurrogatePairAwareTextIterator::consumeSlowCase(UChar32& character, unsigned& clusterLength)
-{
-    ASSERT(U16_IS_SURROGATE(character));
-
-    // If we have a surrogate pair, make sure it starts with the high part.
-    if (!U16_IS_SURROGATE_LEAD(character))
-        return false;
-
-    // Do we have a surrogate pair? If so, determine the full Unicode (32 bit) code point before glyph lookup.
-    // Make sure we have another character and it's a low surrogate.
-    if (m_currentIndex + 1 >= m_endIndex)
-        return false;
-
-    UChar low = m_characters[1];
-    if (!U16_IS_TRAIL(low))
-        return false;
-
-    character = U16_GET_SUPPLEMENTARY(character, low);
-    clusterLength = 2;
-    return true;
-}
-
-UChar32 SurrogatePairAwareTextIterator::normalizeVoicingMarks()
-{
-    // According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combining_Class_Values
-    static constexpr uint8_t hiraganaKatakanaVoicingMarksCombiningClass = 8;
-
-    if (m_currentIndex + 1 >= m_endIndex)
-        return 0;
-
-    if (u_getCombiningClass(m_characters[1]) == hiraganaKatakanaVoicingMarksCombiningClass) {
-        UErrorCode status = U_ZERO_ERROR;
-        const UNormalizer2* normalizer = unorm2_getNFCInstance(&status);
-        ASSERT(U_SUCCESS(status));
-        auto composedCharacter = unorm2_composePair(normalizer, m_characters[0], m_characters[1]);
-        if (composedCharacter > 0)
-            return composedCharacter;
-    }
-
-    return 0;
-}
-
-}

Modified: trunk/Source/WebCore/platform/graphics/SurrogatePairAwareTextIterator.h (281730 => 281731)


--- trunk/Source/WebCore/platform/graphics/SurrogatePairAwareTextIterator.h	2021-08-28 02:09:00 UTC (rev 281730)
+++ trunk/Source/WebCore/platform/graphics/SurrogatePairAwareTextIterator.h	2021-08-28 03:20:21 UTC (rev 281731)
@@ -18,10 +18,9 @@
  *
  */
 
-#ifndef SurrogatePairAwareTextIterator_h
-#define SurrogatePairAwareTextIterator_h
+#pragma once
 
-#include <wtf/unicode/CharacterNames.h>
+#include <unicode/utf16.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -28,22 +27,24 @@
 
 class SurrogatePairAwareTextIterator {
 public:
-    // The passed in UChar pointer starts at 'currentIndex'. The iterator operatoes on the range [currentIndex, lastIndex].
+    // The passed in UChar pointer starts at 'currentIndex'. The iterator operates on the range [currentIndex, lastIndex].
     // 'endIndex' denotes the maximum length of the UChar array, which might exceed 'lastIndex'.
-    SurrogatePairAwareTextIterator(const UChar*, unsigned currentIndex, unsigned lastIndex, unsigned endIndex);
+    SurrogatePairAwareTextIterator(const UChar* characters, unsigned currentIndex, unsigned lastIndex, unsigned endIndex)
+        : m_characters(characters)
+        , m_currentIndex(currentIndex)
+        , m_lastIndex(lastIndex)
+        , m_endIndex(endIndex)
+    {
+    }
 
-    inline bool consume(UChar32& character, unsigned& clusterLength)
+    bool consume(UChar32& character, unsigned& clusterLength)
     {
         if (m_currentIndex >= m_lastIndex)
             return false;
 
-        character = *m_characters;
-        clusterLength = 1;
-
-        if (!U16_IS_SURROGATE(character))
-            return true;
-
-        return consumeSlowCase(character, clusterLength);
+        clusterLength = 0;
+        U16_NEXT(m_characters, clusterLength, m_endIndex - m_currentIndex, character);
+        return true;
     }
 
     void advance(unsigned advanceLength)
@@ -53,18 +54,12 @@
     }
 
     unsigned currentIndex() const { return m_currentIndex; }
-    const UChar* characters() const { return m_characters; }
 
 private:
-    bool consumeSlowCase(UChar32&, unsigned&);
-    UChar32 normalizeVoicingMarks();
-
-    const UChar* m_characters;
-    unsigned m_currentIndex;
-    unsigned m_lastIndex;
-    unsigned m_endIndex;
+    const UChar* m_characters { nullptr };
+    unsigned m_currentIndex { 0 };
+    unsigned m_lastIndex { 0 };
+    unsigned m_endIndex { 0 };
 };
 
 }
-
-#endif

Modified: trunk/Source/WebCore/platform/graphics/WidthIterator.cpp (281730 => 281731)


--- trunk/Source/WebCore/platform/graphics/WidthIterator.cpp	2021-08-28 02:09:00 UTC (rev 281730)
+++ trunk/Source/WebCore/platform/graphics/WidthIterator.cpp	2021-08-28 03:20:21 UTC (rev 281731)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 - 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2003 - 2021 Apple Inc. All rights reserved.
  * Copyright (C) 2008 Holger Hans Peter Freyther
  *
  * This library is free software; you can redistribute it and/or
@@ -278,6 +278,8 @@
     float widthOfCurrentFontRange = 0;
     // We are iterating in string order, not glyph order. Compare this to ComplexTextController::adjustGlyphsAndAdvances()
     while (textIterator.consume(character, clusterLength)) {
+        // FIXME: Should we replace unpaired surrogates with the object replacement character?
+        // Should we do this before or after shaping? What does a shaper do with an unpaired surrogate?
         m_containsTabs |= character == tabCharacter;
         currentCharacterIndex = textIterator.currentIndex();
         unsigned advanceLength = clusterLength;

Modified: trunk/Source/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp (281730 => 281731)


--- trunk/Source/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp	2021-08-28 02:09:00 UTC (rev 281730)
+++ trunk/Source/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp	2021-08-28 03:20:21 UTC (rev 281731)
@@ -42,7 +42,6 @@
 #include "GlyphBuffer.h"
 #include "OpenTypeTypes.h"
 #include "RefPtrCairo.h"
-#include "SurrogatePairAwareTextIterator.h"
 #include "UTF16UChar32Iterator.h"
 #include <cairo-ft.h>
 #include <cairo.h>

Modified: trunk/Source/WebCore/rendering/InlineIterator.h (281730 => 281731)


--- trunk/Source/WebCore/rendering/InlineIterator.h	2021-08-28 02:09:00 UTC (rev 281730)
+++ trunk/Source/WebCore/rendering/InlineIterator.h	2021-08-28 03:20:21 UTC (rev 281731)
@@ -92,6 +92,7 @@
     void setRefersToEndOfPreviousNode();
 
     void fastIncrementInTextNode();
+    void incrementByCodePointInTextNode();
     void increment(InlineBidiResolver* = nullptr);
     void fastDecrement();
     bool atEnd() const;
@@ -346,6 +347,19 @@
     ++m_pos;
 }
 
+inline void InlineIterator::incrementByCodePointInTextNode()
+{
+    ASSERT(m_renderer);
+    const auto& text = downcast<RenderText>(*m_renderer).text();
+    ASSERT(m_pos < text.length());
+    if (text.is8Bit()) {
+        ++m_pos;
+        return;
+    }
+    UChar32 character;
+    U16_NEXT(text.characters16(), m_pos, text.length(), character);
+}
+
 inline void InlineIterator::setOffset(unsigned position)
 {
     ASSERT(position <= UINT_MAX - 10); // Sanity check

Modified: trunk/Source/WebCore/rendering/RenderText.cpp (281730 => 281731)


--- trunk/Source/WebCore/rendering/RenderText.cpp	2021-08-28 02:09:00 UTC (rev 281730)
+++ trunk/Source/WebCore/rendering/RenderText.cpp	2021-08-28 03:20:21 UTC (rev 281731)
@@ -1069,13 +1069,19 @@
         bool betweenWords = true;
         unsigned j = i;
         while (c != '\n' && !isSpaceAccordingToStyle(c, style) && c != '\t' && (c != softHyphen || style.hyphens() == Hyphens::None)) {
+            UChar previousCharacter = c;
             j++;
             if (j == length)
                 break;
             c = string[j];
+            if (U_IS_LEAD(previousCharacter) && U_IS_TRAIL(c))
+                continue;
             if (isBreakable(breakIterator, j, nextBreakable, breakNBSP, canUseLineBreakShortcut, keepAllWords, breakAnywhere) && characterAt(j - 1) != softHyphen)
                 break;
             if (breakAll) {
+                // FIXME: This code is ultra wrong.
+                // The spec says "word-break: break-all: Any typographic letter units are treated as ID(“ideographic characters”) for the purpose of line-breaking."
+                // The spec describes how a "typographic letter unit" is a cluster, not a code point: https://drafts.csswg.org/css-text-3/#typographic-character-unit
                 betweenWords = false;
                 break;
             }

Modified: trunk/Source/WebCore/rendering/line/BreakingContext.h (281730 => 281731)


--- trunk/Source/WebCore/rendering/line/BreakingContext.h	2021-08-28 02:09:00 UTC (rev 281730)
+++ trunk/Source/WebCore/rendering/line/BreakingContext.h	2021-08-28 03:20:21 UTC (rev 281731)
@@ -738,11 +738,11 @@
     // words with their trailing space, then subtract its width.
     TextLayout* textLayout = m_renderTextInfo.layout.get();
     WordTrailingSpace wordTrailingSpace(style, !textLayout);
-    for (; m_current.offset() < renderer.text().length(); m_current.fastIncrementInTextNode()) {
+    for (; m_current.offset() < renderer.text().length(); m_current.incrementByCodePointInTextNode()) {
         ASSERT(&renderer == m_current.renderer());
         bool previousCharacterIsSpace = m_currentCharacterIsSpace;
         bool previousCharacterIsWS = m_currentCharacterIsWS;
-        UChar c = m_current.current();
+        UChar c = m_current.current(); // FIXME: It's silly to pull out a single surrogate from the content and attempt to do anything useful with it.
         m_currentCharacterIsSpace = c == ' ' || c == '\t' || (!m_preservesNewline && (c == '\n'));
 
         // A single preserved leading white-space doesn't fulfill the 'betweenWords' condition, however it's indeed a
@@ -776,6 +776,9 @@
         m_currentCharacterIsWS = m_currentCharacterIsSpace || (breakNBSP && c == noBreakSpace);
 
         if (canBreakMidWord && !midWordBreak && (!m_currentCharacterIsSpace || m_atStart || style.whiteSpace() != WhiteSpace::PreWrap)) {
+            // FIXME: This code is ultra wrong.
+            // The spec says "word-break: break-all: Any typographic letter units are treated as ID(“ideographic characters”) for the purpose of line-breaking."
+            // The spec describes how a "typographic letter unit" is a cluster, not a code point: https://drafts.csswg.org/css-text-3/#typographic-character-unit
             wrapW += charWidth;
             bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && U16_IS_TRAIL(renderer.characterAt(m_current.offset() + 1));
             charWidth = textWidth(renderer, m_current.offset(), midWordBreakIsBeforeSurrogatePair ? 2 : 1, font, m_width.committedWidth() + wrapW, isFixedPitch, m_collapseWhiteSpace, fallbackFonts, textLayout);
@@ -783,7 +786,7 @@
         }
 
         std::optional<unsigned> nextBreakablePosition = m_current.nextBreakablePosition();
-        bool betweenWords = c == '\n' || (m_currWS != WhiteSpace::Pre && !m_atStart && isBreakable(m_renderTextInfo.lineBreakIterator, m_current.offset(), nextBreakablePosition, breakNBSP, canUseLineBreakShortcut, keepAllWords, breakAnywhere)
+        bool betweenWords = c == newlineCharacter || (m_currWS != WhiteSpace::Pre && !m_atStart && isBreakable(m_renderTextInfo.lineBreakIterator, m_current.offset(), nextBreakablePosition, breakNBSP, canUseLineBreakShortcut, keepAllWords, breakAnywhere)
             && (style.hyphens() != Hyphens::None || (m_current.previousInSameNode() != softHyphen)));
         m_current.setNextBreakablePosition(nextBreakablePosition);
         
@@ -931,7 +934,7 @@
                 }
             }
 
-            if (c == '\n' && m_preservesNewline) {
+            if (c == newlineCharacter && m_preservesNewline) {
                 if (!stoppedIgnoringSpaces && m_current.offset())
                     ensureCharacterGetsLineBox(m_lineWhitespaceCollapsingState, m_current);
                 commitLineBreakAtCurrentWidth(renderer, m_current.offset(), m_current.nextBreakablePosition());
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to