File: print_compositor_impl.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (335 lines) | stat: -rw-r--r-- 13,002 bytes parent folder | download | duplicates (6)
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_SERVICES_PRINT_COMPOSITOR_PRINT_COMPOSITOR_IMPL_H_
#define COMPONENTS_SERVICES_PRINT_COMPOSITOR_PRINT_COMPOSITOR_IMPL_H_

#include <map>
#include <memory>
#include <string>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/containers/span.h"
#include "base/gtest_prod_util.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_refptr.h"
#include "build/build_config.h"
#include "components/enterprise/buildflags/buildflags.h"
#include "components/services/print_compositor/public/cpp/print_service_mojo_types.h"
#include "components/services/print_compositor/public/mojom/print_compositor.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "printing/buildflags/buildflags.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "ui/accessibility/ax_tree_update.h"

#if BUILDFLAG(ENTERPRISE_WATERMARK)
#include "components/enterprise/watermarking/mojom/watermark.mojom-forward.h"  // nogncheck
#endif

class SkDocument;
struct SkDocumentPage;

namespace base {
class SingleThreadTaskRunner;
}

namespace discardable_memory {
class ClientDiscardableSharedMemoryManager;
}

namespace printing {

#if BUILDFLAG(IS_WIN)
class ScopedXPSInitializer;
#endif

class PrintCompositorImpl : public mojom::PrintCompositor {
 public:
  // Creates an instance with an optional Mojo receiver (may be null) and
  // optional initialization of the runtime environment necessary for
  // compositing operations. `io_task_runner` is used for shared memory
  // management, if and only if there is a receiver, which may not be the case
  // in unit tests. In practice, `initialize_environment` is only false in unit
  // tests.
  PrintCompositorImpl(
      mojo::PendingReceiver<mojom::PrintCompositor> receiver,
      bool initialize_environment,
      scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);

  PrintCompositorImpl(const PrintCompositorImpl&) = delete;
  PrintCompositorImpl& operator=(const PrintCompositorImpl&) = delete;

  ~PrintCompositorImpl() override;

  // mojom::PrintCompositor
  void NotifyUnavailableSubframe(uint64_t frame_guid) override;
  void AddSubframeContent(
      uint64_t frame_guid,
      base::ReadOnlySharedMemoryRegion serialized_content,
      const ContentToFrameMap& subframe_content_map) override;
  void SetAccessibilityTree(
      const ui::AXTreeUpdate& accessibility_tree) override;
  void CompositePage(
      uint64_t frame_guid,
      base::ReadOnlySharedMemoryRegion serialized_content,
      const ContentToFrameMap& subframe_content_map,
      mojom::PrintCompositor::CompositePageCallback callback) override;
  void CompositeDocument(
      uint64_t frame_guid,
      base::ReadOnlySharedMemoryRegion serialized_content,
      const ContentToFrameMap& subframe_content_map,
      mojom::PrintCompositor::DocumentType document_type,
      mojom::PrintCompositor::CompositeDocumentCallback callback) override;
  void PrepareToCompositeDocument(
      mojom::PrintCompositor::DocumentType document_type,
      mojom::PrintCompositor::PrepareToCompositeDocumentCallback callback)
      override;
  void FinishDocumentComposition(
      uint32_t page_count,
      mojom::PrintCompositor::FinishDocumentCompositionCallback callback)
      override;
  void SetWebContentsURL(const GURL& url) override;
  void SetUserAgent(const std::string& user_agent) override;
  void SetGenerateDocumentOutline(
      mojom::GenerateDocumentOutline generate_document_outline) override;
  void SetTitle(const std::string& title) override;
#if BUILDFLAG(ENTERPRISE_WATERMARK)
  void SetWatermarkBlock(
      watermark::mojom::WatermarkBlockPtr watermark_block) override;
#endif

 protected:
  // This is the uniform underlying type for both
  // mojom::PrintCompositor::CompositePageCallback and
  // mojom::PrintCompositor::CompositeDocumentCallback.
  using CompositePagesCallback =
      base::OnceCallback<void(PrintCompositor::Status,
                              base::ReadOnlySharedMemoryRegion)>;

  using PrepareForDocumentCompositionCallback =
      base::OnceCallback<void(PrintCompositor::Status)>;
  using FinishDocumentCompositionCallback =
      base::OnceCallback<void(PrintCompositor::Status,
                              base::ReadOnlySharedMemoryRegion)>;

  // The core function for content composition and conversion to a PDF file,
  // and possibly also into a full document PDF/XPS file.
  // Make this function virtual so tests can override it.
  virtual mojom::PrintCompositor::Status CompositePages(
      base::span<const uint8_t> serialized_content,
      const ContentToFrameMap& subframe_content_map,
      base::ReadOnlySharedMemoryRegion* region,
      mojom::PrintCompositor::DocumentType document_type);

  // Make these functions virtual so tests can override them.
  virtual void DrawPage(SkDocument* doc, const SkDocumentPage& page);
  virtual void FulfillRequest(
      base::span<const uint8_t> serialized_content,
      const ContentToFrameMap& subframe_content_map,
      mojom::PrintCompositor::DocumentType document_type,
      CompositePagesCallback callback);
  virtual void FinishDocumentRequest(
      FinishDocumentCompositionCallback callback);

#if BUILDFLAG(ENTERPRISE_WATERMARK)
  // Accessor for watermark block for tests
  const watermark::mojom::WatermarkBlockPtr& watermark_block_for_testing()
      const;
#endif

 private:
  FRIEND_TEST_ALL_PREFIXES(PrintCompositorImplTest, IsReadyToComposite);
  FRIEND_TEST_ALL_PREFIXES(PrintCompositorImplTest, MultiLayerDependency);
  FRIEND_TEST_ALL_PREFIXES(PrintCompositorImplTest, DependencyLoop);

  friend class MockCompletionPrintCompositorImpl;

  // The map needed during content deserialization. It stores the mapping
  // between content id and its actual content.
  using PictureDeserializationContext =
      base::flat_map<uint32_t, sk_sp<SkPicture>>;
  using TypefaceDeserializationContext =
      base::flat_map<uint32_t, sk_sp<SkTypeface>>;
  using ImageDeserializationContext = base::flat_map<uint32_t, sk_sp<SkImage>>;

  // Base structure to store a frame's content and its subframe
  // content information.
  struct FrameContentInfo {
    FrameContentInfo(base::span<const uint8_t> content,
                     const ContentToFrameMap& map);
    FrameContentInfo();
    ~FrameContentInfo();

    // Serialized SkPicture content of this frame.
    std::vector<uint8_t> serialized_content;

    // Frame content after composition with subframe content.
    sk_sp<SkPicture> content;

    // Subframe content id and its corresponding frame guid.
    ContentToFrameMap subframe_content_map;

    // Typefaces used within scope of this frame.
    TypefaceDeserializationContext typefaces;

    // Images used within scope of this frame.
    ImageDeserializationContext images;
  };

  // Other than content, it also stores the status during frame composition.
  struct FrameInfo : public FrameContentInfo {
    using FrameContentInfo::FrameContentInfo;

    // The following fields are used for storing composition status.
    // Set to true when this frame's |serialized_content| is composed with
    // subframe content and the final result is stored in |content|.
    bool composited = false;
  };

  // Stores the mapping between frame's global unique ids and their
  // corresponding frame information.
  using FrameMap = base::flat_map<uint64_t, std::unique_ptr<FrameInfo>>;

  // Stores the page or document's request information.
  struct RequestInfo : public FrameContentInfo {
    RequestInfo(base::span<const uint8_t> content,
                const ContentToFrameMap& content_info,
                const base::flat_set<uint64_t>& pending_subframes,
                mojom::PrintCompositor::DocumentType document_type,
                CompositePagesCallback callback);
    ~RequestInfo();

    // All pending frame ids whose content is not available but needed
    // for composition.
    base::flat_set<uint64_t> pending_subframes;

    mojom::PrintCompositor::DocumentType document_type;
    CompositePagesCallback callback;
  };

  // Stores the concurrent document composition information.
  //
  // While PrintCompositorImpl is creating a document for every page it is
  // compositing, it can reuse the same page info to concurrently create the
  // full document with all pages. Only used when PrepareToCompositeDocument()
  // gets called.
  struct DocumentInfo {
    explicit DocumentInfo(mojom::PrintCompositor::DocumentType document_type);
    ~DocumentInfo();

    SkDynamicMemoryWStream compositor_stream;
    sk_sp<SkDocument> doc;
    mojom::PrintCompositor::DocumentType document_type;
    uint32_t pages_written = 0;
    uint32_t page_count = 0;
    FinishDocumentCompositionCallback callback;
  };

  // Check whether any request is waiting for the specific subframe, if so,
  // update its dependecy with the subframe's pending child frames.
  void UpdateRequestsWithSubframeInfo(
      uint64_t frame_guid,
      const std::vector<uint64_t>& pending_subframes);

  // Check whether the frame with a list of subframe content is ready to
  // composite. If not, return all unavailable frames' ids in
  // |pending_subframes|.
  bool IsReadyToComposite(uint64_t frame_guid,
                          const ContentToFrameMap& subframe_content_map,
                          base::flat_set<uint64_t>* pending_subframes) const;

  // Recursively check all the subframes in |subframe_content_map| and put those
  // not ready in |pending_subframes|.
  void CheckFramesForReadiness(const ContentToFrameMap& subframe_content_map,
                               base::flat_set<uint64_t>* pending_subframes,
                               base::flat_set<uint64_t>* visited) const;

  // The internal implementation for handling page and documentation composition
  // requests.
  void HandleCompositionRequest(
      uint64_t frame_guid,
      base::ReadOnlySharedMemoryRegion serialized_content,
      const ContentToFrameMap& subframe_content_ids,
      mojom::PrintCompositor::DocumentType document_type,
      CompositePagesCallback callback);
  void HandleDocumentCompletionRequest();

  // Composite the content of a subframe.
  void CompositeSubframe(FrameInfo* frame_info);

  PictureDeserializationContext GetPictureDeserializationContext(
      const ContentToFrameMap& subframe_content_map);

  mojo::Receiver<mojom::PrintCompositor> receiver_{this};

#if BUILDFLAG(IS_WIN)
  std::unique_ptr<ScopedXPSInitializer> xps_initializer_;
#endif

  const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
  scoped_refptr<discardable_memory::ClientDiscardableSharedMemoryManager>
      discardable_shared_memory_manager_;

  // The creator of this service.
  // Currently contains the service creator's user agent string if given,
  // otherwise just use string "Chromium".
  std::string creator_ = "Chromium";

  // Keep track of all frames' information indexed by frame id.
  FrameMap frame_info_map_;

  // Context for dealing with all typefaces encountered across multiple pages.
  TypefaceDeserializationContext typefaces_;

  // Context for dealing with all images encountered across multiple pages.
  ImageDeserializationContext images_;

  std::vector<std::unique_ptr<RequestInfo>> requests_;
  std::unique_ptr<DocumentInfo> doc_info_;

  // If present, the accessibility tree for the document needed to
  // export a tagged (accessible) PDF.
  ui::AXTreeUpdate accessibility_tree_;

  // How (or if) to generate a document outline.
  mojom::GenerateDocumentOutline generate_document_outline_ =
      mojom::GenerateDocumentOutline::kNone;

  // The title of the document.
  std::string title_;

#if BUILDFLAG(ENTERPRISE_WATERMARK)
  // The watermark block. The special value `nullptr` indicates that there is no
  // watermark.
  watermark::mojom::WatermarkBlockPtr watermark_block_;
#endif
};

#if BUILDFLAG(ENTERPRISE_WATERMARK)
// Draw the watermark specified by `watermark_block` using the provided canvas
// and its size. Exposed for testing.
void DrawEnterpriseWatermark(
    SkCanvas* canvas,
    SkSize size,
    const watermark::mojom::WatermarkBlockPtr& watermark_block);

// Helper function to draw the watermark block without checking for feature
// flags. Exposed for testing.
void DrawWatermarkBlockForTesting(
    SkCanvas* canvas,
    SkSize size,
    const watermark::mojom::WatermarkBlockPtr& watermark_block);
#endif

}  // namespace printing

#endif  // COMPONENTS_SERVICES_PRINT_COMPOSITOR_PRINT_COMPOSITOR_IMPL_H_