// one child.
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.
SkTDArray<SkPDFDict*> curNodes;
curNodes.setReserve(pages.count());
int count = 0;
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();
// TODO(vandebo): put the objects in strict access order.
if (i == curNodes.count()) {
pageCount = ((pages.count() - 1) % treeCapacity) + 1;
}
- newNode->insert(countName.get(), new SkPDFInt(pageCount))->unref();
- newNode->insert(kidsName.get(), kids.get());
+ newNode->insert("Count", new SkPDFInt(pageCount))->unref();
+ newNode->insert("Kids", kids.get());
nextRoundNodes.push(newNode); // Transfer reference.
}
SkPDFArray* SkPDFDevice::copyMediaBox() const {
// 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->append(zero.get());
- mediaBox->append(zero.get());
+ mediaBox->appendInt(0);
+ mediaBox->appendInt(0);
mediaBox->appendInt(fPageSize.fWidth);
mediaBox->appendInt(fPageSize.fHeight);
- return mediaBox;
+ return mediaBox.detach();
}
SkStreamAsset* SkPDFDevice::content() const {
urlData->size() - 1);
SkAutoTUnref<SkPDFDict> action(SkNEW_ARGS(SkPDFDict, ("Action")));
action->insertName("S", "URI");
- action->insert("URI", SkNEW_ARGS(SkPDFString, (url)))->unref();
+ action->insertString("URI", url);
annotation->insert("A", action.get());
}
SkAutoTUnref<SkPDFDict> annotation(createLinkAnnotation(r, matrix));
SkString name(static_cast<const char *>(nameData->data()),
nameData->size() - 1);
- annotation->insert("Dest", SkNEW_ARGS(SkPDFName, (name)))->unref();
+ annotation->insertName("Dest", name);
}
struct NamedDestination {
SkPoint point;
NamedDestination(const SkData* nameData, const SkPoint& point)
- : nameData(nameData), point(point) {
- nameData->ref();
- }
+ : nameData(SkRef(nameData)), point(point) {}
~NamedDestination() {
nameData->unref();
NamedDestination* dest = fNamedDestinations[i];
SkAutoTUnref<SkPDFArray> pdfDest(SkNEW(SkPDFArray));
pdfDest->reserve(5);
- pdfDest->append(SkNEW_ARGS(SkPDFObjRef, (page)))->unref();
+ pdfDest->appendObjRef(SkRef(page));
pdfDest->appendName("XYZ");
pdfDest->appendScalar(dest->point.x());
pdfDest->appendScalar(dest->point.y());
pdfDest->appendInt(0); // Leave zoom unchanged
- dict->insert(static_cast<const char *>(dest->nameData->data()),
- pdfDest);
+ SkString name(static_cast<const char*>(dest->nameData->data()));
+ dict->insertObject(name, pdfDest.detach());
}
}
SkAutoTDelete<SkMemoryStream> glyphStream(new SkMemoryStream());
glyphStream->setData(content.copyToData())->unref();
- SkAutoTUnref<SkPDFStream> glyphDescription(
- new SkPDFStream(glyphStream.get()));
- charProcs->insert(characterName.c_str(),
- new SkPDFObjRef(glyphDescription.get()))->unref();
+ charProcs->insertObjRef(characterName,
+ new SkPDFStream(glyphStream.get()));
}
insert("FontBBox", makeFontBBox(bbox, 1000))->unref();
static const char* get_resource_type_name(
SkPDFResourceDict::SkPDFResourceType type) {
SkASSERT(type >= 0);
- SkASSERT(type < SkPDFResourceDict::kResourceTypeCount);
+ SkASSERT(type < SK_ARRAY_COUNT(resource_type_names));
return resource_type_names[type];
}
}
SkAutoTUnref<SkPDFDict> resources(SkNEW(SkPDFDict));
for (int i = 0; i < resourceList.count(); i++) {
- SkString keyString = SkPDFResourceDict::getResourceName(type, i);
- SkAutoTUnref<SkPDFName> keyName(SkNEW_ARGS(SkPDFName, (keyString)));
- SkAutoTUnref<SkPDFObjRef> ref(
- SkNEW_ARGS(SkPDFObjRef, (resourceList[i])));
- resources->insert(keyName, ref);
+ resources->insertObjRef(SkPDFResourceDict::getResourceName(type, i),
+ SkRef(resourceList[i]));
}
- dst->insert(get_resource_type_name(type), resources);
+ dst->insertObject(get_resource_type_name(type), resources.detach());
}
SkPDFDict* SkPDFResourceDict::Create(
for (size_t i = 0; i < SK_ARRAY_COUNT(kProcs); i++) {
procSets->appendName(kProcs[i]);
}
- dict->insert("ProcSets", procSets);
+ dict->insertObject("ProcSets", procSets.detach());
if (gStateResources) {
add_subdict(*gStateResources, kExtGState_ResourceType, dict);
* found in the LICENSE file.
*/
-
#include "SkPDFTypes.h"
#include "SkStream.h"
////////////////////////////////////////////////////////////////////////////////
-SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {
- SkSafeRef(obj);
+SkString* pun(char* x) { return reinterpret_cast<SkString*>(x); }
+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,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) {
- SkPDFObject* obj = substitutes.getSubstitute(fObj);
- stream->writeDecAsText(objNumMap.getObjectNumber(obj));
- stream->writeText(" 0 R"); // Generation number is always 0.
+SkPDFUnion::~SkPDFUnion() {
+ switch (fType) {
+ case Type::kNameSkS:
+ case Type::kStringSkS:
+ pun(fSkString)->~SkString();
+ return;
+ case Type::kObjRef:
+ case Type::kObject:
+ SkSafeUnref(fObject);
+ return;
+ default:
+ return;
+ }
}
-void SkPDFObjRef::addResources(SkPDFObjNumMap* catalog,
- const SkPDFSubstituteMap& substitutes) const {
- SkPDFObject* obj = substitutes.getSubstitute(fObj);
- SkASSERT(obj);
- 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;
+}
+
+SkPDFUnion::SkPDFUnion(SkPDFUnion&& other) {
+ SkASSERT(this != &other);
+ memcpy(this, &other, sizeof(*this));
+ other.fType = Type::kDestroyed;
+}
+
+#if 0
+SkPDFUnion SkPDFUnion::copy() const {
+ SkPDFUnion u(fType);
+ 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;
+}
-SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {}
-SkPDFInt::~SkPDFInt() {}
+#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
-void SkPDFInt::emitObject(SkWStream* stream,
- const SkPDFObjNumMap&,
- const SkPDFSubstituteMap&) {
- stream->writeDecAsText(fValue);
+// 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());
+}
-SkPDFBool::SkPDFBool(bool value) : fValue(value) {}
-SkPDFBool::~SkPDFBool() {}
+static void write_string(SkWStream* o, const SkString& s) {
+ o->write(s.c_str(), s.size());
+}
-void SkPDFBool::emitObject(SkWStream* stream,
- const SkPDFObjNumMap&,
- const SkPDFSubstituteMap&) {
- stream->writeText(fValue ? "true" : "false");
+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));
+}
-SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {}
-SkPDFScalar::~SkPDFScalar() {}
+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();
+}
-void SkPDFScalar::emitObject(SkWStream* stream,
- const SkPDFObjNumMap&,
- const SkPDFSubstituteMap&) {
- SkPDFScalar::Append(fValue, stream);
+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();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void SkPDFAtom::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) {
+ fValue.emitObject(stream, objNumMap, substitutes);
+}
+void SkPDFAtom::addResources(SkPDFObjNumMap* map,
+ const SkPDFSubstituteMap& substitutes) const {
+ fValue.addResources(map, substitutes);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
// static
void SkPDFScalar::Append(SkScalar value, SkWStream* stream) {
// The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and
////////////////////////////////////////////////////////////////////////////////
-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
+
SkString SkPDFString::FormatString(const char* cin, size_t len) {
SkASSERT(len <= kMaxLen);
////////////////////////////////////////////////////////////////////////////////
-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);
- }
+SkPDFArray::SkPDFArray() {}
+SkPDFArray::~SkPDFArray() {
+ for (SkPDFUnion& value : fValues) {
+ value.~SkPDFUnion();
}
-
- return result;
+ fValues.reset();
}
-////////////////////////////////////////////////////////////////////////////////
+int SkPDFArray::size() const { return fValues.count(); }
-SkPDFArray::SkPDFArray() {}
-SkPDFArray::~SkPDFArray() {
- fValue.unrefAll();
-}
+void SkPDFArray::reserve(int length) { fValues.setReserve(length); }
void SkPDFArray::emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) {
stream->writeText("[");
- for (int i = 0; i < fValue.count(); i++) {
- SkASSERT(substitutes.getSubstitute(fValue[i]) == fValue[i]);
- fValue[i]->emitObject(stream, objNumMap, substitutes);
- if (i + 1 < fValue.count()) {
+ for (int i = 0; i < fValues.count(); i++) {
+ fValues[i].emitObject(stream, objNumMap, substitutes);
+ if (i + 1 < fValues.count()) {
stream->writeText(" ");
}
}
void SkPDFArray::addResources(SkPDFObjNumMap* catalog,
const SkPDFSubstituteMap& substitutes) const {
- for (int i = 0; i < fValue.count(); i++) {
- SkASSERT(substitutes.getSubstitute(fValue[i]) == fValue[i]);
- fValue[i]->addResources(catalog, substitutes);
+ for (const SkPDFUnion& value : fValues) {
+ value.addResources(catalog, substitutes);
}
}
-void SkPDFArray::reserve(int length) {
- SkASSERT(length <= kMaxLen);
- fValue.setReserve(length);
+void SkPDFArray::append(SkPDFUnion&& value) {
+ SkNEW_PLACEMENT_ARGS(fValues.append(), SkPDFUnion, (value.move()));
}
SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
- SkASSERT(fValue.count() < kMaxLen);
- value->ref();
- fValue.push(value);
+ // DEPRECATED
+ this->append(SkPDFUnion::Object(SkRef(value)));
return value;
}
void SkPDFArray::appendInt(int32_t value) {
- SkASSERT(fValue.count() < kMaxLen);
- fValue.push(new SkPDFInt(value));
+ this->append(SkPDFUnion::Int(value));
+}
+
+void SkPDFArray::appendBool(bool value) {
+ this->append(SkPDFUnion::Bool(value));
}
void SkPDFArray::appendScalar(SkScalar value) {
- SkASSERT(fValue.count() < kMaxLen);
- fValue.push(new SkPDFScalar(value));
+ this->append(SkPDFUnion::Scalar(value));
}
void SkPDFArray::appendName(const char name[]) {
- SkASSERT(fValue.count() < kMaxLen);
- fValue.push(new SkPDFName(name));
+ this->append(SkPDFUnion::Name(SkString(name)));
}
-///////////////////////////////////////////////////////////////////////////////
+void SkPDFArray::appendName(const SkString& name) {
+ this->append(SkPDFUnion::Name(name));
+}
-SkPDFDict::SkPDFDict() {}
+void SkPDFArray::appendString(const SkString& value) {
+ this->append(SkPDFUnion::String(value));
+}
-SkPDFDict::SkPDFDict(const char type[]) {
- insertName("Type", type);
+void SkPDFArray::appendString(const char value[]) {
+ this->append(SkPDFUnion::String(value));
}
-SkPDFDict::~SkPDFDict() {
- clear();
+void SkPDFArray::appendObject(SkPDFObject* value) {
+ this->append(SkPDFUnion::Object(value));
}
-int SkPDFDict::size() const {
- return fValue.count();
+void SkPDFArray::appendObjRef(SkPDFObject* value) {
+ this->append(SkPDFUnion::ObjRef(value));
}
+///////////////////////////////////////////////////////////////////////////////
+
+SkPDFDict::SkPDFDict() {}
+
+SkPDFDict::~SkPDFDict() { this->clear(); }
+
+SkPDFDict::SkPDFDict(const char type[]) { this->insertName("Type", type); }
+
void SkPDFDict::emitObject(SkWStream* stream,
const SkPDFObjNumMap& objNumMap,
const SkPDFSubstituteMap& substitutes) {
stream->writeText("<<");
- for (int i = 0; i < fValue.count(); i++) {
- SkASSERT(fValue[i].key);
- 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);
+ for (int i = 0; i < fRecords.count(); i++) {
+ fRecords[i].fKey.emitObject(stream, objNumMap, substitutes);
stream->writeText(" ");
- fValue[i].value->emitObject(stream, objNumMap, substitutes);
- if (i + 1 < fValue.count()) {
+ fRecords[i].fValue.emitObject(stream, objNumMap, substitutes);
+ if (i + 1 < fRecords.count()) {
stream->writeText("\n");
}
}
void SkPDFDict::addResources(SkPDFObjNumMap* catalog,
const SkPDFSubstituteMap& substitutes) const {
- for (int i = 0; i < fValue.count(); i++) {
- SkASSERT(fValue[i].key);
- SkASSERT(fValue[i].value);
- fValue[i].key->addResources(catalog, substitutes);
- SkASSERT(substitutes.getSubstitute(fValue[i].value) == fValue[i].value);
- fValue[i].value->addResources(catalog, substitutes);
+ for (int i = 0; i < fRecords.count(); i++) {
+ fRecords[i].fKey.addResources(catalog, substitutes);
+ fRecords[i].fValue.addResources(catalog, substitutes);
}
}
-SkPDFObject* SkPDFDict::append(SkPDFName* key, SkPDFObject* value) {
- SkASSERT(key);
- SkASSERT(value);
- *(fValue.append()) = Rec(key, value);
- return value;
+void SkPDFDict::set(SkPDFUnion&& name, SkPDFUnion&& value) {
+ Record* rec = fRecords.append();
+ SkASSERT(name.isName());
+ 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));
}
-SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) {
- return this->append(SkRef(key), SkRef(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) {
- return this->append(new SkPDFName(key), SkRef(value));
+ this->set(SkPDFUnion::Name(key), SkPDFUnion::Object(SkRef(value)));
+ return 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)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)this->append(new SkPDFName(key), new SkPDFName(name));
+ this->set(SkPDFUnion::Name(key), SkPDFUnion::Name(name));
}
-void SkPDFDict::clear() {
- for (int i = 0; i < fValue.count(); i++) {
- SkASSERT(fValue[i].key);
- SkASSERT(fValue[i].value);
- 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::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::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));
+void SkPDFDict::clear() {
+ for (Record& rec : fRecords) {
+ rec.fKey.~SkPDFUnion();
+ rec.fValue.~SkPDFUnion();
}
+ fRecords.reset();
}
////////////////////////////////////////////////////////////////////////////////
-
/*
* Copyright 2010 The Android Open Source Project
*
#ifndef SkPDFTypes_DEFINED
#define SkPDFTypes_DEFINED
-#include "SkPDFTypes.h"
#include "SkRefCnt.h"
#include "SkScalar.h"
#include "SkString.h"
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,
which are common in the PDF format.
+
*/
class SkPDFObject : public SkRefCnt {
public:
- SK_DECLARE_INST_COUNT(SkPDFObject)
+ SK_DECLARE_INST_COUNT(SkPDFObject);
/** Subclasses must implement this method to print the object to the
* PDF file.
typedef SkRefCnt INHERITED;
};
-/** \class SkPDFObjRef
+////////////////////////////////////////////////////////////////////////////////
- An indirect reference to a PDF object.
-*/
-class SkPDFObjRef : public SkPDFObject {
+/**
+ A SkPDFUnion is a non-virtualized implementation of the
+ non-compound, non-specialized PDF Object types: Name, String,
+ Number, Boolean.
+ */
+class SkPDFUnion {
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.
- * @param obj The object to reference.
- */
- explicit SkPDFObjRef(SkPDFObject* obj);
- virtual ~SkPDFObjRef();
+ ~SkPDFUnion();
- // The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) override;
- virtual void addResources(SkPDFObjNumMap*,
- const SkPDFSubstituteMap&) const override;
+ /** The following nine functions are the standard way of creating
+ SkPDFUnion objects. */
-private:
- SkAutoTUnref<SkPDFObject> fObj;
+ static SkPDFUnion Int(int32_t);
- typedef SkPDFObject INHERITED;
-};
+ static SkPDFUnion Bool(bool);
-/** \class SkPDFInt
+ static SkPDFUnion Scalar(SkScalar);
- An integer object in a PDF.
-*/
-class SkPDFInt : public SkPDFObject {
-public:
- SK_DECLARE_INST_COUNT(SkPDFInt)
+ /** 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"); */
- /** Create a PDF integer (usually for indirect reference purposes).
- * @param value An integer value between 2^31 - 1 and -2^31.
- */
- explicit SkPDFInt(int32_t value);
- virtual ~SkPDFInt();
+ /** 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*);
- // The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) override;
+ /** SkPDFUnion::String will encode the passed string. This will
+ not copy the name. */
+ static SkPDFUnion String(const char*);
-private:
- int32_t fValue;
+ /** 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&);
- typedef SkPDFObject INHERITED;
-};
+ /** SkPDFUnion::String will encode the passed string. */
+ static SkPDFUnion String(const SkString&);
-/** \class SkPDFBool
+ /** 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*);
- An boolean value in a PDF.
-*/
-class SkPDFBool : public SkPDFObject {
-public:
- SK_DECLARE_INST_COUNT(SkPDFBool)
+ /** 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*);
- /** Create a PDF boolean.
- * @param value true or false.
- */
- explicit SkPDFBool(bool value);
- virtual ~SkPDFBool();
+ /** These two non-virtual methods mirror SkPDFObject's
+ corresponding virtuals. */
+ void emitObject(SkWStream*,
+ const SkPDFObjNumMap&,
+ const SkPDFSubstituteMap&) const;
+ void addResources(SkPDFObjNumMap*, const SkPDFSubstituteMap&) const;
- // The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) override;
+ bool isName() const;
private:
- bool fValue;
+ 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;
- typedef SkPDFObject INHERITED;
+ 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);
-/** \class SkPDFScalar
+////////////////////////////////////////////////////////////////////////////////
- A real number object in a PDF.
-*/
-class SkPDFScalar : public SkPDFObject {
+/** 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:
- SK_DECLARE_INST_COUNT(SkPDFScalar)
+ void emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) final;
+ void addResources(SkPDFObjNumMap*, const SkPDFSubstituteMap&) const final;
- /** Create a PDF real number.
- * @param value A real value.
- */
- explicit SkPDFScalar(SkScalar value);
- virtual ~SkPDFScalar();
-
- static void Append(SkScalar value, SkWStream* stream);
-
- // The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) override;
+protected:
+ SkPDFAtom(SkPDFUnion&& v) : fValue(v.move()) {}
private:
- SkScalar fValue;
-
+ const SkPDFUnion fValue;
typedef SkPDFObject INHERITED;
};
-/** \class SkPDFString
+/** The following six classes exist only to ease transition to SkPDFUnion. */
+class SkPDFObjRef : public SkPDFAtom {
+public:
+ SK_DECLARE_INST_COUNT(SkPDFObjRef);
+ explicit SkPDFObjRef(SkPDFObject* obj)
+ : INHERITED(SkPDFUnion::ObjRef(SkRef(obj))) {}
+ typedef SkPDFAtom INHERITED;
+};
- A string object in a PDF.
-*/
-class SkPDFString : public SkPDFObject {
+class SkPDFInt : public SkPDFAtom {
public:
- SK_DECLARE_INST_COUNT(SkPDFString)
+ SK_DECLARE_INST_COUNT(SkPDFInt);
+ explicit SkPDFInt(int32_t value) : INHERITED(SkPDFUnion::Int(value)) {}
+ typedef SkPDFAtom INHERITED;
+};
- /** Create a PDF string. Maximum length (in bytes) is 65,535.
- * @param value A string value.
- */
- explicit SkPDFString(const char value[]);
- explicit SkPDFString(const SkString& value);
+class SkPDFBool : public SkPDFAtom {
+public:
+ SK_DECLARE_INST_COUNT(SkPDFBool);
+ explicit SkPDFBool(bool value) : INHERITED(SkPDFUnion::Bool(value)) {}
+ typedef SkPDFAtom INHERITED;
+};
- virtual ~SkPDFString();
+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);
+ typedef SkPDFAtom INHERITED;
+};
- // The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) override;
+class SkPDFString : public SkPDFAtom {
+public:
+ SK_DECLARE_INST_COUNT(SkPDFString);
+ explicit SkPDFString(const char value[])
+ : INHERITED(SkPDFUnion::String(value)) {}
+ explicit SkPDFString(const SkString& value)
+ : INHERITED(SkPDFUnion::String(value)) {}
static SkString FormatString(const char* input, size_t len);
-private:
- static const size_t kMaxLen = 65535;
- const SkString fValue;
+ static const size_t kMaxLen = 65535;
- typedef SkPDFObject INHERITED;
+private:
+ typedef SkPDFAtom INHERITED;
};
-/** \class SkPDFName
-
- A name object in a PDF.
-*/
-class SkPDFName : public SkPDFObject {
+class SkPDFName : public SkPDFAtom {
public:
- SK_DECLARE_INST_COUNT(SkPDFName)
-
- /** 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;
+ 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)) {}
-private:
static const size_t kMaxLen = 127;
- const SkString fValue;
-
- static SkString FormatName(const SkString& input);
-
- typedef SkPDFObject INHERITED;
+private:
+ typedef SkPDFAtom INHERITED;
};
/** \class SkPDFArray
public:
SK_DECLARE_INST_COUNT(SkPDFArray)
+ static const int kMaxLen = 8191;
+
/** Create a PDF array. Maximum length is 8191.
*/
SkPDFArray();
/** The size of the array.
*/
- int size() { return fValue.count(); }
+ int size() const;
/** Preallocate space for the given number of entries.
* @param length The number of array slots to preallocate.
* @param value The value to add to the array.
* @return The value argument is returned.
*/
+ // DEPRECATED
SkPDFObject* append(SkPDFObject* value);
- /** Creates a SkPDFInt object and appends it to the array.
- * @param value The value to add to the array.
- */
- void appendInt(int32_t value);
-
- /** Creates a SkPDFScalar 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.
*/
- void appendScalar(SkScalar value);
-
- /** Creates a SkPDFName object and appends it to the array.
- * @param value The value to add to the array.
- */
- void appendName(const char name[]);
+ void appendInt(int32_t);
+ void appendBool(bool);
+ void appendScalar(SkScalar);
+ void appendName(const char[]);
+ void appendName(const SkString&);
+ void appendString(const char[]);
+ void appendString(const SkString&);
+ /** appendObject and appendObjRef take ownership of the passed object */
+ void appendObject(SkPDFObject*);
+ void appendObjRef(SkPDFObject*);
private:
- static const int kMaxLen = 8191;
- SkTDArray<SkPDFObject*> fValue;
-
+ SkTDArray<SkPDFUnion> fValues;
+ void append(SkPDFUnion&& value);
typedef SkPDFObject INHERITED;
};
* @param value The value for this dictionary entry.
* @return The value argument is returned.
*/
+ // DEPRECATED
SkPDFObject* insert(SkPDFName* key, SkPDFObject* value);
+ // DEPRECATED
+ SkPDFObject* insert(const char key[], SkPDFObject* value);
- /** Add the value to the dictionary with the given key. Refs value. The
- * method will create the SkPDFName object.
+ /** 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 value The value for this dictionary entry.
- * @return The value argument is returned.
*/
- SkPDFObject* insert(const char key[], SkPDFObject* value);
+ 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 int to the dictionary with the given key.
+ /** Add the value to the dictionary with the given key.
* @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 insertInt(const char key[], int32_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 insertInt(const char key[], size_t value);
void insertScalar(const char key[], SkScalar value);
-
- /** 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 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());
- }
+ void insertName(const char key[], const char nameValue[]);
+ void insertName(const char key[], const SkString& nameValue);
+ void insertString(const char key[], const char value[]);
+ void insertString(const char key[], const SkString& value);
/** Remove all entries from the dictionary.
*/
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:
- struct Rec {
- SkPDFName* key;
- SkPDFObject* value;
- Rec(SkPDFName* k, SkPDFObject* v) : key(k), value(v) {}
+ struct Record {
+ SkPDFUnion fKey;
+ SkPDFUnion fValue;
};
-
+ SkTDArray<Record> fRecords;
static const int kMaxLen = 4095;
- SkTDArray<struct Rec> fValue;
-
- SkPDFObject* append(SkPDFName* key, SkPDFObject* value);
+ void set(const SkPDFUnion& name, const SkPDFUnion& value);
+ void set(SkPDFUnion&& name, SkPDFUnion&& value);
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
The PDF Object Number Map manages object numbers. It is used to
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
SkDynamicMemoryWStream buffer;
emit_object(obj, &buffer, catalog, substituteMap, false);
REPORTER_ASSERT(reporter, directSize == buffer.getOffset());
- REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedData,
- directSize));
+ if (!stream_equals(buffer, 0, expectedData, 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) {
// Indirect output.
SkAutoTUnref<SkPDFDict> dict(new SkPDFDict);
SimpleCheckObjectOutput(reporter, dict.get(), "<<>>");
- SkAutoTUnref<SkPDFName> n1(new SkPDFName("n1"));
- dict->insert(n1.get(), int42.get());
+ dict->insert("n1", int42.get());
SimpleCheckObjectOutput(reporter, dict.get(), "<</n1 42>>");
- SkAutoTUnref<SkPDFName> n2(new SkPDFName("n2"));
- SkAutoTUnref<SkPDFName> n3(new SkPDFName("n3"));
- dict->insert(n2.get(), realHalf.get());
- dict->insert(n3.get(), array.get());
+ SkString n3("n3");
+ dict->insert("n2", realHalf.get());
+ dict->insertObject(n3, array.detach());
SimpleCheckObjectOutput(reporter, dict.get(),
"<</n1 42\n/n2 0.5\n/n3 [42 0.5 0]>>");