diff options
Diffstat (limited to 'gfx/skia/skia/src/core/SkPicture.cpp')
-rw-r--r-- | gfx/skia/skia/src/core/SkPicture.cpp | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/core/SkPicture.cpp b/gfx/skia/skia/src/core/SkPicture.cpp new file mode 100644 index 0000000000..609943748d --- /dev/null +++ b/gfx/skia/skia/src/core/SkPicture.cpp @@ -0,0 +1,352 @@ +/* + * Copyright 2007 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkPicture.h" + +#include "include/core/SkImageGenerator.h" +#include "include/core/SkPictureRecorder.h" +#include "include/core/SkSerialProcs.h" +#include "include/private/base/SkTo.h" +#include "src/base/SkMathPriv.h" +#include "src/core/SkCanvasPriv.h" +#include "src/core/SkPictureData.h" +#include "src/core/SkPicturePlayback.h" +#include "src/core/SkPicturePriv.h" +#include "src/core/SkPictureRecord.h" +#include "src/core/SkResourceCache.h" +#include "src/core/SkStreamPriv.h" + +#include <atomic> + +#if defined(SK_GANESH) +#include "include/private/chromium/Slug.h" +#endif + +// When we read/write the SkPictInfo via a stream, we have a sentinel byte right after the info. +// Note: in the read/write buffer versions, we have a slightly different convention: +// We have a sentinel int32_t: +// 0 : failure +// 1 : PictureData +// <0 : -size of the custom data +enum { + kFailure_TrailingStreamByteAfterPictInfo = 0, // nothing follows + kPictureData_TrailingStreamByteAfterPictInfo = 1, // SkPictureData follows + kCustom_TrailingStreamByteAfterPictInfo = 2, // -size32 follows +}; + +/* SkPicture impl. This handles generic responsibilities like unique IDs and serialization. */ + +SkPicture::SkPicture() { + static std::atomic<uint32_t> nextID{1}; + do { + fUniqueID = nextID.fetch_add(+1, std::memory_order_relaxed); + } while (fUniqueID == 0); +} + +SkPicture::~SkPicture() { + if (fAddedToCache.load()) { + SkResourceCache::PostPurgeSharedID(SkPicturePriv::MakeSharedID(fUniqueID)); + } +} + +static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' }; + +SkPictInfo SkPicture::createHeader() const { + SkPictInfo info; + // Copy magic bytes at the beginning of the header + static_assert(sizeof(kMagic) == 8, ""); + static_assert(sizeof(kMagic) == sizeof(info.fMagic), ""); + memcpy(info.fMagic, kMagic, sizeof(kMagic)); + + // Set picture info after magic bytes in the header + info.setVersion(SkPicturePriv::kCurrent_Version); + info.fCullRect = this->cullRect(); + return info; +} + +bool SkPicture::IsValidPictInfo(const SkPictInfo& info) { + if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) { + return false; + } + if (info.getVersion() < SkPicturePriv::kMin_Version || + info.getVersion() > SkPicturePriv::kCurrent_Version) { + return false; + } + return true; +} + +bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) { + if (!stream) { + return false; + } + + SkPictInfo info; + SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); + if (stream->read(&info.fMagic, sizeof(kMagic)) != sizeof(kMagic)) { + return false; + } + + uint32_t version; + if (!stream->readU32(&version)) { return false; } + info.setVersion(version); + if (!stream->readScalar(&info.fCullRect.fLeft )) { return false; } + if (!stream->readScalar(&info.fCullRect.fTop )) { return false; } + if (!stream->readScalar(&info.fCullRect.fRight )) { return false; } + if (!stream->readScalar(&info.fCullRect.fBottom)) { return false; } + + if (pInfo) { + *pInfo = info; + } + return IsValidPictInfo(info); +} + +bool SkPicture_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) { + return SkPicture::StreamIsSKP(stream, pInfo); +} + +bool SkPicture::BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) { + SkPictInfo info; + SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); + if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) { + return false; + } + + info.setVersion(buffer->readUInt()); + buffer->readRect(&info.fCullRect); + + if (IsValidPictInfo(info)) { + if (pInfo) { *pInfo = info; } + return true; + } + return false; +} + +sk_sp<SkPicture> SkPicture::Forwardport(const SkPictInfo& info, + const SkPictureData* data, + SkReadBuffer* buffer) { + if (!data) { + return nullptr; + } + if (!data->opData()) { + return nullptr; + } + SkPicturePlayback playback(data); + SkPictureRecorder r; + playback.draw(r.beginRecording(info.fCullRect), nullptr/*no callback*/, buffer); + return r.finishRecordingAsPicture(); +} + +static const int kNestedSKPLimit = 100; // Arbitrarily set + +sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialProcs* procs) { + return MakeFromStreamPriv(stream, procs, nullptr, kNestedSKPLimit); +} + +sk_sp<SkPicture> SkPicture::MakeFromData(const void* data, size_t size, + const SkDeserialProcs* procs) { + if (!data) { + return nullptr; + } + SkMemoryStream stream(data, size); + return MakeFromStreamPriv(&stream, procs, nullptr, kNestedSKPLimit); +} + +sk_sp<SkPicture> SkPicture::MakeFromData(const SkData* data, const SkDeserialProcs* procs) { + if (!data) { + return nullptr; + } + SkMemoryStream stream(data->data(), data->size()); + return MakeFromStreamPriv(&stream, procs, nullptr, kNestedSKPLimit); +} + +sk_sp<SkPicture> SkPicture::MakeFromStreamPriv(SkStream* stream, const SkDeserialProcs* procsPtr, + SkTypefacePlayback* typefaces, int recursionLimit) { + if (recursionLimit <= 0) { + return nullptr; + } + SkPictInfo info; + if (!StreamIsSKP(stream, &info)) { + return nullptr; + } + + SkDeserialProcs procs; + if (procsPtr) { + procs = *procsPtr; + } + + uint8_t trailingStreamByteAfterPictInfo; + if (!stream->readU8(&trailingStreamByteAfterPictInfo)) { return nullptr; } + switch (trailingStreamByteAfterPictInfo) { + case kPictureData_TrailingStreamByteAfterPictInfo: { + std::unique_ptr<SkPictureData> data( + SkPictureData::CreateFromStream(stream, info, procs, typefaces, + recursionLimit)); + return Forwardport(info, data.get(), nullptr); + } + case kCustom_TrailingStreamByteAfterPictInfo: { + int32_t ssize; + if (!stream->readS32(&ssize) || ssize >= 0 || !procs.fPictureProc) { + return nullptr; + } + size_t size = sk_negate_to_size_t(ssize); + if (StreamRemainingLengthIsBelow(stream, size)) { + return nullptr; + } + auto data = SkData::MakeUninitialized(size); + if (stream->read(data->writable_data(), size) != size) { + return nullptr; + } + return procs.fPictureProc(data->data(), size, procs.fPictureCtx); + } + default: // fall out to error return + break; + } + return nullptr; +} + +sk_sp<SkPicture> SkPicturePriv::MakeFromBuffer(SkReadBuffer& buffer) { + SkPictInfo info; + if (!SkPicture::BufferIsSKP(&buffer, &info)) { + return nullptr; + } + // size should be 0, 1, or negative + int32_t ssize = buffer.read32(); + if (ssize < 0) { + const SkDeserialProcs& procs = buffer.getDeserialProcs(); + if (!procs.fPictureProc) { + return nullptr; + } + size_t size = sk_negate_to_size_t(ssize); + return procs.fPictureProc(buffer.skip(size), size, procs.fPictureCtx); + } + if (ssize != 1) { + // 1 is the magic 'size' that means SkPictureData follows + return nullptr; + } + std::unique_ptr<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info)); + return SkPicture::Forwardport(info, data.get(), &buffer); +} + +SkPictureData* SkPicture::backport() const { + SkPictInfo info = this->createHeader(); + SkPictureRecord rec(info.fCullRect.roundOut(), 0/*flags*/); + rec.beginRecording(); + this->playback(&rec); + rec.endRecording(); + return new SkPictureData(rec, info); +} + +void SkPicture::serialize(SkWStream* stream, const SkSerialProcs* procs) const { + this->serialize(stream, procs, nullptr); +} + +sk_sp<SkData> SkPicture::serialize(const SkSerialProcs* procs) const { + SkDynamicMemoryWStream stream; + this->serialize(&stream, procs, nullptr); + return stream.detachAsData(); +} + +static sk_sp<SkData> custom_serialize(const SkPicture* picture, const SkSerialProcs& procs) { + if (procs.fPictureProc) { + auto data = procs.fPictureProc(const_cast<SkPicture*>(picture), procs.fPictureCtx); + if (data) { + size_t size = data->size(); + if (!SkTFitsIn<int32_t>(size) || size <= 1) { + return SkData::MakeEmpty(); + } + return data; + } + } + return nullptr; +} + +static bool write_pad32(SkWStream* stream, const void* data, size_t size) { + if (!stream->write(data, size)) { + return false; + } + if (size & 3) { + uint32_t zero = 0; + return stream->write(&zero, 4 - (size & 3)); + } + return true; +} + +// Private serialize. +// SkPictureData::serialize makes a first pass on all subpictures, indicatewd by textBlobsOnly=true, +// to fill typefaceSet. +void SkPicture::serialize(SkWStream* stream, const SkSerialProcs* procsPtr, + SkRefCntSet* typefaceSet, bool textBlobsOnly) const { + SkSerialProcs procs; + if (procsPtr) { + procs = *procsPtr; + } + + SkPictInfo info = this->createHeader(); + stream->write(&info, sizeof(info)); + + if (auto custom = custom_serialize(this, procs)) { + int32_t size = SkToS32(custom->size()); + if (size == 0) { + stream->write8(kFailure_TrailingStreamByteAfterPictInfo); + return; + } + stream->write8(kCustom_TrailingStreamByteAfterPictInfo); + stream->write32(-size); // negative for custom format + write_pad32(stream, custom->data(), size); + return; + } + + std::unique_ptr<SkPictureData> data(this->backport()); + if (data) { + stream->write8(kPictureData_TrailingStreamByteAfterPictInfo); + data->serialize(stream, procs, typefaceSet, textBlobsOnly); + } else { + stream->write8(kFailure_TrailingStreamByteAfterPictInfo); + } +} + +void SkPicturePriv::Flatten(const sk_sp<const SkPicture> picture, SkWriteBuffer& buffer) { + SkPictInfo info = picture->createHeader(); + std::unique_ptr<SkPictureData> data(picture->backport()); + + buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic)); + buffer.writeUInt(info.getVersion()); + buffer.writeRect(info.fCullRect); + + if (auto custom = custom_serialize(picture.get(), buffer.fProcs)) { + int32_t size = SkToS32(custom->size()); + buffer.write32(-size); // negative for custom format + buffer.writePad32(custom->data(), size); + return; + } + + if (data) { + buffer.write32(1); // special size meaning SkPictureData + data->flatten(buffer); + } else { + buffer.write32(0); // signal no content + } +} + +sk_sp<SkPicture> SkPicture::MakePlaceholder(SkRect cull) { + struct Placeholder : public SkPicture { + explicit Placeholder(SkRect cull) : fCull(cull) {} + + void playback(SkCanvas*, AbortCallback*) const override { } + + // approximateOpCount() needs to be greater than kMaxPictureOpsToUnrollInsteadOfRef + // (SkCanvasPriv.h) to avoid unrolling this into a parent picture. + int approximateOpCount(bool) const override { + return kMaxPictureOpsToUnrollInsteadOfRef+1; + } + size_t approximateBytesUsed() const override { return sizeof(*this); } + SkRect cullRect() const override { return fCull; } + + SkRect fCull; + }; + return sk_make_sp<Placeholder>(cull); +} |