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:
halcanary 2015-04-25 06:45:07 -07:00 committed by Commit bot
parent 8e71d38126
commit 130444fdaf
7 changed files with 607 additions and 447 deletions

View File

@ -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.
} }

View File

@ -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());
} }
} }

View File

@ -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();

View File

@ -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);

View File

@ -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();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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]>>");