summaryrefslogtreecommitdiffstats
path: root/win8/metro_driver/print_document_source.h
blob: fed333e3706727e17dd5a51e5b85c24879fcf3be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// 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_