Commit dec2a918 authored by Xiaocheng Hu's avatar Xiaocheng Hu Committed by Commit Bot

Specialize RenderedPosition for bidi adjustment in SelectionController

This patch removes the general member functions in RenderedPosition
that inspect properties of bidi runs, and replace them by functions
providing the exact information needed by SelectionController, which
is the only client of RenderedPosition.

Details:
- Introduced RenderedPosition::BidiBoundaryType, so that we can obtain
  whether an RP is at bidi boundary without re-comparing its offset.
- Replaced almost all existing member functions by
 - AtBidiBoundary(), replacing AtL/RBoundaryOfBidiRun()
 - BidiRunContains(other_rp), replacing
   |other_rp == this->L/RBoundaryOfBidiRun(other_rp.BidiLevelOnR/L())|
 - IsPossiblyOtherBoundaryOf(other_rp), replacing
   |this->AtL/RBoundaryOfBidiRun(other_rp.BidiLevelOnL/R())|


Bug: 811502
Change-Id: I0b59b76e8060a5953295e09c98fcf7127a636ecc
Reviewed-on: https://chromium-review.googlesource.com/1056220Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#558202}
parent c2b143c2
...@@ -65,123 +65,63 @@ RenderedPosition RenderedPosition::Create( ...@@ -65,123 +65,63 @@ RenderedPosition RenderedPosition::Create(
// For example, abc FED |ghi should be changed into abc FED| ghi // For example, abc FED |ghi should be changed into abc FED| ghi
if (offset == box->CaretLeftmostOffset()) { if (offset == box->CaretLeftmostOffset()) {
const InlineBox* prev_box = box->PrevLeafChildIgnoringLineBreak(); const InlineBox* prev_box = box->PrevLeafChildIgnoringLineBreak();
if (prev_box && prev_box->BidiLevel() > box->BidiLevel()) if (prev_box && prev_box->BidiLevel() > box->BidiLevel()) {
return RenderedPosition(prev_box, prev_box->CaretRightmostOffset()); return RenderedPosition(prev_box, prev_box->CaretRightmostOffset(),
BidiBoundaryType::kRightBoundary);
}
BidiBoundaryType type =
prev_box && prev_box->BidiLevel() == box->BidiLevel()
? BidiBoundaryType::kNotBoundary
: BidiBoundaryType::kLeftBoundary;
return RenderedPosition(box, offset, type);
} }
// For example, abc| FED ghi should be changed into abc |FED ghi // For example, abc| FED ghi should be changed into abc |FED ghi
if (offset == box->CaretRightmostOffset()) { if (offset == box->CaretRightmostOffset()) {
const InlineBox* next_box = box->NextLeafChildIgnoringLineBreak(); const InlineBox* next_box = box->NextLeafChildIgnoringLineBreak();
if (next_box && next_box->BidiLevel() > box->BidiLevel()) if (next_box && next_box->BidiLevel() > box->BidiLevel()) {
return RenderedPosition(next_box, next_box->CaretLeftmostOffset()); return RenderedPosition(next_box, next_box->CaretLeftmostOffset(),
BidiBoundaryType::kLeftBoundary);
}
BidiBoundaryType type =
next_box && next_box->BidiLevel() == box->BidiLevel()
? BidiBoundaryType::kNotBoundary
: BidiBoundaryType::kRightBoundary;
return RenderedPosition(box, offset, type);
} }
return RenderedPosition(box, offset); return RenderedPosition(box, offset, BidiBoundaryType::kNotBoundary);
} }
const InlineBox* RenderedPosition::PrevLeafChild() const { bool RenderedPosition::IsPossiblyOtherBoundaryOf(
if (!prev_leaf_child_.has_value()) const RenderedPosition& other) const {
prev_leaf_child_ = inline_box_->PrevLeafChildIgnoringLineBreak(); DCHECK(other.AtBidiBoundary());
return prev_leaf_child_.value(); if (!AtBidiBoundary())
}
const InlineBox* RenderedPosition::NextLeafChild() const {
if (!next_leaf_child_.has_value())
next_leaf_child_ = inline_box_->NextLeafChildIgnoringLineBreak();
return next_leaf_child_.value();
}
unsigned char RenderedPosition::BidiLevelOnLeft() const {
const InlineBox* box =
AtLeftmostOffsetInBox() ? PrevLeafChild() : inline_box_;
return box ? box->BidiLevel() : 0;
}
unsigned char RenderedPosition::BidiLevelOnRight() const {
const InlineBox* box =
AtRightmostOffsetInBox() ? NextLeafChild() : inline_box_;
return box ? box->BidiLevel() : 0;
}
RenderedPosition RenderedPosition::LeftBoundaryOfBidiRun(
unsigned char bidi_level_of_run) const {
if (!inline_box_ || bidi_level_of_run > inline_box_->BidiLevel())
return RenderedPosition();
const InlineBox& box =
InlineBoxTraversal::FindLeftBoundaryOfEntireBidiRunIgnoringLineBreak(
*inline_box_, bidi_level_of_run);
return RenderedPosition(&box, box.CaretLeftmostOffset());
}
RenderedPosition RenderedPosition::RightBoundaryOfBidiRun(
unsigned char bidi_level_of_run) const {
if (!inline_box_ || bidi_level_of_run > inline_box_->BidiLevel())
return RenderedPosition();
const InlineBox& box =
InlineBoxTraversal::FindRightBoundaryOfEntireBidiRunIgnoringLineBreak(
*inline_box_, bidi_level_of_run);
return RenderedPosition(&box, box.CaretRightmostOffset());
}
bool RenderedPosition::AtLeftBoundaryOfBidiRun(
ShouldMatchBidiLevel should_match_bidi_level,
unsigned char bidi_level_of_run) const {
if (!inline_box_)
return false; return false;
if (bidi_boundary_type_ == other.bidi_boundary_type_)
if (AtLeftmostOffsetInBox()) { return false;
if (should_match_bidi_level == kIgnoreBidiLevel) return inline_box_->BidiLevel() >= other.inline_box_->BidiLevel();
return !PrevLeafChild() ||
PrevLeafChild()->BidiLevel() < inline_box_->BidiLevel();
return inline_box_->BidiLevel() >= bidi_level_of_run &&
(!PrevLeafChild() ||
PrevLeafChild()->BidiLevel() < bidi_level_of_run);
}
if (AtRightmostOffsetInBox()) {
if (should_match_bidi_level == kIgnoreBidiLevel)
return NextLeafChild() &&
inline_box_->BidiLevel() < NextLeafChild()->BidiLevel();
return NextLeafChild() && inline_box_->BidiLevel() < bidi_level_of_run &&
NextLeafChild()->BidiLevel() >= bidi_level_of_run;
}
return false;
} }
bool RenderedPosition::AtRightBoundaryOfBidiRun( bool RenderedPosition::BidiRunContains(const RenderedPosition& other) const {
ShouldMatchBidiLevel should_match_bidi_level, DCHECK(AtBidiBoundary());
unsigned char bidi_level_of_run) const { DCHECK(!other.IsNull());
if (!inline_box_) UBiDiLevel level = inline_box_->BidiLevel();
if (level > other.inline_box_->BidiLevel())
return false; return false;
const InlineBox& boundary_of_other =
if (AtRightmostOffsetInBox()) { bidi_boundary_type_ == BidiBoundaryType::kLeftBoundary
if (should_match_bidi_level == kIgnoreBidiLevel) ? InlineBoxTraversal::
return !NextLeafChild() || FindLeftBoundaryOfEntireBidiRunIgnoringLineBreak(
NextLeafChild()->BidiLevel() < inline_box_->BidiLevel(); *other.inline_box_, level)
return inline_box_->BidiLevel() >= bidi_level_of_run && : InlineBoxTraversal::
(!NextLeafChild() || FindRightBoundaryOfEntireBidiRunIgnoringLineBreak(
NextLeafChild()->BidiLevel() < bidi_level_of_run); *other.inline_box_, level);
} return inline_box_ == &boundary_of_other;
if (AtLeftmostOffsetInBox()) {
if (should_match_bidi_level == kIgnoreBidiLevel)
return PrevLeafChild() &&
inline_box_->BidiLevel() < PrevLeafChild()->BidiLevel();
return PrevLeafChild() && inline_box_->BidiLevel() < bidi_level_of_run &&
PrevLeafChild()->BidiLevel() >= bidi_level_of_run;
}
return false;
} }
PositionInFlatTree RenderedPosition::GetPosition() const { PositionInFlatTree RenderedPosition::GetPosition() const {
DCHECK(AtLeftBoundaryOfBidiRun() || AtRightBoundaryOfBidiRun()); DCHECK(AtBidiBoundary());
DCHECK_EQ(AtLeftmostOffsetInBox(), AtLeftBoundaryOfBidiRun());
DCHECK_EQ(AtRightmostOffsetInBox(), AtRightBoundaryOfBidiRun());
return PositionInFlatTree::EditingPositionOf( return PositionInFlatTree::EditingPositionOf(
inline_box_->GetLineLayoutItem().GetNode(), offset_); inline_box_->GetLineLayoutItem().GetNode(), offset_);
} }
......
...@@ -44,42 +44,33 @@ struct CompositedSelection; ...@@ -44,42 +44,33 @@ struct CompositedSelection;
// TODO(xiaochengh): RenderedPosition is deprecated. It's currently only used in // TODO(xiaochengh): RenderedPosition is deprecated. It's currently only used in
// |SelectionController| for bidi adjustment. We should break this class and // |SelectionController| for bidi adjustment. We should break this class and
// move relevant code to |inline_box_traversal.cc|, and templatize it so that it // move relevant code to |inline_box_traversal.cc|, and generalize it so that it
// can be reused in LayoutNG. // can be reused in LayoutNG.
class CORE_EXPORT RenderedPosition { class CORE_EXPORT RenderedPosition {
STACK_ALLOCATED(); STACK_ALLOCATED();
public: public:
RenderedPosition(); RenderedPosition() = default;
static RenderedPosition Create(const VisiblePositionInFlatTree&); static RenderedPosition Create(const VisiblePositionInFlatTree&);
bool IsNull() const { return !inline_box_; } bool IsNull() const { return !inline_box_; }
bool operator==(const RenderedPosition& other) const { bool operator==(const RenderedPosition& other) const {
return inline_box_ == other.inline_box_ && offset_ == other.offset_; return inline_box_ == other.inline_box_ && offset_ == other.offset_ &&
bidi_boundary_type_ == other.bidi_boundary_type_;
} }
unsigned char BidiLevelOnLeft() const; bool AtBidiBoundary() const {
unsigned char BidiLevelOnRight() const; return bidi_boundary_type_ != BidiBoundaryType::kNotBoundary;
RenderedPosition LeftBoundaryOfBidiRun(unsigned char bidi_level_of_run) const;
RenderedPosition RightBoundaryOfBidiRun(
unsigned char bidi_level_of_run) const;
enum ShouldMatchBidiLevel { kMatchBidiLevel, kIgnoreBidiLevel };
bool AtLeftBoundaryOfBidiRun() const {
return AtLeftBoundaryOfBidiRun(kIgnoreBidiLevel, 0);
}
bool AtRightBoundaryOfBidiRun() const {
return AtRightBoundaryOfBidiRun(kIgnoreBidiLevel, 0);
}
// The following two functions return true only if the current position is
// at the end of the bidi run of the specified bidi embedding level.
bool AtLeftBoundaryOfBidiRun(unsigned char bidi_level_of_run) const {
return AtLeftBoundaryOfBidiRun(kMatchBidiLevel, bidi_level_of_run);
}
bool AtRightBoundaryOfBidiRun(unsigned char bidi_level_of_run) const {
return AtRightBoundaryOfBidiRun(kMatchBidiLevel, bidi_level_of_run);
} }
// Given |other|, which is a boundary of a bidi run, returns true if |this|
// can be the other boundary of that run by checking some conditions.
bool IsPossiblyOtherBoundaryOf(const RenderedPosition& other) const;
// Callable only when |this| is at boundary of a bidi run. Returns true if
// |other| is in that bidi run.
bool BidiRunContains(const RenderedPosition& other) const;
PositionInFlatTree GetPosition() const; PositionInFlatTree GetPosition() const;
// TODO(editing-dev): This function doesn't use RenderedPosition // TODO(editing-dev): This function doesn't use RenderedPosition
...@@ -87,33 +78,18 @@ class CORE_EXPORT RenderedPosition { ...@@ -87,33 +78,18 @@ class CORE_EXPORT RenderedPosition {
static CompositedSelection ComputeCompositedSelection(const FrameSelection&); static CompositedSelection ComputeCompositedSelection(const FrameSelection&);
private: private:
explicit RenderedPosition(const InlineBox*, int offset); enum class BidiBoundaryType { kNotBoundary, kLeftBoundary, kRightBoundary };
explicit RenderedPosition(const InlineBox*, int offset, BidiBoundaryType);
const InlineBox* PrevLeafChild() const; const InlineBox* inline_box_ = nullptr;
const InlineBox* NextLeafChild() const; int offset_ = 0;
bool AtLeftmostOffsetInBox() const { BidiBoundaryType bidi_boundary_type_ = BidiBoundaryType::kNotBoundary;
return inline_box_ && offset_ == inline_box_->CaretLeftmostOffset();
}
bool AtRightmostOffsetInBox() const {
return inline_box_ && offset_ == inline_box_->CaretRightmostOffset();
}
bool AtLeftBoundaryOfBidiRun(ShouldMatchBidiLevel,
unsigned char bidi_level_of_run) const;
bool AtRightBoundaryOfBidiRun(ShouldMatchBidiLevel,
unsigned char bidi_level_of_run) const;
const InlineBox* inline_box_;
int offset_;
mutable base::Optional<const InlineBox*> prev_leaf_child_;
mutable base::Optional<const InlineBox*> next_leaf_child_;
}; };
inline RenderedPosition::RenderedPosition() inline RenderedPosition::RenderedPosition(const InlineBox* box,
: inline_box_(nullptr), offset_(0) {} int offset,
BidiBoundaryType type)
inline RenderedPosition::RenderedPosition(const InlineBox* box, int offset) : inline_box_(box), offset_(offset), bidi_boundary_type_(type) {}
: inline_box_(box), offset_(offset) {}
} // namespace blink } // namespace blink
......
...@@ -766,28 +766,17 @@ void SelectionController::SelectClosestWordOrLinkFromMouseEvent( ...@@ -766,28 +766,17 @@ void SelectionController::SelectClosestWordOrLinkFromMouseEvent(
static bool ShouldAdjustBaseAtBidiBoundary(const RenderedPosition& base, static bool ShouldAdjustBaseAtBidiBoundary(const RenderedPosition& base,
const RenderedPosition& extent) { const RenderedPosition& extent) {
if (base.AtLeftBoundaryOfBidiRun()) { DCHECK(base.AtBidiBoundary());
return !extent.AtRightBoundaryOfBidiRun(base.BidiLevelOnRight()) && if (extent.IsPossiblyOtherBoundaryOf(base))
base == extent.LeftBoundaryOfBidiRun(base.BidiLevelOnRight()); return false;
} return base.BidiRunContains(extent);
if (base.AtRightBoundaryOfBidiRun()) {
return !extent.AtLeftBoundaryOfBidiRun(base.BidiLevelOnLeft()) &&
base == extent.RightBoundaryOfBidiRun(base.BidiLevelOnLeft());
}
return false;
} }
static bool ShouldAdjustExtentAtBidiBoundary(const RenderedPosition& base, static bool ShouldAdjustExtentAtBidiBoundary(const RenderedPosition& base,
const RenderedPosition& extent) { const RenderedPosition& extent) {
if (extent.AtLeftBoundaryOfBidiRun()) if (!extent.AtBidiBoundary())
return extent == base.LeftBoundaryOfBidiRun(extent.BidiLevelOnRight()); return false;
return extent.BidiRunContains(base);
if (extent.AtRightBoundaryOfBidiRun())
return extent == base.RightBoundaryOfBidiRun(extent.BidiLevelOnLeft());
return false;
} }
static SelectionInFlatTree AdjustEndpointsAtBidiBoundary( static SelectionInFlatTree AdjustEndpointsAtBidiBoundary(
...@@ -808,7 +797,7 @@ static SelectionInFlatTree AdjustEndpointsAtBidiBoundary( ...@@ -808,7 +797,7 @@ static SelectionInFlatTree AdjustEndpointsAtBidiBoundary(
if (base.IsNull() || extent.IsNull() || base == extent) if (base.IsNull() || extent.IsNull() || base == extent)
return unchanged_selection; return unchanged_selection;
if (base.AtLeftBoundaryOfBidiRun() || base.AtRightBoundaryOfBidiRun()) { if (base.AtBidiBoundary()) {
if (ShouldAdjustBaseAtBidiBoundary(base, extent)) { if (ShouldAdjustBaseAtBidiBoundary(base, extent)) {
const PositionInFlatTree adjusted_base = const PositionInFlatTree adjusted_base =
CreateVisiblePosition(base.GetPosition()).DeepEquivalent(); CreateVisiblePosition(base.GetPosition()).DeepEquivalent();
......
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