Commit 0efc9daf authored by Yoshifumi Inoue's avatar Yoshifumi Inoue Committed by Commit Bot

Make |HonorEditingBoundaryAtOrAfter()| to work correctly for nested editable

This patch changes |HonorEditingBoundaryAtOrAfter()| to handle nested editable.

Before this patch, |HonorEditingBoundaryAtOrAfter()| returns null position for
editable position anchored by non-editable position.

After this patch, |HonorEditingBoundaryAtOrAfter()| returns the last position in
the highest non-editable ancestor of |anchor|

Note: This patch is a preparation of the patch[1] which changes finding word
boundary in the block instead of inside editing boundary.

Example:
In below HTML, current code finds word boundary in "ABC", but the patch[1]
finds from "abcABCdef".

<div contenteditable>abc<span contenteditable=false>A^BC</span>def</div>
where "^" is starting position to find word boundary.

[1] http://crrev.com/c/737981 Simplify word granularity handling

Change-Id: I1fa702cba0bd48e8eec642c008ddda8fd063a6b8
Reviewed-on: https://chromium-review.googlesource.com/970130
Commit-Queue: Yoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarXiaocheng Hu <xiaochengh@chromium.org>
Reviewed-by: default avatarYoichi Osato <yoichio@chromium.org>
Cr-Commit-Position: refs/heads/master@{#545031}
parent 47080ffd
......@@ -255,11 +255,18 @@ HonorEditingBoundaryAtOrAfterTemplate(
if (HighestEditableRoot(pos.GetPosition()) == highest_root)
return pos;
// Return empty position if this position is non-editable, but |pos| is
// editable.
// TODO(yosin) Move to the next non-editable region.
if (!highest_root)
// Returns the last position in the highest non-editable ancestor of |anchor|.
if (!highest_root) {
const Node* last_non_editable = anchor.ComputeContainerNode();
for (const Node& ancestor : Strategy::AncestorsOf(*last_non_editable)) {
if (HasEditableStyle(ancestor)) {
return PositionWithAffinityTemplate<Strategy>(
PositionTemplate<Strategy>::LastPositionInNode(*last_non_editable));
}
last_non_editable = &ancestor;
}
return PositionWithAffinityTemplate<Strategy>();
}
// Return the next position after |pos| that is in the same editable region
// as this position
......
......@@ -304,8 +304,8 @@ Position PreviousBoundary(const VisiblePosition&, BoundarySearchFunction);
PositionInFlatTree PreviousBoundary(const VisiblePositionInFlatTree&,
BoundarySearchFunction);
PositionWithAffinity HonorEditingBoundaryAtOrAfter(const PositionWithAffinity&,
const Position&);
CORE_EXPORT PositionWithAffinity
HonorEditingBoundaryAtOrAfter(const PositionWithAffinity&, const Position&);
PositionInFlatTreeWithAffinity HonorEditingBoundaryAtOrAfter(
const PositionInFlatTreeWithAffinity&,
......
......@@ -7,6 +7,7 @@
#include "bindings/core/v8/V8BindingForTesting.h"
#include "core/dom/Text.h"
#include "core/editing/PositionWithAffinity.h"
#include "core/editing/SelectionTemplate.h"
#include "core/editing/VisiblePosition.h"
#include "core/editing/testing/EditingTestBase.h"
#include "core/html/forms/TextControlElement.h"
......@@ -222,6 +223,26 @@ TEST_F(VisibleUnitsTest, endOfDocument) {
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, HonorEditingBoundaryAtOrAfterNestedEditable) {
const SelectionInDOMTree& selection = SetSelectionTextToBody(
"<div contenteditable>"
"abc"
"<span contenteditable=\"false\">A^BC</span>"
"d|ef"
"</div>");
const PositionWithAffinity& result = HonorEditingBoundaryAtOrAfter(
PositionWithAffinity(selection.Extent()), selection.Base());
ASSERT_TRUE(result.IsNotNull());
EXPECT_EQ(
"<div contenteditable>"
"abc"
"<span contenteditable=\"false\">ABC|</span>"
"def"
"</div>",
GetCaretTextFromBody(result.GetPosition()));
EXPECT_EQ(TextAffinity::kDownstream, result.Affinity());
}
TEST_F(VisibleUnitsTest, isEndOfEditableOrNonEditableContent) {
const char* body_content =
"<a id=host><b id=one contenteditable>1</b><b id=two>22</b></a>";
......
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