[LFC][IFC] Optimize LineBuilder::appendTextContent for the most common inline content
https://bugs.webkit.org/show_bug.cgi?id=206397
<rdar://problem/58671338>
Reviewed by Antti Koivisto.
~2% progression on PerformanceTests/Layout/line-layout-simple.html.
* layout/inlineformatting/InlineLineBuilder.cpp:
(WebCore::Layout::LineBuilder::LineBuilder):
(WebCore::Layout::shouldPreserveLeadingContent):
(WebCore::Layout::LineBuilder::appendTextContent):
(WebCore::Layout::LineBuilder::appendLineBreak):
(WebCore::Layout::LineBuilder::InlineItemRun::InlineItemRun):
* layout/inlineformatting/InlineLineBuilder.h:
(WebCore::Layout::LineBuilder::InlineItemRun::setIsCollapsed): Deleted.
* layout/inlineformatting/InlineTextItem.cpp:
(WebCore::Layout::InlineTextItem::InlineTextItem):
* layout/inlineformatting/InlineTextItem.h:
(WebCore::Layout::InlineTextItem::isCollapsible const):
* layout/inlineformatting/text/TextUtil.cpp:
(WebCore::Layout::TextUtil::shouldPreserveTrailingWhitespace): Deleted.
* layout/inlineformatting/text/TextUtil.h:
(WebCore::Layout::TextUtil::shouldPreserveTrailingWhitespace):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@254750 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index b69b899..140f543 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,30 @@
+2020-01-17 Zalan Bujtas <zalan@apple.com>
+
+ [LFC][IFC] Optimize LineBuilder::appendTextContent for the most common inline content
+ https://bugs.webkit.org/show_bug.cgi?id=206397
+ <rdar://problem/58671338>
+
+ Reviewed by Antti Koivisto.
+
+ ~2% progression on PerformanceTests/Layout/line-layout-simple.html.
+
+ * layout/inlineformatting/InlineLineBuilder.cpp:
+ (WebCore::Layout::LineBuilder::LineBuilder):
+ (WebCore::Layout::shouldPreserveLeadingContent):
+ (WebCore::Layout::LineBuilder::appendTextContent):
+ (WebCore::Layout::LineBuilder::appendLineBreak):
+ (WebCore::Layout::LineBuilder::InlineItemRun::InlineItemRun):
+ * layout/inlineformatting/InlineLineBuilder.h:
+ (WebCore::Layout::LineBuilder::InlineItemRun::setIsCollapsed): Deleted.
+ * layout/inlineformatting/InlineTextItem.cpp:
+ (WebCore::Layout::InlineTextItem::InlineTextItem):
+ * layout/inlineformatting/InlineTextItem.h:
+ (WebCore::Layout::InlineTextItem::isCollapsible const):
+ * layout/inlineformatting/text/TextUtil.cpp:
+ (WebCore::Layout::TextUtil::shouldPreserveTrailingWhitespace): Deleted.
+ * layout/inlineformatting/text/TextUtil.h:
+ (WebCore::Layout::TextUtil::shouldPreserveTrailingWhitespace):
+
2020-01-17 Antti Koivisto <antti@apple.com>
[LFC][IFC] Allocate InlineItems in a vector
diff --git a/Source/WebCore/layout/inlineformatting/InlineItem.cpp b/Source/WebCore/layout/inlineformatting/InlineItem.cpp
index 5ca9882..4625a0b 100644
--- a/Source/WebCore/layout/inlineformatting/InlineItem.cpp
+++ b/Source/WebCore/layout/inlineformatting/InlineItem.cpp
@@ -38,6 +38,7 @@
uint8_t enum1;
uint8_t enum2;
bool widthBool;
+ bool isCollapsible;
InlineLayoutUnit width;
unsigned start;
unsigned length;
diff --git a/Source/WebCore/layout/inlineformatting/InlineItem.h b/Source/WebCore/layout/inlineformatting/InlineItem.h
index 1064cf9..26ddefc 100644
--- a/Source/WebCore/layout/inlineformatting/InlineItem.h
+++ b/Source/WebCore/layout/inlineformatting/InlineItem.h
@@ -60,6 +60,7 @@
enum class TextItemType : uint8_t { Undefined, Whitespace, NonWhitespace };
TextItemType m_textItemType { TextItemType::Undefined };
bool m_hasWidth { false };
+ bool m_isCollapsible { false };
InlineLayoutUnit m_width { };
unsigned m_length { 0 };
diff --git a/Source/WebCore/layout/inlineformatting/InlineLineBuilder.cpp b/Source/WebCore/layout/inlineformatting/InlineLineBuilder.cpp
index 51f9793..7abf426 100644
--- a/Source/WebCore/layout/inlineformatting/InlineLineBuilder.cpp
+++ b/Source/WebCore/layout/inlineformatting/InlineLineBuilder.cpp
@@ -189,6 +189,7 @@
, m_collapsibleContent(m_inlineItemRuns)
, m_horizontalAlignment(horizontalAlignment)
, m_isIntrinsicSizing(intrinsicSizing == IntrinsicSizing::Yes)
+ , m_shouldIgnoreTrailingLetterSpacing(RuntimeEnabledFeatures::sharedFeatures().layoutFormattingContextIntegrationEnabled())
{
}
@@ -220,7 +221,7 @@
m_lineIsVisuallyEmptyBeforeCollapsibleContent = { };
}
-static bool shouldPreserveLeadingContent(const InlineTextItem& inlineTextItem)
+static inline bool shouldPreserveLeadingContent(const InlineTextItem& inlineTextItem)
{
if (!inlineTextItem.isWhitespace())
return true;
@@ -635,15 +636,12 @@
void LineBuilder::appendTextContent(const InlineTextItem& inlineItem, InlineLayoutUnit logicalWidth)
{
+ auto isCollapsible = inlineItem.isCollapsible();
auto willCollapseCompletely = [&] {
- if (!inlineItem.isCollapsible())
+ if (!isCollapsible)
return false;
- // Leading whitespace.
- if (m_inlineItemRuns.isEmpty())
- return !shouldPreserveLeadingContent(inlineItem);
// Check if the last item is collapsed as well.
- for (auto i = m_inlineItemRuns.size(); i--;) {
- auto& run = m_inlineItemRuns[i];
+ for (auto& run : WTF::makeReversedRange(m_inlineItemRuns)) {
if (run.isBox())
return false;
// https://drafts.csswg.org/css-text-3/#white-space-phase-1
@@ -655,34 +653,27 @@
return run.isCollapsible();
ASSERT(run.isContainerStart() || run.isContainerEnd());
}
- return true;
+ // Leading whitespace.
+ return !shouldPreserveLeadingContent(inlineItem);
};
auto collapsesToZeroAdvanceWidth = willCollapseCompletely();
- auto collapsedRun = inlineItem.isCollapsible() && inlineItem.length() > 1;
- auto contentStart = inlineItem.start();
+ logicalWidth = collapsesToZeroAdvanceWidth ? 0 : logicalWidth;
+ auto collapsedRun = isCollapsible && inlineItem.length() > 1;
auto contentLength = collapsedRun ? 1 : inlineItem.length();
- m_inlineItemRuns.append({ inlineItem, contentLogicalWidth(), logicalWidth, Display::Run::TextContext { contentStart, contentLength, inlineItem.layoutBox().textContext()->content } });
- auto& lineRun = m_inlineItemRuns.last();
+ m_inlineItemRuns.append({ inlineItem, contentLogicalWidth(), logicalWidth, collapsedRun, collapsesToZeroAdvanceWidth, Display::Run::TextContext { inlineItem.start(), contentLength, inlineItem.layoutBox().textContext()->content } });
+ m_lineBox.expandHorizontally(logicalWidth);
- if (collapsesToZeroAdvanceWidth)
- lineRun.setCollapsesToZeroAdvanceWidth();
-
- if (collapsedRun)
- lineRun.setIsCollapsed();
-
- m_lineBox.expandHorizontally(lineRun.logicalWidth());
-
- // Existing trailing collapsible content can only be expanded if the current run is fully collapsible.
- auto collapsibleListNeedsReset = !m_collapsibleContent.isEmpty() && !lineRun.isCollapsibleWhitespace();
- if (collapsibleListNeedsReset)
- m_collapsibleContent.reset();
- auto isCollapsible = lineRun.isCollapsibleWhitespace() || lineRun.hasTrailingLetterSpacing();
- if (isCollapsible) {
+ if (isCollapsible && !TextUtil::shouldPreserveTrailingWhitespace(inlineItem.style())) {
// If we ever collapse this content, we need to know if the line visibility state needs to be recomputed.
if (m_collapsibleContent.isEmpty())
m_lineIsVisuallyEmptyBeforeCollapsibleContent = isVisuallyEmpty();
m_collapsibleContent.append(m_inlineItemRuns.size() - 1);
+ } else {
+ // Existing trailing collapsible content can only be expanded if the current run is fully collapsible.
+ m_collapsibleContent.reset();
+ if (!m_shouldIgnoreTrailingLetterSpacing && !inlineItem.isWhitespace() && inlineItem.style().letterSpacing() > 0)
+ m_collapsibleContent.append(m_inlineItemRuns.size() - 1);
}
}
@@ -710,7 +701,7 @@
// Soft line breaks (preserved new line characters) require inline text boxes for compatibility reasons.
ASSERT(inlineItem.isSoftLineBreak());
auto& softLineBreakItem = downcast<InlineSoftLineBreakItem>(inlineItem);
- m_inlineItemRuns.append({ softLineBreakItem, contentLogicalWidth(), 0_lu, Display::Run::TextContext { softLineBreakItem.position(), 1, softLineBreakItem.layoutBox().textContext()->content } });
+ m_inlineItemRuns.append({ softLineBreakItem, contentLogicalWidth(), 0_lu, false, false, Display::Run::TextContext { softLineBreakItem.position(), 1, softLineBreakItem.layoutBox().textContext()->content } });
}
void LineBuilder::adjustBaselineAndLineHeight(const Run& run)
@@ -964,11 +955,20 @@
return 0_lu;
}
-LineBuilder::InlineItemRun::InlineItemRun(const InlineItem& inlineItem, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth, WTF::Optional<Display::Run::TextContext> textContext)
+LineBuilder::InlineItemRun::InlineItemRun(const InlineItem& inlineItem, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth)
: m_inlineItem(inlineItem)
, m_logicalLeft(logicalLeft)
, m_logicalWidth(logicalWidth)
- , m_textContext(textContext)
+{
+}
+
+LineBuilder::InlineItemRun::InlineItemRun(const InlineItem& inlineItem, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth, bool isCollapsed, bool isCollapsedToZeroAdvanceWidth, Display::Run::TextContext&& textContext)
+ : m_inlineItem(inlineItem)
+ , m_logicalLeft(logicalLeft)
+ , m_logicalWidth(logicalWidth)
+ , m_textContext(WTFMove(textContext))
+ , m_isCollapsed(isCollapsed)
+ , m_collapsedToZeroAdvanceWidth(isCollapsedToZeroAdvanceWidth)
{
}
diff --git a/Source/WebCore/layout/inlineformatting/InlineLineBuilder.h b/Source/WebCore/layout/inlineformatting/InlineLineBuilder.h
index e285db1..f78a614 100644
--- a/Source/WebCore/layout/inlineformatting/InlineLineBuilder.h
+++ b/Source/WebCore/layout/inlineformatting/InlineLineBuilder.h
@@ -161,7 +161,8 @@
class InlineItemRun {
public:
- InlineItemRun(const InlineItem&, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth, WTF::Optional<Display::Run::TextContext> = WTF::nullopt);
+ InlineItemRun(const InlineItem&, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth, bool isCollapsed, bool isCollapsedToZeroAdvanceWidth, Display::Run::TextContext&&);
+ InlineItemRun(const InlineItem&, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth);
const Box& layoutBox() const { return m_inlineItem.layoutBox(); }
const RenderStyle& style() const { return layoutBox().style(); }
@@ -176,7 +177,6 @@
bool isLineBreak() const { return m_inlineItem.isLineBreak(); }
InlineItem::Type type() const { return m_inlineItem.type(); }
- void setIsCollapsed() { m_isCollapsed = true; }
bool isCollapsed() const { return m_isCollapsed; }
void moveHorizontally(InlineLayoutUnit offset) { m_logicalLeft += offset; }
@@ -242,6 +242,7 @@
bool m_hasIntrusiveFloat { false };
Display::LineBox m_lineBox;
Optional<bool> m_lineIsVisuallyEmptyBeforeCollapsibleContent;
+ bool m_shouldIgnoreTrailingLetterSpacing { false };
};
inline void LineBuilder::CollapsibleContent::reset()
diff --git a/Source/WebCore/layout/inlineformatting/InlineTextItem.h b/Source/WebCore/layout/inlineformatting/InlineTextItem.h
index 2f724a7..ec24114 100644
--- a/Source/WebCore/layout/inlineformatting/InlineTextItem.h
+++ b/Source/WebCore/layout/inlineformatting/InlineTextItem.h
@@ -46,7 +46,7 @@
unsigned length() const { return m_length; }
bool isWhitespace() const { return m_textItemType == TextItemType::Whitespace; }
- bool isCollapsible() const { return isWhitespace() && style().collapseWhiteSpace(); }
+ bool isCollapsible() const { return m_isCollapsible; }
Optional<InlineLayoutUnit> width() const { return m_hasWidth ? makeOptional(m_width) : Optional<InlineLayoutUnit> { }; }
bool isEmptyContent() const;
@@ -80,6 +80,7 @@
m_startOrPosition = start;
m_length = length;
m_hasWidth = !!width;
+ m_isCollapsible = textItemType == TextItemType::Whitespace && inlineBox.style().collapseWhiteSpace();
m_width = width.valueOr(0);
m_textItemType = textItemType;
}
diff --git a/Source/WebCore/layout/inlineformatting/text/TextUtil.cpp b/Source/WebCore/layout/inlineformatting/text/TextUtil.cpp
index 782f5bd..e8db9d7 100644
--- a/Source/WebCore/layout/inlineformatting/text/TextUtil.cpp
+++ b/Source/WebCore/layout/inlineformatting/text/TextUtil.cpp
@@ -128,12 +128,6 @@
return { startPosition, right - startPosition, leftSideWidth };
}
-bool TextUtil::shouldPreserveTrailingWhitespace(const RenderStyle& style)
-{
- auto whitespace = style.whiteSpace();
- return whitespace == WhiteSpace::Pre || whitespace == WhiteSpace::PreWrap || whitespace == WhiteSpace::BreakSpaces;
-}
-
unsigned TextUtil::findNextBreakablePosition(LazyLineBreakIterator& lineBreakIterator, unsigned startPosition, const RenderStyle& style)
{
auto keepAllWordsForCJK = style.wordBreak() == WordBreak::KeepAll;
diff --git a/Source/WebCore/layout/inlineformatting/text/TextUtil.h b/Source/WebCore/layout/inlineformatting/text/TextUtil.h
index 0e1b695..c40e5ef 100644
--- a/Source/WebCore/layout/inlineformatting/text/TextUtil.h
+++ b/Source/WebCore/layout/inlineformatting/text/TextUtil.h
@@ -56,6 +56,12 @@
static InlineLayoutUnit fixedPitchWidth(const StringView&, const RenderStyle&, unsigned from, unsigned to, InlineLayoutUnit contentLogicalLeft);
};
+inline bool TextUtil::shouldPreserveTrailingWhitespace(const RenderStyle& style)
+{
+ auto whitespace = style.whiteSpace();
+ return whitespace == WhiteSpace::Pre || whitespace == WhiteSpace::PreWrap || whitespace == WhiteSpace::BreakSpaces;
+}
+
}
}
#endif