Commit 4da86e95 authored by thestig's avatar thestig Committed by Commit bot

PDF: Fix potential bad indexes in find results.

Add a new FindTextData class to store the index to avoid all the size_t
to int casts.

BUG=416696

Review URL: https://codereview.chromium.org/691273003

Cr-Commit-Position: refs/heads/master@{#302532}
parent 63d3aa3c
...@@ -1286,6 +1286,7 @@ void Instance::NotifyNumberOfFindResultsChanged(int total, bool final_result) { ...@@ -1286,6 +1286,7 @@ void Instance::NotifyNumberOfFindResultsChanged(int total, bool final_result) {
} }
void Instance::NotifySelectedFindResultChanged(int current_find_index) { void Instance::NotifySelectedFindResultChanged(int current_find_index) {
DCHECK_GE(current_find_index, 0);
SelectedFindResultChanged(current_find_index); SelectedFindResultChanged(current_find_index);
} }
......
...@@ -906,6 +906,7 @@ void OutOfProcessInstance::NotifyNumberOfFindResultsChanged(int total, ...@@ -906,6 +906,7 @@ void OutOfProcessInstance::NotifyNumberOfFindResultsChanged(int total,
void OutOfProcessInstance::NotifySelectedFindResultChanged( void OutOfProcessInstance::NotifySelectedFindResultChanged(
int current_find_index) { int current_find_index) {
DCHECK_GE(current_find_index, 0);
SelectedFindResultChanged(current_find_index); SelectedFindResultChanged(current_find_index);
} }
......
...@@ -566,8 +566,6 @@ PDFiumEngine::PDFiumEngine(PDFEngine::Client* client) ...@@ -566,8 +566,6 @@ PDFiumEngine::PDFiumEngine(PDFEngine::Client* client)
next_page_to_search_(-1), next_page_to_search_(-1),
last_page_to_search_(-1), last_page_to_search_(-1),
last_character_index_to_search_(-1), last_character_index_to_search_(-1),
current_find_index_(-1),
resume_find_index_(-1),
permissions_(0), permissions_(0),
fpdf_availability_(NULL), fpdf_availability_(NULL),
next_timer_id_(0), next_timer_id_(0),
...@@ -1686,10 +1684,17 @@ void PDFiumEngine::StartFind(const char* text, bool case_sensitive) { ...@@ -1686,10 +1684,17 @@ void PDFiumEngine::StartFind(const char* text, bool case_sensitive) {
client_->NotifyNumberOfFindResultsChanged(find_results_.size(), true); client_->NotifyNumberOfFindResultsChanged(find_results_.size(), true);
// When searching is complete, resume finding at a particular index. // When searching is complete, resume finding at a particular index.
if (resume_find_index_ != -1) { // Assuming the user has not clicked the find button in the meanwhile.
current_find_index_ = resume_find_index_; if (resume_find_index_.valid() && !current_find_index_.valid()) {
resume_find_index_ = -1; size_t resume_index = resume_find_index_.GetIndex();
if (resume_index >= find_results_.size()) {
// This might happen if the PDF has some dynamically generated text?
resume_index = 0;
}
current_find_index_.SetIndex(resume_index);
client_->NotifySelectedFindResultChanged(resume_index);
} }
resume_find_index_.Invalidate();
} else { } else {
pp::CompletionCallback callback = pp::CompletionCallback callback =
find_factory_.NewCallback(&PDFiumEngine::ContinueFind); find_factory_.NewCallback(&PDFiumEngine::ContinueFind);
...@@ -1772,26 +1777,29 @@ void PDFiumEngine::SearchUsingICU(const base::string16& term, ...@@ -1772,26 +1777,29 @@ void PDFiumEngine::SearchUsingICU(const base::string16& term,
void PDFiumEngine::AddFindResult(const PDFiumRange& result) { void PDFiumEngine::AddFindResult(const PDFiumRange& result) {
// Figure out where to insert the new location, since we could have // Figure out where to insert the new location, since we could have
// started searching midway and now we wrapped. // started searching midway and now we wrapped.
size_t i; size_t result_index;
int page_index = result.page_index(); int page_index = result.page_index();
int char_index = result.char_index(); int char_index = result.char_index();
for (i = 0; i < find_results_.size(); ++i) { for (result_index = 0; result_index < find_results_.size(); ++result_index) {
if (find_results_[i].page_index() > page_index || if (find_results_[result_index].page_index() > page_index ||
(find_results_[i].page_index() == page_index && (find_results_[result_index].page_index() == page_index &&
find_results_[i].char_index() > char_index)) { find_results_[result_index].char_index() > char_index)) {
break; break;
} }
} }
find_results_.insert(find_results_.begin() + i, result); find_results_.insert(find_results_.begin() + result_index, result);
UpdateTickMarks(); UpdateTickMarks();
if (current_find_index_ == -1 && resume_find_index_ == -1) { if (current_find_index_.valid()) {
// Select the first match. if (result_index <= current_find_index_.GetIndex()) {
// Update the current match index
size_t find_index = current_find_index_.IncrementIndex();
DCHECK_LT(find_index, find_results_.size());
client_->NotifySelectedFindResultChanged(current_find_index_.GetIndex());
}
} else if (!resume_find_index_.valid()) {
// Both indices are invalid. Select the first match.
SelectFindResult(true); SelectFindResult(true);
} else if (static_cast<int>(i) <= current_find_index_) {
// Update the current match index
current_find_index_++;
client_->NotifySelectedFindResultChanged(current_find_index_);
} }
client_->NotifyNumberOfFindResultsChanged(find_results_.size(), false); client_->NotifyNumberOfFindResultsChanged(find_results_.size(), false);
} }
...@@ -1805,34 +1813,40 @@ bool PDFiumEngine::SelectFindResult(bool forward) { ...@@ -1805,34 +1813,40 @@ bool PDFiumEngine::SelectFindResult(bool forward) {
SelectionChangeInvalidator selection_invalidator(this); SelectionChangeInvalidator selection_invalidator(this);
// Move back/forward through the search locations we previously found. // Move back/forward through the search locations we previously found.
if (forward) { size_t new_index;
if (++current_find_index_ == static_cast<int>(find_results_.size())) const size_t last_index = find_results_.size() - 1;
current_find_index_ = 0; if (current_find_index_.valid()) {
} else { size_t current_index = current_find_index_.GetIndex();
if (--current_find_index_ < 0) { if (forward) {
current_find_index_ = find_results_.size() - 1; new_index = (current_index >= last_index) ? 0 : current_index + 1;
} else {
new_index = (current_find_index_.GetIndex() == 0) ?
last_index : current_index - 1;
} }
} else {
new_index = forward ? 0 : last_index;
} }
current_find_index_.SetIndex(new_index);
// Update the selection before telling the client to scroll, since it could // Update the selection before telling the client to scroll, since it could
// paint then. // paint then.
selection_.clear(); selection_.clear();
selection_.push_back(find_results_[current_find_index_]); selection_.push_back(find_results_[current_find_index_.GetIndex()]);
// If the result is not in view, scroll to it. // If the result is not in view, scroll to it.
size_t i;
pp::Rect bounding_rect; pp::Rect bounding_rect;
pp::Rect visible_rect = GetVisibleRect(); pp::Rect visible_rect = GetVisibleRect();
// Use zoom of 1.0 since visible_rect is without zoom. // Use zoom of 1.0 since visible_rect is without zoom.
std::vector<pp::Rect> rects = find_results_[current_find_index_]. std::vector<pp::Rect> rects;
GetScreenRects(pp::Point(), 1.0, current_rotation_); rects = find_results_[current_find_index_.GetIndex()].GetScreenRects(
for (i = 0; i < rects.size(); ++i) pp::Point(), 1.0, current_rotation_);
for (size_t i = 0; i < rects.size(); ++i)
bounding_rect = bounding_rect.Union(rects[i]); bounding_rect = bounding_rect.Union(rects[i]);
if (!visible_rect.Contains(bounding_rect)) { if (!visible_rect.Contains(bounding_rect)) {
pp::Point center = bounding_rect.CenterPoint(); pp::Point center = bounding_rect.CenterPoint();
// Make the page centered. // Make the page centered.
int new_y = static_cast<int>(center.y() * current_zoom_) - int new_y = static_cast<int>(center.y() * current_zoom_) -
static_cast<int>(visible_rect.height() * current_zoom_ / 2); static_cast<int>(visible_rect.height() * current_zoom_ / 2);
if (new_y < 0) if (new_y < 0)
new_y = 0; new_y = 0;
client_->ScrollToY(new_y); client_->ScrollToY(new_y);
...@@ -1840,15 +1854,14 @@ bool PDFiumEngine::SelectFindResult(bool forward) { ...@@ -1840,15 +1854,14 @@ bool PDFiumEngine::SelectFindResult(bool forward) {
// Only move horizontally if it's not visible. // Only move horizontally if it's not visible.
if (center.x() < visible_rect.x() || center.x() > visible_rect.right()) { if (center.x() < visible_rect.x() || center.x() > visible_rect.right()) {
int new_x = static_cast<int>(center.x() * current_zoom_) - int new_x = static_cast<int>(center.x() * current_zoom_) -
static_cast<int>(visible_rect.width() * current_zoom_ / 2); static_cast<int>(visible_rect.width() * current_zoom_ / 2);
if (new_x < 0) if (new_x < 0)
new_x = 0; new_x = 0;
client_->ScrollToX(new_x); client_->ScrollToX(new_x);
} }
} }
client_->NotifySelectedFindResultChanged(current_find_index_); client_->NotifySelectedFindResultChanged(current_find_index_.GetIndex());
return true; return true;
} }
...@@ -1861,7 +1874,7 @@ void PDFiumEngine::StopFind() { ...@@ -1861,7 +1874,7 @@ void PDFiumEngine::StopFind() {
next_page_to_search_ = -1; next_page_to_search_ = -1;
last_page_to_search_ = -1; last_page_to_search_ = -1;
last_character_index_to_search_ = -1; last_character_index_to_search_ = -1;
current_find_index_ = -1; current_find_index_.Invalidate();
current_find_text_.clear(); current_find_text_.clear();
UpdateTickMarks(); UpdateTickMarks();
find_factory_.CancelAll(); find_factory_.CancelAll();
...@@ -1893,30 +1906,12 @@ void PDFiumEngine::ZoomUpdated(double new_zoom_level) { ...@@ -1893,30 +1906,12 @@ void PDFiumEngine::ZoomUpdated(double new_zoom_level) {
void PDFiumEngine::RotateClockwise() { void PDFiumEngine::RotateClockwise() {
current_rotation_ = (current_rotation_ + 1) % 4; current_rotation_ = (current_rotation_ + 1) % 4;
RotateInternal();
// Store the current find index so that we can resume finding at that
// particular index after we have recomputed the find results.
std::string current_find_text = current_find_text_;
resume_find_index_ = current_find_index_;
InvalidateAllPages();
if (!current_find_text.empty())
StartFind(current_find_text.c_str(), false);
} }
void PDFiumEngine::RotateCounterclockwise() { void PDFiumEngine::RotateCounterclockwise() {
current_rotation_ = (current_rotation_ - 1) % 4; current_rotation_ = (current_rotation_ - 1) % 4;
RotateInternal();
// Store the current find index so that we can resume finding at that
// particular index after we have recomputed the find results.
std::string current_find_text = current_find_text_;
resume_find_index_ = current_find_index_;
InvalidateAllPages();
if (!current_find_text.empty())
StartFind(current_find_text.c_str(), false);
} }
void PDFiumEngine::InvalidateAllPages() { void PDFiumEngine::InvalidateAllPages() {
...@@ -2809,6 +2804,32 @@ bool PDFiumEngine::MouseDownState::Matches( ...@@ -2809,6 +2804,32 @@ bool PDFiumEngine::MouseDownState::Matches(
return false; return false;
} }
PDFiumEngine::FindTextIndex::FindTextIndex()
: valid_(false), index_(0) {
}
PDFiumEngine::FindTextIndex::~FindTextIndex() {
}
void PDFiumEngine::FindTextIndex::Invalidate() {
valid_ = false;
}
size_t PDFiumEngine::FindTextIndex::GetIndex() const {
DCHECK(valid_);
return index_;
}
void PDFiumEngine::FindTextIndex::SetIndex(size_t index) {
valid_ = true;
index_ = index;
}
size_t PDFiumEngine::FindTextIndex::IncrementIndex() {
DCHECK(valid_);
return ++index_;
}
void PDFiumEngine::DeviceToPage(int page_index, void PDFiumEngine::DeviceToPage(int page_index,
float device_x, float device_x,
float device_y, float device_y,
...@@ -2988,6 +3009,24 @@ void PDFiumEngine::OnSelectionChanged() { ...@@ -2988,6 +3009,24 @@ void PDFiumEngine::OnSelectionChanged() {
pp::PDF::SetSelectedText(GetPluginInstance(), GetSelectedText().c_str()); pp::PDF::SetSelectedText(GetPluginInstance(), GetSelectedText().c_str());
} }
void PDFiumEngine::RotateInternal() {
// Store the current find index so that we can resume finding at that
// particular index after we have recomputed the find results.
std::string current_find_text = current_find_text_;
if (current_find_index_.valid())
resume_find_index_.SetIndex(current_find_index_.GetIndex());
else
resume_find_index_.Invalidate();
InvalidateAllPages();
if (!current_find_text.empty()) {
// Clear the UI.
client_->NotifyNumberOfFindResultsChanged(0, false);
StartFind(current_find_text.c_str(), false);
}
}
void PDFiumEngine::Form_Invalidate(FPDF_FORMFILLINFO* param, void PDFiumEngine::Form_Invalidate(FPDF_FORMFILLINFO* param,
FPDF_PAGE page, FPDF_PAGE page,
double left, double left,
......
...@@ -151,6 +151,26 @@ class PDFiumEngine : public PDFEngine, ...@@ -151,6 +151,26 @@ class PDFiumEngine : public PDFEngine,
DISALLOW_COPY_AND_ASSIGN(MouseDownState); DISALLOW_COPY_AND_ASSIGN(MouseDownState);
}; };
// Used to store the state of a text search.
class FindTextIndex {
public:
FindTextIndex();
~FindTextIndex();
bool valid() const { return valid_; }
void Invalidate();
size_t GetIndex() const;
void SetIndex(size_t index);
size_t IncrementIndex();
private:
bool valid_; // Whether |index_| is valid or not.
size_t index_; // The current search result, 0-based.
DISALLOW_COPY_AND_ASSIGN(FindTextIndex);
};
friend class SelectionChangeInvalidator; friend class SelectionChangeInvalidator;
struct FileAvail : public FX_FILEAVAIL { struct FileAvail : public FX_FILEAVAIL {
...@@ -391,6 +411,9 @@ class PDFiumEngine : public PDFEngine, ...@@ -391,6 +411,9 @@ class PDFiumEngine : public PDFEngine,
// Called when the selection changes. // Called when the selection changes.
void OnSelectionChanged(); void OnSelectionChanged();
// Common code shared by RotateClockwise() and RotateCounterclockwise().
void RotateInternal();
// FPDF_FORMFILLINFO callbacks. // FPDF_FORMFILLINFO callbacks.
static void Form_Invalidate(FPDF_FORMFILLINFO* param, static void Form_Invalidate(FPDF_FORMFILLINFO* param,
FPDF_PAGE page, FPDF_PAGE page,
...@@ -540,9 +563,9 @@ class PDFiumEngine : public PDFEngine, ...@@ -540,9 +563,9 @@ class PDFiumEngine : public PDFEngine,
int last_page_to_search_; int last_page_to_search_;
int last_character_index_to_search_; // -1 if search until end of page. int last_character_index_to_search_; // -1 if search until end of page.
// Which result the user has currently selected. // Which result the user has currently selected.
int current_find_index_; FindTextIndex current_find_index_;
// Where to resume searching. // Where to resume searching.
int resume_find_index_; FindTextIndex resume_find_index_;
// Permissions bitfield. // Permissions bitfield.
unsigned long permissions_; unsigned long permissions_;
......
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