Commit b0b7031e authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

[LayoutNG] Implements Range.getClientRects and getBoundingClientRect

This patch implements Range.getClientRects and getBoundingClientRect
by implemeting LayoutText::AbsoluteQuadsForRange, the underlying
function to compute quads for a range of text.

VisibleUnits and TouchAdjustment are other users of this function.

crbug.com/698038 added some logic to clear the quad vector under
specific condition for legacy, but the logic is a bit complicated.
This patch tries to match to the spec without using the same logic.
There may be a need to tweak the logic a little more, but the new
logic seems to be more interoperable with Edge/Gecko.

Bug: 636993, 755750
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_layout_ng
Change-Id: I5c6323680285a4e03d64109cd5681c788f6a6bbf
Reviewed-on: https://chromium-review.googlesource.com/979732Reviewed-by: default avatarXiaocheng Hu <xiaochengh@chromium.org>
Reviewed-by: default avatarEmil A Eklund <eae@chromium.org>
Commit-Queue: Koji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#546079}
parent 88da69d3
......@@ -3,7 +3,6 @@
# Need support for Range.getClientRects() and Range.getBoundingClientRect()
crbug.com/755750 accessibility/selection-affinity.html [ Failure ]
crbug.com/755750 fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-in-zoom-and-scroll.html [ Failure ]
## Reverse hosting of editable block
crbug.com/707656 editing/input/scroll-viewport-page-up-down.html [ Failure ]
......@@ -243,7 +242,6 @@ crbug.com/591099 editing/selection/paint-hyphen.html [ Failure ]
crbug.com/591099 editing/selection/paragraph-granularity.html [ Failure ]
crbug.com/591099 editing/selection/programmatic-selection-on-mac-is-directionless.html [ Timeout ]
crbug.com/591099 editing/selection/select-bidi-run.html [ Failure ]
crbug.com/714962 editing/selection/select-from-textfield-outwards.html [ Failure ]
crbug.com/591099 editing/selection/select-text-overflow-ellipsis-mixed-in-ltr-2.html [ Failure ]
crbug.com/591099 editing/selection/select-text-overflow-ellipsis-mixed-in-ltr.html [ Failure ]
crbug.com/591099 editing/selection/select-text-overflow-ellipsis-mixed-in-rtl-2.html [ Failure ]
......@@ -685,7 +683,6 @@ crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-vrl-022.x
crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-vrl-024.xht [ Failure ]
crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-vrl-026.xht [ Failure ]
crbug.com/591099 external/wpt/css/css-writing-modes/wm-propagation-body-006.xht [ Failure ]
crbug.com/714962 external/wpt/css/cssom-view/DOMRectList.html [ Failure ]
crbug.com/591099 external/wpt/css/cssom-view/cssom-getClientRects-002.html [ Failure ]
crbug.com/591099 external/wpt/css/cssom-view/elementFromPoint-002.html [ Failure ]
crbug.com/591099 external/wpt/css/cssom-view/elementFromPoint-003.html [ Failure ]
......@@ -1239,13 +1236,7 @@ crbug.com/714962 fast/dom/Element/getClientRects.html [ Failure ]
crbug.com/591099 fast/dom/HTMLMeterElement/meter-boundary-values.html [ Failure ]
crbug.com/591099 fast/dom/HTMLMeterElement/meter-optimums.html [ Failure ]
crbug.com/591099 fast/dom/HTMLProgressElement/progress-bar-value-pseudo-element.html [ Failure ]
crbug.com/714962 fast/dom/Range/collapsed-range-bounding-client-rect.html [ Failure ]
crbug.com/714962 fast/dom/Range/get-bounding-client-rect-empty-and-non-empty.html [ Timeout ]
crbug.com/714962 fast/dom/Range/getBoundingClientRect-getClientRects-relative-to-viewport.html [ Failure ]
crbug.com/714962 fast/dom/Range/getBoundingClientRect-linebreak-character.html [ Failure ]
crbug.com/714962 fast/dom/Range/getBoundingClientRect.html [ Failure ]
crbug.com/714962 fast/dom/Range/getClientRects-character.html [ Failure ]
crbug.com/591099 fast/dom/Range/getClientRects-leading-trailing-whitespaces.html [ Failure ]
crbug.com/591099 fast/dom/Window/property-access-on-cached-window-after-frame-navigated.html [ Failure Timeout ]
crbug.com/591099 fast/dom/Window/window-lookup-precedence.html [ Timeout ]
crbug.com/591099 fast/dom/Window/window-postmessage-clone-deep-array.html [ Failure ]
......@@ -1275,7 +1266,6 @@ crbug.com/591099 fast/encoding/utf-16-little-endian.html [ Failure ]
crbug.com/714962 fast/events/drag-in-frames.html [ Failure ]
crbug.com/714962 fast/events/event-on-culled_inline.html [ Failure ]
crbug.com/591099 fast/events/keyboardevent-getModifierState.html [ Timeout ]
crbug.com/591099 fast/events/menu-key-context-menu-document-pinch-zoom.html [ Failure ]
crbug.com/714962 fast/events/middleClickAutoscroll-latching.html [ Pass Timeout ]
crbug.com/714962 fast/events/mouse-down-on-pseudo-element-remove-crash.html [ Failure Pass ]
crbug.com/591099 fast/events/mouse-event-buttons-attribute.html [ Timeout ]
......@@ -1472,8 +1462,6 @@ crbug.com/591099 fast/scrolling/fractional-scroll-offset-fixed-position-non-comp
crbug.com/591099 fast/scrolling/jquery-rtl-scroll-type.html [ Failure ]
crbug.com/591099 fast/scrolling/scrollable-area-frame-overflow-hidden.html [ Failure ]
crbug.com/591099 fast/scrolling/scrollbar-tickmarks-hittest.html [ Pass ]
crbug.com/714962 fast/scrolling/scrollbar-tickmarks-styled-after-onload.html [ Failure ]
crbug.com/714962 fast/scrolling/scrollbar-tickmarks-styled.html [ Failure ]
crbug.com/591099 fast/selectors/038.html [ Failure ]
crbug.com/591099 fast/selectors/166.html [ Failure ]
crbug.com/591099 fast/selectors/167.html [ Failure ]
......@@ -1701,19 +1689,14 @@ crbug.com/591099 fast/text/emphasis-ellipsis-complextext.html [ Failure ]
crbug.com/591099 fast/text/emphasis-overlap.html [ Failure ]
crbug.com/591099 fast/text/find-kana.html [ Timeout ]
crbug.com/714962 fast/text/get-client-rects-grapheme.html [ Failure ]
crbug.com/714962 fast/text/glyph-reordering.html [ Failure ]
crbug.com/591099 fast/text/hide-atomic-inlines-after-ellipsis.html [ Failure ]
crbug.com/591099 fast/text/international/bidi-linebreak-002.html [ Failure ]
crbug.com/591099 fast/text/international/bidi-linebreak-003.html [ Failure ]
crbug.com/591099 fast/text/international/combining-marks-position.html [ Failure ]
crbug.com/714962 fast/text/international/hindi-whitespace.html [ Failure ]
crbug.com/714962 fast/text/international/iso-8859-8.html [ Failure ]
crbug.com/714962 fast/text/international/rtl-selection-rect-with-fallback.html [ Failure ]
crbug.com/796943 fast/text/international/shape-across-elements-simple.html [ Pass ]
crbug.com/591099 fast/text/international/text-combine-image-test.html [ Failure ]
crbug.com/591099 fast/text/large-text-composed-char.html [ Timeout ]
crbug.com/714962 fast/text/line-break-after-inline-latin1.html [ Failure ]
crbug.com/714962 fast/text/multiglyph-characters.html [ Failure ]
crbug.com/591099 fast/text/place-ellipsis-in-inline-block-adjacent-float-2.html [ Failure ]
crbug.com/591099 fast/text/place-ellipsis-in-inline-block-adjacent-float.html [ Failure ]
crbug.com/591099 fast/text/place-ellipsis-in-inline-blocks-2.html [ Failure ]
......@@ -1745,7 +1728,6 @@ crbug.com/591099 fast/text/selection/selection-hard-linebreak.html [ Failure ]
crbug.com/591099 fast/text/selection/selection-rect-rounding.html [ Failure ]
crbug.com/591099 fast/text/selection/selection-with-inline-padding.html [ Failure ]
crbug.com/714962 fast/text/selection/shaping-selection-rect.html [ Failure ]
crbug.com/714962 fast/text/text-range-bounds.html [ Failure ]
crbug.com/714962 fast/text/transform-text-first-line-capitalize.html [ Failure ]
crbug.com/714962 fast/text/transform-text-first-line-lowercase.html [ Failure ]
crbug.com/714962 fast/text/transform-text-first-line.html [ Failure ]
......@@ -1775,7 +1757,6 @@ crbug.com/591099 fast/writing-mode/english-rl-text.html [ Failure ]
crbug.com/591099 fast/writing-mode/fieldsets.html [ Failure ]
crbug.com/714962 fast/writing-mode/flipped-blocks-hit-test-line-edges.html [ Failure ]
crbug.com/591099 fast/writing-mode/flipped-blocks-inline-map-local-to-container.html [ Failure ]
crbug.com/714962 fast/writing-mode/flipped-blocks-text-map-local-to-container.html [ Failure ]
crbug.com/714962 fast/writing-mode/japanese-lr-selection.html [ Failure ]
crbug.com/714962 fast/writing-mode/japanese-rl-selection.html [ Failure ]
crbug.com/591099 fast/writing-mode/japanese-ruby-vertical-lr.html [ Failure ]
......@@ -1837,10 +1818,7 @@ crbug.com/591099 http/tests/devtools/console/console-viewport-control.js [ Failu
crbug.com/591099 http/tests/devtools/editor/text-editor-block-indent.js [ Pass Timeout ]
crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-1.js [ Timeout ]
crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-2.js [ Timeout ]
crbug.com/714962 http/tests/devtools/editor/text-editor-enter-behaviour.js [ Timeout ]
crbug.com/714962 http/tests/devtools/editor/text-editor-formatter.js [ Timeout ]
crbug.com/714962 http/tests/devtools/editor/text-editor-indent-autodetection.js [ Timeout ]
crbug.com/714962 http/tests/devtools/editor/text-editor-reveal-line.js [ Timeout ]
crbug.com/591099 http/tests/devtools/editor/text-editor-word-jumps.js [ Timeout ]
crbug.com/714962 http/tests/devtools/elements/edit/edit-dom-actions-4.js [ Crash ]
crbug.com/591099 http/tests/devtools/elements/elements-panel-rewrite-href.js [ Failure Pass ]
......
......@@ -450,7 +450,6 @@ crbug.com/714962 virtual/layout_ng/fast/writing-mode/fallback-orientation.html [
crbug.com/714962 virtual/layout_ng/fast/writing-mode/fieldsets.html [ Failure ]
crbug.com/714962 virtual/layout_ng/fast/writing-mode/flipped-blocks-hit-test-line-edges.html [ Failure ]
crbug.com/714962 virtual/layout_ng/fast/writing-mode/flipped-blocks-inline-map-local-to-container.html [ Failure ]
crbug.com/714962 virtual/layout_ng/fast/writing-mode/flipped-blocks-text-map-local-to-container.html [ Failure ]
crbug.com/714962 virtual/layout_ng/fast/writing-mode/japanese-lr-selection.html [ Failure ]
crbug.com/714962 [ Mac Win ] virtual/layout_ng/fast/writing-mode/japanese-lr-text.html [ Failure ]
crbug.com/714962 virtual/layout_ng/fast/writing-mode/japanese-rl-selection.html [ Failure ]
......
......@@ -45,9 +45,11 @@
#include "core/layout/line/EllipsisBox.h"
#include "core/layout/line/GlyphOverflow.h"
#include "core/layout/line/InlineTextBox.h"
#include "core/layout/ng/geometry/ng_logical_rect.h"
#include "core/layout/ng/inline/ng_inline_fragment_traversal.h"
#include "core/layout/ng/inline/ng_inline_node.h"
#include "core/layout/ng/inline/ng_offset_mapping.h"
#include "core/layout/ng/inline/ng_physical_text_fragment.h"
#include "core/layout/ng/layout_ng_block_flow.h"
#include "platform/fonts/CharacterRange.h"
#include "platform/geometry/FloatQuad.h"
......@@ -409,6 +411,48 @@ void LayoutText::AbsoluteQuads(Vector<FloatQuad>& quads,
Quads(quads, kNoClipping, kAbsoluteQuads, mode);
}
bool LayoutText::MapDOMOffsetToTextContentOffset(const NGOffsetMapping& mapping,
unsigned* start,
unsigned* end) const {
DCHECK_LE(*start, *end);
// Adjust |start| to the next non-collapsed offset if |start| is collapsed.
Position start_position =
PositionForCaretOffset(std::min(*start, TextLength()));
Position non_collapsed_start_position =
mapping.StartOfNextNonCollapsedContent(start_position);
// If all characters after |start| are collapsed, adjust to the last
// non-collapsed offset.
if (non_collapsed_start_position.IsNull()) {
non_collapsed_start_position =
mapping.EndOfLastNonCollapsedContent(start_position);
// If all characters are collapsed, return false.
if (non_collapsed_start_position.IsNull())
return false;
}
*start = mapping.GetTextContentOffset(non_collapsed_start_position).value();
// Adjust |end| to the last non-collapsed offset if |end| is collapsed.
Position end_position = PositionForCaretOffset(std::min(*end, TextLength()));
Position non_collpased_end_position =
mapping.EndOfLastNonCollapsedContent(end_position);
if (non_collpased_end_position.IsNull() ||
non_collpased_end_position.OffsetInContainerNode() <=
non_collapsed_start_position.OffsetInContainerNode()) {
// If all characters in the range are collapsed, make |end| = |start|.
*end = *start;
} else {
*end = mapping.GetTextContentOffset(non_collpased_end_position).value();
}
DCHECK_LE(*start, *end);
return true;
}
void LayoutText::AbsoluteQuadsForRange(Vector<FloatQuad>& quads,
unsigned start,
unsigned end) const {
......@@ -424,6 +468,28 @@ void LayoutText::AbsoluteQuadsForRange(Vector<FloatQuad>& quads,
start = std::min(start, static_cast<unsigned>(INT_MAX));
end = std::min(end, static_cast<unsigned>(INT_MAX));
if (auto* mapping = GetNGOffsetMapping()) {
if (!MapDOMOffsetToTextContentOffset(*mapping, &start, &end))
return;
// Find fragments that have text for the specified range.
DCHECK_LE(start, end);
auto fragments = NGPaintFragment::InlineFragmentsFor(this);
for (const NGPaintFragment* fragment : fragments) {
const NGPhysicalTextFragment& text_fragment =
ToNGPhysicalTextFragment(fragment->PhysicalFragment());
if (start > text_fragment.EndOffset() ||
end < text_fragment.StartOffset())
continue;
NGPhysicalOffsetRect rect =
text_fragment.LocalRect(std::max(start, text_fragment.StartOffset()),
std::min(end, text_fragment.EndOffset()));
rect.offset += fragment->InlineOffsetToContainerBox();
quads.push_back(LocalToAbsoluteQuad(rect.ToFloatRect()));
}
return;
}
const unsigned caret_min_offset = static_cast<unsigned>(CaretMinOffset());
const unsigned caret_max_offset = static_cast<unsigned>(CaretMaxOffset());
......
......@@ -265,6 +265,18 @@ class CORE_EXPORT LayoutText : public LayoutObject {
virtual UChar PreviousCharacter() const;
// Returns the NGOffsetMapping object when the current text is laid out with
// LayoutNG.
// Note that the text can be in legacy layout even when LayoutNG is enabled,
// so we can't simply check the RuntimeEnabledFeature.
const NGOffsetMapping* GetNGOffsetMapping() const;
// Map DOM offset to LayoutNG text content offset.
// Returns false if all characters in this LayoutText are collapsed.
bool MapDOMOffsetToTextContentOffset(const NGOffsetMapping&,
unsigned* start,
unsigned* end) const;
protected:
void WillBeDestroyed() override;
......@@ -285,12 +297,6 @@ class CORE_EXPORT LayoutText : public LayoutObject {
void InvalidateDisplayItemClients(PaintInvalidationReason) const override;
// Returns the NGOffsetMapping object when the current text is laid out with
// LayoutNG.
// Note that the text can be in legacy layout even when LayoutNG is enabled,
// so we can't simply check the RuntimeEnabledFeature.
const NGOffsetMapping* GetNGOffsetMapping() const;
bool CanBeSelectionLeafInternal() const final { return true; }
private:
......
......@@ -145,6 +145,61 @@ TEST_F(LayoutTextTest, ContainsOnlyWhitespaceOrNbsp) {
GetBasicText()->ContainsOnlyWhitespaceOrNbsp());
}
struct NGOffsetMappingTestData {
const char* text;
unsigned dom_start;
unsigned dom_end;
bool success;
unsigned text_start;
unsigned text_end;
} offset_mapping_test_data[] = {
{"<div id=target> a b </div>", 0, 1, true, 0, 0},
{"<div id=target> a b </div>", 1, 2, true, 0, 1},
{"<div id=target> a b </div>", 2, 3, true, 1, 2},
{"<div id=target> a b </div>", 2, 4, true, 1, 2},
{"<div id=target> a b </div>", 2, 5, true, 1, 3},
{"<div id=target> a b </div>", 3, 4, true, 2, 2},
{"<div id=target> a b </div>", 3, 5, true, 2, 3},
{"<div id=target> a b </div>", 5, 6, true, 3, 3},
{"<div id=target> a b </div>", 5, 7, true, 3, 3},
{"<div id=target> a b </div>", 6, 7, true, 3, 3},
{"<div>a <span id=target> </span>b</div>", 0, 1, false, 0, 1}};
std::ostream& operator<<(std::ostream& out, NGOffsetMappingTestData data) {
return out << "\"" << data.text << "\" " << data.dom_start << ","
<< data.dom_end << " => " << (data.success ? "true " : "false ")
<< data.text_start << "," << data.text_end;
}
class MapDOMOffsetToTextContentOffset
: public LayoutTextTest,
private ScopedLayoutNGForTest,
public ::testing::WithParamInterface<NGOffsetMappingTestData> {
public:
MapDOMOffsetToTextContentOffset() : ScopedLayoutNGForTest(true) {}
};
INSTANTIATE_TEST_CASE_P(LayoutTextTest,
MapDOMOffsetToTextContentOffset,
::testing::ValuesIn(offset_mapping_test_data));
TEST_P(MapDOMOffsetToTextContentOffset, Basic) {
const auto data = GetParam();
SetBodyInnerHTML(data.text);
LayoutText* layout_text = GetBasicText();
const NGOffsetMapping* mapping = layout_text->GetNGOffsetMapping();
ASSERT_TRUE(mapping);
unsigned start = data.dom_start;
unsigned end = data.dom_end;
bool success =
layout_text->MapDOMOffsetToTextContentOffset(*mapping, &start, &end);
EXPECT_EQ(data.success, success);
if (success) {
EXPECT_EQ(data.text_start, start);
EXPECT_EQ(data.text_end, end);
}
}
TEST_P(ParameterizedLayoutTextTest, CaretMinMaxOffset) {
SetBasicBody("foo");
EXPECT_EQ(0, GetBasicText()->CaretMinOffset());
......
......@@ -4,6 +4,7 @@
#include "core/layout/ng/geometry/ng_physical_offset_rect.h"
#include "platform/geometry/FloatRect.h"
#include "platform/geometry/LayoutRect.h"
#include "platform/wtf/text/WTFString.h"
......@@ -42,6 +43,10 @@ LayoutRect NGPhysicalOffsetRect::ToLayoutRect() const {
return {offset.left, offset.top, size.width, size.height};
}
FloatRect NGPhysicalOffsetRect::ToFloatRect() const {
return {offset.left, offset.top, size.width, size.height};
}
String NGPhysicalOffsetRect::ToString() const {
return String::Format("%s,%s %sx%s", offset.left.ToString().Ascii().data(),
offset.top.ToString().Ascii().data(),
......
......@@ -12,6 +12,7 @@
namespace blink {
class FloatRect;
class LayoutRect;
// NGPhysicalOffsetRect is the position and size of a rect (typically a
......@@ -39,6 +40,7 @@ struct CORE_EXPORT NGPhysicalOffsetRect {
// logical/physical distinctions.
explicit NGPhysicalOffsetRect(const LayoutRect&);
LayoutRect ToLayoutRect() const;
FloatRect ToFloatRect() const;
String ToString() const;
};
......
......@@ -7,6 +7,7 @@
#include "core/dom/Node.h"
#include "core/editing/PositionWithAffinity.h"
#include "core/layout/LayoutTextFragment.h"
#include "core/layout/ng/geometry/ng_logical_rect.h"
#include "core/layout/ng/geometry/ng_physical_offset_rect.h"
#include "core/layout/ng/inline/ng_line_height_metrics.h"
#include "core/layout/ng/inline/ng_offset_mapping.h"
......@@ -14,6 +15,40 @@
namespace blink {
NGPhysicalOffsetRect NGPhysicalTextFragment::LocalRect(
unsigned start_offset,
unsigned end_offset) const {
DCHECK_LE(start_offset, end_offset);
DCHECK_GE(start_offset, start_offset_);
DCHECK_LE(end_offset, end_offset_);
if (UNLIKELY(!shape_result_)) {
DCHECK(IsFlowControl());
DCHECK_EQ(Length(), 1u);
return {{}, Size()};
}
if (UNLIKELY(IsRtl(shape_result_->Direction())))
std::swap(start_offset, end_offset);
LayoutUnit start_position = LayoutUnit::FromFloatFloor(
shape_result_->PositionForOffset(start_offset - start_offset_));
LayoutUnit end_position = LayoutUnit::FromFloatCeil(
shape_result_->PositionForOffset(end_offset - start_offset_));
DCHECK_GE(end_position, start_position);
LayoutUnit inline_size = end_position - start_position;
switch (LineOrientation()) {
case NGLineOrientation::kHorizontal:
return {{start_position, LayoutUnit()}, {inline_size, Size().height}};
case NGLineOrientation::kClockWiseVertical:
return {{LayoutUnit(), start_position}, {Size().width, inline_size}};
case NGLineOrientation::kCounterClockWiseVertical:
return {{LayoutUnit(), Size().height - end_position},
{Size().width, inline_size}};
}
NOTREACHED();
return {};
}
NGPhysicalOffsetRect NGPhysicalTextFragment::SelfVisualRect() const {
if (!shape_result_)
return {};
......
......@@ -105,6 +105,11 @@ class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
return IsHorizontal() ? kAlphabeticBaseline : kIdeographicBaseline;
}
// The layout box of text in (start, end) range in local coordinate.
// Start and end offsets must be between StartOffset() and EndOffset().
NGPhysicalOffsetRect LocalRect(unsigned start_offset,
unsigned end_offset) const;
// The visual bounding box that includes glpyh bounding box and CSS
// properties, in local coordinates.
NGPhysicalOffsetRect SelfVisualRect() const;
......
......@@ -4,6 +4,7 @@
#include "core/layout/ng/inline/ng_physical_text_fragment.h"
#include "core/layout/ng/geometry/ng_logical_rect.h"
#include "core/layout/ng/inline/ng_inline_fragment_traversal.h"
#include "core/layout/ng/ng_layout_test.h"
#include "core/layout/ng/ng_physical_box_fragment.h"
......@@ -36,6 +37,84 @@ class NGPhysicalTextFragmentTest : public NGLayoutTest {
}
};
TEST_F(NGPhysicalTextFragmentTest, LocalRect) {
LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
div {
font: 10px/1 Ahem;
width: 5em;
}
</style>
<div id=container>01234 67890</div>
)HTML");
auto text_fragments = CollectTextFragmentsInContainer("container");
ASSERT_EQ(2u, text_fragments.size());
EXPECT_EQ(NGPhysicalOffsetRect({LayoutUnit(20), LayoutUnit(0)},
{LayoutUnit(20), LayoutUnit(10)}),
text_fragments[1]->LocalRect(8, 10));
}
TEST_F(NGPhysicalTextFragmentTest, LocalRectRTL) {
LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
div {
font: 10px/1 Ahem;
width: 10em;
direction: rtl;
unicode-bidi: bidi-override;
}
</style>
<div id=container>0123456789 123456789</div>
)HTML");
auto text_fragments = CollectTextFragmentsInContainer("container");
ASSERT_EQ(2u, text_fragments.size());
// The 2nd line starts at 12, because the div has a bidi-control.
EXPECT_EQ(12u, text_fragments[1]->StartOffset());
EXPECT_EQ(NGPhysicalOffsetRect({LayoutUnit(50), LayoutUnit(0)},
{LayoutUnit(20), LayoutUnit(10)}),
text_fragments[1]->LocalRect(14, 16));
}
TEST_F(NGPhysicalTextFragmentTest, LocalRectVLR) {
LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
div {
font: 10px/1 Ahem;
height: 5em;
writing-mode: vertical-lr;
}
</style>
<div id=container>01234 67890</div>
)HTML");
auto text_fragments = CollectTextFragmentsInContainer("container");
ASSERT_EQ(2u, text_fragments.size());
EXPECT_EQ(NGPhysicalOffsetRect({LayoutUnit(0), LayoutUnit(20)},
{LayoutUnit(10), LayoutUnit(20)}),
text_fragments[1]->LocalRect(8, 10));
}
TEST_F(NGPhysicalTextFragmentTest, LocalRectVRL) {
LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
div {
font: 10px/1 Ahem;
height: 5em;
writing-mode: vertical-rl;
}
</style>
<div id=container>01234 67890</div>
)HTML");
auto text_fragments = CollectTextFragmentsInContainer("container");
ASSERT_EQ(2u, text_fragments.size());
EXPECT_EQ(NGPhysicalOffsetRect({LayoutUnit(0), LayoutUnit(20)},
{LayoutUnit(10), LayoutUnit(20)}),
text_fragments[1]->LocalRect(8, 10));
}
TEST_F(NGPhysicalTextFragmentTest, NormalTextIsNotAnonymousText) {
SetBodyInnerHTML("<div id=div>text</div>");
......
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