SkPDF: Refactor SkPDFObject heiararchy.
Flatten and use a tagged union type Δmemory ~= -2.4% ± 0.5% Δtime ~= -1.2% ± 0.2% BUG=skia:3585 Review URL: https://codereview.chromium.org/1069103003
This commit is contained in:
parent
8e71d38126
commit
130444fdaf
@ -94,10 +94,6 @@ static void generate_page_tree(const SkTDArray<SkPDFDict*>& pages,
|
|||||||
// one child.
|
// one child.
|
||||||
static const int kNodeSize = 8;
|
static const int kNodeSize = 8;
|
||||||
|
|
||||||
SkAutoTUnref<SkPDFName> kidsName(new SkPDFName("Kids"));
|
|
||||||
SkAutoTUnref<SkPDFName> countName(new SkPDFName("Count"));
|
|
||||||
SkAutoTUnref<SkPDFName> parentName(new SkPDFName("Parent"));
|
|
||||||
|
|
||||||
// curNodes takes a reference to its items, which it passes to pageTree.
|
// curNodes takes a reference to its items, which it passes to pageTree.
|
||||||
SkTDArray<SkPDFDict*> curNodes;
|
SkTDArray<SkPDFDict*> curNodes;
|
||||||
curNodes.setReserve(pages.count());
|
curNodes.setReserve(pages.count());
|
||||||
@ -126,7 +122,7 @@ static void generate_page_tree(const SkTDArray<SkPDFDict*>& pages,
|
|||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (; i < curNodes.count() && count < kNodeSize; i++, count++) {
|
for (; i < curNodes.count() && count < kNodeSize; i++, count++) {
|
||||||
curNodes[i]->insert(parentName.get(), newNodeRef.get());
|
curNodes[i]->insert("Parent", newNodeRef.get());
|
||||||
kids->append(new SkPDFObjRef(curNodes[i]))->unref();
|
kids->append(new SkPDFObjRef(curNodes[i]))->unref();
|
||||||
|
|
||||||
// TODO(vandebo): put the objects in strict access order.
|
// TODO(vandebo): put the objects in strict access order.
|
||||||
@ -149,8 +145,8 @@ static void generate_page_tree(const SkTDArray<SkPDFDict*>& pages,
|
|||||||
if (i == curNodes.count()) {
|
if (i == curNodes.count()) {
|
||||||
pageCount = ((pages.count() - 1) % treeCapacity) + 1;
|
pageCount = ((pages.count() - 1) % treeCapacity) + 1;
|
||||||
}
|
}
|
||||||
newNode->insert(countName.get(), new SkPDFInt(pageCount))->unref();
|
newNode->insert("Count", new SkPDFInt(pageCount))->unref();
|
||||||
newNode->insert(kidsName.get(), kids.get());
|
newNode->insert("Kids", kids.get());
|
||||||
nextRoundNodes.push(newNode); // Transfer reference.
|
nextRoundNodes.push(newNode); // Transfer reference.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1299,15 +1299,14 @@ const SkTDArray<SkPDFFont*>& SkPDFDevice::getFontResources() const {
|
|||||||
|
|
||||||
SkPDFArray* SkPDFDevice::copyMediaBox() const {
|
SkPDFArray* SkPDFDevice::copyMediaBox() const {
|
||||||
// should this be a singleton?
|
// should this be a singleton?
|
||||||
SkAutoTUnref<SkPDFInt> zero(SkNEW_ARGS(SkPDFInt, (0)));
|
|
||||||
|
|
||||||
SkPDFArray* mediaBox = SkNEW(SkPDFArray);
|
SkAutoTUnref<SkPDFArray> mediaBox(SkNEW(SkPDFArray));
|
||||||
mediaBox->reserve(4);
|
mediaBox->reserve(4);
|
||||||
mediaBox->append(zero.get());
|
mediaBox->appendInt(0);
|
||||||
mediaBox->append(zero.get());
|
mediaBox->appendInt(0);
|
||||||
mediaBox->appendInt(fPageSize.fWidth);
|
mediaBox->appendInt(fPageSize.fWidth);
|
||||||
mediaBox->appendInt(fPageSize.fHeight);
|
mediaBox->appendInt(fPageSize.fHeight);
|
||||||
return mediaBox;
|
return mediaBox.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
SkStreamAsset* SkPDFDevice::content() const {
|
SkStreamAsset* SkPDFDevice::content() const {
|
||||||
@ -1505,7 +1504,7 @@ void SkPDFDevice::handleLinkToURL(SkData* urlData, const SkRect& r,
|
|||||||
urlData->size() - 1);
|
urlData->size() - 1);
|
||||||
SkAutoTUnref<SkPDFDict> action(SkNEW_ARGS(SkPDFDict, ("Action")));
|
SkAutoTUnref<SkPDFDict> action(SkNEW_ARGS(SkPDFDict, ("Action")));
|
||||||
action->insertName("S", "URI");
|
action->insertName("S", "URI");
|
||||||
action->insert("URI", SkNEW_ARGS(SkPDFString, (url)))->unref();
|
action->insertString("URI", url);
|
||||||
annotation->insert("A", action.get());
|
annotation->insert("A", action.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1514,7 +1513,7 @@ void SkPDFDevice::handleLinkToNamedDest(SkData* nameData, const SkRect& r,
|
|||||||
SkAutoTUnref<SkPDFDict> annotation(createLinkAnnotation(r, matrix));
|
SkAutoTUnref<SkPDFDict> annotation(createLinkAnnotation(r, matrix));
|
||||||
SkString name(static_cast<const char *>(nameData->data()),
|
SkString name(static_cast<const char *>(nameData->data()),
|
||||||
nameData->size() - 1);
|
nameData->size() - 1);
|
||||||
annotation->insert("Dest", SkNEW_ARGS(SkPDFName, (name)))->unref();
|
annotation->insertName("Dest", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NamedDestination {
|
struct NamedDestination {
|
||||||
@ -1522,9 +1521,7 @@ struct NamedDestination {
|
|||||||
SkPoint point;
|
SkPoint point;
|
||||||
|
|
||||||
NamedDestination(const SkData* nameData, const SkPoint& point)
|
NamedDestination(const SkData* nameData, const SkPoint& point)
|
||||||
: nameData(nameData), point(point) {
|
: nameData(SkRef(nameData)), point(point) {}
|
||||||
nameData->ref();
|
|
||||||
}
|
|
||||||
|
|
||||||
~NamedDestination() {
|
~NamedDestination() {
|
||||||
nameData->unref();
|
nameData->unref();
|
||||||
@ -1547,13 +1544,13 @@ void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) const {
|
|||||||
NamedDestination* dest = fNamedDestinations[i];
|
NamedDestination* dest = fNamedDestinations[i];
|
||||||
SkAutoTUnref<SkPDFArray> pdfDest(SkNEW(SkPDFArray));
|
SkAutoTUnref<SkPDFArray> pdfDest(SkNEW(SkPDFArray));
|
||||||
pdfDest->reserve(5);
|
pdfDest->reserve(5);
|
||||||
pdfDest->append(SkNEW_ARGS(SkPDFObjRef, (page)))->unref();
|
pdfDest->appendObjRef(SkRef(page));
|
||||||
pdfDest->appendName("XYZ");
|
pdfDest->appendName("XYZ");
|
||||||
pdfDest->appendScalar(dest->point.x());
|
pdfDest->appendScalar(dest->point.x());
|
||||||
pdfDest->appendScalar(dest->point.y());
|
pdfDest->appendScalar(dest->point.y());
|
||||||
pdfDest->appendInt(0); // Leave zoom unchanged
|
pdfDest->appendInt(0); // Leave zoom unchanged
|
||||||
dict->insert(static_cast<const char *>(dest->nameData->data()),
|
SkString name(static_cast<const char*>(dest->nameData->data()));
|
||||||
pdfDest);
|
dict->insertObject(name, pdfDest.detach());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1390,10 +1390,8 @@ bool SkPDFType3Font::populate(uint16_t glyphID) {
|
|||||||
SkAutoTDelete<SkMemoryStream> glyphStream(new SkMemoryStream());
|
SkAutoTDelete<SkMemoryStream> glyphStream(new SkMemoryStream());
|
||||||
glyphStream->setData(content.copyToData())->unref();
|
glyphStream->setData(content.copyToData())->unref();
|
||||||
|
|
||||||
SkAutoTUnref<SkPDFStream> glyphDescription(
|
charProcs->insertObjRef(characterName,
|
||||||
new SkPDFStream(glyphStream.get()));
|
new SkPDFStream(glyphStream.get()));
|
||||||
charProcs->insert(characterName.c_str(),
|
|
||||||
new SkPDFObjRef(glyphDescription.get()))->unref();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
insert("FontBBox", makeFontBBox(bbox, 1000))->unref();
|
insert("FontBBox", makeFontBBox(bbox, 1000))->unref();
|
||||||
|
@ -46,7 +46,7 @@ static char get_resource_type_prefix(
|
|||||||
static const char* get_resource_type_name(
|
static const char* get_resource_type_name(
|
||||||
SkPDFResourceDict::SkPDFResourceType type) {
|
SkPDFResourceDict::SkPDFResourceType type) {
|
||||||
SkASSERT(type >= 0);
|
SkASSERT(type >= 0);
|
||||||
SkASSERT(type < SkPDFResourceDict::kResourceTypeCount);
|
SkASSERT(type < SK_ARRAY_COUNT(resource_type_names));
|
||||||
|
|
||||||
return resource_type_names[type];
|
return resource_type_names[type];
|
||||||
}
|
}
|
||||||
@ -67,13 +67,10 @@ static void add_subdict(
|
|||||||
}
|
}
|
||||||
SkAutoTUnref<SkPDFDict> resources(SkNEW(SkPDFDict));
|
SkAutoTUnref<SkPDFDict> resources(SkNEW(SkPDFDict));
|
||||||
for (int i = 0; i < resourceList.count(); i++) {
|
for (int i = 0; i < resourceList.count(); i++) {
|
||||||
SkString keyString = SkPDFResourceDict::getResourceName(type, i);
|
resources->insertObjRef(SkPDFResourceDict::getResourceName(type, i),
|
||||||
SkAutoTUnref<SkPDFName> keyName(SkNEW_ARGS(SkPDFName, (keyString)));
|
SkRef(resourceList[i]));
|
||||||
SkAutoTUnref<SkPDFObjRef> ref(
|
|
||||||
SkNEW_ARGS(SkPDFObjRef, (resourceList[i])));
|
|
||||||
resources->insert(keyName, ref);
|
|
||||||
}
|
}
|
||||||
dst->insert(get_resource_type_name(type), resources);
|
dst->insertObject(get_resource_type_name(type), resources.detach());
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPDFDict* SkPDFResourceDict::Create(
|
SkPDFDict* SkPDFResourceDict::Create(
|
||||||
@ -90,7 +87,7 @@ SkPDFDict* SkPDFResourceDict::Create(
|
|||||||
for (size_t i = 0; i < SK_ARRAY_COUNT(kProcs); i++) {
|
for (size_t i = 0; i < SK_ARRAY_COUNT(kProcs); i++) {
|
||||||
procSets->appendName(kProcs[i]);
|
procSets->appendName(kProcs[i]);
|
||||||
}
|
}
|
||||||
dict->insert("ProcSets", procSets);
|
dict->insertObject("ProcSets", procSets.detach());
|
||||||
|
|
||||||
if (gStateResources) {
|
if (gStateResources) {
|
||||||
add_subdict(*gStateResources, kExtGState_ResourceType, dict);
|
add_subdict(*gStateResources, kExtGState_ResourceType, dict);
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "SkPDFTypes.h"
|
#include "SkPDFTypes.h"
|
||||||
#include "SkStream.h"
|
#include "SkStream.h"
|
||||||
|
|
||||||
@ -18,62 +17,271 @@
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {
|
SkString* pun(char* x) { return reinterpret_cast<SkString*>(x); }
|
||||||
SkSafeRef(obj);
|
const SkString* pun(const char* x) {
|
||||||
|
return reinterpret_cast<const SkString*>(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPDFObjRef::~SkPDFObjRef() {}
|
SkPDFUnion::SkPDFUnion(Type t) : fType(t) {}
|
||||||
|
|
||||||
void SkPDFObjRef::emitObject(SkWStream* stream,
|
SkPDFUnion::~SkPDFUnion() {
|
||||||
const SkPDFObjNumMap& objNumMap,
|
switch (fType) {
|
||||||
const SkPDFSubstituteMap& substitutes) {
|
case Type::kNameSkS:
|
||||||
SkPDFObject* obj = substitutes.getSubstitute(fObj);
|
case Type::kStringSkS:
|
||||||
stream->writeDecAsText(objNumMap.getObjectNumber(obj));
|
pun(fSkString)->~SkString();
|
||||||
stream->writeText(" 0 R"); // Generation number is always 0.
|
return;
|
||||||
}
|
case Type::kObjRef:
|
||||||
|
case Type::kObject:
|
||||||
void SkPDFObjRef::addResources(SkPDFObjNumMap* catalog,
|
SkSafeUnref(fObject);
|
||||||
const SkPDFSubstituteMap& substitutes) const {
|
return;
|
||||||
SkPDFObject* obj = substitutes.getSubstitute(fObj);
|
default:
|
||||||
SkASSERT(obj);
|
return;
|
||||||
if (catalog->addObject(obj)) {
|
|
||||||
obj->addResources(catalog, substitutes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
SkPDFUnion& SkPDFUnion::operator=(SkPDFUnion&& other) {
|
||||||
|
if (this != &other) {
|
||||||
|
this->~SkPDFUnion();
|
||||||
|
SkNEW_PLACEMENT_ARGS(this, SkPDFUnion, (other.move()));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {}
|
SkPDFUnion::SkPDFUnion(SkPDFUnion&& other) {
|
||||||
SkPDFInt::~SkPDFInt() {}
|
SkASSERT(this != &other);
|
||||||
|
memcpy(this, &other, sizeof(*this));
|
||||||
|
other.fType = Type::kDestroyed;
|
||||||
|
}
|
||||||
|
|
||||||
void SkPDFInt::emitObject(SkWStream* stream,
|
#if 0
|
||||||
const SkPDFObjNumMap&,
|
SkPDFUnion SkPDFUnion::copy() const {
|
||||||
const SkPDFSubstituteMap&) {
|
SkPDFUnion u(fType);
|
||||||
stream->writeDecAsText(fValue);
|
memcpy(&u, this, sizeof(u));
|
||||||
|
switch (fType) {
|
||||||
|
case Type::kNameSkS:
|
||||||
|
case Type::kStringSkS:
|
||||||
|
SkNEW_PLACEMENT_ARGS(pun(u.fSkString), SkString,
|
||||||
|
(*pun(fSkString)));
|
||||||
|
return u.move();
|
||||||
|
case Type::kObjRef:
|
||||||
|
case Type::kObject:
|
||||||
|
SkRef(u.fObject);
|
||||||
|
return u.move();
|
||||||
|
default:
|
||||||
|
return u.move();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SkPDFUnion& SkPDFUnion::operator=(const SkPDFUnion& other) {
|
||||||
|
return *this = other.copy();
|
||||||
|
}
|
||||||
|
SkPDFUnion::SkPDFUnion(const SkPDFUnion& other) {
|
||||||
|
*this = other.copy();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool SkPDFUnion::isName() const {
|
||||||
|
return Type::kName == fType || Type::kNameSkS == fType;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SK_DEBUG
|
||||||
|
// Most names need no escaping. Such names are handled as static
|
||||||
|
// const strings.
|
||||||
|
bool is_valid_name(const char* n) {
|
||||||
|
static const char kControlChars[] = "/%()<>[]{}";
|
||||||
|
while (*n) {
|
||||||
|
if (*n < '!' || *n > '~' || strchr(kControlChars, *n)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif // SK_DEBUG
|
||||||
|
|
||||||
|
// Given an arbitrary string, convert it to a valid name.
|
||||||
|
static SkString escape_name(const char* name, size_t len) {
|
||||||
|
static const char kToEscape[] = "#/%()<>[]{}";
|
||||||
|
int count = 0;
|
||||||
|
const char* const end = &name[len];
|
||||||
|
for (const char* n = name; n != end; ++n) {
|
||||||
|
if (*n < '!' || *n > '~' || strchr(kToEscape, *n)) {
|
||||||
|
count += 2;
|
||||||
|
}
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
SkString result(count);
|
||||||
|
char* s = result.writable_str();
|
||||||
|
static const char kHex[] = "0123456789ABCDEF";
|
||||||
|
for (const char* n = name; n != end; ++n) {
|
||||||
|
if (*n < '!' || *n > '~' || strchr(kToEscape, *n)) {
|
||||||
|
*s++ = '#';
|
||||||
|
*s++ = kHex[(*n >> 4) & 0xF];
|
||||||
|
*s++ = kHex[*n & 0xF];
|
||||||
|
} else {
|
||||||
|
*s++ = *n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SkASSERT(&result.writable_str()[count] == s); // don't over-write
|
||||||
|
return result; // allocated space
|
||||||
|
}
|
||||||
|
|
||||||
|
static SkString escape_name(const SkString& name) {
|
||||||
|
return escape_name(name.c_str(), name.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_string(SkWStream* o, const SkString& s) {
|
||||||
|
o->write(s.c_str(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static SkString format_string(const SkString& s) {
|
||||||
|
return SkPDFString::FormatString(s.c_str(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static SkString format_string(const char* s) {
|
||||||
|
return SkPDFString::FormatString(s, strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkPDFUnion::emitObject(SkWStream* stream,
|
||||||
|
const SkPDFObjNumMap& objNumMap,
|
||||||
|
const SkPDFSubstituteMap& substitutes) const {
|
||||||
|
switch (fType) {
|
||||||
|
case Type::kInt:
|
||||||
|
stream->writeDecAsText(fIntValue);
|
||||||
|
return;
|
||||||
|
case Type::kBool:
|
||||||
|
stream->writeText(fBoolValue ? "true" : "false");
|
||||||
|
return;
|
||||||
|
case Type::kScalar:
|
||||||
|
SkPDFScalar::Append(fScalarValue, stream);
|
||||||
|
return;
|
||||||
|
case Type::kName:
|
||||||
|
stream->writeText("/");
|
||||||
|
SkASSERT(is_valid_name(fStaticString));
|
||||||
|
stream->writeText(fStaticString);
|
||||||
|
return;
|
||||||
|
case Type::kString:
|
||||||
|
SkASSERT(fStaticString);
|
||||||
|
write_string(stream, format_string(fStaticString));
|
||||||
|
return;
|
||||||
|
case Type::kNameSkS:
|
||||||
|
stream->writeText("/");
|
||||||
|
write_string(stream, escape_name(*pun(fSkString)));
|
||||||
|
return;
|
||||||
|
case Type::kStringSkS:
|
||||||
|
write_string(stream, format_string(*pun(fSkString)));
|
||||||
|
return;
|
||||||
|
case Type::kObjRef:
|
||||||
|
stream->writeDecAsText(objNumMap.getObjectNumber(
|
||||||
|
substitutes.getSubstitute(fObject)));
|
||||||
|
stream->writeText(" 0 R"); // Generation number is always 0.
|
||||||
|
return;
|
||||||
|
case Type::kObject:
|
||||||
|
fObject->emitObject(stream, objNumMap, substitutes);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
SkDEBUGFAIL("SkPDFUnion::emitObject with bad type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkPDFUnion::addResources(SkPDFObjNumMap* objNumMap,
|
||||||
|
const SkPDFSubstituteMap& substituteMap) const {
|
||||||
|
switch (fType) {
|
||||||
|
case Type::kInt:
|
||||||
|
case Type::kBool:
|
||||||
|
case Type::kScalar:
|
||||||
|
case Type::kName:
|
||||||
|
case Type::kString:
|
||||||
|
case Type::kNameSkS:
|
||||||
|
case Type::kStringSkS:
|
||||||
|
return; // These have no resources.
|
||||||
|
case Type::kObjRef: {
|
||||||
|
SkPDFObject* obj = substituteMap.getSubstitute(fObject);
|
||||||
|
if (objNumMap->addObject(obj)) {
|
||||||
|
obj->addResources(objNumMap, substituteMap);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case Type::kObject:
|
||||||
|
fObject->addResources(objNumMap, substituteMap);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
SkDEBUGFAIL("SkPDFUnion::addResources with bad type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPDFUnion SkPDFUnion::Int(int32_t value) {
|
||||||
|
SkPDFUnion u(Type::kInt);
|
||||||
|
u.fIntValue = value;
|
||||||
|
return u.move();
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPDFUnion SkPDFUnion::Bool(bool value) {
|
||||||
|
SkPDFUnion u(Type::kBool);
|
||||||
|
u.fBoolValue = value;
|
||||||
|
return u.move();
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPDFUnion SkPDFUnion::Scalar(SkScalar value) {
|
||||||
|
SkPDFUnion u(Type::kScalar);
|
||||||
|
u.fScalarValue = value;
|
||||||
|
return u.move();
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPDFUnion SkPDFUnion::Name(const char* value) {
|
||||||
|
SkPDFUnion u(Type::kName);
|
||||||
|
SkASSERT(value);
|
||||||
|
SkASSERT(is_valid_name(value));
|
||||||
|
u.fStaticString = value;
|
||||||
|
return u.move();
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPDFUnion SkPDFUnion::String(const char* value) {
|
||||||
|
SkPDFUnion u(Type::kString);
|
||||||
|
SkASSERT(value);
|
||||||
|
u.fStaticString = value;
|
||||||
|
return u.move();
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPDFUnion SkPDFUnion::Name(const SkString& s) {
|
||||||
|
SkPDFUnion u(Type::kNameSkS);
|
||||||
|
SkNEW_PLACEMENT_ARGS(pun(u.fSkString), SkString, (s));
|
||||||
|
return u.move();
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPDFUnion SkPDFUnion::String(const SkString& s) {
|
||||||
|
SkPDFUnion u(Type::kStringSkS);
|
||||||
|
SkNEW_PLACEMENT_ARGS(pun(u.fSkString), SkString, (s));
|
||||||
|
return u.move();
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPDFUnion SkPDFUnion::ObjRef(SkPDFObject* ptr) {
|
||||||
|
SkPDFUnion u(Type::kObjRef);
|
||||||
|
SkASSERT(ptr);
|
||||||
|
u.fObject = ptr;
|
||||||
|
return u.move();
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPDFUnion SkPDFUnion::Object(SkPDFObject* ptr) {
|
||||||
|
SkPDFUnion u(Type::kObject);
|
||||||
|
SkASSERT(ptr);
|
||||||
|
u.fObject = ptr;
|
||||||
|
return u.move();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SkPDFBool::SkPDFBool(bool value) : fValue(value) {}
|
void SkPDFAtom::emitObject(SkWStream* stream,
|
||||||
SkPDFBool::~SkPDFBool() {}
|
const SkPDFObjNumMap& objNumMap,
|
||||||
|
const SkPDFSubstituteMap& substitutes) {
|
||||||
void SkPDFBool::emitObject(SkWStream* stream,
|
fValue.emitObject(stream, objNumMap, substitutes);
|
||||||
const SkPDFObjNumMap&,
|
}
|
||||||
const SkPDFSubstituteMap&) {
|
void SkPDFAtom::addResources(SkPDFObjNumMap* map,
|
||||||
stream->writeText(fValue ? "true" : "false");
|
const SkPDFSubstituteMap& substitutes) const {
|
||||||
|
fValue.addResources(map, substitutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {}
|
|
||||||
SkPDFScalar::~SkPDFScalar() {}
|
|
||||||
|
|
||||||
void SkPDFScalar::emitObject(SkWStream* stream,
|
|
||||||
const SkPDFObjNumMap&,
|
|
||||||
const SkPDFSubstituteMap&) {
|
|
||||||
SkPDFScalar::Append(fValue, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void SkPDFScalar::Append(SkScalar value, SkWStream* stream) {
|
void SkPDFScalar::Append(SkScalar value, SkWStream* stream) {
|
||||||
// The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and
|
// The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and
|
||||||
@ -125,23 +333,8 @@ void SkPDFScalar::Append(SkScalar value, SkWStream* stream) {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SkPDFString::SkPDFString(const char value[])
|
|
||||||
: fValue(FormatString(value, strlen(value))) {
|
|
||||||
}
|
|
||||||
|
|
||||||
SkPDFString::SkPDFString(const SkString& value)
|
|
||||||
: fValue(FormatString(value.c_str(), value.size())) {
|
|
||||||
}
|
|
||||||
|
|
||||||
SkPDFString::~SkPDFString() {}
|
|
||||||
|
|
||||||
void SkPDFString::emitObject(SkWStream* stream,
|
|
||||||
const SkPDFObjNumMap&,
|
|
||||||
const SkPDFSubstituteMap&) {
|
|
||||||
stream->write(fValue.c_str(), fValue.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
||||||
SkString SkPDFString::FormatString(const char* cin, size_t len) {
|
SkString SkPDFString::FormatString(const char* cin, size_t len) {
|
||||||
SkASSERT(len <= kMaxLen);
|
SkASSERT(len <= kMaxLen);
|
||||||
|
|
||||||
@ -187,55 +380,25 @@ SkString SkPDFString::FormatString(const char* cin, size_t len) {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {}
|
|
||||||
SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {}
|
|
||||||
SkPDFName::~SkPDFName() {}
|
|
||||||
|
|
||||||
bool SkPDFName::operator==(const SkPDFName& b) const {
|
|
||||||
return fValue == b.fValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkPDFName::emitObject(SkWStream* stream,
|
|
||||||
const SkPDFObjNumMap&,
|
|
||||||
const SkPDFSubstituteMap&) {
|
|
||||||
stream->write(fValue.c_str(), fValue.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
SkString SkPDFName::FormatName(const SkString& input) {
|
|
||||||
SkASSERT(input.size() <= kMaxLen);
|
|
||||||
// TODO(vandebo) If more escaping is needed, improve the linear scan.
|
|
||||||
static const char escaped[] = "#/%()<>[]{}";
|
|
||||||
|
|
||||||
SkString result("/");
|
|
||||||
for (size_t i = 0; i < input.size(); i++) {
|
|
||||||
if (input[i] & 0x80 || input[i] < '!' || strchr(escaped, input[i])) {
|
|
||||||
result.append("#");
|
|
||||||
// Mask with 0xFF to avoid sign extension. i.e. #FFFFFF81
|
|
||||||
result.appendHex(input[i] & 0xFF, 2);
|
|
||||||
} else {
|
|
||||||
result.append(input.c_str() + i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
SkPDFArray::SkPDFArray() {}
|
SkPDFArray::SkPDFArray() {}
|
||||||
SkPDFArray::~SkPDFArray() {
|
SkPDFArray::~SkPDFArray() {
|
||||||
fValue.unrefAll();
|
for (SkPDFUnion& value : fValues) {
|
||||||
|
value.~SkPDFUnion();
|
||||||
|
}
|
||||||
|
fValues.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SkPDFArray::size() const { return fValues.count(); }
|
||||||
|
|
||||||
|
void SkPDFArray::reserve(int length) { fValues.setReserve(length); }
|
||||||
|
|
||||||
void SkPDFArray::emitObject(SkWStream* stream,
|
void SkPDFArray::emitObject(SkWStream* stream,
|
||||||
const SkPDFObjNumMap& objNumMap,
|
const SkPDFObjNumMap& objNumMap,
|
||||||
const SkPDFSubstituteMap& substitutes) {
|
const SkPDFSubstituteMap& substitutes) {
|
||||||
stream->writeText("[");
|
stream->writeText("[");
|
||||||
for (int i = 0; i < fValue.count(); i++) {
|
for (int i = 0; i < fValues.count(); i++) {
|
||||||
SkASSERT(substitutes.getSubstitute(fValue[i]) == fValue[i]);
|
fValues[i].emitObject(stream, objNumMap, substitutes);
|
||||||
fValue[i]->emitObject(stream, objNumMap, substitutes);
|
if (i + 1 < fValues.count()) {
|
||||||
if (i + 1 < fValue.count()) {
|
|
||||||
stream->writeText(" ");
|
stream->writeText(" ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,68 +407,74 @@ void SkPDFArray::emitObject(SkWStream* stream,
|
|||||||
|
|
||||||
void SkPDFArray::addResources(SkPDFObjNumMap* catalog,
|
void SkPDFArray::addResources(SkPDFObjNumMap* catalog,
|
||||||
const SkPDFSubstituteMap& substitutes) const {
|
const SkPDFSubstituteMap& substitutes) const {
|
||||||
for (int i = 0; i < fValue.count(); i++) {
|
for (const SkPDFUnion& value : fValues) {
|
||||||
SkASSERT(substitutes.getSubstitute(fValue[i]) == fValue[i]);
|
value.addResources(catalog, substitutes);
|
||||||
fValue[i]->addResources(catalog, substitutes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFArray::reserve(int length) {
|
void SkPDFArray::append(SkPDFUnion&& value) {
|
||||||
SkASSERT(length <= kMaxLen);
|
SkNEW_PLACEMENT_ARGS(fValues.append(), SkPDFUnion, (value.move()));
|
||||||
fValue.setReserve(length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
|
SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
|
||||||
SkASSERT(fValue.count() < kMaxLen);
|
// DEPRECATED
|
||||||
value->ref();
|
this->append(SkPDFUnion::Object(SkRef(value)));
|
||||||
fValue.push(value);
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFArray::appendInt(int32_t value) {
|
void SkPDFArray::appendInt(int32_t value) {
|
||||||
SkASSERT(fValue.count() < kMaxLen);
|
this->append(SkPDFUnion::Int(value));
|
||||||
fValue.push(new SkPDFInt(value));
|
}
|
||||||
|
|
||||||
|
void SkPDFArray::appendBool(bool value) {
|
||||||
|
this->append(SkPDFUnion::Bool(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFArray::appendScalar(SkScalar value) {
|
void SkPDFArray::appendScalar(SkScalar value) {
|
||||||
SkASSERT(fValue.count() < kMaxLen);
|
this->append(SkPDFUnion::Scalar(value));
|
||||||
fValue.push(new SkPDFScalar(value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFArray::appendName(const char name[]) {
|
void SkPDFArray::appendName(const char name[]) {
|
||||||
SkASSERT(fValue.count() < kMaxLen);
|
this->append(SkPDFUnion::Name(SkString(name)));
|
||||||
fValue.push(new SkPDFName(name));
|
}
|
||||||
|
|
||||||
|
void SkPDFArray::appendName(const SkString& name) {
|
||||||
|
this->append(SkPDFUnion::Name(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkPDFArray::appendString(const SkString& value) {
|
||||||
|
this->append(SkPDFUnion::String(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkPDFArray::appendString(const char value[]) {
|
||||||
|
this->append(SkPDFUnion::String(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkPDFArray::appendObject(SkPDFObject* value) {
|
||||||
|
this->append(SkPDFUnion::Object(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkPDFArray::appendObjRef(SkPDFObject* value) {
|
||||||
|
this->append(SkPDFUnion::ObjRef(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SkPDFDict::SkPDFDict() {}
|
SkPDFDict::SkPDFDict() {}
|
||||||
|
|
||||||
SkPDFDict::SkPDFDict(const char type[]) {
|
SkPDFDict::~SkPDFDict() { this->clear(); }
|
||||||
insertName("Type", type);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkPDFDict::~SkPDFDict() {
|
SkPDFDict::SkPDFDict(const char type[]) { this->insertName("Type", type); }
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
int SkPDFDict::size() const {
|
|
||||||
return fValue.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkPDFDict::emitObject(SkWStream* stream,
|
void SkPDFDict::emitObject(SkWStream* stream,
|
||||||
const SkPDFObjNumMap& objNumMap,
|
const SkPDFObjNumMap& objNumMap,
|
||||||
const SkPDFSubstituteMap& substitutes) {
|
const SkPDFSubstituteMap& substitutes) {
|
||||||
stream->writeText("<<");
|
stream->writeText("<<");
|
||||||
for (int i = 0; i < fValue.count(); i++) {
|
for (int i = 0; i < fRecords.count(); i++) {
|
||||||
SkASSERT(fValue[i].key);
|
fRecords[i].fKey.emitObject(stream, objNumMap, substitutes);
|
||||||
SkASSERT(fValue[i].value);
|
|
||||||
SkASSERT(substitutes.getSubstitute(fValue[i].key) == fValue[i].key);
|
|
||||||
SkASSERT(substitutes.getSubstitute(fValue[i].value) == fValue[i].value);
|
|
||||||
fValue[i].key->emitObject(stream, objNumMap, substitutes);
|
|
||||||
stream->writeText(" ");
|
stream->writeText(" ");
|
||||||
fValue[i].value->emitObject(stream, objNumMap, substitutes);
|
fRecords[i].fValue.emitObject(stream, objNumMap, substitutes);
|
||||||
if (i + 1 < fValue.count()) {
|
if (i + 1 < fRecords.count()) {
|
||||||
stream->writeText("\n");
|
stream->writeText("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,72 +483,75 @@ void SkPDFDict::emitObject(SkWStream* stream,
|
|||||||
|
|
||||||
void SkPDFDict::addResources(SkPDFObjNumMap* catalog,
|
void SkPDFDict::addResources(SkPDFObjNumMap* catalog,
|
||||||
const SkPDFSubstituteMap& substitutes) const {
|
const SkPDFSubstituteMap& substitutes) const {
|
||||||
for (int i = 0; i < fValue.count(); i++) {
|
for (int i = 0; i < fRecords.count(); i++) {
|
||||||
SkASSERT(fValue[i].key);
|
fRecords[i].fKey.addResources(catalog, substitutes);
|
||||||
SkASSERT(fValue[i].value);
|
fRecords[i].fValue.addResources(catalog, substitutes);
|
||||||
fValue[i].key->addResources(catalog, substitutes);
|
|
||||||
SkASSERT(substitutes.getSubstitute(fValue[i].value) == fValue[i].value);
|
|
||||||
fValue[i].value->addResources(catalog, substitutes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPDFObject* SkPDFDict::append(SkPDFName* key, SkPDFObject* value) {
|
void SkPDFDict::set(SkPDFUnion&& name, SkPDFUnion&& value) {
|
||||||
SkASSERT(key);
|
Record* rec = fRecords.append();
|
||||||
SkASSERT(value);
|
SkASSERT(name.isName());
|
||||||
*(fValue.append()) = Rec(key, value);
|
SkNEW_PLACEMENT_ARGS(&rec->fKey, SkPDFUnion, (name.move()));
|
||||||
|
SkNEW_PLACEMENT_ARGS(&rec->fValue, SkPDFUnion, (value.move()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int SkPDFDict::size() const { return fRecords.count(); }
|
||||||
|
|
||||||
|
void SkPDFDict::insertObjRef(const char key[], SkPDFObject* value) {
|
||||||
|
this->set(SkPDFUnion::Name(key), SkPDFUnion::ObjRef(value));
|
||||||
|
}
|
||||||
|
void SkPDFDict::insertObjRef(const SkString& key, SkPDFObject* value) {
|
||||||
|
this->set(SkPDFUnion::Name(key), SkPDFUnion::ObjRef(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkPDFDict::insertObject(const char key[], SkPDFObject* value) {
|
||||||
|
this->set(SkPDFUnion::Name(key), SkPDFUnion::Object(value));
|
||||||
|
}
|
||||||
|
void SkPDFDict::insertObject(const SkString& key, SkPDFObject* value) {
|
||||||
|
this->set(SkPDFUnion::Name(key), SkPDFUnion::Object(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED
|
||||||
|
SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) {
|
||||||
|
this->set(SkPDFUnion::Name(key), SkPDFUnion::Object(SkRef(value)));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) {
|
|
||||||
return this->append(SkRef(key), SkRef(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) {
|
|
||||||
return this->append(new SkPDFName(key), SkRef(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkPDFDict::insertInt(const char key[], int32_t value) {
|
void SkPDFDict::insertInt(const char key[], int32_t value) {
|
||||||
(void)this->append(new SkPDFName(key), new SkPDFInt(value));
|
this->set(SkPDFUnion::Name(key), SkPDFUnion::Int(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkPDFDict::insertInt(const char key[], size_t value) {
|
||||||
|
this->insertInt(key, SkToS32(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFDict::insertScalar(const char key[], SkScalar value) {
|
void SkPDFDict::insertScalar(const char key[], SkScalar value) {
|
||||||
(void)this->append(new SkPDFName(key), new SkPDFScalar(value));
|
this->set(SkPDFUnion::Name(key), SkPDFUnion::Scalar(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFDict::insertName(const char key[], const char name[]) {
|
void SkPDFDict::insertName(const char key[], const char name[]) {
|
||||||
(void)this->append(new SkPDFName(key), new SkPDFName(name));
|
this->set(SkPDFUnion::Name(key), SkPDFUnion::Name(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkPDFDict::insertName(const char key[], const SkString& name) {
|
||||||
|
this->set(SkPDFUnion::Name(key), SkPDFUnion::Name(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkPDFDict::insertString(const char key[], const char value[]) {
|
||||||
|
this->set(SkPDFUnion::Name(key), SkPDFUnion::String(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkPDFDict::insertString(const char key[], const SkString& value) {
|
||||||
|
this->set(SkPDFUnion::Name(key), SkPDFUnion::String(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFDict::clear() {
|
void SkPDFDict::clear() {
|
||||||
for (int i = 0; i < fValue.count(); i++) {
|
for (Record& rec : fRecords) {
|
||||||
SkASSERT(fValue[i].key);
|
rec.fKey.~SkPDFUnion();
|
||||||
SkASSERT(fValue[i].value);
|
rec.fValue.~SkPDFUnion();
|
||||||
fValue[i].key->unref();
|
|
||||||
fValue[i].value->unref();
|
|
||||||
}
|
|
||||||
fValue.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkPDFDict::remove(const char key[]) {
|
|
||||||
SkASSERT(key);
|
|
||||||
SkPDFName name(key);
|
|
||||||
for (int i = 0; i < fValue.count(); i++) {
|
|
||||||
SkASSERT(fValue[i].key);
|
|
||||||
if (*(fValue[i].key) == name) {
|
|
||||||
fValue[i].key->unref();
|
|
||||||
SkASSERT(fValue[i].value);
|
|
||||||
fValue[i].value->unref();
|
|
||||||
fValue.removeShuffle(i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkPDFDict::mergeFrom(const SkPDFDict& other) {
|
|
||||||
for (int i = 0; i < other.fValue.count(); i++) {
|
|
||||||
*(fValue.append()) =
|
|
||||||
Rec(SkRef(other.fValue[i].key), SkRef(other.fValue[i].value));
|
|
||||||
}
|
}
|
||||||
|
fRecords.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2010 The Android Open Source Project
|
* Copyright 2010 The Android Open Source Project
|
||||||
*
|
*
|
||||||
@ -10,7 +9,6 @@
|
|||||||
#ifndef SkPDFTypes_DEFINED
|
#ifndef SkPDFTypes_DEFINED
|
||||||
#define SkPDFTypes_DEFINED
|
#define SkPDFTypes_DEFINED
|
||||||
|
|
||||||
#include "SkPDFTypes.h"
|
|
||||||
#include "SkRefCnt.h"
|
#include "SkRefCnt.h"
|
||||||
#include "SkScalar.h"
|
#include "SkScalar.h"
|
||||||
#include "SkString.h"
|
#include "SkString.h"
|
||||||
@ -28,10 +26,11 @@ class SkWStream;
|
|||||||
A PDF Object is the base class for primitive elements in a PDF file. A
|
A PDF Object is the base class for primitive elements in a PDF file. A
|
||||||
common subtype is used to ease the use of indirect object references,
|
common subtype is used to ease the use of indirect object references,
|
||||||
which are common in the PDF format.
|
which are common in the PDF format.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
class SkPDFObject : public SkRefCnt {
|
class SkPDFObject : public SkRefCnt {
|
||||||
public:
|
public:
|
||||||
SK_DECLARE_INST_COUNT(SkPDFObject)
|
SK_DECLARE_INST_COUNT(SkPDFObject);
|
||||||
|
|
||||||
/** Subclasses must implement this method to print the object to the
|
/** Subclasses must implement this method to print the object to the
|
||||||
* PDF file.
|
* PDF file.
|
||||||
@ -55,170 +54,191 @@ private:
|
|||||||
typedef SkRefCnt INHERITED;
|
typedef SkRefCnt INHERITED;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \class SkPDFObjRef
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
An indirect reference to a PDF object.
|
/**
|
||||||
*/
|
A SkPDFUnion is a non-virtualized implementation of the
|
||||||
class SkPDFObjRef : public SkPDFObject {
|
non-compound, non-specialized PDF Object types: Name, String,
|
||||||
|
Number, Boolean.
|
||||||
|
*/
|
||||||
|
class SkPDFUnion {
|
||||||
public:
|
public:
|
||||||
SK_DECLARE_INST_COUNT(SkPDFObjRef)
|
// u.move() is analogous to std::move(u). It returns an rvalue.
|
||||||
|
SkPDFUnion move() { return static_cast<SkPDFUnion&&>(*this); }
|
||||||
|
// Move contstructor and assignemnt operator destroy the argument
|
||||||
|
// and steal their references (if needed).
|
||||||
|
SkPDFUnion(SkPDFUnion&& other);
|
||||||
|
SkPDFUnion& operator=(SkPDFUnion&& other);
|
||||||
|
|
||||||
/** Create a reference to an existing SkPDFObject.
|
~SkPDFUnion();
|
||||||
* @param obj The object to reference.
|
|
||||||
*/
|
|
||||||
explicit SkPDFObjRef(SkPDFObject* obj);
|
|
||||||
virtual ~SkPDFObjRef();
|
|
||||||
|
|
||||||
// The SkPDFObject interface.
|
/** The following nine functions are the standard way of creating
|
||||||
virtual void emitObject(SkWStream* stream,
|
SkPDFUnion objects. */
|
||||||
const SkPDFObjNumMap& objNumMap,
|
|
||||||
const SkPDFSubstituteMap& substitutes) override;
|
static SkPDFUnion Int(int32_t);
|
||||||
virtual void addResources(SkPDFObjNumMap*,
|
|
||||||
const SkPDFSubstituteMap&) const override;
|
static SkPDFUnion Bool(bool);
|
||||||
|
|
||||||
|
static SkPDFUnion Scalar(SkScalar);
|
||||||
|
|
||||||
|
/** These two functions do NOT take ownership of ptr, and do NOT
|
||||||
|
copy the string. Suitable for passing in static const
|
||||||
|
strings. For example:
|
||||||
|
SkPDFUnion n = SkPDFUnion::Name("Length");
|
||||||
|
SkPDFUnion u = SkPDFUnion::String("Identity"); */
|
||||||
|
|
||||||
|
/** SkPDFUnion::Name(const char*) assumes that the passed string
|
||||||
|
is already a valid name (that is: it has no control or
|
||||||
|
whitespace characters). This will not copy the name. */
|
||||||
|
static SkPDFUnion Name(const char*);
|
||||||
|
|
||||||
|
/** SkPDFUnion::String will encode the passed string. This will
|
||||||
|
not copy the name. */
|
||||||
|
static SkPDFUnion String(const char*);
|
||||||
|
|
||||||
|
/** SkPDFUnion::Name(const SkString&) does not assume that the
|
||||||
|
passed string is already a valid name and it will escape the
|
||||||
|
string. */
|
||||||
|
static SkPDFUnion Name(const SkString&);
|
||||||
|
|
||||||
|
/** SkPDFUnion::String will encode the passed string. */
|
||||||
|
static SkPDFUnion String(const SkString&);
|
||||||
|
|
||||||
|
/** This function DOES take ownership of the object. E.g.
|
||||||
|
SkAutoTUnref<SkPDFDict> dict(new SkPDFDict);
|
||||||
|
dict->insert(.....);
|
||||||
|
SkPDFUnion u = SkPDFUnion::Object(dict.detach()) */
|
||||||
|
static SkPDFUnion Object(SkPDFObject*);
|
||||||
|
|
||||||
|
/** This function DOES take ownership of the object. E.g.
|
||||||
|
SkAutoTUnref<SkPDFBitmap> image(
|
||||||
|
SkPDFBitmap::Create(fCanon, bitmap));
|
||||||
|
SkPDFUnion u = SkPDFUnion::ObjRef(image.detach()) */
|
||||||
|
static SkPDFUnion ObjRef(SkPDFObject*);
|
||||||
|
|
||||||
|
/** These two non-virtual methods mirror SkPDFObject's
|
||||||
|
corresponding virtuals. */
|
||||||
|
void emitObject(SkWStream*,
|
||||||
|
const SkPDFObjNumMap&,
|
||||||
|
const SkPDFSubstituteMap&) const;
|
||||||
|
void addResources(SkPDFObjNumMap*, const SkPDFSubstituteMap&) const;
|
||||||
|
|
||||||
|
bool isName() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SkAutoTUnref<SkPDFObject> fObj;
|
union {
|
||||||
|
int32_t fIntValue;
|
||||||
|
bool fBoolValue;
|
||||||
|
SkScalar fScalarValue;
|
||||||
|
const char* fStaticString;
|
||||||
|
char fSkString[sizeof(SkString)];
|
||||||
|
SkPDFObject* fObject;
|
||||||
|
};
|
||||||
|
enum class Type : char {
|
||||||
|
/** It is an error to call emitObject() or addResources() on an
|
||||||
|
kDestroyed object. */
|
||||||
|
kDestroyed = 0,
|
||||||
|
kInt,
|
||||||
|
kBool,
|
||||||
|
kScalar,
|
||||||
|
kName,
|
||||||
|
kString,
|
||||||
|
kNameSkS,
|
||||||
|
kStringSkS,
|
||||||
|
kObjRef,
|
||||||
|
kObject,
|
||||||
|
};
|
||||||
|
Type fType;
|
||||||
|
|
||||||
|
SkPDFUnion(Type);
|
||||||
|
// We do not now need copy constructor and copy assignment, so we
|
||||||
|
// will disable this functionality.
|
||||||
|
SkPDFUnion& operator=(const SkPDFUnion&) = delete;
|
||||||
|
SkPDFUnion(const SkPDFUnion&) = delete;
|
||||||
|
};
|
||||||
|
SK_COMPILE_ASSERT(sizeof(SkString) == sizeof(void*), SkString_size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/** This class is a SkPDFUnion with SkPDFObject virtuals attached. */
|
||||||
|
// TODO(halcanary): 99% of the uses of this class should be
|
||||||
|
// transitioned to using a bare SkPDFUnion inside an array or dict.
|
||||||
|
class SkPDFAtom : public SkPDFObject {
|
||||||
|
public:
|
||||||
|
void emitObject(SkWStream* stream,
|
||||||
|
const SkPDFObjNumMap& objNumMap,
|
||||||
|
const SkPDFSubstituteMap& substitutes) final;
|
||||||
|
void addResources(SkPDFObjNumMap*, const SkPDFSubstituteMap&) const final;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SkPDFAtom(SkPDFUnion&& v) : fValue(v.move()) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const SkPDFUnion fValue;
|
||||||
typedef SkPDFObject INHERITED;
|
typedef SkPDFObject INHERITED;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \class SkPDFInt
|
/** The following six classes exist only to ease transition to SkPDFUnion. */
|
||||||
|
class SkPDFObjRef : public SkPDFAtom {
|
||||||
An integer object in a PDF.
|
|
||||||
*/
|
|
||||||
class SkPDFInt : public SkPDFObject {
|
|
||||||
public:
|
public:
|
||||||
SK_DECLARE_INST_COUNT(SkPDFInt)
|
SK_DECLARE_INST_COUNT(SkPDFObjRef);
|
||||||
|
explicit SkPDFObjRef(SkPDFObject* obj)
|
||||||
/** Create a PDF integer (usually for indirect reference purposes).
|
: INHERITED(SkPDFUnion::ObjRef(SkRef(obj))) {}
|
||||||
* @param value An integer value between 2^31 - 1 and -2^31.
|
typedef SkPDFAtom INHERITED;
|
||||||
*/
|
|
||||||
explicit SkPDFInt(int32_t value);
|
|
||||||
virtual ~SkPDFInt();
|
|
||||||
|
|
||||||
// The SkPDFObject interface.
|
|
||||||
virtual void emitObject(SkWStream* stream,
|
|
||||||
const SkPDFObjNumMap& objNumMap,
|
|
||||||
const SkPDFSubstituteMap& substitutes) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int32_t fValue;
|
|
||||||
|
|
||||||
typedef SkPDFObject INHERITED;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \class SkPDFBool
|
class SkPDFInt : public SkPDFAtom {
|
||||||
|
|
||||||
An boolean value in a PDF.
|
|
||||||
*/
|
|
||||||
class SkPDFBool : public SkPDFObject {
|
|
||||||
public:
|
public:
|
||||||
SK_DECLARE_INST_COUNT(SkPDFBool)
|
SK_DECLARE_INST_COUNT(SkPDFInt);
|
||||||
|
explicit SkPDFInt(int32_t value) : INHERITED(SkPDFUnion::Int(value)) {}
|
||||||
/** Create a PDF boolean.
|
typedef SkPDFAtom INHERITED;
|
||||||
* @param value true or false.
|
|
||||||
*/
|
|
||||||
explicit SkPDFBool(bool value);
|
|
||||||
virtual ~SkPDFBool();
|
|
||||||
|
|
||||||
// The SkPDFObject interface.
|
|
||||||
virtual void emitObject(SkWStream* stream,
|
|
||||||
const SkPDFObjNumMap& objNumMap,
|
|
||||||
const SkPDFSubstituteMap& substitutes) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool fValue;
|
|
||||||
|
|
||||||
typedef SkPDFObject INHERITED;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \class SkPDFScalar
|
class SkPDFBool : public SkPDFAtom {
|
||||||
|
|
||||||
A real number object in a PDF.
|
|
||||||
*/
|
|
||||||
class SkPDFScalar : public SkPDFObject {
|
|
||||||
public:
|
public:
|
||||||
SK_DECLARE_INST_COUNT(SkPDFScalar)
|
SK_DECLARE_INST_COUNT(SkPDFBool);
|
||||||
|
explicit SkPDFBool(bool value) : INHERITED(SkPDFUnion::Bool(value)) {}
|
||||||
/** Create a PDF real number.
|
typedef SkPDFAtom INHERITED;
|
||||||
* @param value A real value.
|
};
|
||||||
*/
|
|
||||||
explicit SkPDFScalar(SkScalar value);
|
|
||||||
virtual ~SkPDFScalar();
|
|
||||||
|
|
||||||
|
class SkPDFScalar : public SkPDFAtom {
|
||||||
|
public:
|
||||||
|
SK_DECLARE_INST_COUNT(SkPDFScalar);
|
||||||
|
explicit SkPDFScalar(SkScalar value)
|
||||||
|
: INHERITED(SkPDFUnion::Scalar(value)) {}
|
||||||
static void Append(SkScalar value, SkWStream* stream);
|
static void Append(SkScalar value, SkWStream* stream);
|
||||||
|
typedef SkPDFAtom INHERITED;
|
||||||
// The SkPDFObject interface.
|
|
||||||
virtual void emitObject(SkWStream* stream,
|
|
||||||
const SkPDFObjNumMap& objNumMap,
|
|
||||||
const SkPDFSubstituteMap& substitutes) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
SkScalar fValue;
|
|
||||||
|
|
||||||
typedef SkPDFObject INHERITED;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \class SkPDFString
|
class SkPDFString : public SkPDFAtom {
|
||||||
|
|
||||||
A string object in a PDF.
|
|
||||||
*/
|
|
||||||
class SkPDFString : public SkPDFObject {
|
|
||||||
public:
|
public:
|
||||||
SK_DECLARE_INST_COUNT(SkPDFString)
|
SK_DECLARE_INST_COUNT(SkPDFString);
|
||||||
|
explicit SkPDFString(const char value[])
|
||||||
/** Create a PDF string. Maximum length (in bytes) is 65,535.
|
: INHERITED(SkPDFUnion::String(value)) {}
|
||||||
* @param value A string value.
|
explicit SkPDFString(const SkString& value)
|
||||||
*/
|
: INHERITED(SkPDFUnion::String(value)) {}
|
||||||
explicit SkPDFString(const char value[]);
|
|
||||||
explicit SkPDFString(const SkString& value);
|
|
||||||
|
|
||||||
virtual ~SkPDFString();
|
|
||||||
|
|
||||||
// The SkPDFObject interface.
|
|
||||||
virtual void emitObject(SkWStream* stream,
|
|
||||||
const SkPDFObjNumMap& objNumMap,
|
|
||||||
const SkPDFSubstituteMap& substitutes) override;
|
|
||||||
|
|
||||||
static SkString FormatString(const char* input, size_t len);
|
static SkString FormatString(const char* input, size_t len);
|
||||||
private:
|
|
||||||
static const size_t kMaxLen = 65535;
|
static const size_t kMaxLen = 65535;
|
||||||
|
|
||||||
const SkString fValue;
|
private:
|
||||||
|
typedef SkPDFAtom INHERITED;
|
||||||
typedef SkPDFObject INHERITED;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \class SkPDFName
|
class SkPDFName : public SkPDFAtom {
|
||||||
|
|
||||||
A name object in a PDF.
|
|
||||||
*/
|
|
||||||
class SkPDFName : public SkPDFObject {
|
|
||||||
public:
|
public:
|
||||||
SK_DECLARE_INST_COUNT(SkPDFName)
|
SK_DECLARE_INST_COUNT(SkPDFName);
|
||||||
|
/** Create a PDF name object. Maximum length is 127 bytes. */
|
||||||
|
explicit SkPDFName(const char name[])
|
||||||
|
: INHERITED(SkPDFUnion::Name(SkString(name))) {}
|
||||||
|
explicit SkPDFName(const SkString& name)
|
||||||
|
: INHERITED(SkPDFUnion::Name(name)) {}
|
||||||
|
|
||||||
/** Create a PDF name object. Maximum length is 127 bytes.
|
|
||||||
* @param value The name.
|
|
||||||
*/
|
|
||||||
explicit SkPDFName(const char name[]);
|
|
||||||
explicit SkPDFName(const SkString& name);
|
|
||||||
virtual ~SkPDFName();
|
|
||||||
|
|
||||||
bool operator==(const SkPDFName& b) const;
|
|
||||||
|
|
||||||
// The SkPDFObject interface.
|
|
||||||
virtual void emitObject(SkWStream* stream,
|
|
||||||
const SkPDFObjNumMap& objNumMap,
|
|
||||||
const SkPDFSubstituteMap& substitutes) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const size_t kMaxLen = 127;
|
static const size_t kMaxLen = 127;
|
||||||
|
|
||||||
const SkString fValue;
|
private:
|
||||||
|
typedef SkPDFAtom INHERITED;
|
||||||
static SkString FormatName(const SkString& input);
|
|
||||||
|
|
||||||
typedef SkPDFObject INHERITED;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \class SkPDFArray
|
/** \class SkPDFArray
|
||||||
@ -229,6 +249,8 @@ class SkPDFArray : public SkPDFObject {
|
|||||||
public:
|
public:
|
||||||
SK_DECLARE_INST_COUNT(SkPDFArray)
|
SK_DECLARE_INST_COUNT(SkPDFArray)
|
||||||
|
|
||||||
|
static const int kMaxLen = 8191;
|
||||||
|
|
||||||
/** Create a PDF array. Maximum length is 8191.
|
/** Create a PDF array. Maximum length is 8191.
|
||||||
*/
|
*/
|
||||||
SkPDFArray();
|
SkPDFArray();
|
||||||
@ -243,7 +265,7 @@ public:
|
|||||||
|
|
||||||
/** The size of the array.
|
/** The size of the array.
|
||||||
*/
|
*/
|
||||||
int size() { return fValue.count(); }
|
int size() const;
|
||||||
|
|
||||||
/** Preallocate space for the given number of entries.
|
/** Preallocate space for the given number of entries.
|
||||||
* @param length The number of array slots to preallocate.
|
* @param length The number of array slots to preallocate.
|
||||||
@ -254,27 +276,26 @@ public:
|
|||||||
* @param value The value to add to the array.
|
* @param value The value to add to the array.
|
||||||
* @return The value argument is returned.
|
* @return The value argument is returned.
|
||||||
*/
|
*/
|
||||||
|
// DEPRECATED
|
||||||
SkPDFObject* append(SkPDFObject* value);
|
SkPDFObject* append(SkPDFObject* value);
|
||||||
|
|
||||||
/** Creates a SkPDFInt object and appends it to the array.
|
/** Appends a value to the end of the array.
|
||||||
* @param value The value to add to the array.
|
* @param value The value to add to the array.
|
||||||
*/
|
*/
|
||||||
void appendInt(int32_t value);
|
void appendInt(int32_t);
|
||||||
|
void appendBool(bool);
|
||||||
/** Creates a SkPDFScalar object and appends it to the array.
|
void appendScalar(SkScalar);
|
||||||
* @param value The value to add to the array.
|
void appendName(const char[]);
|
||||||
*/
|
void appendName(const SkString&);
|
||||||
void appendScalar(SkScalar value);
|
void appendString(const char[]);
|
||||||
|
void appendString(const SkString&);
|
||||||
/** Creates a SkPDFName object and appends it to the array.
|
/** appendObject and appendObjRef take ownership of the passed object */
|
||||||
* @param value The value to add to the array.
|
void appendObject(SkPDFObject*);
|
||||||
*/
|
void appendObjRef(SkPDFObject*);
|
||||||
void appendName(const char name[]);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int kMaxLen = 8191;
|
SkTDArray<SkPDFUnion> fValues;
|
||||||
SkTDArray<SkPDFObject*> fValue;
|
void append(SkPDFUnion&& value);
|
||||||
|
|
||||||
typedef SkPDFObject INHERITED;
|
typedef SkPDFObject INHERITED;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -313,104 +334,53 @@ public:
|
|||||||
* @param value The value for this dictionary entry.
|
* @param value The value for this dictionary entry.
|
||||||
* @return The value argument is returned.
|
* @return The value argument is returned.
|
||||||
*/
|
*/
|
||||||
|
// DEPRECATED
|
||||||
SkPDFObject* insert(SkPDFName* key, SkPDFObject* value);
|
SkPDFObject* insert(SkPDFName* key, SkPDFObject* value);
|
||||||
|
// DEPRECATED
|
||||||
/** Add the value to the dictionary with the given key. Refs value. The
|
|
||||||
* method will create the SkPDFName object.
|
|
||||||
* @param key The text of the key for this dictionary entry.
|
|
||||||
* @param value The value for this dictionary entry.
|
|
||||||
* @return The value argument is returned.
|
|
||||||
*/
|
|
||||||
SkPDFObject* insert(const char key[], SkPDFObject* value);
|
SkPDFObject* insert(const char key[], SkPDFObject* value);
|
||||||
|
|
||||||
/** Add the int to the dictionary with the given key.
|
/** Add the value to the dictionary with the given key. Takes
|
||||||
|
* ownership of the object.
|
||||||
* @param key The text of the key for this dictionary entry.
|
* @param key The text of the key for this dictionary entry.
|
||||||
* @param value The int value for this dictionary entry.
|
* @param value The value for this dictionary entry.
|
||||||
|
*/
|
||||||
|
void insertObject(const char key[], SkPDFObject* value);
|
||||||
|
void insertObject(const SkString& key, SkPDFObject* value);
|
||||||
|
void insertObjRef(const char key[], SkPDFObject* value);
|
||||||
|
void insertObjRef(const SkString& key, SkPDFObject* value);
|
||||||
|
|
||||||
|
/** Add the value to the dictionary with the given key.
|
||||||
|
* @param key The text of the key for this dictionary entry.
|
||||||
|
* @param value The value for this dictionary entry.
|
||||||
*/
|
*/
|
||||||
void insertInt(const char key[], int32_t value);
|
void insertInt(const char key[], int32_t value);
|
||||||
|
void insertInt(const char key[], size_t value);
|
||||||
/**
|
|
||||||
* Calls insertInt() but asserts in debug builds that the value can be represented
|
|
||||||
* by an int32_t.
|
|
||||||
*/
|
|
||||||
void insertInt(const char key[], size_t value) {
|
|
||||||
this->insertInt(key, SkToS32(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add the scalar to the dictionary with the given key.
|
|
||||||
* @param key The text of the key for this dictionary entry.
|
|
||||||
* @param value The scalar value for this dictionary entry.
|
|
||||||
*/
|
|
||||||
void insertScalar(const char key[], SkScalar value);
|
void insertScalar(const char key[], SkScalar value);
|
||||||
|
void insertName(const char key[], const char nameValue[]);
|
||||||
/** Add the name to the dictionary with the given key.
|
void insertName(const char key[], const SkString& nameValue);
|
||||||
* @param key The text of the key for this dictionary entry.
|
void insertString(const char key[], const char value[]);
|
||||||
* @param name The name for this dictionary entry.
|
void insertString(const char key[], const SkString& value);
|
||||||
*/
|
|
||||||
void insertName(const char key[], const char name[]);
|
|
||||||
|
|
||||||
/** Add the name to the dictionary with the given key.
|
|
||||||
* @param key The text of the key for this dictionary entry.
|
|
||||||
* @param name The name for this dictionary entry.
|
|
||||||
*/
|
|
||||||
void insertName(const char key[], const SkString& name) {
|
|
||||||
this->insertName(key, name.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Remove all entries from the dictionary.
|
/** Remove all entries from the dictionary.
|
||||||
*/
|
*/
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
protected:
|
|
||||||
/** Use to remove a single key from the dictionary.
|
|
||||||
*/
|
|
||||||
void remove(const char key[]);
|
|
||||||
|
|
||||||
/** Insert references to all of the key-value pairs from the other
|
|
||||||
* dictionary into this one.
|
|
||||||
*/
|
|
||||||
void mergeFrom(const SkPDFDict& other);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Rec {
|
struct Record {
|
||||||
SkPDFName* key;
|
SkPDFUnion fKey;
|
||||||
SkPDFObject* value;
|
SkPDFUnion fValue;
|
||||||
Rec(SkPDFName* k, SkPDFObject* v) : key(k), value(v) {}
|
|
||||||
};
|
};
|
||||||
|
SkTDArray<Record> fRecords;
|
||||||
static const int kMaxLen = 4095;
|
static const int kMaxLen = 4095;
|
||||||
|
|
||||||
SkTDArray<struct Rec> fValue;
|
void set(const SkPDFUnion& name, const SkPDFUnion& value);
|
||||||
|
void set(SkPDFUnion&& name, SkPDFUnion&& value);
|
||||||
SkPDFObject* append(SkPDFName* key, SkPDFObject* value);
|
|
||||||
|
|
||||||
typedef SkPDFObject INHERITED;
|
typedef SkPDFObject INHERITED;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/** \class SkPDFSubstituteMap
|
|
||||||
|
|
||||||
The PDF Substitute Map manages substitute objects and owns the
|
|
||||||
substitutes.
|
|
||||||
*/
|
|
||||||
class SkPDFSubstituteMap : SkNoncopyable {
|
|
||||||
public:
|
|
||||||
~SkPDFSubstituteMap();
|
|
||||||
/** Set substitute object for the passed object.
|
|
||||||
Refs substitute.
|
|
||||||
*/
|
|
||||||
void setSubstitute(SkPDFObject* original, SkPDFObject* substitute);
|
|
||||||
|
|
||||||
/** Find and return any substitute object set for the passed object. If
|
|
||||||
* there is none, return the passed object.
|
|
||||||
*/
|
|
||||||
SkPDFObject* getSubstitute(SkPDFObject* object) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
SkTHashMap<SkPDFObject*, SkPDFObject*> fSubstituteMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \class SkPDFObjNumMap
|
/** \class SkPDFObjNumMap
|
||||||
|
|
||||||
The PDF Object Number Map manages object numbers. It is used to
|
The PDF Object Number Map manages object numbers. It is used to
|
||||||
@ -436,4 +406,32 @@ private:
|
|||||||
SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers;
|
SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/** \class SkPDFSubstituteMap
|
||||||
|
|
||||||
|
The PDF Substitute Map manages substitute objects and owns the
|
||||||
|
substitutes.
|
||||||
|
*/
|
||||||
|
class SkPDFSubstituteMap : SkNoncopyable {
|
||||||
|
public:
|
||||||
|
~SkPDFSubstituteMap();
|
||||||
|
/** Set substitute object for the passed object.
|
||||||
|
Refs substitute.
|
||||||
|
*/
|
||||||
|
void setSubstitute(SkPDFObject* original, SkPDFObject* substitute);
|
||||||
|
|
||||||
|
/** Find and return any substitute object set for the passed object. If
|
||||||
|
* there is none, return the passed object.
|
||||||
|
*/
|
||||||
|
SkPDFObject* getSubstitute(SkPDFObject* object) const;
|
||||||
|
|
||||||
|
SkPDFObject* operator()(SkPDFObject* o) const {
|
||||||
|
return this->getSubstitute(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SkTHashMap<SkPDFObject*, SkPDFObject*> fSubstituteMap;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -69,8 +69,12 @@ static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj,
|
|||||||
SkDynamicMemoryWStream buffer;
|
SkDynamicMemoryWStream buffer;
|
||||||
emit_object(obj, &buffer, catalog, substituteMap, false);
|
emit_object(obj, &buffer, catalog, substituteMap, false);
|
||||||
REPORTER_ASSERT(reporter, directSize == buffer.getOffset());
|
REPORTER_ASSERT(reporter, directSize == buffer.getOffset());
|
||||||
REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedData,
|
if (!stream_equals(buffer, 0, expectedData, directSize)) {
|
||||||
directSize));
|
SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
|
||||||
|
SkString s(asset->getLength());
|
||||||
|
asset->read(s.writable_str(), s.size());
|
||||||
|
ERRORF(reporter, "!stream_equals() '%s' '%s'", expectedData, s.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
if (indirect) {
|
if (indirect) {
|
||||||
// Indirect output.
|
// Indirect output.
|
||||||
@ -272,13 +276,11 @@ DEF_TEST(PDFPrimitives, reporter) {
|
|||||||
|
|
||||||
SkAutoTUnref<SkPDFDict> dict(new SkPDFDict);
|
SkAutoTUnref<SkPDFDict> dict(new SkPDFDict);
|
||||||
SimpleCheckObjectOutput(reporter, dict.get(), "<<>>");
|
SimpleCheckObjectOutput(reporter, dict.get(), "<<>>");
|
||||||
SkAutoTUnref<SkPDFName> n1(new SkPDFName("n1"));
|
dict->insert("n1", int42.get());
|
||||||
dict->insert(n1.get(), int42.get());
|
|
||||||
SimpleCheckObjectOutput(reporter, dict.get(), "<</n1 42>>");
|
SimpleCheckObjectOutput(reporter, dict.get(), "<</n1 42>>");
|
||||||
SkAutoTUnref<SkPDFName> n2(new SkPDFName("n2"));
|
SkString n3("n3");
|
||||||
SkAutoTUnref<SkPDFName> n3(new SkPDFName("n3"));
|
dict->insert("n2", realHalf.get());
|
||||||
dict->insert(n2.get(), realHalf.get());
|
dict->insertObject(n3, array.detach());
|
||||||
dict->insert(n3.get(), array.get());
|
|
||||||
SimpleCheckObjectOutput(reporter, dict.get(),
|
SimpleCheckObjectOutput(reporter, dict.get(),
|
||||||
"<</n1 42\n/n2 0.5\n/n3 [42 0.5 0]>>");
|
"<</n1 42\n/n2 0.5\n/n3 [42 0.5 0]>>");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user