1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef PDF_INSTANCE_H_
6#define PDF_INSTANCE_H_
7
8#include <queue>
9#include <set>
10#include <string>
11#include <utility>
12#include <vector>
13
14#include "base/memory/scoped_ptr.h"
15#include "pdf/button.h"
16#include "pdf/fading_controls.h"
17#include "pdf/page_indicator.h"
18#include "pdf/paint_manager.h"
19#include "pdf/pdf_engine.h"
20#include "pdf/preview_mode_client.h"
21#include "pdf/progress_control.h"
22#include "pdf/thumbnail_control.h"
23
24#include "ppapi/c/private/ppb_pdf.h"
25#include "ppapi/cpp/dev/printing_dev.h"
26#include "ppapi/cpp/dev/scriptable_object_deprecated.h"
27#include "ppapi/cpp/dev/scrollbar_dev.h"
28#include "ppapi/cpp/dev/selection_dev.h"
29#include "ppapi/cpp/dev/widget_client_dev.h"
30#include "ppapi/cpp/dev/zoom_dev.h"
31#include "ppapi/cpp/graphics_2d.h"
32#include "ppapi/cpp/image_data.h"
33#include "ppapi/cpp/input_event.h"
34#include "ppapi/cpp/private/find_private.h"
35#include "ppapi/cpp/private/instance_private.h"
36#include "ppapi/cpp/private/var_private.h"
37#include "ppapi/cpp/url_loader.h"
38#include "ppapi/utility/completion_callback_factory.h"
39
40namespace pp {
41class TextInput_Dev;
42}
43
44namespace chrome_pdf {
45
46struct ToolbarButtonInfo;
47
48class Instance : public pp::InstancePrivate,
49                 public pp::Find_Private,
50                 public pp::Printing_Dev,
51                 public pp::Selection_Dev,
52                 public pp::WidgetClient_Dev,
53                 public pp::Zoom_Dev,
54                 public PaintManager::Client,
55                 public PDFEngine::Client,
56                 public PreviewModeClient::Client,
57                 public ControlOwner {
58 public:
59  explicit Instance(PP_Instance instance);
60  virtual ~Instance();
61
62  // pp::Instance implementation.
63  virtual bool Init(uint32_t argc,
64                    const char* argn[],
65                    const char* argv[]) OVERRIDE;
66  virtual bool HandleDocumentLoad(const pp::URLLoader& loader) OVERRIDE;
67  virtual bool HandleInputEvent(const pp::InputEvent& event) OVERRIDE;
68  virtual void DidChangeView(const pp::View& view) OVERRIDE;
69  virtual pp::Var GetInstanceObject() OVERRIDE;
70
71  // pp::Find_Private implementation.
72  virtual bool StartFind(const std::string& text, bool case_sensitive) OVERRIDE;
73  virtual void SelectFindResult(bool forward) OVERRIDE;
74  virtual void StopFind() OVERRIDE;
75
76  // pp::PaintManager::Client implementation.
77  virtual void OnPaint(const std::vector<pp::Rect>& paint_rects,
78                       std::vector<PaintManager::ReadyRect>* ready,
79                       std::vector<pp::Rect>* pending) OVERRIDE;
80
81  // pp::Printing_Dev implementation.
82  virtual uint32_t QuerySupportedPrintOutputFormats() OVERRIDE;
83  virtual int32_t PrintBegin(
84      const PP_PrintSettings_Dev& print_settings) OVERRIDE;
85  virtual pp::Resource PrintPages(
86      const PP_PrintPageNumberRange_Dev* page_ranges,
87      uint32_t page_range_count) OVERRIDE;
88  virtual void PrintEnd() OVERRIDE;
89  virtual bool IsPrintScalingDisabled() OVERRIDE;
90
91  // pp::Private implementation.
92  virtual pp::Var GetLinkAtPosition(const pp::Point& point);
93
94  // PPP_Selection_Dev implementation.
95  virtual pp::Var GetSelectedText(bool html) OVERRIDE;
96
97  // WidgetClient_Dev implementation.
98  virtual void InvalidateWidget(pp::Widget_Dev widget,
99                                const pp::Rect& dirty_rect) OVERRIDE;
100  virtual void ScrollbarValueChanged(pp::Scrollbar_Dev scrollbar,
101                                     uint32_t value) OVERRIDE;
102  virtual void ScrollbarOverlayChanged(pp::Scrollbar_Dev scrollbar,
103                                       bool overlay) OVERRIDE;
104
105  // pp::Zoom_Dev implementation.
106  virtual void Zoom(double scale, bool text_only) OVERRIDE;
107  void ZoomChanged(double factor);  // Override.
108
109  void FlushCallback(int32_t result);
110  void DidOpen(int32_t result);
111  void DidOpenPreview(int32_t result);
112  // If the given widget intersects the rectangle, paints it and adds the
113  // rect to ready.
114  void PaintIfWidgetIntersects(pp::Widget_Dev* widget,
115                               const pp::Rect& rect,
116                               std::vector<PaintManager::ReadyRect>* ready,
117                               std::vector<pp::Rect>* pending);
118
119  // Called when the timer is fired.
120  void OnTimerFired(int32_t);
121  void OnClientTimerFired(int32_t id);
122
123  // Called when the control timer is fired.
124  void OnControlTimerFired(int32_t,
125                           const uint32& control_id,
126                           const uint32& timer_id);
127
128  // Called to print without re-entrancy issues.
129  void OnPrint(int32_t);
130
131  // PDFEngine::Client implementation.
132  virtual void DocumentSizeUpdated(const pp::Size& size);
133  virtual void Invalidate(const pp::Rect& rect);
134  virtual void Scroll(const pp::Point& point);
135  virtual void ScrollToX(int position);
136  virtual void ScrollToY(int position);
137  virtual void ScrollToPage(int page);
138  virtual void NavigateTo(const std::string& url, bool open_in_new_tab);
139  virtual void UpdateCursor(PP_CursorType_Dev cursor);
140  virtual void UpdateTickMarks(const std::vector<pp::Rect>& tickmarks);
141  virtual void NotifyNumberOfFindResultsChanged(int total, bool final_result);
142  virtual void NotifySelectedFindResultChanged(int current_find_index);
143  virtual void GetDocumentPassword(
144      pp::CompletionCallbackWithOutput<pp::Var> callback);
145  virtual void Alert(const std::string& message);
146  virtual bool Confirm(const std::string& message);
147  virtual std::string Prompt(const std::string& question,
148                             const std::string& default_answer);
149  virtual std::string GetURL();
150  virtual void Email(const std::string& to,
151                     const std::string& cc,
152                     const std::string& bcc,
153                     const std::string& subject,
154                     const std::string& body);
155  virtual void Print();
156  virtual void SubmitForm(const std::string& url,
157                          const void* data,
158                          int length);
159  virtual std::string ShowFileSelectionDialog();
160  virtual pp::URLLoader CreateURLLoader();
161  virtual void ScheduleCallback(int id, int delay_in_ms);
162  virtual void SearchString(const base::char16* string,
163                            const base::char16* term,
164                            bool case_sensitive,
165                            std::vector<SearchStringResult>* results);
166  virtual void DocumentPaintOccurred();
167  virtual void DocumentLoadComplete(int page_count);
168  virtual void DocumentLoadFailed();
169  virtual pp::Instance* GetPluginInstance();
170  virtual void DocumentHasUnsupportedFeature(const std::string& feature);
171  virtual void DocumentLoadProgress(uint32 available, uint32 doc_size);
172  virtual void FormTextFieldFocusChange(bool in_focus);
173  virtual bool IsPrintPreview();
174
175  // ControlOwner implementation.
176  virtual void OnEvent(uint32 control_id, uint32 event_id, void* data);
177  virtual void Invalidate(uint32 control_id, const pp::Rect& rc);
178  virtual uint32 ScheduleTimer(uint32 control_id, uint32 timeout_ms);
179  virtual void SetEventCapture(uint32 control_id, bool set_capture);
180  virtual void SetCursor(uint32 control_id, PP_CursorType_Dev cursor_type);
181  virtual pp::Instance* GetInstance();
182
183  bool dont_paint() const { return dont_paint_; }
184  void set_dont_paint(bool dont_paint) { dont_paint_ = dont_paint; }
185
186  // Called by PDFScriptableObject.
187  bool HasScriptableMethod(const pp::Var& method, pp::Var* exception);
188  pp::Var CallScriptableMethod(const pp::Var& method,
189                               const std::vector<pp::Var>& args,
190                               pp::Var* exception);
191
192  // PreviewModeClient::Client implementation.
193  virtual void PreviewDocumentLoadComplete() OVERRIDE;
194  virtual void PreviewDocumentLoadFailed() OVERRIDE;
195
196  // Helper functions for implementing PPP_PDF.
197  void RotateClockwise();
198  void RotateCounterclockwise();
199
200 private:
201  // Called whenever the plugin geometry changes to update the location of the
202  // scrollbars, background parts, and notifies the pdf engine.
203  void OnGeometryChanged(double old_zoom, float old_device_scale);
204
205  void CreateHorizontalScrollbar();
206  void CreateVerticalScrollbar();
207  void DestroyHorizontalScrollbar();
208  void DestroyVerticalScrollbar();
209
210  // Returns the thickness of a scrollbar. This returns the thickness when it's
211  // shown, so for overlay scrollbars it'll still be non-zero.
212  int GetScrollbarThickness();
213
214  // Returns the space we need to reserve for the scrollbar in the plugin area.
215  // If overlay scrollbars are used, this will be 0.
216  int GetScrollbarReservedThickness();
217
218  // Returns true if overlay scrollbars are in use.
219  bool IsOverlayScrollbar();
220
221  // Figures out the location of any background rectangles (i.e. those that
222  // aren't painted by the PDF engine).
223  void CalculateBackgroundParts();
224
225  // Computes document width/height in device pixels, based on current zoom and
226  // device scale
227  int GetDocumentPixelWidth() const;
228  int GetDocumentPixelHeight() const;
229
230  // Draws a rectangle with the specified dimensions and color in our buffer.
231  void FillRect(const pp::Rect& rect, unsigned int color);
232
233  std::vector<pp::ImageData> GetThumbnailResources();
234  std::vector<pp::ImageData> GetProgressBarResources(pp::ImageData* background);
235
236  void CreateToolbar(const ToolbarButtonInfo* tb_info, size_t size);
237  int GetToolbarRightOffset();
238  int GetToolbarBottomOffset();
239  void CreateProgressBar();
240  void ConfigureProgressBar();
241  void CreateThumbnails();
242  void CreatePageIndicator(bool always_visible);
243  void ConfigurePageIndicator();
244
245  void PaintOverlayControl(Control* ctrl,
246                           pp::ImageData* image_data,
247                           std::vector<PaintManager::ReadyRect>* ready);
248
249  void LoadUrl(const std::string& url);
250  void LoadPreviewUrl(const std::string& url);
251  void LoadUrlInternal(const std::string& url, pp::URLLoader* loader,
252                       void (Instance::* method)(int32_t));
253
254  // Creates a URL loader and allows it to access all urls, i.e. not just the
255  // frame's origin.
256  pp::URLLoader CreateURLLoaderInternal();
257
258  // Figure out the initial page to display based on #page=N and #nameddest=foo
259  // in the |url_|.
260  // Returns -1 if there is no valid fragment. The returned value is 0-based,
261  // whereas page=N is 1-based.
262  int GetInitialPage(const std::string& url);
263
264  void UpdateToolbarPosition(bool invalidate);
265  void UpdateProgressBarPosition(bool invalidate);
266  void UpdatePageIndicatorPosition(bool invalidate);
267
268  void FormDidOpen(int32_t result);
269
270  std::string GetLocalizedString(PP_ResourceString id);
271
272  void UserMetricsRecordAction(const std::string& action);
273
274  void SaveAs();
275
276  enum ZoomMode {
277    ZOOM_SCALE,  // Standard zooming mode, resize will not affect it.
278    ZOOM_FIT_TO_WIDTH,  // Maintain fit to width on resize.
279    ZOOM_FIT_TO_PAGE,  // Maintain fit to page on resize.
280    ZOOM_AUTO  // Maintain the default auto fitting mode on resize.
281  };
282
283  enum DocumentLoadState {
284    LOAD_STATE_LOADING,
285    LOAD_STATE_COMPLETE,
286    LOAD_STATE_FAILED,
287  };
288
289  // Set new zoom mode and scale. Scale will be ignored if mode != ZOOM_SCALE.
290  void SetZoom(ZoomMode zoom_mode, double scale);
291
292  // Updates internal zoom scale based on the plugin/document geometry and
293  // current mode.
294  void UpdateZoomScale();
295
296  // Simulates how Chrome "snaps" zooming up/down to the next nearest zoom level
297  // when the previous zoom level wasn't an integer.  We do this so that
298  // pressing the zoom buttons has the same effect as the menu buttons, even if
299  // we start from a non-standard zoom level because of fit-width or fit-height.
300  double CalculateZoom(uint32 control_id) const;
301
302  pp::ImageData CreateResourceImage(PP_ResourceImage image_id);
303
304  void DrawText(const pp::Point& top_center, PP_ResourceString id);
305
306  // Set print preview mode, where the current PDF document is reduced to
307  // only one page, and then extended to |page_count| pages with
308  // |page_count| - 1 blank pages.
309  void SetPrintPreviewMode(int page_count);
310
311  // Returns the page number to be displayed in the page indicator. If the
312  // plugin is running within print preview, the displayed number might be
313  // different from the index of the displayed page.
314  int GetPageNumberToDisplay();
315
316  // Process the preview page data information. |src_url| specifies the preview
317  // page data location. The |src_url| is in the format:
318  // chrome://print/id/page_number/print.pdf
319  // |dst_page_index| specifies the blank page index that needs to be replaced
320  // with the new page data.
321  void ProcessPreviewPageInfo(const std::string& src_url, int dst_page_index);
322  // Load the next available preview page into the blank page.
323  void LoadAvailablePreviewPage();
324
325  // Enables autoscroll using origin as a neutral (center) point.
326  void EnableAutoscroll(const pp::Point& origin);
327  // Disables autoscroll and returns to normal functionality.
328  void DisableAutoscroll();
329  // Calculate autoscroll info and return proper mouse pointer and scroll
330  // andjustments.
331  PP_CursorType_Dev CalculateAutoscroll(const pp::Point& mouse_pos);
332
333  void ConfigureNumberImageGenerator();
334
335  NumberImageGenerator* number_image_generator();
336
337  int GetScaled(int x) const;
338
339  pp::ImageData image_data_;
340  // Used when the plugin is embedded in a page and we have to create the loader
341  // ourself.
342  pp::CompletionCallbackFactory<Instance> loader_factory_;
343  pp::URLLoader embed_loader_;
344  pp::URLLoader embed_preview_loader_;
345
346  scoped_ptr<pp::Scrollbar_Dev> h_scrollbar_;
347  scoped_ptr<pp::Scrollbar_Dev> v_scrollbar_;
348  int32 valid_v_range_;
349
350  PP_CursorType_Dev cursor_;  // The current cursor.
351
352  // Used when selecting and dragging beyond the visible portion, in which case
353  // we want to scroll the document.
354  bool timer_pending_;
355  pp::MouseInputEvent last_mouse_event_;
356  pp::CompletionCallbackFactory<Instance> timer_factory_;
357  uint32 current_timer_id_;
358
359  // Size, in pixels, of plugin rectangle.
360  pp::Size plugin_size_;
361  // Size, in DIPs, of plugin rectangle.
362  pp::Size plugin_dip_size_;
363  // Remaining area, in pixels, to render the pdf in after accounting for
364  // scrollbars/toolbars and horizontal centering.
365  pp::Rect available_area_;
366  // Size of entire document in pixels (i.e. if each page is 800 pixels high and
367  // there are 10 pages, the height will be 8000).
368  pp::Size document_size_;
369
370  double zoom_;  // Current zoom factor.
371
372  float device_scale_;  // Current device scale factor.
373  bool printing_enabled_;
374  bool hidpi_enabled_;
375  // True if the plugin is full-page.
376  bool full_;
377  // Zooming mode (none, fit to width, fit to height)
378  ZoomMode zoom_mode_;
379
380  // If true, this means we told the RenderView that we're starting a network
381  // request so that it can start the throbber. We will tell it again once the
382  // document finishes loading.
383  bool did_call_start_loading_;
384
385  // Hold off on painting invalidated requests while this flag is true.
386  bool dont_paint_;
387
388  // Indicates if plugin is in autoscroll mode.
389  bool is_autoscroll_;
390  // Rect for autoscroll anchor.
391  pp::Rect autoscroll_rect_;
392  // Image of the autoscroll anchor and its background.
393  pp::ImageData autoscroll_anchor_;
394  // Autoscrolling deltas in pixels.
395  int autoscroll_x_;
396  int autoscroll_y_;
397
398  // Thickness of a scrollbar.
399  int scrollbar_thickness_;
400
401  // Reserved thickness of a scrollbar. This is how much space the scrollbar
402  // takes from the available area. 0 for overlay.
403  int scrollbar_reserved_thickness_;
404
405  // Used to remember which toolbar is in use
406  const ToolbarButtonInfo* current_tb_info_;
407  size_t current_tb_info_size_;
408
409  PaintManager paint_manager_;
410
411  struct BackgroundPart {
412    pp::Rect location;
413    unsigned int color;
414  };
415  std::vector<BackgroundPart> background_parts_;
416
417  struct PrintSettings {
418    PrintSettings() {
419      Clear();
420    }
421    void Clear() {
422      is_printing = false;
423      print_pages_called_ = false;
424      memset(&pepper_print_settings, 0, sizeof(pepper_print_settings));
425    }
426    // This is set to true when PrintBegin is called and false when PrintEnd is
427    // called.
428    bool is_printing;
429    // To know whether this was an actual print operation, so we don't double
430    // count UMA logging.
431    bool print_pages_called_;
432    PP_PrintSettings_Dev pepper_print_settings;
433  };
434
435  PrintSettings print_settings_;
436
437  scoped_ptr<PDFEngine> engine_;
438
439  // This engine is used to render the individual preview page data. This is
440  // used only in print preview mode. This will use |PreviewModeClient|
441  // interface which has very limited access to the pp::Instance.
442  scoped_ptr<PDFEngine> preview_engine_;
443
444  std::string url_;
445
446  scoped_ptr<FadingControls> toolbar_;
447  ThumbnailControl thumbnails_;
448  ProgressControl progress_bar_;
449  uint32 delayed_progress_timer_id_;
450  PageIndicator page_indicator_;
451
452  // Used for creating images from numbers.
453  scoped_ptr<NumberImageGenerator> number_image_generator_;
454
455  // Used for submitting forms.
456  pp::CompletionCallbackFactory<Instance> form_factory_;
457  pp::URLLoader form_loader_;
458
459  // Used for printing without re-entrancy issues.
460  pp::CompletionCallbackFactory<Instance> print_callback_factory_;
461
462  // True if we haven't painted the plugin viewport yet.
463  bool first_paint_;
464
465  // True when we've painted at least one page from the document.
466  bool painted_first_page_;
467
468  // True if we should display page indicator, false otherwise
469  bool show_page_indicator_;
470
471  // Callback when the document load completes.
472  pp::Var on_load_callback_;
473  pp::Var on_scroll_callback_;
474  pp::Var on_plugin_size_changed_callback_;
475
476  DocumentLoadState document_load_state_;
477  DocumentLoadState preview_document_load_state_;
478
479  // JavaScript interface to control this instance.
480  // This wraps a PDFScriptableObject in a pp::Var.
481  pp::VarPrivate instance_object_;
482
483  // Used so that we only tell the browser once about an unsupported feature, to
484  // avoid the infobar going up more than once.
485  bool told_browser_about_unsupported_feature_;
486
487  // Keeps track of which unsupported features we reported, so we avoid spamming
488  // the stats if a feature shows up many times per document.
489  std::set<std::string> unsupported_features_reported_;
490
491  // Number of pages in print preview mode, 0 if not in print preview mode.
492  int print_preview_page_count_;
493  std::vector<int> print_preview_page_numbers_;
494
495  // Used to manage loaded print preview page information. A |PreviewPageInfo|
496  // consists of data source url string and the page index in the destination
497  // document.
498  typedef std::pair<std::string, int> PreviewPageInfo;
499  std::queue<PreviewPageInfo> preview_pages_info_;
500
501  // Used to signal the browser about focus changes to trigger the OSK.
502  // TODO(abodenha@chromium.org) Implement full IME support in the plugin.
503  // http://crbug.com/132565
504  scoped_ptr<pp::TextInput_Dev> text_input_;
505};
506
507// This implements the JavaScript class entrypoint for the plugin instance.
508// This class is just a thin wrapper. It delegates relevant methods to Instance.
509class PDFScriptableObject : public pp::deprecated::ScriptableObject {
510 public:
511  explicit PDFScriptableObject(Instance* instance);
512  virtual ~PDFScriptableObject();
513
514  // pp::deprecated::ScriptableObject implementation.
515  virtual bool HasMethod(const pp::Var& method, pp::Var* exception);
516  virtual pp::Var Call(const pp::Var& method,
517                       const std::vector<pp::Var>& args,
518                       pp::Var* exception);
519
520 private:
521  Instance* instance_;
522};
523
524}  // namespace chrome_pdf
525
526#endif  // PDF_INSTANCE_H_
527