Commit d62cf5da authored by Vladimir Levin's avatar Vladimir Levin Committed by Commit Bot

FindBuffer: Reorder some functions in find buffer.

This patch just moves some code around so that it is a little better
organized. There are no behavior changes here, just some comments and
reoderdering.

This is split off from
https://chromium-review.googlesource.com/c/chromium/src/+/2028177

R=rakina@chromium.org, yosin@chromium.org

Change-Id: Ib4862e5a9baee36e295144a0af5a8b2120ac71cc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2032167Reviewed-by: default avatarRakina Zata Amni <rakina@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Commit-Queue: vmpstr <vmpstr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#737345}
parent 7ead8225
...@@ -24,108 +24,10 @@ ...@@ -24,108 +24,10 @@
#include "third_party/blink/renderer/platform/wtf/text/unicode.h" #include "third_party/blink/renderer/platform/wtf/text/unicode.h"
namespace blink { namespace blink {
namespace {
FindBuffer::FindBuffer(const EphemeralRangeInFlatTree& range) { // Returns true if the search should ignore the given |node|'s contents. In
DCHECK(range.IsNotNull() && !range.IsCollapsed()) << range; // other words, we don't need to recurse into the node's children.
CollectTextUntilBlockBoundary(range);
}
FindBuffer::Results::Results() {
empty_result_ = true;
}
FindBuffer::Results::Results(const FindBuffer& find_buffer,
TextSearcherICU* text_searcher,
const Vector<UChar>& buffer,
const String& search_text,
const blink::FindOptions options) {
// We need to own the |search_text| because |text_searcher_| only has a
// StringView (doesn't own the search text).
search_text_ = search_text;
find_buffer_ = &find_buffer;
text_searcher_ = text_searcher;
text_searcher_->SetPattern(search_text_, options);
text_searcher_->SetText(buffer.data(), buffer.size());
text_searcher_->SetOffset(0);
}
FindBuffer::Results::Iterator::Iterator(const FindBuffer& find_buffer,
TextSearcherICU* text_searcher,
const String& search_text)
: find_buffer_(&find_buffer),
text_searcher_(text_searcher),
has_match_(true) {
operator++();
}
const FindBuffer::BufferMatchResult FindBuffer::Results::Iterator::operator*()
const {
DCHECK(has_match_);
return FindBuffer::BufferMatchResult({match_.start, match_.length});
}
void FindBuffer::Results::Iterator::operator++() {
DCHECK(has_match_);
has_match_ = text_searcher_->NextMatchResult(match_);
if (has_match_ && find_buffer_ && find_buffer_->IsInvalidMatch(match_))
operator++();
}
bool FindBuffer::IsInvalidMatch(MatchResultICU match) const {
// Invalid matches are a result of accidentally matching elements that are
// replaced with the max code point, and may lead to crashes. To avoid
// crashing, we should skip the matches that are invalid - they would have
// either an empty position or a non-offset-in-anchor position.
const unsigned start_index = match.start;
PositionInFlatTree start_position =
PositionAtStartOfCharacterAtIndex(start_index);
if (start_position.IsNull() || !start_position.IsOffsetInAnchor())
return true;
const unsigned end_index = match.start + match.length;
DCHECK_LE(start_index, end_index);
PositionInFlatTree end_position =
PositionAtEndOfCharacterAtIndex(end_index - 1);
if (end_position.IsNull() || !end_position.IsOffsetInAnchor())
return true;
return false;
}
FindBuffer::Results::Iterator FindBuffer::Results::begin() const {
if (empty_result_)
return end();
text_searcher_->SetOffset(0);
return Iterator(*find_buffer_, text_searcher_, search_text_);
}
FindBuffer::Results::Iterator FindBuffer::Results::end() const {
return Iterator();
}
bool FindBuffer::Results::IsEmpty() const {
return begin() == end();
}
FindBuffer::BufferMatchResult FindBuffer::Results::front() const {
return *begin();
}
FindBuffer::BufferMatchResult FindBuffer::Results::back() const {
Iterator last_result;
for (Iterator it = begin(); it != end(); ++it) {
last_result = it;
}
return *last_result;
}
unsigned FindBuffer::Results::CountForTesting() const {
unsigned result = 0;
for (Iterator it = begin(); it != end(); ++it) {
++result;
}
return result;
}
bool ShouldIgnoreContents(const Node& node) { bool ShouldIgnoreContents(const Node& node) {
const auto* element = DynamicTo<HTMLElement>(node); const auto* element = DynamicTo<HTMLElement>(node);
if (!element) if (!element)
...@@ -145,6 +47,9 @@ bool ShouldIgnoreContents(const Node& node) { ...@@ -145,6 +47,9 @@ bool ShouldIgnoreContents(const Node& node) {
DisplayLockActivationReason::kFindInPage)); DisplayLockActivationReason::kFindInPage));
} }
// Returns the first ancestor that isn't searchable. In other words, either
// ShouldIgnoreContents() returns true for it or it has a display: none style.
// Returns nullptr if no such ancestor exists.
Node* GetNonSearchableAncestor(const Node& node) { Node* GetNonSearchableAncestor(const Node& node) {
for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(node)) { for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(node)) {
const ComputedStyle* style = ancestor.EnsureComputedStyle(); const ComputedStyle* style = ancestor.EnsureComputedStyle();
...@@ -157,12 +62,15 @@ Node* GetNonSearchableAncestor(const Node& node) { ...@@ -157,12 +62,15 @@ Node* GetNonSearchableAncestor(const Node& node) {
return nullptr; return nullptr;
} }
// Returns true if the given |display| is considered a 'block'
bool IsBlock(EDisplay display) { bool IsBlock(EDisplay display) {
return display == EDisplay::kBlock || display == EDisplay::kTable || return display == EDisplay::kBlock || display == EDisplay::kTable ||
display == EDisplay::kFlowRoot || display == EDisplay::kGrid || display == EDisplay::kFlowRoot || display == EDisplay::kGrid ||
display == EDisplay::kFlex || display == EDisplay::kListItem; display == EDisplay::kFlex || display == EDisplay::kListItem;
} }
// Returns the next node after |start_node| (including start node) that is a
// text node and is searchable and visible.
Node* GetVisibleTextNode(Node& start_node) { Node* GetVisibleTextNode(Node& start_node) {
Node* node = &start_node; Node* node = &start_node;
// Move to outside display none subtree if we're inside one. // Move to outside display none subtree if we're inside one.
...@@ -193,6 +101,8 @@ Node* GetVisibleTextNode(Node& start_node) { ...@@ -193,6 +101,8 @@ Node* GetVisibleTextNode(Node& start_node) {
return nullptr; return nullptr;
} }
// Returns the closest ancestor of |start_node| (including the node itself) that
// is a block.
Node& GetLowestDisplayBlockInclusiveAncestor(const Node& start_node) { Node& GetLowestDisplayBlockInclusiveAncestor(const Node& start_node) {
// Gets lowest inclusive ancestor that has block display value. // Gets lowest inclusive ancestor that has block display value.
// <div id=outer>a<div id=inner>b</div>c</div> // <div id=outer>a<div id=inner>b</div>c</div>
...@@ -205,6 +115,33 @@ Node& GetLowestDisplayBlockInclusiveAncestor(const Node& start_node) { ...@@ -205,6 +115,33 @@ Node& GetLowestDisplayBlockInclusiveAncestor(const Node& start_node) {
} }
return *start_node.GetDocument().documentElement(); return *start_node.GetDocument().documentElement();
} }
} // namespace
// FindBuffer implementation.
FindBuffer::FindBuffer(const EphemeralRangeInFlatTree& range) {
DCHECK(range.IsNotNull() && !range.IsCollapsed()) << range;
CollectTextUntilBlockBoundary(range);
}
bool FindBuffer::IsInvalidMatch(MatchResultICU match) const {
// Invalid matches are a result of accidentally matching elements that are
// replaced with the max code point, and may lead to crashes. To avoid
// crashing, we should skip the matches that are invalid - they would have
// either an empty position or a non-offset-in-anchor position.
const unsigned start_index = match.start;
PositionInFlatTree start_position =
PositionAtStartOfCharacterAtIndex(start_index);
if (start_position.IsNull() || !start_position.IsOffsetInAnchor())
return true;
const unsigned end_index = match.start + match.length;
DCHECK_LE(start_index, end_index);
PositionInFlatTree end_position =
PositionAtEndOfCharacterAtIndex(end_index - 1);
if (end_position.IsNull() || !end_position.IsOffsetInAnchor())
return true;
return false;
}
EphemeralRangeInFlatTree FindBuffer::FindMatchInRange( EphemeralRangeInFlatTree FindBuffer::FindMatchInRange(
const EphemeralRangeInFlatTree& range, const EphemeralRangeInFlatTree& range,
...@@ -308,11 +245,12 @@ void FindBuffer::CollectScopedForcedUpdates(Node& start_node, ...@@ -308,11 +245,12 @@ void FindBuffer::CollectScopedForcedUpdates(Node& start_node,
} }
} }
// Collects text until block boundary located at or after |start_node|
// to |buffer_|. Saves the next starting node after the block to
// |node_after_block_|.
void FindBuffer::CollectTextUntilBlockBoundary( void FindBuffer::CollectTextUntilBlockBoundary(
const EphemeralRangeInFlatTree& range) { const EphemeralRangeInFlatTree& range) {
// Collects text until block boundary located at or after |start_node|
// to |buffer_|. Saves the next starting node after the block to
// |node_after_block_|.
DCHECK(range.IsNotNull() && !range.IsCollapsed()) << range; DCHECK(range.IsNotNull() && !range.IsCollapsed()) << range;
node_after_block_ = nullptr; node_after_block_ = nullptr;
...@@ -501,4 +439,82 @@ void FindBuffer::AddTextToBuffer(const Text& text_node, ...@@ -501,4 +439,82 @@ void FindBuffer::AddTextToBuffer(const Text& text_node,
} }
} }
// FindBuffer::Results implementation.
FindBuffer::Results::Results() {
empty_result_ = true;
}
FindBuffer::Results::Results(const FindBuffer& find_buffer,
TextSearcherICU* text_searcher,
const Vector<UChar>& buffer,
const String& search_text,
const blink::FindOptions options) {
// We need to own the |search_text| because |text_searcher_| only has a
// StringView (doesn't own the search text).
search_text_ = search_text;
find_buffer_ = &find_buffer;
text_searcher_ = text_searcher;
text_searcher_->SetPattern(search_text_, options);
text_searcher_->SetText(buffer.data(), buffer.size());
text_searcher_->SetOffset(0);
}
FindBuffer::Results::Iterator FindBuffer::Results::begin() const {
if (empty_result_)
return end();
text_searcher_->SetOffset(0);
return Iterator(*find_buffer_, text_searcher_, search_text_);
}
FindBuffer::Results::Iterator FindBuffer::Results::end() const {
return Iterator();
}
bool FindBuffer::Results::IsEmpty() const {
return begin() == end();
}
FindBuffer::BufferMatchResult FindBuffer::Results::front() const {
return *begin();
}
FindBuffer::BufferMatchResult FindBuffer::Results::back() const {
Iterator last_result;
for (Iterator it = begin(); it != end(); ++it) {
last_result = it;
}
return *last_result;
}
unsigned FindBuffer::Results::CountForTesting() const {
unsigned result = 0;
for (Iterator it = begin(); it != end(); ++it) {
++result;
}
return result;
}
// Findbuffer::Results::Iterator implementation.
FindBuffer::Results::Iterator::Iterator(const FindBuffer& find_buffer,
TextSearcherICU* text_searcher,
const String& search_text)
: find_buffer_(&find_buffer),
text_searcher_(text_searcher),
has_match_(true) {
operator++();
}
const FindBuffer::BufferMatchResult FindBuffer::Results::Iterator::operator*()
const {
DCHECK(has_match_);
return FindBuffer::BufferMatchResult({match_.start, match_.length});
}
void FindBuffer::Results::Iterator::operator++() {
DCHECK(has_match_);
has_match_ = text_searcher_->NextMatchResult(match_);
if (has_match_ && find_buffer_ && find_buffer_->IsInvalidMatch(match_))
operator++();
}
} // namespace blink } // 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