1// Copyright 2013 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// TODO(sgurun) copied from chrome/renderer. Remove after crbug.com/322276
6
7#ifndef AW_RENDERER_PRINT_WEB_VIEW_HELPER_H_
8#define AW_RENDERER_PRINT_WEB_VIEW_HELPER_H_
9
10#include <vector>
11
12#include "base/gtest_prod_util.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/memory/shared_memory.h"
15#include "base/memory/weak_ptr.h"
16#include "base/time/time.h"
17#include "content/public/renderer/render_view_observer.h"
18#include "content/public/renderer/render_view_observer_tracker.h"
19#include "printing/pdf_metafile_skia.h"
20#include "third_party/WebKit/public/platform/WebCanvas.h"
21#include "third_party/WebKit/public/web/WebNode.h"
22#include "third_party/WebKit/public/web/WebPrintParams.h"
23#include "ui/gfx/size.h"
24
25struct PrintMsg_Print_Params;
26struct PrintMsg_PrintPage_Params;
27struct PrintMsg_PrintPages_Params;
28
29namespace base {
30class DictionaryValue;
31}
32
33namespace blink {
34class WebFrame;
35class WebView;
36}
37
38namespace printing {
39
40struct PageSizeMargins;
41class PrepareFrameAndViewForPrint;
42
43// Stores reference to frame using WebVew and unique name.
44// Workaround to modal dialog issue on Linux. crbug.com/236147.
45// If WebFrame someday supports WeakPtr, we should use it here.
46class FrameReference {
47 public:
48  explicit FrameReference(blink::WebLocalFrame* frame);
49  FrameReference();
50  ~FrameReference();
51
52  void Reset(blink::WebLocalFrame* frame);
53
54  blink::WebLocalFrame* GetFrame();
55  blink::WebView* view();
56
57 private:
58  blink::WebView* view_;
59  blink::WebLocalFrame* frame_;
60};
61
62// PrintWebViewHelper handles most of the printing grunt work for RenderView.
63// We plan on making print asynchronous and that will require copying the DOM
64// of the document and creating a new WebView with the contents.
65class PrintWebViewHelper
66    : public content::RenderViewObserver,
67      public content::RenderViewObserverTracker<PrintWebViewHelper> {
68 public:
69  explicit PrintWebViewHelper(content::RenderView* render_view);
70  virtual ~PrintWebViewHelper();
71
72  bool IsPrintingEnabled();
73
74  void PrintNode(const blink::WebNode& node);
75
76 private:
77  friend class PrintWebViewHelperTestBase;
78  FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperTest,
79                           BlockScriptInitiatedPrinting);
80  FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperTest,
81                           BlockScriptInitiatedPrintingFromPopup);
82  FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperTest, OnPrintPages);
83
84#if defined(OS_WIN) || defined(OS_MACOSX)
85  FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperTest, PrintLayoutTest);
86  FRIEND_TEST_ALL_PREFIXES(PrintWebViewHelperTest, PrintWithIframe);
87#endif  // defined(OS_WIN) || defined(OS_MACOSX)
88
89  enum PrintingResult {
90    OK,
91    FAIL_PRINT_INIT,
92    FAIL_PRINT,
93    FAIL_PREVIEW,
94  };
95
96  enum PrintPreviewErrorBuckets {
97    PREVIEW_ERROR_NONE,  // Always first.
98    PREVIEW_ERROR_BAD_SETTING,
99    PREVIEW_ERROR_METAFILE_COPY_FAILED,
100    PREVIEW_ERROR_METAFILE_INIT_FAILED,
101    PREVIEW_ERROR_ZERO_PAGES,
102    PREVIEW_ERROR_MAC_DRAFT_METAFILE_INIT_FAILED,
103    PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE,
104    PREVIEW_ERROR_UPDATING_PRINT_SETTINGS,
105    PREVIEW_ERROR_INVALID_PRINTER_SETTINGS,
106    PREVIEW_ERROR_LAST_ENUM  // Always last.
107  };
108
109  enum PrintPreviewRequestType {
110    PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME,
111    PRINT_PREVIEW_USER_INITIATED_SELECTION,
112    PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE,
113    PRINT_PREVIEW_SCRIPTED  // triggered by window.print().
114  };
115
116  // RenderViewObserver implementation.
117  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
118  virtual void PrintPage(blink::WebLocalFrame* frame,
119                         bool user_initiated) OVERRIDE;
120  virtual void DidStartLoading() OVERRIDE;
121  virtual void DidStopLoading() OVERRIDE;
122
123  // Message handlers ---------------------------------------------------------
124  void OnPrintPages();
125  void OnPrintForSystemDialog();
126  void OnInitiatePrintPreview(bool selection_only);
127  void OnPrintPreview(const base::DictionaryValue& settings);
128  void OnPrintForPrintPreview(const base::DictionaryValue& job_settings);
129  void OnPrintingDone(bool success);
130
131  // Get |page_size| and |content_area| information from
132  // |page_layout_in_points|.
133  void GetPageSizeAndContentAreaFromPageLayout(
134      const PageSizeMargins& page_layout_in_points,
135      gfx::Size* page_size,
136      gfx::Rect* content_area);
137
138  // Update |ignore_css_margins_| based on settings.
139  void UpdateFrameMarginsCssInfo(const base::DictionaryValue& settings);
140
141  // Returns true if the current destination printer is PRINT_TO_PDF.
142  bool IsPrintToPdfRequested(const base::DictionaryValue& settings);
143
144  // Returns the print scaling option to retain/scale/crop the source page size
145  // to fit the printable area of the paper.
146  //
147  // We retain the source page size when the current destination printer is
148  // SAVE_AS_PDF.
149  //
150  // We crop the source page size to fit the printable area or we print only the
151  // left top page contents when
152  // (1) Source is PDF and the user has requested not to fit to printable area
153  // via |job_settings|.
154  // (2) Source is PDF. This is the first preview request and print scaling
155  // option is disabled for initiator renderer plugin.
156  //
157  // In all other cases, we scale the source page to fit the printable area.
158  blink::WebPrintScalingOption GetPrintScalingOption(
159      bool source_is_html,
160      const base::DictionaryValue& job_settings,
161      const PrintMsg_Print_Params& params);
162
163  // Prepare frame for creating preview document.
164  void PrepareFrameForPreviewDocument();
165
166  // Continue creating preview document.
167  void OnFramePreparedForPreviewDocument();
168
169  // Initialize the print preview document.
170  bool CreatePreviewDocument();
171
172  // Renders a print preview page. |page_number| is 0-based.
173  // Returns true if print preview should continue, false on failure.
174  bool RenderPreviewPage(int page_number,
175                         const PrintMsg_Print_Params& print_params);
176
177  // Finalize the print ready preview document.
178  bool FinalizePrintReadyDocument();
179
180  // Enable/Disable window.print calls.  If |blocked| is true window.print
181  // calls will silently fail.  Call with |blocked| set to false to reenable.
182  void SetScriptedPrintBlocked(bool blocked);
183
184  // Main printing code -------------------------------------------------------
185
186  void Print(blink::WebLocalFrame* frame, const blink::WebNode& node);
187
188  // Notification when printing is done - signal tear-down/free resources.
189  void DidFinishPrinting(PrintingResult result);
190
191  // Print Settings -----------------------------------------------------------
192
193  // Initialize print page settings with default settings.
194  // Used only for native printing workflow.
195  bool InitPrintSettings(bool fit_to_paper_size);
196
197  // Calculate number of pages in source document.
198  bool CalculateNumberOfPages(blink::WebLocalFrame* frame,
199                              const blink::WebNode& node,
200                              int* number_of_pages);
201
202  // Update the current print settings with new |passed_job_settings|.
203  // |passed_job_settings| dictionary contains print job details such as printer
204  // name, number of copies, page range, etc.
205  bool UpdatePrintSettings(blink::WebLocalFrame* frame,
206                           const blink::WebNode& node,
207                           const base::DictionaryValue& passed_job_settings);
208
209  // Get final print settings from the user.
210  // Return false if the user cancels or on error.
211  bool GetPrintSettingsFromUser(blink::WebFrame* frame,
212                                const blink::WebNode& node,
213                                int expected_pages_count);
214
215  // Page Printing / Rendering ------------------------------------------------
216
217  void OnFramePreparedForPrintPages();
218  void PrintPages();
219  bool PrintPagesNative(blink::WebFrame* frame,
220                        int page_count,
221                        const gfx::Size& canvas_size);
222  void FinishFramePrinting();
223
224  // Prints the page listed in |params|.
225#if defined(OS_LINUX) || defined(OS_ANDROID)
226  void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
227                         const gfx::Size& canvas_size,
228                         blink::WebFrame* frame,
229                         PdfMetafileSkia* metafile);
230#else
231  void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
232                         const gfx::Size& canvas_size,
233                         blink::WebFrame* frame);
234#endif
235
236  // Render the frame for printing.
237  bool RenderPagesForPrint(blink::WebLocalFrame* frame,
238                           const blink::WebNode& node);
239
240  // Platform specific helper function for rendering page(s) to |metafile|.
241#if defined(OS_WIN)
242  void RenderPage(const PrintMsg_Print_Params& params,
243                  int page_number,
244                  blink::WebFrame* frame,
245                  bool is_preview,
246                  PdfMetafileSkia* metafile,
247                  double* scale_factor,
248                  gfx::Size* page_size_in_dpi,
249                  gfx::Rect* content_area_in_dpi);
250#elif defined(OS_MACOSX)
251  void RenderPage(const PrintMsg_Print_Params& params,
252                  int page_number,
253                  blink::WebFrame* frame,
254                  bool is_preview,
255                  PdfMetafileSkia* metafile,
256                  gfx::Size* page_size,
257                  gfx::Rect* content_rect);
258#endif  // defined(OS_WIN)
259
260  // Renders page contents from |frame| to |content_area| of |canvas|.
261  // |page_number| is zero-based.
262  // When method is called, canvas should be setup to draw to |canvas_area|
263  // with |scale_factor|.
264  static float RenderPageContent(blink::WebFrame* frame,
265                                 int page_number,
266                                 const gfx::Rect& canvas_area,
267                                 const gfx::Rect& content_area,
268                                 double scale_factor,
269                                 blink::WebCanvas* canvas);
270
271  // Helper methods -----------------------------------------------------------
272
273  bool CopyMetafileDataToSharedMem(PdfMetafileSkia* metafile,
274                                   base::SharedMemoryHandle* shared_mem_handle);
275
276  // Helper method to get page layout in points and fit to page if needed.
277  static void ComputePageLayoutInPointsForCss(
278      blink::WebFrame* frame,
279      int page_index,
280      const PrintMsg_Print_Params& default_params,
281      bool ignore_css_margins,
282      double* scale_factor,
283      PageSizeMargins* page_layout_in_points);
284
285  // Given the |device| and |canvas| to draw on, prints the appropriate headers
286  // and footers using strings from |header_footer_info| on to the canvas.
287  static void PrintHeaderAndFooter(
288      blink::WebCanvas* canvas,
289      int page_number,
290      int total_pages,
291      float webkit_scale_factor,
292      const PageSizeMargins& page_layout_in_points,
293      const base::DictionaryValue& header_footer_info,
294      const PrintMsg_Print_Params& params);
295
296  bool GetPrintFrame(blink::WebLocalFrame** frame);
297
298  // Script Initiated Printing ------------------------------------------------
299
300  // Return true if script initiated printing is currently
301  // allowed. |user_initiated| should be true when a user event triggered the
302  // script, most likely by pressing a print button on the page.
303  bool IsScriptInitiatedPrintAllowed(blink::WebFrame* frame,
304                                     bool user_initiated);
305
306  // Returns true if script initiated printing occurs too often.
307  bool IsScriptInitiatedPrintTooFrequent(blink::WebFrame* frame);
308
309  // Reset the counter for script initiated printing.
310  // Scripted printing will be allowed to continue.
311  void ResetScriptedPrintCount();
312
313  // Increment the counter for script initiated printing.
314  // Scripted printing will be blocked for a limited amount of time.
315  void IncrementScriptedPrintCount();
316
317  // Shows scripted print preview when options from plugin are availible.
318  void ShowScriptedPrintPreview();
319
320  void RequestPrintPreview(PrintPreviewRequestType type);
321
322  // Checks whether print preview should continue or not.
323  // Returns true if cancelling, false if continuing.
324  bool CheckForCancel();
325
326  // Notifies the browser a print preview page has been rendered.
327  // |page_number| is 0-based.
328  // For a valid |page_number| with modifiable content,
329  // |metafile| is the rendered page. Otherwise |metafile| is NULL.
330  // Returns true if print preview should continue, false on failure.
331  bool PreviewPageRendered(int page_number, PdfMetafileSkia* metafile);
332
333  // WebView used only to print the selection.
334  scoped_ptr<PrepareFrameAndViewForPrint> prep_frame_view_;
335  bool reset_prep_frame_view_;
336
337  scoped_ptr<PrintMsg_PrintPages_Params> print_pages_params_;
338  bool is_preview_enabled_;
339  bool is_scripted_print_throttling_disabled_;
340  bool is_print_ready_metafile_sent_;
341  bool ignore_css_margins_;
342
343  // Used for scripted initiated printing blocking.
344  base::Time last_cancelled_script_print_;
345  int user_cancelled_scripted_print_count_;
346  bool is_scripted_printing_blocked_;
347
348  // Let the browser process know of a printing failure. Only set to false when
349  // the failure came from the browser in the first place.
350  bool notify_browser_of_print_failure_;
351
352  // True, when printing from print preview.
353  bool print_for_preview_;
354
355  // Strings generated by the browser process to be printed as headers and
356  // footers if requested by the user.
357  scoped_ptr<base::DictionaryValue> header_footer_info_;
358
359  // Keeps track of the state of print preview between messages.
360  // TODO(vitalybuka): Create PrintPreviewContext when needed and delete after
361  // use. Now it's interaction with various messages is confusing.
362  class PrintPreviewContext {
363   public:
364    PrintPreviewContext();
365    ~PrintPreviewContext();
366
367    // Initializes the print preview context. Need to be called to set
368    // the |web_frame| / |web_node| to generate the print preview for.
369    void InitWithFrame(blink::WebLocalFrame* web_frame);
370    void InitWithNode(const blink::WebNode& web_node);
371
372    // Does bookkeeping at the beginning of print preview.
373    void OnPrintPreview();
374
375    // Create the print preview document. |pages| is empty to print all pages.
376    // Takes ownership of |prepared_frame|.
377    bool CreatePreviewDocument(PrepareFrameAndViewForPrint* prepared_frame,
378                               const std::vector<int>& pages);
379
380    // Called after a page gets rendered. |page_time| is how long the
381    // rendering took.
382    void RenderedPreviewPage(const base::TimeDelta& page_time);
383
384    // Updates the print preview context when the required pages are rendered.
385    void AllPagesRendered();
386
387    // Finalizes the print ready preview document.
388    void FinalizePrintReadyDocument();
389
390    // Cleanup after print preview finishes.
391    void Finished();
392
393    // Cleanup after print preview fails.
394    void Failed(bool report_error);
395
396    // Helper functions
397    int GetNextPageNumber();
398    bool IsRendering() const;
399    bool IsModifiable();
400    bool HasSelection();
401    bool IsLastPageOfPrintReadyMetafile() const;
402    bool IsFinalPageRendered() const;
403
404    // Setters
405    void set_generate_draft_pages(bool generate_draft_pages);
406    void set_error(enum PrintPreviewErrorBuckets error);
407
408    // Getters
409    // Original frame for which preview was requested.
410    blink::WebLocalFrame* source_frame();
411    // Original node for which preview was requested.
412    const blink::WebNode& source_node() const;
413
414    // Frame to be use to render preview. May be the same as source_frame(), or
415    // generated from it, e.g. copy of selected block.
416    blink::WebLocalFrame* prepared_frame();
417    // Node to be use to render preview. May be the same as source_node(), or
418    // generated from it, e.g. copy of selected block.
419    const blink::WebNode& prepared_node() const;
420
421    int total_page_count() const;
422    bool generate_draft_pages() const;
423    PdfMetafileSkia* metafile();
424    gfx::Size GetPrintCanvasSize() const;
425    int last_error() const;
426
427   private:
428    enum State {
429      UNINITIALIZED,  // Not ready to render.
430      INITIALIZED,    // Ready to render.
431      RENDERING,      // Rendering.
432      DONE            // Finished rendering.
433    };
434
435    // Reset some of the internal rendering context.
436    void ClearContext();
437
438    // Specifies what to render for print preview.
439    FrameReference source_frame_;
440    blink::WebNode source_node_;
441
442    scoped_ptr<PrepareFrameAndViewForPrint> prep_frame_view_;
443    scoped_ptr<PdfMetafileSkia> metafile_;
444
445    // Total page count in the renderer.
446    int total_page_count_;
447
448    // The current page to render.
449    int current_page_index_;
450
451    // List of page indices that need to be rendered.
452    std::vector<int> pages_to_render_;
453
454    // True, when draft pages needs to be generated.
455    bool generate_draft_pages_;
456
457    // Specifies the total number of pages in the print ready metafile.
458    int print_ready_metafile_page_count_;
459
460    base::TimeDelta document_render_time_;
461    base::TimeTicks begin_time_;
462
463    enum PrintPreviewErrorBuckets error_;
464
465    State state_;
466  };
467
468  bool print_node_in_progress_;
469  PrintPreviewContext print_preview_context_;
470  bool is_loading_;
471  bool is_scripted_preview_delayed_;
472  base::WeakPtrFactory<PrintWebViewHelper> weak_ptr_factory_;
473  DISALLOW_COPY_AND_ASSIGN(PrintWebViewHelper);
474};
475
476}  // namespace printing
477
478#endif  // AW_RENDERER_PRINT_WEB_VIEW_HELPER_H_
479