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