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