1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/paint_preview/common/serial_utils.h"
6
7 #include "components/paint_preview/common/subset_font.h"
8 #include "third_party/skia/include/core/SkCanvas.h"
9 #include "third_party/skia/include/core/SkPictureRecorder.h"
10
11 namespace paint_preview {
12
13 namespace {
14
15 // Supported by MSVC, g++, and clang++. Ensures no gaps in packing.
16 #pragma pack(push, 1)
17 struct SerializedRectData {
18 uint32_t content_id;
19 int64_t x;
20 int64_t y;
21 int64_t width;
22 int64_t height;
23 };
24 #pragma pack(pop)
25
26 // Serializes a SkPicture representing a subframe as a custom data placeholder.
SerializeSubframe(SkPicture * picture,void * ctx)27 sk_sp<SkData> SerializeSubframe(SkPicture* picture, void* ctx) {
28 const PictureSerializationContext* context =
29 reinterpret_cast<PictureSerializationContext*>(ctx);
30 SerializedRectData rect_data = {
31 picture->uniqueID(), picture->cullRect().x(), picture->cullRect().y(),
32 picture->cullRect().width(), picture->cullRect().height()};
33
34 if (context->count(picture->uniqueID()))
35 return SkData::MakeWithCopy(&rect_data, sizeof(rect_data));
36 // Defers picture serialization behavior to Skia.
37 return nullptr;
38 }
39
40 // De-duplicates and subsets used typefaces and discards any unused typefaces.
SerializeTypeface(SkTypeface * typeface,void * ctx)41 sk_sp<SkData> SerializeTypeface(SkTypeface* typeface, void* ctx) {
42 TypefaceSerializationContext* context =
43 reinterpret_cast<TypefaceSerializationContext*>(ctx);
44
45 if (context->finished.count(typeface->uniqueID()))
46 return typeface->serialize(SkTypeface::SerializeBehavior::kDontIncludeData);
47 context->finished.insert(typeface->uniqueID());
48
49 auto usage_it = context->usage->find(typeface->uniqueID());
50 if (usage_it == context->usage->end())
51 return typeface->serialize(SkTypeface::SerializeBehavior::kDontIncludeData);
52
53 auto subset_data = SubsetFont(typeface, *usage_it->second);
54 // This will fail if the font cannot be subsetted properly. In such cases
55 // all typeface data should be added for portability.
56 if (!subset_data)
57 return typeface->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
58 return subset_data;
59 }
60
61 // Deserializies a clip rect for a subframe within the main SkPicture. These
62 // represent subframes and require special decoding as they are custom data
63 // rather than a valid SkPicture.
64 // Precondition: the version of the SkPicture should be checked prior to
65 // invocation to ensure deserialization will succeed.
DeserializeSubframe(const void * data,size_t length,void * ctx)66 sk_sp<SkPicture> DeserializeSubframe(const void* data,
67 size_t length,
68 void* ctx) {
69 SerializedRectData rect_data;
70 if (length < sizeof(rect_data))
71 return MakeEmptyPicture();
72 memcpy(&rect_data, data, sizeof(rect_data));
73 auto* context = reinterpret_cast<DeserializationContext*>(ctx);
74 context->insert(
75 {rect_data.content_id,
76 gfx::Rect(rect_data.x, rect_data.y, rect_data.width, rect_data.height)});
77 return MakeEmptyPicture();
78 }
79
80 } // namespace
81
TypefaceSerializationContext(TypefaceUsageMap * usage)82 TypefaceSerializationContext::TypefaceSerializationContext(
83 TypefaceUsageMap* usage)
84 : usage(usage) {}
85 TypefaceSerializationContext::~TypefaceSerializationContext() = default;
86
MakeEmptyPicture()87 sk_sp<SkPicture> MakeEmptyPicture() {
88 // Effectively a no-op.
89 SkPictureRecorder rec;
90 rec.beginRecording(1, 1);
91 return rec.finishRecordingAsPicture();
92 }
93
MakeSerialProcs(PictureSerializationContext * picture_ctx,TypefaceSerializationContext * typeface_ctx)94 SkSerialProcs MakeSerialProcs(PictureSerializationContext* picture_ctx,
95 TypefaceSerializationContext* typeface_ctx) {
96 SkSerialProcs procs;
97 procs.fPictureProc = SerializeSubframe;
98 procs.fPictureCtx = picture_ctx;
99 procs.fTypefaceProc = SerializeTypeface;
100 procs.fTypefaceCtx = typeface_ctx;
101 // TODO(crbug/1008875): find a consistently smaller and low-memory overhead
102 // image downsampling method to use as fImageProc.
103 return procs;
104 }
105
MakeDeserialProcs(DeserializationContext * ctx)106 SkDeserialProcs MakeDeserialProcs(DeserializationContext* ctx) {
107 SkDeserialProcs procs;
108 procs.fPictureProc = DeserializeSubframe;
109 procs.fPictureCtx = ctx;
110 return procs;
111 }
112
113 } // namespace paint_preview
114