Index: src/pdf/SkPDFTypes.cpp |
diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp |
index e3cc90c1de27e711a702e95f8982f42b562d1f76..7b79e411b601f7845ab49390f734eaf322ea4f70 100644 |
--- a/src/pdf/SkPDFTypes.cpp |
+++ b/src/pdf/SkPDFTypes.cpp |
@@ -396,14 +396,26 @@ SkPDFDict::~SkPDFDict() { |
clear(); |
} |
+int SkPDFDict::size() const { |
+ SkAutoMutexAcquire lock(fMutex); |
+ return fValue.count(); |
+} |
+ |
+ |
void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog, |
bool indirect) { |
if (indirect) { |
return emitIndirectObject(stream, catalog); |
} |
+ SkAutoMutexAcquire lock(fMutex); // If another thread triggers a |
+ // resize while this thread is in |
+ // the for-loop, we can be left |
+ // with a bad fValue[i] reference. |
stream->writeText("<<"); |
for (int i = 0; i < fValue.count(); i++) { |
+ SkASSERT(fValue[i].key); |
+ SkASSERT(fValue[i].value); |
fValue[i].key->emitObject(stream, catalog, false); |
stream->writeText(" "); |
fValue[i].value->emit(stream, catalog, false); |
@@ -417,69 +429,84 @@ size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) { |
return getIndirectOutputSize(catalog); |
} |
+ SkAutoMutexAcquire lock(fMutex); // If another thread triggers a |
+ // resize while this thread is in |
+ // the for-loop, we can be left |
+ // with a bad fValue[i] reference. |
size_t result = strlen("<<>>") + (fValue.count() * 2); |
for (int i = 0; i < fValue.count(); i++) { |
+ SkASSERT(fValue[i].key); |
+ SkASSERT(fValue[i].value); |
result += fValue[i].key->getOutputSize(catalog, false); |
result += fValue[i].value->getOutputSize(catalog, false); |
} |
return result; |
} |
-SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) { |
- key->ref(); |
- value->ref(); |
- struct Rec* newEntry = fValue.append(); |
- newEntry->key = key; |
- newEntry->value = value; |
+SkPDFObject* SkPDFDict::append(SkPDFName* key, SkPDFObject* value) { |
+ SkASSERT(key); |
+ SkASSERT(value); |
+ SkAutoMutexAcquire lock(fMutex); // If the SkTDArray resizes while |
+ // two threads access array, one |
+ // is left with a bad pointer. |
+ *(fValue.append()) = Rec(key, 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) { |
- value->ref(); |
- struct Rec* newEntry = fValue.append(); |
- newEntry->key = new SkPDFName(key); |
- newEntry->value = value; |
- return value; |
+ return this->append(new SkPDFName(key), SkRef(value)); |
} |
void SkPDFDict::insertInt(const char key[], int32_t value) { |
- struct Rec* newEntry = fValue.append(); |
- newEntry->key = new SkPDFName(key); |
- newEntry->value = new SkPDFInt(value); |
+ (void)this->append(new SkPDFName(key), new SkPDFInt(value)); |
} |
void SkPDFDict::insertScalar(const char key[], SkScalar value) { |
- struct Rec* newEntry = fValue.append(); |
- newEntry->key = new SkPDFName(key); |
- newEntry->value = new SkPDFScalar(value); |
+ (void)this->append(new SkPDFName(key), new SkPDFScalar(value)); |
} |
void SkPDFDict::insertName(const char key[], const char name[]) { |
- struct Rec* newEntry = fValue.append(); |
- newEntry->key = new SkPDFName(key); |
- newEntry->value = new SkPDFName(name); |
+ (void)this->append(new SkPDFName(key), new SkPDFName(name)); |
} |
void SkPDFDict::clear() { |
+ SkAutoMutexAcquire lock(fMutex); |
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(); |
} |
-SkPDFDict::Iter::Iter(const SkPDFDict& dict) |
- : fIter(dict.fValue.begin()), |
- fStop(dict.fValue.end()) { |
+void SkPDFDict::remove(const char key[]) { |
+ SkASSERT(key); |
+ SkPDFName name(key); |
+ SkAutoMutexAcquire lock(fMutex); |
+ 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; |
+ } |
+ } |
} |
-SkPDFName* SkPDFDict::Iter::next(SkPDFObject** value) { |
- if (fIter != fStop) { |
- const Rec* cur = fIter; |
- fIter++; |
- *value = cur->value; |
- return cur->key; |
+void SkPDFDict::mergeFrom(const SkPDFDict& other) { |
+ SkAutoMutexAcquire lockOther(other.fMutex); |
+ SkTDArray<Rec> copy(other.fValue); |
+ lockOther.release(); // Do not hold both mutexes at once. |
+ |
+ SkAutoMutexAcquire lock(fMutex); |
+ for (int i = 0; i < copy.count(); i++) { |
+ *(fValue.append()) = Rec(SkRef(copy[i].key), SkRef(copy[i].value)); |
} |
- *value = NULL; |
- return NULL; |
} |