Commit 06cc5abb authored by Xiaocheng Hu's avatar Xiaocheng Hu Committed by Commit Bot

[LayoutNG] Introduce NGPhysicalLineBoxFragment::First/LastLogicalLeaf()

This patch introduces the two helper functions as a preparation for
crrev.com/c/882292, where we need to check if an inline fragment is the
logically first/last leaf in its line to resolve caret position around
line wrap.

Bug: 771398
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_layout_ng
Change-Id: I905ddc8923417da7178f8962db9c01e6fdf24754
Reviewed-on: https://chromium-review.googlesource.com/884381Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#531703}
parent 1fd72230
...@@ -1945,6 +1945,7 @@ jumbo_source_set("unit_tests") { ...@@ -1945,6 +1945,7 @@ jumbo_source_set("unit_tests") {
"layout/ng/inline/ng_inline_node_test.cc", "layout/ng/inline/ng_inline_node_test.cc",
"layout/ng/inline/ng_line_breaker_test.cc", "layout/ng/inline/ng_line_breaker_test.cc",
"layout/ng/inline/ng_offset_mapping_test.cc", "layout/ng/inline/ng_offset_mapping_test.cc",
"layout/ng/inline/ng_physical_line_box_fragment_test.cc",
"layout/ng/inline/ng_physical_text_fragment_test.cc", "layout/ng/inline/ng_physical_text_fragment_test.cc",
"layout/ng/ng_absolute_utils_test.cc", "layout/ng/ng_absolute_utils_test.cc",
"layout/ng/ng_base_layout_algorithm_test.cc", "layout/ng/ng_base_layout_algorithm_test.cc",
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "core/layout/ng/inline/ng_physical_line_box_fragment.h" #include "core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "core/style/ComputedStyle.h"
namespace blink { namespace blink {
NGPhysicalLineBoxFragment::NGPhysicalLineBoxFragment( NGPhysicalLineBoxFragment::NGPhysicalLineBoxFragment(
...@@ -33,4 +35,44 @@ NGPhysicalOffsetRect NGPhysicalLineBoxFragment::VisualRectWithContents() const { ...@@ -33,4 +35,44 @@ NGPhysicalOffsetRect NGPhysicalLineBoxFragment::VisualRectWithContents() const {
return ContentsVisualRect(); return ContentsVisualRect();
} }
const NGPhysicalFragment* NGPhysicalLineBoxFragment::FirstLogicalLeaf() const {
if (Children().IsEmpty())
return nullptr;
// TODO(xiaochengh): This isn't correct for mixed Bidi. Fix it. Besides, we
// should compute and store it during layout.
const TextDirection direction = Style().Direction();
const NGPhysicalFragment* runner = this;
while (runner->IsContainer() && !runner->IsBlockLayoutRoot()) {
const NGPhysicalContainerFragment* runner_as_container =
ToNGPhysicalContainerFragment(runner);
if (runner_as_container->Children().IsEmpty())
break;
runner = direction == TextDirection::kLtr
? runner_as_container->Children().front().get()
: runner_as_container->Children().back().get();
}
DCHECK_NE(runner, this);
return runner;
}
const NGPhysicalFragment* NGPhysicalLineBoxFragment::LastLogicalLeaf() const {
if (Children().IsEmpty())
return nullptr;
// TODO(xiaochengh): This isn't correct for mixed Bidi. Fix it. Besides, we
// should compute and store it during layout.
const TextDirection direction = Style().Direction();
const NGPhysicalFragment* runner = this;
while (runner->IsContainer() && !runner->IsBlockLayoutRoot()) {
const NGPhysicalContainerFragment* runner_as_container =
ToNGPhysicalContainerFragment(runner);
if (runner_as_container->Children().IsEmpty())
break;
runner = direction == TextDirection::kLtr
? runner_as_container->Children().back().get()
: runner_as_container->Children().front().get();
}
DCHECK_NE(runner, this);
return runner;
}
} // namespace blink } // namespace blink
...@@ -31,6 +31,11 @@ class CORE_EXPORT NGPhysicalLineBoxFragment final ...@@ -31,6 +31,11 @@ class CORE_EXPORT NGPhysicalLineBoxFragment final
// VisualRect of itself including contents, in the local coordinate. // VisualRect of itself including contents, in the local coordinate.
NGPhysicalOffsetRect VisualRectWithContents() const; NGPhysicalOffsetRect VisualRectWithContents() const;
// Returns the first/last leaf fragment in the line in logical order. Returns
// nullptr if the line box is empty.
const NGPhysicalFragment* FirstLogicalLeaf() const;
const NGPhysicalFragment* LastLogicalLeaf() const;
scoped_refptr<NGPhysicalFragment> CloneWithoutOffset() const { scoped_refptr<NGPhysicalFragment> CloneWithoutOffset() const {
Vector<scoped_refptr<NGPhysicalFragment>> children_copy(children_); Vector<scoped_refptr<NGPhysicalFragment>> children_copy(children_);
return base::AdoptRef(new NGPhysicalLineBoxFragment( return base::AdoptRef(new NGPhysicalLineBoxFragment(
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "core/layout/ng/inline/ng_inline_fragment_traversal.h"
#include "core/layout/ng/inline/ng_physical_text_fragment.h"
#include "core/layout/ng/ng_layout_test.h"
#include "core/layout/ng/ng_physical_box_fragment.h"
namespace blink {
class NGPhysicalLineBoxFragmentTest
: public NGLayoutTest,
private ScopedLayoutNGPaintFragmentsForTest {
public:
NGPhysicalLineBoxFragmentTest()
: NGLayoutTest(), ScopedLayoutNGPaintFragmentsForTest(true) {}
protected:
const NGPhysicalLineBoxFragment* GetLineBox() const {
const Element* container = GetElementById("root");
DCHECK(container);
const LayoutObject* layout_object = container->GetLayoutObject();
DCHECK(layout_object) << container;
DCHECK(layout_object->IsLayoutBlockFlow()) << container;
const NGPhysicalBoxFragment* root_fragment =
ToLayoutBlockFlow(layout_object)->CurrentFragment();
DCHECK(root_fragment) << container;
for (const auto& child :
NGInlineFragmentTraversal::DescendantsOf(*root_fragment)) {
if (child.fragment->IsLineBox())
return ToNGPhysicalLineBoxFragment(child.fragment.get());
}
NOTREACHED();
return nullptr;
}
};
#define EXPECT_TEXT_FRAGMENT(text, fragment) \
{ \
EXPECT_TRUE(fragment); \
EXPECT_TRUE(fragment->IsText()); \
EXPECT_EQ(text, ToNGPhysicalTextFragment(fragment)->Text().ToString()); \
}
#define EXPECT_BOX_FRAGMENT(id, fragment) \
{ \
EXPECT_TRUE(fragment); \
EXPECT_TRUE(fragment->IsBox()); \
EXPECT_TRUE(fragment->GetNode()); \
EXPECT_EQ(GetElementById(id), fragment->GetNode()); \
}
TEST_F(NGPhysicalLineBoxFragmentTest, FirstLastLogicalLeafInSimpleText) {
SetBodyInnerHTML(
"<div id=root>"
"<span>foo</span>"
"<span>bar</span>"
"</div>");
EXPECT_TEXT_FRAGMENT("foo", GetLineBox()->FirstLogicalLeaf());
EXPECT_TEXT_FRAGMENT("bar", GetLineBox()->LastLogicalLeaf());
}
TEST_F(NGPhysicalLineBoxFragmentTest, FirstLastLogicalLeafInRtlText) {
SetBodyInnerHTML(
"<bdo id=root dir=rtl style='display: block'>"
"<span>foo</span>"
"<span>bar</span>"
"</bdo>");
EXPECT_TEXT_FRAGMENT("foo", GetLineBox()->FirstLogicalLeaf());
EXPECT_TEXT_FRAGMENT("bar", GetLineBox()->LastLogicalLeaf());
}
TEST_F(NGPhysicalLineBoxFragmentTest,
FirstLastLogicalLeafInTextAsDeepDescendants) {
SetBodyInnerHTML(
"<style>span {border: 1px solid black}</style>"
"<div id=root>"
"<span><span>f</span>oo</span>"
"<span>ba<span>r</span></span>"
"</div>");
EXPECT_TEXT_FRAGMENT("f", GetLineBox()->FirstLogicalLeaf());
EXPECT_TEXT_FRAGMENT("r", GetLineBox()->LastLogicalLeaf());
}
TEST_F(NGPhysicalLineBoxFragmentTest, FirstLastLogicalLeafWithInlineBlock) {
SetBodyInnerHTML(
"<div id=root>"
"<span id=foo style='display: inline-block'>foo</span>"
"bar"
"<span id=baz style='display: inline-block'>baz</span>"
"</div>");
EXPECT_BOX_FRAGMENT("foo", GetLineBox()->FirstLogicalLeaf());
EXPECT_BOX_FRAGMENT("baz", GetLineBox()->LastLogicalLeaf());
}
TEST_F(NGPhysicalLineBoxFragmentTest, FirstLastLogicalLeafWithImages) {
SetBodyInnerHTML("<div id=root><img id=img1>foo<img id=img2></div>");
EXPECT_BOX_FRAGMENT("img1", GetLineBox()->FirstLogicalLeaf());
EXPECT_BOX_FRAGMENT("img2", GetLineBox()->LastLogicalLeaf());
}
} // namespace blink
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