Title: [281337] trunk
Revision
281337
Author
[email protected]
Date
2021-08-20 14:24:44 -0700 (Fri, 20 Aug 2021)

Log Message

[LFC][IFC] Add support for justified non-breaking space
https://bugs.webkit.org/show_bug.cgi?id=228727

Reviewed by Antti Koivisto.

Let's use FontCascade::expansionOpportunityCount to figure out the number of expansion counts in a run.
It helps with finding non-breakable space in an otherwise non-whitespace content (foo bar where the contet forms one run but the because
of the non-breakable _space_ in the middle, it also produces an expansion opportunity).
This patch moves all the expansion handling over to Line::applyRunExpansion as we anyway need to walk the content to find such spaces (i.e. not worth trying to pre-compute them).

* layout/formattingContexts/inline/InlineLine.cpp:
(WebCore::Layout::Line::applyRunExpansion):
(WebCore::Layout::Line::Run::Run):
(WebCore::Layout::Line::Run::expand):
(WebCore::Layout::Line::Run::visuallyCollapseTrailingWhitespace):
(WebCore::Layout::Line::Run::setExpansionBehavior): Deleted.
(WebCore::Layout::Line::Run::expansionBehavior const): Deleted.
(WebCore::Layout::Line::Run::setHorizontalExpansion): Deleted.
* layout/formattingContexts/inline/InlineLine.h:
(WebCore::Layout::Line::Run::expansion const):
(WebCore::Layout::Line::Run::setExpansion):
(WebCore::Layout::Line::Run::hasExpansionOpportunity const): Deleted.
(WebCore::Layout::Line::Run::expansionOpportunityCount const): Deleted.
* layout/integration/LayoutIntegrationCoverage.cpp:
(WebCore::LayoutIntegration::canUseForCharacter):
(WebCore::LayoutIntegration::canUseForText):
(WebCore::LayoutIntegration::canUseForFontAndText):
(WebCore::LayoutIntegration::canUseForStyle):

Modified Paths

Diff

Modified: trunk/LayoutTests/platform/mac/fast/text/justify-nbsp-expected.txt (281336 => 281337)


--- trunk/LayoutTests/platform/mac/fast/text/justify-nbsp-expected.txt	2021-08-20 20:56:03 UTC (rev 281336)
+++ trunk/LayoutTests/platform/mac/fast/text/justify-nbsp-expected.txt	2021-08-20 21:24:44 UTC (rev 281337)
@@ -10,7 +10,7 @@
         RenderText {#text} at (360,15) size 650x75
           text run at (360,15) width 293: "e f g h"
           text run at (3,65) width 275: "xxxxxxxxxxx"
-        RenderBR {BR} at (278,53) size 0x25
+        RenderBR {BR} at (278,65) size 0x25
         RenderInline {SPAN} at (0,0) size 358x25
           RenderText {#text} at (3,115) size 358x25
             text run at (3,115) width 358: "a b c d "

Modified: trunk/Source/WebCore/ChangeLog (281336 => 281337)


--- trunk/Source/WebCore/ChangeLog	2021-08-20 20:56:03 UTC (rev 281336)
+++ trunk/Source/WebCore/ChangeLog	2021-08-20 21:24:44 UTC (rev 281337)
@@ -1,5 +1,36 @@
 2021-08-20  Alan Bujtas  <[email protected]>
 
+        [LFC][IFC] Add support for justified non-breaking space
+        https://bugs.webkit.org/show_bug.cgi?id=228727
+
+        Reviewed by Antti Koivisto.
+
+        Let's use FontCascade::expansionOpportunityCount to figure out the number of expansion counts in a run.
+        It helps with finding non-breakable space in an otherwise non-whitespace content (foo&nbsp;bar where the contet forms one run but the because
+        of the non-breakable _space_ in the middle, it also produces an expansion opportunity).
+        This patch moves all the expansion handling over to Line::applyRunExpansion as we anyway need to walk the content to find such spaces (i.e. not worth trying to pre-compute them).
+
+        * layout/formattingContexts/inline/InlineLine.cpp:
+        (WebCore::Layout::Line::applyRunExpansion):
+        (WebCore::Layout::Line::Run::Run):
+        (WebCore::Layout::Line::Run::expand):
+        (WebCore::Layout::Line::Run::visuallyCollapseTrailingWhitespace):
+        (WebCore::Layout::Line::Run::setExpansionBehavior): Deleted.
+        (WebCore::Layout::Line::Run::expansionBehavior const): Deleted.
+        (WebCore::Layout::Line::Run::setHorizontalExpansion): Deleted.
+        * layout/formattingContexts/inline/InlineLine.h:
+        (WebCore::Layout::Line::Run::expansion const):
+        (WebCore::Layout::Line::Run::setExpansion):
+        (WebCore::Layout::Line::Run::hasExpansionOpportunity const): Deleted.
+        (WebCore::Layout::Line::Run::expansionOpportunityCount const): Deleted.
+        * layout/integration/LayoutIntegrationCoverage.cpp:
+        (WebCore::LayoutIntegration::canUseForCharacter):
+        (WebCore::LayoutIntegration::canUseForText):
+        (WebCore::LayoutIntegration::canUseForFontAndText):
+        (WebCore::LayoutIntegration::canUseForStyle):
+
+2021-08-20  Alan Bujtas  <[email protected]>
+
         [LFC][IFC] LineBox provides redundant geometry information
         https://bugs.webkit.org/show_bug.cgi?id=228050
 

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp (281336 => 281337)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp	2021-08-20 20:56:03 UTC (rev 281336)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp	2021-08-20 21:24:44 UTC (rev 281337)
@@ -73,36 +73,66 @@
     // the last line before a forced break or the end of the block is start-aligned.
     if (m_runs.isEmpty() || m_runs.last().isLineBreak())
         return;
+    // Anything to distribute?
+    if (!extraHorizontalSpace)
+        return;
 
-    auto expansionOpportunityCount = 0;
-    Run* lastRunWithContent = nullptr;
     // Collect and distribute the expansion opportunities.
-    for (auto& run : m_runs) {
-        expansionOpportunityCount += run.expansionOpportunityCount();
+    size_t lineExpansionOpportunities = 0;
+    Vector<size_t> runsExpansionOpportunities(m_runs.size());
+    Vector<ExpansionBehavior> runsExpansionBehaviors(m_runs.size());
+    auto lastRunIndexWithContent = std::optional<size_t> { };
+
+    // Line start behaves as if we had an expansion here (i.e. fist runs should not start with allowing left expansion).
+    auto runIsAfterExpansion = true;
+    for (size_t runIndex = 0; runIndex < m_runs.size(); ++runIndex) {
+        auto& run = m_runs[runIndex];
+        auto& style = run.style();
+        int expansionBehavior = DefaultExpansion;
+        size_t expansionOpportunitiesInRun = 0;
+
+        if (run.isText() && !TextUtil::shouldPreserveSpacesAndTabs(run.layoutBox())) {
+            if (style.textCombine() == TextCombine::Horizontal)
+                expansionBehavior = ForbidLeftExpansion | ForbidRightExpansion;
+            else {
+                expansionBehavior = (runIsAfterExpansion ? ForbidLeftExpansion : AllowLeftExpansion) | AllowRightExpansion;
+                std::tie(expansionOpportunitiesInRun, runIsAfterExpansion) = FontCascade::expansionOpportunityCount(StringView(run.textContent()->content()).substring(run.textContent()->start(), run.textContent()->length()), run.style().direction(), expansionBehavior);
+            }
+        } else if (run.isBox())
+            runIsAfterExpansion = false;
+
+        runsExpansionBehaviors[runIndex] = expansionBehavior;
+        runsExpansionOpportunities[runIndex] = expansionOpportunitiesInRun;
+        lineExpansionOpportunities += expansionOpportunitiesInRun;
+
         if (run.isText() || run.isBox())
-            lastRunWithContent = &run;
+            lastRunIndexWithContent = runIndex;
     }
     // Need to fix up the last run's trailing expansion.
-    if (lastRunWithContent && lastRunWithContent->hasExpansionOpportunity()) {
+    if (lastRunIndexWithContent && runsExpansionOpportunities[*lastRunIndexWithContent]) {
         // Turn off the trailing bits first and add the forbid trailing expansion.
-        auto leadingExpansion = lastRunWithContent->expansionBehavior() & LeftExpansionMask;
-        lastRunWithContent->setExpansionBehavior(leadingExpansion | ForbidRightExpansion);
+        auto leadingExpansion = runsExpansionBehaviors[*lastRunIndexWithContent] & LeftExpansionMask;
+        runsExpansionBehaviors[*lastRunIndexWithContent] = leadingExpansion | ForbidRightExpansion;
+        if (runIsAfterExpansion) {
+            // When the last run has an after expansion (e.g. CJK ideograph) we need to remove this trailing expansion opportunity.
+            // Note that this is not about trailing collapsible whitespace as at this point we trimmed them all.
+            ASSERT(lineExpansionOpportunities && runsExpansionOpportunities[*lastRunIndexWithContent]);
+            --lineExpansionOpportunities;
+            --runsExpansionOpportunities[*lastRunIndexWithContent];
+        }
     }
     // Anything to distribute?
-    if (!expansionOpportunityCount || !extraHorizontalSpace)
+    if (!lineExpansionOpportunities)
         return;
     // Distribute the extra space.
-    auto expansionToDistribute = extraHorizontalSpace / expansionOpportunityCount;
+    auto expansionToDistribute = extraHorizontalSpace / lineExpansionOpportunities;
     auto accumulatedExpansion = InlineLayoutUnit { };
-    for (auto& run : m_runs) {
+    for (size_t runIndex = 0; runIndex < m_runs.size(); ++runIndex) {
+        auto& run = m_runs[runIndex];
         // Expand and move runs by the accumulated expansion.
         run.moveHorizontally(accumulatedExpansion);
-        if (!run.hasExpansionOpportunity())
-            continue;
-        ASSERT(run.expansionOpportunityCount());
-        auto computedExpansion = expansionToDistribute * run.expansionOpportunityCount();
-        // FIXME: Check why we need to set both.
-        run.setHorizontalExpansion(computedExpansion);
+        auto computedExpansion = expansionToDistribute * runsExpansionOpportunities[runIndex];
+        run.setExpansion({ runsExpansionBehaviors[runIndex], computedExpansion });
         run.shrinkHorizontally(-computedExpansion);
         accumulatedExpansion += computedExpansion;
     }
@@ -436,20 +466,14 @@
     , m_layoutBox(&inlineTextItem.layoutBox())
     , m_logicalLeft(logicalLeft)
     , m_logicalWidth(logicalWidth)
-    , m_whitespaceIsExpansionOpportunity(!TextUtil::shouldPreserveSpacesAndTabs(inlineTextItem.layoutBox()))
     , m_trailingWhitespaceType(trailingWhitespaceType(inlineTextItem))
+    , m_trailingWhitespaceWidth(m_trailingWhitespaceType != TrailingWhitespace::None ? logicalWidth : InlineLayoutUnit { })
     , m_textContent({ inlineTextItem.start(), m_trailingWhitespaceType == TrailingWhitespace::Collapsed ? 1 : inlineTextItem.length(), inlineTextItem.inlineTextBox().content() })
 {
-    if (m_trailingWhitespaceType != TrailingWhitespace::None) {
-        m_trailingWhitespaceWidth = logicalWidth;
-        if (m_whitespaceIsExpansionOpportunity)
-            m_expansionOpportunityCount = 1;
-    }
 }
 
 void Line::Run::expand(const InlineTextItem& inlineTextItem, InlineLayoutUnit logicalWidth)
 {
-    // FIXME: This is a very simple expansion merge. We should eventually switch over to FontCascade::expansionOpportunityCount.
     ASSERT(!hasCollapsedTrailingWhitespace());
     ASSERT(isText() && inlineTextItem.isText());
     ASSERT(m_layoutBox == &inlineTextItem.layoutBox());
@@ -459,14 +483,10 @@
 
     if (m_trailingWhitespaceType == TrailingWhitespace::None) {
         m_trailingWhitespaceWidth = { };
-        setExpansionBehavior(AllowLeftExpansion | AllowRightExpansion);
         m_textContent->expand(inlineTextItem.length());
         return;
     }
     m_trailingWhitespaceWidth += logicalWidth;
-    if (m_whitespaceIsExpansionOpportunity)
-        ++m_expansionOpportunityCount;
-    setExpansionBehavior(DefaultExpansion);
     m_textContent->expand(m_trailingWhitespaceType == TrailingWhitespace::Collapsed ? 1 : inlineTextItem.length());
 }
 
@@ -509,36 +529,11 @@
     if (!m_trailingWhitespaceWidth) {
         // We trimmed the trailing whitespace completely.
         m_trailingWhitespaceType = TrailingWhitespace::None;
-
-        if (m_whitespaceIsExpansionOpportunity) {
-            ASSERT(m_expansionOpportunityCount);
-            m_expansionOpportunityCount--;
-        }
-        setExpansionBehavior(AllowLeftExpansion | AllowRightExpansion);
     }
     return trimmedWidth;
 }
 
-void Line::Run::setExpansionBehavior(ExpansionBehavior expansionBehavior)
-{
-    ASSERT(isText());
-    m_expansion.behavior = expansionBehavior;
 }
-
-ExpansionBehavior Line::Run::expansionBehavior() const
-{
-    ASSERT(isText());
-    return m_expansion.behavior;
 }
 
-void Line::Run::setHorizontalExpansion(InlineLayoutUnit logicalExpansion)
-{
-    ASSERT(isText());
-    ASSERT(hasExpansionOpportunity());
-    m_expansion.horizontalExpansion = logicalExpansion;
-}
-
-}
-}
-
 #endif

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.h (281336 => 281337)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.h	2021-08-20 20:56:03 UTC (rev 281336)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.h	2021-08-20 21:24:44 UTC (rev 281337)
@@ -78,9 +78,6 @@
         InlineLayoutUnit logicalRight() const { return logicalLeft() + logicalWidth(); }
 
         const LineRun::Expansion& expansion() const { return m_expansion; }
-        bool hasExpansionOpportunity() const { return m_expansionOpportunityCount; }
-        ExpansionBehavior expansionBehavior() const;
-        unsigned expansionOpportunityCount() const { return m_expansionOpportunityCount; }
 
         bool hasTrailingWhitespace() const { return m_trailingWhitespaceType != TrailingWhitespace::None; }
         InlineLayoutUnit trailingWhitespaceWidth() const { return m_trailingWhitespaceWidth; }
@@ -95,8 +92,7 @@
         void expand(const InlineTextItem&, InlineLayoutUnit logicalWidth);
         void moveHorizontally(InlineLayoutUnit offset) { m_logicalLeft += offset; }
         void shrinkHorizontally(InlineLayoutUnit width) { m_logicalWidth -= width; }
-        void setExpansionBehavior(ExpansionBehavior);
-        void setHorizontalExpansion(InlineLayoutUnit logicalExpansion);
+        void setExpansion(LineRun::Expansion expansion) { m_expansion = expansion; }
         void setNeedsHyphen(InlineLayoutUnit hyphenLogicalWidth);
 
         enum class TrailingWhitespace {
@@ -119,12 +115,10 @@
         const Box* m_layoutBox { nullptr };
         InlineLayoutUnit m_logicalLeft { 0 };
         InlineLayoutUnit m_logicalWidth { 0 };
-        bool m_whitespaceIsExpansionOpportunity { false };
         TrailingWhitespace m_trailingWhitespaceType { TrailingWhitespace::None };
         InlineLayoutUnit m_trailingWhitespaceWidth { 0 };
         std::optional<LineRun::Text> m_textContent;
         LineRun::Expansion m_expansion;
-        unsigned m_expansionOpportunityCount { 0 };
     };
     using RunList = Vector<Run, 10>;
     const RunList& runs() const { return m_runs; }

Modified: trunk/Source/WebCore/layout/integration/LayoutIntegrationCoverage.cpp (281336 => 281337)


--- trunk/Source/WebCore/layout/integration/LayoutIntegrationCoverage.cpp	2021-08-20 20:56:03 UTC (rev 281336)
+++ trunk/Source/WebCore/layout/integration/LayoutIntegrationCoverage.cpp	2021-08-20 21:24:44 UTC (rev 281337)
@@ -123,9 +123,6 @@
     case AvoidanceReason::FlowHasUnsupportedFloat:
         stream << "complicated float";
         break;
-    case AvoidanceReason::FlowHasJustifiedNonLatinText:
-        stream << "text-align: justify with non-latin text";
-        break;
     case AvoidanceReason::FlowHasOverflowNotVisible:
         stream << "overflow: hidden | scroll | auto";
         break;
@@ -418,21 +415,11 @@
 }
 #endif
 
-template <typename CharacterType> OptionSet<AvoidanceReason> canUseForCharacter(CharacterType, bool textIsJustified, IncludeReasons);
+template <typename CharacterType> OptionSet<AvoidanceReason> canUseForCharacter(CharacterType, IncludeReasons);
 
-template<> OptionSet<AvoidanceReason> canUseForCharacter(UChar character, bool textIsJustified, IncludeReasons includeReasons)
+template<> OptionSet<AvoidanceReason> canUseForCharacter(UChar character, IncludeReasons includeReasons)
 {
     OptionSet<AvoidanceReason> reasons;
-    if (textIsJustified) {
-        if (character == noBreakSpace)
-            SET_REASON_AND_RETURN_IF_NEEDED(FlowHasJustifiedNonBreakingSpace, reasons, includeReasons);
-        // Include characters up to Latin Extended-B and some punctuation range when text is justified.
-        bool isLatinIncludingExtendedB = character <= 0x01FF;
-        bool isPunctuationRange = character >= 0x2010 && character <= 0x2027;
-        if (!(isLatinIncludingExtendedB || isPunctuationRange))
-            SET_REASON_AND_RETURN_IF_NEEDED(FlowHasJustifiedNonLatinText, reasons, includeReasons);
-    }
-
     if (U16_IS_SURROGATE(character))
         SET_REASON_AND_RETURN_IF_NEEDED(FlowTextHasSurrogatePair, reasons, includeReasons);
 
@@ -446,16 +433,13 @@
     return reasons;
 }
 
-template<> OptionSet<AvoidanceReason> canUseForCharacter(LChar character, bool textIsJustified, IncludeReasons)
+template<> OptionSet<AvoidanceReason> canUseForCharacter(LChar, IncludeReasons)
 {
-    if (textIsJustified && character == noBreakSpace)
-        return { AvoidanceReason::FlowHasJustifiedNonBreakingSpace };
     return { };
 }
 
 template <typename CharacterType>
-static OptionSet<AvoidanceReason> canUseForText(const CharacterType* text, unsigned length, const FontCascade& fontCascade, std::optional<float> lineHeightConstraint,
-    bool textIsJustified, IncludeReasons includeReasons)
+static OptionSet<AvoidanceReason> canUseForText(const CharacterType* text, unsigned length, const FontCascade& fontCascade, std::optional<float> lineHeightConstraint, IncludeReasons includeReasons)
 {
     OptionSet<AvoidanceReason> reasons;
     auto& primaryFont = fontCascade.primaryFont();
@@ -470,7 +454,7 @@
 
     for (unsigned i = 0; i < length; ++i) {
         auto character = text[i];
-        auto characterReasons = canUseForCharacter(character, textIsJustified, includeReasons);
+        auto characterReasons = canUseForCharacter(character, includeReasons);
         if (characterReasons)
             ADD_REASONS_AND_RETURN_IF_NEEDED(characterReasons, reasons, includeReasons);
 
@@ -487,11 +471,11 @@
     return reasons;
 }
 
-static OptionSet<AvoidanceReason> canUseForText(StringView text, const FontCascade& fontCascade, std::optional<float> lineHeightConstraint, bool textIsJustified, IncludeReasons includeReasons)
+static OptionSet<AvoidanceReason> canUseForText(StringView text, const FontCascade& fontCascade, std::optional<float> lineHeightConstraint, IncludeReasons includeReasons)
 {
     if (text.is8Bit())
-        return canUseForText(text.characters8(), text.length(), fontCascade, lineHeightConstraint, textIsJustified, includeReasons);
-    return canUseForText(text.characters16(), text.length(), fontCascade, lineHeightConstraint, textIsJustified, includeReasons);
+        return canUseForText(text.characters8(), text.length(), fontCascade, lineHeightConstraint, includeReasons);
+    return canUseForText(text.characters16(), text.length(), fontCascade, lineHeightConstraint, includeReasons);
 }
 
 static OptionSet<AvoidanceReason> canUseForFontAndText(const RenderBoxModelObject& container, IncludeReasons includeReasons)
@@ -505,7 +489,6 @@
     std::optional<float> lineHeightConstraint;
     if (style.lineBoxContain().contains(LineBoxContain::Glyphs))
         lineHeightConstraint = container.lineHeight(false, HorizontalLine, PositionOfInteriorLineBoxes).toFloat();
-    bool flowIsJustified = style.textAlign() == TextAlignMode::Justify;
     for (const auto& textRenderer : childrenOfType<RenderText>(container)) {
         // FIXME: Do not return until after checking all children.
         if (textRenderer.isCombineText())
@@ -528,7 +511,7 @@
                 SET_REASON_AND_RETURN_IF_NEEDED(FlowHasComplexFontCodePath, reasons, includeReasons);
         }
 
-        auto textReasons = canUseForText(textRenderer.stringView(), fontCascade, lineHeightConstraint, flowIsJustified, includeReasons);
+        auto textReasons = canUseForText(textRenderer.stringView(), fontCascade, lineHeightConstraint, includeReasons);
         if (textReasons)
             ADD_REASONS_AND_RETURN_IF_NEEDED(textReasons, reasons, includeReasons);
     }

Modified: trunk/Source/WebCore/layout/integration/LayoutIntegrationCoverage.h (281336 => 281337)


--- trunk/Source/WebCore/layout/integration/LayoutIntegrationCoverage.h	2021-08-20 20:56:03 UTC (rev 281336)
+++ trunk/Source/WebCore/layout/integration/LayoutIntegrationCoverage.h	2021-08-20 21:24:44 UTC (rev 281337)
@@ -49,7 +49,7 @@
     FlowHasNonSupportedChild                     = 1LLU  << 9,
     FlowHasUnsupportedFloat                      = 1LLU  << 10,
     // Unused                                    = 1LLU  << 11,
-    FlowHasJustifiedNonLatinText                 = 1LLU  << 12,
+    // Unused                                    = 1LLU  << 12,
     FlowHasOverflowNotVisible                    = 1LLU  << 13,
     // Unused                                    = 1LLU  << 14,
     FlowIsNotLTR                                 = 1LLU  << 15,
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to