12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003 |
- // Copyright 2020 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_view_web_plugin.h"
- #include <stddef.h>
- #include <stdint.h>
- #include <algorithm>
- #include <memory>
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/bind.h"
- #include "base/callback.h"
- #include "base/check_op.h"
- #include "base/containers/fixed_flat_map.h"
- #include "base/containers/queue.h"
- #include "base/debug/crash_logging.h"
- #include "base/i18n/char_iterator.h"
- #include "base/i18n/string_search.h"
- #include "base/i18n/time_formatting.h"
- #include "base/logging.h"
- #include "base/memory/raw_ptr.h"
- #include "base/no_destructor.h"
- #include "base/notreached.h"
- #include "base/numerics/safe_conversions.h"
- #include "base/strings/strcat.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/string_piece.h"
- #include "base/strings/string_split.h"
- #include "base/strings/string_util.h"
- #include "base/thread_annotations.h"
- #include "base/threading/sequenced_task_runner_handle.h"
- #include "base/threading/thread_checker.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/time/time.h"
- #include "base/values.h"
- #include "cc/paint/paint_canvas.h"
- #include "cc/paint/paint_flags.h"
- #include "cc/paint/paint_image.h"
- #include "cc/paint/paint_image_builder.h"
- #include "net/cookies/site_for_cookies.h"
- #include "pdf/accessibility_structs.h"
- #include "pdf/buildflags.h"
- #include "pdf/content_restriction.h"
- #include "pdf/document_layout.h"
- #include "pdf/loader/result_codes.h"
- #include "pdf/loader/url_loader.h"
- #include "pdf/metrics_handler.h"
- #include "pdf/mojom/pdf.mojom.h"
- #include "pdf/paint_ready_rect.h"
- #include "pdf/parsed_params.h"
- #include "pdf/pdf_accessibility_data_handler.h"
- #include "pdf/pdf_engine.h"
- #include "pdf/pdf_init.h"
- #include "pdf/pdfium/pdfium_engine.h"
- #include "pdf/post_message_receiver.h"
- #include "pdf/ui/document_properties.h"
- #include "pdf/ui/file_name.h"
- #include "pdf/ui/thumbnail.h"
- #include "printing/metafile_skia.h"
- #include "services/network/public/mojom/referrer_policy.mojom-shared.h"
- #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
- #include "third_party/blink/public/common/input/web_coalesced_input_event.h"
- #include "third_party/blink/public/common/input/web_input_event.h"
- #include "third_party/blink/public/common/input/web_keyboard_event.h"
- #include "third_party/blink/public/common/metrics/document_update_reason.h"
- #include "third_party/blink/public/mojom/input/focus_type.mojom-shared.h"
- #include "third_party/blink/public/platform/platform.h"
- #include "third_party/blink/public/platform/web_input_event_result.h"
- #include "third_party/blink/public/platform/web_string.h"
- #include "third_party/blink/public/platform/web_text_input_type.h"
- #include "third_party/blink/public/platform/web_url.h"
- #include "third_party/blink/public/platform/web_url_error.h"
- #include "third_party/blink/public/platform/web_url_response.h"
- #include "third_party/blink/public/web/web_associated_url_loader.h"
- #include "third_party/blink/public/web/web_associated_url_loader_options.h"
- #include "third_party/blink/public/web/web_document.h"
- #include "third_party/blink/public/web/web_frame.h"
- #include "third_party/blink/public/web/web_plugin_container.h"
- #include "third_party/blink/public/web/web_plugin_params.h"
- #include "third_party/blink/public/web/web_print_params.h"
- #include "third_party/blink/public/web/web_print_preset_options.h"
- #include "third_party/blink/public/web/web_view.h"
- #include "third_party/blink/public/web/web_widget.h"
- #include "third_party/skia/include/core/SkBitmap.h"
- #include "third_party/skia/include/core/SkColor.h"
- #include "third_party/skia/include/core/SkImage.h"
- #include "third_party/skia/include/core/SkImageInfo.h"
- #include "third_party/skia/include/core/SkRect.h"
- #include "third_party/skia/include/core/SkRefCnt.h"
- #include "third_party/skia/include/core/SkSize.h"
- #include "ui/base/cursor/cursor.h"
- #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
- #include "ui/base/text/bytes_formatting.h"
- #include "ui/events/base_event_utils.h"
- #include "ui/events/blink/blink_event_util.h"
- #include "ui/events/keycodes/keyboard_codes.h"
- #include "ui/gfx/geometry/point.h"
- #include "ui/gfx/geometry/point_f.h"
- #include "ui/gfx/geometry/rect.h"
- #include "ui/gfx/geometry/size.h"
- #include "ui/gfx/geometry/skia_conversions.h"
- #include "ui/gfx/geometry/vector2d.h"
- #include "ui/gfx/geometry/vector2d_f.h"
- #include "ui/gfx/range/range.h"
- #include "url/gurl.h"
- #include "v8/include/v8.h"
- namespace chrome_pdf {
- namespace {
- // The minimum zoom level allowed.
- constexpr double kMinZoom = 0.01;
- constexpr base::TimeDelta kFindResultCooldown = base::Milliseconds(100);
- constexpr base::StringPiece kChromeExtensionHost =
- "chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/";
- // Print Preview base URL.
- constexpr base::StringPiece kChromePrintHost = "chrome://print/";
- // Untrusted Print Preview base URL.
- constexpr base::StringPiece kChromeUntrustedPrintHost =
- "chrome-untrusted://print/";
- // Same value as `printing::COMPLETE_PREVIEW_DOCUMENT_INDEX`.
- constexpr int kCompletePDFIndex = -1;
- // A different negative value to differentiate itself from `kCompletePDFIndex`.
- constexpr int kInvalidPDFIndex = -2;
- // Enumeration of pinch states.
- // This should match PinchPhase enum in
- // chrome/browser/resources/pdf/viewport.ts.
- enum class PinchPhase {
- kNone = 0,
- kStart = 1,
- kUpdateZoomOut = 2,
- kUpdateZoomIn = 3,
- kEnd = 4,
- };
- // Initialization performed per renderer process. Initialization may be
- // triggered from multiple plugin instances, but should only execute once.
- //
- // TODO(crbug.com/1123621): We may be able to simplify this once we've figured
- // out exactly which processes need to initialize and shutdown PDFium.
- class PerProcessInitializer final {
- public:
- static PerProcessInitializer& GetInstance() {
- static base::NoDestructor<PerProcessInitializer,
- base::AllowForTriviallyDestructibleType>
- instance;
- return *instance;
- }
- void Acquire() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK_GE(init_count_, 0);
- if (init_count_++ > 0)
- return;
- DCHECK(!IsSDKInitializedViaPlugin());
- InitializeSDK(/*enable_v8=*/true, FontMappingMode::kBlink);
- SetIsSDKInitializedViaPlugin(true);
- }
- void Release() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK_GT(init_count_, 0);
- if (--init_count_ > 0)
- return;
- DCHECK(IsSDKInitializedViaPlugin());
- ShutdownSDK();
- SetIsSDKInitializedViaPlugin(false);
- }
- private:
- int init_count_ GUARDED_BY_CONTEXT(thread_checker_) = 0;
- // TODO(crbug.com/1123731): Assuming PDFium is thread-hostile for now, and
- // must use one thread exclusively.
- THREAD_CHECKER(thread_checker_);
- };
- base::Value::Dict DictFromRect(const gfx::Rect& rect) {
- base::Value::Dict dict;
- dict.Set("x", rect.x());
- dict.Set("y", rect.y());
- dict.Set("width", rect.width());
- dict.Set("height", rect.height());
- return dict;
- }
- bool IsPrintPreviewUrl(base::StringPiece url) {
- return base::StartsWith(url, kChromeUntrustedPrintHost);
- }
- int ExtractPrintPreviewPageIndex(base::StringPiece src_url) {
- // Sample `src_url` format: chrome-untrusted://print/id/page_index/print.pdf
- // The page_index is zero-based, but can be negative with special meanings.
- std::vector<base::StringPiece> url_substr =
- base::SplitStringPiece(src_url.substr(kChromeUntrustedPrintHost.size()),
- "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- if (url_substr.size() != 3)
- return kInvalidPDFIndex;
- if (url_substr[2] != "print.pdf")
- return kInvalidPDFIndex;
- int page_index = 0;
- if (!base::StringToInt(url_substr[1], &page_index))
- return kInvalidPDFIndex;
- return page_index;
- }
- bool IsPreviewingPDF(int print_preview_page_count) {
- return print_preview_page_count == 0;
- }
- // Prepares messages from the plugin that reply to messages from the embedder.
- // If the "type" value of `message` is "foo", then the `reply_type` must be
- // "fooReply". The `message` from the embedder must have a "messageId" value
- // that will be copied to the reply message.
- base::Value::Dict PrepareReplyMessage(base::StringPiece reply_type,
- const base::Value::Dict& message) {
- DCHECK_EQ(reply_type, *message.FindString("type") + "Reply");
- base::Value::Dict reply;
- reply.Set("type", reply_type);
- reply.Set("messageId", *message.FindString("messageId"));
- return reply;
- }
- } // namespace
- std::unique_ptr<PDFiumEngine> PdfViewWebPlugin::Client::CreateEngine(
- PDFEngine::Client* client,
- PDFiumFormFiller::ScriptOption script_option) {
- return std::make_unique<PDFiumEngine>(client, script_option);
- }
- std::unique_ptr<PdfAccessibilityDataHandler>
- PdfViewWebPlugin::Client::CreateAccessibilityDataHandler(
- PdfAccessibilityActionHandler* action_handler) {
- return nullptr;
- }
- PdfViewWebPlugin::PdfViewWebPlugin(
- std::unique_ptr<Client> client,
- mojo::AssociatedRemote<pdf::mojom::PdfService> pdf_service,
- const blink::WebPluginParams& params)
- : client_(std::move(client)),
- pdf_service_(std::move(pdf_service)),
- initial_params_(params),
- pdf_accessibility_data_handler_(
- client_->CreateAccessibilityDataHandler(this)) {
- DCHECK(pdf_service_);
- pdf_service_->SetListener(listener_receiver_.BindNewPipeAndPassRemote());
- }
- PdfViewWebPlugin::~PdfViewWebPlugin() = default;
- std::unique_ptr<PDFiumEngine> PdfViewWebPlugin::CreateEngine(
- PDFEngine::Client* client,
- PDFiumFormFiller::ScriptOption script_option) {
- return client_->CreateEngine(client, script_option);
- }
- // TODO(crbug.com/1302059): Delete after merging with `PdfViewPluginBase`.
- const PDFiumEngine* PdfViewWebPlugin::engine() const {
- return engine_.get();
- }
- // TODO(crbug.com/1302059): Delete after merging with `PdfViewPluginBase`.
- PDFiumEngine* PdfViewWebPlugin::engine() {
- return engine_.get();
- }
- bool PdfViewWebPlugin::Initialize(blink::WebPluginContainer* container) {
- DCHECK(container);
- client_->SetPluginContainer(container);
- DCHECK_EQ(container->Plugin(), this);
- return InitializeCommon();
- }
- bool PdfViewWebPlugin::InitializeForTesting() {
- return InitializeCommon();
- }
- bool PdfViewWebPlugin::InitializeCommon() {
- // Allow the plugin to handle touch events.
- client_->RequestTouchEventType(
- blink::WebPluginContainer::kTouchEventRequestTypeRaw);
- // Allow the plugin to handle find requests.
- client_->UsePluginAsFindHandler();
- absl::optional<ParsedParams> params = ParseWebPluginParams(initial_params_);
- // The contents of `initial_params_` are no longer needed.
- initial_params_ = {};
- if (!params.has_value())
- return false;
- // Sets crash keys like `ppapi::proxy::PDFResource::SetCrashData()`. Note that
- // we don't set the active URL from the top-level URL, as unlike within a
- // plugin process, the active URL changes frequently within a renderer process
- // (see crbug.com/1266050 for details).
- //
- // TODO(crbug.com/1266087): If multiple PDF plugin instances share the same
- // renderer process, the crash key will be overwritten by the newest value.
- static base::debug::CrashKeyString* subresource_url =
- base::debug::AllocateCrashKeyString("subresource_url",
- base::debug::CrashKeySize::Size256);
- base::debug::SetCrashKeyString(subresource_url, params->original_url);
- PerProcessInitializer::GetInstance().Acquire();
- // Check if the PDF is being loaded in the PDF chrome extension. We only allow
- // the plugin to be loaded in the extension and print preview to avoid
- // exposing sensitive APIs directly to external websites.
- //
- // This is enforced before creating the plugin (see
- // `pdf::CreateInternalPlugin()`), so we just `CHECK` for defense-in-depth.
- const std::string& embedder_origin = client_->GetEmbedderOriginString();
- is_print_preview_ = (embedder_origin == kChromePrintHost);
- CHECK(IsPrintPreview() || embedder_origin == kChromeExtensionHost);
- full_frame_ = params->full_frame;
- background_color_ = params->background_color;
- engine_ = CreateEngine(this, params->script_option);
- DCHECK(engine_);
- SendSetSmoothScrolling();
- // Skip the remaining initialization when in Print Preview mode. Loading will
- // continue after the plugin receives a "resetPrintPreviewMode" message.
- if (IsPrintPreview())
- return true;
- set_last_progress_sent(0);
- LoadUrl(params->src_url, base::BindOnce(&PdfViewWebPlugin::DidOpen,
- weak_factory_.GetWeakPtr()));
- url_ = params->original_url;
- // Not all edits go through the PDF plugin's form filler. The plugin instance
- // can be restarted by exiting annotation mode on ChromeOS, which can set the
- // document to an edited state.
- edit_mode_ = params->has_edits;
- #if !BUILDFLAG(ENABLE_INK)
- DCHECK(!edit_mode_);
- #endif // !BUILDFLAG(ENABLE_INK)
- metrics_handler_ = std::make_unique<MetricsHandler>();
- return true;
- }
- void PdfViewWebPlugin::SendSetSmoothScrolling() {
- base::Value::Dict message;
- message.Set("type", "setSmoothScrolling");
- message.Set("smoothScrolling",
- blink::Platform::Current()->IsScrollAnimatorEnabled());
- SendMessage(std::move(message));
- }
- void PdfViewWebPlugin::DidOpen(std::unique_ptr<UrlLoader> loader,
- int32_t result) {
- if (result == kSuccess) {
- if (!engine_->HandleDocumentLoad(std::move(loader), url_)) {
- set_document_load_state(DocumentLoadState::kLoading);
- DocumentLoadFailed();
- }
- } else if (result != kErrorAborted) {
- DocumentLoadFailed();
- }
- }
- void PdfViewWebPlugin::Destroy() {
- if (client_->PluginContainer()) {
- // Explicitly destroy the PDFEngine during destruction as it may call back
- // into this object.
- preview_engine_.reset();
- engine_.reset();
- PerProcessInitializer::GetInstance().Release();
- client_->SetPluginContainer(nullptr);
- }
- delete this;
- }
- blink::WebPluginContainer* PdfViewWebPlugin::Container() const {
- return client_->PluginContainer();
- }
- v8::Local<v8::Object> PdfViewWebPlugin::V8ScriptableObject(
- v8::Isolate* isolate) {
- if (scriptable_receiver_.IsEmpty()) {
- // TODO(crbug.com/1123731): Messages should not be handled on the renderer
- // main thread.
- scriptable_receiver_.Reset(
- isolate, PostMessageReceiver::Create(
- isolate, client_->GetWeakPtr(), weak_factory_.GetWeakPtr(),
- base::SequencedTaskRunnerHandle::Get()));
- }
- return scriptable_receiver_.Get(isolate);
- }
- bool PdfViewWebPlugin::SupportsKeyboardFocus() const {
- return !IsPrintPreview();
- }
- void PdfViewWebPlugin::UpdateAllLifecyclePhases(
- blink::DocumentUpdateReason reason) {}
- void PdfViewWebPlugin::Paint(cc::PaintCanvas* canvas, const gfx::Rect& rect) {
- // Clip the intersection of the paint rect and the plugin rect, so that
- // painting outside the plugin or the paint rect area can be avoided.
- // Note: `rect` is in CSS pixels. We need to use `css_plugin_rect_`
- // to calculate the intersection.
- SkRect invalidate_rect =
- gfx::RectToSkRect(gfx::IntersectRects(css_plugin_rect_, rect));
- cc::PaintCanvasAutoRestore auto_restore(canvas, /*save=*/true);
- canvas->clipRect(invalidate_rect);
- // Paint with the plugin's background color if the snapshot is not ready.
- if (snapshot_.GetSkImageInfo().isEmpty()) {
- cc::PaintFlags flags;
- flags.setBlendMode(SkBlendMode::kSrc);
- flags.setColor(GetBackgroundColor());
- canvas->drawRect(invalidate_rect, flags);
- return;
- }
- // Layer translate is independent of scaling, so apply first.
- if (!total_translate_.IsZero())
- canvas->translate(total_translate_.x(), total_translate_.y());
- if (device_to_css_scale_ != 1.0f)
- canvas->scale(device_to_css_scale_, device_to_css_scale_);
- // Position layer at plugin origin before layer scaling.
- if (!plugin_rect_.origin().IsOrigin())
- canvas->translate(plugin_rect_.x(), plugin_rect_.y());
- if (snapshot_scale_ != 1.0f)
- canvas->scale(snapshot_scale_, snapshot_scale_);
- canvas->drawImage(snapshot_, 0, 0);
- }
- void PdfViewWebPlugin::PrepareForFirstPaint(
- std::vector<PaintReadyRect>& ready) {
- if (!first_paint_)
- return;
- // Fill the image data buffer with the background color.
- first_paint_ = false;
- image_data().eraseColor(background_color_);
- ready.emplace_back(gfx::SkIRectToRect(image_data().bounds()),
- image_data().asImage(), /*flush_now=*/true);
- }
- void PdfViewWebPlugin::UpdateGeometry(const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect,
- const gfx::Rect& unobscured_rect,
- bool is_visible) {
- // An empty `window_rect` can be received here in the following cases:
- // - If the embedded plugin size is 0.
- // - If the embedded plugin size is not 0, it can come from re-layouts during
- // the plugin initialization.
- // For either case, there is no need to create a graphic device to display
- // a PDF in an empty window. Since an empty `window_rect` can cause failure
- // to create the graphic device, avoid all updates on the geometries and the
- // device scales used by the plugin, the PaintManager and the PDFiumEngine
- // unless a non-empty `window_rect` is received.
- if (window_rect.IsEmpty())
- return;
- OnViewportChanged(window_rect, client_->DeviceScaleFactor());
- gfx::PointF scroll_position = client_->GetScrollPosition();
- // Convert back to CSS pixels.
- scroll_position.Scale(1.0f / device_scale_);
- UpdateScroll(scroll_position);
- }
- void PdfViewWebPlugin::UpdateScroll(const gfx::PointF& scroll_position) {
- if (stop_scrolling_)
- return;
- float max_x = std::max(document_size().width() * static_cast<float>(zoom()) -
- plugin_dip_size_.width(),
- 0.0f);
- float max_y = std::max(document_size().height() * static_cast<float>(zoom()) -
- plugin_dip_size_.height(),
- 0.0f);
- gfx::PointF scaled_scroll_position(
- base::clamp(scroll_position.x(), 0.0f, max_x),
- base::clamp(scroll_position.y(), 0.0f, max_y));
- scaled_scroll_position.Scale(device_scale_);
- engine_->ScrolledToXPosition(scaled_scroll_position.x());
- engine_->ScrolledToYPosition(scaled_scroll_position.y());
- }
- void PdfViewWebPlugin::UpdateFocus(bool focused,
- blink::mojom::FocusType focus_type) {
- if (has_focus_ != focused) {
- engine_->UpdateFocus(focused);
- client_->UpdateTextInputState();
- client_->UpdateSelectionBounds();
- }
- has_focus_ = focused;
- if (!has_focus_ || !SupportsKeyboardFocus())
- return;
- if (focus_type != blink::mojom::FocusType::kBackward &&
- focus_type != blink::mojom::FocusType::kForward) {
- return;
- }
- const int modifiers = focus_type == blink::mojom::FocusType::kForward
- ? blink::WebInputEvent::kNoModifiers
- : blink::WebInputEvent::kShiftKey;
- blink::WebKeyboardEvent simulated_event(blink::WebInputEvent::Type::kKeyDown,
- modifiers, base::TimeTicks());
- simulated_event.windows_key_code = ui::KeyboardCode::VKEY_TAB;
- HandleWebInputEvent(simulated_event);
- }
- void PdfViewWebPlugin::UpdateVisibility(bool visibility) {}
- blink::WebInputEventResult PdfViewWebPlugin::HandleInputEvent(
- const blink::WebCoalescedInputEvent& event,
- ui::Cursor* cursor) {
- // TODO(crbug.com/1302059): The input events received by the Pepper plugin
- // already have the viewport-to-DIP scale applied. The scaling done here
- // should be moved into `HandleWebInputEvent()` once the Pepper plugin is
- // removed.
- std::unique_ptr<blink::WebInputEvent> scaled_event =
- ui::ScaleWebInputEvent(event.Event(), viewport_to_dip_scale_);
- const blink::WebInputEvent& event_to_handle =
- scaled_event ? *scaled_event : event.Event();
- const blink::WebInputEventResult result =
- HandleWebInputEvent(event_to_handle)
- ? blink::WebInputEventResult::kHandledApplication
- : blink::WebInputEventResult::kNotHandled;
- *cursor = cursor_type_;
- return result;
- }
- void PdfViewWebPlugin::DidReceiveResponse(
- const blink::WebURLResponse& response) {}
- void PdfViewWebPlugin::DidReceiveData(const char* data, size_t data_length) {}
- void PdfViewWebPlugin::DidFinishLoading() {}
- void PdfViewWebPlugin::DidFailLoading(const blink::WebURLError& error) {}
- bool PdfViewWebPlugin::SupportsPaginatedPrint() {
- return true;
- }
- bool PdfViewWebPlugin::GetPrintPresetOptionsFromDocument(
- blink::WebPrintPresetOptions* print_preset_options) {
- print_preset_options->is_scaling_disabled = !engine_->GetPrintScaling();
- print_preset_options->copies = engine_->GetCopiesToPrint();
- print_preset_options->duplex_mode = engine_->GetDuplexMode();
- print_preset_options->uniform_page_size = engine_->GetUniformPageSizePoints();
- return true;
- }
- int PdfViewWebPlugin::PrintBegin(const blink::WebPrintParams& print_params) {
- // The returned value is always equal to the number of pages in the PDF
- // document irrespective of the printable area.
- int32_t ret = engine_->GetNumberOfPages();
- if (!ret)
- return 0;
- if (!engine_->HasPermission(DocumentPermission::kPrintLowQuality))
- return 0;
- print_params_ = print_params;
- if (!engine_->HasPermission(DocumentPermission::kPrintHighQuality))
- print_params_->rasterize_pdf = true;
- engine_->PrintBegin();
- return ret;
- }
- void PdfViewWebPlugin::PrintPage(int page_number, cc::PaintCanvas* canvas) {
- // The entire document goes into one metafile. However, it is impossible to
- // know if a call to `PrintPage()` is the last call. Thus, `PrintPage()` just
- // stores the pages to print and the metafile. Eventually, the printed output
- // is generated in `PrintEnd()` and copied over to the metafile.
- // Every `canvas` passed to this method should have a valid `metafile`.
- printing::MetafileSkia* metafile = canvas->GetPrintingMetafile();
- DCHECK(metafile);
- // `pages_to_print_` should be empty iff `printing_metafile_` is not set.
- DCHECK_EQ(pages_to_print_.empty(), !printing_metafile_);
- // The metafile should be the same across all calls for a given print job.
- DCHECK(!printing_metafile_ || (printing_metafile_ == metafile));
- if (!printing_metafile_)
- printing_metafile_ = metafile;
- pages_to_print_.push_back(page_number);
- }
- void PdfViewWebPlugin::PrintEnd() {
- if (pages_to_print_.empty())
- return;
- print_pages_called_ = true;
- printing_metafile_->InitFromData(
- engine_->PrintPages(pages_to_print_, print_params_.value()));
- if (print_pages_called_)
- UserMetricsRecordAction("PDF.PrintPage");
- print_pages_called_ = false;
- print_params_.reset();
- engine_->PrintEnd();
- printing_metafile_ = nullptr;
- pages_to_print_.clear();
- }
- bool PdfViewWebPlugin::HasSelection() const {
- return !selected_text_.IsEmpty();
- }
- blink::WebString PdfViewWebPlugin::SelectionAsText() const {
- return selected_text_;
- }
- blink::WebString PdfViewWebPlugin::SelectionAsMarkup() const {
- return selected_text_;
- }
- bool PdfViewWebPlugin::CanEditText() const {
- return engine_->CanEditText();
- }
- bool PdfViewWebPlugin::HasEditableText() const {
- return engine_->HasEditableText();
- }
- bool PdfViewWebPlugin::CanUndo() const {
- return engine_->CanUndo();
- }
- bool PdfViewWebPlugin::CanRedo() const {
- return engine_->CanRedo();
- }
- bool PdfViewWebPlugin::CanCopy() const {
- return engine_->HasPermission(DocumentPermission::kCopy);
- }
- bool PdfViewWebPlugin::ExecuteEditCommand(const blink::WebString& name,
- const blink::WebString& value) {
- if (name == "SelectAll")
- return SelectAll();
- if (name == "Cut")
- return Cut();
- if (name == "Paste" || name == "PasteAndMatchStyle")
- return Paste(value);
- if (name == "Undo")
- return Undo();
- if (name == "Redo")
- return Redo();
- return false;
- }
- blink::WebURL PdfViewWebPlugin::LinkAtPosition(
- const gfx::Point& /*position*/) const {
- return GURL(link_under_cursor_);
- }
- bool PdfViewWebPlugin::StartFind(const blink::WebString& search_text,
- bool case_sensitive,
- int identifier) {
- ResetRecentlySentFindUpdate();
- find_identifier_ = identifier;
- engine_->StartFind(search_text.Utf8(), case_sensitive);
- return true;
- }
- void PdfViewWebPlugin::SelectFindResult(bool forward, int identifier) {
- find_identifier_ = identifier;
- engine_->SelectFindResult(forward);
- }
- void PdfViewWebPlugin::StopFind() {
- find_identifier_ = -1;
- engine_->StopFind();
- tickmarks_.clear();
- client_->ReportFindInPageTickmarks(tickmarks_);
- }
- bool PdfViewWebPlugin::CanRotateView() {
- return !IsPrintPreview();
- }
- void PdfViewWebPlugin::RotateView(blink::WebPlugin::RotationType type) {
- DCHECK(CanRotateView());
- switch (type) {
- case blink::WebPlugin::RotationType::k90Clockwise:
- engine_->RotateClockwise();
- break;
- case blink::WebPlugin::RotationType::k90Counterclockwise:
- engine_->RotateCounterclockwise();
- break;
- }
- }
- bool PdfViewWebPlugin::ShouldDispatchImeEventsToPlugin() {
- return true;
- }
- blink::WebTextInputType PdfViewWebPlugin::GetPluginTextInputType() {
- return text_input_type_;
- }
- gfx::Rect PdfViewWebPlugin::GetPluginCaretBounds() {
- return caret_rect_;
- }
- void PdfViewWebPlugin::ImeSetCompositionForPlugin(
- const blink::WebString& text,
- const std::vector<ui::ImeTextSpan>& /*ime_text_spans*/,
- const gfx::Range& /*replacement_range*/,
- int /*selection_start*/,
- int /*selection_end*/) {
- composition_text_ = text;
- }
- void PdfViewWebPlugin::ImeCommitTextForPlugin(
- const blink::WebString& text,
- const std::vector<ui::ImeTextSpan>& /*ime_text_spans*/,
- const gfx::Range& /*replacement_range*/,
- int /*relative_cursor_pos*/) {
- HandleImeCommit(text);
- }
- void PdfViewWebPlugin::ImeFinishComposingTextForPlugin(
- bool /*keep_selection*/) {
- HandleImeCommit(composition_text_);
- }
- void PdfViewWebPlugin::ProposeDocumentLayout(const DocumentLayout& layout) {
- base::Value::Dict message;
- message.Set("type", "documentDimensions");
- message.Set("width", layout.size().width());
- message.Set("height", layout.size().height());
- message.Set("layoutOptions", layout.options().ToValue());
- base::Value::List page_dimensions;
- for (size_t i = 0; i < layout.page_count(); ++i)
- page_dimensions.Append(DictFromRect(layout.page_rect(i)));
- message.Set("pageDimensions", std::move(page_dimensions));
- SendMessage(std::move(message));
- // Reload the accessibility tree on layout changes because the relative page
- // bounds are no longer valid.
- if (layout.dirty() && accessibility_state() == AccessibilityState::kLoaded)
- LoadAccessibility();
- }
- void PdfViewWebPlugin::UpdateCursor(ui::mojom::CursorType new_cursor_type) {
- cursor_type_ = new_cursor_type;
- }
- void PdfViewWebPlugin::UpdateTickMarks(
- const std::vector<gfx::Rect>& tickmarks) {
- float inverse_scale = 1.0f / device_scale_;
- tickmarks_.clear();
- tickmarks_.reserve(tickmarks.size());
- std::transform(tickmarks.begin(), tickmarks.end(),
- std::back_inserter(tickmarks_),
- [inverse_scale](const gfx::Rect& t) -> gfx::Rect {
- return gfx::ScaleToEnclosingRect(t, inverse_scale);
- });
- }
- void PdfViewWebPlugin::NotifyNumberOfFindResultsChanged(int total,
- bool final_result) {
- // We don't want to spam the renderer with too many updates to the number of
- // find results. Don't send an update if we sent one too recently. If it's the
- // final update, we always send it though.
- if (recently_sent_find_update_ && !final_result)
- return;
- // After stopping search and setting `find_identifier_` to -1 there still may
- // be a NotifyNumberOfFindResultsChanged notification pending from engine.
- // Just ignore them.
- if (find_identifier_ != -1) {
- client_->ReportFindInPageMatchCount(find_identifier_, total, final_result);
- }
- client_->ReportFindInPageTickmarks(tickmarks_);
- if (final_result)
- return;
- recently_sent_find_update_ = true;
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&PdfViewWebPlugin::ResetRecentlySentFindUpdate,
- weak_factory_.GetWeakPtr()),
- kFindResultCooldown);
- }
- void PdfViewWebPlugin::NotifySelectedFindResultChanged(int current_find_index,
- bool final_result) {
- if (find_identifier_ == -1 || !client_->PluginContainer())
- return;
- DCHECK_GE(current_find_index, -1);
- client_->ReportFindInPageSelection(find_identifier_, current_find_index + 1,
- final_result);
- }
- void PdfViewWebPlugin::CaretChanged(const gfx::Rect& caret_rect) {
- caret_rect_ = gfx::ScaleToEnclosingRect(
- caret_rect + available_area().OffsetFromOrigin(), device_to_css_scale_);
- }
- void PdfViewWebPlugin::GetDocumentPassword(
- base::OnceCallback<void(const std::string&)> callback) {
- DCHECK(password_callback_.is_null());
- password_callback_ = std::move(callback);
- base::Value::Dict message;
- message.Set("type", "getPassword");
- SendMessage(std::move(message));
- }
- void PdfViewWebPlugin::Beep() {
- base::Value::Dict message;
- message.Set("type", "beep");
- SendMessage(std::move(message));
- }
- void PdfViewWebPlugin::Alert(const std::string& message) {
- client_->Alert(blink::WebString::FromUTF8(message));
- }
- bool PdfViewWebPlugin::Confirm(const std::string& message) {
- return client_->Confirm(blink::WebString::FromUTF8(message));
- }
- std::string PdfViewWebPlugin::Prompt(const std::string& question,
- const std::string& default_answer) {
- return client_
- ->Prompt(blink::WebString::FromUTF8(question),
- blink::WebString::FromUTF8(default_answer))
- .Utf8();
- }
- std::string PdfViewWebPlugin::GetURL() {
- return url_;
- }
- void PdfViewWebPlugin::LoadUrl(base::StringPiece url,
- LoadUrlCallback callback) {
- UrlRequest request;
- request.url = std::string(url);
- request.method = "GET";
- request.ignore_redirects = true;
- auto loader = std::make_unique<UrlLoader>(weak_factory_.GetWeakPtr());
- UrlLoader* raw_loader = loader.get();
- raw_loader->Open(request,
- base::BindOnce(std::move(callback), std::move(loader)));
- }
- void PdfViewWebPlugin::Print() {
- if (!engine_)
- return;
- const bool can_print =
- engine_->HasPermission(DocumentPermission::kPrintLowQuality) ||
- engine_->HasPermission(DocumentPermission::kPrintHighQuality);
- if (!can_print)
- return;
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&PdfViewWebPlugin::OnInvokePrintDialog,
- weak_factory_.GetWeakPtr()));
- }
- void PdfViewWebPlugin::SubmitForm(const std::string& url,
- const void* data,
- int length) {
- // `url` might be a relative URL. Resolve it against the document's URL.
- // TODO(crbug.com/1322928): Probably redundant with `Client::CompleteURL()`.
- GURL resolved_url = GURL(url_).Resolve(url);
- if (!resolved_url.is_valid())
- return;
- UrlRequest request;
- request.url = resolved_url.spec();
- request.method = "POST";
- request.body.assign(static_cast<const char*>(data), length);
- form_loader_ = std::make_unique<UrlLoader>(weak_factory_.GetWeakPtr());
- form_loader_->Open(request, base::BindOnce(&PdfViewWebPlugin::DidFormOpen,
- weak_factory_.GetWeakPtr()));
- }
- void PdfViewWebPlugin::DidFormOpen(int32_t result) {
- // TODO(crbug.com/719344): Process response.
- LOG_IF(ERROR, result != kSuccess) << "DidFormOpen failed: " << result;
- form_loader_.reset();
- }
- std::unique_ptr<UrlLoader> PdfViewWebPlugin::CreateUrlLoader() {
- if (full_frame_) {
- DidStartLoading();
- // Disable save and print until the document is fully loaded, since they
- // would generate an incomplete document. This needs to be done each time
- // DidStartLoading() is called because that resets the content restrictions.
- SetContentRestrictions(kContentRestrictionSave | kContentRestrictionPrint);
- }
- return std::make_unique<UrlLoader>(weak_factory_.GetWeakPtr());
- }
- std::vector<PDFEngine::Client::SearchStringResult>
- PdfViewWebPlugin::SearchString(const char16_t* string,
- const char16_t* term,
- bool case_sensitive) {
- base::i18n::RepeatingStringSearch searcher(
- /*find_this=*/term, /*in_this=*/string, case_sensitive);
- std::vector<SearchStringResult> results;
- int match_index;
- int match_length;
- while (searcher.NextMatchResult(match_index, match_length))
- results.push_back({.start_index = match_index, .length = match_length});
- return results;
- }
- void PdfViewWebPlugin::DocumentHasUnsupportedFeature(
- const std::string& feature) {
- DCHECK(!feature.empty());
- std::string metric = base::StrCat({"PDF_Unsupported_", feature});
- if (unsupported_features_reported_.insert(metric).second)
- client_->RecordComputedAction(metric);
- if (!full_frame() || notified_browser_about_unsupported_feature_)
- return;
- notified_browser_about_unsupported_feature_ = true;
- pdf_service_->HasUnsupportedFeature();
- }
- bool PdfViewWebPlugin::IsPrintPreview() const {
- return is_print_preview_;
- }
- SkColor PdfViewWebPlugin::GetBackgroundColor() const {
- return background_color_;
- }
- void PdfViewWebPlugin::EnteredEditMode() {
- edit_mode_ = true;
- pdf_service_->SetPluginCanSave(true);
- base::Value::Dict message;
- message.Set("type", "setIsEditing");
- SendMessage(std::move(message));
- }
- void PdfViewWebPlugin::SetSelectedText(const std::string& selected_text) {
- selected_text_ = blink::WebString::FromUTF8(selected_text);
- client_->TextSelectionChanged(selected_text_, /*offset=*/0,
- gfx::Range(0, selected_text_.length()));
- }
- void PdfViewWebPlugin::SetLinkUnderCursor(
- const std::string& link_under_cursor) {
- link_under_cursor_ = link_under_cursor;
- }
- bool PdfViewWebPlugin::IsValidLink(const std::string& url) {
- return base::Value(url).is_string();
- }
- void PdfViewWebPlugin::SetCaretPosition(const gfx::PointF& position) {
- engine_->SetCaretPosition(FrameToPdfCoordinates(position));
- }
- void PdfViewWebPlugin::MoveRangeSelectionExtent(const gfx::PointF& extent) {
- engine_->MoveRangeSelectionExtent(FrameToPdfCoordinates(extent));
- }
- void PdfViewWebPlugin::SetSelectionBounds(const gfx::PointF& base,
- const gfx::PointF& extent) {
- engine_->SetSelectionBounds(FrameToPdfCoordinates(base),
- FrameToPdfCoordinates(extent));
- }
- bool PdfViewWebPlugin::IsValid() const {
- return client_->HasFrame();
- }
- blink::WebURL PdfViewWebPlugin::CompleteURL(
- const blink::WebString& partial_url) const {
- DCHECK(IsValid());
- return client_->CompleteURL(partial_url);
- }
- net::SiteForCookies PdfViewWebPlugin::SiteForCookies() const {
- DCHECK(IsValid());
- return client_->SiteForCookies();
- }
- void PdfViewWebPlugin::SetReferrerForRequest(
- blink::WebURLRequest& request,
- const blink::WebURL& referrer_url) {
- client_->SetReferrerForRequest(request, referrer_url);
- }
- std::unique_ptr<blink::WebAssociatedURLLoader>
- PdfViewWebPlugin::CreateAssociatedURLLoader(
- const blink::WebAssociatedURLLoaderOptions& options) {
- return client_->CreateAssociatedURLLoader(options);
- }
- void PdfViewWebPlugin::OnMessage(const base::Value::Dict& message) {
- using MessageHandler = void (PdfViewWebPlugin::*)(const base::Value::Dict&);
- // Settings this as const instead of constexpr to workaround a bug
- // in GCC, that will try to reinterpret_cast the method pointers.
- // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105996
- // TODO(crbug.com/1302059): make it constexpr again when we get rid
- // of PdfViewPluginBase
- static const auto kMessageHandlers =
- base::MakeFixedFlatMap<base::StringPiece, MessageHandler>({
- {"displayAnnotations",
- &PdfViewWebPlugin::HandleDisplayAnnotationsMessage},
- {"getNamedDestination",
- &PdfViewWebPlugin::HandleGetNamedDestinationMessage},
- {"getPasswordComplete",
- &PdfViewWebPlugin::HandleGetPasswordCompleteMessage},
- {"getSelectedText", &PdfViewWebPlugin::HandleGetSelectedTextMessage},
- {"getThumbnail", &PdfViewWebPlugin::HandleGetThumbnailMessage},
- {"print", &PdfViewWebPlugin::HandlePrintMessage},
- {"loadPreviewPage", &PdfViewWebPlugin::HandleLoadPreviewPageMessage},
- {"resetPrintPreviewMode",
- &PdfViewWebPlugin::HandleResetPrintPreviewModeMessage},
- {"rotateClockwise", &PdfViewWebPlugin::HandleRotateClockwiseMessage},
- {"rotateCounterclockwise",
- &PdfViewWebPlugin::HandleRotateCounterclockwiseMessage},
- {"save", &PdfViewWebPlugin::HandleSaveMessage},
- {"saveAttachment", &PdfViewWebPlugin::HandleSaveAttachmentMessage},
- {"selectAll", &PdfViewWebPlugin::HandleSelectAllMessage},
- {"setBackgroundColor",
- &PdfViewWebPlugin::HandleSetBackgroundColorMessage},
- {"setPresentationMode",
- &PdfViewWebPlugin::HandleSetPresentationModeMessage},
- {"setTwoUpView", &PdfViewWebPlugin::HandleSetTwoUpViewMessage},
- {"stopScrolling", &PdfViewWebPlugin::HandleStopScrollingMessage},
- {"viewport", &PdfViewWebPlugin::HandleViewportMessage},
- });
- MessageHandler handler = kMessageHandlers.at(*message.FindString("type"));
- (this->*handler)(message);
- }
- void PdfViewWebPlugin::HandleDisplayAnnotationsMessage(
- const base::Value::Dict& message) {
- engine_->DisplayAnnotations(message.FindBool("display").value());
- }
- void PdfViewWebPlugin::HandleGetNamedDestinationMessage(
- const base::Value::Dict& message) {
- absl::optional<PDFEngine::NamedDestination> named_destination =
- engine_->GetNamedDestination(*message.FindString("namedDestination"));
- const int page_number = named_destination.has_value()
- ? base::checked_cast<int>(named_destination->page)
- : -1;
- base::Value::Dict reply =
- PrepareReplyMessage("getNamedDestinationReply", message);
- reply.Set("pageNumber", page_number);
- if (named_destination.has_value() && !named_destination->view.empty()) {
- std::ostringstream view_stream;
- view_stream << named_destination->view;
- if (named_destination->xyz_params.empty()) {
- for (unsigned long i = 0; i < named_destination->num_params; ++i)
- view_stream << "," << named_destination->params[i];
- } else {
- view_stream << "," << named_destination->xyz_params;
- }
- reply.Set("namedDestinationView", view_stream.str());
- }
- SendMessage(std::move(reply));
- }
- void PdfViewWebPlugin::HandleGetPasswordCompleteMessage(
- const base::Value::Dict& message) {
- DCHECK(password_callback_);
- std::move(password_callback_).Run(*message.FindString("password"));
- }
- void PdfViewWebPlugin::HandleGetSelectedTextMessage(
- const base::Value::Dict& message) {
- // Always return unix newlines to JavaScript.
- std::string selected_text;
- base::RemoveChars(engine_->GetSelectedText(), "\r", &selected_text);
- base::Value::Dict reply =
- PrepareReplyMessage("getSelectedTextReply", message);
- reply.Set("selectedText", selected_text);
- SendMessage(std::move(reply));
- }
- void PdfViewWebPlugin::HandleGetThumbnailMessage(
- const base::Value::Dict& message) {
- const int page_index = message.FindInt("page").value();
- base::Value::Dict reply = PrepareReplyMessage("getThumbnailReply", message);
- engine_->RequestThumbnail(
- page_index, device_scale(),
- base::BindOnce(&PdfViewWebPlugin::SendThumbnail,
- weak_factory_.GetWeakPtr(), std::move(reply)));
- }
- void PdfViewWebPlugin::HandlePrintMessage(
- const base::Value::Dict& /*message*/) {
- Print();
- }
- void PdfViewWebPlugin::HandleRotateClockwiseMessage(
- const base::Value::Dict& /*message*/) {
- engine_->RotateClockwise();
- }
- void PdfViewWebPlugin::HandleRotateCounterclockwiseMessage(
- const base::Value::Dict& /*message*/) {
- engine_->RotateCounterclockwise();
- }
- void PdfViewWebPlugin::HandleSaveAttachmentMessage(
- const base::Value::Dict& message) {
- const int index = message.FindInt("attachmentIndex").value();
- const std::vector<DocumentAttachmentInfo>& list =
- engine_->GetDocumentAttachmentInfoList();
- DCHECK_GE(index, 0);
- DCHECK_LT(static_cast<size_t>(index), list.size());
- DCHECK(list[index].is_readable);
- DCHECK(IsSaveDataSizeValid(list[index].size_bytes));
- std::vector<uint8_t> data = engine_->GetAttachmentData(index);
- base::Value data_to_save(
- IsSaveDataSizeValid(data.size()) ? data : std::vector<uint8_t>());
- base::Value::Dict reply = PrepareReplyMessage("saveAttachmentReply", message);
- reply.Set("dataToSave", std::move(data_to_save));
- SendMessage(std::move(reply));
- }
- void PdfViewWebPlugin::HandleSaveMessage(const base::Value::Dict& message) {
- const std::string& token = *message.FindString("token");
- int request_type = message.FindInt("saveRequestType").value();
- DCHECK_GE(request_type, static_cast<int>(SaveRequestType::kAnnotation));
- DCHECK_LE(request_type, static_cast<int>(SaveRequestType::kEdited));
- switch (static_cast<SaveRequestType>(request_type)) {
- case SaveRequestType::kAnnotation:
- #if BUILDFLAG(ENABLE_INK)
- // In annotation mode, assume the user will make edits and prefer saving
- // using the plugin data.
- pdf_service_->SetPluginCanSave(true);
- SaveToBuffer(token);
- #else
- NOTREACHED();
- #endif // BUILDFLAG(ENABLE_INK)
- break;
- case SaveRequestType::kOriginal:
- pdf_service_->SetPluginCanSave(false);
- SaveToFile(token);
- pdf_service_->SetPluginCanSave(edit_mode_);
- break;
- case SaveRequestType::kEdited:
- SaveToBuffer(token);
- break;
- }
- }
- void PdfViewWebPlugin::HandleSelectAllMessage(
- const base::Value::Dict& /*message*/) {
- engine_->SelectAll();
- }
- void PdfViewWebPlugin::HandleSetBackgroundColorMessage(
- const base::Value::Dict& message) {
- background_color_ =
- base::checked_cast<SkColor>(message.FindDouble("color").value());
- }
- void PdfViewWebPlugin::HandleSetPresentationModeMessage(
- const base::Value::Dict& message) {
- engine_->SetReadOnly(message.FindBool("enablePresentationMode").value());
- }
- void PdfViewWebPlugin::HandleSetTwoUpViewMessage(
- const base::Value::Dict& message) {
- engine_->SetDocumentLayout(message.FindBool("enableTwoUpView").value()
- ? DocumentLayout::PageSpread::kTwoUpOdd
- : DocumentLayout::PageSpread::kOneUp);
- }
- void PdfViewWebPlugin::HandleStopScrollingMessage(
- const base::Value::Dict& /*message*/) {
- stop_scrolling_ = true;
- }
- void PdfViewWebPlugin::HandleViewportMessage(const base::Value::Dict& message) {
- const base::Value::Dict* layout_options_value =
- message.FindDict("layoutOptions");
- if (layout_options_value) {
- DocumentLayout::Options layout_options;
- layout_options.FromValue(*layout_options_value);
- ui_direction_ = layout_options.direction();
- // TODO(crbug.com/1013800): Eliminate need to get document size from here.
- set_document_size(engine_->ApplyDocumentLayout(layout_options));
- OnGeometryChanged(zoom(), device_scale_);
- if (!document_size().IsEmpty())
- paint_manager().InvalidateRect(gfx::Rect(plugin_rect_.size()));
- // Send 100% loading progress only after initial layout negotiated.
- if (last_progress_sent() < 100 &&
- document_load_state() == DocumentLoadState::kComplete) {
- SendLoadingProgress(/*percentage=*/100);
- }
- }
- gfx::Vector2dF scroll_offset(*message.FindDouble("xOffset"),
- *message.FindDouble("yOffset"));
- double new_zoom = *message.FindDouble("zoom");
- const PinchPhase pinch_phase =
- static_cast<PinchPhase>(*message.FindInt("pinchPhase"));
- received_viewport_message_ = true;
- stop_scrolling_ = false;
- const double zoom_ratio = new_zoom / zoom();
- if (pinch_phase == PinchPhase::kStart) {
- scroll_offset_at_last_raster_ = scroll_offset;
- last_bitmap_smaller_ = false;
- needs_reraster_ = false;
- return;
- }
- // When zooming in, we set a layer transform to avoid unneeded rerasters.
- // Also, if we're zooming out and the last time we rerastered was when
- // we were even further zoomed out (i.e. we pinch zoomed in and are now
- // pinch zooming back out in the same gesture), we update the layer
- // transform instead of rerastering.
- if (pinch_phase == PinchPhase::kUpdateZoomIn ||
- (pinch_phase == PinchPhase::kUpdateZoomOut && zoom_ratio > 1.0)) {
- // Get the coordinates of the center of the pinch gesture.
- const double pinch_x = *message.FindDouble("pinchX");
- const double pinch_y = *message.FindDouble("pinchY");
- gfx::Point pinch_center(pinch_x, pinch_y);
- // Get the pinch vector which represents the panning caused by the change in
- // pinch center between the start and the end of the gesture.
- const double pinch_vector_x = *message.FindDouble("pinchVectorX");
- const double pinch_vector_y = *message.FindDouble("pinchVectorY");
- gfx::Vector2d pinch_vector =
- gfx::Vector2d(pinch_vector_x * zoom_ratio, pinch_vector_y * zoom_ratio);
- gfx::Vector2d scroll_delta;
- // If the rendered document doesn't fill the display area we will
- // use `paint_offset` to anchor the paint vertically into the same place.
- // We use the scroll bars instead of the pinch vector to get the actual
- // position on screen of the paint.
- gfx::Vector2d paint_offset;
- if (plugin_rect_.width() > GetDocumentPixelWidth() * zoom_ratio) {
- // We want to keep the paint in the middle but it must stay in the same
- // position relative to the scroll bars.
- paint_offset = gfx::Vector2d(0, (1 - zoom_ratio) * pinch_center.y());
- scroll_delta = gfx::Vector2d(
- 0,
- (scroll_offset.y() - scroll_offset_at_last_raster_.y() * zoom_ratio));
- pinch_vector = gfx::Vector2d();
- last_bitmap_smaller_ = true;
- } else if (last_bitmap_smaller_) {
- // When the document width covers the display area's width, we will anchor
- // the scroll bars disregarding where the actual pinch certer is.
- pinch_center = gfx::Point((plugin_rect_.width() / device_scale_) / 2,
- (plugin_rect_.height() / device_scale_) / 2);
- const double zoom_when_doc_covers_plugin_width =
- zoom() * plugin_rect_.width() / GetDocumentPixelWidth();
- paint_offset = gfx::Vector2d(
- (1 - new_zoom / zoom_when_doc_covers_plugin_width) * pinch_center.x(),
- (1 - zoom_ratio) * pinch_center.y());
- pinch_vector = gfx::Vector2d();
- scroll_delta = gfx::Vector2d(
- (scroll_offset.x() - scroll_offset_at_last_raster_.x() * zoom_ratio),
- (scroll_offset.y() - scroll_offset_at_last_raster_.y() * zoom_ratio));
- }
- paint_manager().SetTransform(zoom_ratio, pinch_center,
- pinch_vector + paint_offset + scroll_delta,
- true);
- needs_reraster_ = false;
- return;
- }
- if (pinch_phase == PinchPhase::kUpdateZoomOut ||
- pinch_phase == PinchPhase::kEnd) {
- // We reraster on pinch zoom out in order to solve the invalid regions
- // that appear after zooming out.
- // On pinch end the scale is again 1.f and we request a reraster
- // in the new position.
- paint_manager().ClearTransform();
- last_bitmap_smaller_ = false;
- needs_reraster_ = true;
- // If we're rerastering due to zooming out, we need to update the scroll
- // offset for the last raster, in case the user continues the gesture by
- // zooming in.
- scroll_offset_at_last_raster_ = scroll_offset;
- }
- // Bound the input parameters.
- new_zoom = std::max(kMinZoom, new_zoom);
- DCHECK(message.FindBool("userInitiated").has_value());
- SetZoom(new_zoom);
- UpdateScroll(GetScrollPositionFromOffset(scroll_offset));
- }
- void PdfViewWebPlugin::SaveToBuffer(const std::string& token) {
- engine_->KillFormFocus();
- base::Value::Dict message;
- message.Set("type", "saveData");
- message.Set("token", token);
- message.Set("fileName", GetFileNameForSaveFromUrl(url_));
- // Expose `edit_mode_` state for integration testing.
- message.Set("editModeForTesting", edit_mode_);
- base::Value data_to_save;
- if (edit_mode_) {
- base::Value::BlobStorage data = engine_->GetSaveData();
- if (IsSaveDataSizeValid(data.size()))
- data_to_save = base::Value(std::move(data));
- } else {
- #if BUILDFLAG(ENABLE_INK)
- uint32_t length = engine_->GetLoadedByteSize();
- if (IsSaveDataSizeValid(length)) {
- base::Value::BlobStorage data(length);
- if (engine_->ReadLoadedBytes(length, data.data()))
- data_to_save = base::Value(std::move(data));
- }
- #else
- NOTREACHED();
- #endif // BUILDFLAG(ENABLE_INK)
- }
- message.Set("dataToSave", std::move(data_to_save));
- SendMessage(std::move(message));
- }
- void PdfViewWebPlugin::SaveToFile(const std::string& token) {
- engine_->KillFormFocus();
- base::Value::Dict message;
- message.Set("type", "consumeSaveToken");
- message.Set("token", token);
- SendMessage(std::move(message));
- // TODO(crbug.com/1302059): Is there a good reason to null-terminate here?
- pdf_service_->SaveUrlAs(GURL(url_.c_str()),
- network::mojom::ReferrerPolicy::kDefault);
- }
- void PdfViewWebPlugin::InvalidatePluginContainer() {
- client_->Invalidate();
- }
- void PdfViewWebPlugin::UpdateSnapshot(sk_sp<SkImage> snapshot) {
- snapshot_ =
- cc::PaintImageBuilder::WithDefault()
- .set_image(std::move(snapshot), cc::PaintImage::GetNextContentId())
- .set_id(cc::PaintImage::GetNextId())
- .TakePaintImage();
- if (!plugin_rect_.IsEmpty())
- InvalidatePluginContainer();
- }
- void PdfViewWebPlugin::UpdateScaledValues() {
- total_translate_ = snapshot_translate_;
- if (viewport_to_dip_scale_ != 1.0f)
- total_translate_.Scale(1.0f / viewport_to_dip_scale_);
- }
- void PdfViewWebPlugin::UpdateScale(float scale) {
- if (scale <= 0.0f) {
- NOTREACHED();
- return;
- }
- viewport_to_dip_scale_ = scale;
- device_to_css_scale_ = 1.0f;
- UpdateScaledValues();
- }
- void PdfViewWebPlugin::UpdateLayerTransform(float scale,
- const gfx::Vector2dF& translate) {
- snapshot_translate_ = translate;
- snapshot_scale_ = scale;
- UpdateScaledValues();
- }
- void PdfViewWebPlugin::EnableAccessibility() {
- if (accessibility_state() == AccessibilityState::kLoaded)
- return;
- if (accessibility_state() == AccessibilityState::kOff)
- set_accessibility_state(AccessibilityState::kPending);
- if (document_load_state() == DocumentLoadState::kComplete)
- LoadAccessibility();
- }
- void PdfViewWebPlugin::HandleAccessibilityAction(
- const AccessibilityActionData& action_data) {
- engine_->HandleAccessibilityAction(action_data);
- }
- base::WeakPtr<PdfViewPluginBase> PdfViewWebPlugin::GetWeakPtr() {
- return weak_factory_.GetWeakPtr();
- }
- void PdfViewWebPlugin::OnPrintPreviewLoaded() {
- // Scroll location is retained across document loads in Print Preview, so
- // there's no need to override the scroll position by scrolling again.
- if (IsPreviewingPDF(print_preview_page_count_)) {
- SendPrintPreviewLoadedNotification();
- } else {
- DCHECK_EQ(0, print_preview_loaded_page_count_);
- print_preview_loaded_page_count_ = 1;
- engine_->AppendBlankPages(print_preview_page_count_);
- LoadNextPreviewPage();
- }
- OnGeometryChanged(0, 0);
- if (!document_size().IsEmpty())
- paint_manager().InvalidateRect(gfx::Rect(plugin_rect_.size()));
- }
- void PdfViewWebPlugin::OnDocumentLoadComplete() {
- RecordDocumentMetrics();
- SendAttachments();
- SendBookmarks();
- SendMetadata();
- if (accessibility_state() == AccessibilityState::kPending)
- LoadAccessibility();
- }
- void PdfViewWebPlugin::SendMessage(base::Value::Dict message) {
- client_->PostMessage(std::move(message));
- }
- void PdfViewWebPlugin::SetFormTextFieldInFocus(bool in_focus) {
- text_input_type_ = in_focus ? blink::WebTextInputType::kWebTextInputTypeText
- : blink::WebTextInputType::kWebTextInputTypeNone;
- client_->UpdateTextInputState();
- }
- void PdfViewWebPlugin::SetAccessibilityDocInfo(AccessibilityDocInfo doc_info) {
- pdf_accessibility_data_handler_->SetAccessibilityDocInfo(std::move(doc_info));
- }
- void PdfViewWebPlugin::SetAccessibilityPageInfo(
- AccessibilityPageInfo page_info,
- std::vector<AccessibilityTextRunInfo> text_runs,
- std::vector<AccessibilityCharInfo> chars,
- AccessibilityPageObjects page_objects) {
- pdf_accessibility_data_handler_->SetAccessibilityPageInfo(
- std::move(page_info), std::move(text_runs), std::move(chars),
- std::move(page_objects));
- }
- void PdfViewWebPlugin::SetAccessibilityViewportInfo(
- AccessibilityViewportInfo viewport_info) {
- pdf_accessibility_data_handler_->SetAccessibilityViewportInfo(
- std::move(viewport_info));
- }
- void PdfViewWebPlugin::SetContentRestrictions(int content_restrictions) {
- pdf_service_->UpdateContentRestrictions(content_restrictions);
- }
- void PdfViewWebPlugin::DidStartLoading() {
- if (did_call_start_loading_)
- return;
- client_->DidStartLoading();
- did_call_start_loading_ = true;
- }
- void PdfViewWebPlugin::DidStopLoading() {
- if (!did_call_start_loading_)
- return;
- client_->DidStopLoading();
- did_call_start_loading_ = false;
- }
- void PdfViewWebPlugin::NotifySelectionChanged(const gfx::PointF& left,
- int left_height,
- const gfx::PointF& right,
- int right_height) {
- pdf_service_->SelectionChanged(left, left_height, right, right_height);
- }
- // TODO(crbug.com/1302059): Delete after merging with `PdfViewPluginBase`.
- void PdfViewWebPlugin::UserMetricsRecordAction(const std::string& action) {
- client_->RecordComputedAction(action);
- }
- // TODO(crbug.com/1302059): Delete after merging with `PdfViewPluginBase`.
- bool PdfViewWebPlugin::full_frame() const {
- return full_frame_;
- }
- // TODO(crbug.com/1302059): Delete after merging with `PdfViewPluginBase`.
- const gfx::Size& PdfViewWebPlugin::plugin_dip_size() const {
- return plugin_dip_size_;
- }
- // TODO(crbug.com/1302059): Delete after merging with `PdfViewPluginBase`.
- const gfx::Rect& PdfViewWebPlugin::plugin_rect() const {
- return plugin_rect_;
- }
- // TODO(crbug.com/1302059): Delete after merging with `PdfViewPluginBase`.
- float PdfViewWebPlugin::device_scale() const {
- return device_scale_;
- }
- // TODO(crbug.com/1302059): Delete after merging with `PdfViewPluginBase`.
- bool PdfViewWebPlugin::needs_reraster() const {
- return needs_reraster_;
- }
- // TODO(crbug.com/1302059): Delete after merging with `PdfViewPluginBase`.
- base::i18n::TextDirection PdfViewWebPlugin::ui_direction() const {
- return ui_direction_;
- }
- // TODO(crbug.com/1302059): Delete after merging with `PdfViewPluginBase`.
- bool PdfViewWebPlugin::received_viewport_message() const {
- return received_viewport_message_;
- }
- void PdfViewWebPlugin::OnViewportChanged(
- const gfx::Rect& new_plugin_rect_in_css_pixel,
- float new_device_scale) {
- DCHECK_GT(new_device_scale, 0.0f);
- css_plugin_rect_ = new_plugin_rect_in_css_pixel;
- if (new_device_scale == device_scale_ &&
- new_plugin_rect_in_css_pixel == plugin_rect_) {
- return;
- }
- const float old_device_scale = device_scale_;
- device_scale_ = new_device_scale;
- plugin_rect_ = new_plugin_rect_in_css_pixel;
- // TODO(crbug.com/1250173): We should try to avoid the downscaling in this
- // calculation, perhaps by migrating off `plugin_dip_size_`.
- plugin_dip_size_ = gfx::ScaleToEnclosingRect(new_plugin_rect_in_css_pixel,
- 1.0f / new_device_scale)
- .size();
- paint_manager().SetSize(plugin_rect_.size(), device_scale_);
- // Initialize the image data buffer if the context size changes.
- const gfx::Size old_image_size =
- gfx::SkISizeToSize(image_data().dimensions());
- const gfx::Size new_image_size =
- PaintManager::GetNewContextSize(old_image_size, plugin_rect_.size());
- if (new_image_size != old_image_size) {
- image_data().allocPixels(
- SkImageInfo::MakeN32Premul(gfx::SizeToSkISize(new_image_size)));
- first_paint_ = true;
- }
- // Skip updating the geometry if the new image data buffer is empty.
- if (image_data().drawsNothing())
- return;
- OnGeometryChanged(zoom(), old_device_scale);
- }
- bool PdfViewWebPlugin::SelectAll() {
- if (!CanEditText())
- return false;
- engine_->SelectAll();
- return true;
- }
- bool PdfViewWebPlugin::Cut() {
- if (!HasSelection() || !CanEditText())
- return false;
- engine_->ReplaceSelection("");
- return true;
- }
- bool PdfViewWebPlugin::Paste(const blink::WebString& value) {
- if (!CanEditText())
- return false;
- engine_->ReplaceSelection(value.Utf8());
- return true;
- }
- bool PdfViewWebPlugin::Undo() {
- if (!CanUndo())
- return false;
- engine_->Undo();
- return true;
- }
- bool PdfViewWebPlugin::Redo() {
- if (!CanRedo())
- return false;
- engine_->Redo();
- return true;
- }
- bool PdfViewWebPlugin::HandleWebInputEvent(const blink::WebInputEvent& event) {
- // Ignore user input in read-only mode.
- if (engine_->IsReadOnly())
- return false;
- // `engine_` expects input events in device coordinates.
- std::unique_ptr<blink::WebInputEvent> transformed_event =
- ui::TranslateAndScaleWebInputEvent(
- event, gfx::Vector2dF(-available_area().x() / device_scale(), 0),
- device_scale());
- const blink::WebInputEvent& event_to_handle =
- transformed_event ? *transformed_event : event;
- if (engine_->HandleInputEvent(event_to_handle))
- return true;
- // Middle click is used for scrolling and is handled by the container page.
- if (blink::WebInputEvent::IsMouseEventType(event_to_handle.GetType()) &&
- static_cast<const blink::WebMouseEvent&>(event_to_handle).button ==
- blink::WebPointerProperties::Button::kMiddle) {
- return false;
- }
- // Return true for unhandled clicks so the plugin takes focus.
- return event_to_handle.GetType() == blink::WebInputEvent::Type::kMouseDown;
- }
- void PdfViewWebPlugin::HandleImeCommit(const blink::WebString& text) {
- if (text.IsEmpty())
- return;
- std::u16string text16 = text.Utf16();
- composition_text_.Reset();
- size_t i = 0;
- for (base::i18n::UTF16CharIterator iterator(text16); iterator.Advance();) {
- blink::WebKeyboardEvent char_event(blink::WebInputEvent::Type::kChar,
- blink::WebInputEvent::kNoModifiers,
- ui::EventTimeForNow());
- char_event.windows_key_code = text16[i];
- char_event.native_key_code = text16[i];
- for (const size_t char_start = i; i < iterator.array_pos(); ++i) {
- char_event.text[i - char_start] = text16[i];
- char_event.unmodified_text[i - char_start] = text16[i];
- }
- blink::WebCoalescedInputEvent input_event(char_event, ui::LatencyInfo());
- ui::Cursor dummy_cursor_info;
- HandleInputEvent(input_event, &dummy_cursor_info);
- }
- }
- void PdfViewWebPlugin::OnInvokePrintDialog() {
- client_->Print();
- }
- void PdfViewWebPlugin::ResetRecentlySentFindUpdate() {
- recently_sent_find_update_ = false;
- }
- void PdfViewWebPlugin::RecordDocumentMetrics() {
- if (!metrics_handler_)
- return;
- metrics_handler_->RecordDocumentMetrics(engine_->GetDocumentMetadata());
- metrics_handler_->RecordAttachmentTypes(
- engine_->GetDocumentAttachmentInfoList());
- }
- void PdfViewWebPlugin::SendAttachments() {
- const std::vector<DocumentAttachmentInfo>& attachment_infos =
- engine_->GetDocumentAttachmentInfoList();
- if (attachment_infos.empty())
- return;
- base::Value::List attachments;
- for (const DocumentAttachmentInfo& attachment_info : attachment_infos) {
- // Send `size` as -1 to indicate that the attachment is too large to be
- // downloaded.
- const int size = attachment_info.size_bytes <= kMaximumSavedFileSize
- ? static_cast<int>(attachment_info.size_bytes)
- : -1;
- base::Value::Dict attachment;
- attachment.Set("name", attachment_info.name);
- attachment.Set("size", size);
- attachment.Set("readable", attachment_info.is_readable);
- attachments.Append(std::move(attachment));
- }
- base::Value::Dict message;
- message.Set("type", "attachments");
- message.Set("attachmentsData", std::move(attachments));
- SendMessage(std::move(message));
- }
- void PdfViewWebPlugin::SendBookmarks() {
- base::Value::List bookmarks = engine_->GetBookmarks();
- if (bookmarks.empty())
- return;
- base::Value::Dict message;
- message.Set("type", "bookmarks");
- message.Set("bookmarksData", std::move(bookmarks));
- SendMessage(std::move(message));
- }
- void PdfViewWebPlugin::SendMetadata() {
- base::Value::Dict metadata;
- const DocumentMetadata& document_metadata = engine_->GetDocumentMetadata();
- const std::string version = FormatPdfVersion(document_metadata.version);
- if (!version.empty())
- metadata.Set("version", version);
- metadata.Set("fileSize", ui::FormatBytes(document_metadata.size_bytes));
- metadata.Set("linearized", document_metadata.linearized);
- if (!document_metadata.title.empty())
- metadata.Set("title", document_metadata.title);
- if (!document_metadata.author.empty())
- metadata.Set("author", document_metadata.author);
- if (!document_metadata.subject.empty())
- metadata.Set("subject", document_metadata.subject);
- if (!document_metadata.keywords.empty())
- metadata.Set("keywords", document_metadata.keywords);
- if (!document_metadata.creator.empty())
- metadata.Set("creator", document_metadata.creator);
- if (!document_metadata.producer.empty())
- metadata.Set("producer", document_metadata.producer);
- if (!document_metadata.creation_date.is_null()) {
- metadata.Set("creationDate", base::TimeFormatShortDateAndTime(
- document_metadata.creation_date));
- }
- if (!document_metadata.mod_date.is_null()) {
- metadata.Set("modDate",
- base::TimeFormatShortDateAndTime(document_metadata.mod_date));
- }
- metadata.Set("pageSize", FormatPageSize(engine_->GetUniformPageSizePoints()));
- metadata.Set("canSerializeDocument",
- IsSaveDataSizeValid(engine_->GetLoadedByteSize()));
- base::Value::Dict message;
- message.Set("type", "metadata");
- message.Set("metadataData", std::move(metadata));
- SendMessage(std::move(message));
- }
- void PdfViewWebPlugin::HandleResetPrintPreviewModeMessage(
- const base::Value::Dict& message) {
- const std::string& url = *message.FindString("url");
- bool is_grayscale = message.FindBool("grayscale").value();
- int print_preview_page_count = message.FindInt("pageCount").value();
- // For security reasons, crash if `url` is not for Print Preview.
- CHECK(IsPrintPreview());
- CHECK(IsPrintPreviewUrl(url));
- DCHECK_GE(print_preview_page_count, 0);
- int page_index = ExtractPrintPreviewPageIndex(url);
- if (IsPreviewingPDF(print_preview_page_count)) {
- DCHECK_EQ(page_index, kCompletePDFIndex);
- } else {
- DCHECK_GE(page_index, 0);
- }
- print_preview_page_count_ = print_preview_page_count;
- print_preview_loaded_page_count_ = 0;
- url_ = url;
- preview_pages_info_ = base::queue<PreviewPageInfo>();
- preview_document_load_state_ = DocumentLoadState::kComplete;
- set_document_load_state(DocumentLoadState::kLoading);
- set_last_progress_sent(0);
- LoadUrl(url_, base::BindOnce(&PdfViewWebPlugin::DidOpen,
- weak_factory_.GetWeakPtr()));
- preview_engine_.reset();
- // TODO(crbug.com/1237952): Figure out a more consistent way to preserve
- // engine settings across a Print Preview reset.
- engine_ = CreateEngine(this, PDFiumFormFiller::ScriptOption::kNoJavaScript);
- engine_->ZoomUpdated(zoom() * device_scale_);
- engine_->PageOffsetUpdated(available_area().OffsetFromOrigin());
- engine_->PluginSizeUpdated(available_area().size());
- engine_->SetGrayscale(is_grayscale);
- paint_manager().InvalidateRect(gfx::Rect(plugin_rect_.size()));
- }
- void PdfViewWebPlugin::HandleLoadPreviewPageMessage(
- const base::Value::Dict& message) {
- const std::string& url = *message.FindString("url");
- int dest_page_index = message.FindInt("index").value();
- // For security reasons, crash if `url` is not for Print Preview.
- CHECK(IsPrintPreview());
- CHECK(IsPrintPreviewUrl(url));
- DCHECK_GE(dest_page_index, 0);
- DCHECK_LT(dest_page_index, print_preview_page_count_);
- // Print Preview JS will send the loadPreviewPage message for every page,
- // including the first page in the print preview, which has already been
- // loaded when handing the resetPrintPreviewMode message. Just ignore it.
- if (dest_page_index == 0)
- return;
- int src_page_index = ExtractPrintPreviewPageIndex(url);
- DCHECK_GE(src_page_index, 0);
- preview_pages_info_.push({.url = url, .dest_page_index = dest_page_index});
- LoadAvailablePreviewPage();
- }
- void PdfViewWebPlugin::LoadAvailablePreviewPage() {
- if (preview_pages_info_.empty() ||
- document_load_state() != DocumentLoadState::kComplete ||
- preview_document_load_state_ == DocumentLoadState::kLoading) {
- return;
- }
- preview_document_load_state_ = DocumentLoadState::kLoading;
- const std::string& url = preview_pages_info_.front().url;
- // Note that `last_progress_sent_` is not reset for preview page loads.
- LoadUrl(url, base::BindOnce(&PdfViewWebPlugin::DidOpenPreview,
- weak_factory_.GetWeakPtr()));
- }
- void PdfViewWebPlugin::DidOpenPreview(std::unique_ptr<UrlLoader> loader,
- int32_t result) {
- DCHECK_EQ(result, kSuccess);
- preview_client_ = std::make_unique<PreviewModeClient>(this);
- preview_engine_ = CreateEngine(preview_client_.get(),
- PDFiumFormFiller::ScriptOption::kNoJavaScript);
- preview_engine_->PluginSizeUpdated({});
- preview_engine_->HandleDocumentLoad(std::move(loader), url_);
- }
- void PdfViewWebPlugin::PreviewDocumentLoadComplete() {
- if (preview_document_load_state_ != DocumentLoadState::kLoading ||
- preview_pages_info_.empty()) {
- return;
- }
- preview_document_load_state_ = DocumentLoadState::kComplete;
- int dest_page_index = preview_pages_info_.front().dest_page_index;
- DCHECK_GT(dest_page_index, 0);
- preview_pages_info_.pop();
- DCHECK(preview_engine_);
- engine_->AppendPage(preview_engine_.get(), dest_page_index);
- ++print_preview_loaded_page_count_;
- LoadNextPreviewPage();
- }
- void PdfViewWebPlugin::PreviewDocumentLoadFailed() {
- client_->RecordComputedAction("PDF.PreviewDocumentLoadFailure");
- if (preview_document_load_state_ != DocumentLoadState::kLoading ||
- preview_pages_info_.empty()) {
- return;
- }
- // Even if a print preview page failed to load, keep going.
- preview_document_load_state_ = DocumentLoadState::kFailed;
- preview_pages_info_.pop();
- ++print_preview_loaded_page_count_;
- LoadNextPreviewPage();
- }
- void PdfViewWebPlugin::LoadNextPreviewPage() {
- if (!preview_pages_info_.empty()) {
- DCHECK_LT(print_preview_loaded_page_count_, print_preview_page_count_);
- LoadAvailablePreviewPage();
- return;
- }
- if (print_preview_loaded_page_count_ == print_preview_page_count_)
- SendPrintPreviewLoadedNotification();
- }
- void PdfViewWebPlugin::SendPrintPreviewLoadedNotification() {
- base::Value::Dict message;
- message.Set("type", "printPreviewLoaded");
- SendMessage(std::move(message));
- }
- void PdfViewWebPlugin::SendThumbnail(base::Value::Dict reply,
- Thumbnail thumbnail) {
- DCHECK_EQ(*reply.FindString("type"), "getThumbnailReply");
- DCHECK(reply.FindString("messageId"));
- reply.Set("imageData", thumbnail.TakeData());
- reply.Set("width", thumbnail.image_size().width());
- reply.Set("height", thumbnail.image_size().height());
- SendMessage(std::move(reply));
- }
- } // namespace chrome_pdf
|