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