Home | History | Annotate | Download | only in core
      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