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/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/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,