1 /*
2  * Copyright 2007 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkAtomics.h"
9 #include "SkImageGenerator.h"
10 #include "SkMessageBus.h"
11 #include "SkPicture.h"
12 #include "SkPictureData.h"
13 #include "SkPicturePlayback.h"
14 #include "SkPictureRecord.h"
15 #include "SkPictureRecorder.h"
16 
17 #if defined(SK_DISALLOW_CROSSPROCESS_PICTUREIMAGEFILTERS) || \
18     defined(SK_ENABLE_PICTURE_IO_SECURITY_PRECAUTIONS)
19 static bool g_AllPictureIOSecurityPrecautionsEnabled = true;
20 #else
21 static bool g_AllPictureIOSecurityPrecautionsEnabled = false;
22 #endif
23 
24 DECLARE_SKMESSAGEBUS_MESSAGE(SkPicture::DeletionMessage);
25 
26 /* SkPicture impl.  This handles generic responsibilities like unique IDs and serialization. */
27 
SkPicture()28 SkPicture::SkPicture() : fUniqueID(0) {}
29 
~SkPicture()30 SkPicture::~SkPicture() {
31     // TODO: move this to ~SkBigPicture() only?
32 
33     // If the ID is still zero, no one has read it, so no need to send this message.
34     uint32_t id = sk_atomic_load(&fUniqueID, sk_memory_order_relaxed);
35     if (id != 0) {
36         SkPicture::DeletionMessage msg = { (int32_t)id };
37         SkMessageBus<SkPicture::DeletionMessage>::Post(msg);
38     }
39 }
40 
uniqueID() const41 uint32_t SkPicture::uniqueID() const {
42     static uint32_t gNextID = 1;
43     uint32_t id = sk_atomic_load(&fUniqueID, sk_memory_order_relaxed);
44     while (id == 0) {
45         uint32_t next = sk_atomic_fetch_add(&gNextID, 1u);
46         if (sk_atomic_compare_exchange(&fUniqueID, &id, next,
47                                        sk_memory_order_relaxed,
48                                        sk_memory_order_relaxed)) {
49             id = next;
50         } else {
51             // sk_atomic_compare_exchange replaced id with the current value of fUniqueID.
52         }
53     }
54     return id;
55 }
56 
57 static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
58 
createHeader() const59 SkPictInfo SkPicture::createHeader() const {
60     SkPictInfo info;
61     // Copy magic bytes at the beginning of the header
62     static_assert(sizeof(kMagic) == 8, "");
63     static_assert(sizeof(kMagic) == sizeof(info.fMagic), "");
64     memcpy(info.fMagic, kMagic, sizeof(kMagic));
65 
66     // Set picture info after magic bytes in the header
67     info.fVersion = CURRENT_PICTURE_VERSION;
68     info.fCullRect = this->cullRect();
69     info.fFlags = SkPictInfo::kCrossProcess_Flag;
70     // TODO: remove this flag, since we're always float (now)
71     info.fFlags |= SkPictInfo::kScalarIsFloat_Flag;
72 
73     if (8 == sizeof(void*)) {
74         info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
75     }
76     return info;
77 }
78 
IsValidPictInfo(const SkPictInfo & info)79 bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
80     if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
81         return false;
82     }
83     if (info.fVersion < MIN_PICTURE_VERSION || info.fVersion > CURRENT_PICTURE_VERSION) {
84         return false;
85     }
86     return true;
87 }
88 
InternalOnly_StreamIsSKP(SkStream * stream,SkPictInfo * pInfo)89 bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
90     if (!stream) {
91         return false;
92     }
93 
94     SkPictInfo info;
95     SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
96     if (!stream->read(&info.fMagic, sizeof(kMagic))) {
97         return false;
98     }
99 
100     info.fVersion          = stream->readU32();
101     info.fCullRect.fLeft   = stream->readScalar();
102     info.fCullRect.fTop    = stream->readScalar();
103     info.fCullRect.fRight  = stream->readScalar();
104     info.fCullRect.fBottom = stream->readScalar();
105     info.fFlags            = stream->readU32();
106 
107     if (IsValidPictInfo(info)) {
108         if (pInfo) { *pInfo = info; }
109         return true;
110     }
111     return false;
112 }
113 
InternalOnly_BufferIsSKP(SkReadBuffer * buffer,SkPictInfo * pInfo)114 bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) {
115     SkPictInfo info;
116     SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
117     if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) {
118         return false;
119     }
120 
121     info.fVersion = buffer->readUInt();
122     buffer->readRect(&info.fCullRect);
123     info.fFlags = buffer->readUInt();
124 
125     if (IsValidPictInfo(info)) {
126         if (pInfo) { *pInfo = info; }
127         return true;
128     }
129     return false;
130 }
131 
Forwardport(const SkPictInfo & info,const SkPictureData * data)132 SkPicture* SkPicture::Forwardport(const SkPictInfo& info, const SkPictureData* data) {
133     if (!data) {
134         return nullptr;
135     }
136     SkPicturePlayback playback(data);
137     SkPictureRecorder r;
138     playback.draw(r.beginRecording(info.fCullRect), nullptr/*no callback*/);
139     return r.endRecording();
140 }
141 
default_install(const void * src,size_t length,SkBitmap * dst)142 static bool default_install(const void* src, size_t length, SkBitmap* dst) {
143     SkAutoTUnref<SkData> encoded(SkData::NewWithCopy(src, length));
144     return encoded && SkDEPRECATED_InstallDiscardablePixelRef(
145             SkImageGenerator::NewFromEncoded(encoded), dst);
146 }
147 
CreateFromStream(SkStream * stream)148 SkPicture* SkPicture::CreateFromStream(SkStream* stream) {
149     return CreateFromStream(stream, &default_install, nullptr);
150 }
151 
CreateFromStream(SkStream * stream,InstallPixelRefProc proc)152 SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
153     return CreateFromStream(stream, proc, nullptr);
154 }
155 
CreateFromStream(SkStream * stream,InstallPixelRefProc proc,SkTypefacePlayback * typefaces)156 SkPicture* SkPicture::CreateFromStream(SkStream* stream,
157                                        InstallPixelRefProc proc,
158                                        SkTypefacePlayback* typefaces) {
159     SkPictInfo info;
160     if (!InternalOnly_StreamIsSKP(stream, &info) || !stream->readBool()) {
161         return nullptr;
162     }
163     SkAutoTDelete<SkPictureData> data(
164             SkPictureData::CreateFromStream(stream, info, proc, typefaces));
165     return Forwardport(info, data);
166 }
167 
CreateFromBuffer(SkReadBuffer & buffer)168 SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
169     SkPictInfo info;
170     if (!InternalOnly_BufferIsSKP(&buffer, &info) || !buffer.readBool()) {
171         return nullptr;
172     }
173     SkAutoTDelete<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info));
174     return Forwardport(info, data);
175 }
176 
backport() const177 SkPictureData* SkPicture::backport() const {
178     SkPictInfo info = this->createHeader();
179     SkPictureRecord rec(SkISize::Make(info.fCullRect.width(), info.fCullRect.height()), 0/*flags*/);
180     rec.beginRecording();
181         this->playback(&rec);
182     rec.endRecording();
183     return new SkPictureData(rec, info, false /*deep copy ops?*/);
184 }
185 
serialize(SkWStream * stream,SkPixelSerializer * pixelSerializer) const186 void SkPicture::serialize(SkWStream* stream, SkPixelSerializer* pixelSerializer) const {
187     this->serialize(stream, pixelSerializer, nullptr);
188 }
189 
serialize(SkWStream * stream,SkPixelSerializer * pixelSerializer,SkRefCntSet * typefaceSet) const190 void SkPicture::serialize(SkWStream* stream,
191                           SkPixelSerializer* pixelSerializer,
192                           SkRefCntSet* typefaceSet) const {
193     SkPictInfo info = this->createHeader();
194     SkAutoTDelete<SkPictureData> data(this->backport());
195 
196     stream->write(&info, sizeof(info));
197     if (data) {
198         stream->writeBool(true);
199         data->serialize(stream, pixelSerializer, typefaceSet);
200     } else {
201         stream->writeBool(false);
202     }
203 }
204 
flatten(SkWriteBuffer & buffer) const205 void SkPicture::flatten(SkWriteBuffer& buffer) const {
206     SkPictInfo info = this->createHeader();
207     SkAutoTDelete<SkPictureData> data(this->backport());
208 
209     buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
210     buffer.writeUInt(info.fVersion);
211     buffer.writeRect(info.fCullRect);
212     buffer.writeUInt(info.fFlags);
213     if (data) {
214         buffer.writeBool(true);
215         data->flatten(buffer);
216     } else {
217         buffer.writeBool(false);
218     }
219 }
220 
suitableForGpuRasterization(GrContext *,const char ** whyNot) const221 bool SkPicture::suitableForGpuRasterization(GrContext*, const char** whyNot) const {
222     if (this->numSlowPaths() > 5) {
223         if (whyNot) { *whyNot = "Too many slow paths (either concave or dashed)."; }
224         return false;
225     }
226     return true;
227 }
228 
229 // Global setting to disable security precautions for serialization.
SetPictureIOSecurityPrecautionsEnabled_Dangerous(bool set)230 void SkPicture::SetPictureIOSecurityPrecautionsEnabled_Dangerous(bool set) {
231     g_AllPictureIOSecurityPrecautionsEnabled = set;
232 }
233 
PictureIOSecurityPrecautionsEnabled()234 bool SkPicture::PictureIOSecurityPrecautionsEnabled() {
235     return g_AllPictureIOSecurityPrecautionsEnabled;
236 }
237