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