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