| Index: third_party/WebKit/Source/core/editing/VisibleUnits.cpp
|
| diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
|
| index 22bac6ebd7a4563ea75306633bc388285b8834c3..c4a7f761376bbac09d0268e03d8ca26ab10c4a1a 100644
|
| --- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
|
| +++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
|
| @@ -199,7 +199,7 @@ static PositionWithAffinityTemplate<Strategy> HonorEditingBoundaryAtOrBefore(
|
| }
|
|
|
| template <typename Strategy>
|
| -static VisiblePositionTemplate<Strategy> HonorEditingBoundaryAtOrBefore(
|
| +VisiblePositionTemplate<Strategy> HonorEditingBoundaryAtOrBeforeAlgorithm(
|
| const VisiblePositionTemplate<Strategy>& pos,
|
| const PositionTemplate<Strategy>& anchor) {
|
| DCHECK(pos.IsValid()) << pos;
|
| @@ -207,6 +207,18 @@ static VisiblePositionTemplate<Strategy> HonorEditingBoundaryAtOrBefore(
|
| HonorEditingBoundaryAtOrBefore(pos.ToPositionWithAffinity(), anchor));
|
| }
|
|
|
| +VisiblePosition HonorEditingBoundaryAtOrBefore(
|
| + const VisiblePosition& visiblePosition,
|
| + const Position& anchor) {
|
| + return HonorEditingBoundaryAtOrBeforeAlgorithm(visiblePosition, anchor);
|
| +}
|
| +
|
| +VisiblePositionInFlatTree HonorEditingBoundaryAtOrBefore(
|
| + const VisiblePositionInFlatTree& visiblePosition,
|
| + const PositionInFlatTree& anchor) {
|
| + return HonorEditingBoundaryAtOrBeforeAlgorithm(visiblePosition, anchor);
|
| +}
|
| +
|
| template <typename Strategy>
|
| static VisiblePositionTemplate<Strategy> HonorEditingBoundaryAtOrAfter(
|
| const VisiblePositionTemplate<Strategy>& pos,
|
| @@ -317,7 +329,7 @@ static Node* NextLeafWithSameEditability(
|
| }
|
|
|
| // FIXME: consolidate with code in previousLinePosition.
|
| -static Position PreviousRootInlineBoxCandidatePosition(
|
| +Position PreviousRootInlineBoxCandidatePosition(
|
| Node* node,
|
| const VisiblePosition& visible_position,
|
| EditableType editable_type) {
|
| @@ -353,7 +365,7 @@ static Position PreviousRootInlineBoxCandidatePosition(
|
| return Position();
|
| }
|
|
|
| -static Position NextRootInlineBoxCandidatePosition(
|
| +Position NextRootInlineBoxCandidatePosition(
|
| Node* node,
|
| const VisiblePosition& visible_position,
|
| EditableType editable_type) {
|
| @@ -383,396 +395,6 @@ static Position NextRootInlineBoxCandidatePosition(
|
| return Position();
|
| }
|
|
|
| -class CachedLogicallyOrderedLeafBoxes {
|
| - public:
|
| - CachedLogicallyOrderedLeafBoxes();
|
| -
|
| - const InlineTextBox* PreviousTextBox(const RootInlineBox*,
|
| - const InlineTextBox*);
|
| - const InlineTextBox* NextTextBox(const RootInlineBox*, const InlineTextBox*);
|
| -
|
| - size_t size() const { return leaf_boxes_.size(); }
|
| - const InlineBox* FirstBox() const { return leaf_boxes_[0]; }
|
| -
|
| - private:
|
| - const Vector<InlineBox*>& CollectBoxes(const RootInlineBox*);
|
| - int BoxIndexInLeaves(const InlineTextBox*) const;
|
| -
|
| - const RootInlineBox* root_inline_box_;
|
| - Vector<InlineBox*> leaf_boxes_;
|
| -};
|
| -
|
| -CachedLogicallyOrderedLeafBoxes::CachedLogicallyOrderedLeafBoxes()
|
| - : root_inline_box_(0) {}
|
| -
|
| -const InlineTextBox* CachedLogicallyOrderedLeafBoxes::PreviousTextBox(
|
| - const RootInlineBox* root,
|
| - const InlineTextBox* box) {
|
| - if (!root)
|
| - return 0;
|
| -
|
| - CollectBoxes(root);
|
| -
|
| - // If box is null, root is box's previous RootInlineBox, and previousBox is
|
| - // the last logical box in root.
|
| - int box_index = leaf_boxes_.size() - 1;
|
| - if (box)
|
| - box_index = BoxIndexInLeaves(box) - 1;
|
| -
|
| - for (int i = box_index; i >= 0; --i) {
|
| - if (leaf_boxes_[i]->IsInlineTextBox())
|
| - return ToInlineTextBox(leaf_boxes_[i]);
|
| - }
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -const InlineTextBox* CachedLogicallyOrderedLeafBoxes::NextTextBox(
|
| - const RootInlineBox* root,
|
| - const InlineTextBox* box) {
|
| - if (!root)
|
| - return 0;
|
| -
|
| - CollectBoxes(root);
|
| -
|
| - // If box is null, root is box's next RootInlineBox, and nextBox is the first
|
| - // logical box in root. Otherwise, root is box's RootInlineBox, and nextBox is
|
| - // the next logical box in the same line.
|
| - size_t next_box_index = 0;
|
| - if (box)
|
| - next_box_index = BoxIndexInLeaves(box) + 1;
|
| -
|
| - for (size_t i = next_box_index; i < leaf_boxes_.size(); ++i) {
|
| - if (leaf_boxes_[i]->IsInlineTextBox())
|
| - return ToInlineTextBox(leaf_boxes_[i]);
|
| - }
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -const Vector<InlineBox*>& CachedLogicallyOrderedLeafBoxes::CollectBoxes(
|
| - const RootInlineBox* root) {
|
| - if (root_inline_box_ != root) {
|
| - root_inline_box_ = root;
|
| - leaf_boxes_.clear();
|
| - root->CollectLeafBoxesInLogicalOrder(leaf_boxes_);
|
| - }
|
| - return leaf_boxes_;
|
| -}
|
| -
|
| -int CachedLogicallyOrderedLeafBoxes::BoxIndexInLeaves(
|
| - const InlineTextBox* box) const {
|
| - for (size_t i = 0; i < leaf_boxes_.size(); ++i) {
|
| - if (box == leaf_boxes_[i])
|
| - return i;
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -static const InlineTextBox* LogicallyPreviousBox(
|
| - const VisiblePosition& visible_position,
|
| - const InlineTextBox* text_box,
|
| - bool& previous_box_in_different_block,
|
| - CachedLogicallyOrderedLeafBoxes& leaf_boxes) {
|
| - DCHECK(visible_position.IsValid()) << visible_position;
|
| - const InlineBox* start_box = text_box;
|
| -
|
| - const InlineTextBox* previous_box =
|
| - leaf_boxes.PreviousTextBox(&start_box->Root(), text_box);
|
| - if (previous_box)
|
| - return previous_box;
|
| -
|
| - previous_box = leaf_boxes.PreviousTextBox(start_box->Root().PrevRootBox(), 0);
|
| - if (previous_box)
|
| - return previous_box;
|
| -
|
| - while (1) {
|
| - Node* start_node = start_box->GetLineLayoutItem().NonPseudoNode();
|
| - if (!start_node)
|
| - break;
|
| -
|
| - Position position = PreviousRootInlineBoxCandidatePosition(
|
| - start_node, visible_position, kContentIsEditable);
|
| - if (position.IsNull())
|
| - break;
|
| -
|
| - RenderedPosition rendered_position(position, TextAffinity::kDownstream);
|
| - RootInlineBox* previous_root = rendered_position.RootBox();
|
| - if (!previous_root)
|
| - break;
|
| -
|
| - previous_box = leaf_boxes.PreviousTextBox(previous_root, 0);
|
| - if (previous_box) {
|
| - previous_box_in_different_block = true;
|
| - return previous_box;
|
| - }
|
| -
|
| - if (!leaf_boxes.size())
|
| - break;
|
| - start_box = leaf_boxes.FirstBox();
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -static const InlineTextBox* LogicallyNextBox(
|
| - const VisiblePosition& visible_position,
|
| - const InlineTextBox* text_box,
|
| - bool& next_box_in_different_block,
|
| - CachedLogicallyOrderedLeafBoxes& leaf_boxes) {
|
| - DCHECK(visible_position.IsValid()) << visible_position;
|
| - const InlineBox* start_box = text_box;
|
| -
|
| - const InlineTextBox* next_box =
|
| - leaf_boxes.NextTextBox(&start_box->Root(), text_box);
|
| - if (next_box)
|
| - return next_box;
|
| -
|
| - next_box = leaf_boxes.NextTextBox(start_box->Root().NextRootBox(), 0);
|
| - if (next_box)
|
| - return next_box;
|
| -
|
| - while (1) {
|
| - Node* start_node = start_box->GetLineLayoutItem().NonPseudoNode();
|
| - if (!start_node)
|
| - break;
|
| -
|
| - Position position = NextRootInlineBoxCandidatePosition(
|
| - start_node, visible_position, kContentIsEditable);
|
| - if (position.IsNull())
|
| - break;
|
| -
|
| - RenderedPosition rendered_position(position, TextAffinity::kDownstream);
|
| - RootInlineBox* next_root = rendered_position.RootBox();
|
| - if (!next_root)
|
| - break;
|
| -
|
| - next_box = leaf_boxes.NextTextBox(next_root, 0);
|
| - if (next_box) {
|
| - next_box_in_different_block = true;
|
| - return next_box;
|
| - }
|
| -
|
| - if (!leaf_boxes.size())
|
| - break;
|
| - start_box = leaf_boxes.FirstBox();
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -static TextBreakIterator* WordBreakIteratorForMinOffsetBoundary(
|
| - const VisiblePosition& visible_position,
|
| - const InlineTextBox* text_box,
|
| - int& previous_box_length,
|
| - bool& previous_box_in_different_block,
|
| - Vector<UChar, 1024>& string,
|
| - CachedLogicallyOrderedLeafBoxes& leaf_boxes) {
|
| - DCHECK(visible_position.IsValid()) << visible_position;
|
| - previous_box_in_different_block = false;
|
| -
|
| - // FIXME: Handle the case when we don't have an inline text box.
|
| - const InlineTextBox* previous_box = LogicallyPreviousBox(
|
| - visible_position, text_box, previous_box_in_different_block, leaf_boxes);
|
| -
|
| - int len = 0;
|
| - string.clear();
|
| - if (previous_box) {
|
| - previous_box_length = previous_box->Len();
|
| - previous_box->GetLineLayoutItem().GetText().AppendTo(
|
| - string, previous_box->Start(), previous_box_length);
|
| - len += previous_box_length;
|
| - }
|
| - text_box->GetLineLayoutItem().GetText().AppendTo(string, text_box->Start(),
|
| - text_box->Len());
|
| - len += text_box->Len();
|
| -
|
| - return WordBreakIterator(string.data(), len);
|
| -}
|
| -
|
| -static TextBreakIterator* WordBreakIteratorForMaxOffsetBoundary(
|
| - const VisiblePosition& visible_position,
|
| - const InlineTextBox* text_box,
|
| - bool& next_box_in_different_block,
|
| - Vector<UChar, 1024>& string,
|
| - CachedLogicallyOrderedLeafBoxes& leaf_boxes) {
|
| - DCHECK(visible_position.IsValid()) << visible_position;
|
| - next_box_in_different_block = false;
|
| -
|
| - // FIXME: Handle the case when we don't have an inline text box.
|
| - const InlineTextBox* next_box = LogicallyNextBox(
|
| - visible_position, text_box, next_box_in_different_block, leaf_boxes);
|
| -
|
| - int len = 0;
|
| - string.clear();
|
| - text_box->GetLineLayoutItem().GetText().AppendTo(string, text_box->Start(),
|
| - text_box->Len());
|
| - len += text_box->Len();
|
| - if (next_box) {
|
| - next_box->GetLineLayoutItem().GetText().AppendTo(string, next_box->Start(),
|
| - next_box->Len());
|
| - len += next_box->Len();
|
| - }
|
| -
|
| - return WordBreakIterator(string.data(), len);
|
| -}
|
| -
|
| -static bool IsLogicalStartOfWord(TextBreakIterator* iter,
|
| - int position,
|
| - bool hard_line_break) {
|
| - bool boundary = hard_line_break ? true : iter->isBoundary(position);
|
| - if (!boundary)
|
| - return false;
|
| -
|
| - iter->following(position);
|
| - // isWordTextBreak returns true after moving across a word and false after
|
| - // moving across a punctuation/space.
|
| - return IsWordTextBreak(iter);
|
| -}
|
| -
|
| -static bool IslogicalEndOfWord(TextBreakIterator* iter,
|
| - int position,
|
| - bool hard_line_break) {
|
| - bool boundary = iter->isBoundary(position);
|
| - return (hard_line_break || boundary) && IsWordTextBreak(iter);
|
| -}
|
| -
|
| -enum CursorMovementDirection { kMoveLeft, kMoveRight };
|
| -
|
| -static VisiblePosition VisualWordPosition(
|
| - const VisiblePosition& visible_position,
|
| - CursorMovementDirection direction,
|
| - bool skips_space_when_moving_right) {
|
| - DCHECK(visible_position.IsValid()) << visible_position;
|
| - if (visible_position.IsNull())
|
| - return VisiblePosition();
|
| -
|
| - TextDirection block_direction =
|
| - DirectionOfEnclosingBlock(visible_position.DeepEquivalent());
|
| - InlineBox* previously_visited_box = 0;
|
| - VisiblePosition current = visible_position;
|
| - TextBreakIterator* iter = 0;
|
| -
|
| - CachedLogicallyOrderedLeafBoxes leaf_boxes;
|
| - Vector<UChar, 1024> string;
|
| -
|
| - while (1) {
|
| - VisiblePosition adjacent_character_position = direction == kMoveRight
|
| - ? RightPositionOf(current)
|
| - : LeftPositionOf(current);
|
| - if (adjacent_character_position.DeepEquivalent() ==
|
| - current.DeepEquivalent() ||
|
| - adjacent_character_position.IsNull())
|
| - return VisiblePosition();
|
| -
|
| - InlineBoxPosition box_position = ComputeInlineBoxPosition(
|
| - adjacent_character_position.DeepEquivalent(), TextAffinity::kUpstream);
|
| - InlineBox* box = box_position.inline_box;
|
| - int offset_in_box = box_position.offset_in_box;
|
| -
|
| - if (!box)
|
| - break;
|
| - if (!box->IsInlineTextBox()) {
|
| - current = adjacent_character_position;
|
| - continue;
|
| - }
|
| -
|
| - InlineTextBox* text_box = ToInlineTextBox(box);
|
| - int previous_box_length = 0;
|
| - bool previous_box_in_different_block = false;
|
| - bool next_box_in_different_block = false;
|
| - bool moving_into_new_box = previously_visited_box != box;
|
| -
|
| - if (offset_in_box == box->CaretMinOffset()) {
|
| - iter = WordBreakIteratorForMinOffsetBoundary(
|
| - visible_position, text_box, previous_box_length,
|
| - previous_box_in_different_block, string, leaf_boxes);
|
| - } else if (offset_in_box == box->CaretMaxOffset()) {
|
| - iter = WordBreakIteratorForMaxOffsetBoundary(visible_position, text_box,
|
| - next_box_in_different_block,
|
| - string, leaf_boxes);
|
| - } else if (moving_into_new_box) {
|
| - iter = WordBreakIterator(text_box->GetLineLayoutItem().GetText(),
|
| - text_box->Start(), text_box->Len());
|
| - previously_visited_box = box;
|
| - }
|
| -
|
| - if (!iter)
|
| - break;
|
| -
|
| - iter->first();
|
| - int offset_in_iterator =
|
| - offset_in_box - text_box->Start() + previous_box_length;
|
| -
|
| - bool is_word_break;
|
| - bool box_has_same_directionality_as_block =
|
| - box->Direction() == block_direction;
|
| - bool moving_backward =
|
| - (direction == kMoveLeft && box->Direction() == TextDirection::kLtr) ||
|
| - (direction == kMoveRight && box->Direction() == TextDirection::kRtl);
|
| - if ((skips_space_when_moving_right &&
|
| - box_has_same_directionality_as_block) ||
|
| - (!skips_space_when_moving_right && moving_backward)) {
|
| - bool logical_start_in_layout_object =
|
| - offset_in_box == static_cast<int>(text_box->Start()) &&
|
| - previous_box_in_different_block;
|
| - is_word_break = IsLogicalStartOfWord(iter, offset_in_iterator,
|
| - logical_start_in_layout_object);
|
| - } else {
|
| - bool logical_end_in_layout_object =
|
| - offset_in_box ==
|
| - static_cast<int>(text_box->Start() + text_box->Len()) &&
|
| - next_box_in_different_block;
|
| - is_word_break = IslogicalEndOfWord(iter, offset_in_iterator,
|
| - logical_end_in_layout_object);
|
| - }
|
| -
|
| - if (is_word_break)
|
| - return adjacent_character_position;
|
| -
|
| - current = adjacent_character_position;
|
| - }
|
| - return VisiblePosition();
|
| -}
|
| -
|
| -VisiblePosition LeftWordPosition(const VisiblePosition& visible_position,
|
| - bool skips_space_when_moving_right) {
|
| - DCHECK(visible_position.IsValid()) << visible_position;
|
| - VisiblePosition left_word_break = VisualWordPosition(
|
| - visible_position, kMoveLeft, skips_space_when_moving_right);
|
| - left_word_break = HonorEditingBoundaryAtOrBefore(
|
| - left_word_break, visible_position.DeepEquivalent());
|
| -
|
| - // FIXME: How should we handle a non-editable position?
|
| - if (left_word_break.IsNull() &&
|
| - IsEditablePosition(visible_position.DeepEquivalent())) {
|
| - TextDirection block_direction =
|
| - DirectionOfEnclosingBlock(visible_position.DeepEquivalent());
|
| - left_word_break = block_direction == TextDirection::kLtr
|
| - ? StartOfEditableContent(visible_position)
|
| - : EndOfEditableContent(visible_position);
|
| - }
|
| - return left_word_break;
|
| -}
|
| -
|
| -VisiblePosition RightWordPosition(const VisiblePosition& visible_position,
|
| - bool skips_space_when_moving_right) {
|
| - DCHECK(visible_position.IsValid()) << visible_position;
|
| - VisiblePosition right_word_break = VisualWordPosition(
|
| - visible_position, kMoveRight, skips_space_when_moving_right);
|
| - right_word_break = HonorEditingBoundaryAtOrBefore(
|
| - right_word_break, visible_position.DeepEquivalent());
|
| -
|
| - // FIXME: How should we handle a non-editable position?
|
| - if (right_word_break.IsNull() &&
|
| - IsEditablePosition(visible_position.DeepEquivalent())) {
|
| - TextDirection block_direction =
|
| - DirectionOfEnclosingBlock(visible_position.DeepEquivalent());
|
| - right_word_break = block_direction == TextDirection::kLtr
|
| - ? EndOfEditableContent(visible_position)
|
| - : StartOfEditableContent(visible_position);
|
| - }
|
| - return right_word_break;
|
| -}
|
| -
|
| template <typename Strategy>
|
| static ContainerNode* NonShadowBoundaryParentNode(Node* node) {
|
| ContainerNode* parent = Strategy::Parent(*node);
|
|
|