From d17ea114e5ef69ad5d5d7413280a13e6428098aa Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 15 May 2018 10:20:33 +0200 Subject: BASELINE: Update Chromium to 67.0.3396.47 Change-Id: Idcb1341782e417561a2473eeecc82642dafda5b7 Reviewed-by: Michal Klocek --- chromium/pdf/BUILD.gn | 7 +- chromium/pdf/DEPS | 2 + chromium/pdf/OWNERS | 1 + chromium/pdf/chunk_stream.h | 32 +-- chromium/pdf/document_loader.cc | 88 +++++--- chromium/pdf/document_loader.h | 17 +- chromium/pdf/out_of_process_instance.cc | 60 +++--- chromium/pdf/out_of_process_instance.h | 7 +- chromium/pdf/pdf.cc | 10 +- chromium/pdf/pdf.h | 8 +- chromium/pdf/pdf_engine.h | 21 +- chromium/pdf/pdf_transform.cc | 139 ++++++++++++ chromium/pdf/pdf_transform.h | 100 +++++++++ chromium/pdf/pdf_transform_unittest.cc | 335 ++++++++++++++++++++++++++++ chromium/pdf/pdfium/DEPS | 3 - chromium/pdf/pdfium/fuzzers/BUILD.gn | 9 - chromium/pdf/pdfium/pdfium_engine.cc | 372 ++++++++++++++++++++++---------- chromium/pdf/pdfium/pdfium_engine.h | 22 +- chromium/pdf/pdfium/pdfium_range.cc | 47 ++-- chromium/pdf/pdfium/pdfium_range.h | 2 +- chromium/pdf/preview_mode_client.cc | 13 +- chromium/pdf/preview_mode_client.h | 7 +- chromium/pdf/run_all_unittests.cc | 2 +- 23 files changed, 1072 insertions(+), 232 deletions(-) create mode 100644 chromium/pdf/pdf_transform.cc create mode 100644 chromium/pdf/pdf_transform.h create mode 100644 chromium/pdf/pdf_transform_unittest.cc (limited to 'chromium/pdf') diff --git a/chromium/pdf/BUILD.gn b/chromium/pdf/BUILD.gn index 6d46f53b399..c5afc0833b5 100644 --- a/chromium/pdf/BUILD.gn +++ b/chromium/pdf/BUILD.gn @@ -10,8 +10,8 @@ import("//testing/test.gni") import("//third_party/pdfium/pdfium.gni") # Generate a buildflag header for compile-time checking of PDF support. -buildflag_header("features") { - header = "features.h" +buildflag_header("buildflags") { + header = "buildflags.h" flags = [ "ENABLE_PDF=$enable_pdf" ] } @@ -52,6 +52,8 @@ if (enable_pdf) { "pdf_engine.h", "pdf_ppapi.cc", "pdf_ppapi.h", + "pdf_transform.cc", + "pdf_transform.h", "preview_mode_client.cc", "preview_mode_client.h", "range_set.cc", @@ -102,6 +104,7 @@ if (enable_pdf) { sources = [ "chunk_stream_unittest.cc", "document_loader_unittest.cc", + "pdf_transform_unittest.cc", "range_set_unittest.cc", "run_all_unittests.cc", ] diff --git a/chromium/pdf/DEPS b/chromium/pdf/DEPS index 6e45472268d..36bce0d849a 100644 --- a/chromium/pdf/DEPS +++ b/chromium/pdf/DEPS @@ -2,9 +2,11 @@ include_rules = [ "+chrome/common/content_restriction.h", "+net", "+ppapi", + "+printing/units.h", "+ui/base/window_open_disposition.h", "+ui/events/keycodes/keyboard_codes.h", "+ui/gfx/geometry/point_f.h", + "+ui/gfx/geometry/rect.h", "+ui/gfx/range/range.h", "+v8/include/v8.h" ] diff --git a/chromium/pdf/OWNERS b/chromium/pdf/OWNERS index f9f754215c0..1b70ae55ba7 100644 --- a/chromium/pdf/OWNERS +++ b/chromium/pdf/OWNERS @@ -1,4 +1,5 @@ dsinclair@chromium.org +hnakashima@chromium.org jochen@chromium.org thestig@chromium.org diff --git a/chromium/pdf/chunk_stream.h b/chromium/pdf/chunk_stream.h index b8b3c831e90..7eb75cf61b8 100644 --- a/chromium/pdf/chunk_stream.h +++ b/chromium/pdf/chunk_stream.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "pdf/range_set.h" @@ -31,20 +32,21 @@ class ChunkStream { void SetChunkData(uint32_t chunk_index, std::unique_ptr data) { if (!data) return; - if (chunk_index >= data_.size()) { + + if (chunk_index >= data_.size()) data_.resize(chunk_index + 1); - } - if (!data_[chunk_index]) { + + if (!data_[chunk_index]) ++filled_chunks_count_; - } + data_[chunk_index] = std::move(data); filled_chunks_.Union(gfx::Range(chunk_index, chunk_index + 1)); } bool ReadData(const gfx::Range& range, void* buffer) const { - if (!IsRangeAvailable(range)) { + if (!IsRangeAvailable(range)) return false; - } + unsigned char* data_buffer = static_cast(buffer); uint32_t start = range.start(); while (start != range.end()) { @@ -62,18 +64,20 @@ class ChunkStream { uint32_t GetChunkIndex(uint32_t offset) const { return offset / kChunkSize; } gfx::Range GetChunksRange(uint32_t offset, uint32_t size) const { - return gfx::Range(GetChunkIndex(offset), - GetChunkIndex(offset + size + kChunkSize - 1)); + return gfx::Range(GetChunkIndex(offset), GetChunkEnd(offset + size)); } bool IsRangeAvailable(const gfx::Range& range) const { if (!range.IsValid() || range.is_reversed() || - (eof_pos_ > 0 && eof_pos_ < range.end())) + (eof_pos_ > 0 && eof_pos_ < range.end())) { return false; + } + if (range.is_empty()) return true; + const gfx::Range chunks_range(GetChunkIndex(range.start()), - GetChunkIndex(range.end() + kChunkSize - 1)); + GetChunkEnd(range.end())); return filled_chunks_.Contains(chunks_range); } @@ -94,11 +98,13 @@ class ChunkStream { } uint32_t filled_chunks_count() const { return filled_chunks_count_; } - uint32_t total_chunks_count() const { - return GetChunkIndex(eof_pos_ + kChunkSize - 1); - } + uint32_t total_chunks_count() const { return GetChunkEnd(eof_pos_); } private: + uint32_t GetChunkEnd(uint32_t offset) const { + return (offset + kChunkSize - 1) / kChunkSize; + } + std::vector> data_; uint32_t eof_pos_ = 0; RangeSet filled_chunks_; diff --git a/chromium/pdf/document_loader.cc b/chromium/pdf/document_loader.cc index f8f89f55d36..23ed4ac83ac 100644 --- a/chromium/pdf/document_loader.cc +++ b/chromium/pdf/document_loader.cc @@ -98,16 +98,15 @@ bool DocumentLoader::Init(std::unique_ptr loader, url_ = url; loader_ = std::move(loader); - if (!loader_->IsContentEncoded()) { - chunk_stream_.set_eof_pos(std::max(0, loader_->GetContentLength())); - } + if (!loader_->IsContentEncoded()) + SetDocumentSize(std::max(0, loader_->GetContentLength())); + int64_t bytes_received = 0; int64_t total_bytes_to_be_received = 0; - if (!chunk_stream_.eof_pos() && + if (GetDocumentSize() == 0 && loader_->GetDownloadProgress(&bytes_received, &total_bytes_to_be_received)) { - chunk_stream_.set_eof_pos( - std::max(0, static_cast(total_bytes_to_be_received))); + SetDocumentSize(std::max(0, static_cast(total_bytes_to_be_received))); } SetPartialLoadingEnabled( @@ -124,6 +123,10 @@ bool DocumentLoader::IsDocumentComplete() const { return chunk_stream_.IsComplete(); } +void DocumentLoader::SetDocumentSize(uint32_t size) { + chunk_stream_.set_eof_pos(size); +} + uint32_t DocumentLoader::GetDocumentSize() const { return chunk_stream_.eof_pos(); } @@ -153,22 +156,22 @@ bool DocumentLoader::IsDataAvailable(uint32_t position, uint32_t size) const { } void DocumentLoader::RequestData(uint32_t position, uint32_t size) { - if (!size || IsDataAvailable(position, size)) { + if (size == 0 || IsDataAvailable(position, size)) return; - } - { - // Check integer overflow. + + const uint32_t document_size = GetDocumentSize(); + if (document_size != 0) { + // Check for integer overflow. base::CheckedNumeric addition_result = position; addition_result += size; if (!addition_result.IsValid()) return; - } - if (GetDocumentSize() && (position + size > GetDocumentSize())) { - return; + if (addition_result.ValueOrDie() > document_size) + return; } - // We have some artefact request from + // We have some artifact request from // PDFiumEngine::OnDocumentComplete() -> FPDFAvail_IsPageAvail after // document is complete. // We need this fix in PDFIum. Adding this as a work around. @@ -207,9 +210,10 @@ bool DocumentLoader::ShouldCancelLoading() const { void DocumentLoader::ContinueDownload() { if (!ShouldCancelLoading()) return ReadMore(); + DCHECK(partial_loading_enabled_); DCHECK(!IsDocumentComplete()); - DCHECK(GetDocumentSize()); + DCHECK_GT(GetDocumentSize(), 0U); const uint32_t range_start = pending_requests_.IsEmpty() ? 0 : pending_requests_.First().start(); @@ -241,7 +245,7 @@ void DocumentLoader::ContinueDownload() { const uint32_t start = next_request.start() * DataStream::kChunkSize; const uint32_t length = - std::min(chunk_stream_.eof_pos() - start, + std::min(GetDocumentSize() - start, next_request.length() * DataStream::kChunkSize); loader_ = client_->CreateURLLoader(); @@ -311,35 +315,37 @@ void DocumentLoader::DidRead(int32_t result) { DCHECK(!chunk_.chunk_data); chunk_.chunk_index = chunk_stream_.GetChunkIndex(start_pos); } - if (!SaveChunkData(buffer_, result)) + if (!SaveBuffer(buffer_, result)) return ReadMore(); if (IsDocumentComplete()) return ReadComplete(); return ContinueDownload(); } -bool DocumentLoader::SaveChunkData(char* input, uint32_t input_size) { - count_of_bytes_received_ += input_size; +bool DocumentLoader::SaveBuffer(char* input, uint32_t input_size) { + const uint32_t document_size = GetDocumentSize(); + if (document_size != 0) { + // If the HTTP server sends more data than expected, then truncate + // |input_size| to the expected size. + input_size = std::min(document_size - bytes_received_, input_size); + } + bytes_received_ += input_size; bool chunk_saved = false; bool loading_pending_request = pending_requests_.Contains(chunk_.chunk_index); while (input_size > 0) { - if (chunk_.data_size == 0) { + if (chunk_.data_size == 0) chunk_.chunk_data = std::make_unique(); - } + const uint32_t new_chunk_data_len = std::min(DataStream::kChunkSize - chunk_.data_size, input_size); memcpy(chunk_.chunk_data->data() + chunk_.data_size, input, new_chunk_data_len); chunk_.data_size += new_chunk_data_len; if (chunk_.data_size == DataStream::kChunkSize || - chunk_stream_.eof_pos() == - chunk_.chunk_index * DataStream::kChunkSize + chunk_.data_size) { - chunk_stream_.SetChunkData(chunk_.chunk_index, - std::move(chunk_.chunk_data)); + document_size == EndOfCurrentChunk()) { pending_requests_.Subtract( gfx::Range(chunk_.chunk_index, chunk_.chunk_index + 1)); - chunk_.data_size = 0; - ++(chunk_.chunk_index); + SaveChunkData(); chunk_saved = true; } @@ -362,20 +368,32 @@ bool DocumentLoader::SaveChunkData(char* input, uint32_t input_size) { return true; } +void DocumentLoader::SaveChunkData() { + chunk_stream_.SetChunkData(chunk_.chunk_index, std::move(chunk_.chunk_data)); + chunk_.data_size = 0; + ++chunk_.chunk_index; +} + +uint32_t DocumentLoader::EndOfCurrentChunk() const { + return chunk_.chunk_index * DataStream::kChunkSize + chunk_.data_size; +} + void DocumentLoader::ReadComplete() { - if (!GetDocumentSize()) { - uint32_t eof = - chunk_.chunk_index * DataStream::kChunkSize + chunk_.data_size; + if (GetDocumentSize() != 0) { + // If there is remaining data in |chunk_|, then save whatever can be saved. + // e.g. In the underrun case. + if (chunk_.data_size != 0) + SaveChunkData(); + } else { + uint32_t eof = EndOfCurrentChunk(); if (!chunk_stream_.filled_chunks().IsEmpty()) { eof = std::max( chunk_stream_.filled_chunks().Last().end() * DataStream::kChunkSize, eof); } - chunk_stream_.set_eof_pos(eof); - if (eof == chunk_.chunk_index * DataStream::kChunkSize + chunk_.data_size) { - chunk_stream_.SetChunkData(chunk_.chunk_index, - std::move(chunk_.chunk_data)); - } + SetDocumentSize(eof); + if (eof == EndOfCurrentChunk()) + SaveChunkData(); } loader_.reset(); if (IsDocumentComplete()) { diff --git a/chromium/pdf/document_loader.h b/chromium/pdf/document_loader.h index b8af158c06e..3df4f8ccf33 100644 --- a/chromium/pdf/document_loader.h +++ b/chromium/pdf/document_loader.h @@ -11,6 +11,7 @@ #include #include +#include "base/macros.h" #include "pdf/chunk_stream.h" #include "ppapi/utility/completion_callback_factory.h" @@ -62,8 +63,9 @@ class DocumentLoader { void RequestData(uint32_t position, uint32_t size); bool IsDocumentComplete() const; + void SetDocumentSize(uint32_t size); uint32_t GetDocumentSize() const; - uint32_t count_of_bytes_received() const { return count_of_bytes_received_; } + uint32_t bytes_received() const { return bytes_received_; } // Clear pending requests from the queue. void ClearPendingRequests(); @@ -97,7 +99,10 @@ class DocumentLoader { // Called when we complete server request. void ReadComplete(); - bool SaveChunkData(char* input, uint32_t input_size); + bool SaveBuffer(char* input, uint32_t input_size); + void SaveChunkData(); + + uint32_t EndOfCurrentChunk() const; Client* const client_; std::string url_; @@ -112,9 +117,15 @@ class DocumentLoader { static constexpr uint32_t kReadBufferSize = 256 * 1024; char buffer_[kReadBufferSize]; + // The current chunk DocumentLoader is working with. Chunk chunk_; + + // In units of Chunks. RangeSet pending_requests_; - uint32_t count_of_bytes_received_ = 0; + + uint32_t bytes_received_ = 0; + + DISALLOW_COPY_AND_ASSIGN(DocumentLoader); }; } // namespace chrome_pdf diff --git a/chromium/pdf/out_of_process_instance.cc b/chromium/pdf/out_of_process_instance.cc index a8d19d236d2..804971bc44d 100644 --- a/chromium/pdf/out_of_process_instance.cc +++ b/chromium/pdf/out_of_process_instance.cc @@ -112,6 +112,8 @@ const char kJSPreviewPageIndex[] = "index"; const char kJSSetScrollPositionType[] = "setScrollPosition"; const char kJSPositionX[] = "x"; const char kJSPositionY[] = "y"; +// Scroll by (Plugin -> Page) +const char kJSScrollByType[] = "scrollBy"; // Cancel the stream URL request (Plugin -> Page) const char kJSCancelStreamUrlType[] = "cancelStreamUrl"; // Navigate to the given URL (Plugin -> Page) @@ -323,24 +325,6 @@ void ScaleRect(float scale, pp::Rect* rect) { rect->SetRect(left, top, right - left, bottom - top); } -// TODO(raymes): Remove this dependency on VarPrivate/InstancePrivate. It's -// needed right now to do a synchronous call to JavaScript, but we could easily -// replace this with a custom PPB_PDF function. -pp::Var ModalDialog(const pp::Instance* instance, - const std::string& type, - const std::string& message, - const std::string& default_answer) { - const PPB_Instance_Private* ppb_interface = - reinterpret_cast( - pp::Module::Get()->GetBrowserInterface( - PPB_INSTANCE_PRIVATE_INTERFACE)); - pp::VarPrivate window( - pp::PASS_REF, ppb_interface->GetWindowObject(instance->pp_instance())); - if (default_answer.empty()) - return window.Call(type, message); - return window.Call(type, message, default_answer); -} - } // namespace OutOfProcessInstance::OutOfProcessInstance(PP_Instance instance) @@ -932,6 +916,12 @@ void OutOfProcessInstance::SendAccessibilityViewportInfo() { -top_toolbar_height_in_viewport_coords_ * device_scale_; viewport_info.offset = available_area_.point(); viewport_info.zoom = zoom_ * device_scale_; + + engine_->GetSelection(&viewport_info.selection_start_page_index, + &viewport_info.selection_start_char_index, + &viewport_info.selection_end_page_index, + &viewport_info.selection_end_char_index); + pp::PDF::SetAccessibilityViewportInfo(GetPluginInstance(), &viewport_info); } @@ -947,6 +937,8 @@ void OutOfProcessInstance::SelectionChanged(const pp::Rect& left, pp::PDF::SelectionChanged(GetPluginInstance(), PP_MakeFloatPoint(l.x(), l.y()), left.height(), PP_MakeFloatPoint(r.x(), r.y()), right.height()); + if (accessibility_state_ == ACCESSIBILITY_STATE_LOADED) + SendAccessibilityViewportInfo(); } void OutOfProcessInstance::SetCaretPosition(const pp::FloatPoint& position) { @@ -1226,11 +1218,9 @@ void OutOfProcessInstance::Invalidate(const pp::Rect& rect) { paint_manager_.InvalidateRect(offset_rect); } -void OutOfProcessInstance::Scroll(const pp::Point& point) { - if (!image_data_.is_null()) { +void OutOfProcessInstance::DidScroll(const pp::Point& point) { + if (!image_data_.is_null()) paint_manager_.ScrollRect(available_area_, point); - pp::PDF::DidScroll(GetPluginInstance()); - } } void OutOfProcessInstance::ScrollToX(int x_in_screen_coords) { @@ -1252,6 +1242,14 @@ void OutOfProcessInstance::ScrollToY(int y_in_screen_coords, PostMessage(position); } +void OutOfProcessInstance::ScrollBy(const pp::Point& point) { + pp::VarDictionary position; + position.Set(kType, kJSScrollByType); + position.Set(kJSPositionX, pp::Var(point.x() / device_scale_)); + position.Set(kJSPositionY, pp::Var(point.y() / device_scale_)); + PostMessage(position); +} + void OutOfProcessInstance::ScrollToPage(int page) { if (engine_->GetNumberOfPages() == 0) return; @@ -1367,17 +1365,17 @@ void OutOfProcessInstance::GetDocumentPassword( } void OutOfProcessInstance::Alert(const std::string& message) { - ModalDialog(this, "alert", message, std::string()); + pp::PDF::ShowAlertDialog(this, message.c_str()); } bool OutOfProcessInstance::Confirm(const std::string& message) { - pp::Var result = ModalDialog(this, "confirm", message, std::string()); - return result.is_bool() ? result.AsBool() : false; + return pp::PDF::ShowConfirmDialog(this, message.c_str()); } std::string OutOfProcessInstance::Prompt(const std::string& question, const std::string& default_answer) { - pp::Var result = ModalDialog(this, "prompt", question, default_answer); + pp::Var result = + pp::PDF::ShowPromptDialog(this, question.c_str(), default_answer.c_str()); return result.is_string() ? result.AsString() : std::string(); } @@ -1500,7 +1498,8 @@ OutOfProcessInstance::SearchString(const base::char16* string, void OutOfProcessInstance::DocumentPaintOccurred() {} void OutOfProcessInstance::DocumentLoadComplete( - const PDFEngine::DocumentFeatures& document_features) { + const PDFEngine::DocumentFeatures& document_features, + uint32_t file_size) { // Clear focus state for OSK. FormTextFieldFocusChange(false); @@ -1565,6 +1564,9 @@ void OutOfProcessInstance::DocumentLoadComplete( } pp::PDF::SetContentRestriction(this, content_restrictions); + static const int32_t kMaxFileSizeInKB = 12 * 1024 * 1024; + HistogramCustomCounts("PDF.FileSizeInKB", file_size / 1024, 0, + kMaxFileSizeInKB, 50); HistogramCustomCounts("PDF.PageCount", document_features.page_count, 1, 1000000, 50); HistogramEnumeration("PDF.HasAttachment", @@ -1813,6 +1815,10 @@ void OutOfProcessInstance::IsEditModeChanged(bool is_edit_mode) { PostMessage(message); } +float OutOfProcessInstance::GetToolbarHeightInScreenCoords() { + return top_toolbar_height_in_viewport_coords_ * device_scale_; +} + void OutOfProcessInstance::ProcessPreviewPageInfo(const std::string& url, int dest_page_index) { DCHECK(IsPrintPreview()); diff --git a/chromium/pdf/out_of_process_instance.h b/chromium/pdf/out_of_process_instance.h index 99b58b2a46b..654623f941b 100644 --- a/chromium/pdf/out_of_process_instance.h +++ b/chromium/pdf/out_of_process_instance.h @@ -98,9 +98,10 @@ class OutOfProcessInstance : public pp::Instance, // PDFEngine::Client implementation. void DocumentSizeUpdated(const pp::Size& size) override; void Invalidate(const pp::Rect& rect) override; - void Scroll(const pp::Point& point) override; + void DidScroll(const pp::Point& point) override; void ScrollToX(int x_in_screen_coords) override; void ScrollToY(int y_in_screen_coords, bool compensate_for_toolbar) override; + void ScrollBy(const pp::Point& point) override; void ScrollToPage(int page) override; void NavigateTo(const std::string& url, WindowOpenDisposition disposition) override; @@ -134,7 +135,8 @@ class OutOfProcessInstance : public pp::Instance, bool case_sensitive) override; void DocumentPaintOccurred() override; void DocumentLoadComplete( - const PDFEngine::DocumentFeatures& document_features) override; + const PDFEngine::DocumentFeatures& document_features, + uint32_t file_size) override; void DocumentLoadFailed() override; void FontSubstituted() override; pp::Instance* GetPluginInstance() override; @@ -147,6 +149,7 @@ class OutOfProcessInstance : public pp::Instance, void IsSelectingChanged(bool is_selecting) override; void SelectionChanged(const pp::Rect& left, const pp::Rect& right) override; void IsEditModeChanged(bool is_edit_mode) override; + float GetToolbarHeightInScreenCoords() override; // PreviewModeClient::Client implementation. void PreviewDocumentLoadComplete() override; diff --git a/chromium/pdf/pdf.cc b/chromium/pdf/pdf.cc index ea9df891797..e4583f5250a 100644 --- a/chromium/pdf/pdf.cc +++ b/chromium/pdf/pdf.cc @@ -31,7 +31,8 @@ bool RenderPDFPageToDC(const void* pdf_buffer, bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds, - bool autorotate) { + bool autorotate, + bool use_color) { if (!IsSDKInitializedViaPepper()) { if (!InitializeSDK()) { return false; @@ -42,7 +43,7 @@ bool RenderPDFPageToDC(const void* pdf_buffer, dpi_x, dpi_y, pp::Rect(bounds_origin_x, bounds_origin_y, bounds_width, bounds_height), fit_to_bounds, stretch_to_bounds, keep_aspect_ratio, center_in_bounds, - autorotate); + autorotate, use_color); bool ret = engine_exports->RenderPDFPageToDC(pdf_buffer, buffer_size, page_number, settings, dc); if (!IsSDKInitializedViaPepper()) @@ -108,7 +109,8 @@ bool RenderPDFPageToBitmap(const void* pdf_buffer, int bitmap_height, int dpi_x, int dpi_y, - bool autorotate) { + bool autorotate, + bool use_color) { if (!IsSDKInitializedViaPepper()) { if (!InitializeSDK()) return false; @@ -116,7 +118,7 @@ bool RenderPDFPageToBitmap(const void* pdf_buffer, PDFEngineExports* engine_exports = PDFEngineExports::Get(); PDFEngineExports::RenderingSettings settings( dpi_x, dpi_y, pp::Rect(bitmap_width, bitmap_height), true, false, true, - true, autorotate); + true, autorotate, use_color); bool ret = engine_exports->RenderPDFPageToBitmap( pdf_buffer, pdf_buffer_size, page_number, settings, bitmap_buffer); if (!IsSDKInitializedViaPepper()) diff --git a/chromium/pdf/pdf.h b/chromium/pdf/pdf.h index 751e3a5dfa9..ddd286d1998 100644 --- a/chromium/pdf/pdf.h +++ b/chromium/pdf/pdf.h @@ -53,6 +53,7 @@ enum PrintingMode { // done) should be centered within the given bounds. // |autorotate| specifies whether the final image should be rotated to match // the output bound. +// |use_color| specifies color or grayscale. // Returns false if the document or the page number are not valid. bool RenderPDFPageToDC(const void* pdf_buffer, int buffer_size, @@ -68,7 +69,8 @@ bool RenderPDFPageToDC(const void* pdf_buffer, bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds, - bool autorotate); + bool autorotate, + bool use_color); void SetPDFEnsureTypefaceCharactersAccessible( PDFEnsureTypefaceCharactersAccessible func); @@ -111,6 +113,7 @@ bool GetPDFPageSizeByIndex(const void* pdf_buffer, // |dpi_x| and |dpi_y| is the resolution. // |autorotate| specifies whether the final image should be rotated to match // the output bound. +// |use_color| specifies color or grayscale. // Returns false if the document or the page number are not valid. bool RenderPDFPageToBitmap(const void* pdf_buffer, int pdf_buffer_size, @@ -120,7 +123,8 @@ bool RenderPDFPageToBitmap(const void* pdf_buffer, int bitmap_height, int dpi_x, int dpi_y, - bool autorotate); + bool autorotate, + bool use_color); } // namespace chrome_pdf diff --git a/chromium/pdf/pdf_engine.h b/chromium/pdf/pdf_engine.h index df7225f524d..e547974bfa7 100644 --- a/chromium/pdf/pdf_engine.h +++ b/chromium/pdf/pdf_engine.h @@ -135,7 +135,7 @@ class PDFEngine { virtual void Invalidate(const pp::Rect& rect) = 0; // Informs the client to scroll the plugin area by the given offset. - virtual void Scroll(const pp::Point& point) = 0; + virtual void DidScroll(const pp::Point& point) = 0; // Scroll the horizontal/vertical scrollbars to a given position. // Values are in screen coordinates, where 0 is the top/left of the document @@ -146,6 +146,9 @@ class PDFEngine { virtual void ScrollToY(int y_in_screen_coords, bool compensate_for_toolbar) = 0; + // Scroll by a given delta relative to the current position. + virtual void ScrollBy(const pp::Point& point) = 0; + // Scroll to zero-based |page|. virtual void ScrollToPage(int page) = 0; @@ -232,8 +235,8 @@ class PDFEngine { virtual void DocumentPaintOccurred() = 0; // Notifies the client that the document has finished loading. - virtual void DocumentLoadComplete( - const DocumentFeatures& document_features) = 0; + virtual void DocumentLoadComplete(const DocumentFeatures& document_features, + uint32_t file_size) = 0; // Notifies the client that the document has failed to load. virtual void DocumentLoadFailed() = 0; @@ -270,6 +273,10 @@ class PDFEngine { // Sets edit mode state. virtual void IsEditModeChanged(bool is_edit_mode) {} + + // Gets the height of the top toolbar in screen coordinates. This is + // independent of whether it is hidden or not at the moment. + virtual float GetToolbarHeightInScreenCoords() = 0; }; // Factory method to create an instance of the PDF Engine. @@ -399,6 +406,10 @@ class PDFEngine { virtual void MoveRangeSelectionExtent(const pp::Point& extent) = 0; virtual void SetSelectionBounds(const pp::Point& base, const pp::Point& extent) = 0; + virtual void GetSelection(uint32_t* selection_start_page_index, + uint32_t* selection_start_char_index, + uint32_t* selection_end_page_index, + uint32_t* selection_end_char_index) = 0; // Remove focus from form widgets, consolidating the user input. virtual void KillFormFocus() = 0; @@ -415,7 +426,8 @@ class PDFEngineExports { bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds, - bool autorotate); + bool autorotate, + bool use_color); RenderingSettings(const RenderingSettings& that); int dpi_x; @@ -426,6 +438,7 @@ class PDFEngineExports { bool keep_aspect_ratio; bool center_in_bounds; bool autorotate; + bool use_color; }; PDFEngineExports() {} diff --git a/chromium/pdf/pdf_transform.cc b/chromium/pdf/pdf_transform.cc new file mode 100644 index 00000000000..28a69de503f --- /dev/null +++ b/chromium/pdf/pdf_transform.cc @@ -0,0 +1,139 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/pdf_transform.h" + +#include +#include + +#include "base/logging.h" +#include "ui/gfx/geometry/rect.h" + +namespace chrome_pdf { + +namespace { + +// When a PdfRectangle has top < bottom, or right < left, the values should be +// swapped. +void SwapPdfRectangleValuesIfNeeded(PdfRectangle* rect) { + if (rect->top < rect->bottom) + std::swap(rect->top, rect->bottom); + if (rect->right < rect->left) + std::swap(rect->right, rect->left); +} + +} // namespace + +double CalculateScaleFactor(const gfx::Rect& content_rect, + double src_width, + double src_height, + bool rotated) { + if (src_width == 0 || src_height == 0) + return 1.0; + + double actual_source_page_width = rotated ? src_height : src_width; + double actual_source_page_height = rotated ? src_width : src_height; + double ratio_x = + static_cast(content_rect.width()) / actual_source_page_width; + double ratio_y = + static_cast(content_rect.height()) / actual_source_page_height; + return std::min(ratio_x, ratio_y); +} + +void SetDefaultClipBox(bool rotated, PdfRectangle* clip_box) { + const int kDpi = 72; + const float kPaperWidth = 8.5 * kDpi; + const float kPaperHeight = 11 * kDpi; + clip_box->left = 0; + clip_box->bottom = 0; + clip_box->right = rotated ? kPaperHeight : kPaperWidth; + clip_box->top = rotated ? kPaperWidth : kPaperHeight; +} + +void CalculateMediaBoxAndCropBox(bool rotated, + bool has_media_box, + bool has_crop_box, + PdfRectangle* media_box, + PdfRectangle* crop_box) { + if (has_media_box) + SwapPdfRectangleValuesIfNeeded(media_box); + if (has_crop_box) + SwapPdfRectangleValuesIfNeeded(crop_box); + + if (!has_media_box && !has_crop_box) { + SetDefaultClipBox(rotated, crop_box); + SetDefaultClipBox(rotated, media_box); + } else if (has_crop_box && !has_media_box) { + *media_box = *crop_box; + } else if (has_media_box && !has_crop_box) { + *crop_box = *media_box; + } +} + +PdfRectangle CalculateClipBoxBoundary(const PdfRectangle& media_box, + const PdfRectangle& crop_box) { + PdfRectangle clip_box; + + // Clip |media_box| to the size of |crop_box|, but ignore |crop_box| if it is + // bigger than |media_box|. + clip_box.left = std::max(crop_box.left, media_box.left); + clip_box.bottom = std::max(crop_box.bottom, media_box.bottom); + clip_box.right = std::min(crop_box.right, media_box.right); + clip_box.top = std::min(crop_box.top, media_box.top); + return clip_box; +} + +void ScalePdfRectangle(double scale_factor, PdfRectangle* rect) { + rect->left *= scale_factor; + rect->bottom *= scale_factor; + rect->right *= scale_factor; + rect->top *= scale_factor; +} + +void CalculateScaledClipBoxOffset(const gfx::Rect& content_rect, + const PdfRectangle& source_clip_box, + double* offset_x, + double* offset_y) { + const float clip_box_width = source_clip_box.right - source_clip_box.left; + const float clip_box_height = source_clip_box.top - source_clip_box.bottom; + + // Center the intended clip region to real clip region. + *offset_x = (content_rect.width() - clip_box_width) / 2 + content_rect.x() - + source_clip_box.left; + *offset_y = (content_rect.height() - clip_box_height) / 2 + content_rect.y() - + source_clip_box.bottom; +} + +void CalculateNonScaledClipBoxOffset(const gfx::Rect& content_rect, + int rotation, + int page_width, + int page_height, + const PdfRectangle& source_clip_box, + double* offset_x, + double* offset_y) { + // Align the intended clip region to left-top corner of real clip region. + switch (rotation) { + case 0: + *offset_x = -1 * source_clip_box.left; + *offset_y = page_height - source_clip_box.top; + break; + case 1: + *offset_x = 0; + *offset_y = -1 * source_clip_box.bottom; + break; + case 2: + *offset_x = page_width - source_clip_box.right; + *offset_y = 0; + break; + case 3: + *offset_x = page_height - source_clip_box.right; + *offset_y = page_width - source_clip_box.top; + break; + default: + NOTREACHED(); + break; + } +} + +} // namespace chrome_pdf diff --git a/chromium/pdf/pdf_transform.h b/chromium/pdf/pdf_transform.h new file mode 100644 index 00000000000..da506f1678d --- /dev/null +++ b/chromium/pdf/pdf_transform.h @@ -0,0 +1,100 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PDF_PDF_TRANSFORM_H_ +#define PDF_PDF_TRANSFORM_H_ + +namespace gfx { +class Rect; +} + +namespace chrome_pdf { + +// A rect struct for use with FPDF bounding box functions. +// With PDFs, origin is bottom-left. +struct PdfRectangle { + float left; + float bottom; + float right; + float top; +}; + +// Calculate the scale factor between |content_rect| and a page of size +// |src_width| x |src_height|. +// +// |content_rect| specifies the printable area of the destination page, with +// origin at left-bottom. Values are in points. +// |src_width| specifies the source page width in points. +// |src_height| specifies the source page height in points. +// |rotated| True if source page is rotated 90 degree or 270 degree. +double CalculateScaleFactor(const gfx::Rect& content_rect, + double src_width, + double src_height, + bool rotated); + +// Make the default size to be letter size (8.5" X 11"). We are just following +// the PDFium way of handling these corner cases. PDFium always consider +// US-Letter as the default page size. +void SetDefaultClipBox(bool rotated, PdfRectangle* clip_box); + +// Set the media box and/or crop box as needed. If both boxes are there, then +// nothing needs to be done. If one box is missing, then fill it with the value +// from the other box. If both boxes are missing, then they both get the default +// value from SetDefaultClipBox(), based on |rotated|. +void CalculateMediaBoxAndCropBox(bool rotated, + bool has_media_box, + bool has_crop_box, + PdfRectangle* media_box, + PdfRectangle* crop_box); + +// Compute source clip box boundaries based on the crop box / media box of +// source page and scale factor. +// Returns the computed source clip box values. +// +// |media_box| The PDF's media box. +// |crop_box| The PDF's crop box. +PdfRectangle CalculateClipBoxBoundary(const PdfRectangle& media_box, + const PdfRectangle& crop_box); + +// Scale |box| by |scale_factor|. +void ScalePdfRectangle(double scale_factor, PdfRectangle* rect); + +// Calculate the clip box translation offset for a page that does need to be +// scaled. All parameters are in points. +// +// |content_rect| specifies the printable area of the destination page, with +// origin at left-bottom. +// |source_clip_box| specifies the source clip box positions, relative to +// origin at left-bottom. +// |offset_x| and |offset_y| will contain the final translation offsets for the +// source clip box, relative to origin at left-bottom. +void CalculateScaledClipBoxOffset(const gfx::Rect& content_rect, + const PdfRectangle& source_clip_box, + double* offset_x, + double* offset_y); + +// Calculate the clip box offset for a page that does not need to be scaled. +// All parameters are in points. +// +// |content_rect| specifies the printable area of the destination page, with +// origin at left-bottom. +// |rotation| specifies the source page rotation values which are N / 90 +// degrees. +// |page_width| specifies the screen destination page width. +// |page_height| specifies the screen destination page height. +// |source_clip_box| specifies the source clip box positions, relative to origin +// at left-bottom. +// |offset_x| and |offset_y| will contain the final translation offsets for the +// source clip box, relative to origin at left-bottom. +void CalculateNonScaledClipBoxOffset(const gfx::Rect& content_rect, + int rotation, + int page_width, + int page_height, + const PdfRectangle& source_clip_box, + double* offset_x, + double* offset_y); + +} // namespace chrome_pdf + +#endif // PDF_PDF_TRANSFORM_H_ diff --git a/chromium/pdf/pdf_transform_unittest.cc b/chromium/pdf/pdf_transform_unittest.cc new file mode 100644 index 00000000000..e52b02a8665 --- /dev/null +++ b/chromium/pdf/pdf_transform_unittest.cc @@ -0,0 +1,335 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/pdf_transform.h" + +#include "printing/units.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/rect.h" + +namespace chrome_pdf { + +namespace { + +const float kDefaultWidth = 8.5 * printing::kPointsPerInch; +const float kDefaultHeight = 11.0 * printing::kPointsPerInch; +const float kDefaultRatio = kDefaultWidth / kDefaultHeight; +const double kTolerance = 0.0001; + +void ExpectDefaultPortraitBox(const PdfRectangle& box) { + EXPECT_FLOAT_EQ(0, box.left); + EXPECT_FLOAT_EQ(0, box.bottom); + EXPECT_FLOAT_EQ(kDefaultWidth, box.right); + EXPECT_FLOAT_EQ(kDefaultHeight, box.top); +} + +void ExpectDefaultLandscapeBox(const PdfRectangle& box) { + EXPECT_FLOAT_EQ(0, box.left); + EXPECT_FLOAT_EQ(0, box.bottom); + EXPECT_FLOAT_EQ(kDefaultHeight, box.right); + EXPECT_FLOAT_EQ(kDefaultWidth, box.top); +} + +void ExpectBoxesAreEqual(const PdfRectangle& expected, + const PdfRectangle& actual) { + EXPECT_FLOAT_EQ(expected.left, actual.left); + EXPECT_FLOAT_EQ(expected.bottom, actual.bottom); + EXPECT_FLOAT_EQ(expected.right, actual.right); + EXPECT_FLOAT_EQ(expected.top, actual.top); +} + +void InitializeBoxToInvalidValues(PdfRectangle* box) { + box->left = box->bottom = box->right = box->top = -1; +} + +void InitializeBoxToDefaultPortraitValues(PdfRectangle* box) { + box->left = 0; + box->bottom = 0; + box->right = kDefaultWidth; + box->top = kDefaultHeight; +} + +void InitializeBoxToDefaultLandscapeValue(PdfRectangle* box) { + box->left = 0; + box->bottom = 0; + box->right = kDefaultHeight; + box->top = kDefaultWidth; +} + +} // namespace + +TEST(PdfTransformTest, CalculateScaleFactor) { + gfx::Rect rect(kDefaultWidth, kDefaultHeight); + double scale; + + // 1:1 + scale = CalculateScaleFactor(rect, kDefaultWidth, kDefaultHeight, false); + EXPECT_NEAR(1, scale, kTolerance); + scale = CalculateScaleFactor(rect, kDefaultWidth, kDefaultHeight, true); + EXPECT_NEAR(kDefaultRatio, scale, kTolerance); + + // 1:2 + rect = gfx::Rect(kDefaultWidth / 2, kDefaultHeight / 2); + scale = CalculateScaleFactor(rect, kDefaultWidth, kDefaultHeight, false); + EXPECT_NEAR(0.5, scale, kTolerance); + scale = CalculateScaleFactor(rect, kDefaultWidth, kDefaultHeight, true); + EXPECT_NEAR(kDefaultRatio / 2, scale, kTolerance); + + // 3:1 + rect = gfx::Rect(kDefaultWidth * 3, kDefaultHeight * 3); + scale = CalculateScaleFactor(rect, kDefaultWidth, kDefaultHeight, false); + EXPECT_NEAR(3, scale, kTolerance); + scale = CalculateScaleFactor(rect, kDefaultWidth, kDefaultHeight, true); + EXPECT_NEAR(kDefaultRatio * 3, scale, kTolerance); + + // 3:1, rotated. + rect = gfx::Rect(kDefaultHeight * 3, kDefaultWidth * 3); + scale = CalculateScaleFactor(rect, kDefaultWidth, kDefaultHeight, false); + EXPECT_NEAR(kDefaultRatio * 3, scale, kTolerance); + scale = CalculateScaleFactor(rect, kDefaultWidth, kDefaultHeight, true); + EXPECT_NEAR(3, scale, kTolerance); + + // Odd size + rect = gfx::Rect(10, 1000); + scale = CalculateScaleFactor(rect, kDefaultWidth, kDefaultHeight, false); + EXPECT_NEAR(0.01634, scale, kTolerance); + scale = CalculateScaleFactor(rect, kDefaultWidth, kDefaultHeight, true); + EXPECT_NEAR(0.01263, scale, kTolerance); +} + +TEST(PdfTransformTest, SetDefaultClipBox) { + PdfRectangle box; + + SetDefaultClipBox(false, &box); + ExpectDefaultPortraitBox(box); + + SetDefaultClipBox(true, &box); + ExpectDefaultLandscapeBox(box); +} + +TEST(PdfTransformTest, CalculateMediaBoxAndCropBox) { + PdfRectangle media_box; + PdfRectangle crop_box; + + // Assume both boxes are there. + InitializeBoxToDefaultPortraitValues(&media_box); + InitializeBoxToDefaultLandscapeValue(&crop_box); + CalculateMediaBoxAndCropBox(true, true, true, &media_box, &crop_box); + ExpectDefaultPortraitBox(media_box); + ExpectDefaultLandscapeBox(crop_box); + + // Assume both boxes are missing. + InitializeBoxToInvalidValues(&media_box); + InitializeBoxToInvalidValues(&crop_box); + CalculateMediaBoxAndCropBox(false, false, false, &media_box, &crop_box); + ExpectDefaultPortraitBox(media_box); + ExpectDefaultPortraitBox(crop_box); + CalculateMediaBoxAndCropBox(true, false, false, &media_box, &crop_box); + ExpectDefaultLandscapeBox(media_box); + ExpectDefaultLandscapeBox(crop_box); + + // Assume crop box is missing. + const PdfRectangle expected_box = {0, 0, 42, 420}; + media_box = expected_box; + InitializeBoxToInvalidValues(&crop_box); + CalculateMediaBoxAndCropBox(false, true, false, &media_box, &crop_box); + ExpectBoxesAreEqual(expected_box, media_box); + ExpectBoxesAreEqual(expected_box, crop_box); + + // Assume media box is missing. + InitializeBoxToInvalidValues(&media_box); + CalculateMediaBoxAndCropBox(false, false, true, &media_box, &crop_box); + ExpectBoxesAreEqual(expected_box, media_box); + ExpectBoxesAreEqual(expected_box, crop_box); +} + +TEST(PdfTransformTest, CalculateClipBoxBoundary) { + PdfRectangle media_box; + PdfRectangle crop_box; + PdfRectangle result; + + // media box and crop box are the same. + InitializeBoxToDefaultPortraitValues(&media_box); + InitializeBoxToDefaultPortraitValues(&crop_box); + result = CalculateClipBoxBoundary(media_box, crop_box); + ExpectDefaultPortraitBox(result); + + // media box is portrait and crop box is landscape. + InitializeBoxToDefaultLandscapeValue(&crop_box); + result = CalculateClipBoxBoundary(media_box, crop_box); + EXPECT_FLOAT_EQ(0, result.left); + EXPECT_FLOAT_EQ(0, result.bottom); + EXPECT_FLOAT_EQ(kDefaultWidth, result.right); + EXPECT_FLOAT_EQ(kDefaultWidth, result.top); + + // crop box is smaller than media box. + crop_box.left = 0; + crop_box.bottom = 0; + crop_box.right = 100; + crop_box.top = 200; + result = CalculateClipBoxBoundary(media_box, crop_box); + EXPECT_FLOAT_EQ(0, result.left); + EXPECT_FLOAT_EQ(0, result.bottom); + EXPECT_FLOAT_EQ(100, result.right); + EXPECT_FLOAT_EQ(200, result.top); + + // crop box is smaller than the media box in one dimension and longer in the + // other. + crop_box.left = 0; + crop_box.bottom = 0; + crop_box.right = 100; + crop_box.top = 2000; + result = CalculateClipBoxBoundary(media_box, crop_box); + EXPECT_FLOAT_EQ(0, result.left); + EXPECT_FLOAT_EQ(0, result.bottom); + EXPECT_FLOAT_EQ(100, result.right); + EXPECT_FLOAT_EQ(kDefaultHeight, result.top); +} + +TEST(PdfTransformTest, CalculateScaledClipBoxOffset) { + const gfx::Rect rect(kDefaultWidth, kDefaultHeight); + PdfRectangle clip_box; + double offset_x; + double offset_y; + + // |rect| and |clip_box| are the same size. + InitializeBoxToDefaultPortraitValues(&clip_box); + CalculateScaledClipBoxOffset(rect, clip_box, &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(0, offset_y); + + // |rect| is larger than |clip_box|. + clip_box.top /= 2; + clip_box.right /= 4; + CalculateScaledClipBoxOffset(rect, clip_box, &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(229.5, offset_x); + EXPECT_DOUBLE_EQ(198, offset_y); +} + +TEST(PdfTransformTest, CalculateNonScaledClipBoxOffset) { + int page_width = kDefaultWidth; + int page_height = kDefaultHeight; + const gfx::Rect rect(kDefaultWidth, kDefaultHeight); + PdfRectangle clip_box; + double offset_x; + double offset_y; + + // |rect|, page size and |clip_box| are the same. + InitializeBoxToDefaultPortraitValues(&clip_box); + CalculateNonScaledClipBoxOffset(rect, 0, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(0, offset_y); + CalculateNonScaledClipBoxOffset(rect, 1, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(0, offset_y); + CalculateNonScaledClipBoxOffset(rect, 2, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(0, offset_y); + CalculateNonScaledClipBoxOffset(rect, 3, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(180, offset_x); + EXPECT_DOUBLE_EQ(-180, offset_y); + + // Smaller |clip_box|. + clip_box.top /= 4; + clip_box.right /= 2; + CalculateNonScaledClipBoxOffset(rect, 0, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(594, offset_y); + CalculateNonScaledClipBoxOffset(rect, 1, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(0, offset_y); + CalculateNonScaledClipBoxOffset(rect, 2, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(306, offset_x); + EXPECT_DOUBLE_EQ(0, offset_y); + CalculateNonScaledClipBoxOffset(rect, 3, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(486, offset_x); + EXPECT_DOUBLE_EQ(414, offset_y); + + // Larger page size. + InitializeBoxToDefaultPortraitValues(&clip_box); + page_width += 10; + page_height += 20; + CalculateNonScaledClipBoxOffset(rect, 0, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(20, offset_y); + CalculateNonScaledClipBoxOffset(rect, 1, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(0, offset_y); + CalculateNonScaledClipBoxOffset(rect, 2, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(10, offset_x); + EXPECT_DOUBLE_EQ(0, offset_y); + CalculateNonScaledClipBoxOffset(rect, 3, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(200, offset_x); + EXPECT_DOUBLE_EQ(-170, offset_y); +} + +// https://crbug.com/491160 and https://crbug.com/588757 +TEST(PdfTransformTest, ReversedMediaBox) { + int page_width = kDefaultWidth; + int page_height = kDefaultHeight; + const gfx::Rect rect(kDefaultWidth, kDefaultHeight); + PdfRectangle clip_box; + double offset_x; + double offset_y; + + const PdfRectangle expected_media_box_b491160 = {0, -792, 612, 0}; + PdfRectangle media_box_b491160 = {0, 0, 612, -792}; + CalculateMediaBoxAndCropBox(false, true, false, &media_box_b491160, + &clip_box); + ExpectBoxesAreEqual(expected_media_box_b491160, media_box_b491160); + ExpectBoxesAreEqual(expected_media_box_b491160, clip_box); + + CalculateScaledClipBoxOffset(rect, media_box_b491160, &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(792, offset_y); + + CalculateNonScaledClipBoxOffset(rect, 0, page_width, page_height, + media_box_b491160, &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(792, offset_y); + + PdfRectangle media_box_b588757 = {0, 792, 612, 0}; + CalculateMediaBoxAndCropBox(false, true, false, &media_box_b588757, + &clip_box); + ExpectDefaultPortraitBox(media_box_b588757); + ExpectDefaultPortraitBox(clip_box); + + CalculateScaledClipBoxOffset(rect, clip_box, &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(0, offset_y); + + CalculateNonScaledClipBoxOffset(rect, 0, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(0, offset_y); + + PdfRectangle media_box_left_right_flipped = {612, 792, 0, 0}; + CalculateMediaBoxAndCropBox(false, true, false, &media_box_left_right_flipped, + &clip_box); + ExpectDefaultPortraitBox(media_box_left_right_flipped); + ExpectDefaultPortraitBox(clip_box); + + CalculateScaledClipBoxOffset(rect, clip_box, &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(0, offset_y); + + CalculateNonScaledClipBoxOffset(rect, 0, page_width, page_height, clip_box, + &offset_x, &offset_y); + EXPECT_DOUBLE_EQ(0, offset_x); + EXPECT_DOUBLE_EQ(0, offset_y); +} + +} // namespace chrome_pdf diff --git a/chromium/pdf/pdfium/DEPS b/chromium/pdf/pdfium/DEPS index cf1dc868957..00a544d4693 100644 --- a/chromium/pdf/pdfium/DEPS +++ b/chromium/pdf/pdfium/DEPS @@ -1,9 +1,6 @@ include_rules = [ "+gin/array_buffer.h", "+gin/public", - "+printing/pdf_transform.h", - "+printing/units.h", "+third_party/pdfium/public", "+ui/gfx/codec/jpeg_codec.h", - "+ui/gfx/geometry/rect.h", ] diff --git a/chromium/pdf/pdfium/fuzzers/BUILD.gn b/chromium/pdf/pdfium/fuzzers/BUILD.gn index cfff56d9296..98062af13e0 100644 --- a/chromium/pdf/pdfium/fuzzers/BUILD.gn +++ b/chromium/pdf/pdfium/fuzzers/BUILD.gn @@ -31,7 +31,6 @@ group("pdf_fuzzers") { if (pdf_enable_xfa) { deps += [ ":pdf_cfx_barcode_fuzzer", - ":pdf_cfx_saxreader_fuzzer", ":pdf_codec_bmp_fuzzer", ":pdf_codec_gif_fuzzer", ":pdf_codec_jpeg_fuzzer", @@ -242,14 +241,6 @@ if (pdf_enable_xfa) { ] } - fuzzer_test("pdf_cfx_saxreader_fuzzer") { - sources = [] - deps = [ - "//third_party/pdfium/testing/libfuzzer:pdf_cfx_saxreader_fuzzer", - ] - dict = "dicts/pdf_xml.dict" - } - fuzzer_test("pdfium_xfa_fuzzer") { sources = [ "pdfium_fuzzer_helper.cc", diff --git a/chromium/pdf/pdfium/pdfium_engine.cc b/chromium/pdf/pdfium/pdfium_engine.cc index f2062ee90c7..7f5da005d37 100644 --- a/chromium/pdf/pdfium/pdfium_engine.cc +++ b/chromium/pdf/pdfium/pdfium_engine.cc @@ -31,6 +31,7 @@ #include "gin/public/gin_embedders.h" #include "gin/public/isolate_holder.h" #include "pdf/draw_utils.h" +#include "pdf/pdf_transform.h" #include "pdf/pdfium/pdfium_api_string_buffer_adapter.h" #include "pdf/pdfium/pdfium_mem_buffer_file_read.h" #include "pdf/pdfium/pdfium_mem_buffer_file_write.h" @@ -48,7 +49,6 @@ #include "ppapi/cpp/url_response_info.h" #include "ppapi/cpp/var.h" #include "ppapi/cpp/var_dictionary.h" -#include "printing/pdf_transform.h" #include "printing/units.h" #include "third_party/pdfium/public/cpp/fpdf_deleters.h" #include "third_party/pdfium/public/fpdf_annot.h" @@ -111,6 +111,13 @@ constexpr int kMaxPasswordTries = 3; constexpr base::TimeDelta kTouchLongPressTimeout = base::TimeDelta::FromMilliseconds(300); +// Windows has native panning capabilities. No need to use our own. +#if defined(OS_WIN) +constexpr bool kViewerImplementedPanning = false; +#else +constexpr bool kViewerImplementedPanning = true; +#endif + // See Table 3.20 in // http://www.adobe.com/devnet/acrobat/pdfs/pdf_reference_1-7.pdf const uint32_t kPDFPermissionPrintLowQualityMask = 1 << 2; @@ -758,6 +765,7 @@ PDFiumEngine::PDFiumEngine(PDFEngine::Client* client) in_form_text_area_(false), editable_form_text_area_(false), mouse_left_button_down_(false), + mouse_middle_button_down_(false), permissions_(0), permissions_handler_revision_(-1), fpdf_availability_(nullptr), @@ -906,13 +914,58 @@ void PDFiumEngine::Form_GetPageViewRect(FPDF_FORMFILLINFO* param, double* right, double* bottom) { PDFiumEngine* engine = static_cast(param); - int page_index = engine->GetMostVisiblePage(); + int page_index = engine->GetVisiblePageIndex(page); + if (!engine->PageIndexInBounds(page_index)) { + *left = 0; + *right = 0; + *top = 0; + *bottom = 0; + return; + } + pp::Rect page_view_rect = engine->GetPageContentsRect(page_index); - *left = page_view_rect.x(); - *right = page_view_rect.right(); - *top = page_view_rect.y(); - *bottom = page_view_rect.bottom(); + float toolbar_height_in_screen_coords = + engine->GetToolbarHeightInScreenCoords(); + + float page_width = FPDF_GetPageWidth(page); + float page_height = FPDF_GetPageHeight(page); + + // To convert from a screen scale to a page scale, we multiply by + // (page_height / page_view_rect.height()) and + // (page_width / page_view_rect.width()), + // The base point of the page in screen coords is (page_view_rect.x(), + // page_view_rect.y()). + // Therefore, to convert an x position from screen to page + // coords, we use (page_width * (x - base_x) / page_view_rect.width()). + // For y positions, (page_height * (y - base_y) / page_view_rect.height()). + + // The top-most y position that can be relied to be visible on the screen is + // the bottom of the toolbar, which is y = toolbar_height_in_screen_coords. + float screen_top_in_page_coords = + page_height * (toolbar_height_in_screen_coords - page_view_rect.y()) / + page_view_rect.height(); + // The bottom-most y position that is visible on the screen is the bottom of + // the plugin area, which is y = engine->plugin_size_.height(). + float screen_bottom_in_page_coords = + page_height * (engine->plugin_size_.height() - page_view_rect.y()) / + page_view_rect.height(); + // The left-most x position that is visible on the screen is the left of the + // plugin area, which is x = 0. + float screen_left_in_page_coords = + page_width * (0 - page_view_rect.x()) / page_view_rect.width(); + // The right-most x position that is visible on the screen is the right of the + // plugin area, which is x = engine->plugin_size_.width(). + float screen_right_in_page_coords = + page_width * (engine->plugin_size_.width() - page_view_rect.x()) / + page_view_rect.width(); + + // Return the edge of the screen or of the page, since we're restricted to + // both. + *left = std::max(screen_left_in_page_coords, 0.0f); + *right = std::min(screen_right_in_page_coords, page_width); + *top = std::max(screen_top_in_page_coords, 0.0f); + *bottom = std::min(screen_bottom_in_page_coords, page_height); } int PDFiumEngine::Form_GetPlatform(FPDF_FORMFILLINFO* param, @@ -1063,7 +1116,8 @@ void PDFiumEngine::ScrolledToXPosition(int position) { int old_x = position_.x(); position_.set_x(position); CalculateVisiblePages(); - client_->Scroll(pp::Point(old_x - position, 0)); + client_->DidScroll(pp::Point(old_x - position, 0)); + OnSelectionPositionChanged(); } void PDFiumEngine::ScrolledToYPosition(int position) { @@ -1072,7 +1126,8 @@ void PDFiumEngine::ScrolledToYPosition(int position) { int old_y = position_.y(); position_.set_y(position); CalculateVisiblePages(); - client_->Scroll(pp::Point(0, old_y - position)); + client_->DidScroll(pp::Point(0, old_y - position)); + OnSelectionPositionChanged(); } void PDFiumEngine::PrePaint() { @@ -1263,14 +1318,14 @@ void PDFiumEngine::OnPendingRequestComplete() { } void PDFiumEngine::OnNewDataReceived() { - client_->DocumentLoadProgress(doc_loader_->count_of_bytes_received(), + client_->DocumentLoadProgress(doc_loader_->bytes_received(), doc_loader_->GetDocumentSize()); } void PDFiumEngine::OnDocumentComplete() { - if (doc_) { + if (doc_) return FinishLoadingDocument(); - } + file_access_.m_FileLen = doc_loader_->GetDocumentSize(); if (!fpdf_availability_) { fpdf_availability_ = FPDFAvail_Create(&file_availability_, &file_access_); @@ -1291,7 +1346,8 @@ void PDFiumEngine::CancelBrowserDownload() { } void PDFiumEngine::FinishLoadingDocument() { - DCHECK(doc_loader_->IsDocumentComplete() && doc_); + DCHECK(doc_); + DCHECK(doc_loader_->IsDocumentComplete()); LoadBody(); @@ -1331,7 +1387,8 @@ void PDFiumEngine::FinishLoadingDocument() { (FPDFAvail_IsLinearized(fpdf_availability_) == PDF_LINEARIZED); document_features.is_tagged = FPDFCatalog_IsTagged(doc_); document_features.form_type = static_cast(FPDF_GetFormType(doc_)); - client_->DocumentLoadComplete(document_features); + client_->DocumentLoadComplete(document_features, + doc_loader_->bytes_received()); } } @@ -1403,6 +1460,9 @@ bool PDFiumEngine::HandleEvent(const pp::InputEvent& event) { case PP_INPUTEVENT_TYPE_MOUSEMOVE: rv = OnMouseMove(pp::MouseInputEvent(event)); break; + case PP_INPUTEVENT_TYPE_MOUSEENTER: + OnMouseEnter(pp::MouseInputEvent(event)); + break; case PP_INPUTEVENT_TYPE_KEYDOWN: rv = OnKeyDown(pp::KeyboardInputEvent(event)); break; @@ -1499,7 +1559,13 @@ FPDF_DOCUMENT PDFiumEngine::CreateSinglePageRasterPdf( FPDF_RenderPageBitmap(bitmap, page_to_print->GetPrintPage(), page_rect.x(), page_rect.y(), page_rect.width(), page_rect.height(), print_settings.orientation, - FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH); + FPDF_PRINTING | FPDF_NO_CATCH); + + // Draw the forms. + FPDF_FFLDraw(form_, bitmap, page_to_print->GetPrintPage(), page_rect.x(), + page_rect.y(), page_rect.width(), page_rect.height(), + print_settings.orientation, + FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH); unsigned char* bitmap_data = static_cast(FPDFBitmap_GetBuffer(bitmap)); @@ -1902,6 +1968,8 @@ bool PDFiumEngine::OnLeftMouseDown(const pp::MouseInputEvent& event) { bool PDFiumEngine::OnMiddleMouseDown(const pp::MouseInputEvent& event) { SetMouseLeftButtonDown(false); + mouse_middle_button_down_ = true; + mouse_middle_button_last_position_ = event.GetPosition(); SelectionChangeInvalidator selection_invalidator(this); selection_.clear(); @@ -1920,6 +1988,11 @@ bool PDFiumEngine::OnMiddleMouseDown(const pp::MouseInputEvent& event) { if (IsLinkArea(area)) return true; + if (kViewerImplementedPanning) { + // Switch to hand cursor when panning. + client_->UpdateCursor(PP_CURSORTYPE_HAND); + } + // Prevent middle mouse button from selecting texts. return false; } @@ -2002,6 +2075,8 @@ bool PDFiumEngine::OnMouseUp(const pp::MouseInputEvent& event) { if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT) SetMouseLeftButtonDown(false); + else if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_MIDDLE) + mouse_middle_button_down_ = false; int page_index = -1; int char_index = -1; @@ -2030,6 +2105,9 @@ bool PDFiumEngine::OnMouseUp(const pp::MouseInputEvent& event) { return true; } if (area == PDFiumPage::DOCLINK_AREA) { + if (!PageIndexInBounds(target.page)) + return true; + pp::Rect page_rect(GetPageScreenRect(target.page)); int y = position_.y() + page_rect.y(); if (target.y_in_pixels) @@ -2040,9 +2118,15 @@ bool PDFiumEngine::OnMouseUp(const pp::MouseInputEvent& event) { } } - // Prevent middle mouse button from selecting texts. - if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_MIDDLE) + if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_MIDDLE) { + if (kViewerImplementedPanning) { + // Update the cursor when panning stops. + client_->UpdateCursor(DetermineCursorType(area, form_type)); + } + + // Prevent middle mouse button from selecting texts. return false; + } if (page_index != -1) { double page_x; @@ -2073,48 +2157,7 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) { mouse_down_state_.Reset(); if (!selecting_) { - PP_CursorType_Dev cursor; - switch (area) { - case PDFiumPage::TEXT_AREA: - cursor = PP_CURSORTYPE_IBEAM; - break; - case PDFiumPage::WEBLINK_AREA: - case PDFiumPage::DOCLINK_AREA: - cursor = PP_CURSORTYPE_HAND; - break; - case PDFiumPage::NONSELECTABLE_AREA: - case PDFiumPage::FORM_TEXT_AREA: - default: - switch (form_type) { - case FPDF_FORMFIELD_PUSHBUTTON: - case FPDF_FORMFIELD_CHECKBOX: - case FPDF_FORMFIELD_RADIOBUTTON: - case FPDF_FORMFIELD_COMBOBOX: - case FPDF_FORMFIELD_LISTBOX: - cursor = PP_CURSORTYPE_HAND; - break; - case FPDF_FORMFIELD_TEXTFIELD: - cursor = PP_CURSORTYPE_IBEAM; - break; -#if defined(PDF_ENABLE_XFA) - case FPDF_FORMFIELD_XFA_CHECKBOX: - case FPDF_FORMFIELD_XFA_COMBOBOX: - case FPDF_FORMFIELD_XFA_IMAGEFIELD: - case FPDF_FORMFIELD_XFA_LISTBOX: - case FPDF_FORMFIELD_XFA_PUSHBUTTON: - case FPDF_FORMFIELD_XFA_SIGNATURE: - cursor = PP_CURSORTYPE_HAND; - break; - case FPDF_FORMFIELD_XFA_TEXTFIELD: - cursor = PP_CURSORTYPE_IBEAM; - break; -#endif - default: - cursor = PP_CURSORTYPE_POINTER; - break; - } - break; - } + client_->UpdateCursor(DetermineCursorType(area, form_type)); if (page_index != -1) { double page_x; @@ -2123,7 +2166,6 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) { FORM_OnMouseMove(form_, pages_[page_index]->GetPage(), 0, page_x, page_y); } - client_->UpdateCursor(cursor); std::string url = GetLinkAtPosition(event.GetPosition()); if (url != link_under_cursor_) { link_under_cursor_ = url; @@ -2137,6 +2179,19 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) { SetFormSelectedText(form_, pages_[last_page_mouse_down_]->GetPage()); } + if (kViewerImplementedPanning && mouse_middle_button_down_) { + // Subtract (origin - destination) so delta is already the delta for + // moving the page, rather than the delta the mouse moved. + // GetMovement() does not work here, as small mouse movements are + // considered zero. + pp::Point page_position_delta = + mouse_middle_button_last_position_ - event.GetPosition(); + if (page_position_delta.x() != 0 || page_position_delta.y() != 0) { + client_->ScrollBy(page_position_delta); + mouse_middle_button_last_position_ = event.GetPosition(); + } + } + // No need to swallow the event, since this might interfere with the // scrollbars if the user is dragging them. return false; @@ -2151,6 +2206,60 @@ bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) { return ExtendSelection(page_index, char_index); } +PP_CursorType_Dev PDFiumEngine::DetermineCursorType(PDFiumPage::Area area, + int form_type) const { + if (kViewerImplementedPanning && mouse_middle_button_down_) { + return PP_CURSORTYPE_HAND; + } + + switch (area) { + case PDFiumPage::TEXT_AREA: + return PP_CURSORTYPE_IBEAM; + case PDFiumPage::WEBLINK_AREA: + case PDFiumPage::DOCLINK_AREA: + return PP_CURSORTYPE_HAND; + case PDFiumPage::NONSELECTABLE_AREA: + case PDFiumPage::FORM_TEXT_AREA: + default: + switch (form_type) { + case FPDF_FORMFIELD_PUSHBUTTON: + case FPDF_FORMFIELD_CHECKBOX: + case FPDF_FORMFIELD_RADIOBUTTON: + case FPDF_FORMFIELD_COMBOBOX: + case FPDF_FORMFIELD_LISTBOX: + return PP_CURSORTYPE_HAND; + case FPDF_FORMFIELD_TEXTFIELD: + return PP_CURSORTYPE_IBEAM; +#if defined(PDF_ENABLE_XFA) + case FPDF_FORMFIELD_XFA_CHECKBOX: + case FPDF_FORMFIELD_XFA_COMBOBOX: + case FPDF_FORMFIELD_XFA_IMAGEFIELD: + case FPDF_FORMFIELD_XFA_LISTBOX: + case FPDF_FORMFIELD_XFA_PUSHBUTTON: + case FPDF_FORMFIELD_XFA_SIGNATURE: + return PP_CURSORTYPE_HAND; + case FPDF_FORMFIELD_XFA_TEXTFIELD: + return PP_CURSORTYPE_IBEAM; +#endif + default: + return PP_CURSORTYPE_POINTER; + } + } +} + +void PDFiumEngine::OnMouseEnter(const pp::MouseInputEvent& event) { + if (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN) { + if (!mouse_middle_button_down_) { + mouse_middle_button_down_ = true; + mouse_middle_button_last_position_ = event.GetPosition(); + } + } else { + if (mouse_middle_button_down_) { + mouse_middle_button_down_ = false; + } + } +} + bool PDFiumEngine::ExtendSelection(int page_index, int char_index) { // Check if the user has decreased their selection area and we need to remove // pages from |selection_|. @@ -3010,7 +3119,8 @@ bool PDFiumEngine::TryLoadingDoc(const std::string& password, void PDFiumEngine::GetPasswordAndLoad() { getting_password_ = true; - DCHECK(!doc_ && FPDF_GetLastError() == FPDF_ERR_PASSWORD); + DCHECK(!doc_); + DCHECK_EQ(static_cast(FPDF_ERR_PASSWORD), FPDF_GetLastError()); client_->GetDocumentPassword(password_factory_.NewCallbackWithOutput( &PDFiumEngine::OnGetPasswordComplete)); } @@ -3662,8 +3772,10 @@ PDFiumEngine::SelectionChangeInvalidator::~SelectionChangeInvalidator() { } } - if (selection_changed) - engine_->OnSelectionChanged(); + if (selection_changed) { + engine_->OnSelectionTextChanged(); + engine_->OnSelectionPositionChanged(); + } } std::vector @@ -3795,35 +3907,33 @@ void PDFiumEngine::TransformPDFPageForPrinting( const gfx::Rect gfx_content_rect(content_rect.x(), content_rect.y(), content_rect.width(), content_rect.height()); const double scale_factor = - fit_to_page - ? printing::CalculateScaleFactor(gfx_content_rect, src_page_width, - src_page_height, rotated) - : 1.0; + fit_to_page ? CalculateScaleFactor(gfx_content_rect, src_page_width, + src_page_height, rotated) + : 1.0; // Calculate positions for the clip box. - printing::PdfRectangle media_box; - printing::PdfRectangle crop_box; + PdfRectangle media_box; + PdfRectangle crop_box; bool has_media_box = !!FPDFPage_GetMediaBox(page, &media_box.left, &media_box.bottom, &media_box.right, &media_box.top); bool has_crop_box = !!FPDFPage_GetCropBox( page, &crop_box.left, &crop_box.bottom, &crop_box.right, &crop_box.top); - printing::CalculateMediaBoxAndCropBox(rotated, has_media_box, has_crop_box, - &media_box, &crop_box); - printing::PdfRectangle source_clip_box = - printing::CalculateClipBoxBoundary(media_box, crop_box); - printing::ScalePdfRectangle(scale_factor, &source_clip_box); + CalculateMediaBoxAndCropBox(rotated, has_media_box, has_crop_box, &media_box, + &crop_box); + PdfRectangle source_clip_box = CalculateClipBoxBoundary(media_box, crop_box); + ScalePdfRectangle(scale_factor, &source_clip_box); // Calculate the translation offset values. double offset_x = 0; double offset_y = 0; if (fit_to_page) { - printing::CalculateScaledClipBoxOffset(gfx_content_rect, source_clip_box, - &offset_x, &offset_y); + CalculateScaledClipBoxOffset(gfx_content_rect, source_clip_box, &offset_x, + &offset_y); } else { - printing::CalculateNonScaledClipBoxOffset( - gfx_content_rect, src_page_rotation, actual_page_width, - actual_page_height, source_clip_box, &offset_x, &offset_y); + CalculateNonScaledClipBoxOffset(gfx_content_rect, src_page_rotation, + actual_page_width, actual_page_height, + source_clip_box, &offset_x, &offset_y); } // Reset the media box and crop box. When the page has crop box and media box, @@ -3915,10 +4025,12 @@ void PDFiumEngine::GetRegion(const pp::Point& location, *region = buffer; } -void PDFiumEngine::OnSelectionChanged() { +void PDFiumEngine::OnSelectionTextChanged() { DCHECK(!in_form_text_area_); pp::PDF::SetSelectedText(GetPluginInstance(), GetSelectedText().c_str()); +} +void PDFiumEngine::OnSelectionPositionChanged() { // We need to determine the top-left and bottom-right points of the selection // in order to report those to the embedder. This code assumes that the // selection list is out of order. @@ -4038,6 +4150,10 @@ bool PDFiumEngine::PageIndexInBounds(int index) const { return index >= 0 && index < static_cast(pages_.size()); } +float PDFiumEngine::GetToolbarHeightInScreenCoords() { + return client_->GetToolbarHeightInScreenCoords(); +} + void PDFiumEngine::Form_Invalidate(FPDF_FORMFILLINFO* param, FPDF_PAGE page, double left, @@ -4378,6 +4494,35 @@ void PDFiumEngine::SetSelectionBounds(const pp::Point& base, : RangeSelectionDirection::Right; } +void PDFiumEngine::GetSelection(uint32_t* selection_start_page_index, + uint32_t* selection_start_char_index, + uint32_t* selection_end_page_index, + uint32_t* selection_end_char_index) { + size_t len = selection_.size(); + if (len == 0) { + *selection_start_page_index = 0; + *selection_start_char_index = 0; + *selection_end_page_index = 0; + *selection_end_char_index = 0; + return; + } + + *selection_start_page_index = selection_[0].page_index(); + *selection_start_char_index = selection_[0].char_index(); + *selection_end_page_index = selection_[len - 1].page_index(); + + // If the selection is all within one page, the end index is the + // start index plus the char count. But if the selection spans + // multiple pages, the selection starts at the beginning of the + // last page in |selection_| and goes to the char count. + if (len == 1) { + *selection_end_char_index = + selection_[0].char_index() + selection_[0].char_count(); + } else { + *selection_end_char_index = selection_[len - 1].char_count(); + } +} + PDFiumEngine::FormFillTimerData::FormFillTimerData(base::TimeDelta period, TimerCallback callback) : timer_period(period), timer_callback(callback) {} @@ -4484,7 +4629,8 @@ PDFEngineExports::RenderingSettings::RenderingSettings(int dpi_x, bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds, - bool autorotate) + bool autorotate, + bool use_color) : dpi_x(dpi_x), dpi_y(dpi_y), bounds(bounds), @@ -4492,7 +4638,8 @@ PDFEngineExports::RenderingSettings::RenderingSettings(int dpi_x, stretch_to_bounds(stretch_to_bounds), keep_aspect_ratio(keep_aspect_ratio), center_in_bounds(center_in_bounds), - autorotate(autorotate) {} + autorotate(autorotate), + use_color(use_color) {} PDFEngineExports::RenderingSettings::RenderingSettings( const RenderingSettings& that) = default; @@ -4507,14 +4654,14 @@ bool PDFiumEngineExports::RenderPDFPageToDC(const void* pdf_buffer, int page_number, const RenderingSettings& settings, HDC dc) { - FPDF_DOCUMENT doc = FPDF_LoadMemDocument(pdf_buffer, buffer_size, nullptr); + std::unique_ptr doc( + FPDF_LoadMemDocument(pdf_buffer, buffer_size, nullptr)); if (!doc) return false; - FPDF_PAGE page = FPDF_LoadPage(doc, page_number); - if (!page) { - FPDF_CloseDocument(doc); + FPDF_PAGE page = FPDF_LoadPage(doc.get(), page_number); + if (!page) return false; - } + RenderingSettings new_settings = settings; // calculate the page size if (new_settings.dpi_x == -1) @@ -4533,6 +4680,10 @@ bool PDFiumEngineExports::RenderPDFPageToDC(const void* pdf_buffer, settings.bounds.x() + settings.bounds.width(), settings.bounds.y() + settings.bounds.height()); + int flags = FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH; + if (!settings.use_color) + flags |= FPDF_GRAYSCALE; + // A "temporary" hack. Some PDFs seems to render very slowly if // FPDF_RenderPage() is directly used on a printer DC. I suspect it is // because of the code to talk Postscript directly to the printer if @@ -4546,7 +4697,7 @@ bool PDFiumEngineExports::RenderPDFPageToDC(const void* pdf_buffer, // Clear the bitmap FPDFBitmap_FillRect(bitmap, 0, 0, dest.width(), dest.height(), 0xFFFFFFFF); FPDF_RenderPageBitmap(bitmap, page, 0, 0, dest.width(), dest.height(), - rotate, FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH); + rotate, flags); int stride = FPDFBitmap_GetStride(bitmap); BITMAPINFO bmi; memset(&bmi, 0, sizeof(bmi)); @@ -4563,11 +4714,10 @@ bool PDFiumEngineExports::RenderPDFPageToDC(const void* pdf_buffer, FPDFBitmap_Destroy(bitmap); } else { FPDF_RenderPage(dc, page, dest.x(), dest.y(), dest.width(), dest.height(), - rotate, FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH); + rotate, flags); } RestoreDC(dc, save_state); FPDF_ClosePage(page); - FPDF_CloseDocument(doc); return true; } @@ -4592,15 +4742,13 @@ bool PDFiumEngineExports::RenderPDFPageToBitmap( int page_number, const RenderingSettings& settings, void* bitmap_buffer) { - FPDF_DOCUMENT doc = - FPDF_LoadMemDocument(pdf_buffer, pdf_buffer_size, nullptr); + std::unique_ptr doc( + FPDF_LoadMemDocument(pdf_buffer, pdf_buffer_size, nullptr)); if (!doc) return false; - FPDF_PAGE page = FPDF_LoadPage(doc, page_number); - if (!page) { - FPDF_CloseDocument(doc); + FPDF_PAGE page = FPDF_LoadPage(doc.get(), page_number); + if (!page) return false; - } pp::Rect dest; int rotate = CalculatePosition(page, settings, &dest); @@ -4613,12 +4761,15 @@ bool PDFiumEngineExports::RenderPDFPageToBitmap( settings.bounds.height(), 0xFFFFFFFF); // Shift top-left corner of bounds to (0, 0) if it's not there. dest.set_point(dest.point() - settings.bounds.point()); + + int flags = FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH; + if (!settings.use_color) + flags |= FPDF_GRAYSCALE; + FPDF_RenderPageBitmap(bitmap, page, dest.x(), dest.y(), dest.width(), - dest.height(), rotate, - FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH); + dest.height(), rotate, flags); FPDFBitmap_Destroy(bitmap); FPDF_ClosePage(page); - FPDF_CloseDocument(doc); return true; } @@ -4626,25 +4777,30 @@ bool PDFiumEngineExports::GetPDFDocInfo(const void* pdf_buffer, int buffer_size, int* page_count, double* max_page_width) { - FPDF_DOCUMENT doc = FPDF_LoadMemDocument(pdf_buffer, buffer_size, nullptr); + std::unique_ptr doc( + FPDF_LoadMemDocument(pdf_buffer, buffer_size, nullptr)); if (!doc) return false; - int page_count_local = FPDF_GetPageCount(doc); - if (page_count) { + + if (!page_count && !max_page_width) + return true; + + int page_count_local = FPDF_GetPageCount(doc.get()); + if (page_count) *page_count = page_count_local; - } + if (max_page_width) { *max_page_width = 0; for (int page_number = 0; page_number < page_count_local; page_number++) { double page_width = 0; double page_height = 0; - FPDF_GetPageSizeByIndex(doc, page_number, &page_width, &page_height); + FPDF_GetPageSizeByIndex(doc.get(), page_number, &page_width, + &page_height); if (page_width > *max_page_width) { *max_page_width = page_width; } } } - FPDF_CloseDocument(doc); return true; } @@ -4653,13 +4809,11 @@ bool PDFiumEngineExports::GetPDFPageSizeByIndex(const void* pdf_buffer, int page_number, double* width, double* height) { - FPDF_DOCUMENT doc = - FPDF_LoadMemDocument(pdf_buffer, pdf_buffer_size, nullptr); + std::unique_ptr doc( + FPDF_LoadMemDocument(pdf_buffer, pdf_buffer_size, nullptr)); if (!doc) return false; - bool success = FPDF_GetPageSizeByIndex(doc, page_number, width, height) != 0; - FPDF_CloseDocument(doc); - return success; + return FPDF_GetPageSizeByIndex(doc.get(), page_number, width, height) != 0; } } // namespace chrome_pdf diff --git a/chromium/pdf/pdfium/pdfium_engine.h b/chromium/pdf/pdfium/pdfium_engine.h index fb6990d023d..ce15d90ac9a 100644 --- a/chromium/pdf/pdfium/pdfium_engine.h +++ b/chromium/pdf/pdfium/pdfium_engine.h @@ -115,6 +115,10 @@ class PDFiumEngine : public PDFEngine, void MoveRangeSelectionExtent(const pp::Point& extent) override; void SetSelectionBounds(const pp::Point& base, const pp::Point& extent) override; + void GetSelection(uint32_t* selection_start_page_index, + uint32_t* selection_start_char_index, + uint32_t* selection_end_page_index, + uint32_t* selection_end_char_index) override; // DocumentLoader::Client implementation. pp::Instance* GetPluginInstance() override; @@ -291,10 +295,15 @@ class PDFiumEngine : public PDFEngine, bool OnMouseDown(const pp::MouseInputEvent& event); bool OnMouseUp(const pp::MouseInputEvent& event); bool OnMouseMove(const pp::MouseInputEvent& event); + void OnMouseEnter(const pp::MouseInputEvent& event); bool OnKeyDown(const pp::KeyboardInputEvent& event); bool OnKeyUp(const pp::KeyboardInputEvent& event); bool OnChar(const pp::KeyboardInputEvent& event); + // Decide what cursor should be displayed. + PP_CursorType_Dev DetermineCursorType(PDFiumPage::Area area, + int form_type) const; + bool ExtendSelection(int page_index, int char_index); FPDF_DOCUMENT CreateSinglePageRasterPdf( @@ -435,7 +444,8 @@ class PDFiumEngine : public PDFEngine, int* stride) const; // Called when the selection changes. - void OnSelectionChanged(); + void OnSelectionTextChanged(); + void OnSelectionPositionChanged(); // Common code shared by RotateClockwise() and RotateCounterclockwise(). void RotateInternal(); @@ -460,6 +470,10 @@ class PDFiumEngine : public PDFEngine, bool PageIndexInBounds(int index) const; + // Gets the height of the top toolbar in screen coordinates. This is + // independent of whether it is hidden or not at the moment. + float GetToolbarHeightInScreenCoords(); + void ScheduleTouchTimer(const pp::TouchInputEvent& event); void KillTouchTimer(int timer_id); void HandleLongPress(const pp::TouchInputEvent& event); @@ -691,6 +705,12 @@ class PDFiumEngine : public PDFEngine, // True if left mouse button is currently being held down. bool mouse_left_button_down_; + // True if middle mouse button is currently being held down. + bool mouse_middle_button_down_; + + // Last known position while performing middle mouse button pan. + pp::Point mouse_middle_button_last_position_; + // The current text used for searching. std::string current_find_text_; // The results found. diff --git a/chromium/pdf/pdfium/pdfium_range.cc b/chromium/pdf/pdfium/pdfium_range.cc index fb1d94b4a31..bec834ff3d9 100644 --- a/chromium/pdf/pdfium/pdfium_range.cc +++ b/chromium/pdf/pdfium/pdfium_range.cc @@ -10,11 +10,26 @@ namespace chrome_pdf { +namespace { + +void AdjustForBackwardsRange(int* index, int* count) { + int& char_index = *index; + int& char_count = *count; + if (char_count < 0) { + char_count *= -1; + char_index -= char_count - 1; + } +} + +} // namespace + PDFiumRange::PDFiumRange(PDFiumPage* page, int char_index, int char_count) - : page_(page), - char_index_(char_index), - char_count_(char_count), - cached_screen_rects_zoom_(0) {} + : page_(page), char_index_(char_index), char_count_(char_count) { +#if DCHECK_IS_ON() + AdjustForBackwardsRange(&char_index, &char_count); + DCHECK_LE(char_count, FPDFText_CountChars(page_->GetTextPage())); +#endif +} PDFiumRange::PDFiumRange(const PDFiumRange& that) = default; @@ -22,6 +37,11 @@ PDFiumRange::~PDFiumRange() = default; void PDFiumRange::SetCharCount(int char_count) { char_count_ = char_count; +#if DCHECK_IS_ON() + int dummy_index = 0; + AdjustForBackwardsRange(&dummy_index, &char_count); + DCHECK_LE(char_count, FPDFText_CountChars(page_->GetTextPage())); +#endif cached_screen_rects_offset_ = pp::Point(); cached_screen_rects_zoom_ = 0; @@ -42,10 +62,14 @@ const std::vector& PDFiumRange::GetScreenRects( int char_index = char_index_; int char_count = char_count_; - if (char_count < 0) { - char_count *= -1; - char_index -= char_count - 1; - } + if (char_count == 0) + return cached_screen_rects_; + + AdjustForBackwardsRange(&char_index, &char_count); + DCHECK_GE(char_index, 0) << " start: " << char_index_ + << " count: " << char_count_; + DCHECK_LT(char_index, FPDFText_CountChars(page_->GetTextPage())) + << " start: " << char_index_ << " count: " << char_count_; int count = FPDFText_CountRects(page_->GetTextPage(), char_index, char_count); for (int i = 0; i < count; ++i) { @@ -68,11 +92,10 @@ base::string16 PDFiumRange::GetText() const { int index = char_index_; int count = char_count_; base::string16 rv; - if (count < 0) { - count *= -1; - index -= count - 1; - } + if (count == 0) + return rv; + AdjustForBackwardsRange(&index, &count); if (count > 0) { PDFiumAPIStringBufferAdapter api_string_adapter(&rv, count, false); diff --git a/chromium/pdf/pdfium/pdfium_range.h b/chromium/pdf/pdfium/pdfium_range.h index 6137c4dc7cb..56b0fcadb8e 100644 --- a/chromium/pdf/pdfium/pdfium_range.h +++ b/chromium/pdf/pdfium/pdfium_range.h @@ -47,7 +47,7 @@ class PDFiumRange { // Cache of ScreenRect, and the associated variables used when caching it. std::vector cached_screen_rects_; pp::Point cached_screen_rects_offset_; - double cached_screen_rects_zoom_; + double cached_screen_rects_zoom_ = 0; }; } // namespace chrome_pdf diff --git a/chromium/pdf/preview_mode_client.cc b/chromium/pdf/preview_mode_client.cc index c824fdafe58..cfe2bfc99d2 100644 --- a/chromium/pdf/preview_mode_client.cc +++ b/chromium/pdf/preview_mode_client.cc @@ -18,7 +18,7 @@ void PreviewModeClient::Invalidate(const pp::Rect& rect) { NOTREACHED(); } -void PreviewModeClient::Scroll(const pp::Point& point) { +void PreviewModeClient::DidScroll(const pp::Point& point) { NOTREACHED(); } @@ -31,6 +31,10 @@ void PreviewModeClient::ScrollToY(int y_in_screen_coords, NOTREACHED(); } +void PreviewModeClient::ScrollBy(const pp::Point& point) { + NOTREACHED(); +} + void PreviewModeClient::ScrollToPage(int page) { NOTREACHED(); } @@ -132,7 +136,8 @@ void PreviewModeClient::DocumentPaintOccurred() { } void PreviewModeClient::DocumentLoadComplete( - const PDFEngine::DocumentFeatures& document_features) { + const PDFEngine::DocumentFeatures& document_features, + uint32_t file_size) { client_->PreviewDocumentLoadComplete(); } @@ -167,6 +172,10 @@ bool PreviewModeClient::IsPrintPreview() { void PreviewModeClient::CancelBrowserDownload() {} +float PreviewModeClient::GetToolbarHeightInScreenCoords() { + return 0.0f; +} + uint32_t PreviewModeClient::GetBackgroundColor() { NOTREACHED(); return 0; diff --git a/chromium/pdf/preview_mode_client.h b/chromium/pdf/preview_mode_client.h index 807cf800b40..3786478b0a9 100644 --- a/chromium/pdf/preview_mode_client.h +++ b/chromium/pdf/preview_mode_client.h @@ -29,9 +29,10 @@ class PreviewModeClient : public PDFEngine::Client { // PDFEngine::Client implementation. void DocumentSizeUpdated(const pp::Size& size) override; void Invalidate(const pp::Rect& rect) override; - void Scroll(const pp::Point& point) override; + void DidScroll(const pp::Point& point) override; void ScrollToX(int x_in_screen_coords) override; void ScrollToY(int y_in_screen_coords, bool compensate_for_toolbar) override; + void ScrollBy(const pp::Point& point) override; void ScrollToPage(int page) override; void NavigateTo(const std::string& url, WindowOpenDisposition disposition) override; @@ -65,7 +66,8 @@ class PreviewModeClient : public PDFEngine::Client { bool case_sensitive) override; void DocumentPaintOccurred() override; void DocumentLoadComplete( - const PDFEngine::DocumentFeatures& document_features) override; + const PDFEngine::DocumentFeatures& document_features, + uint32_t file_size) override; void DocumentLoadFailed() override; void FontSubstituted() override; pp::Instance* GetPluginInstance() override; @@ -74,6 +76,7 @@ class PreviewModeClient : public PDFEngine::Client { void FormTextFieldFocusChange(bool in_focus) override; bool IsPrintPreview() override; void CancelBrowserDownload() override; + float GetToolbarHeightInScreenCoords() override; uint32_t GetBackgroundColor() override; private: diff --git a/chromium/pdf/run_all_unittests.cc b/chromium/pdf/run_all_unittests.cc index 138e5a2361f..a700cb9765a 100644 --- a/chromium/pdf/run_all_unittests.cc +++ b/chromium/pdf/run_all_unittests.cc @@ -20,5 +20,5 @@ int main(int argc, char** argv) { base::TestSuite test_suite(argc, argv); return base::LaunchUnitTests( argc, argv, - base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite))); + base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite))); } -- cgit v1.2.1