blob: 62642aa4aea3886af40725473add2f71155cc8aa [file]
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkFlattenable.h"
#include "include/core/SkData.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSerialProcs.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkTDArray.h"
#include "src/base/SkSharedMutex.h"
#include "src/core/SkPtrRecorder.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <iterator>
#include <utility>
SkNamedFactorySet::SkNamedFactorySet() : fNextAddedFactory(0) {}
uint32_t SkNamedFactorySet::find(SkFlattenable::Factory factory) {
uint32_t index = fFactorySet.find(factory);
if (index > 0) {
return index;
}
const char* name = SkFlattenable::FactoryToName(factory);
if (nullptr == name) {
return 0;
}
*fNames.append() = name;
return fFactorySet.add(factory);
}
const char* SkNamedFactorySet::getNextAddedFactoryName() {
if (fNextAddedFactory < fNames.size()) {
return fNames[fNextAddedFactory++];
}
return nullptr;
}
///////////////////////////////////////////////////////////////////////////////
SkRefCntSet::~SkRefCntSet() {
// call this now, while our decPtr() is sill in scope
this->reset();
}
void SkRefCntSet::incPtr(void* ptr) {
((SkRefCnt*)ptr)->ref();
}
void SkRefCntSet::decPtr(void* ptr) {
((SkRefCnt*)ptr)->unref();
}
///////////////////////////////////////////////////////////////////////////////
namespace {
struct Entry {
const char* fName;
SkFlattenable::Factory fFactory;
};
struct EntryComparator {
bool operator()(const Entry& a, const Entry& b) const {
return strcmp(a.fName, b.fName) < 0;
}
bool operator()(const Entry& a, const char* b) const {
return strcmp(a.fName, b) < 0;
}
bool operator()(const char* a, const Entry& b) const {
return strcmp(a, b.fName) < 0;
}
};
int gCount = 0;
Entry gEntries[128] = {};
SkSharedMutex gEntriesMutex;
} // namespace
void SkFlattenable::Register(const char name[], Factory factory) {
SkAutoSharedMutexExclusive lock(gEntriesMutex);
SkASSERT(name);
SkASSERT(factory);
SkASSERT(gCount < (int)std::size(gEntries));
/**
* We add the new Entry to gEntries using a sorted insertion
*
* We first find the position at which we must insert the new Entry (insertion_element =
* std::upper_bound). Then we add our new Entry to gEntries[gCount]
*
* Then we call std::rotate(first, middle, last) to place our new Entry at the beginning of
* insertion_element
* - first will be the beginning of the elements we want to shift
* - middle will be the new Entry we want to insert, the things before it will get shifted
* - last will be the element after the one we are inserting
*
* As an example, let's insert name = 'dragonfruit' into
* gEntries = ['apple', 'blueberry', 'coconut', 'elderberry', 'fig'] with
* gCount = 5
*
* After upper_bound, insertion_element points to 'elderberry' (the first element that comes
* after 'dragonfruit')
*
* After gEntries[gCount] = name, gEntries + gCount points to 'dragonfruit'
*
* now we have gEntries = ['apple', 'blueberry', 'coconut', 'elderberry', 'fig', 'dragonfruit']
*
* so std::rotate('elderberry', 'dragonfruit', 'dragonfruit'+1); will result in
* gEntries = ['apple', 'blueberry', 'coconut', 'dragonfruit', 'elderberry', 'fig']
*
* This will effectively move the new Entry to the insertion_element position, while maintaining
* the order of the other elements
*/
Entry* insertion_element =
std::upper_bound(gEntries, gEntries + gCount, name, EntryComparator());
gEntries[gCount].fName = name;
gEntries[gCount].fFactory = factory;
std::rotate(insertion_element, gEntries + gCount, gEntries + gCount + 1);
gCount += 1;
}
SkFlattenable::Factory SkFlattenable::NameToFactory(const char name[]) {
SkAutoSharedMutexShared lock(gEntriesMutex);
RegisterFlattenablesIfNeeded();
SkASSERT(std::is_sorted(gEntries, gEntries + gCount, EntryComparator()));
auto pair = std::equal_range(gEntries, gEntries + gCount, name, EntryComparator());
if (pair.first == pair.second) {
return nullptr;
}
return pair.first->fFactory;
}
const char* SkFlattenable::FactoryToName(Factory fact) {
SkAutoSharedMutexShared lock(gEntriesMutex);
RegisterFlattenablesIfNeeded();
const Entry* entries = gEntries;
for (int i = gCount - 1; i >= 0; --i) {
if (entries[i].fFactory == fact) {
return entries[i].fName;
}
}
return nullptr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<SkData> SkFlattenable::serialize(const SkSerialProcs* procs) const {
SkSerialProcs p;
if (procs) {
p = *procs;
}
SkBinaryWriteBuffer writer(p);
writer.writeFlattenable(this);
size_t size = writer.bytesWritten();
auto data = SkData::MakeUninitialized(size);
writer.writeToMemory(data->writable_data());
return data;
}
size_t SkFlattenable::serialize(void* memory, size_t memory_size,
const SkSerialProcs* procs) const {
SkSerialProcs p;
if (procs) {
p = *procs;
}
SkBinaryWriteBuffer writer(memory, memory_size, p);
writer.writeFlattenable(this);
return writer.usingInitialStorage() ? writer.bytesWritten() : 0u;
}
sk_sp<SkFlattenable> SkFlattenable::Deserialize(SkFlattenable::Type type, const void* data,
size_t size, const SkDeserialProcs* procs) {
SkReadBuffer buffer(data, size);
if (procs) {
buffer.setDeserialProcs(*procs);
}
return sk_sp<SkFlattenable>(buffer.readFlattenable(type));
}