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