1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "pdf/pdf_view_plugin_base.h"
15 #include "base/bind.h"
16 #include "base/callback.h"
17 #include "base/check.h"
18 #include "base/check_op.h"
19 #include "base/containers/span.h"
20 #include "base/cxx17_backports.h"
21 #include "base/feature_list.h"
22 #include "base/location.h"
23 #include "base/memory/weak_ptr.h"
24 #include "base/notreached.h"
25 #include "base/numerics/safe_conversions.h"
26 #include "base/strings/string_piece.h"
27 #include "base/strings/string_util.h"
28 #include "base/threading/thread_task_runner_handle.h"
29 #include "base/time/time.h"
30 #include "base/values.h"
31 #include "pdf/accessibility.h"
32 #include "pdf/accessibility_structs.h"
33 #include "pdf/buildflags.h"
34 #include "pdf/content_restriction.h"
35 #include "pdf/document_layout.h"
36 #include "pdf/document_metadata.h"
37 #include "pdf/paint_ready_rect.h"
38 #include "pdf/pdf_engine.h"
39 #include "pdf/pdf_features.h"
40 #include "pdf/pdfium/pdfium_engine.h"
41 #include "pdf/pdfium/pdfium_form_filler.h"
42 #include "pdf/ui/file_name.h"
43 #include "third_party/abseil-cpp/absl/types/optional.h"
44 #include "third_party/blink/public/common/input/web_input_event.h"
45 #include "third_party/blink/public/common/input/web_mouse_event.h"
46 #include "third_party/blink/public/common/input/web_touch_event.h"
47 #include "third_party/skia/include/core/SkBitmap.h"
48 #include "third_party/skia/include/core/SkImage.h"
49 #include "third_party/skia/include/core/SkRefCnt.h"
50 #include "ui/events/blink/blink_event_util.h"
51 #include "ui/gfx/geometry/point.h"
52 #include "ui/gfx/geometry/point_f.h"
53 #include "ui/gfx/geometry/rect.h"
54 #include "ui/gfx/geometry/size.h"
55 #include "ui/gfx/geometry/skia_conversions.h"
56 #include "ui/gfx/geometry/vector2d.h"
57 #include "ui/gfx/geometry/vector2d_f.h"
60 namespace chrome_pdf {
64 // A delay to wait between each accessibility page to keep the system
66 constexpr base::TimeDelta kAccessibilityPageDelay = base::Milliseconds(100);
70 PdfViewPluginBase::PdfViewPluginBase() = default;
72 PdfViewPluginBase::~PdfViewPluginBase() = default;
74 void PdfViewPluginBase::DocumentLoadComplete() {
75 DCHECK_EQ(DocumentLoadState::kLoading, document_load_state());
76 set_document_load_state(DocumentLoadState::kComplete);
78 UserMetricsRecordAction("PDF.LoadSuccess");
80 // Clear the focus state for on-screen keyboards.
81 FormFieldFocusChange(PDFEngine::FocusFieldType::kNoFocus);
84 OnPrintPreviewLoaded();
86 OnDocumentLoadComplete();
92 SetContentRestrictions(GetContentRestrictions());
95 void PdfViewPluginBase::DocumentLoadFailed() {
96 DCHECK_EQ(DocumentLoadState::kLoading, document_load_state());
97 set_document_load_state(DocumentLoadState::kFailed);
99 UserMetricsRecordAction("PDF.LoadFailure");
101 // Send a progress value of -1 to indicate a failure.
102 SendLoadingProgress(-1);
106 paint_manager().InvalidateRect(gfx::Rect(plugin_rect().size()));
109 void PdfViewPluginBase::SelectionChanged(const gfx::Rect& left,
110 const gfx::Rect& right) {
111 gfx::PointF left_point(left.x() + available_area().x(), left.y());
112 gfx::PointF right_point(right.x() + available_area().x(), right.y());
114 const float inverse_scale = 1.0f / device_scale();
115 left_point.Scale(inverse_scale);
116 right_point.Scale(inverse_scale);
118 NotifySelectionChanged(left_point, left.height() * inverse_scale, right_point,
119 right.height() * inverse_scale);
121 if (accessibility_state() == AccessibilityState::kLoaded)
122 PrepareAndSetAccessibilityViewportInfo();
125 int PdfViewPluginBase::GetContentRestrictions() const {
126 int content_restrictions = kContentRestrictionCut | kContentRestrictionPaste;
127 if (!engine()->HasPermission(DocumentPermission::kCopy))
128 content_restrictions |= kContentRestrictionCopy;
130 if (!engine()->HasPermission(DocumentPermission::kPrintLowQuality) &&
131 !engine()->HasPermission(DocumentPermission::kPrintHighQuality)) {
132 content_restrictions |= kContentRestrictionPrint;
135 return content_restrictions;
138 AccessibilityDocInfo PdfViewPluginBase::GetAccessibilityDocInfo() const {
139 AccessibilityDocInfo doc_info;
140 doc_info.page_count = engine()->GetNumberOfPages();
141 doc_info.text_accessible =
142 engine()->HasPermission(DocumentPermission::kCopyAccessible);
143 doc_info.text_copyable = engine()->HasPermission(DocumentPermission::kCopy);
147 void PdfViewPluginBase::PrepareAndSetAccessibilityPageInfo(int32_t page_index) {
148 // Outdated calls are ignored.
149 if (page_index != next_accessibility_page_index())
151 increment_next_accessibility_page_index();
153 AccessibilityPageInfo page_info;
154 std::vector<AccessibilityTextRunInfo> text_runs;
155 std::vector<AccessibilityCharInfo> chars;
156 AccessibilityPageObjects page_objects;
158 if (!GetAccessibilityInfo(engine(), page_index, page_info, text_runs, chars,
163 SetAccessibilityPageInfo(std::move(page_info), std::move(text_runs),
164 std::move(chars), std::move(page_objects));
166 // Schedule loading the next page.
167 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
169 base::BindOnce(&PdfViewPluginBase::PrepareAndSetAccessibilityPageInfo,
170 GetWeakPtr(), page_index + 1),
171 kAccessibilityPageDelay);
174 void PdfViewPluginBase::PrepareAndSetAccessibilityViewportInfo() {
175 AccessibilityViewportInfo viewport_info;
176 viewport_info.offset = gfx::ScaleToFlooredPoint(
177 available_area().origin(), 1 / (device_scale() * zoom()));
178 viewport_info.zoom = zoom();
179 viewport_info.scale = device_scale();
180 viewport_info.focus_info = {FocusObjectType::kNone, 0, 0};
182 engine()->GetSelection(&viewport_info.selection_start_page_index,
183 &viewport_info.selection_start_char_index,
184 &viewport_info.selection_end_page_index,
185 &viewport_info.selection_end_char_index);
187 SetAccessibilityViewportInfo(std::move(viewport_info));
190 void PdfViewPluginBase::LoadAccessibility() {
191 set_accessibility_state(AccessibilityState::kLoaded);
193 // A new document layout will trigger the creation of a new accessibility
194 // tree, so `next_accessibility_page_index_` should be reset to ignore
195 // outdated asynchronous calls of PrepareAndSetAccessibilityPageInfo().
196 reset_next_accessibility_page_index();
197 SetAccessibilityDocInfo(GetAccessibilityDocInfo());
199 // If the document contents isn't accessible, don't send anything more.
200 if (!(engine()->HasPermission(DocumentPermission::kCopy) ||
201 engine()->HasPermission(DocumentPermission::kCopyAccessible))) {
205 PrepareAndSetAccessibilityViewportInfo();
207 // Schedule loading the first page.
208 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
210 base::BindOnce(&PdfViewPluginBase::PrepareAndSetAccessibilityPageInfo,
211 GetWeakPtr(), /*page_index=*/0),
212 kAccessibilityPageDelay);
215 } // namespace chrome_pdf