Title: [287195] trunk/Source/WebCore
Revision
287195
Author
[email protected]
Date
2021-12-17 10:11:49 -0800 (Fri, 17 Dec 2021)

Log Message

Refactor hyphenation logic in RenderText::computePreferredLogicalWidths()
https://bugs.webkit.org/show_bug.cgi?id=234421

Reviewed by Alan Bujtas.

The hyphenation logic in RenderText::computePreferredLogicalWidths() was split across two functions.
If you consider the word "ABC-DEF-GHI" (where the '-' characters are hyphenation opportunities), one
function, maxWordFragmentWidth() was responsible for calculating the width of "ABC-" and "DEF-" but
not "GHI". RenderText::computePreferredLogicalWidths() called that function, and after it returned,
would then calculate the width of "GHI", and compare that to the width returned by
maxWordFragmentWidth(). A much simpler design would be to have one function, maxWordFragmentWidth(),
handle all the hyphenation logic, and do all the calculation necessary to just return a single value
to RenderText::computePreferredLogicalWidths().

No new tests because there is no behavior change.

* rendering/RenderText.cpp:
(WebCore::RenderText::maxWordFragmentWidth):
(WebCore::RenderText::computePreferredLogicalWidths):
(WebCore::maxWordFragmentWidth): Deleted.
* rendering/RenderText.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (287194 => 287195)


--- trunk/Source/WebCore/ChangeLog	2021-12-17 18:02:33 UTC (rev 287194)
+++ trunk/Source/WebCore/ChangeLog	2021-12-17 18:11:49 UTC (rev 287195)
@@ -1,3 +1,27 @@
+2021-12-17  Myles C. Maxfield  <[email protected]>
+
+        Refactor hyphenation logic in RenderText::computePreferredLogicalWidths()
+        https://bugs.webkit.org/show_bug.cgi?id=234421
+
+        Reviewed by Alan Bujtas.
+
+        The hyphenation logic in RenderText::computePreferredLogicalWidths() was split across two functions.
+        If you consider the word "ABC-DEF-GHI" (where the '-' characters are hyphenation opportunities), one
+        function, maxWordFragmentWidth() was responsible for calculating the width of "ABC-" and "DEF-" but
+        not "GHI". RenderText::computePreferredLogicalWidths() called that function, and after it returned,
+        would then calculate the width of "GHI", and compare that to the width returned by
+        maxWordFragmentWidth(). A much simpler design would be to have one function, maxWordFragmentWidth(),
+        handle all the hyphenation logic, and do all the calculation necessary to just return a single value
+        to RenderText::computePreferredLogicalWidths().
+
+        No new tests because there is no behavior change.
+
+        * rendering/RenderText.cpp:
+        (WebCore::RenderText::maxWordFragmentWidth):
+        (WebCore::RenderText::computePreferredLogicalWidths):
+        (WebCore::maxWordFragmentWidth): Deleted.
+        * rendering/RenderText.h:
+
 2021-12-17  Gabriel Nava Marino  <[email protected]>
 
         null ptr deref in WebCore::findPlaceForCounter

Modified: trunk/Source/WebCore/rendering/RenderText.cpp (287194 => 287195)


--- trunk/Source/WebCore/rendering/RenderText.cpp	2021-12-17 18:02:33 UTC (rev 287194)
+++ trunk/Source/WebCore/rendering/RenderText.cpp	2021-12-17 18:11:49 UTC (rev 287195)
@@ -924,9 +924,9 @@
     return font.width(textRun);
 }
 
-static float maxWordFragmentWidth(RenderText& renderer, const RenderStyle& style, const FontCascade& font, StringView word, unsigned minimumPrefixLength, unsigned minimumSuffixLength, unsigned& suffixStart, HashSet<const Font*>& fallbackFonts, GlyphOverflow& glyphOverflow)
+float RenderText::maxWordFragmentWidth(const RenderStyle& style, const FontCascade& font, StringView word, unsigned minimumPrefixLength, unsigned minimumSuffixLength, bool currentCharacterIsSpace, unsigned characterIndex, float xPos, float entireWordWidth, WordTrailingSpace& wordTrailingSpace, HashSet<const Font*>& fallbackFonts, GlyphOverflow& glyphOverflow)
 {
-    suffixStart = 0;
+    unsigned suffixStart = 0;
     if (word.length() <= minimumSuffixLength)
         return 0;
 
@@ -941,8 +941,13 @@
 
     hyphenLocations.reverse();
 
-    // FIXME: Breaking the string at these places in the middle of words is completely broken with complex text.
-    float minimumFragmentWidthToConsider = font.pixelSize() * 5 / 4 + hyphenWidth(renderer, font);
+    // Consider the word "ABC-DEF-GHI" (where the '-' characters are hyphenation opportunities). We want to measure the width
+    // of "ABC-" and "DEF-", but not "GHI-". Instead, we should measure "GHI" the same way we measure regular unhyphenated
+    // words (by using wordTrailingSpace). Therefore, this function is split up into two parts - one that measures each prefix,
+    // and one that measures the single last suffix.
+
+    // FIXME: Breaking the string at these places in the middle of words doesn't work with complex text.
+    float minimumFragmentWidthToConsider = font.pixelSize() * 5 / 4 + hyphenWidth(*this, font);
     float maxFragmentWidth = 0;
     for (size_t k = 0; k < hyphenLocations.size(); ++k) {
         int fragmentLength = hyphenLocations[k] - suffixStart;
@@ -951,7 +956,7 @@
         fragmentWithHyphen.append(style.hyphenString());
 
         TextRun run = RenderBlock::constructTextRun(fragmentWithHyphen.toString(), style);
-        run.setCharacterScanForCodePath(!renderer.canUseSimpleFontCodePath());
+        run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
         float fragmentWidth = font.width(run, &fallbackFonts, &glyphOverflow);
 
         // Narrow prefixes are ignored. See tryHyphenating in RenderBlockLineLayout.cpp.
@@ -962,7 +967,22 @@
         maxFragmentWidth = std::max(maxFragmentWidth, fragmentWidth);
     }
 
-    return maxFragmentWidth;
+    if (!suffixStart) {
+        // We didn't find any hyphenation opportunities that we're willing to actually use.
+        // Therefore, the width of the maximum fragment is just ... the width of the entire word.
+        return entireWordWidth;
+    }
+
+    float suffixWidth;
+    std::optional<float> wordTrailingSpaceWidth;
+    if (currentCharacterIsSpace)
+        wordTrailingSpaceWidth = wordTrailingSpace.width(fallbackFonts);
+    if (wordTrailingSpaceWidth)
+        suffixWidth = widthFromCache(font, characterIndex + suffixStart, word.length() - suffixStart + 1, xPos, 0, 0, style) - wordTrailingSpaceWidth.value();
+    else
+        suffixWidth = widthFromCache(font, characterIndex + suffixStart, word.length() - suffixStart, xPos, 0, 0, style);
+
+    return std::max(maxFragmentWidth, suffixWidth);
 }
 
 void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Font*>& fallbackFonts, GlyphOverflow& glyphOverflow)
@@ -1108,25 +1128,9 @@
             }
 
             if (w > maxWordWidth) {
-                unsigned suffixStart;
-                float maxFragmentWidth = maxWordFragmentWidth(*this, style, font, StringView(string).substring(i, wordLen), minimumPrefixLength, minimumSuffixLength, suffixStart, fallbackFonts, glyphOverflow);
-
-                if (suffixStart) {
-                    float suffixWidth;
-                    std::optional<float> wordTrailingSpaceWidth;
-                    if (isSpace)
-                        wordTrailingSpaceWidth = wordTrailingSpace.width(fallbackFonts);
-                    if (wordTrailingSpaceWidth)
-                        suffixWidth = widthFromCache(font, i + suffixStart, wordLen - suffixStart + 1, leadWidth + currMaxWidth, 0, 0, style) - wordTrailingSpaceWidth.value();
-                    else
-                        suffixWidth = widthFromCache(font, i + suffixStart, wordLen - suffixStart, leadWidth + currMaxWidth, 0, 0, style);
-
-                    maxFragmentWidth = std::max(maxFragmentWidth, suffixWidth);
-
-                    currMinWidth += maxFragmentWidth - w;
-                    maxWordWidth = std::max(maxWordWidth, maxFragmentWidth);
-                } else
-                    maxWordWidth = w;
+                auto maxFragmentWidth = maxWordFragmentWidth(style, font, StringView(string).substring(i, wordLen), minimumPrefixLength, minimumSuffixLength, isSpace, i, leadWidth + currMaxWidth, w, wordTrailingSpace, fallbackFonts, glyphOverflow);
+                currMinWidth += maxFragmentWidth - w; // This, when combined with "currMinWidth += w" below, has the effect of executing "currMinWidth += maxFragmentWidth" instead.
+                maxWordWidth = std::max(maxWordWidth, maxFragmentWidth);
             }
 
             if (!firstGlyphLeftOverflow)

Modified: trunk/Source/WebCore/rendering/RenderText.h (287194 => 287195)


--- trunk/Source/WebCore/rendering/RenderText.h	2021-12-17 18:02:33 UTC (rev 287194)
+++ trunk/Source/WebCore/rendering/RenderText.h	2021-12-17 18:11:49 UTC (rev 287195)
@@ -33,6 +33,7 @@
 class Font;
 class LegacyInlineTextBox;
 struct GlyphOverflow;
+struct WordTrailingSpace;
 
 namespace LayoutIntegration {
 class LineLayout;
@@ -222,6 +223,8 @@
     void container() const = delete; // Use parent() instead.
     void container(const RenderLayerModelObject&, bool&) const = delete; // Use parent() instead.
 
+    float maxWordFragmentWidth(const RenderStyle&, const FontCascade&, StringView word, unsigned minimumPrefixLength, unsigned minimumSuffixLength, bool currentCharacterIsSpace, unsigned characterIndex, float xPos, float entireWordWidth, WordTrailingSpace&, HashSet<const Font*>& fallbackFonts, GlyphOverflow&);
+
     // We put the bitfield first to minimize padding on 64-bit.
     unsigned m_hasBreakableChar : 1; // Whether or not we can be broken into multiple lines.
     unsigned m_hasBreak : 1; // Whether or not we have a hard break (e.g., <pre> with '\n').
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to