15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "stdafx.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "win8/metro_driver/print_document_source.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.graphics.display.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/safe_numerics.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class D2DFactoryAutoLock {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit D2DFactoryAutoLock(ID2D1Factory* d2d_factory) {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HRESULT hr = d2d_factory->QueryInterface(IID_PPV_ARGS(&d2d_multithread_));
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (d2d_multithread_.Get())
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      d2d_multithread_->Enter();
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Failed to QI for ID2D1Multithread " << std::hex << hr;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~D2DFactoryAutoLock() {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (d2d_multithread_.Get())
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      d2d_multithread_->Leave();
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<ID2D1Multithread> d2d_multithread_;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(mad): remove once we don't run mixed SDK/OS anymore.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const GUID kOldPackageTargetGuid =
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {0xfb2a33c0, 0x8c35, 0x465f,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {0xbe, 0xd5, 0x9f, 0x36, 0x89, 0x51, 0x77, 0x52}};
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const GUID kNewPackageTargetGuid =
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {0x1a6dd0ad, 0x1e2a, 0x4e99,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {0xa5, 0xba, 0x91, 0xf1, 0x78, 0x18, 0x29, 0x0e}};
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace metro_driver {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PrintDocumentSource::PrintDocumentSource()
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : page_count_ready_(true, false),
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_lock_(NULL),
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      height_(0),
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      width_(0),
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dpi_(96),
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      aborted_(false),
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      using_old_preview_interface_(false) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT PrintDocumentSource::RuntimeClassInitialize(
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DirectXContext& directx_context,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Lock* parent_lock) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(parent_lock != NULL);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(directx_context.d2d_context.Get() != NULL);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(directx_context.d2d_device.Get() != NULL);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(directx_context.d2d_factory.Get() != NULL);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(directx_context.d3d_device.Get() != NULL);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(directx_context.wic_factory.Get() != NULL);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  directx_context_ = directx_context;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No other method can be called before RuntimeClassInitialize which is called
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // during the construction via mswr::MakeAndInitialize(), so it's safe for all
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // other methods to use the parent_lock_ without checking if it's NULL.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(parent_lock_ == NULL);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parent_lock_ = parent_lock;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrintDocumentSource::Abort() {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock lock(*parent_lock_);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  aborted_ = true;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (page_count_ready_.IsSignaled()) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pages_.clear();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < pages_ready_state_.size(); ++i)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pages_ready_state_[i]->Broadcast();
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(pages_.empty() && pages_ready_state_.empty());
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STDMETHODIMP PrintDocumentSource::GetPreviewPageCollection(
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPrintDocumentPackageTarget* package_target,
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPrintPreviewPageCollection** page_collection) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(package_target != NULL);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(page_collection != NULL);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = package_target->GetPackageTarget(
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      __uuidof(IPrintPreviewDxgiPackageTarget),
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IID_PPV_ARGS(&dxgi_preview_target_));
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(mad): remove once we don't run mixed SDK/OS anymore.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The IID changed from one version of the SDK to another, so try the other
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // one in case we are running a build from a different SDK than the one
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // related to the OS version we are running.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GUID package_target_uuid = kNewPackageTargetGuid;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (package_target_uuid == __uuidof(IPrintPreviewDxgiPackageTarget)) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      package_target_uuid = kOldPackageTargetGuid;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      using_old_preview_interface_ = true;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = package_target->GetPackageTarget(package_target_uuid,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          package_target_uuid,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          &dxgi_preview_target_);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr)) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to get IPrintPreviewDXGIPackageTarget " << std::hex
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << hr;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return hr;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    using_old_preview_interface_ = (__uuidof(IPrintPreviewDxgiPackageTarget) ==
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    kOldPackageTargetGuid);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<IPrintPreviewPageCollection> preview_page_collection;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<PrintDocumentSource> print_document_source(this);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = print_document_source.As(&preview_page_collection);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to get preview_page_collection " << std::hex << hr;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = preview_page_collection.CopyTo(page_collection);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to copy preview_page_collection " << std::hex << hr;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STDMETHODIMP PrintDocumentSource::MakeDocument(
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IInspectable* options,
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPrintDocumentPackageTarget* package_target) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(options != NULL);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(package_target != NULL);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<wingfx::Printing::IPrintTaskOptionsCore> print_task_options;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = options->QueryInterface(
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wingfx::Printing::IID_IPrintTaskOptionsCore,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<void**>(print_task_options.GetAddressOf()));
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to QI for IPrintTaskOptionsCore " << std::hex << hr;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use the first page's description for the whole document. Page numbers
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are 1-based in this context.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mad): Check if it would be useful to use per page descriptions.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wingfx::Printing::PrintPageDescription page_desc = {};
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = print_task_options->GetPageDescription(1 /* page */, &page_desc);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to GetPageDescription " << std::hex << hr;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  D2D1_PRINT_CONTROL_PROPERTIES print_control_properties;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (page_desc.DpiX > page_desc.DpiY)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print_control_properties.rasterDPI = static_cast<float>(page_desc.DpiY);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print_control_properties.rasterDPI = static_cast<float>(page_desc.DpiX);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Color space for vector graphics in D2D print control.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_control_properties.colorSpace = D2D1_COLOR_SPACE_SRGB;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_control_properties.fontSubset = D2D1_PRINT_FONT_SUBSET_MODE_DEFAULT;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<ID2D1PrintControl> print_control;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = directx_context_.d2d_device->CreatePrintControl(
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      directx_context_.wic_factory.Get(),
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      package_target,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print_control_properties,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print_control.GetAddressOf());
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to CreatePrintControl " << std::hex << hr;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  D2D1_SIZE_F page_size = D2D1::SizeF(page_desc.PageSize.Width,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      page_desc.PageSize.Height);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wait for the number of pages to be available.
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If an abort occured, we'll get 0 and won't enter the loop below.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t page_count = WaitAndGetPageCount();
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<ID2D1GdiMetafile> gdi_metafile;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t page = 0; page < page_count; ++page) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gdi_metafile.Reset();
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = WaitAndGetPage(page, gdi_metafile.GetAddressOf());
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG_IF(ERROR, FAILED(hr)) << "Failed to get page's metafile " << std::hex
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              << hr;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // S_FALSE means we got aborted.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (hr == S_FALSE || FAILED(hr))
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = PrintPage(print_control.Get(), gdi_metafile.Get(), page_size);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr))
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT close_hr = print_control->Close();
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(close_hr) && SUCCEEDED(hr))
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return close_hr;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STDMETHODIMP PrintDocumentSource::Paginate(uint32 page,
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           IInspectable* options) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__ << ", page = " << page;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(options != NULL);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // GetPreviewPageCollection must have been successfuly called.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(dxgi_preview_target_.Get() != NULL);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get print settings from PrintTaskOptions for preview, such as page
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // description, which contains page size, imageable area, DPI.
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mad): obtain other print settings in the same way, such as ColorMode,
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NumberOfCopies, etc...
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<wingfx::Printing::IPrintTaskOptionsCore> print_options;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = options->QueryInterface(
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wingfx::Printing::IID_IPrintTaskOptionsCore,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<void**>(print_options.GetAddressOf()));
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to QI for IPrintTaskOptionsCore " << std::hex << hr;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wingfx::Printing::PrintPageDescription page_desc = {};
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = print_options->GetPageDescription(1 /* page */, &page_desc);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to GetPageDescription " << std::hex << hr;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  width_ = page_desc.PageSize.Width;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  height_ = page_desc.PageSize.Height;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = dxgi_preview_target_->InvalidatePreview();
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to InvalidatePreview " << std::hex << hr;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t page_count = WaitAndGetPageCount();
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A page_count of 0 means abort...
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (page_count == 0)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_FALSE;
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = dxgi_preview_target_->SetJobPageCount(
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           PageCountType::FinalPageCount,
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           base::checked_numeric_cast<UINT32>(page_count));
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to SetJobPageCount " << std::hex << hr;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STDMETHODIMP PrintDocumentSource::MakePage(uint32 job_page,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           float width,
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           float height) {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__ << ", width: " << width << ", height: " << height
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << ", job_page: " << job_page;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(width > 0 && height > 0);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Paginate must have been called before this.
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (width_ <= 0.0 || height_ <= 0.0)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_FALSE;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When job_page is JOB_PAGE_APPLICATION_DEFINED, it means a new preview
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // begins. TODO(mad): Double check if we need to cancel pending resources.
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (job_page == JOB_PAGE_APPLICATION_DEFINED)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    job_page = 1;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  winfoundtn::Size preview_size;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preview_size.Width  = width;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preview_size.Height = height;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float scale = width_ / width;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<ID2D1Factory> factory;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  directx_context_.d2d_device->GetFactory(&factory);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<ID2D1GdiMetafile> gdi_metafile;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = WaitAndGetPage(job_page - 1, gdi_metafile.GetAddressOf());
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG_IF(ERROR, FAILED(hr)) << "Failed to get page's metafile " << std::hex
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            << hr;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Again, S_FALSE means we got aborted.
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (hr == S_FALSE || FAILED(hr))
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We are accessing D3D resources directly without D2D's knowledge, so we
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // must manually acquire the D2D factory lock.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  D2DFactoryAutoLock factory_lock(directx_context_.d2d_factory.Get());
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CD3D11_TEXTURE2D_DESC texture_desc(
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DXGI_FORMAT_B8G8R8A8_UNORM,
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<UINT32>(ceil(width  * dpi_ / 96)),
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<UINT32>(ceil(height * dpi_ / 96)),
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      1,
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      1,
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      );
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<ID3D11Texture2D> texture;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = directx_context_.d3d_device->CreateTexture2D(
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &texture_desc, NULL, &texture);
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to create a 2D texture " << std::hex << hr;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<IDXGISurface> dxgi_surface;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = texture.As<IDXGISurface>(&dxgi_surface);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to QI for IDXGISurface " << std::hex << hr;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // D2D device contexts are stateful, and hence a unique device context must
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be used on each call.
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<ID2D1DeviceContext> d2d_context;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = directx_context_.d2d_device->CreateDeviceContext(
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &d2d_context);
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  d2d_context->SetDpi(dpi_, dpi_);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<ID2D1Bitmap1> d2dSurfaceBitmap;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = d2d_context->CreateBitmapFromDxgiSurface(dxgi_surface.Get(),
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                NULL,  // default properties.
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &d2dSurfaceBitmap);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to CreateBitmapFromDxgiSurface " << std::hex << hr;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  d2d_context->SetTarget(d2dSurfaceBitmap.Get());
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  d2d_context->BeginDraw();
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  d2d_context->Clear();
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  d2d_context->SetTransform(D2D1::Matrix3x2F(1/scale, 0, 0, 1/scale, 0, 0));
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  d2d_context->DrawGdiMetafile(gdi_metafile.Get());
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = d2d_context->EndDraw();
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to EndDraw " << std::hex << hr;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(mad): remove once we don't run mixed SDK/OS anymore.
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef __IPrintPreviewDxgiPackageTarget_FWD_DEFINED__
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FLOAT dpi = dpi_;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (using_old_preview_interface_) {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We compiled with the new API but run on the old OS, so we must cheat
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and send something that looks like a float but has a UINT32 value.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *reinterpret_cast<UINT32*>(&dpi) = static_cast<UINT32>(dpi_);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UINT32 dpi = static_cast<UINT32>(dpi_);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!using_old_preview_interface_) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We compiled with the old API but run on the new OS, so we must cheat
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and send something that looks like a UINT32 but has a float value.
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *reinterpret_cast<FLOAT*>(&dpi) = dpi_;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // __IPrintPreviewDxgiPackageTarget_FWD_DEFINED__
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = dxgi_preview_target_->DrawPage(job_page, dxgi_surface.Get(), dpi, dpi);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to DrawPage " << std::hex << hr;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrintDocumentSource::ResetDpi(float dpi) {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock lock(*parent_lock_);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (dpi == dpi_)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dpi_ = dpi;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  directx_context_.d2d_context->SetDpi(dpi, dpi);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrintDocumentSource::SetPageCount(size_t page_count) {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(page_count > 0);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock lock(*parent_lock_);
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!page_count_ready_.IsSignaled());
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(pages_.empty() && pages_ready_state_.empty());
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pages_.resize(page_count);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pages_ready_state_.resize(page_count);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < page_count; ++i)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pages_ready_state_[i].reset(new base::ConditionVariable(parent_lock_));
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  page_count_ready_.Signal();
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrintDocumentSource::AddPage(size_t page_number,
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  IStream* metafile_stream) {
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(metafile_stream != NULL);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock lock(*parent_lock_);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(page_count_ready_.IsSignaled());
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(page_number < pages_.size());
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pages_[page_number] = metafile_stream;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pages_ready_state_[page_number]->Signal();
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT PrintDocumentSource::PrintPage(ID2D1PrintControl* print_control,
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       ID2D1GdiMetafile* gdi_metafile,
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       D2D1_SIZE_F page_size) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__ << ", page_size: (" << page_size.width << ", "
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << page_size.height << ")";
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(print_control != NULL);
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(gdi_metafile != NULL);
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // D2D device contexts are stateful, and hence a unique device context must
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be used on each call.
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<ID2D1DeviceContext> d2d_context;
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = directx_context_.d2d_device->CreateDeviceContext(
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &d2d_context);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to CreateDeviceContext " << std::hex << hr;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<ID2D1CommandList> print_command_list;
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = d2d_context->CreateCommandList(&print_command_list);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to CreateCommandList " << std::hex << hr;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  d2d_context->SetTarget(print_command_list.Get());
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  d2d_context->BeginDraw();
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  d2d_context->DrawGdiMetafile(gdi_metafile);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = d2d_context->EndDraw();
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG_IF(ERROR, FAILED(hr)) << "Failed to EndDraw " << std::hex << hr;
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure to always close the command list.
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT close_hr = print_command_list->Close();
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG_IF(ERROR, FAILED(close_hr)) << "Failed to close command list " << std::hex
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  << hr;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SUCCEEDED(hr) && SUCCEEDED(close_hr))
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = print_control->AddPage(print_command_list.Get(), page_size, NULL);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return close_hr;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t PrintDocumentSource::WaitAndGetPageCount() {
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Properly protect the wait/access to the page count.
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock lock(*parent_lock_);
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (aborted_)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(pages_.size() == pages_ready_state_.size());
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!pages_.empty())
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return pages_.size();
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  page_count_ready_.Wait();
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock lock(*parent_lock_);
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!aborted_) {
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(pages_.size() == pages_ready_state_.size());
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return pages_.size();
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A page count of 0 means abort.
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT PrintDocumentSource::WaitAndGetPage(size_t page_number,
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            ID2D1GdiMetafile** gdi_metafile) {
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Properly protect the wait/access to the page data.
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock lock(*parent_lock_);
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we weren't canceled before getting here.
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And the page count should have been received before we get here too.
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (aborted_)
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_FALSE;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We shouldn't be asked for a page until we got the page count.
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(page_count_ready_.IsSignaled());
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(page_number <= pages_ready_state_.size());
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(pages_.size() == pages_ready_state_.size());
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!aborted_ && pages_[page_number].Get() == NULL)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pages_ready_state_[page_number]->Wait();
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we weren't aborted while we waited unlocked.
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (aborted_)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_FALSE;
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(page_number < pages_.size());
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<ID2D1Factory> factory;
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  directx_context_.d2d_device->GetFactory(&factory);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<ID2D1Factory1> factory1;
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = factory.As(&factory1);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to QI for ID2D1Factory1 " << std::hex << hr;
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULARGE_INTEGER result;
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LARGE_INTEGER seek_pos;
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  seek_pos.QuadPart = 0;
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = pages_[page_number]->Seek(seek_pos, STREAM_SEEK_SET, &result);
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to Seek page stream " << std::hex << hr;
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = factory1->CreateGdiMetafile(pages_[page_number].Get(), gdi_metafile);
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to CreateGdiMetafile " << std::hex << hr;
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace metro_driver
528