// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_METRO_DRIVER_PRINT_DOCUMENT_SOURCE_H_
#define CHROME_BROWSER_UI_METRO_DRIVER_PRINT_DOCUMENT_SOURCE_H_
#include <documentsource.h>
#include <printpreview.h>
#include <windows.graphics.printing.h>
#include <vector>
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/waitable_event.h"
#include "win8/metro_driver/winrt_utils.h"
// Hack to be removed once we don't need to build with an SDK earlier than
// 8441 where the name of the interface has been changed.
// TODO(mad): remove once we don't run mixed SDK/OS anymore.
#ifndef __IPrintPreviewDxgiPackageTarget_FWD_DEFINED__
typedef IPrintPreviewDXGIPackageTarget IPrintPreviewDxgiPackageTarget;
#endif
namespace base {
class Lock;
}; // namespace base
namespace metro_driver {
// This class is given to Metro as a source for print documents.
// The methodless IPrintDocumentSource interface is used to identify it as such.
// Then, the other interfaces are used to generate preview and print documents.
// It also exposes a few methods for the print handler to control the document.
class PrintDocumentSource
: public mswr::RuntimeClass<
mswr::RuntimeClassFlags<mswr::WinRtClassicComMix>,
wingfx::Printing::IPrintDocumentSource,
IPrintDocumentPageSource,
IPrintPreviewPageCollection> {
public:
// A set of interfaces for the DirectX context that our parent owns
// and that don't need to change from document to document.
struct DirectXContext {
DirectXContext() {}
DirectXContext(ID3D11Device1* device_3d,
ID2D1Factory1* factory_2d,
ID2D1Device* device_2d,
ID2D1DeviceContext* context_2d,
IWICImagingFactory2* factory_wic)
: d3d_device(device_3d),
d2d_factory(factory_2d),
d2d_device(device_2d),
d2d_context(context_2d),
wic_factory(factory_wic) {
}
DirectXContext(const DirectXContext& other)
: d3d_device(other.d3d_device),
d2d_factory(other.d2d_factory),
d2d_device(other.d2d_device),
d2d_context(other.d2d_context),
wic_factory(other.wic_factory) {
}
mswr::ComPtr<ID3D11Device1> d3d_device;
mswr::ComPtr<ID2D1Factory1> d2d_factory;
mswr::ComPtr<ID2D1Device> d2d_device;
mswr::ComPtr<ID2D1DeviceContext> d2d_context;
mswr::ComPtr<IWICImagingFactory2> wic_factory;
};
// Construction / Initialization.
explicit PrintDocumentSource();
HRESULT RuntimeClassInitialize(const DirectXContext& directx_context,
base::Lock* parent_lock);
// Aborts any pending asynchronous operation.
void Abort();
// classic COM interface IPrintDocumentPageSource methods
STDMETHOD(GetPreviewPageCollection) (
IPrintDocumentPackageTarget* package_target,
IPrintPreviewPageCollection** page_collection);
STDMETHOD(MakeDocument)(IInspectable* options,
IPrintDocumentPackageTarget* package_target);
// classic COM interface IPrintPreviewPageCollection methods
STDMETHOD(Paginate)(uint32 page, IInspectable* options);
STDMETHOD(MakePage)(uint32 desired_page, float width, float height);
// If the screen DPI changes, we must be warned here.
void ResetDpi(float dpi);
// When the page count is known, this is called and we can setup our data.
void SetPageCount(size_t page_count);
// Every time a page is ready, this is called and we can read the data if
// we were waiting for it, or store it for later use.
void AddPage(size_t page_number, IStream* metafile_stream);
private:
// Print the page given in the metafile stream to the given print control.
HRESULT PrintPage(ID2D1PrintControl* print_control,
ID2D1GdiMetafile* metafile_stream,
D2D1_SIZE_F pageSize);
// Helper function to wait for the page count to be ready.
// Returns 0 when aborted.
size_t WaitAndGetPageCount();
// Helper function to wait for a given page to be ready.
// Returns S_FALSE when aborted.
HRESULT WaitAndGetPage(size_t page_number,
ID2D1GdiMetafile** metafile_stream);
DirectXContext directx_context_;
// Once page data is available, it's added to this vector.
std::vector<mswr::ComPtr<IStream>> pages_;
// When page count is set, the size of this vector is set to that number.
// Then, every time page data is added to pages_, the associated condition
// variable in this vector is signaled. This is only filled when we receive
// the page count, so we must wait on page_count_ready_ before accessing
// the content of this vector.
std::vector<scoped_ptr<base::ConditionVariable> > pages_ready_state_;
// This event is signaled when we receive a page count from Chrome. We should
// not receive any page data before the count, so we can check this event
// while waiting for pages too, in case we ask for page data before we got
// the count, so before we properly initialized pages_ready_state_.
base::WaitableEvent page_count_ready_;
// The preview target interface set from within GetPreviewPageCollection
// but used from within MakePage.
mswr::ComPtr<IPrintPreviewDxgiPackageTarget> dxgi_preview_target_;
// Our parent's lock (to make sure it is initialized and destroyed early
// enough), which we use to protect access to our data members.
base::Lock* parent_lock_;
// The width/height requested in Paginate and used in MakePage.
// TODO(mad): Height is currently not used, and width is only used for
// scaling. We need to add a way to specify width and height when we request
// pages from Chrome.
float height_;
float width_;
// The DPI is set by Windows and we need to give it to DirectX.
float dpi_;
// A flag identiying that we have been aborted. Needed to properly handle
// asynchronous callbacks.
bool aborted_;
// TODO(mad): remove once we don't run mixed SDK/OS anymore.
bool using_old_preview_interface_;
};
} // namespace metro_driver
#endif // CHROME_BROWSER_UI_METRO_DRIVER_PRINT_DOCUMENT_SOURCE_H_