michael@0: /* michael@0: * Copyright 2011 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "SkMallocPixelRef.h" michael@0: #include "SkBitmap.h" michael@0: #include "SkReadBuffer.h" michael@0: #include "SkWriteBuffer.h" michael@0: michael@0: // assumes ptr was allocated via sk_malloc michael@0: static void sk_free_releaseproc(void* ptr, void*) { michael@0: sk_free(ptr); michael@0: } michael@0: michael@0: static bool is_valid(const SkImageInfo& info, SkColorTable* ctable) { michael@0: if (info.fWidth < 0 || michael@0: info.fHeight < 0 || michael@0: (unsigned)info.fColorType > (unsigned)kLastEnum_SkColorType || michael@0: (unsigned)info.fAlphaType > (unsigned)kLastEnum_SkAlphaType) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: // these seem like good checks, but currently we have (at least) tests michael@0: // that expect the pixelref to succeed even when there is a mismatch michael@0: // with colortables. fix? michael@0: #if 0 michael@0: if (kIndex8_SkColorType == info.fColorType && NULL == ctable) { michael@0: return false; michael@0: } michael@0: if (kIndex8_SkColorType != info.fColorType && NULL != ctable) { michael@0: return false; michael@0: } michael@0: #endif michael@0: return true; michael@0: } michael@0: michael@0: SkMallocPixelRef* SkMallocPixelRef::NewDirect(const SkImageInfo& info, michael@0: void* addr, michael@0: size_t rowBytes, michael@0: SkColorTable* ctable) { michael@0: if (!is_valid(info, ctable)) { michael@0: return NULL; michael@0: } michael@0: return SkNEW_ARGS(SkMallocPixelRef, michael@0: (info, addr, rowBytes, ctable, NULL, NULL)); michael@0: } michael@0: michael@0: SkMallocPixelRef* SkMallocPixelRef::NewAllocate(const SkImageInfo& info, michael@0: size_t requestedRowBytes, michael@0: SkColorTable* ctable) { michael@0: if (!is_valid(info, ctable)) { michael@0: return NULL; michael@0: } michael@0: michael@0: int32_t minRB = SkToS32(info.minRowBytes()); michael@0: if (minRB < 0) { michael@0: return NULL; // allocation will be too large michael@0: } michael@0: if (requestedRowBytes > 0 && (int32_t)requestedRowBytes < minRB) { michael@0: return NULL; // cannot meet requested rowbytes michael@0: } michael@0: michael@0: int32_t rowBytes; michael@0: if (requestedRowBytes) { michael@0: rowBytes = SkToS32(requestedRowBytes); michael@0: } else { michael@0: rowBytes = minRB; michael@0: } michael@0: michael@0: int64_t bigSize = (int64_t)info.fHeight * rowBytes; michael@0: if (!sk_64_isS32(bigSize)) { michael@0: return NULL; michael@0: } michael@0: michael@0: size_t size = sk_64_asS32(bigSize); michael@0: SkASSERT(size >= info.getSafeSize(rowBytes)); michael@0: void* addr = sk_malloc_flags(size, 0); michael@0: if (NULL == addr) { michael@0: return NULL; michael@0: } michael@0: michael@0: return SkNEW_ARGS(SkMallocPixelRef, michael@0: (info, addr, rowBytes, ctable, michael@0: sk_free_releaseproc, NULL)); michael@0: } michael@0: michael@0: SkMallocPixelRef* SkMallocPixelRef::NewWithProc(const SkImageInfo& info, michael@0: size_t rowBytes, michael@0: SkColorTable* ctable, michael@0: void* addr, michael@0: SkMallocPixelRef::ReleaseProc proc, michael@0: void* context) { michael@0: if (!is_valid(info, ctable)) { michael@0: return NULL; michael@0: } michael@0: return SkNEW_ARGS(SkMallocPixelRef, michael@0: (info, addr, rowBytes, ctable, proc, context)); michael@0: } michael@0: michael@0: static void sk_data_releaseproc(void*, void* dataPtr) { michael@0: (static_cast(dataPtr))->unref(); michael@0: } michael@0: michael@0: SkMallocPixelRef* SkMallocPixelRef::NewWithData(const SkImageInfo& info, michael@0: size_t rowBytes, michael@0: SkColorTable* ctable, michael@0: SkData* data, michael@0: size_t offset) { michael@0: SkASSERT(data != NULL); michael@0: SkASSERT(offset <= data->size()); michael@0: if (!is_valid(info, ctable)) { michael@0: return NULL; michael@0: } michael@0: if ((rowBytes < info.minRowBytes()) michael@0: || ((data->size() - offset) < info.getSafeSize(rowBytes))) { michael@0: return NULL; michael@0: } michael@0: data->ref(); michael@0: const void* ptr = static_cast(data->bytes() + offset); michael@0: SkMallocPixelRef* pr michael@0: = SkNEW_ARGS(SkMallocPixelRef, michael@0: (info, const_cast(ptr), rowBytes, ctable, michael@0: sk_data_releaseproc, static_cast(data))); michael@0: SkASSERT(pr != NULL); michael@0: // We rely on the immutability of the pixels to make the michael@0: // const_cast okay. michael@0: pr->setImmutable(); michael@0: return pr; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage, michael@0: size_t rowBytes, SkColorTable* ctable, michael@0: bool ownsPixels) michael@0: : INHERITED(info) michael@0: , fReleaseProc(ownsPixels ? sk_free_releaseproc : NULL) michael@0: , fReleaseProcContext(NULL) { michael@0: // This constructor is now DEPRICATED. michael@0: SkASSERT(is_valid(info, ctable)); michael@0: SkASSERT(rowBytes >= info.minRowBytes()); michael@0: michael@0: if (kIndex_8_SkColorType != info.fColorType) { michael@0: ctable = NULL; michael@0: } michael@0: michael@0: fStorage = storage; michael@0: fCTable = ctable; michael@0: fRB = rowBytes; michael@0: SkSafeRef(ctable); michael@0: michael@0: this->setPreLocked(fStorage, rowBytes, fCTable); michael@0: } michael@0: michael@0: SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage, michael@0: size_t rowBytes, SkColorTable* ctable, michael@0: SkMallocPixelRef::ReleaseProc proc, michael@0: void* context) michael@0: : INHERITED(info) michael@0: , fReleaseProc(proc) michael@0: , fReleaseProcContext(context) michael@0: { michael@0: SkASSERT(is_valid(info, ctable)); michael@0: SkASSERT(rowBytes >= info.minRowBytes()); michael@0: michael@0: if (kIndex_8_SkColorType != info.fColorType) { michael@0: ctable = NULL; michael@0: } michael@0: michael@0: fStorage = storage; michael@0: fCTable = ctable; michael@0: fRB = rowBytes; michael@0: SkSafeRef(ctable); michael@0: michael@0: this->setPreLocked(fStorage, rowBytes, fCTable); michael@0: } michael@0: michael@0: michael@0: SkMallocPixelRef::~SkMallocPixelRef() { michael@0: SkSafeUnref(fCTable); michael@0: if (fReleaseProc != NULL) { michael@0: fReleaseProc(fStorage, fReleaseProcContext); michael@0: } michael@0: } michael@0: michael@0: bool SkMallocPixelRef::onNewLockPixels(LockRec* rec) { michael@0: rec->fPixels = fStorage; michael@0: rec->fRowBytes = fRB; michael@0: rec->fColorTable = fCTable; michael@0: return true; michael@0: } michael@0: michael@0: void SkMallocPixelRef::onUnlockPixels() { michael@0: // nothing to do michael@0: } michael@0: michael@0: size_t SkMallocPixelRef::getAllocatedSizeInBytes() const { michael@0: return this->info().getSafeSize(fRB); michael@0: } michael@0: michael@0: void SkMallocPixelRef::flatten(SkWriteBuffer& buffer) const { michael@0: this->INHERITED::flatten(buffer); michael@0: michael@0: buffer.write32(SkToU32(fRB)); michael@0: michael@0: // TODO: replace this bulk write with a chunky one that can trim off any michael@0: // trailing bytes on each scanline (in case rowbytes > width*size) michael@0: size_t size = this->info().getSafeSize(fRB); michael@0: buffer.writeByteArray(fStorage, size); michael@0: buffer.writeBool(fCTable != NULL); michael@0: if (fCTable) { michael@0: fCTable->writeToBuffer(buffer); michael@0: } michael@0: } michael@0: michael@0: SkMallocPixelRef::SkMallocPixelRef(SkReadBuffer& buffer) michael@0: : INHERITED(buffer, NULL) michael@0: , fReleaseProc(sk_free_releaseproc) michael@0: , fReleaseProcContext(NULL) michael@0: { michael@0: fRB = buffer.read32(); michael@0: size_t size = buffer.isValid() ? this->info().getSafeSize(fRB) : 0; michael@0: if (buffer.validateAvailable(size)) { michael@0: fStorage = sk_malloc_throw(size); michael@0: buffer.readByteArray(fStorage, size); michael@0: } else { michael@0: fStorage = NULL; michael@0: } michael@0: michael@0: if (buffer.readBool()) { michael@0: fCTable = SkNEW_ARGS(SkColorTable, (buffer)); michael@0: } else { michael@0: fCTable = NULL; michael@0: } michael@0: michael@0: this->setPreLocked(fStorage, fRB, fCTable); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkPixelRef* SkMallocPixelRef::PRFactory::create(const SkImageInfo& info, michael@0: SkColorTable* ctable) { michael@0: return SkMallocPixelRef::NewAllocate(info, info.minRowBytes(), ctable); michael@0: }