Commit message: None
CVE: None
Vulnerability description: None

Project: Chrome

void CalculatePrintCanvasSize(const PrintMsg_Print_Params& print_params,
                              gfx::Size* result) {
  int dpi = GetDPI(&print_params);
  result->set_width(ConvertUnit(print_params.printable_size.width(), dpi,
                                print_params.desired_dpi));

  result->set_height(ConvertUnit(print_params.printable_size.height(), dpi,
                                 print_params.desired_dpi));
}

Project: Chrome

void PrintWebViewHelper::PrintPreviewContext::ClearContext() {
  prep_frame_view_.reset();
  metafile_.reset();
  pages_to_render_.clear();
  error_ = PREVIEW_ERROR_NONE;
}

Project: Chrome

bool PrintWebViewHelper::CopyAndPrint(WebKit::WebFrame* web_frame) {
  WebPreferences prefs = render_view()->GetWebkitPreferences();
  prefs.javascript_enabled = false;
  prefs.java_enabled = false;

  print_web_view_ = WebView::create(this);
  prefs.Apply(print_web_view_);
  print_web_view_->initializeMainFrame(this);

  print_pages_params_->pages.clear();  // Print all pages of selection.

  std::string html = web_frame->selectionAsMarkup().utf8();
  std::string url_str = "data:text/html;charset=utf-8,";
  url_str.append(html);
  GURL url(url_str);

  print_web_view_->mainFrame()->loadRequest(WebURLRequest(url));

  return true;
}

Project: Chrome

bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
    printing::Metafile* metafile,
    base::SharedMemoryHandle* shared_mem_handle) {
  uint32 buf_size = metafile->GetDataSize();
  base::SharedMemoryHandle mem_handle =
      content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(buf_size);
  if (base::SharedMemory::IsHandleValid(mem_handle)) {
    base::SharedMemory shared_buf(mem_handle, false);
    if (shared_buf.Map(buf_size)) {
      metafile->GetData(shared_buf.memory(), buf_size);
      shared_buf.GiveToProcess(base::GetCurrentProcessHandle(),
                               shared_mem_handle);
      return true;
    }
  }
  NOTREACHED();
  return false;
}

Project: Chrome

bool PrintWebViewHelper::CreatePreviewDocument() {
  PrintMsg_Print_Params print_params = print_pages_params_->params;
  const std::vector<int>& pages = print_pages_params_->pages;
  if (!print_preview_context_.CreatePreviewDocument(&print_params, pages))
    return false;
  PrintHostMsg_DidGetPreviewPageCount_Params params;
  params.page_count = print_preview_context_.total_page_count();
  params.is_modifiable = print_preview_context_.IsModifiable();
  params.document_cookie = print_pages_params_->params.document_cookie;
  params.preview_request_id = print_pages_params_->params.preview_request_id;
  params.clear_preview_data = print_preview_context_.generate_draft_pages();
  Send(new PrintHostMsg_DidGetPreviewPageCount(routing_id(), params));
  if (CheckForCancel())
    return false;

  while (!print_preview_context_.IsFinalPageRendered()) {
    int page_number = print_preview_context_.GetNextPageNumber();
    DCHECK_GE(page_number, 0);
    if (!RenderPreviewPage(page_number))
      return false;

    if (CheckForCancel())
      return false;

    if (print_preview_context_.IsFinalPageRendered())
      print_preview_context_.AllPagesRendered();

    if (print_preview_context_.IsLastPageOfPrintReadyMetafile()) {
      DCHECK(print_preview_context_.IsModifiable() ||
             print_preview_context_.IsFinalPageRendered());
      if (!FinalizePrintReadyDocument())
        return false;
    }
  }
  print_preview_context_.Finished();
  return true;
}

Project: Chrome

void PrintWebViewHelper::DidFinishPrinting(PrintingResult result) {
  bool store_print_pages_params = true;
  if (result == FAIL_PRINT) {
    DisplayPrintJobError();

    if (notify_browser_of_print_failure_ && print_pages_params_.get()) {
      int cookie = print_pages_params_->params.document_cookie;
      Send(new PrintHostMsg_PrintingFailed(routing_id(), cookie));
    }
  } else if (result == FAIL_PREVIEW) {
    DCHECK(is_preview_enabled_);
    store_print_pages_params = false;
    int cookie = print_pages_params_.get() ?
                     print_pages_params_->params.document_cookie : 0;
    if (notify_browser_of_print_failure_)
      Send(new PrintHostMsg_PrintPreviewFailed(routing_id(), cookie));
    else
      Send(new PrintHostMsg_PrintPreviewCancelled(routing_id(), cookie));
    print_preview_context_.Failed(notify_browser_of_print_failure_);
  }

  if (print_web_view_) {
    print_web_view_->close();
    print_web_view_ = NULL;
  }

  if (store_print_pages_params) {
    old_print_pages_params_.reset(print_pages_params_.release());
  } else {
    print_pages_params_.reset();
    old_print_pages_params_.reset();
  }

  notify_browser_of_print_failure_ = true;
}

Project: Chrome

void PrintWebViewHelper::DisplayPrintJobError() {
  WebView* web_view = print_web_view_;
  if (!web_view)
    web_view = render_view()->GetWebView();

  render_view()->RunModalAlertDialog(
      web_view->mainFrame(),
      l10n_util::GetStringUTF16(IDS_PRINT_SPOOL_FAILED_ERROR_TEXT));
}

Project: Chrome

void PrintWebViewHelper::PrintPreviewContext::Failed(bool report_error) {
  DCHECK(state_ == INITIALIZED || state_ == RENDERING);
  state_ = INITIALIZED;
  if (report_error) {
    DCHECK_NE(PREVIEW_ERROR_NONE, error_);
    UMA_HISTOGRAM_ENUMERATION("PrintPreview.RendererError", error_,
                              PREVIEW_ERROR_LAST_ENUM);
  }
  ClearContext();
}

Project: Chrome

bool PrintWebViewHelper::FinalizePrintReadyDocument() {
  DCHECK(!is_print_ready_metafile_sent_);
  print_preview_context_.FinalizePrintReadyDocument();

  printing::PreviewMetafile* metafile = print_preview_context_.metafile();
  uint32 buf_size = metafile->GetDataSize();
  DCHECK_GT(buf_size, 0u);

  PrintHostMsg_DidPreviewDocument_Params preview_params;
  preview_params.reuse_existing_data = false;
  preview_params.data_size = buf_size;
  preview_params.document_cookie = print_pages_params_->params.document_cookie;
  preview_params.expected_pages_count =
      print_preview_context_.total_page_count();
  preview_params.modifiable = print_preview_context_.IsModifiable();
  preview_params.preview_request_id =
      print_pages_params_->params.preview_request_id;

  if (!CopyMetafileDataToSharedMem(metafile,
                                   &(preview_params.metafile_data_handle))) {
    LOG(ERROR) << "CopyMetafileDataToSharedMem failed";
    print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED);
    return false;
  }
  is_print_ready_metafile_sent_ = true;

  Send(new PrintHostMsg_MetafileReadyForPrinting(routing_id(), preview_params));
  return true;
}

Project: Chrome

void PrepareFrameAndViewForPrint::FinishPrinting() {
  if (!finished_) {
    finished_ = true;
    frame_->printEnd();
    web_view_->resize(prev_view_size_);
    if (WebFrame* web_frame = web_view_->mainFrame())
      web_frame->setScrollOffset(prev_scroll_offset_);
  }
}

Project: Chrome

void PrintWebViewHelper::PrintPreviewContext::Finished() {
  DCHECK_EQ(DONE, state_);
  state_ = INITIALIZED;
  ClearContext();
}

Project: Chrome

int GetDPI(const PrintMsg_Print_Params* print_params) {
#if defined(OS_MACOSX)
  return printing::kPointsPerInch;
#else
  return static_cast<int>(print_params->dpi);
#endif  // defined(OS_MACOSX)
}

Project: Chrome

SkPoint GetHeaderFooterPosition(
    float webkit_scale_factor,
    const PageSizeMargins& page_layout,
    printing::HorizontalHeaderFooterPosition horizontal_position,
    printing::VerticalHeaderFooterPosition vertical_position,
    double offset_to_baseline,
    double text_width_in_points) {
  SkScalar x = 0;
  switch (horizontal_position) {
    case printing::LEFT: {
      x = printing::kSettingHeaderFooterInterstice - page_layout.margin_left;
      break;
    }
    case printing::RIGHT: {
      x = page_layout.content_width + page_layout.margin_right -
          printing::kSettingHeaderFooterInterstice - text_width_in_points;
      break;
    }
    case printing::CENTER: {
      SkScalar available_width = GetHeaderFooterSegmentWidth(
          page_layout.margin_left + page_layout.margin_right +
              page_layout.content_width);
      x = available_width - page_layout.margin_left +
          (available_width - text_width_in_points) / 2;
      break;
    }
    default: {
      NOTREACHED();
    }
  }

  SkScalar y = 0;
  switch (vertical_position) {
    case printing::TOP:
      y = printing::kSettingHeaderFooterInterstice -
          page_layout.margin_top - offset_to_baseline;
      break;
    case printing::BOTTOM:
      y = page_layout.margin_bottom + page_layout.content_height -
          printing::kSettingHeaderFooterInterstice - offset_to_baseline;
      break;
    default:
      NOTREACHED();
  }

  SkPoint point = SkPoint::Make(x / webkit_scale_factor,
                                y / webkit_scale_factor);
  return point;
}

Project: Chrome

printing::MarginType GetMarginsForPdf(WebFrame* frame, const WebNode& node) {
  if (frame->isPrintScalingDisabledForPlugin(node))
    return printing::NO_MARGINS;
  else
    return printing::PRINTABLE_AREA_MARGINS;
}

Project: Chrome

int PrintWebViewHelper::PrintPreviewContext::GetNextPageNumber() {
  DCHECK_EQ(RENDERING, state_);
  if (IsFinalPageRendered())
    return -1;
  return pages_to_render_[current_page_index_++];
}

Project: Chrome

void PrintWebViewHelper::GetPageSizeAndMarginsInPoints(
    WebFrame* frame,
    int page_index,
    const PrintMsg_Print_Params& default_params,
    PageSizeMargins* page_layout_in_points) {
  int dpi = GetDPI(&default_params);

  WebSize page_size_in_pixels(
      ConvertUnit(default_params.page_size.width(),
                  dpi, printing::kPixelsPerInch),
      ConvertUnit(default_params.page_size.height(),
                  dpi, printing::kPixelsPerInch));
  int margin_top_in_pixels = ConvertUnit(
      default_params.margin_top,
      dpi, printing::kPixelsPerInch);
  int margin_right_in_pixels = ConvertUnit(
      default_params.page_size.width() -
      default_params.printable_size.width() - default_params.margin_left,
      dpi, printing::kPixelsPerInch);
  int margin_bottom_in_pixels = ConvertUnit(
      default_params.page_size.height() -
      default_params.printable_size.height() - default_params.margin_top,
      dpi, printing::kPixelsPerInch);
  int margin_left_in_pixels = ConvertUnit(
      default_params.margin_left,
      dpi, printing::kPixelsPerInch);

  if (frame) {
    frame->pageSizeAndMarginsInPixels(page_index,
                                      page_size_in_pixels,
                                      margin_top_in_pixels,
                                      margin_right_in_pixels,
                                      margin_bottom_in_pixels,
                                      margin_left_in_pixels);
  }

  page_layout_in_points->content_width =
      ConvertPixelsToPoint(page_size_in_pixels.width -
                           margin_left_in_pixels -
                           margin_right_in_pixels);
  page_layout_in_points->content_height =
      ConvertPixelsToPoint(page_size_in_pixels.height -
                           margin_top_in_pixels -
                           margin_bottom_in_pixels);

  if (page_layout_in_points->content_width < 1.0 ||
      page_layout_in_points->content_height < 1.0) {
    CHECK(frame != NULL);
    GetPageSizeAndMarginsInPoints(NULL, page_index, default_params,
                                  page_layout_in_points);
    return;
  }

    page_layout_in_points->margin_top =
        ConvertPixelsToPointDouble(margin_top_in_pixels);
    page_layout_in_points->margin_right =
        ConvertPixelsToPointDouble(margin_right_in_pixels);
    page_layout_in_points->margin_bottom =
        ConvertPixelsToPointDouble(margin_bottom_in_pixels);
    page_layout_in_points->margin_left =
        ConvertPixelsToPointDouble(margin_left_in_pixels);
}

Project: Chrome

PrintWebViewHelper::PrintPreviewContext::GetPrintCanvasSize() const {
  DCHECK(IsRendering());
  return prep_frame_view_->GetPrintCanvasSize();
}

Project: Chrome

bool PrintWebViewHelper::GetPrintFrame(WebKit::WebFrame** frame) {
  DCHECK(frame);
  DCHECK(render_view()->GetWebView());
  if (!render_view()->GetWebView())
    return false;

  *frame = render_view()->GetWebView()->focusedFrame()->hasSelection() ?
      render_view()->GetWebView()->focusedFrame() :
      render_view()->GetWebView()->mainFrame();
  return true;
}

Project: Chrome

bool PrintWebViewHelper::GetPrintSettingsFromUser(WebKit::WebFrame* frame,
                                                  const WebKit::WebNode& node,
                                                  int expected_pages_count,
                                                  bool use_browser_overlays) {
  PrintHostMsg_ScriptedPrint_Params params;
  PrintMsg_PrintPages_Params print_settings;

  params.routing_id = render_view()->GetRoutingId();
  params.host_window_id = render_view()->GetHostWindow();
  params.cookie = print_pages_params_->params.document_cookie;
  params.has_selection = frame->hasSelection();
  params.expected_pages_count = expected_pages_count;
  printing::MarginType margin_type = printing::DEFAULT_MARGINS;
  if (PrintingNodeOrPdfFrame(frame, node))
    margin_type = GetMarginsForPdf(frame, node);
  params.margin_type = margin_type;

  Send(new PrintHostMsg_DidShowPrintDialog(routing_id()));

  print_pages_params_.reset();
  IPC::SyncMessage* msg =
      new PrintHostMsg_ScriptedPrint(routing_id(), params, &print_settings);
  msg->EnableMessagePumping();
  Send(msg);
  print_pages_params_.reset(new PrintMsg_PrintPages_Params(print_settings));
  return (print_settings.params.dpi && print_settings.params.document_cookie);
}

Project: Chrome

void PrintWebViewHelper::IncrementScriptedPrintCount() {
  ++user_cancelled_scripted_print_count_;
  last_cancelled_script_print_ = base::Time::Now();
}

Project: Chrome

bool PrintWebViewHelper::InitPrintSettings(WebKit::WebFrame* frame,
                                           const WebKit::WebNode& node) {
  DCHECK(frame);
  PrintMsg_PrintPages_Params settings;

  Send(new PrintHostMsg_GetDefaultPrintSettings(routing_id(),
                                                &settings.params));
  bool result = true;
  if (PrintMsg_Print_Params_IsEmpty(settings.params)) {
    render_view()->RunModalAlertDialog(
        frame,
        l10n_util::GetStringUTF16(
            IDS_PRINT_PREVIEW_INVALID_PRINTER_SETTINGS));
    result = false;
  }

  if (result &&
      (settings.params.dpi < kMinDpi || settings.params.document_cookie == 0)) {
    NOTREACHED();
    result = false;
  }

  settings.pages.clear();
  print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings));
  return result;
}

Project: Chrome

bool PrintWebViewHelper::InitPrintSettingsAndPrepareFrame(
    WebKit::WebFrame* frame, const WebKit::WebNode& node,
    scoped_ptr<PrepareFrameAndViewForPrint>* prepare) {
  if (!InitPrintSettings(frame, node))
    return false;

  DCHECK(!prepare->get());
  prepare->reset(new PrepareFrameAndViewForPrint(print_pages_params_->params,
                                                 frame, node));
  UpdatePrintableSizeInPrintParameters(frame, node, prepare->get(),
                                       &print_pages_params_->params);
  Send(new PrintHostMsg_DidGetDocumentCookie(
        routing_id(), print_pages_params_->params.document_cookie));
  return true;
}

Project: Chrome

void PrintWebViewHelper::PrintPreviewContext::InitWithFrame(
    WebKit::WebFrame* web_frame) {
  DCHECK(web_frame);
  DCHECK(!IsRendering());
  state_ = INITIALIZED;
  frame_ = web_frame;
  node_.reset();
}

Project: Chrome

void PrintWebViewHelper::PrintPreviewContext::InitWithNode(
    const WebKit::WebNode& web_node) {
  DCHECK(!web_node.isNull());
  DCHECK(!IsRendering());
  state_ = INITIALIZED;
  frame_ = web_node.document().frame();
  node_ = web_node;
}

Project: Chrome

bool  PrintWebViewHelper::PrintPreviewContext::IsFinalPageRendered() const {
  DCHECK(IsRendering());
  return static_cast<size_t>(current_page_index_) == pages_to_render_.size();
}

Project: Chrome

bool PrintWebViewHelper::PrintPreviewContext::IsLastPageOfPrintReadyMetafile()
    const {
  DCHECK(IsRendering());
  return current_page_index_ == print_ready_metafile_page_count_;
}

Project: Chrome

bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() const {
  return !PrintingNodeOrPdfFrame(frame(), node());
}

Project: Chrome

bool PrintWebViewHelper::PrintPreviewContext::IsRendering() const {
  return state_ == RENDERING || state_ == DONE;
}

Project: Chrome

void PrintWebViewHelper::OnInitiatePrintPreview() {
  DCHECK(is_preview_enabled_);
  WebFrame* frame;
  if (GetPrintFrame(&frame)) {
    print_preview_context_.InitWithFrame(frame);
    RequestPrintPreview();
  }
}

Project: Chrome

bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(PrintWebViewHelper, message)
    IPC_MESSAGE_HANDLER(PrintMsg_PrintPages, OnPrintPages)
    IPC_MESSAGE_HANDLER(PrintMsg_PrintForSystemDialog, OnPrintForSystemDialog)
    IPC_MESSAGE_HANDLER(PrintMsg_InitiatePrintPreview, OnInitiatePrintPreview)
    IPC_MESSAGE_HANDLER(PrintMsg_PrintNodeUnderContextMenu,
                        OnPrintNodeUnderContextMenu)
    IPC_MESSAGE_HANDLER(PrintMsg_PrintPreview, OnPrintPreview)
    IPC_MESSAGE_HANDLER(PrintMsg_PrintForPrintPreview, OnPrintForPrintPreview)
    IPC_MESSAGE_HANDLER(PrintMsg_PrintingDone, OnPrintingDone)
    IPC_MESSAGE_HANDLER(PrintMsg_ResetScriptedPrintCount,
                        ResetScriptedPrintCount)
    IPC_MESSAGE_HANDLER(PrintMsg_PreviewPrintingRequestCancelled,
                        DisplayPrintJobError)
    IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP()
  return handled;
}

Project: Chrome

void PrintWebViewHelper::OnPrintForPrintPreview(
    const DictionaryValue& job_settings) {
  DCHECK(is_preview_enabled_);
  if (print_web_view_)
    return;

  if (!render_view()->GetWebView())
    return;
  WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
  if (!main_frame)
    return;

  WebDocument document = main_frame->document();
  WebElement pdf_element = document.getElementById("pdf-viewer");
  if (pdf_element.isNull()) {
    NOTREACHED();
    return;
  }

  WebFrame* pdf_frame = pdf_element.document().frame();
  if (!UpdatePrintSettings(pdf_frame, pdf_element, job_settings, true)) {
    LOG(ERROR) << "UpdatePrintSettings failed";
    DidFinishPrinting(FAIL_PRINT);
    return;
  }

  scoped_ptr<PrepareFrameAndViewForPrint> prepare;
  prepare.reset(new PrepareFrameAndViewForPrint(print_pages_params_->params,
                                                pdf_frame, pdf_element));
  UpdatePrintableSizeInPrintParameters(pdf_frame, pdf_element, prepare.get(),
                                       &print_pages_params_->params);

  if (!RenderPagesForPrint(pdf_frame, pdf_element, prepare.get())) {
    LOG(ERROR) << "RenderPagesForPrint failed";
    DidFinishPrinting(FAIL_PRINT);
  }
}

Project: Chrome

void PrintWebViewHelper::OnPrintNodeUnderContextMenu() {
  const WebNode& context_menu_node = render_view()->GetContextMenuNode();
  if (context_menu_node.isNull()) {
    NOTREACHED();
    return;
  }

  if (is_preview_enabled_) {
    print_preview_context_.InitWithNode(context_menu_node);
    RequestPrintPreview();
  } else {
    WebNode duplicate_node(context_menu_node);
    Print(duplicate_node.document().frame(), duplicate_node);
  }
}

Project: Chrome

void PrintWebViewHelper::OnPrintPages() {
  WebFrame* frame;
  if (GetPrintFrame(&frame))
    Print(frame, WebNode());
}

Project: Chrome

void PrintWebViewHelper::OnPrintPreview(const DictionaryValue& settings) {
  DCHECK(is_preview_enabled_);
  print_preview_context_.OnPrintPreview();

  if (!UpdatePrintSettings(print_preview_context_.frame(),
                           print_preview_context_.node(), settings, false)) {
    if (print_preview_context_.last_error() != PREVIEW_ERROR_BAD_SETTING) {
      Send(new PrintHostMsg_PrintPreviewInvalidPrinterSettings(
          routing_id(), print_pages_params_->params.document_cookie));
      notify_browser_of_print_failure_ = false;  // Already sent.
    }
    DidFinishPrinting(FAIL_PREVIEW);
    return;
  }

  if (!print_pages_params_->params.is_first_request &&
      old_print_pages_params_.get() &&
      PrintMsg_Print_Params_IsEqual(*old_print_pages_params_,
                                    *print_pages_params_)) {
    PrintHostMsg_DidPreviewDocument_Params preview_params;
    preview_params.reuse_existing_data = true;
    preview_params.data_size = 0;
    preview_params.document_cookie =
        print_pages_params_->params.document_cookie;
    preview_params.expected_pages_count =
        print_preview_context_.total_page_count();
    preview_params.modifiable = print_preview_context_.IsModifiable();
    preview_params.preview_request_id =
        print_pages_params_->params.preview_request_id;

    Send(new PrintHostMsg_MetafileReadyForPrinting(routing_id(),
                                                   preview_params));
    return;
  }
  old_print_pages_params_.reset();
  is_print_ready_metafile_sent_ = false;

  print_pages_params_->params.supports_alpha_blend = true;

  bool generate_draft_pages = false;
  if (!settings.GetBoolean(printing::kSettingGenerateDraftData,
                           &generate_draft_pages)) {
    NOTREACHED();
  }
  print_preview_context_.set_generate_draft_pages(generate_draft_pages);

  if (CreatePreviewDocument()) {
    DidFinishPrinting(OK);
  } else {
    if (notify_browser_of_print_failure_)
      LOG(ERROR) << "CreatePreviewDocument failed";
    DidFinishPrinting(FAIL_PREVIEW);
  }
}

Project: Chrome

void PrintWebViewHelper::PrintPreviewContext::OnPrintPreview() {
  DCHECK_EQ(INITIALIZED, state_);
  ClearContext();
}

Project: Chrome

bool PageLayoutIsEqual(const PrintMsg_PrintPages_Params& oldParams,
                       const PrintMsg_PrintPages_Params& newParams) {
  return oldParams.params.printable_size == newParams.params.printable_size &&
         oldParams.params.page_size == newParams.params.page_size &&
         oldParams.params.margin_top == newParams.params.margin_top &&
         oldParams.params.margin_left == newParams.params.margin_left &&
         oldParams.params.desired_dpi == newParams.params.desired_dpi &&
         oldParams.params.dpi == newParams.params.dpi;
}

Project: Chrome

bool PrintWebViewHelper::PreviewPageRendered(int page_number,
                                             printing::Metafile* metafile) {
  DCHECK_GE(page_number, printing::FIRST_PAGE_INDEX);

  if (!print_preview_context_.IsModifiable() ||
      !print_preview_context_.generate_draft_pages()) {
    DCHECK(!metafile);
    return true;
  }

  if (!metafile) {
    NOTREACHED();
    print_preview_context_.set_error(
        PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE);
    return false;
  }

  PrintHostMsg_DidPreviewPage_Params preview_page_params;
  uint32 buf_size = metafile->GetDataSize();
  DCHECK_GT(buf_size, 0u);
  if (!CopyMetafileDataToSharedMem(
      metafile, &(preview_page_params.metafile_data_handle))) {
    LOG(ERROR) << "CopyMetafileDataToSharedMem failed";
    print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED);
    return false;
  }
  preview_page_params.data_size = buf_size;
  preview_page_params.page_number = page_number;
  preview_page_params.preview_request_id =
      print_pages_params_->params.preview_request_id;

  Send(new PrintHostMsg_DidPreviewPage(routing_id(), preview_page_params));
  return true;
}

Project: Chrome

void PrintWebViewHelper::Print(WebKit::WebFrame* frame,
                               const WebKit::WebNode& node) {
  if (print_web_view_)
    return;

  scoped_ptr<PrepareFrameAndViewForPrint> prepare;
  if (!InitPrintSettingsAndPrepareFrame(frame, node, &prepare)) {
    DidFinishPrinting(FAIL_PRINT);
    return;  // Failed to init print page settings.
  }

  int expected_page_count = 0;
  bool use_browser_overlays = true;

  expected_page_count = prepare->GetExpectedPageCount();
  if (expected_page_count)
    use_browser_overlays = prepare->ShouldUseBrowserOverlays();

  prepare.reset();

  if (!expected_page_count) {
    DidFinishPrinting(OK);  // Release resources and fail silently.
    return;
  }

  if (!GetPrintSettingsFromUser(frame, node, expected_page_count,
                                use_browser_overlays)) {
    DidFinishPrinting(OK);  // Release resources and fail silently.
    return;
  }

  if (!RenderPagesForPrint(frame, node, NULL)) {
    LOG(ERROR) << "RenderPagesForPrint failed";
    DidFinishPrinting(FAIL_PRINT);
  }
  ResetScriptedPrintCount();
}

Project: Chrome

void PrintWebViewHelper::PrintHeaderAndFooter(
    WebKit::WebCanvas* canvas,
    int page_number,
    int total_pages,
    float webkit_scale_factor,
    const PageSizeMargins& page_layout,
    const DictionaryValue& header_footer_info) {
#if defined(USE_SKIA)
  skia::VectorPlatformDeviceSkia* device =
      static_cast<skia::VectorPlatformDeviceSkia*>(canvas->getTopDevice());
  device->setDrawingArea(SkPDFDevice::kMargin_DrawingArea);

  SkPaint paint;
  paint.setColor(SK_ColorBLACK);
  paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
  paint.setTextSize(SkDoubleToScalar(printing::kSettingHeaderFooterFontSize));
  paint.setTypeface(SkTypeface::CreateFromName(
      printing::kSettingHeaderFooterFontFamilyName, SkTypeface::kNormal));
#elif defined(OS_MACOSX)
  gfx::ScopedCGContextSaveGState CGContextSaveGState(canvas);
  CGContextSetCharacterSpacing(canvas,
                               printing::kSettingHeaderFooterCharacterSpacing);
  CGContextSetTextDrawingMode(canvas, kCGTextFill);
  CGContextSetGrayFillColor(canvas, kBlackGrayLevel, kOpaqueLevel);
  CGContextSelectFont(canvas, printing::kSettingHeaderFooterFontName,
                      printing::kSettingHeaderFooterFontSize,
                      kCGEncodingFontSpecific);
  ScopedCFTypeRef<CFStringRef> font_name(base::SysUTF8ToCFStringRef(
      printing::kSettingHeaderFooterFontName));
  const CGAffineTransform flip_text =  CGAffineTransformMakeScale(1.0f, -1.0f);
  ScopedCFTypeRef<CTFontRef> ct_font(CTFontCreateWithName(
      font_name,
      printing::kSettingHeaderFooterFontSize / webkit_scale_factor,
      &flip_text));
  const void* keys[] = {kCTFontAttributeName};
  const void* values[] = {ct_font};
  ScopedCFTypeRef<CFDictionaryRef> paint(CFDictionaryCreate(
      NULL, keys, values, sizeof(keys) / sizeof(keys[0]), NULL, NULL));
#endif

  string16 date;
  string16 title;
  if (!header_footer_info.GetString(printing::kSettingHeaderFooterTitle,
                                    &title) ||
      !header_footer_info.GetString(printing::kSettingHeaderFooterDate,
                                    &date)) {
    NOTREACHED();
  }
  string16 header_text = date + title;

  SkRect header_vertical_bounds;
#if defined(USE_SKIA)
  paint.measureText(header_text.c_str(), header_text.length() * sizeof(char16),
                    &header_vertical_bounds, 0);
#elif defined(OS_MACOSX)
  header_vertical_bounds.fTop = CTFontGetAscent(ct_font) * webkit_scale_factor;
  header_vertical_bounds.fBottom = -CTFontGetDescent(ct_font) *
                                   webkit_scale_factor;
#endif
  double text_height = printing::kSettingHeaderFooterInterstice +
                       header_vertical_bounds.height();
  if (text_height <= page_layout.margin_top) {
    PrintHeaderFooterText(date, canvas, paint, webkit_scale_factor, page_layout,
                          printing::LEFT, printing::TOP,
                          header_vertical_bounds.top());
    PrintHeaderFooterText(title, canvas, paint, webkit_scale_factor,
                          page_layout, printing::CENTER, printing::TOP,
                          header_vertical_bounds.top());
  }

  string16 page_of_total_pages = base::IntToString16(page_number) +
                                 UTF8ToUTF16("/") +
                                 base::IntToString16(total_pages);
  string16 url;
  if (!header_footer_info.GetString(printing::kSettingHeaderFooterURL,
                                    &url)) {
    NOTREACHED();
  }
  string16 footer_text = page_of_total_pages + url;

  SkRect footer_vertical_bounds;
#if defined(USE_SKIA)
  paint.measureText(footer_text.c_str(), footer_text.length() * sizeof(char16),
                    &footer_vertical_bounds, 0);
#elif defined(OS_MACOSX)
  footer_vertical_bounds.fTop = header_vertical_bounds.fTop;
  footer_vertical_bounds.fBottom = header_vertical_bounds.fBottom;
#endif
  text_height = printing::kSettingHeaderFooterInterstice +
                footer_vertical_bounds.height();
  if (text_height <= page_layout.margin_bottom) {
    PrintHeaderFooterText(page_of_total_pages, canvas, paint,
                          webkit_scale_factor, page_layout, printing::RIGHT,
                          printing::BOTTOM, footer_vertical_bounds.bottom());
    PrintHeaderFooterText(url, canvas, paint, webkit_scale_factor, page_layout,
                          printing::LEFT, printing::BOTTOM,
                          footer_vertical_bounds.bottom());
  }

#if defined(USE_SKIA)
  device->setDrawingArea(SkPDFDevice::kContent_DrawingArea);
#endif
}

Project: Chrome

void PrintHeaderFooterText(
    string16 text,
    WebKit::WebCanvas* canvas,
    HeaderFooterPaint paint,
    float webkit_scale_factor,
    const PageSizeMargins& page_layout,
    printing::HorizontalHeaderFooterPosition horizontal_position,
    printing::VerticalHeaderFooterPosition vertical_position,
    double offset_to_baseline) {
#if defined(USE_SKIA)
  size_t text_byte_length = text.length() * sizeof(char16);
  double text_width_in_points = SkScalarToDouble(paint.measureText(
      text.c_str(), text_byte_length));
  SkPoint point = GetHeaderFooterPosition(webkit_scale_factor, page_layout,
                                          horizontal_position,
                                          vertical_position, offset_to_baseline,
                                          text_width_in_points);
  paint.setTextSize(SkDoubleToScalar(
      paint.getTextSize() / webkit_scale_factor));
  canvas->drawText(text.c_str(), text_byte_length, point.x(), point.y(),
                   paint);
#elif defined(OS_MACOSX)
  ScopedCFTypeRef<CFStringRef> cf_text(base::SysUTF16ToCFStringRef(text));
  ScopedCFTypeRef<CFAttributedStringRef> cf_attr_text(
      CFAttributedStringCreate(NULL, cf_text, paint));
  ScopedCFTypeRef<CTLineRef> line(CTLineCreateWithAttributedString(
      cf_attr_text));
  double text_width_in_points =
      CTLineGetTypographicBounds(line, NULL, NULL, NULL) * webkit_scale_factor;
  SkPoint point = GetHeaderFooterPosition(webkit_scale_factor,
                                          page_layout, horizontal_position,
                                          vertical_position, offset_to_baseline,
                                          text_width_in_points);
  CGContextSetTextPosition(canvas, SkScalarToDouble(point.x()),
                           SkScalarToDouble(point.y()));
  CTLineDraw(line, canvas);
#endif
}

Project: Chrome

bool PrintMsg_Print_Params_IsEmpty(const PrintMsg_Print_Params& params) {
  return !params.document_cookie && !params.desired_dpi && !params.max_shrink &&
         !params.min_shrink && !params.dpi && params.printable_size.IsEmpty() &&
         !params.selection_only && params.page_size.IsEmpty() &&
         !params.margin_top && !params.margin_left &&
         !params.supports_alpha_blend;
}

Project: Chrome

bool PrintMsg_Print_Params_IsEqual(
    const PrintMsg_PrintPages_Params& oldParams,
    const PrintMsg_PrintPages_Params& newParams) {
  return PageLayoutIsEqual(oldParams, newParams) &&
         oldParams.params.max_shrink == newParams.params.max_shrink &&
         oldParams.params.min_shrink == newParams.params.min_shrink &&
         oldParams.params.selection_only == newParams.params.selection_only &&
         oldParams.params.supports_alpha_blend ==
             newParams.params.supports_alpha_blend &&
         oldParams.pages.size() == newParams.pages.size() &&
         oldParams.params.display_header_footer ==
             newParams.params.display_header_footer &&
         oldParams.params.date == newParams.params.date &&
         oldParams.params.title == newParams.params.title &&
         oldParams.params.url == newParams.params.url &&
         std::equal(oldParams.pages.begin(), oldParams.pages.end(),
             newParams.pages.begin());
}

Project: Chrome

void PrintWebViewHelper::PrintPage(WebKit::WebFrame* frame) {
  DCHECK(frame);

  if (prerender::PrerenderHelper::IsPrerendering(render_view())) {
    Send(new ChromeViewHostMsg_CancelPrerenderForPrinting(routing_id()));
    return;
  }

  if (IsScriptInitiatedPrintTooFrequent(frame))
    return;
  IncrementScriptedPrintCount();

  if (is_preview_enabled_) {
    print_preview_context_.InitWithFrame(frame);
    RequestPrintPreview();
  } else {
    Print(frame, WebNode());
  }
}

Project: Chrome

bool PrintWebViewHelper::PrintPages(const PrintMsg_PrintPages_Params& params,
                                    WebFrame* frame,
                                    const WebNode& node,
                                    PrepareFrameAndViewForPrint* prepare) {
  PrintMsg_Print_Params print_params = params.params;
  scoped_ptr<PrepareFrameAndViewForPrint> prep_frame_view;
  if (!prepare) {
    prep_frame_view.reset(new PrepareFrameAndViewForPrint(print_params, frame,
                                                          node));
    prepare = prep_frame_view.get();
  }
  UpdatePrintableSizeInPrintParameters(frame, node, prepare, &print_params);

  int page_count = prepare->GetExpectedPageCount();
  if (!page_count)
    return false;
  Send(new PrintHostMsg_DidGetPrintedPagesCount(routing_id(),
                                                print_params.document_cookie,
                                                page_count));

  const gfx::Size& canvas_size = prepare->GetPrintCanvasSize();
  PrintMsg_PrintPage_Params page_params;
  page_params.params = print_params;
  if (params.pages.empty()) {
    for (int i = 0; i < page_count; ++i) {
      page_params.page_number = i;
      PrintPageInternal(page_params, canvas_size, frame);
    }
  } else {
    for (size_t i = 0; i < params.pages.size(); ++i) {
      if (params.pages[i] >= page_count)
        break;
      page_params.page_number = params.pages[i];
      PrintPageInternal(page_params, canvas_size, frame);
    }
  }
  return true;
}

Project: Chrome

PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext()
    : frame_(NULL),
      total_page_count_(0),
      current_page_index_(0),
      generate_draft_pages_(true),
      print_ready_metafile_page_count_(0),
      error_(PREVIEW_ERROR_NONE),
      state_(UNINITIALIZED) {
}

Project: Chrome

PrintWebViewHelper::PrintWebViewHelper(content::RenderView* render_view)
    : content::RenderViewObserver(render_view),
      content::RenderViewObserverTracker<PrintWebViewHelper>(render_view),
      print_web_view_(NULL),
      is_preview_enabled_(switches::IsPrintPreviewEnabled()),
      is_print_ready_metafile_sent_(false),
      user_cancelled_scripted_print_count_(0),
      notify_browser_of_print_failure_(true) {
}

Project: Chrome

bool PrintingNodeOrPdfFrame(const WebFrame* frame, const WebNode& node) {
  if (!node.isNull())
    return true;
  std::string mime(frame->dataSource()->response().mimeType().utf8());
  return mime == "application/pdf";
}

Project: Chrome

bool PrintWebViewHelper::RenderPagesForPrint(
    WebKit::WebFrame* frame,
    const WebKit::WebNode& node,
    PrepareFrameAndViewForPrint* prepare) {
  PrintMsg_PrintPages_Params print_settings = *print_pages_params_;
  if (print_settings.params.selection_only) {
    return CopyAndPrint(frame);
  } else {
    return PrintPages(print_settings, frame, node, prepare);
  }
}

Project: Chrome

void PrintWebViewHelper::PrintPreviewContext::RenderedPreviewPage(
    const base::TimeDelta& page_time) {
  DCHECK_EQ(RENDERING, state_);
  document_render_time_ += page_time;
  UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", page_time);
}

Project: Chrome

void PrintWebViewHelper::RequestPrintPreview() {
  old_print_pages_params_.reset();
  Send(new PrintHostMsg_RequestPrintPreview(routing_id()));
}

Project: Chrome

void PrintWebViewHelper::ResetScriptedPrintCount() {
  user_cancelled_scripted_print_count_ = 0;
}

Project: Chrome

void PrepareFrameAndViewForPrint::StartPrinting(
    const gfx::Size& print_canvas_size) {
  print_canvas_size_ = print_canvas_size;

  gfx::Size print_layout_size(print_canvas_size_);
  print_layout_size.set_height(static_cast<int>(
      static_cast<double>(print_layout_size.height()) * 1.25));

  web_view_->resize(print_layout_size);

  expected_pages_count_ = frame_->printBegin(print_canvas_size_, node_to_print_,
                                             dpi_, &use_browser_overlays_);
}

Project: Chrome

void PrepareFrameAndViewForPrint::UpdatePrintParams(
    const PrintMsg_Print_Params& print_params) {
  DCHECK(!finished_);
  gfx::Size canvas_size;
  CalculatePrintCanvasSize(print_params, &canvas_size);
  if (canvas_size == print_canvas_size_)
    return;

  frame_->printEnd();
  dpi_ = static_cast<int>(print_params.dpi);
  StartPrinting(canvas_size);
}

Project: Chrome

bool PrintWebViewHelper::UpdatePrintSettings(
    WebKit::WebFrame* frame, const WebKit::WebNode& node,
    const DictionaryValue& passed_job_settings, bool print_for_preview) {
  DCHECK(is_preview_enabled_);
  const DictionaryValue* job_settings = &passed_job_settings;
  DictionaryValue modified_job_settings;
  if (job_settings->empty()) {
    if (!print_for_preview)
      print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING);
    return false;
  }

  bool source_is_html = true;
  if (print_for_preview) {
    if (!job_settings->GetBoolean(printing::kSettingPreviewModifiable,
                                  &source_is_html)) {
      NOTREACHED();
    }
  } else {
    source_is_html = !PrintingNodeOrPdfFrame(frame, node);
  }

  if (print_for_preview || !source_is_html) {
    modified_job_settings.MergeDictionary(job_settings);
    modified_job_settings.SetBoolean(printing::kSettingHeaderFooterEnabled,
                                     false);

#if defined(OS_MACOSX) && !defined(USE_SKIA)
    bool get_margins_from_pdf = !source_is_html && !print_for_preview;
#elif defined(OS_WIN) || defined(OS_MACOSX)
    bool get_margins_from_pdf = !source_is_html && print_for_preview;
#else
    bool get_margins_from_pdf = false;
#endif

    printing::MarginType margin_type = printing::NO_MARGINS;
    if (get_margins_from_pdf)
      margin_type = GetMarginsForPdf(frame, node);
    modified_job_settings.SetInteger(printing::kSettingMarginsType,
                                     margin_type);
    job_settings = &modified_job_settings;
  }

  int cookie = print_pages_params_.get() ?
      print_pages_params_->params.document_cookie : 0;
  PrintMsg_PrintPages_Params settings;
  Send(new PrintHostMsg_UpdatePrintSettings(routing_id(),
      cookie, *job_settings, &settings));
  print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings));

  if (PrintMsg_Print_Params_IsEmpty(settings.params)) {
    if (!print_for_preview) {
      print_preview_context_.set_error(PREVIEW_ERROR_INVALID_PRINTER_SETTINGS);
    } else {
      WebKit::WebFrame* print_frame = NULL;
      GetPrintFrame(&print_frame);
      if (print_frame) {
        render_view()->RunModalAlertDialog(
            print_frame,
            l10n_util::GetStringUTF16(
                IDS_PRINT_PREVIEW_INVALID_PRINTER_SETTINGS));
      }
    }
    return false;
  }

  if (settings.params.dpi < kMinDpi || !settings.params.document_cookie) {
    print_preview_context_.set_error(PREVIEW_ERROR_UPDATING_PRINT_SETTINGS);
    return false;
  }

  if (!print_for_preview) {
    if (!job_settings->GetString(printing::kPreviewUIAddr,
                                 &(settings.params.preview_ui_addr)) ||
        !job_settings->GetInteger(printing::kPreviewRequestID,
                                  &(settings.params.preview_request_id)) ||
        !job_settings->GetBoolean(printing::kIsFirstRequest,
                                  &(settings.params.is_first_request))) {
      NOTREACHED();
      print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING);
      return false;
    }

    PageSizeMargins default_page_layout;
    GetPageSizeAndMarginsInPoints(NULL, -1, settings.params,
                                  &default_page_layout);
    if (!old_print_pages_params_.get() ||
        !PageLayoutIsEqual(*old_print_pages_params_, settings)) {
      Send(new PrintHostMsg_DidGetDefaultPageLayout(routing_id(),
                                                    default_page_layout));
    }

    if (settings.params.display_header_footer) {
      header_footer_info_.reset(new DictionaryValue());
      header_footer_info_->SetString(printing::kSettingHeaderFooterDate,
                                     settings.params.date);
      header_footer_info_->SetString(printing::kSettingHeaderFooterURL,
                                     settings.params.url);
      header_footer_info_->SetString(printing::kSettingHeaderFooterTitle,
                                     settings.params.title);
    }
  }

  print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings));
  Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(),
                                             settings.params.document_cookie));
  return true;
}

Project: Chrome

void PrintWebViewHelper::UpdatePrintableSizeInPrintParameters(
    WebFrame* frame,
    const WebNode& node,
    PrepareFrameAndViewForPrint* prepare,
    PrintMsg_Print_Params* params) {
  if (PrintingNodeOrPdfFrame(frame, node))
    return;
  PageSizeMargins page_layout_in_points;
  PrintWebViewHelper::GetPageSizeAndMarginsInPoints(frame, 0, *params,
                                                    &page_layout_in_points);
  int dpi = GetDPI(params);
  params->printable_size = gfx::Size(
      static_cast<int>(ConvertUnitDouble(
          page_layout_in_points.content_width,
          printing::kPointsPerInch, dpi)),
      static_cast<int>(ConvertUnitDouble(
          page_layout_in_points.content_height,
          printing::kPointsPerInch, dpi)));

  double page_width_in_points =
      page_layout_in_points.content_width +
      page_layout_in_points.margin_left +
      page_layout_in_points.margin_right;
  double page_height_in_points =
      page_layout_in_points.content_height +
      page_layout_in_points.margin_top +
      page_layout_in_points.margin_bottom;

  params->page_size = gfx::Size(
      static_cast<int>(ConvertUnitDouble(
          page_width_in_points, printing::kPointsPerInch, dpi)),
      static_cast<int>(ConvertUnitDouble(
          page_height_in_points, printing::kPointsPerInch, dpi)));

  params->margin_top = static_cast<int>(ConvertUnitDouble(
      page_layout_in_points.margin_top, printing::kPointsPerInch, dpi));
  params->margin_left = static_cast<int>(ConvertUnitDouble(
      page_layout_in_points.margin_left, printing::kPointsPerInch, dpi));

  prepare->UpdatePrintParams(*params);
}

Project: Chrome

void PrintWebViewHelper::didStopLoading() {
  PrintMsg_PrintPages_Params* params = print_pages_params_.get();
  DCHECK(params != NULL);
  PrintPages(*params, print_web_view_->mainFrame(), WebNode(), NULL);
}

Project: Chrome

int PrintWebViewHelper::PrintPreviewContext::last_error() const {
  return error_;
}

Project: Chrome

PrintWebViewHelper::PrintPreviewContext::metafile() const {
  DCHECK(IsRendering());
  return metafile_.get();
}

Project: Chrome

const WebKit::WebNode& PrintWebViewHelper::PrintPreviewContext::node() const {
  DCHECK(state_ != UNINITIALIZED);
  return node_;
}

Project: Chrome

void PrintWebViewHelper::PrintPreviewContext::set_error(
    enum PrintPreviewErrorBuckets error) {
  error_ = error;
}

Project: Chrome

void PrintWebViewHelper::PrintPreviewContext::set_generate_draft_pages(
    bool generate_draft_pages) {
  DCHECK_EQ(INITIALIZED, state_);
  generate_draft_pages_ = generate_draft_pages;
}

Project: Chrome

int PrintWebViewHelper::PrintPreviewContext::total_page_count() const {
  DCHECK(IsRendering());
  return total_page_count_;
}

Project: Chrome

PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() {
}

Project: Chrome

PrintWebViewHelper::~PrintWebViewHelper() {}