Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(500)

Side by Side Diff: pdf/pdfium/pdfium_engine.cc

Issue 691273003: PDF: Fix potential bad indexes in find results. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: self review Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« pdf/pdfium/pdfium_engine.h ('K') | « pdf/pdfium/pdfium_engine.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "pdf/pdfium/pdfium_engine.h" 5 #include "pdf/pdfium/pdfium_engine.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 8
9 #include "base/json/json_writer.h" 9 #include "base/json/json_writer.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 password_tries_remaining_(0), 559 password_tries_remaining_(0),
560 doc_(NULL), 560 doc_(NULL),
561 form_(NULL), 561 form_(NULL),
562 defer_page_unload_(false), 562 defer_page_unload_(false),
563 selecting_(false), 563 selecting_(false),
564 mouse_down_state_(PDFiumPage::NONSELECTABLE_AREA, 564 mouse_down_state_(PDFiumPage::NONSELECTABLE_AREA,
565 PDFiumPage::LinkTarget()), 565 PDFiumPage::LinkTarget()),
566 next_page_to_search_(-1), 566 next_page_to_search_(-1),
567 last_page_to_search_(-1), 567 last_page_to_search_(-1),
568 last_character_index_to_search_(-1), 568 last_character_index_to_search_(-1),
569 current_find_index_(-1),
570 resume_find_index_(-1),
571 permissions_(0), 569 permissions_(0),
572 fpdf_availability_(NULL), 570 fpdf_availability_(NULL),
573 next_timer_id_(0), 571 next_timer_id_(0),
574 last_page_mouse_down_(-1), 572 last_page_mouse_down_(-1),
575 first_visible_page_(-1), 573 first_visible_page_(-1),
576 most_visible_page_(-1), 574 most_visible_page_(-1),
577 called_do_document_action_(false), 575 called_do_document_action_(false),
578 render_grayscale_(false), 576 render_grayscale_(false),
579 progressive_paint_timeout_(0), 577 progressive_paint_timeout_(0),
580 getting_password_(false) { 578 getting_password_(false) {
(...skipping 1098 matching lines...) Expand 10 before | Expand all | Expand 10 after
1679 // Started midway, but only 1 page and we already looped around. 1677 // Started midway, but only 1 page and we already looped around.
1680 (pages_.size() == 1 && !first_search) || 1678 (pages_.size() == 1 && !first_search) ||
1681 // Started midway, and we've just looped around. 1679 // Started midway, and we've just looped around.
1682 (pages_.size() > 1 && current_page == next_page_to_search_)); 1680 (pages_.size() > 1 && current_page == next_page_to_search_));
1683 1681
1684 if (end_of_search) { 1682 if (end_of_search) {
1685 // Send the final notification. 1683 // Send the final notification.
1686 client_->NotifyNumberOfFindResultsChanged(find_results_.size(), true); 1684 client_->NotifyNumberOfFindResultsChanged(find_results_.size(), true);
1687 1685
1688 // When searching is complete, resume finding at a particular index. 1686 // When searching is complete, resume finding at a particular index.
1689 if (resume_find_index_ != -1) { 1687 // Assuming the user has not clicked the find button in the meanwhile.
1690 current_find_index_ = resume_find_index_; 1688 if (resume_find_index_.valid() && !current_find_index_.valid()) {
1691 resume_find_index_ = -1; 1689 size_t resume_index = resume_find_index_.GetIndex();
1690 if (resume_index >= find_results_.size()) {
1691 // This might happen if the PDF has some dynamically generated text?
1692 resume_index = 0;
1693 }
1694 current_find_index_.SetIndex(resume_index);
1695 client_->NotifySelectedFindResultChanged(resume_index);
1692 } 1696 }
1697 resume_find_index_.Invalidate();
1693 } else { 1698 } else {
1694 pp::CompletionCallback callback = 1699 pp::CompletionCallback callback =
1695 find_factory_.NewCallback(&PDFiumEngine::ContinueFind); 1700 find_factory_.NewCallback(&PDFiumEngine::ContinueFind);
1696 pp::Module::Get()->core()->CallOnMainThread( 1701 pp::Module::Get()->core()->CallOnMainThread(
1697 0, callback, case_sensitive ? 1 : 0); 1702 0, callback, case_sensitive ? 1 : 0);
1698 } 1703 }
1699 } 1704 }
1700 1705
1701 void PDFiumEngine::SearchUsingPDFium(const base::string16& term, 1706 void PDFiumEngine::SearchUsingPDFium(const base::string16& term,
1702 bool case_sensitive, 1707 bool case_sensitive,
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
1765 int end = FPDFText_GetCharIndexFromTextIndex( 1770 int end = FPDFText_GetCharIndexFromTextIndex(
1766 pages_[current_page]->GetTextPage(), 1771 pages_[current_page]->GetTextPage(),
1767 temp_start + results[i].length); 1772 temp_start + results[i].length);
1768 AddFindResult(PDFiumRange(pages_[current_page], start, end - start)); 1773 AddFindResult(PDFiumRange(pages_[current_page], start, end - start));
1769 } 1774 }
1770 } 1775 }
1771 1776
1772 void PDFiumEngine::AddFindResult(const PDFiumRange& result) { 1777 void PDFiumEngine::AddFindResult(const PDFiumRange& result) {
1773 // Figure out where to insert the new location, since we could have 1778 // Figure out where to insert the new location, since we could have
1774 // started searching midway and now we wrapped. 1779 // started searching midway and now we wrapped.
1775 size_t i; 1780 size_t result_index;
1776 int page_index = result.page_index(); 1781 int page_index = result.page_index();
1777 int char_index = result.char_index(); 1782 int char_index = result.char_index();
1778 for (i = 0; i < find_results_.size(); ++i) { 1783 for (result_index = 0; result_index < find_results_.size(); ++result_index) {
1779 if (find_results_[i].page_index() > page_index || 1784 if (find_results_[result_index].page_index() > page_index ||
1780 (find_results_[i].page_index() == page_index && 1785 (find_results_[result_index].page_index() == page_index &&
1781 find_results_[i].char_index() > char_index)) { 1786 find_results_[result_index].char_index() > char_index)) {
1782 break; 1787 break;
1783 } 1788 }
1784 } 1789 }
1785 find_results_.insert(find_results_.begin() + i, result); 1790 find_results_.insert(find_results_.begin() + result_index, result);
1786 UpdateTickMarks(); 1791 UpdateTickMarks();
1787 1792
1788 if (current_find_index_ == -1 && resume_find_index_ == -1) { 1793 if (current_find_index_.valid()) {
1789 // Select the first match. 1794 if (result_index <= current_find_index_.GetIndex()) {
1795 // Update the current match index
1796 size_t find_index = current_find_index_.IncrementIndex();
raymes 2014/11/03 05:17:30 It might be a bit simpler to just have IncrementIn
Lei Zhang 2014/11/03 23:25:41 It's not that much more work. void IncrementIndex(
1797 DCHECK_LT(find_index, find_results_.size());
1798 client_->NotifySelectedFindResultChanged(current_find_index_.GetIndex());
1799 }
1800 } else if (!resume_find_index_.valid()) {
1801 // Both indices are invalid. Select the first match.
1790 SelectFindResult(true); 1802 SelectFindResult(true);
1791 } else if (static_cast<int>(i) <= current_find_index_) {
1792 // Update the current match index
1793 current_find_index_++;
1794 client_->NotifySelectedFindResultChanged(current_find_index_);
1795 } 1803 }
1796 client_->NotifyNumberOfFindResultsChanged(find_results_.size(), false); 1804 client_->NotifyNumberOfFindResultsChanged(find_results_.size(), false);
1797 } 1805 }
1798 1806
1799 bool PDFiumEngine::SelectFindResult(bool forward) { 1807 bool PDFiumEngine::SelectFindResult(bool forward) {
1800 if (find_results_.empty()) { 1808 if (find_results_.empty()) {
1801 NOTREACHED(); 1809 NOTREACHED();
1802 return false; 1810 return false;
1803 } 1811 }
1804 1812
1805 SelectionChangeInvalidator selection_invalidator(this); 1813 SelectionChangeInvalidator selection_invalidator(this);
1806 1814
1807 // Move back/forward through the search locations we previously found. 1815 // Move back/forward through the search locations we previously found.
1808 if (forward) { 1816 size_t new_index;
1809 if (++current_find_index_ == static_cast<int>(find_results_.size())) 1817 const size_t last_index = find_results_.size() - 1;
1810 current_find_index_ = 0; 1818 if (current_find_index_.valid()) {
1819 size_t current_index = current_find_index_.GetIndex();
1820 if (forward) {
1821 new_index = (current_index >= last_index) ? 0 : current_index + 1;
1822 } else {
1823 new_index = (current_find_index_.GetIndex() == 0) ?
1824 last_index : current_index - 1;
1825 }
raymes 2014/11/03 05:17:31 optional: Alternatively I guess you could have Inc
Lei Zhang 2014/11/03 23:25:42 The class doesn't know about the size of |find_res
1811 } else { 1826 } else {
1812 if (--current_find_index_ < 0) { 1827 new_index = forward ? 0 : last_index;
1813 current_find_index_ = find_results_.size() - 1;
1814 }
1815 } 1828 }
1829 current_find_index_.SetIndex(new_index);
1816 1830
1817 // Update the selection before telling the client to scroll, since it could 1831 // Update the selection before telling the client to scroll, since it could
1818 // paint then. 1832 // paint then.
1819 selection_.clear(); 1833 selection_.clear();
1820 selection_.push_back(find_results_[current_find_index_]); 1834 if (current_find_index_.valid()) {
raymes 2014/11/03 05:17:30 Since we call SetIndex right above, won't this alw
Lei Zhang 2014/11/03 23:25:41 Indeed it is.
1835 selection_.push_back(find_results_[current_find_index_.GetIndex()]);
1821 1836
1822 // If the result is not in view, scroll to it. 1837 // If the result is not in view, scroll to it.
1823 size_t i; 1838 pp::Rect bounding_rect;
1824 pp::Rect bounding_rect; 1839 pp::Rect visible_rect = GetVisibleRect();
1825 pp::Rect visible_rect = GetVisibleRect(); 1840 // Use zoom of 1.0 since visible_rect is without zoom.
1826 // Use zoom of 1.0 since visible_rect is without zoom. 1841 std::vector<pp::Rect> rects;
1827 std::vector<pp::Rect> rects = find_results_[current_find_index_]. 1842 rects = find_results_[current_find_index_.GetIndex()].GetScreenRects(
1828 GetScreenRects(pp::Point(), 1.0, current_rotation_); 1843 pp::Point(), 1.0, current_rotation_);
1829 for (i = 0; i < rects.size(); ++i) 1844 for (size_t i = 0; i < rects.size(); ++i)
1830 bounding_rect = bounding_rect.Union(rects[i]); 1845 bounding_rect = bounding_rect.Union(rects[i]);
1831 if (!visible_rect.Contains(bounding_rect)) { 1846 if (!visible_rect.Contains(bounding_rect)) {
1832 pp::Point center = bounding_rect.CenterPoint(); 1847 pp::Point center = bounding_rect.CenterPoint();
1833 // Make the page centered. 1848 // Make the page centered.
1834 int new_y = static_cast<int>(center.y() * current_zoom_) - 1849 int new_y = static_cast<int>(center.y() * current_zoom_) -
1835 static_cast<int>(visible_rect.height() * current_zoom_ / 2); 1850 static_cast<int>(visible_rect.height() * current_zoom_ / 2);
1836 if (new_y < 0) 1851 if (new_y < 0)
1837 new_y = 0; 1852 new_y = 0;
1838 client_->ScrollToY(new_y); 1853 client_->ScrollToY(new_y);
1839 1854
1840 // Only move horizontally if it's not visible. 1855 // Only move horizontally if it's not visible.
1841 if (center.x() < visible_rect.x() || center.x() > visible_rect.right()) { 1856 if (center.x() < visible_rect.x() || center.x() > visible_rect.right()) {
1842 int new_x = static_cast<int>(center.x() * current_zoom_) - 1857 int new_x = static_cast<int>(center.x() * current_zoom_) -
1843 static_cast<int>(visible_rect.width() * current_zoom_ / 2); 1858 static_cast<int>(visible_rect.width() * current_zoom_ / 2);
1844 if (new_x < 0) 1859 if (new_x < 0)
1845 new_x = 0; 1860 new_x = 0;
1846 client_->ScrollToX(new_x); 1861 client_->ScrollToX(new_x);
1862 }
1847 } 1863 }
1864
1865 client_->NotifySelectedFindResultChanged(current_find_index_.GetIndex());
1848 } 1866 }
1849 1867
1850 client_->NotifySelectedFindResultChanged(current_find_index_);
1851
1852 return true; 1868 return true;
1853 } 1869 }
1854 1870
1855 void PDFiumEngine::StopFind() { 1871 void PDFiumEngine::StopFind() {
1856 SelectionChangeInvalidator selection_invalidator(this); 1872 SelectionChangeInvalidator selection_invalidator(this);
1857 1873
1858 selection_.clear(); 1874 selection_.clear();
1859 selecting_ = false; 1875 selecting_ = false;
1860 find_results_.clear(); 1876 find_results_.clear();
1861 next_page_to_search_ = -1; 1877 next_page_to_search_ = -1;
1862 last_page_to_search_ = -1; 1878 last_page_to_search_ = -1;
1863 last_character_index_to_search_ = -1; 1879 last_character_index_to_search_ = -1;
1864 current_find_index_ = -1; 1880 current_find_index_.Invalidate();
1865 current_find_text_.clear(); 1881 current_find_text_.clear();
1866 UpdateTickMarks(); 1882 UpdateTickMarks();
1867 find_factory_.CancelAll(); 1883 find_factory_.CancelAll();
1868 } 1884 }
1869 1885
1870 void PDFiumEngine::UpdateTickMarks() { 1886 void PDFiumEngine::UpdateTickMarks() {
1871 std::vector<pp::Rect> tickmarks; 1887 std::vector<pp::Rect> tickmarks;
1872 for (size_t i = 0; i < find_results_.size(); ++i) { 1888 for (size_t i = 0; i < find_results_.size(); ++i) {
1873 pp::Rect rect; 1889 pp::Rect rect;
1874 // Always use an origin of 0,0 since scroll positions don't affect tickmark. 1890 // Always use an origin of 0,0 since scroll positions don't affect tickmark.
(...skipping 11 matching lines...) Expand all
1886 CancelPaints(); 1902 CancelPaints();
1887 1903
1888 current_zoom_ = new_zoom_level; 1904 current_zoom_ = new_zoom_level;
1889 1905
1890 CalculateVisiblePages(); 1906 CalculateVisiblePages();
1891 UpdateTickMarks(); 1907 UpdateTickMarks();
1892 } 1908 }
1893 1909
1894 void PDFiumEngine::RotateClockwise() { 1910 void PDFiumEngine::RotateClockwise() {
1895 current_rotation_ = (current_rotation_ + 1) % 4; 1911 current_rotation_ = (current_rotation_ + 1) % 4;
1896 1912 RotateInternal();
1897 // Store the current find index so that we can resume finding at that
1898 // particular index after we have recomputed the find results.
1899 std::string current_find_text = current_find_text_;
1900 resume_find_index_ = current_find_index_;
1901
1902 InvalidateAllPages();
1903
1904 if (!current_find_text.empty())
1905 StartFind(current_find_text.c_str(), false);
1906 } 1913 }
1907 1914
1908 void PDFiumEngine::RotateCounterclockwise() { 1915 void PDFiumEngine::RotateCounterclockwise() {
1909 current_rotation_ = (current_rotation_ - 1) % 4; 1916 current_rotation_ = (current_rotation_ - 1) % 4;
1910 1917 RotateInternal();
1911 // Store the current find index so that we can resume finding at that
1912 // particular index after we have recomputed the find results.
1913 std::string current_find_text = current_find_text_;
1914 resume_find_index_ = current_find_index_;
1915
1916 InvalidateAllPages();
1917
1918 if (!current_find_text.empty())
1919 StartFind(current_find_text.c_str(), false);
1920 } 1918 }
1921 1919
1922 void PDFiumEngine::InvalidateAllPages() { 1920 void PDFiumEngine::InvalidateAllPages() {
1923 CancelPaints(); 1921 CancelPaints();
1924 StopFind(); 1922 StopFind();
1925 LoadPageInfo(true); 1923 LoadPageInfo(true);
1926 client_->Invalidate(pp::Rect(plugin_size_)); 1924 client_->Invalidate(pp::Rect(plugin_size_));
1927 } 1925 }
1928 1926
1929 std::string PDFiumEngine::GetSelectedText() { 1927 std::string PDFiumEngine::GetSelectedText() {
(...skipping 872 matching lines...) Expand 10 before | Expand all | Expand 10 after
2802 if (area_ == area) { 2800 if (area_ == area) {
2803 if (area == PDFiumPage::WEBLINK_AREA) 2801 if (area == PDFiumPage::WEBLINK_AREA)
2804 return target_.url == target.url; 2802 return target_.url == target.url;
2805 if (area == PDFiumPage::DOCLINK_AREA) 2803 if (area == PDFiumPage::DOCLINK_AREA)
2806 return target_.page == target.page; 2804 return target_.page == target.page;
2807 return true; 2805 return true;
2808 } 2806 }
2809 return false; 2807 return false;
2810 } 2808 }
2811 2809
2810 PDFiumEngine::FindTextData::FindTextData()
2811 : valid_(false), index_(0) {
2812 }
2813
2814 PDFiumEngine::FindTextData::~FindTextData() {
2815 }
2816
2817 void PDFiumEngine::FindTextData::Invalidate() {
2818 valid_ = false;
2819 }
2820
2821 size_t PDFiumEngine::FindTextData::GetIndex() const {
2822 DCHECK(valid_);
2823 return index_;
2824 }
2825
2826 void PDFiumEngine::FindTextData::SetIndex(size_t index) {
2827 valid_ = true;
2828 index_ = index;
2829 }
2830
2831 size_t PDFiumEngine::FindTextData::IncrementIndex() {
2832 DCHECK(valid_);
2833 return ++index_;
2834 }
2835
2812 void PDFiumEngine::DeviceToPage(int page_index, 2836 void PDFiumEngine::DeviceToPage(int page_index,
2813 float device_x, 2837 float device_x,
2814 float device_y, 2838 float device_y,
2815 double* page_x, 2839 double* page_x,
2816 double* page_y) { 2840 double* page_y) {
2817 *page_x = *page_y = 0; 2841 *page_x = *page_y = 0;
2818 int temp_x = static_cast<int>((device_x + position_.x())/ current_zoom_ - 2842 int temp_x = static_cast<int>((device_x + position_.x())/ current_zoom_ -
2819 pages_[page_index]->rect().x()); 2843 pages_[page_index]->rect().x());
2820 int temp_y = static_cast<int>((device_y + position_.y())/ current_zoom_ - 2844 int temp_y = static_cast<int>((device_y + position_.y())/ current_zoom_ -
2821 pages_[page_index]->rect().y()); 2845 pages_[page_index]->rect().y());
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
2981 buffer += location.y() * (*stride); 3005 buffer += location.y() * (*stride);
2982 buffer += (location.x() + page_offset_.x()) * 4; 3006 buffer += (location.x() + page_offset_.x()) * 4;
2983 *region = buffer; 3007 *region = buffer;
2984 } 3008 }
2985 3009
2986 void PDFiumEngine::OnSelectionChanged() { 3010 void PDFiumEngine::OnSelectionChanged() {
2987 if (HasPermission(PDFEngine::PERMISSION_COPY)) 3011 if (HasPermission(PDFEngine::PERMISSION_COPY))
2988 pp::PDF::SetSelectedText(GetPluginInstance(), GetSelectedText().c_str()); 3012 pp::PDF::SetSelectedText(GetPluginInstance(), GetSelectedText().c_str());
2989 } 3013 }
2990 3014
3015 void PDFiumEngine::RotateInternal() {
3016 // Store the current find index so that we can resume finding at that
3017 // particular index after we have recomputed the find results.
3018 std::string current_find_text = current_find_text_;
3019 if (current_find_index_.valid())
3020 resume_find_index_.SetIndex(current_find_index_.GetIndex());
3021 else
3022 resume_find_index_.Invalidate();
3023
3024 InvalidateAllPages();
3025
3026 if (!current_find_text.empty()) {
3027 // Clear the UI.
3028 client_->NotifyNumberOfFindResultsChanged(0, false);
3029 StartFind(current_find_text.c_str(), false);
3030 }
3031 }
3032
2991 void PDFiumEngine::Form_Invalidate(FPDF_FORMFILLINFO* param, 3033 void PDFiumEngine::Form_Invalidate(FPDF_FORMFILLINFO* param,
2992 FPDF_PAGE page, 3034 FPDF_PAGE page,
2993 double left, 3035 double left,
2994 double top, 3036 double top,
2995 double right, 3037 double right,
2996 double bottom) { 3038 double bottom) {
2997 PDFiumEngine* engine = static_cast<PDFiumEngine*>(param); 3039 PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
2998 int page_index = engine->GetVisiblePageIndex(page); 3040 int page_index = engine->GetVisiblePageIndex(page);
2999 if (page_index == -1) { 3041 if (page_index == -1) {
3000 // This can sometime happen when the page is closed because it went off 3042 // This can sometime happen when the page is closed because it went off
(...skipping 535 matching lines...) Expand 10 before | Expand all | Expand 10 after
3536 double* height) { 3578 double* height) {
3537 FPDF_DOCUMENT doc = FPDF_LoadMemDocument(pdf_buffer, pdf_buffer_size, NULL); 3579 FPDF_DOCUMENT doc = FPDF_LoadMemDocument(pdf_buffer, pdf_buffer_size, NULL);
3538 if (!doc) 3580 if (!doc)
3539 return false; 3581 return false;
3540 bool success = FPDF_GetPageSizeByIndex(doc, page_number, width, height) != 0; 3582 bool success = FPDF_GetPageSizeByIndex(doc, page_number, width, height) != 0;
3541 FPDF_CloseDocument(doc); 3583 FPDF_CloseDocument(doc);
3542 return success; 3584 return success;
3543 } 3585 }
3544 3586
3545 } // namespace chrome_pdf 3587 } // namespace chrome_pdf
OLDNEW
« pdf/pdfium/pdfium_engine.h ('K') | « pdf/pdfium/pdfium_engine.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698