From ae09f2dc3fb1e8a8db99b214c8a71d0b9613a856 Mon Sep 17 00:00:00 2001 From: "bsalomon@google.com" Date: Wed, 3 Oct 2012 19:57:01 +0000 Subject: Adds extra debugging to SkPathRef that can optionally be turned on in a release build. This is pretty hacky but hopefully will be quite short-lived. Review URL: https://codereview.appspot.com/6584074 git-svn-id: http://skia.googlecode.com/svn/trunk@5793 2bbb7eff-a529-9590-31e7-b0007b416f81 --- src/core/SkPathRef.h | 87 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 13 deletions(-) (limited to 'src/core/SkPathRef.h') diff --git a/src/core/SkPathRef.h b/src/core/SkPathRef.h index 339166340e..80ca50cabc 100644 --- a/src/core/SkPathRef.h +++ b/src/core/SkPathRef.h @@ -32,13 +32,29 @@ * verb array use ref.verbs()[~i] (because verbs() returns a pointer just beyond the first * logical verb or the last verb in memory). */ + +class SkPathRef; +SkPathRef* gEmptyPathRef; // This path ref should never be deleted once it is created. + +// Temporary hackery to try to nail down http://code.google.com/p/chromium/issues/detail?id=148637 +#if SK_DEBUG_PATH_REF + #define PR_CONTAINER SkPath::PathRefDebugRef + #define SkDEBUGCODE_X(code) code + #define SkASSERT_X(cond) SK_DEBUGBREAK(cond) + SK_DECLARE_STATIC_MUTEX(gOwnersMutex); +#else + #define PR_CONTAINER SkAutoTUnref + #define SkDEBUGCODE_X(code) SkDEBUGCODE(code) + #define SkASSERT_X(cond) SkASSERT(cond) +#endif + class SkPathRef : public ::SkRefCnt { public: SK_DECLARE_INST_COUNT(SkPathRef); class Editor { public: - Editor(SkAutoTUnref* pathRef, + Editor(PR_CONTAINER* pathRef, int incReserveVerbs = 0, int incReservePoints = 0) { if (pathRef->get()->getRefCnt() > 1) { @@ -50,10 +66,10 @@ public: } fPathRef = pathRef->get(); fPathRef->fGenerationID = 0; - SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);) + SkDEBUGCODE_X(sk_atomic_inc(&fPathRef->fEditorsAttached);) } - ~Editor() { SkDEBUGCODE(sk_atomic_dec(&fPathRef->fEditorsAttached);) } + ~Editor() { SkDEBUGCODE_X(sk_atomic_dec(&fPathRef->fEditorsAttached);) } /** * Returns the array of points. @@ -112,28 +128,56 @@ public: }; public: +#if SK_DEBUG_PATH_REF + void addOwner(SkPath* owner) { + gOwnersMutex.acquire(); + for (int i = 0; i < fOwners.count(); ++i) { + SkASSERT_X(fOwners[i] != owner); + } + *fOwners.append() = owner; + SkASSERT_X((this->getRefCnt() == fOwners.count()) || + (this == gEmptyPathRef && this->getRefCnt() == fOwners.count() + 1)); + gOwnersMutex.release(); + } + + void removeOwner(SkPath* owner) { + gOwnersMutex.acquire(); + SkASSERT_X((this->getRefCnt() == fOwners.count()) || + (this == gEmptyPathRef && this->getRefCnt() == fOwners.count() + 1)); + bool found = false; + for (int i = 0; !found && i < fOwners.count(); ++i) { + found = (owner == fOwners[i]); + if (found) { + fOwners.remove(i); + } + } + SkASSERT_X(found); + gOwnersMutex.release(); + } +#endif /** * Gets a path ref with no verbs or points. */ static SkPathRef* CreateEmpty() { - static SkAutoTUnref gEmptyPathRef(SkNEW(SkPathRef)); - gEmptyPathRef.get()->ref(); - return gEmptyPathRef.get(); + if (!gEmptyPathRef) { + gEmptyPathRef = SkNEW(SkPathRef); // leak! + } + return SkRef(gEmptyPathRef); } /** * Transforms a path ref by a matrix, allocating a new one only if necessary. */ - static void CreateTransformedCopy(SkAutoTUnref* dst, + static void CreateTransformedCopy(PR_CONTAINER* dst, const SkPathRef& src, const SkMatrix& matrix) { src.validate(); if (matrix.isIdentity()) { if (dst->get() != &src) { + src.ref(); dst->reset(const_cast(&src)); (*dst)->validate(); - src.ref(); } return; } @@ -184,7 +228,7 @@ public: * repopulated with approximately the same number of verbs and points. A new path ref is created * only if necessary. */ - static void Rewind(SkAutoTUnref* pathRef) { + static void Rewind(PR_CONTAINER* pathRef) { if (1 == (*pathRef)->getRefCnt()) { (*pathRef)->validate(); (*pathRef)->fVerbCnt = 0; @@ -201,8 +245,21 @@ public: } virtual ~SkPathRef() { + SkASSERT_X(this != gEmptyPathRef); +#if SK_DEBUG_PATH_REF + SkASSERT_X(!fOwners.count()); +#endif + this->validate(); sk_free(fPoints); + + SkDEBUGCODE_X(fPoints = NULL;) + SkDEBUGCODE_X(fVerbs = NULL;) + SkDEBUGCODE_X(fVerbCnt = 0x9999999;) + SkDEBUGCODE_X(fPointCnt = 0xAAAAAAA;) + SkDEBUGCODE_X(fPointCnt = 0xBBBBBBB;) + SkDEBUGCODE_X(fGenerationID = 0xEEEEEEEE;) + SkDEBUGCODE_X(fEditorsAttached = 0x7777777;) } int countPoints() const { this->validate(); return fPointCnt; } @@ -282,7 +339,7 @@ public: #if NEW_PICTURE_FORMAT void writeToBuffer(SkWBuffer* buffer) { this->validate(); - SkDEBUGCODE(size_t beforePos = buffer->pos();) + SkDEBUGCODE_X(size_t beforePos = buffer->pos();) // TODO: write gen ID here. Problem: We don't know if we're cross process or not from // SkWBuffer. Until this is fixed we write 0. @@ -319,7 +376,7 @@ private: fPoints = NULL; fFreeSpace = 0; fGenerationID = kEmptyGenID; - SkDEBUGCODE(fEditorsAttached = 0;) + SkDEBUGCODE_X(fEditorsAttached = 0;) this->validate(); } @@ -480,7 +537,7 @@ private: * for the path ref. */ int32_t genID() const { - SkDEBUGCODE(SkASSERT(!fEditorsAttached)); + SkASSERT_X(!fEditorsAttached); if (!fGenerationID) { if (0 == fPointCnt && 0 == fVerbCnt) { fGenerationID = kEmptyGenID; @@ -521,7 +578,11 @@ private: kEmptyGenID = 1, // GenID reserved for path ref with zero points and zero verbs. }; mutable int32_t fGenerationID; - SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use at any time. + SkDEBUGCODE_X(int32_t fEditorsAttached;) // assert that only one editor in use at any time. + +#if SK_DEBUG_PATH_REF + SkTDArray fOwners; +#endif typedef SkRefCnt INHERITED; }; -- cgit v1.2.3