Changeset 237324 in webkit
- Timestamp:
- Oct 22, 2018 9:27:32 AM (6 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r237323 r237324 1 2018-10-22 Zalan Bujtas <zalan@apple.com> 2 3 [LFC][IFC] Add justify text-align support. 4 https://bugs.webkit.org/show_bug.cgi?id=190779 5 6 Reviewed by Antti Koivisto. 7 8 Collect expansion opportunities and adjust runs accordingly. 9 10 * layout/inlineformatting/InlineFormattingContext.cpp: 11 (WebCore::Layout::InlineFormattingContext::layoutInlineContent const): 12 * layout/inlineformatting/InlineFormattingContext.h: 13 * layout/inlineformatting/InlineRun.h: 14 (WebCore::Layout::InlineRun::expansionOpportunity): 15 (WebCore::Layout::InlineRun::TextContext::setStart): 16 (WebCore::Layout::InlineRun::TextContext::setLength): 17 (WebCore::Layout::InlineRun::setTextContext): 18 (WebCore::Layout::InlineRun::createRun): Deleted. 19 (WebCore::Layout::InlineRun::createTextRun): Deleted. 20 * layout/inlineformatting/Line.cpp: 21 (WebCore::Layout::InlineFormattingContext::Line::Line): 22 (WebCore::Layout::InlineFormattingContext::Line::init): 23 (WebCore::Layout::InlineFormattingContext::Line::computeExpansionOpportunities): 24 (WebCore::Layout::InlineFormattingContext::Line::appendContent): 25 (WebCore::Layout::InlineFormattingContext::Line::justifyRuns): 26 (WebCore::Layout::InlineFormattingContext::Line::close): 27 (WebCore::Layout::isNonCollapsedText): Deleted. 28 1 29 2018-10-22 Zalan Bujtas <zalan@apple.com> 2 30 -
trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
r237323 r237324 144 144 line.appendContent(*run); 145 145 } 146 line.close( );146 line.close(Line::LastLine::Yes); 147 147 } 148 148 -
trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h
r237323 r237324 54 54 void init(LayoutUnit lineLogicalLeft, LayoutUnit availableWidth); 55 55 void appendContent(const InlineLineBreaker::Run&); 56 void close(); 56 enum class LastLine { No, Yes }; 57 void close(LastLine = LastLine::No); 57 58 58 59 bool hasContent() const { return m_firstRunIndex.has_value(); } … … 61 62 62 63 private: 64 void justifyRuns(); 65 void computeExpansionOpportunities(const InlineLineBreaker::Run&); 66 63 67 struct TrailingTrimmableContent { 64 68 LayoutUnit width; … … 66 70 }; 67 71 std::optional<TrailingTrimmableContent> m_trailingTrimmableContent; 68 bool m_lastRunIsNotCollapsedText { true }; 72 bool m_lastRunIsWhitespace { false }; 73 bool m_lastRunCanExpand { false }; 69 74 70 75 InlineFormattingState& m_formattingState; … … 76 81 77 82 std::optional<unsigned> m_firstRunIndex; 83 bool m_alignmentIsJustify { false }; 78 84 }; 79 85 -
trunk/Source/WebCore/layout/inlineformatting/InlineRun.h
r237323 r237324 35 35 36 36 struct InlineRun { 37 static InlineRun createRun(LayoutUnit logcialLeft, LayoutUnit width, const InlineItem&); 38 static InlineRun createTextRun(LayoutUnit logcialLeft, LayoutUnit width, ItemPosition, unsigned length, const InlineItem&); 37 InlineRun(LayoutUnit logcialLeft, LayoutUnit width, const InlineItem&); 39 38 40 39 LayoutUnit logicalLeft() const { return m_logicalLeft; } … … 46 45 void setLogicalRight(LayoutUnit logicalRight) { m_width -= (this->logicalRight() - logicalRight); } 47 46 47 struct ExpansionOpportunity { 48 unsigned count { 0 }; 49 ExpansionBehavior behavior { ForbidLeadingExpansion | ForbidTrailingExpansion }; 50 LayoutUnit expansion; 51 }; 52 ExpansionOpportunity& expansionOpportunity() { return m_expansionOpportunity; } 53 48 54 struct TextContext { 49 55 public: 50 56 TextContext(ItemPosition, unsigned length); 51 57 58 void setStart(ItemPosition start) { m_start = start; } 59 void setLength(unsigned length) { m_length = length; } 60 52 61 ItemPosition start() const { return m_start; } 53 62 unsigned length() const { return m_length; } 54 55 void setLength(unsigned length) { m_length = length; }56 63 57 64 private: … … 59 66 unsigned m_length; 60 67 }; 68 void setTextContext(TextContext textContext) { m_textContext.emplace(textContext); } 61 69 std::optional<TextContext>& textContext() { return m_textContext; } 70 62 71 const InlineItem& inlineItem() const { return m_inlineItem; } 63 72 64 73 private: 65 InlineRun(LayoutUnit logcialLeft, LayoutUnit width, const InlineItem&);66 InlineRun(LayoutUnit logcialLeft, LayoutUnit width, ItemPosition, unsigned length, const InlineItem&);67 68 74 LayoutUnit m_logicalLeft; 69 75 LayoutUnit m_width; 76 ExpansionOpportunity m_expansionOpportunity; 70 77 71 78 const InlineItem& m_inlineItem; … … 75 82 using InlineRuns = Vector<InlineRun>; 76 83 77 inline InlineRun InlineRun::createRun(LayoutUnit logicalLeft, LayoutUnit width, const InlineItem& inlineItem)78 {79 return { logicalLeft, width, inlineItem };80 }81 82 inline InlineRun InlineRun::createTextRun(LayoutUnit logicalLeft, LayoutUnit width, ItemPosition start, unsigned length, const InlineItem& inlineItem)83 {84 return { logicalLeft, width, start, length, inlineItem };85 }86 87 84 inline InlineRun::InlineRun(LayoutUnit logicalLeft, LayoutUnit width, const InlineItem& inlineItem) 88 85 : m_logicalLeft(logicalLeft) 89 86 , m_width(width) 90 87 , m_inlineItem(inlineItem) 91 {92 }93 94 inline InlineRun::InlineRun(LayoutUnit logicalLeft, LayoutUnit width, ItemPosition start, unsigned length, const InlineItem& inlineItem)95 : m_logicalLeft(logicalLeft)96 , m_width(width)97 , m_inlineItem(inlineItem)98 , m_textContext(TextContext { start, length })99 88 { 100 89 } -
trunk/Source/WebCore/layout/inlineformatting/Line.cpp
r237323 r237324 37 37 : m_formattingState(formattingState) 38 38 , m_formattingRoot(formattingRoot) 39 , m_alignmentIsJustify(m_formattingRoot.style().textAlign() == TextAlignMode::Justify) 39 40 { 40 41 } … … 45 46 m_lineWidth = availableWidth; 46 47 m_availableWidth = availableWidth; 48 47 49 m_firstRunIndex = { }; 50 m_lastRunIsWhitespace = false; 51 m_lastRunCanExpand = false; 52 m_trailingTrimmableContent = { }; 48 53 } 49 54 … … 70 75 } 71 76 72 static bool isNonCollapsedText(const InlineRunProvider::Run& inlineRun)73 {74 return inlineRun.isText() && !inlineRun.textContext()->isCollapsed();75 }76 77 77 static bool isTrimmableContent(const InlineRunProvider::Run& inlineRun) 78 78 { … … 88 88 } 89 89 90 void InlineFormattingContext::Line::computeExpansionOpportunities(const InlineLineBreaker::Run& run) 91 { 92 if (!m_alignmentIsJustify) 93 return; 94 95 auto isExpansionOpportunity = [](auto currentRunIsWhitespace, auto lastRunIsWhitespace) { 96 return currentRunIsWhitespace || (!currentRunIsWhitespace && !lastRunIsWhitespace); 97 }; 98 99 auto expansionBehavior = [](auto isAtExpansionOpportunity) { 100 ExpansionBehavior expansionBehavior = AllowTrailingExpansion; 101 expansionBehavior |= isAtExpansionOpportunity ? ForbidLeadingExpansion : AllowLeadingExpansion; 102 return expansionBehavior; 103 }; 104 105 auto isAtExpansionOpportunity = isExpansionOpportunity(run.content.isWhitespace(), m_lastRunIsWhitespace); 106 107 auto& currentInlineRun = m_formattingState.inlineRuns().last(); 108 auto& expansionOpportunity = currentInlineRun.expansionOpportunity(); 109 if (isAtExpansionOpportunity) 110 ++expansionOpportunity.count; 111 112 expansionOpportunity.behavior = expansionBehavior(isAtExpansionOpportunity); 113 } 114 90 115 void InlineFormattingContext::Line::appendContent(const InlineLineBreaker::Run& run) 91 116 { 92 auto lastRunWasNotCollapsedText = m_lastRunIsNotCollapsedText;93 m_trailingTrimmableContent = { };94 m_availableWidth -= run.width;95 96 117 auto& content = run.content; 97 m_lastRunIsNotCollapsedText = isNonCollapsedText(content);98 118 99 119 // Append this text run to the end of the last text run, if the last run is continuous. … … 102 122 auto textContext = content.textContext(); 103 123 auto runLength = textContext->isCollapsed() ? 1 : textContext->length(); 104 105 if (isTrimmableContent(content))106 m_trailingTrimmableContent = TrailingTrimmableContent { run.width, runLength };107 108 if (hasContent() && lastRunWasNotCollapsedText) {109 auto& inlineRun = m_formattingState.inlineRuns().last();110 inlineRun.setWidth(inlineRun.width() + run.width);111 inlineRun.textContext()->setLength(inlineRun.textContext()->length() + runLength);112 return;113 }114 124 textRun = InlineRun::TextContext { textContext->start(), runLength }; 115 125 } 116 126 117 if (textRun) 118 m_formattingState.appendInlineRun(InlineRun::createTextRun(contentLogicalRight(), run.width, textRun->start(), textRun->length(), content.inlineItem())); 119 else 120 m_formattingState.appendInlineRun(InlineRun::createRun(contentLogicalRight(), run.width, content.inlineItem())); 127 auto requiresNewInlineRun = !hasContent() || !content.isText() || !m_lastRunCanExpand; 128 if (requiresNewInlineRun) { 129 auto inlineRun = InlineRun { contentLogicalRight(), run.width, content.inlineItem() }; 130 if (textRun) 131 inlineRun.setTextContext({ textRun->start(), textRun->length() }); 132 m_formattingState.appendInlineRun(inlineRun); 133 } else { 134 // Non-text runs always require new inline run. 135 ASSERT(textRun); 136 auto& inlineRun = m_formattingState.inlineRuns().last(); 137 inlineRun.setWidth(inlineRun.width() + run.width); 138 inlineRun.textContext()->setLength(inlineRun.textContext()->length() + textRun->length()); 139 } 140 141 computeExpansionOpportunities(run); 142 143 m_availableWidth -= run.width; 144 m_lastRunIsWhitespace = content.isWhitespace(); 145 m_lastRunCanExpand = content.isText() && !content.textContext()->isCollapsed(); 121 146 m_firstRunIndex = m_firstRunIndex.value_or(m_formattingState.inlineRuns().size() - 1); 122 } 123 124 void InlineFormattingContext::Line::close() 147 m_trailingTrimmableContent = { }; 148 if (isTrimmableContent(content)) 149 m_trailingTrimmableContent = TrailingTrimmableContent { run.width, textRun->length() }; 150 } 151 152 void InlineFormattingContext::Line::justifyRuns() 153 { 154 if (!hasContent()) 155 return; 156 157 auto& inlineRuns = m_formattingState.inlineRuns(); 158 auto& lastInlineRun = inlineRuns.last(); 159 160 // Adjust (forbid) trailing expansion for the last text run on line. 161 auto expansionBehavior = lastInlineRun.expansionOpportunity().behavior; 162 // Remove allow and add forbid. 163 expansionBehavior ^= AllowTrailingExpansion; 164 expansionBehavior |= ForbidTrailingExpansion; 165 lastInlineRun.expansionOpportunity().behavior = expansionBehavior; 166 167 // Collect expansion opportunities and justify the runs. 168 auto widthToDistribute = availableWidth(); 169 if (widthToDistribute <= 0) 170 return; 171 172 auto expansionOpportunities = 0; 173 for (auto runIndex = *m_firstRunIndex; runIndex < inlineRuns.size(); ++runIndex) 174 expansionOpportunities += inlineRuns[runIndex].expansionOpportunity().count; 175 176 if (!expansionOpportunities) 177 return; 178 179 float expansion = widthToDistribute.toFloat() / expansionOpportunities; 180 LayoutUnit accumulatedExpansion = 0; 181 for (auto runIndex = *m_firstRunIndex; runIndex < inlineRuns.size(); ++runIndex) { 182 auto& inlineRun = inlineRuns[runIndex]; 183 auto expansionForRun = inlineRun.expansionOpportunity().count * expansion; 184 185 inlineRun.expansionOpportunity().expansion = expansionForRun; 186 inlineRun.setLogicalLeft(inlineRun.logicalLeft() + accumulatedExpansion); 187 inlineRun.setWidth(inlineRun.width() + expansionForRun); 188 accumulatedExpansion += expansionForRun; 189 } 190 } 191 192 void InlineFormattingContext::Line::close(LastLine isLastLine) 125 193 { 126 194 auto trimTrailingContent = [&]() { … … 134 202 135 203 if (!lastInlineRun.textContext()->length()) { 204 if (*m_firstRunIndex == m_formattingState.inlineRuns().size() - 1) 205 m_firstRunIndex = { }; 136 206 m_formattingState.inlineRuns().removeLast(); 137 if (m_firstRunIndex.value())138 --*m_firstRunIndex;139 else140 m_firstRunIndex = { };141 207 } 142 208 m_availableWidth += m_trailingTrimmableContent->width; … … 144 210 }; 145 211 146 auto alignRuns = [&]( ) {212 auto alignRuns = [&](auto alignment) { 147 213 148 214 if (!hasContent()) 149 215 return; 150 216 151 auto adjustedLogicalLeft = adjustedLineLogicalLeft( m_formattingRoot.style().textAlign(), m_lineLogicalLeft, m_availableWidth);217 auto adjustedLogicalLeft = adjustedLineLogicalLeft(alignment, m_lineLogicalLeft, m_availableWidth); 152 218 if (m_lineLogicalLeft == adjustedLogicalLeft) 153 219 return; … … 163 229 164 230 trimTrailingContent(); 165 alignRuns(); 231 232 auto textAlignment = m_formattingRoot.style().textAlign(); 233 if (m_alignmentIsJustify) { 234 if (isLastLine == LastLine::No) { 235 justifyRuns(); 236 return; 237 } 238 textAlignment = TextAlignMode::Left; 239 } 240 alignRuns(textAlignment); 166 241 } 167 242
Note: See TracChangeset
for help on using the changeset viewer.