Commit 8846ab0a authored by Yoshifumi Inoue's avatar Yoshifumi Inoue Committed by Commit Bot

Make LayoutBlockFlowRareData to hold NGOffsetMapping for legacy layout

This patch makes |LayoutBlockFlowRareData| to hold |NGOffsetMapping| for legacy
layout to make |NGInlineNode::GetOffsetMapping()| can use |NGOffsetMapping|
once it is computed until next layout for making repeated call of
|Element#innerText| faster.

Before this patch, |NGOffsetMapping| for legacy layout tree is hold by callers
to avoid computing |NGOffsetMapping| in same |LayoutBlockFlow|.

However, this simple cache doesn't work for |Element#innerText| when it is
called for each element:

document.body.innerHTML = '<span>a</span>'.repeat(3000);
[...document.getElementByTagName('*')].forEach(e => e.innerText);

Before this patch, above code fragment takes 4000ms, after this patch it takes
40ms on my local machine.

This patch also movs |LayoutBlockFlowRareData| constructor to ".cc" file to
avoid including "ng_offset_mapping.h" to instantiate
|std::unique_ptr<NGOffsetMapping| in various places.


Note: Following patch[1] will get rid of redundant parameter from
|NGInlineNode::GetOffsetMapping()|.

[1] http://crrev.com/c/1488400 Get rid of redundant parameter from
NGInlineNode::GetOffsetMapping()

Bug: 935237
Change-Id: I5990f53632b06e721cc17eca0c80aea8aac36675
Reviewed-on: https://chromium-review.googlesource.com/c/1488479
Commit-Queue: Yoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Auto-Submit: Yoshifumi Inoue <yosin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#636384}
parent 6c85b61a
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#include "third_party/blink/renderer/core/layout/line/line_width.h" #include "third_party/blink/renderer/core/layout/line/line_width.h"
#include "third_party/blink/renderer/core/layout/logical_values.h" #include "third_party/blink/renderer/core/layout/logical_values.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h" #include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
#include "third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h" #include "third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h"
...@@ -446,6 +447,9 @@ void LayoutBlockFlow::UpdateBlockLayout(bool relayout_children) { ...@@ -446,6 +447,9 @@ void LayoutBlockFlow::UpdateBlockLayout(bool relayout_children) {
if (RuntimeEnabledFeatures::TrackLayoutPassesPerBlockEnabled()) if (RuntimeEnabledFeatures::TrackLayoutPassesPerBlockEnabled())
IncrementLayoutPassCount(); IncrementLayoutPassCount();
if (rare_data_)
ClearOffsetMapping();
if (!relayout_children && SimplifiedLayout()) if (!relayout_children && SimplifiedLayout())
return; return;
...@@ -4906,4 +4910,37 @@ int LayoutBlockFlow::GetLayoutPassCountForTesting() { ...@@ -4906,4 +4910,37 @@ int LayoutBlockFlow::GetLayoutPassCountForTesting() {
return GetLayoutPassCountMap().find(this)->value; return GetLayoutPassCountMap().find(this)->value;
} }
LayoutBlockFlow::LayoutBlockFlowRareData::LayoutBlockFlowRareData(
const LayoutBlockFlow* block)
: margins_(PositiveMarginBeforeDefault(block),
NegativeMarginBeforeDefault(block),
PositiveMarginAfterDefault(block),
NegativeMarginAfterDefault(block)),
break_before_(static_cast<unsigned>(EBreakBetween::kAuto)),
break_after_(static_cast<unsigned>(EBreakBetween::kAuto)),
line_break_to_avoid_widow_(-1),
did_break_at_line_to_avoid_widow_(false),
discard_margin_before_(false),
discard_margin_after_(false) {}
LayoutBlockFlow::LayoutBlockFlowRareData::~LayoutBlockFlowRareData() = default;
void LayoutBlockFlow::ClearOffsetMapping() {
DCHECK(!IsLayoutNGObject());
DCHECK(rare_data_);
rare_data_->offset_mapping_.reset();
}
const NGOffsetMapping* LayoutBlockFlow::GetOffsetMapping() const {
DCHECK(!IsLayoutNGObject());
return rare_data_ ? rare_data_->offset_mapping_.get() : nullptr;
}
void LayoutBlockFlow::SetOffsetMapping(
std::unique_ptr<NGOffsetMapping> offset_mapping) {
DCHECK(!IsLayoutNGObject());
DCHECK(offset_mapping);
EnsureRareData().offset_mapping_ = std::move(offset_mapping);
}
} // namespace blink } // namespace blink
...@@ -63,6 +63,7 @@ class NGBlockBreakToken; ...@@ -63,6 +63,7 @@ class NGBlockBreakToken;
class NGBreakToken; class NGBreakToken;
class NGConstraintSpace; class NGConstraintSpace;
class NGLayoutResult; class NGLayoutResult;
class NGOffsetMapping;
class NGPaintFragment; class NGPaintFragment;
class NGPhysicalFragment; class NGPhysicalFragment;
...@@ -754,18 +755,8 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock { ...@@ -754,18 +755,8 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
USING_FAST_MALLOC(LayoutBlockFlowRareData); USING_FAST_MALLOC(LayoutBlockFlowRareData);
public: public:
LayoutBlockFlowRareData(const LayoutBlockFlow* block) explicit LayoutBlockFlowRareData(const LayoutBlockFlow* block);
: margins_(PositiveMarginBeforeDefault(block), ~LayoutBlockFlowRareData();
NegativeMarginBeforeDefault(block),
PositiveMarginAfterDefault(block),
NegativeMarginAfterDefault(block)),
multi_column_flow_thread_(nullptr),
break_before_(static_cast<unsigned>(EBreakBetween::kAuto)),
break_after_(static_cast<unsigned>(EBreakBetween::kAuto)),
line_break_to_avoid_widow_(-1),
did_break_at_line_to_avoid_widow_(false),
discard_margin_before_(false),
discard_margin_after_(false) {}
static LayoutUnit PositiveMarginBeforeDefault( static LayoutUnit PositiveMarginBeforeDefault(
const LayoutBlockFlow* block) { const LayoutBlockFlow* block) {
...@@ -787,7 +778,13 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock { ...@@ -787,7 +778,13 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
LayoutUnit first_forced_break_offset_; LayoutUnit first_forced_break_offset_;
LayoutMultiColumnFlowThread* multi_column_flow_thread_; LayoutMultiColumnFlowThread* multi_column_flow_thread_ = nullptr;
// |offset_mapping_| is used only for legacy layout tree for caching offset
// mapping for |NGInlineNode::GetOffsetMapping()|.
// TODO(yosin): Once we have no legacy support, we should get rid of
// |offset_mapping_| here.
std::unique_ptr<NGOffsetMapping> offset_mapping_;
unsigned break_before_ : 4; unsigned break_before_ : 4;
unsigned break_after_ : 4; unsigned break_after_ : 4;
...@@ -798,6 +795,10 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock { ...@@ -798,6 +795,10 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
DISALLOW_COPY_AND_ASSIGN(LayoutBlockFlowRareData); DISALLOW_COPY_AND_ASSIGN(LayoutBlockFlowRareData);
}; };
void ClearOffsetMapping();
const NGOffsetMapping* GetOffsetMapping() const;
void SetOffsetMapping(std::unique_ptr<NGOffsetMapping>);
const FloatingObjects* GetFloatingObjects() const { const FloatingObjects* GetFloatingObjects() const {
return floating_objects_.get(); return floating_objects_.get();
} }
......
...@@ -466,22 +466,20 @@ const NGOffsetMapping* NGInlineNode::GetOffsetMapping( ...@@ -466,22 +466,20 @@ const NGOffsetMapping* NGInlineNode::GetOffsetMapping(
// If |layout_block_flow| is LayoutNG, compute from |NGInlineNode|. // If |layout_block_flow| is LayoutNG, compute from |NGInlineNode|.
if (layout_block_flow->IsLayoutNGMixin()) { if (layout_block_flow->IsLayoutNGMixin()) {
NGInlineNode node(layout_block_flow); NGInlineNode node(layout_block_flow);
if (node.IsPrepareLayoutFinished()) CHECK(node.IsPrepareLayoutFinished());
return node.ComputeOffsetMappingIfNeeded(); return node.ComputeOffsetMappingIfNeeded();
// When this is not laid out yet, compute each time it is requested.
// TODO(kojii): We could still keep the result for later uses but it would
// add more states. Reconsider if this turned out to be needed.
} }
// If this is not LayoutNG, compute the offset mapping and store in |storage|. // If this is not LayoutNG, compute the offset mapping and store into
// The caller is responsible to keep |storage| for the life cycle. // |LayoutBlockFlowRateData|.
if (const NGOffsetMapping* mapping = layout_block_flow->GetOffsetMapping())
return mapping;
DCHECK(storage); DCHECK(storage);
NGInlineNodeData data; NGInlineNodeData data;
ComputeOffsetMapping(layout_block_flow, &data); ComputeOffsetMapping(layout_block_flow, &data);
*storage = std::move(data.offset_mapping); NGOffsetMapping* const mapping = data.offset_mapping.get();
DCHECK(*storage); layout_block_flow->SetOffsetMapping(std::move(data.offset_mapping));
return storage->get(); return mapping;
} }
// Depth-first-scan of all LayoutInline and LayoutText nodes that make up this // Depth-first-scan of all LayoutInline and LayoutText nodes that make up this
......
...@@ -84,6 +84,8 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode { ...@@ -84,6 +84,8 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
// Otherwise, this function computes |NGOffsetMapping| and store in |storage| // Otherwise, this function computes |NGOffsetMapping| and store in |storage|
// as well as returning the pointer. The caller is responsible for keeping // as well as returning the pointer. The caller is responsible for keeping
// |storage| for the life cycle of the returned |NGOffsetMapping|. // |storage| for the life cycle of the returned |NGOffsetMapping|.
// TODO(yosin): We should get rid of |storage| parameter, since it is no
// longer used.
static const NGOffsetMapping* GetOffsetMapping( static const NGOffsetMapping* GetOffsetMapping(
LayoutBlockFlow* layout_block_flow, LayoutBlockFlow* layout_block_flow,
std::unique_ptr<NGOffsetMapping>* storage); std::unique_ptr<NGOffsetMapping>* storage);
......
...@@ -1185,7 +1185,6 @@ TEST_P(NGOffsetMappingGetterTest, Get) { ...@@ -1185,7 +1185,6 @@ TEST_P(NGOffsetMappingGetterTest, Get) {
const NGOffsetMapping* mapping = const NGOffsetMapping* mapping =
NGInlineNode::GetOffsetMapping(layout_block_flow, &storage); NGInlineNode::GetOffsetMapping(layout_block_flow, &storage);
EXPECT_TRUE(mapping); EXPECT_TRUE(mapping);
EXPECT_EQ(!storage, GetParam()); // |storage| is used only for legacy.
const String& text_content = mapping->GetText(); const String& text_content = mapping->GetText();
EXPECT_EQ(text_content, "Whitespaces in this text should be collapsed."); EXPECT_EQ(text_content, "Whitespaces in this text should be collapsed.");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment