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 "SkPicture.h" 9 10 #include "SkImageGenerator.h" 11 #include "SkMathPriv.h" 12 #include "SkPictureCommon.h" 13 #include "SkPictureData.h" 14 #include "SkPicturePlayback.h" 15 #include "SkPicturePriv.h" 16 #include "SkPictureRecord.h" 17 #include "SkPictureRecorder.h" 18 #include "SkSerialProcs.h" 19 #include "SkTo.h" 20 #include <atomic> 21 22 // When we read/write the SkPictInfo via a stream, we have a sentinel byte right after the info. 23 // Note: in the read/write buffer versions, we have a slightly different convention: 24 // We have a sentinel int32_t: 25 // 0 : failure 26 // 1 : PictureData 27 // <0 : -size of the custom data 28 enum { 29 kFailure_TrailingStreamByteAfterPictInfo = 0, // nothing follows 30 kPictureData_TrailingStreamByteAfterPictInfo = 1, // SkPictureData follows 31 kCustom_TrailingStreamByteAfterPictInfo = 2, // -size32 follows 32 }; 33 34 /* SkPicture impl. This handles generic responsibilities like unique IDs and serialization. */ 35 36 SkPicture::SkPicture() { 37 static std::atomic<uint32_t> nextID{1}; 38 do { 39 fUniqueID = nextID.fetch_add(+1, std::memory_order_relaxed); 40 } while (fUniqueID == 0); 41 } 42 43 static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' }; 44 45 SkPictInfo SkPicture::createHeader() const { 46 SkPictInfo info; 47 // Copy magic bytes at the beginning of the header 48 static_assert(sizeof(kMagic) == 8, ""); 49 static_assert(sizeof(kMagic) == sizeof(info.fMagic), ""); 50 memcpy(info.fMagic, kMagic, sizeof(kMagic)); 51 52 // Set picture info after magic bytes in the header 53 info.setVersion(CURRENT_PICTURE_VERSION); 54 info.fCullRect = this->cullRect(); 55 return info; 56 } 57 58 bool SkPicture::IsValidPictInfo(const SkPictInfo& info) { 59 if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) { 60 return false; 61 } 62 if (info.getVersion() < MIN_PICTURE_VERSION || info.getVersion() > CURRENT_PICTURE_VERSION) { 63 return false; 64 } 65 return true; 66 } 67 68 bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) { 69 if (!stream) { 70 return false; 71 } 72 73 SkPictInfo info; 74 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); 75 if (stream->read(&info.fMagic, sizeof(kMagic)) != sizeof(kMagic)) { 76 return false; 77 } 78 79 uint32_t version; 80 if (!stream->readU32(&version)) { return false; } 81 info.setVersion(version); 82 if (!stream->readScalar(&info.fCullRect.fLeft )) { return false; } 83 if (!stream->readScalar(&info.fCullRect.fTop )) { return false; } 84 if (!stream->readScalar(&info.fCullRect.fRight )) { return false; } 85 if (!stream->readScalar(&info.fCullRect.fBottom)) { return false; } 86 if (info.getVersion() < SkReadBuffer::kRemoveHeaderFlags_Version) { 87 if (!stream->readU32(nullptr)) { return false; } 88 } 89 90 if (!IsValidPictInfo(info)) { return false; } 91 92 if (pInfo) { *pInfo = info; } 93 return true; 94 } 95 bool SkPicture_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) { 96 return SkPicture::StreamIsSKP(stream, pInfo); 97 } 98 99 bool SkPicture::BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) { 100 SkPictInfo info; 101 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); 102 if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) { 103 return false; 104 } 105 106 info.setVersion(buffer->readUInt()); 107 buffer->readRect(&info.fCullRect); 108 if (info.getVersion() < SkReadBuffer::kRemoveHeaderFlags_Version) { 109 (void)buffer->readUInt(); // used to be flags 110 } 111 112 if (IsValidPictInfo(info)) { 113 if (pInfo) { *pInfo = info; } 114 return true; 115 } 116 return false; 117 } 118 119 sk_sp<SkPicture> SkPicture::Forwardport(const SkPictInfo& info, 120 const SkPictureData* data, 121 SkReadBuffer* buffer) { 122 if (!data) { 123 return nullptr; 124 } 125 if (!data->opData()) { 126 return nullptr; 127 } 128 SkPicturePlayback playback(data); 129 SkPictureRecorder r; 130 playback.draw(r.beginRecording(info.fCullRect), nullptr/*no callback*/, buffer); 131 return r.finishRecordingAsPicture(); 132 } 133 134 sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialProcs* procs) { 135 return MakeFromStream(stream, procs, nullptr); 136 } 137 138 sk_sp<SkPicture> SkPicture::MakeFromData(const void* data, size_t size, 139 const SkDeserialProcs* procs) { 140 if (!data) { 141 return nullptr; 142 } 143 SkMemoryStream stream(data, size); 144 return MakeFromStream(&stream, procs, nullptr); 145 } 146 147 sk_sp<SkPicture> SkPicture::MakeFromData(const SkData* data, const SkDeserialProcs* procs) { 148 if (!data) { 149 return nullptr; 150 } 151 SkMemoryStream stream(data->data(), data->size()); 152 return MakeFromStream(&stream, procs, nullptr); 153 } 154 155 sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialProcs* procsPtr, 156 SkTypefacePlayback* typefaces) { 157 SkPictInfo info; 158 if (!StreamIsSKP(stream, &info)) { 159 return nullptr; 160 } 161 162 SkDeserialProcs procs; 163 if (procsPtr) { 164 procs = *procsPtr; 165 } 166 167 uint8_t trailingStreamByteAfterPictInfo; 168 if (!stream->readU8(&trailingStreamByteAfterPictInfo)) { return nullptr; } 169 switch (trailingStreamByteAfterPictInfo) { 170 case kPictureData_TrailingStreamByteAfterPictInfo: { 171 std::unique_ptr<SkPictureData> data( 172 SkPictureData::CreateFromStream(stream, info, procs, typefaces)); 173 return Forwardport(info, data.get(), nullptr); 174 } 175 case kCustom_TrailingStreamByteAfterPictInfo: { 176 int32_t ssize; 177 if (!stream->readS32(&ssize) || ssize >= 0 || !procs.fPictureProc) { 178 return nullptr; 179 } 180 size_t size = sk_negate_to_size_t(ssize); 181 auto data = SkData::MakeUninitialized(size); 182 if (stream->read(data->writable_data(), size) != size) { 183 return nullptr; 184 } 185 return procs.fPictureProc(data->data(), size, procs.fPictureCtx); 186 } 187 default: // fall through to error return 188 break; 189 } 190 return nullptr; 191 } 192 193 sk_sp<SkPicture> SkPicturePriv::MakeFromBuffer(SkReadBuffer& buffer) { 194 SkPictInfo info; 195 if (!SkPicture::BufferIsSKP(&buffer, &info)) { 196 return nullptr; 197 } 198 // size should be 0, 1, or negative 199 int32_t ssize = buffer.read32(); 200 if (ssize < 0) { 201 const SkDeserialProcs& procs = buffer.getDeserialProcs(); 202 if (!procs.fPictureProc) { 203 return nullptr; 204 } 205 size_t size = sk_negate_to_size_t(ssize); 206 return procs.fPictureProc(buffer.skip(size), size, procs.fPictureCtx); 207 } 208 if (ssize != 1) { 209 // 1 is the magic 'size' that means SkPictureData follows 210 return nullptr; 211 } 212 std::unique_ptr<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info)); 213 return SkPicture::Forwardport(info, data.get(), &buffer); 214 } 215 216 SkPictureData* SkPicture::backport() const { 217 SkPictInfo info = this->createHeader(); 218 SkPictureRecord rec(SkISize::Make(info.fCullRect.width(), info.fCullRect.height()), 0/*flags*/); 219 rec.beginRecording(); 220 this->playback(&rec); 221 rec.endRecording(); 222 return new SkPictureData(rec, info); 223 } 224 225 void SkPicture::serialize(SkWStream* stream, const SkSerialProcs* procs) const { 226 this->serialize(stream, procs, nullptr); 227 } 228 229 sk_sp<SkData> SkPicture::serialize(const SkSerialProcs* procs) const { 230 SkDynamicMemoryWStream stream; 231 this->serialize(&stream, procs, nullptr); 232 return stream.detachAsData(); 233 } 234 235 static sk_sp<SkData> custom_serialize(const SkPicture* picture, const SkSerialProcs& procs) { 236 if (procs.fPictureProc) { 237 auto data = procs.fPictureProc(const_cast<SkPicture*>(picture), procs.fPictureCtx); 238 if (data) { 239 size_t size = data->size(); 240 if (!SkTFitsIn<int32_t>(size) || size <= 1) { 241 return SkData::MakeEmpty(); 242 } 243 return data; 244 } 245 } 246 return nullptr; 247 } 248 249 static bool write_pad32(SkWStream* stream, const void* data, size_t size) { 250 if (!stream->write(data, size)) { 251 return false; 252 } 253 if (size & 3) { 254 uint32_t zero = 0; 255 return stream->write(&zero, 4 - (size & 3)); 256 } 257 return true; 258 } 259 260 void SkPicture::serialize(SkWStream* stream, const SkSerialProcs* procsPtr, 261 SkRefCntSet* typefaceSet) const { 262 SkSerialProcs procs; 263 if (procsPtr) { 264 procs = *procsPtr; 265 } 266 267 SkPictInfo info = this->createHeader(); 268 stream->write(&info, sizeof(info)); 269 270 if (auto custom = custom_serialize(this, procs)) { 271 int32_t size = SkToS32(custom->size()); 272 if (size == 0) { 273 stream->write8(kFailure_TrailingStreamByteAfterPictInfo); 274 return; 275 } 276 stream->write8(kCustom_TrailingStreamByteAfterPictInfo); 277 stream->write32(-size); // negative for custom format 278 write_pad32(stream, custom->data(), size); 279 return; 280 } 281 282 std::unique_ptr<SkPictureData> data(this->backport()); 283 if (data) { 284 stream->write8(kPictureData_TrailingStreamByteAfterPictInfo); 285 data->serialize(stream, procs, typefaceSet); 286 } else { 287 stream->write8(kFailure_TrailingStreamByteAfterPictInfo); 288 } 289 } 290 291 void SkPicturePriv::Flatten(const sk_sp<const SkPicture> picture, SkWriteBuffer& buffer) { 292 SkPictInfo info = picture->createHeader(); 293 std::unique_ptr<SkPictureData> data(picture->backport()); 294 295 buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic)); 296 buffer.writeUInt(info.getVersion()); 297 buffer.writeRect(info.fCullRect); 298 299 if (auto custom = custom_serialize(picture.get(), buffer.fProcs)) { 300 int32_t size = SkToS32(custom->size()); 301 buffer.write32(-size); // negative for custom format 302 buffer.writePad32(custom->data(), size); 303 return; 304 } 305 306 if (data) { 307 buffer.write32(1); // special size meaning SkPictureData 308 data->flatten(buffer); 309 } else { 310 buffer.write32(0); // signal no content 311 } 312 } 313 314 sk_sp<SkPicture> SkPicture::MakePlaceholder(SkRect cull) { 315 struct Placeholder : public SkPicture { 316 explicit Placeholder(SkRect cull) : fCull(cull) {} 317 318 void playback(SkCanvas*, AbortCallback*) const override { } 319 320 // approximateOpCount() needs to be greater than kMaxPictureOpsToUnrollInsteadOfRef 321 // in SkCanvas.cpp to avoid that unrolling. SK_MaxS32 can't not be big enough! 322 int approximateOpCount() const override { return SK_MaxS32; } 323 size_t approximateBytesUsed() const override { return sizeof(*this); } 324 SkRect cullRect() const override { return fCull; } 325 326 SkRect fCull; 327 }; 328 return sk_make_sp<Placeholder>(cull); 329 } 330