SkData can allocate room for its contents in the same block

BUG=skia:
R=bungeman@google.com, mtklein@google.com

Author: reed@google.com

Review URL: https://codereview.chromium.org/560653004
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index e28c6fd..f0ad029 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -1211,9 +1211,9 @@
         return false;
     }
 
-    char* dst = (char*)sk_malloc_throw(ramSize);
+    SkAutoDataUnref data(SkData::NewUninitialized(ramSize));
+    char* dst = (char*)data->writable_data();
     buffer->readByteArray(dst, snugSize);
-    SkAutoDataUnref data(SkData::NewFromMalloc(dst, ramSize));
 
     if (snugSize != ramSize) {
         const char* srcRow = dst + snugRB * (height - 1);
diff --git a/src/core/SkData.cpp b/src/core/SkData.cpp
index c653287..a7a3d8d 100644
--- a/src/core/SkData.cpp
+++ b/src/core/SkData.cpp
@@ -11,19 +11,49 @@
 #include "SkReadBuffer.h"
 #include "SkWriteBuffer.h"
 
+static void sk_inplace_sentinel_releaseproc(const void*, size_t, void*) {
+    // we should never get called, as we are just a sentinel
+    sk_throw();
+}
+
 SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
-    fPtr = ptr;
+    fPtr = const_cast<void*>(ptr);
     fSize = size;
     fReleaseProc = proc;
     fReleaseProcContext = context;
 }
 
+// This constructor means we are inline with our fPtr's contents. Thus we set fPtr
+// to point right after this. We also set our releaseproc to sk_inplace_sentinel_releaseproc,
+// since we need to handle "delete" ourselves. See internal_displose().
+//
+SkData::SkData(size_t size) {
+    fPtr = (char*)(this + 1);   // contents are immediately after this
+    fSize = size;
+    fReleaseProc = sk_inplace_sentinel_releaseproc;
+    fReleaseProcContext = NULL;
+}
+
 SkData::~SkData() {
     if (fReleaseProc) {
         fReleaseProc(fPtr, fSize, fReleaseProcContext);
     }
 }
 
+void SkData::internal_dispose() const {
+    if (sk_inplace_sentinel_releaseproc == fReleaseProc) {
+        const_cast<SkData*>(this)->fReleaseProc = NULL;    // so we don't call it in our destructor
+
+        this->internal_dispose_restore_refcnt_to_1();
+        this->~SkData();        // explicitly call this for refcnt bookkeeping
+
+        sk_free(const_cast<SkData*>(this));
+    } else {
+        this->internal_dispose_restore_refcnt_to_1();
+        SkDELETE(this);
+    }
+}
+
 bool SkData::equals(const SkData* other) const {
     if (NULL == other) {
         return false;
@@ -47,11 +77,24 @@
     return length;
 }
 
+SkData* SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
+    if (0 == length) {
+        return SkData::NewEmpty();
+    }
+    char* storage = (char*)sk_malloc_throw(sizeof(SkData) + length);
+    SkData* data = new (storage) SkData(length);
+    if (srcOrNull) {
+        memcpy(data->writable_data(), srcOrNull, length);
+    }
+    return data;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 SkData* SkData::NewEmptyImpl() {
     return new SkData(NULL, 0, NULL, NULL);
 }
+
 void SkData::DeleteEmpty(SkData* ptr) { SkDELETE(ptr); }
 
 SkData* SkData::NewEmpty() {
@@ -68,14 +111,13 @@
     return new SkData(data, length, sk_free_releaseproc, NULL);
 }
 
-SkData* SkData::NewWithCopy(const void* data, size_t length) {
-    if (0 == length) {
-        return SkData::NewEmpty();
-    }
+SkData* SkData::NewWithCopy(const void* src, size_t length) {
+    SkASSERT(src);
+    return PrivateNewWithCopy(src, length);
+}
 
-    void* copy = sk_malloc_throw(length); // balanced in sk_free_releaseproc
-    memcpy(copy, data, length);
-    return new SkData(copy, length, sk_free_releaseproc, NULL);
+SkData* SkData::NewUninitialized(size_t length) {
+    return PrivateNewWithCopy(NULL, length);
 }
 
 SkData* SkData::NewWithProc(const void* data, size_t length,
diff --git a/src/core/SkFlattenableSerialization.cpp b/src/core/SkFlattenableSerialization.cpp
index b33bca6..3160207 100644
--- a/src/core/SkFlattenableSerialization.cpp
+++ b/src/core/SkFlattenableSerialization.cpp
@@ -15,9 +15,9 @@
     SkWriteBuffer writer(SkWriteBuffer::kValidation_Flag);
     writer.writeFlattenable(flattenable);
     size_t size = writer.bytesWritten();
-    void* data = sk_malloc_throw(size);
-    writer.writeToMemory(data);
-    return SkData::NewFromMalloc(data, size);
+    SkData* data = SkData::NewUninitialized(size);
+    writer.writeToMemory(data->writable_data());
+    return data;
 }
 
 SkFlattenable* SkValidatingDeserializeFlattenable(const void* data, size_t size,
diff --git a/src/core/SkStream.cpp b/src/core/SkStream.cpp
index ca9f51f..b04bc16 100644
--- a/src/core/SkStream.cpp
+++ b/src/core/SkStream.cpp
@@ -69,9 +69,9 @@
     if (0 == size) {
         return SkData::NewEmpty();
     } else {
-        void* buffer = sk_malloc_throw(size);
-        this->read(buffer, size);
-        return SkData::NewFromMalloc(buffer, size);
+        SkData* data = SkData::NewUninitialized(size);
+        this->read(data->writable_data(), size);
+        return data;
     }
 }
 
@@ -308,7 +308,7 @@
     if (copyData) {
         return SkData::NewWithCopy(src, size);
     } else {
-        return SkData::NewWithProc(src, size, NULL, NULL);
+        return SkData::NewWithoutCopy(src, size);
     }
 }
 
@@ -318,7 +318,7 @@
 }
 
 SkMemoryStream::SkMemoryStream(size_t size) {
-    fData = SkData::NewFromMalloc(sk_malloc_throw(size), size);
+    fData = SkData::NewUninitialized(size);
     fOffset = 0;
 }
 
@@ -654,12 +654,12 @@
 
 SkData* SkDynamicMemoryWStream::copyToData() const {
     if (NULL == fCopy) {
-        void* buffer = sk_malloc_throw(fBytesWritten);
-        this->copyTo(buffer);
-        fCopy = SkData::NewFromMalloc(buffer, fBytesWritten);
+        SkData* data = SkData::NewUninitialized(fBytesWritten);
+        // be sure to call copyTo() before we assign to fCopy
+        this->copyTo(data->writable_data());
+        fCopy = data;
     }
-    fCopy->ref();
-    return fCopy;
+    return SkRef(fCopy);
 }
 
 void SkDynamicMemoryWStream::invalidateCopy() {
@@ -891,11 +891,12 @@
 
     if (stream->hasLength()) {
         const size_t length = stream->getLength();
-        SkAutoMalloc dst(length);
-        if (stream->read(dst.get(), length) != length) {
-            return NULL;
+        SkData* data = SkData::NewUninitialized(length);
+        if (stream->read(data->writable_data(), length) != length) {
+            data->unref();
+            data = NULL;
         }
-        return SkData::NewFromMalloc(dst.detach(), length);
+        return data;
     }
 
     SkDynamicMemoryWStream tempStream;
@@ -922,11 +923,9 @@
         if (stream->hasPosition()) {  // If stream has length, but can't rewind.
             length -= stream->getPosition();
         }
-        SkAutoMalloc allocMemory(length);
-        SkDEBUGCODE(size_t read =) stream->read(allocMemory.get(), length);
+        SkAutoTUnref<SkData> data(SkData::NewUninitialized(length));
+        SkDEBUGCODE(size_t read =) stream->read(data->writable_data(), length);
         SkASSERT(length == read);
-        SkAutoTUnref<SkData> data(
-                SkData::NewFromMalloc(allocMemory.detach(), length));
         return SkNEW_ARGS(SkMemoryStream, (data.get()));
     }
     SkDynamicMemoryWStream tempStream;
diff --git a/src/images/SkDecodingImageGenerator.cpp b/src/images/SkDecodingImageGenerator.cpp
index 1d91bcc..359eb37 100644
--- a/src/images/SkDecodingImageGenerator.cpp
+++ b/src/images/SkDecodingImageGenerator.cpp
@@ -132,22 +132,20 @@
 SkData* DecodingImageGenerator::onRefEncodedData() {
     // This functionality is used in `gm --serialize`
     // Does not encode options.
-    if (fData != NULL) {
-        return SkSafeRef(fData);
+    if (NULL == fData) {
+        // TODO(halcanary): SkStreamRewindable needs a refData() function
+        // which returns a cheap copy of the underlying data.
+        if (!fStream->rewind()) {
+            return NULL;
+        }
+        size_t length = fStream->getLength();
+        if (0 == length) {
+            return NULL;
+        }
+        fData = SkData::NewUninitialized(length);
+        SkCheckResult(fStream->read(fData->writable_data(), length), length);
     }
-    // TODO(halcanary): SkStreamRewindable needs a refData() function
-    // which returns a cheap copy of the underlying data.
-    if (!fStream->rewind()) {
-        return NULL;
-    }
-    size_t length = fStream->getLength();
-    if (0 == length) {
-        return NULL;
-    }
-    void* buffer = sk_malloc_flags(length, 0);
-    SkCheckResult(fStream->read(buffer, length), length);
-    fData = SkData::NewFromMalloc(buffer, length);
-    return SkSafeRef(fData);
+    return SkRef(fData);
 }
 
 bool DecodingImageGenerator::onGetPixels(const SkImageInfo& info,
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index 9e13053..b4e6d98 100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -204,16 +204,15 @@
         SkASSERT(length > 0);
         SkASSERT(length + (2 * kPFBSectionHeaderLength) <= srcLen);
 
-        SkAutoTMalloc<uint8_t> buffer(length);
+        SkData* data = SkData::NewUninitialized(length);
 
         const uint8_t* const srcHeader = src + kPFBSectionHeaderLength;
         // There is a six-byte section header before header and data
         // (but not trailer) that we're not going to copy.
-        const uint8_t* const srcData
-            = srcHeader + *headerLen + kPFBSectionHeaderLength;
+        const uint8_t* const srcData = srcHeader + *headerLen + kPFBSectionHeaderLength;
         const uint8_t* const srcTrailer = srcData + *headerLen;
 
-        uint8_t* const resultHeader = buffer.get();
+        uint8_t* const resultHeader = (uint8_t*)data->writable_data();
         uint8_t* const resultData = resultHeader + *headerLen;
         uint8_t* const resultTrailer = resultData + *dataLen;
 
@@ -223,7 +222,7 @@
         memcpy(resultData,    srcData,    *dataLen);
         memcpy(resultTrailer, srcTrailer, *trailerLen);
 
-        return SkData::NewFromMalloc(buffer.detach(), length);
+        return data;
     }
 
     // A PFA has to be converted for PDF.
diff --git a/src/pdf/SkPDFGraphicState.cpp b/src/pdf/SkPDFGraphicState.cpp
index bd8afe0..7664ed6 100644
--- a/src/pdf/SkPDFGraphicState.cpp
+++ b/src/pdf/SkPDFGraphicState.cpp
@@ -123,7 +123,7 @@
         static const char psInvert[] = "{1 exch sub}";
         // Do not copy the trailing '\0' into the SkData.
         SkAutoTUnref<SkData> psInvertStream(
-                SkData::NewWithCopy(psInvert, strlen(psInvert)));
+                SkData::NewWithoutCopy(psInvert, strlen(psInvert)));
 
         invertFunction = new SkPDFStream(psInvertStream.get());
         invertFunction->insertInt("FunctionType", 4);
diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp
index afe6bb0..d9b701c 100644
--- a/src/pdf/SkPDFShader.cpp
+++ b/src/pdf/SkPDFShader.cpp
@@ -1160,10 +1160,8 @@
     fState.get()->fImage.unlockPixels();
 }
 
-SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode,
-                                                 SkPDFArray* domain) {
-    SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(),
-                                                 psCode.size()));
+SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode, SkPDFArray* domain) {
+    SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(), psCode.size()));
     SkPDFStream* result = new SkPDFStream(funcData.get());
     result->insertInt("FunctionType", 4);
     result->insert("Domain", domain);
@@ -1171,14 +1169,12 @@
     return result;
 }
 
-SkPDFShader::ShaderCanonicalEntry::ShaderCanonicalEntry(SkPDFObject* pdfShader,
-                                                        const State* state)
-    : fPDFShader(pdfShader),
-      fState(state) {
-}
+SkPDFShader::ShaderCanonicalEntry::ShaderCanonicalEntry(SkPDFObject* pdfShader, const State* state)
+    : fPDFShader(pdfShader)
+    , fState(state)
+{}
 
-bool SkPDFShader::ShaderCanonicalEntry::operator==(
-        const ShaderCanonicalEntry& b) const {
+bool SkPDFShader::ShaderCanonicalEntry::operator==(const ShaderCanonicalEntry& b) const {
     return fPDFShader == b.fPDFShader ||
            (fState != NULL && b.fState != NULL && *fState == *b.fState);
 }
diff --git a/src/sfnt/SkOTUtils.cpp b/src/sfnt/SkOTUtils.cpp
index e76d1da..0e00952 100644
--- a/src/sfnt/SkOTUtils.cpp
+++ b/src/sfnt/SkOTUtils.cpp
@@ -83,8 +83,8 @@
     size_t originalDataSize = fontData->getLength() - oldNameTablePhysicalSize;
     size_t newDataSize = originalDataSize + nameTablePhysicalSize;
 
-    SK_OT_BYTE* data = static_cast<SK_OT_BYTE*>(sk_malloc_throw(newDataSize));
-    SkAutoTUnref<SkData> rewrittenFontData(SkData::NewFromMalloc(data, newDataSize));
+    SkAutoTUnref<SkData> rewrittenFontData(SkData::NewUninitialized(newDataSize));
+    SK_OT_BYTE* data = static_cast<SK_OT_BYTE*>(rewrittenFontData->writable_data());
 
     if (fontData->read(data, oldNameTableOffset) < oldNameTableOffset) {
         return NULL;
diff --git a/src/utils/SkTextureCompressor.cpp b/src/utils/SkTextureCompressor.cpp
index 07b58c5..799eadc 100644
--- a/src/utils/SkTextureCompressor.cpp
+++ b/src/utils/SkTextureCompressor.cpp
@@ -173,7 +173,7 @@
     return false;
 }
 
-SkData *CompressBitmapToFormat(const SkBitmap &bitmap, Format format) {
+SkData* CompressBitmapToFormat(const SkBitmap &bitmap, Format format) {
     SkAutoLockPixels alp(bitmap);
 
     int compressedDataSize = GetCompressedDataSize(format, bitmap.width(), bitmap.height());
@@ -182,15 +182,14 @@
     }
 
     const uint8_t* src = reinterpret_cast<const uint8_t*>(bitmap.getPixels());
-    uint8_t* dst = reinterpret_cast<uint8_t*>(sk_malloc_throw(compressedDataSize));
+    SkData* dst = SkData::NewUninitialized(compressedDataSize);
 
-    if (CompressBufferToFormat(dst, src, bitmap.colorType(), bitmap.width(), bitmap.height(),
-                               bitmap.rowBytes(), format)) {
-        return SkData::NewFromMalloc(dst, compressedDataSize);
+    if (!CompressBufferToFormat((uint8_t*)dst->writable_data(), src, bitmap.colorType(),
+                                bitmap.width(), bitmap.height(), bitmap.rowBytes(), format)) {
+        dst->unref();
+        dst = NULL;
     }
-
-    sk_free(dst);
-    return NULL;
+    return dst;
 }
 
 SkBlitter* CreateBlitterForFormat(int width, int height, void* compressedBuffer,