summaryrefslogtreecommitdiffstats
path: root/skia/images
diff options
context:
space:
mode:
Diffstat (limited to 'skia/images')
-rw-r--r--skia/images/SkFDStream.cpp85
-rw-r--r--skia/images/SkFlipPixelRef.cpp127
-rw-r--r--skia/images/SkImageDecoder.cpp44
-rw-r--r--skia/images/SkImageDecoder_fpdfemb.cpp236
-rw-r--r--skia/images/SkImageDecoder_libbmp.cpp2
-rw-r--r--skia/images/SkImageDecoder_libgif.cpp39
-rw-r--r--skia/images/SkImageDecoder_libico.cpp28
-rw-r--r--skia/images/SkImageDecoder_libjpeg.cpp367
-rw-r--r--skia/images/SkImageDecoder_libpng.cpp242
-rw-r--r--skia/images/SkImageDecoder_wbmp.cpp2
-rw-r--r--skia/images/SkImageRef.cpp10
-rw-r--r--skia/images/SkMovie_gif.cpp19
-rw-r--r--skia/images/SkScaledBitmapSampler.cpp2
-rw-r--r--skia/images/SkStream.cpp114
-rw-r--r--skia/images/bmpdecoderhelper.cpp2
-rw-r--r--skia/images/bmpdecoderhelper.h5
16 files changed, 1100 insertions, 224 deletions
diff --git a/skia/images/SkFDStream.cpp b/skia/images/SkFDStream.cpp
new file mode 100644
index 0000000..db4a51a
--- /dev/null
+++ b/skia/images/SkFDStream.cpp
@@ -0,0 +1,85 @@
+#include "SkStream.h"
+#include <unistd.h>
+
+//#define TRACE_FDSTREAM
+
+SkFDStream::SkFDStream(int fileDesc, bool closeWhenDone)
+ : fFD(fileDesc), fCloseWhenDone(closeWhenDone) {
+}
+
+SkFDStream::~SkFDStream() {
+ if (fFD >= 0 && fCloseWhenDone) {
+ ::close(fFD);
+ }
+}
+
+bool SkFDStream::rewind() {
+ if (fFD >= 0) {
+ off_t value = ::lseek(fFD, 0, SEEK_SET);
+#ifdef TRACE_FDSTREAM
+ if (value) {
+ SkDebugf("xxxxxxxxxxxxxx rewind failed %d\n", value);
+ }
+#endif
+ return value == 0;
+ }
+ return false;
+}
+
+size_t SkFDStream::read(void* buffer, size_t size) {
+ if (fFD >= 0) {
+ if (buffer == NULL && size == 0) { // request total size
+ off_t curr = ::lseek(fFD, 0, SEEK_CUR);
+ if (curr < 0) {
+#ifdef TRACE_FDSTREAM
+ SkDebugf("xxxxxxxxxxxxx lseek failed 0 CURR\n");
+#endif
+ return 0; // error
+ }
+ off_t size = ::lseek(fFD, 0, SEEK_END);
+ if (size < 0) {
+#ifdef TRACE_FDSTREAM
+ SkDebugf("xxxxxxxxxxxxx lseek failed 0 END\n");
+#endif
+ size = 0; // error
+ }
+ if (::lseek(fFD, curr, SEEK_SET) != curr) {
+ // can't restore, error
+#ifdef TRACE_FDSTREAM
+ SkDebugf("xxxxxxxxxxxxx lseek failed %d SET\n", curr);
+#endif
+ return 0;
+ }
+ return size;
+ } else if (NULL == buffer) { // skip
+ off_t oldCurr = ::lseek(fFD, 0, SEEK_CUR);
+ if (oldCurr < 0) {
+#ifdef TRACE_FDSTREAM
+ SkDebugf("xxxxxxxxxxxxx lseek1 failed %d CUR\n", oldCurr);
+#endif
+ return 0; // error;
+ }
+ off_t newCurr = ::lseek(fFD, size, SEEK_CUR);
+ if (newCurr < 0) {
+#ifdef TRACE_FDSTREAM
+ SkDebugf("xxxxxxxxxxxxx lseek2 failed %d CUR\n", newCurr);
+#endif
+ return 0; // error;
+ }
+ // return the actual amount we skipped
+ return newCurr - oldCurr;
+ } else { // read
+ ssize_t actual = ::read(fFD, buffer, size);
+ // our API can't return an error, so we return 0
+ if (actual < 0) {
+#ifdef TRACE_FDSTREAM
+ SkDebugf("xxxxxxxxxxxxx read failed %d actual %d\n", size, actual);
+#endif
+ actual = 0;
+ }
+ return actual;
+ }
+ }
+ return 0;
+}
+
diff --git a/skia/images/SkFlipPixelRef.cpp b/skia/images/SkFlipPixelRef.cpp
new file mode 100644
index 0000000..95403cc
--- /dev/null
+++ b/skia/images/SkFlipPixelRef.cpp
@@ -0,0 +1,127 @@
+#include "SkFlipPixelRef.h"
+#include "SkFlattenable.h"
+#include "SkRegion.h"
+
+SkFlipPixelRef::SkFlipPixelRef(SkBitmap::Config config, int width, int height)
+: fFlipper(width, height) {
+ fConfig = config;
+ fSize = SkBitmap::ComputeSize(config, width, height);
+ fStorage = sk_malloc_throw(fSize << 1);
+ fPage0 = fStorage;
+ fPage1 = (char*)fStorage + fSize;
+}
+
+SkFlipPixelRef::~SkFlipPixelRef() {
+ sk_free(fStorage);
+}
+
+const SkRegion& SkFlipPixelRef::beginUpdate(SkBitmap* device) {
+ void* writeAddr;
+ const void* readAddr;
+ this->getFrontBack(&readAddr, &writeAddr);
+
+ device->setConfig(fConfig, fFlipper.width(), fFlipper.height());
+ device->setPixels(writeAddr);
+
+ SkRegion copyBits;
+ const SkRegion& dirty = fFlipper.update(&copyBits);
+
+ SkFlipPixelRef::CopyBitsFromAddr(*device, copyBits, readAddr);
+ return dirty;
+}
+
+void SkFlipPixelRef::endUpdate() {
+ this->swapPages();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void* SkFlipPixelRef::onLockPixels(SkColorTable** ct) {
+ fMutex.acquire();
+ *ct = NULL;
+ return fPage0;
+}
+
+void SkFlipPixelRef::onUnlockPixels() {
+ fMutex.release();
+}
+
+void SkFlipPixelRef::swapPages() {
+ fMutex.acquire();
+ SkTSwap<void*>(fPage0, fPage1);
+ fMutex.release();
+}
+
+void SkFlipPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const {
+ this->INHERITED::flatten(buffer);
+
+ buffer.write32(fSize);
+ // only need to write page0
+ buffer.writePad(fPage0, fSize);
+}
+
+SkFlipPixelRef::SkFlipPixelRef(SkFlattenableReadBuffer& buffer)
+ : INHERITED(buffer, NULL) {
+ fSize = buffer.readU32();
+ fStorage = sk_malloc_throw(fSize << 1);
+ fPage0 = fStorage;
+ fPage1 = (char*)fStorage + fSize;
+ buffer.read(fPage0, fSize);
+}
+
+SkPixelRef* SkFlipPixelRef::Create(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkFlipPixelRef, (buffer));
+}
+
+static SkPixelRef::Registrar::Registrar reg("SkFlipPixelRef",
+ SkFlipPixelRef::Create);
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void copyRect(const SkBitmap& dst, const SkIRect& rect,
+ const void* srcAddr, int shift) {
+ const size_t offset = rect.fTop * dst.rowBytes() + (rect.fLeft << shift);
+ char* dstP = static_cast<char*>(dst.getPixels()) + offset;
+ const char* srcP = static_cast<const char*>(srcAddr) + offset;
+ const size_t rb = dst.rowBytes();
+ const size_t bytes = rect.width() << shift;
+
+ int height = rect.height();
+ while (--height >= 0) {
+ memcpy(dstP, srcP, bytes);
+ dstP += rb;
+ srcP += rb;
+ }
+}
+
+static int getShift(SkBitmap::Config config) {
+ switch (config) {
+ case SkBitmap::kARGB_8888_Config:
+ return 2;
+ case SkBitmap::kRGB_565_Config:
+ case SkBitmap::kARGB_4444_Config:
+ return 1;
+ case SkBitmap::kIndex8_Config:
+ case SkBitmap::kA8_Config:
+ return 0;
+ default:
+ return -1; // signal not supported
+ }
+}
+
+void SkFlipPixelRef::CopyBitsFromAddr(const SkBitmap& dst, const SkRegion& clip,
+ const void* srcAddr) {
+ const int shift = getShift(dst.config());
+ if (shift < 0) {
+ return;
+ }
+
+ const SkIRect bounds = {0, 0, dst.width(), dst.height()};
+ SkRegion::Cliperator iter(clip, bounds);
+
+ while (!iter.done()) {
+ copyRect(dst, iter.rect(), srcAddr, shift);
+ iter.next();
+ }
+}
+
diff --git a/skia/images/SkImageDecoder.cpp b/skia/images/SkImageDecoder.cpp
index 3579e3c..405b660 100644
--- a/skia/images/SkImageDecoder.cpp
+++ b/skia/images/SkImageDecoder.cpp
@@ -1,6 +1,6 @@
/* libs/graphics/images/SkImageDecoder.cpp
**
-** Copyright 2006, Google Inc.
+** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -89,6 +89,29 @@ bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
///////////////////////////////////////////////////////////////////////////////
+bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm,
+ SkBitmap::Config pref, Mode mode) {
+ SkBitmap tmp;
+
+ // we reset this to false before calling onDecode
+ fShouldCancelDecode = false;
+
+ // pass a temporary bitmap, so that if we return false, we are assured of
+ // leaving the caller's bitmap untouched.
+ if (this->onDecode(stream, &tmp, pref, mode)) {
+ /* We operate on a tmp bitmap until we know we succeed. This way
+ we're sure we don't change the caller's bitmap and then later
+ return false. Returning false must mean that their parameter
+ is unchanged.
+ */
+ bm->swap(tmp);
+ return true;
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm,
SkBitmap::Config pref, Mode mode) {
SkASSERT(file);
@@ -115,23 +138,14 @@ bool SkImageDecoder::DecodeStream(SkStream* stream, SkBitmap* bm,
SkASSERT(stream);
SkASSERT(bm);
+ bool success = false;
SkImageDecoder* codec = SkImageDecoder::Factory(stream);
+
if (NULL != codec) {
- SkBitmap tmp;
-
- SkAutoTDelete<SkImageDecoder> ad(codec);
-
- if (codec->onDecode(stream, &tmp, pref, mode)) {
- /* We operate on a tmp bitmap until we know we succeed. This way
- we're sure we don't change the caller's bitmap and then later
- return false. Returning false must mean that their parameter
- is unchanged.
- */
- bm->swap(tmp);
- return true;
- }
+ success = codec->decode(stream, bm, pref, mode);
+ delete codec;
}
- return false;
+ return success;
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/skia/images/SkImageDecoder_fpdfemb.cpp b/skia/images/SkImageDecoder_fpdfemb.cpp
new file mode 100644
index 0000000..7f37e3d
--- /dev/null
+++ b/skia/images/SkImageDecoder_fpdfemb.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SkImageDecoder.h"
+#include "SkScaledBitmapSampler.h"
+#include "SkStream.h"
+#include "SkColorPriv.h"
+#include "SkTDArray.h"
+
+#include "fpdfemb.h"
+
+class SkFPDFEMBImageDecoder : public SkImageDecoder {
+public:
+ SkFPDFEMBImageDecoder() {}
+
+ virtual Format getFormat() const {
+ return kBMP_Format;
+ }
+
+protected:
+ virtual bool onDecode(SkStream* stream, SkBitmap* bm,
+ SkBitmap::Config pref, Mode mode);
+
+private:
+ bool render(FPDFEMB_PAGE page, const FPDFEMB_RECT& bounds, SkBitmap* bm,
+ SkBitmap::Config prefConfig, SkImageDecoder::Mode mode);
+};
+
+SkImageDecoder* SkImageDecoder_FPDFEMB_Factory(SkStream*);
+SkImageDecoder* SkImageDecoder_FPDFEMB_Factory(SkStream* stream) {
+ static const char kPDFSig[] = { '%', 'P', 'D', 'F' };
+
+ size_t len = stream->getLength();
+ char buffer[sizeof(kPDFSig)];
+
+ SkDebugf("---- SkImageDecoder_FPDFEMB_Factory len=%d\n", len);
+
+ if (len != 12683) { return NULL; }
+
+ if (len > sizeof(kPDFSig) &&
+ stream->read(buffer, sizeof(kPDFSig)) == sizeof(kPDFSig) &&
+ !memcmp(buffer, kPDFSig, sizeof(kPDFSig))) {
+ return SkNEW(SkFPDFEMBImageDecoder);
+ }
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+extern "C" {
+ static void* pdf_alloc(FPDFEMB_MEMMGR* pMgr, unsigned int size) {
+ void* addr = sk_malloc_throw(size);
+ // SkDebugf("---- pdf_alloc %d %p\n", size, addr);
+ return addr;
+ }
+
+ static void* pdf_alloc_nl(FPDFEMB_MEMMGR* pMgr, unsigned int size) {
+ void* addr = sk_malloc_flags(size, 0);
+ // SkDebugf("---- pdf_alloc_nl %d %p\n", size, addr);
+ return addr;
+ }
+
+ static void* pdf_realloc(FPDFEMB_MEMMGR*, void* addr, unsigned int size) {
+ void* newaddr = sk_realloc_throw(addr, size);
+ // SkDebugf("---- pdf_realloc %p %d %p\n", addr, size, newaddr);
+ return newaddr;
+ }
+
+ static void pdf_free(FPDFEMB_MEMMGR* pMgr, void* pointer) {
+ // SkDebugf("---- pdf_free %p\n", pointer);
+ sk_free(pointer);
+ }
+
+ void FX_OUTPUT_LOG_FUNC(const char* format, ...) {
+ SkDebugf("---- LOG_FUNC %s\n", format);
+ }
+
+ static unsigned int file_getsize(FPDFEMB_FILE_ACCESS* file) {
+ SkStream* stream = (SkStream*)file->user;
+ return stream->getLength();
+ }
+
+ static FPDFEMB_RESULT file_readblock(FPDFEMB_FILE_ACCESS* file, void* dst,
+ unsigned int offset, unsigned int size) {
+ SkStream* stream = (SkStream*)file->user;
+// SkDebugf("---- readblock %p %p %d %d\n", stream, dst, offset, size);
+ if (!stream->rewind()) {
+ SkDebugf("---- rewind failed\n");
+ return FPDFERR_ERROR;
+ }
+ if (stream->skip(offset) != offset) {
+ SkDebugf("---- skip failed\n");
+ return FPDFERR_ERROR;
+ }
+ if (stream->read(dst, size) != size) {
+ SkDebugf("---- read failed\n");
+ return FPDFERR_ERROR;
+ }
+ return FPDFERR_SUCCESS;
+ }
+
+ static void pdf_oom_handler(void* memory, int size) {
+ SkDebugf("======== pdf OOM %p %d\n", memory, size);
+ }
+}
+
+static inline int PDF2Pixels(int x) { return x / 100; }
+static inline SkScalar PDF2Scalar(int x) {
+ return SkScalarMulDiv(SK_Scalar1, x, 100);
+}
+
+bool SkFPDFEMBImageDecoder::render(FPDFEMB_PAGE page, const FPDFEMB_RECT& bounds, SkBitmap* bm,
+ SkBitmap::Config prefConfig, SkImageDecoder::Mode mode) {
+ int width = PDF2Pixels(bounds.right - bounds.left);
+ int height = PDF2Pixels(bounds.top - bounds.bottom);
+
+ SkDebugf("----- bitmap size [%d %d], mode=%d\n", width, height, mode);
+ bm->setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ if (SkImageDecoder::kDecodeBounds_Mode == mode) {
+ return true;
+ }
+
+ // USE THE CODEC TO ALLOCATE THE PIXELS!!!!
+ if (!this->allocPixelRef(bm, NULL)) {
+ SkDebugf("----- failed to alloc pixels\n");
+ return false;
+ }
+
+ bm->eraseColor(0);
+
+ FPDFEMB_RESULT result;
+ FPDFEMB_BITMAP dib;
+
+ result = FPDFEMB_CreateDIB(width, height, FPDFDIB_BGRA, bm->getPixels(),
+ bm->rowBytes(), &dib);
+ SkDebugf("---- createdib %d\n", result);
+
+ result = FPDFEMB_StartRender(dib, page, 0, 0, width, height, 0, 0, NULL, NULL);
+ SkDebugf("---- render %d\n", result);
+
+ result = FPDFEMB_DestroyDIB(dib);
+ SkDebugf("---- destroydib %d\n", result);
+
+ SkPMColor* dst = bm->getAddr32(0, 0);
+ const uint8_t* src = (uint8_t*)dst;
+ int n = bm->getSize() >> 2;
+ for (int i = 0; i < n; i++) {
+ int b = *src++;
+ int g = *src++;
+ int r = *src++;
+ int a = *src++;
+ *dst++ = SkPackARGB32(a, r, g, b);
+ }
+
+ return true;
+}
+
+#define USE_FIXED_MEM (4 * 1024 * 1024)
+
+bool SkFPDFEMBImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
+ SkBitmap::Config prefConfig, Mode mode) {
+
+ FPDFEMB_RESULT result;
+#ifdef USE_FIXED_MEM
+ SkAutoMalloc storage(USE_FIXED_MEM);
+ result = FPDFEMB_InitFixedMemory(storage.get(), USE_FIXED_MEM,
+ pdf_oom_handler);
+#else
+ FPDFEMB_MEMMGR memmgr;
+ memmgr.Alloc = pdf_alloc;
+ memmgr.AllocNL = pdf_alloc_nl;
+ memmgr.Realloc = pdf_realloc;
+ memmgr.Free = pdf_free;
+
+ result = FPDFEMB_Init(&memmgr);
+#endif
+ SkDebugf("----- SkImageDecoder_FPDFEMB_Factory init %d, streamLen = %d\n", result, stream->getLength());
+
+ FPDFEMB_FILE_ACCESS file;
+ file.GetSize = file_getsize;
+ file.ReadBlock = file_readblock;
+ file.user = stream;
+
+ FPDFEMB_DOCUMENT document;
+ result = FPDFEMB_StartLoadDocument(&file, NULL, &document, NULL);
+ SkDebugf("----- SkImageDecoder_FPDFEMB_Factory open %d %p\n", result, document);
+
+ int pageCount = FPDFEMB_GetPageCount(document);
+ SkDebugf("----- SkImageDecoder_FPDFEMB_Factory pageCount %d\n", pageCount);
+
+ if (pageCount > 0) {
+ FPDFEMB_PAGE page;
+ result = FPDFEMB_LoadPage(document, 0, &page);
+ SkDebugf("----- SkImageDecoder_FPDFEMB_Factory load page %d\n", result);
+
+ int width, height;
+ result = FPDFEMB_GetPageSize(page, &width, &height);
+ SkDebugf("----- SkImageDecoder_FPDFEMB_Factory page size %d [%d %d]\n", result, width, height);
+
+ FPDFEMB_RECT rect;
+ result = FPDFEMB_GetPageBBox(page, &rect);
+ SkDebugf("----- SkImageDecoder_FPDFEMB_Factory page rect %d [%d %d %d %d]\n", result,
+ rect.left, rect.top, rect.right, rect.bottom);
+
+ SkDebugf("----- SkImageDecoder_FPDFEMB_Factory begin page parse...\n");
+ result = FPDFEMB_StartParse(page, false, NULL);
+ SkDebugf("----- SkImageDecoder_FPDFEMB_Factory page parse %d\n", result);
+
+ if (0 == result) {
+ this->render(page, rect, bm, prefConfig, mode);
+ }
+
+ result = FPDFEMB_ClosePage(page);
+ SkDebugf("----- SkImageDecoder_FPDFEMB_Factory close page %d\n", result);
+ }
+
+ result = FPDFEMB_CloseDocument(document);
+ SkDebugf("----- SkImageDecoder_FPDFEMB_Factory close %d\n", result);
+
+ // FPDFEMB_Exit();
+
+ return true;
+}
diff --git a/skia/images/SkImageDecoder_libbmp.cpp b/skia/images/SkImageDecoder_libbmp.cpp
index 0de760f..32a7a6d 100644
--- a/skia/images/SkImageDecoder_libbmp.cpp
+++ b/skia/images/SkImageDecoder_libbmp.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2007, Google Inc.
+ * Copyright 2007, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/skia/images/SkImageDecoder_libgif.cpp b/skia/images/SkImageDecoder_libgif.cpp
index 3b5e420..c894c9d 100644
--- a/skia/images/SkImageDecoder_libgif.cpp
+++ b/skia/images/SkImageDecoder_libgif.cpp
@@ -1,6 +1,6 @@
/* libs/graphics/images/SkImageDecoder_libgif.cpp
**
-** Copyright 2006, Google Inc.
+** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -145,11 +145,20 @@ static int find_transpIndex(const SavedImage& image, int colorCount) {
return transpIndex;
}
+static bool error_return(GifFileType* gif, const SkBitmap& bm,
+ const char msg[]) {
+#if 0
+ SkDebugf("libgif error <%s> bitmap [%d %d] pixels %p colortable %p\n",
+ msg, bm.width(), bm.height(), bm.getPixels(), bm.getColorTable());
+#endif
+ return false;
+}
+
bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm,
SkBitmap::Config prefConfig, Mode mode) {
GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc);
if (NULL == gif) {
- return false;
+ return error_return(gif, *bm, "DGifOpen");
}
SkAutoTCallIProc<GifFileType, DGifCloseFile> acp(gif);
@@ -165,17 +174,17 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm,
do {
if (DGifGetRecordType(gif, &recType) == GIF_ERROR) {
- return false;
+ return error_return(gif, *bm, "DGifGetRecordType");
}
switch (recType) {
case IMAGE_DESC_RECORD_TYPE: {
if (DGifGetImageDesc(gif) == GIF_ERROR) {
- return false;
+ return error_return(gif, *bm, "IMAGE_DESC_RECORD_TYPE");
}
if (gif->ImageCount < 1) { // sanity check
- return false;
+ return error_return(gif, *bm, "ImageCount < 1");
}
width = gif->SWidth;
@@ -183,7 +192,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm,
if (width <= 0 || height <= 0 ||
!this->chooseFromOneChoice(SkBitmap::kIndex8_Config,
width, height)) {
- return false;
+ return error_return(gif, *bm, "chooseFromOneChoice");
}
bm->setConfig(SkBitmap::kIndex8_Config, width, height);
@@ -197,7 +206,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm,
if ( (desc.Top | desc.Left) < 0 ||
desc.Left + desc.Width > width ||
desc.Top + desc.Height > height) {
- return false;
+ return error_return(gif, *bm, "TopLeft");
}
// now we decode the colortable
@@ -205,7 +214,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm,
{
const ColorMapObject* cmap = find_colormap(gif);
if (NULL == cmap) {
- return false;
+ return error_return(gif, *bm, "null cmap");
}
colorCount = cmap->ColorCount;
@@ -226,7 +235,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm,
SkAutoUnref aurts(ctable);
if (!this->allocPixelRef(bm, ctable)) {
- return false;
+ return error_return(gif, *bm, "allocPixelRef");
}
}
@@ -241,7 +250,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm,
// abort if either inner dimension is <= 0
if (innerWidth <= 0 || innerHeight <= 0) {
- return false;
+ return error_return(gif, *bm, "non-pos inner width/height");
}
// are we only a subset of the total bounds?
@@ -266,7 +275,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm,
{
uint8_t* row = scanline + iter.currY() * rowBytes;
if (DGifGetLine(gif, row, innerWidth) == GIF_ERROR) {
- return false;
+ return error_return(gif, *bm, "interlace DGifGetLine");
}
iter.next();
}
@@ -276,7 +285,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm,
// easy, non-interlace case
for (int y = 0; y < innerHeight; y++) {
if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) {
- return false;
+ return error_return(gif, *bm, "DGifGetLine");
}
scanline += rowBytes;
}
@@ -287,17 +296,17 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm,
case EXTENSION_RECORD_TYPE:
if (DGifGetExtension(gif, &temp_save.Function,
&extData) == GIF_ERROR) {
- return false;
+ return error_return(gif, *bm, "DGifGetExtension");
}
while (extData != NULL) {
/* Create an extension block with our data */
if (AddExtensionBlock(&temp_save, extData[0],
&extData[1]) == GIF_ERROR) {
- return false;
+ return error_return(gif, *bm, "AddExtensionBlock");
}
if (DGifGetExtensionNext(gif, &extData) == GIF_ERROR) {
- return false;
+ return error_return(gif, *bm, "DGifGetExtensionNext");
}
temp_save.Function = 0;
}
diff --git a/skia/images/SkImageDecoder_libico.cpp b/skia/images/SkImageDecoder_libico.cpp
index 8b1be08..b179a6b 100644
--- a/skia/images/SkImageDecoder_libico.cpp
+++ b/skia/images/SkImageDecoder_libico.cpp
@@ -1,6 +1,6 @@
/* libs/graphics/images/SkImageDecoder_libico.cpp
**
-** Copyright 2006, Google Inc.
+** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -82,6 +82,20 @@ static void editPixelBit32(const int pixelNo, const unsigned char* buf,
const int xorOffset, int& x, int y, const int w,
SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors);
+
+static int calculateRowBytesFor8888(int w, int bitCount)
+{
+ // Default rowBytes is w << 2 for kARGB_8888
+ // In the case of a 4 bit image with an odd width, we need to add some
+ // so we can go off the end of the drawn bitmap.
+ // Add 4 to ensure that it is still a multiple of 4.
+ if (4 == bitCount && (w & 0x1)) {
+ return (w + 1) << 2;
+ }
+ // Otherwise return 0, which will allow it to be calculated automatically.
+ return 0;
+}
+
bool SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
SkBitmap::Config pref, Mode mode)
{
@@ -241,11 +255,8 @@ bool SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
//FIXME: what is the tradeoff in size?
//if the andbitmap (mask) is all zeroes, then we can easily do an index bitmap
//however, with small images with large colortables, maybe it's better to still do argb_8888
- //default rowBytes is w << 2 for kARGB_8888
- //i'm adding one - it's only truly necessary in the case that w is odd and we are four bit
- //so we can go off the end of the drawn bitmap
- //FIXME: need to test with an odd width bitmap that is 4bit
- bm->setConfig(SkBitmap::kARGB_8888_Config, w, h, (w << 2) + (0x1 & w & (bitCount >> 2)));
+
+ bm->setConfig(SkBitmap::kARGB_8888_Config, w, h, calculateRowBytesFor8888(w, bitCount));
if (SkImageDecoder::kDecodeBounds_Mode == mode) {
delete[] colors;
@@ -298,7 +309,12 @@ static void editPixelBit1(const int pixelNo, const unsigned char* buf,
int byte = readByte(buf, xorOffset + (pixelNo >> 3));
int colorBit;
int alphaBit;
+ // Read all of the bits in this byte.
int i = x + 8;
+ // Pin to the width so we do not write outside the bounds of
+ // our color table.
+ i = i > w ? w : i;
+ // While loop to check all 8 bits individually.
while (x < i)
{
diff --git a/skia/images/SkImageDecoder_libjpeg.cpp b/skia/images/SkImageDecoder_libjpeg.cpp
index 0d8da7ef..492de23 100644
--- a/skia/images/SkImageDecoder_libjpeg.cpp
+++ b/skia/images/SkImageDecoder_libjpeg.cpp
@@ -1,16 +1,16 @@
/*
- * Copyright 2007, Google Inc.
+ * Copyright 2007, The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
*/
@@ -25,6 +25,7 @@
#include <stdio.h>
extern "C" {
#include "jpeglib.h"
+ #include "jerror.h"
}
// this enables timing code to report milliseconds for an encode
@@ -49,8 +50,21 @@ protected:
SkBitmap::Config pref, Mode);
};
-SkImageDecoder* SkImageDecoder_JPEG_Factory(SkStream* stream) {
- // !!! unimplemented; rely on PNG test first for now
+SkImageDecoder* SkImageDecoder_JPEG_Factory(SkStream* stream) {
+ static const char gHeader[] = { 0xFF, 0xD8, 0xFF };
+ static const size_t HEADER_SIZE = sizeof(gHeader);
+
+ char buffer[HEADER_SIZE];
+ size_t len = stream->read(buffer, HEADER_SIZE);
+
+ if (len != HEADER_SIZE) {
+ return NULL; // can't read enough
+ }
+
+ if (memcmp(buffer, gHeader, HEADER_SIZE)) {
+ return NULL;
+ }
+
return SkNEW(SkJPEGImageDecoder);
}
@@ -77,10 +91,12 @@ private:
/* our source struct for directing jpeg to our stream object
*/
struct sk_source_mgr : jpeg_source_mgr {
- sk_source_mgr(SkStream* stream);
+ sk_source_mgr(SkStream* stream, SkImageDecoder* decoder);
SkStream* fStream;
-
+ const void* fMemoryBase;
+ size_t fMemoryBaseSize;
+ SkImageDecoder* fDecoder;
enum {
kBufferSize = 1024
};
@@ -111,11 +127,13 @@ static void sk_init_source(j_decompress_ptr cinfo) {
static boolean sk_fill_input_buffer(j_decompress_ptr cinfo) {
sk_source_mgr* src = (sk_source_mgr*)cinfo->src;
+ if (src->fDecoder != NULL && src->fDecoder->shouldCancelDecode()) {
+ return FALSE;
+ }
size_t bytes = src->fStream->read(src->fBuffer, sk_source_mgr::kBufferSize);
// note that JPEG is happy with less than the full read,
// as long as the result is non-zero
if (bytes == 0) {
- cinfo->err->error_exit((j_common_ptr)cinfo);
return FALSE;
}
@@ -129,11 +147,13 @@ static void sk_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
sk_source_mgr* src = (sk_source_mgr*)cinfo->src;
- long skip = num_bytes - src->bytes_in_buffer;
+ long bytesToSkip = num_bytes - src->bytes_in_buffer;
- if (skip > 0) {
- size_t bytes = src->fStream->read(NULL, skip);
- if (bytes != (size_t)skip) {
+ // check if the skip amount exceeds the current buffer
+ if (bytesToSkip > 0) {
+ size_t bytes = src->fStream->skip(bytesToSkip);
+ if (bytes != (size_t)bytesToSkip) {
+// SkDebugf("xxxxxxxxxxxxxx failure to skip request %d actual %d\n", bytesToSkip, bytes);
cinfo->err->error_exit((j_common_ptr)cinfo);
}
src->next_input_byte = (const JOCTET*)src->fBuffer;
@@ -150,22 +170,69 @@ static boolean sk_resync_to_restart(j_decompress_ptr cinfo, int desired) {
// what is the desired param for???
if (!src->fStream->rewind()) {
- printf("------------- sk_resync_to_restart: stream->rewind() failed\n");
+ SkDebugf("xxxxxxxxxxxxxx failure to rewind\n");
cinfo->err->error_exit((j_common_ptr)cinfo);
return FALSE;
}
+ src->next_input_byte = (const JOCTET*)src->fBuffer;
+ src->bytes_in_buffer = 0;
return TRUE;
}
static void sk_term_source(j_decompress_ptr /*cinfo*/) {}
-sk_source_mgr::sk_source_mgr(SkStream* stream)
- : fStream(stream) {
- init_source = sk_init_source;
- fill_input_buffer = sk_fill_input_buffer;
- skip_input_data = sk_skip_input_data;
- resync_to_restart = sk_resync_to_restart;
- term_source = sk_term_source;
+///////////////////////////////////////////////////////////////////////////////
+
+static void skmem_init_source(j_decompress_ptr cinfo) {
+ sk_source_mgr* src = (sk_source_mgr*)cinfo->src;
+ src->next_input_byte = (const JOCTET*)src->fMemoryBase;
+ src->bytes_in_buffer = src->fMemoryBaseSize;
+}
+
+static boolean skmem_fill_input_buffer(j_decompress_ptr cinfo) {
+ SkDebugf("xxxxxxxxxxxxxx skmem_fill_input_buffer called\n");
+ return FALSE;
+}
+
+static void skmem_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
+ sk_source_mgr* src = (sk_source_mgr*)cinfo->src;
+// SkDebugf("xxxxxxxxxxxxxx skmem_skip_input_data called %d\n", num_bytes);
+ src->next_input_byte = (const JOCTET*)((const char*)src->next_input_byte + num_bytes);
+ src->bytes_in_buffer -= num_bytes;
+}
+
+static boolean skmem_resync_to_restart(j_decompress_ptr cinfo, int desired) {
+ SkDebugf("xxxxxxxxxxxxxx skmem_resync_to_restart called\n");
+ return TRUE;
+}
+
+static void skmem_term_source(j_decompress_ptr /*cinfo*/) {}
+
+///////////////////////////////////////////////////////////////////////////////
+
+sk_source_mgr::sk_source_mgr(SkStream* stream, SkImageDecoder* decoder) : fStream(stream) {
+ fDecoder = decoder;
+ const void* baseAddr = stream->getMemoryBase();
+ if (baseAddr && false) {
+ fMemoryBase = baseAddr;
+ fMemoryBaseSize = stream->getLength();
+
+ init_source = skmem_init_source;
+ fill_input_buffer = skmem_fill_input_buffer;
+ skip_input_data = skmem_skip_input_data;
+ resync_to_restart = skmem_resync_to_restart;
+ term_source = skmem_term_source;
+ } else {
+ fMemoryBase = NULL;
+ fMemoryBaseSize = 0;
+
+ init_source = sk_init_source;
+ fill_input_buffer = sk_fill_input_buffer;
+ skip_input_data = sk_skip_input_data;
+ resync_to_restart = sk_resync_to_restart;
+ term_source = sk_term_source;
+ }
+// SkDebugf("**************** use memorybase %p %d\n", fMemoryBase, fMemoryBaseSize);
}
#include <setjmp.h>
@@ -187,14 +254,29 @@ static void sk_error_exit(j_common_ptr cinfo) {
///////////////////////////////////////////////////////////////////////////////
-static void skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer,
+static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer,
int count) {
for (int i = 0; i < count; i++) {
JSAMPLE* rowptr = (JSAMPLE*)buffer;
int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1);
- SkASSERT(row_count == 1);
+ if (row_count != 1) {
+ return false;
+ }
}
-}
+ return true;
+}
+
+// This guy exists just to aid in debugging, as it allows debuggers to just
+// set a break-point in one place to see all error exists.
+static bool return_false(const jpeg_decompress_struct& cinfo,
+ const SkBitmap& bm, const char msg[]) {
+#if 0
+ SkDebugf("libjpeg error %d <%s> from %s [%d %d]", cinfo.err->msg_code,
+ cinfo.err->jpeg_message_table[cinfo.err->msg_code], msg,
+ bm.width(), bm.height());
+#endif
+ return false; // must always return false
+}
bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
SkBitmap::Config prefConfig, Mode mode) {
@@ -207,7 +289,7 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
jpeg_decompress_struct cinfo;
sk_error_mgr sk_err;
- sk_source_mgr sk_stream(stream);
+ sk_source_mgr sk_stream(stream, this);
cinfo.err = jpeg_std_error(&sk_err);
sk_err.error_exit = sk_error_exit;
@@ -215,7 +297,7 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
// All objects need to be instantiated before this setjmp call so that
// they will be cleaned up properly if an error occurs.
if (setjmp(sk_err.fJmpBuf)) {
- return false;
+ return return_false(cinfo, *bm, "setjmp");
}
jpeg_create_decompress(&cinfo);
@@ -224,7 +306,10 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
//jpeg_stdio_src(&cinfo, file);
cinfo.src = &sk_stream;
- jpeg_read_header(&cinfo, true);
+ int status = jpeg_read_header(&cinfo, true);
+ if (status != JPEG_HEADER_OK) {
+ return return_false(cinfo, *bm, "read_header");
+ }
/* Try to fulfill the requested sampleSize. Since jpeg can do it (when it
can) much faster that we, just use their num/denom api to approximate
@@ -236,55 +321,128 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
cinfo.scale_num = 1;
cinfo.scale_denom = sampleSize;
+ /* this gives about 30% performance improvement. In theory it may
+ reduce the visual quality, in practice I'm not seeing a difference
+ */
+ cinfo.do_fancy_upsampling = 0;
+
+ /* this gives another few percents */
+ cinfo.do_block_smoothing = 0;
+
+ /* default format is RGB */
+ cinfo.out_color_space = JCS_RGB;
+
+ SkBitmap::Config config = prefConfig;
+ // if no user preference, see what the device recommends
+ if (config == SkBitmap::kNo_Config)
+ config = SkImageDecoder::GetDeviceConfig();
+
+ // only these make sense for jpegs
+ if (config != SkBitmap::kARGB_8888_Config &&
+ config != SkBitmap::kARGB_4444_Config &&
+ config != SkBitmap::kRGB_565_Config) {
+ config = SkBitmap::kARGB_8888_Config;
+ }
+
+#ifdef ANDROID_RGB
+ cinfo.dither_mode = JDITHER_NONE;
+ if (config == SkBitmap::kARGB_8888_Config) {
+ cinfo.out_color_space = JCS_RGBA_8888;
+ } else if (config == SkBitmap::kRGB_565_Config) {
+ if (sampleSize == 1) {
+ // SkScaledBitmapSampler can't handle RGB_565 yet,
+ // so don't even try.
+ cinfo.out_color_space = JCS_RGB_565;
+ if (this->getDitherImage()) {
+ cinfo.dither_mode = JDITHER_ORDERED;
+ }
+ }
+ }
+#endif
+
/* image_width and image_height are the original dimensions, available
after jpeg_read_header(). To see the scaled dimensions, we have to call
jpeg_start_decompress(), and then read output_width and output_height.
*/
- jpeg_start_decompress(&cinfo);
+ if (!jpeg_start_decompress(&cinfo)) {
+ return return_false(cinfo, *bm, "start_decompress");
+ }
/* If we need to better match the request, we might examine the image and
output dimensions, and determine if the downsampling jpeg provided is
not sufficient. If so, we can recompute a modified sampleSize value to
make up the difference.
-
+
To skip this additional scaling, just set sampleSize = 1; below.
*/
sampleSize = sampleSize * cinfo.output_width / cinfo.image_width;
- // check for supported formats
- bool isRGB; // as opposed to gray8
- if (3 == cinfo.num_components && JCS_RGB == cinfo.out_color_space) {
- isRGB = true;
- } else if (1 == cinfo.num_components &&
- JCS_GRAYSCALE == cinfo.out_color_space) {
- isRGB = false; // could use Index8 config if we want...
- } else {
- SkDEBUGF(("SkJPEGImageDecoder: unsupported jpeg colorspace %d with %d components\n",
- cinfo.jpeg_color_space, cinfo.num_components));
- return false;
- }
-
- SkBitmap::Config config = prefConfig;
- // if no user preference, see what the device recommends
- if (config == SkBitmap::kNo_Config)
- config = SkImageDecoder::GetDeviceConfig();
-
- // only these make sense for jpegs
- if (config != SkBitmap::kARGB_8888_Config &&
- config != SkBitmap::kARGB_4444_Config &&
- config != SkBitmap::kRGB_565_Config) {
- config = SkBitmap::kARGB_8888_Config;
- }
// should we allow the Chooser (if present) to pick a config for us???
if (!this->chooseFromOneChoice(config, cinfo.output_width,
cinfo.output_height)) {
- return false;
+ return return_false(cinfo, *bm, "chooseFromOneChoice");
+ }
+
+#ifdef ANDROID_RGB
+ /* short-circuit the SkScaledBitmapSampler when possible, as this gives
+ a significant performance boost.
+ */
+ if (sampleSize == 1 &&
+ ((config == SkBitmap::kARGB_8888_Config &&
+ cinfo.out_color_space == JCS_RGBA_8888) ||
+ (config == SkBitmap::kRGB_565_Config &&
+ cinfo.out_color_space == JCS_RGB_565)))
+ {
+ bm->setConfig(config, cinfo.output_width, cinfo.output_height);
+ bm->setIsOpaque(true);
+ if (SkImageDecoder::kDecodeBounds_Mode == mode) {
+ return true;
+ }
+ if (!this->allocPixelRef(bm, NULL)) {
+ return return_false(cinfo, *bm, "allocPixelRef");
+ }
+ SkAutoLockPixels alp(*bm);
+ JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
+ INT32 const bpr = bm->rowBytes();
+
+ while (cinfo.output_scanline < cinfo.output_height) {
+ int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
+ // if row_count == 0, then we didn't get a scanline, so abort.
+ // if we supported partial images, we might return true in this case
+ if (0 == row_count) {
+ return return_false(cinfo, *bm, "read_scanlines");
+ }
+ if (this->shouldCancelDecode()) {
+ return return_false(cinfo, *bm, "shouldCancelDecode");
+ }
+ rowptr += bpr;
+ }
+ jpeg_finish_decompress(&cinfo);
+ return true;
+ }
+#endif
+
+ // check for supported formats
+ SkScaledBitmapSampler::SrcConfig sc;
+ if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
+ sc = SkScaledBitmapSampler::kRGB;
+#ifdef ANDROID_RGB
+ } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
+ sc = SkScaledBitmapSampler::kRGBX;
+ //} else if (JCS_RGB_565 == cinfo.out_color_space) {
+ // sc = SkScaledBitmapSampler::kRGB_565;
+#endif
+ } else if (1 == cinfo.out_color_components &&
+ JCS_GRAYSCALE == cinfo.out_color_space) {
+ sc = SkScaledBitmapSampler::kGray;
+ } else {
+ return return_false(cinfo, *bm, "jpeg colorspace");
}
SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height,
sampleSize);
-
+
bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
// jpegs are always opauqe (i.e. have no per-pixel alpha)
bm->setIsOpaque(true);
@@ -293,38 +451,51 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
return true;
}
if (!this->allocPixelRef(bm, NULL)) {
- return false;
+ return return_false(cinfo, *bm, "allocPixelRef");
}
- SkAutoLockPixels alp(*bm);
-
- if (!sampler.begin(bm,
- isRGB ? SkScaledBitmapSampler::kRGB :
- SkScaledBitmapSampler::kGray,
- this->getDitherImage())) {
- return false;
+ SkAutoLockPixels alp(*bm);
+ if (!sampler.begin(bm, sc, this->getDitherImage())) {
+ return return_false(cinfo, *bm, "sampler.begin");
}
- uint8_t* srcRow = (uint8_t*)srcStorage.alloc(cinfo.output_width * 3);
+ uint8_t* srcRow = (uint8_t*)srcStorage.alloc(cinfo.output_width * 4);
+
+ // Possibly skip initial rows [sampler.srcY0]
+ if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
+ return return_false(cinfo, *bm, "skip rows");
+ }
- skip_src_rows(&cinfo, srcRow, sampler.srcY0());
+ // now loop through scanlines until y == bm->height() - 1
for (int y = 0;; y++) {
JSAMPLE* rowptr = (JSAMPLE*)srcRow;
int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
- SkASSERT(row_count == 1);
+ if (0 == row_count) {
+ return return_false(cinfo, *bm, "read_scanlines");
+ }
+ if (this->shouldCancelDecode()) {
+ return return_false(cinfo, *bm, "shouldCancelDecode");
+ }
sampler.next(srcRow);
if (bm->height() - 1 == y) {
+ // we're done
break;
}
- skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1);
+
+ if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
+ return return_false(cinfo, *bm, "skip rows");
+ }
}
- // ??? If I don't do this, I get an error from finish_decompress
- skip_src_rows(&cinfo, srcRow, cinfo.output_height - cinfo.output_scanline);
-
+ // we formally skip the rest, so we don't get a complaint from libjpeg
+ if (!skip_src_rows(&cinfo, srcRow,
+ cinfo.output_height - cinfo.output_scanline)) {
+ return return_false(cinfo, *bm, "skip rows");
+ }
jpeg_finish_decompress(&cinfo);
+// SkDebugf("------------------- bm2 size %d [%d %d] %d\n", bm->getSize(), bm->width(), bm->height(), bm->config());
return true;
}
@@ -383,11 +554,11 @@ static void rgb2yuv_4444(uint8_t dst[], U16CPU c) {
int r = SkGetPackedR4444(c);
int g = SkGetPackedG4444(c);
int b = SkGetPackedB4444(c);
-
+
int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4);
int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4);
int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4);
-
+
dst[0] = SkToU8(y);
dst[1] = SkToU8(u + 128);
dst[2] = SkToU8(v + 128);
@@ -397,11 +568,11 @@ static void rgb2yuv_16(uint8_t dst[], U16CPU c) {
int r = SkGetPackedR16(c);
int g = SkGetPackedG16(c);
int b = SkGetPackedB16(c);
-
+
int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2);
int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2);
int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2);
-
+
dst[0] = SkToU8(y);
dst[1] = SkToU8(u + 128);
dst[2] = SkToU8(v + 128);
@@ -519,9 +690,9 @@ static boolean sk_empty_output_buffer(j_compress_ptr cinfo) {
// if (!dest->fStream->write(dest->fBuffer, sk_destination_mgr::kBufferSize - dest->free_in_buffer))
if (!dest->fStream->write(dest->fBuffer, sk_destination_mgr::kBufferSize)) {
- sk_throw();
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+ return false;
}
- // ERREXIT(cinfo, JERR_FILE_WRITE);
dest->next_output_byte = dest->fBuffer;
dest->free_in_buffer = sk_destination_mgr::kBufferSize;
@@ -534,7 +705,8 @@ static void sk_term_destination (j_compress_ptr cinfo) {
size_t size = sk_destination_mgr::kBufferSize - dest->free_in_buffer;
if (size > 0) {
if (!dest->fStream->write(dest->fBuffer, size)) {
- sk_throw();
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+ return;
}
}
dest->fStream->flush();
@@ -547,23 +719,6 @@ sk_destination_mgr::sk_destination_mgr(SkWStream* stream)
this->term_destination = sk_term_destination;
}
-class SkAutoLockColors : public SkNoncopyable {
-public:
- SkAutoLockColors(const SkBitmap& bm) {
- fCTable = bm.getColorTable();
- fColors = fCTable ? fCTable->lockColors() : NULL;
- }
- ~SkAutoLockColors() {
- if (fCTable) {
- fCTable->unlockColors(false);
- }
- }
- const SkPMColor* colors() const { return fColors; }
-private:
- SkColorTable* fCTable;
- const SkPMColor* fColors;
-};
-
class SkJPEGImageEncoder : public SkImageEncoder {
protected:
virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
@@ -585,6 +740,10 @@ protected:
sk_error_mgr sk_err;
sk_destination_mgr sk_wstream(stream);
+ // allocate these before set call setjmp
+ SkAutoMalloc oneRow;
+ SkAutoLockColors ctLocker;
+
cinfo.err = jpeg_std_error(&sk_err);
sk_err.error_exit = sk_error_exit;
if (setjmp(sk_err.fJmpBuf)) {
@@ -606,17 +765,15 @@ protected:
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
cinfo.dct_method = JDCT_IFAST;
-
+
jpeg_start_compress(&cinfo, TRUE);
const int width = bm.width();
- SkAutoMalloc oneRow(width * 3);
- uint8_t* oneRowP = (uint8_t*)oneRow.get();
+ uint8_t* oneRowP = (uint8_t*)oneRow.alloc(width * 3);
- SkAutoLockColors alc(bm);
- const SkPMColor* colors = alc.colors();
+ const SkPMColor* colors = ctLocker.lockColors(bm);
const void* srcRow = bm.getPixels();
-
+
while (cinfo.next_scanline < cinfo.image_height) {
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
diff --git a/skia/images/SkImageDecoder_libpng.cpp b/skia/images/SkImageDecoder_libpng.cpp
index 4378ca9..862ebf1 100644
--- a/skia/images/SkImageDecoder_libpng.cpp
+++ b/skia/images/SkImageDecoder_libpng.cpp
@@ -1,6 +1,6 @@
/* libs/graphics/images/SkImageDecoder_libpng.cpp
**
-** Copyright 2006, Google Inc.
+** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -83,7 +83,9 @@ static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
}
static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
+#if 0
SkDebugf("------ png error %s\n", msg);
+#endif
longjmp(png_jmpbuf(png_ptr), 1);
}
@@ -98,6 +100,24 @@ static bool pos_le(int value, int max) {
return value > 0 && value <= max;
}
+static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) {
+ SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config);
+
+ bool reallyHasAlpha = false;
+
+ for (int y = bm->height() - 1; y >= 0; --y) {
+ SkPMColor* p = bm->getAddr32(0, y);
+ for (int x = bm->width() - 1; x >= 0; --x) {
+ if (match == *p) {
+ *p = 0;
+ reallyHasAlpha = true;
+ }
+ p += 1;
+ }
+ }
+ return reallyHasAlpha;
+}
+
bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
SkBitmap::Config prefConfig, Mode mode) {
// SkAutoTrace apr("SkPNGImageDecoder::onDecode");
@@ -153,9 +173,30 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type,
&interlace_type, int_p_NULL, int_p_NULL);
+ /* tell libpng to strip 16 bit/color files down to 8 bits/color */
+ if (bit_depth == 16) {
+ png_set_strip_16(png_ptr);
+ }
+ /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
+ * byte into separate bytes (useful for paletted and grayscale images). */
+ if (bit_depth < 8) {
+ png_set_packing(png_ptr);
+ }
+ /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
+ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
+ png_set_gray_1_2_4_to_8(png_ptr);
+ }
+
+ /* Make a grayscale image into RGB. */
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+ png_set_gray_to_rgb(png_ptr);
+ }
+
SkBitmap::Config config;
bool hasAlpha = false;
bool doDither = this->getDitherImage();
+ SkPMColor theTranspColor = 0; // 0 tells us not to try to match
// check for sBIT chunk data, in case we should disable dithering because
// our data is not truely 8bits per component
@@ -176,11 +217,41 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
if (color_type == PNG_COLOR_TYPE_PALETTE) {
config = SkBitmap::kIndex8_Config; // defer sniffing for hasAlpha
} else {
- png_color_16p transColor;
+ png_color_16p transpColor = NULL;
+ int numTransp = 0;
+
+ png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor);
- png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &transColor);
+ bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
- if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ||
+ if (valid && numTransp == 1 && transpColor != NULL) {
+ /* Compute our transparent color, which we'll match against later.
+ We don't really handle 16bit components properly here, since we
+ do our compare *after* the values have been knocked down to 8bit
+ which means we will find more matches than we should. The real
+ fix seems to be to see the actual 16bit components, do the
+ compare, and then knock it down to 8bits ourselves.
+ */
+ if (color_type & PNG_COLOR_MASK_COLOR) {
+ if (16 == bit_depth) {
+ theTranspColor = SkPackARGB32(0xFF, transpColor->red >> 8,
+ transpColor->green >> 8, transpColor->blue >> 8);
+ } else {
+ theTranspColor = SkPackARGB32(0xFF, transpColor->red,
+ transpColor->green, transpColor->blue);
+ }
+ } else { // gray
+ if (16 == bit_depth) {
+ theTranspColor = SkPackARGB32(0xFF, transpColor->gray >> 8,
+ transpColor->gray >> 8, transpColor->gray >> 8);
+ } else {
+ theTranspColor = SkPackARGB32(0xFF, transpColor->gray,
+ transpColor->gray, transpColor->gray);
+ }
+ }
+ }
+
+ if (valid ||
PNG_COLOR_TYPE_RGB_ALPHA == color_type ||
PNG_COLOR_TYPE_GRAY_ALPHA == color_type) {
hasAlpha = true;
@@ -212,26 +283,6 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
// from here down we are concerned with colortables and pixels
- /* tell libpng to strip 16 bit/color files down to 8 bits/color */
- if (bit_depth == 16) {
- png_set_strip_16(png_ptr);
- }
- /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
- * byte into separate bytes (useful for paletted and grayscale images). */
- if (bit_depth < 8) {
- png_set_packing(png_ptr);
- }
- /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
- if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
- png_set_gray_1_2_4_to_8(png_ptr);
- }
-
- /* Make a grayscale image into RGB. */
- if (color_type == PNG_COLOR_TYPE_GRAY ||
- color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
- png_set_gray_to_rgb(png_ptr);
- }
-
// we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
// to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
// draw lots faster if we can flag the bitmap has being opaque
@@ -295,7 +346,6 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
SkAutoUnref aur(colorTable);
if (!this->allocPixelRef(decodedBitmap, colorTable)) {
- delete colorTable;
return false;
}
@@ -374,14 +424,19 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
}
if (hasAlpha && !reallyHasAlpha) {
+#if 0
SkDEBUGF(("Image doesn't really have alpha [%d %d]\n",
origWidth, origHeight));
+#endif
}
}
/* read rest of file, and get additional chunks in info_ptr - REQUIRED */
png_read_end(png_ptr, info_ptr);
+ if (0 != theTranspColor) {
+ reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
+ }
decodedBitmap->setIsOpaque(!reallyHasAlpha);
return true;
}
@@ -488,8 +543,19 @@ static void transform_scanline_4444(const char* SK_RESTRICT src, int width,
}
}
+static void transform_scanline_index8(const char* SK_RESTRICT src, int width,
+ char* SK_RESTRICT dst) {
+ memcpy(dst, src, width);
+}
+
static transform_scanline_proc choose_proc(SkBitmap::Config config,
bool hasAlpha) {
+ // we don't care about search on alpha if we're kIndex8, since only the
+ // colortable packing cares about that distinction, not the pixels
+ if (SkBitmap::kIndex8_Config == config) {
+ hasAlpha = false; // we store false in the table entries for kIndex8
+ }
+
static const struct {
SkBitmap::Config fConfig;
bool fHasAlpha;
@@ -500,6 +566,7 @@ static transform_scanline_proc choose_proc(SkBitmap::Config config,
{ SkBitmap::kARGB_8888_Config, true, transform_scanline_8888 },
{ SkBitmap::kARGB_4444_Config, false, transform_scanline_444 },
{ SkBitmap::kARGB_4444_Config, true, transform_scanline_4444 },
+ { SkBitmap::kIndex8_Config, false, transform_scanline_index8 },
};
for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) {
@@ -511,6 +578,78 @@ static transform_scanline_proc choose_proc(SkBitmap::Config config,
return NULL;
}
+// return the minimum legal bitdepth (by png standards) for this many colortable
+// entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16,
+// we can use fewer bits per in png
+static int computeBitDepth(int colorCount) {
+#if 0
+ int bits = SkNextLog2(colorCount);
+ SkASSERT(bits >= 1 && bits <= 8);
+ // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8)
+ return SkNextPow2(bits);
+#else
+ // for the moment, we don't know how to pack bitdepth < 8
+ return 8;
+#endif
+}
+
+/* Pack palette[] with the corresponding colors, and if hasAlpha is true, also
+ pack trans[] and return the number of trans[] entries written. If hasAlpha
+ is false, the return value will always be 0.
+
+ Note: this routine takes care of unpremultiplying the RGB values when we
+ have alpha in the colortable, since png doesn't support premul colors
+*/
+static int pack_palette(SkColorTable* ctable, png_color* SK_RESTRICT palette,
+ png_byte* SK_RESTRICT trans, bool hasAlpha) {
+ SkAutoLockColors alc(ctable);
+ const SkPMColor* SK_RESTRICT colors = alc.colors();
+ const int ctCount = ctable->count();
+ int i, num_trans = 0;
+
+ if (hasAlpha) {
+ /* first see if we have some number of fully opaque at the end of the
+ ctable. PNG allows num_trans < num_palette, but all of the trans
+ entries must come first in the palette. If I was smarter, I'd
+ reorder the indices and ctable so that all non-opaque colors came
+ first in the palette. But, since that would slow down the encode,
+ I'm leaving the indices and ctable order as is, and just looking
+ at the tail of the ctable for opaqueness.
+ */
+ num_trans = ctCount;
+ for (i = ctCount - 1; i >= 0; --i) {
+ if (SkGetPackedA32(colors[i]) != 0xFF) {
+ break;
+ }
+ num_trans -= 1;
+ }
+
+ const SkUnPreMultiply::Scale* SK_RESTRICT table =
+ SkUnPreMultiply::GetScaleTable();
+
+ for (i = 0; i < num_trans; i++) {
+ const SkPMColor c = *colors++;
+ const unsigned a = SkGetPackedA32(c);
+ const SkUnPreMultiply::Scale s = table[a];
+ trans[i] = a;
+ palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c));
+ palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c));
+ palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c));
+ }
+ // now fall out of this if-block to use common code for the trailing
+ // opaque entries
+ }
+
+ // these (remaining) entries are opaque
+ for (i = num_trans; i < ctCount; i++) {
+ SkPMColor c = *colors++;
+ palette[i].red = SkGetPackedR32(c);
+ palette[i].green = SkGetPackedG32(c);
+ palette[i].blue = SkGetPackedB32(c);
+ }
+ return num_trans;
+}
+
class SkPNGImageEncoder : public SkImageEncoder {
protected:
virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
@@ -521,20 +660,25 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap,
SkBitmap::Config config = bitmap.getConfig();
const bool hasAlpha = !bitmap.isOpaque();
+ int colorType = PNG_COLOR_MASK_COLOR;
+ int bitDepth = 8; // default for color
png_color_8 sig_bit;
switch (config) {
+ case SkBitmap::kIndex8_Config:
+ colorType |= PNG_COLOR_MASK_PALETTE;
+ // fall through to the ARGB_8888 case
case SkBitmap::kARGB_8888_Config:
sig_bit.red = 8;
sig_bit.green = 8;
sig_bit.blue = 8;
- sig_bit.alpha = hasAlpha ? 8 : 0;
+ sig_bit.alpha = 8;
break;
case SkBitmap::kARGB_4444_Config:
sig_bit.red = 4;
sig_bit.green = 4;
sig_bit.blue = 4;
- sig_bit.alpha = hasAlpha ? 4 : 0;
+ sig_bit.alpha = 4;
break;
case SkBitmap::kRGB_565_Config:
sig_bit.red = 5;
@@ -543,16 +687,34 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap,
sig_bit.alpha = 0;
break;
default:
- SkDEBUGF(("SkPNGImageEncoder::onEncode can't encode %d config\n",
- config));
return false;
}
-
+
+ if (hasAlpha) {
+ // don't specify alpha if we're a palette, even if our ctable has alpha
+ if (!(colorType & PNG_COLOR_MASK_PALETTE)) {
+ colorType |= PNG_COLOR_MASK_ALPHA;
+ }
+ } else {
+ sig_bit.alpha = 0;
+ }
+
SkAutoLockPixels alp(bitmap);
- if (NULL == bitmap.getPixels()) {
+ // readyToDraw checks for pixels (and colortable if that is required)
+ if (!bitmap.readyToDraw()) {
return false;
}
-
+
+ // we must do this after we have locked the pixels
+ SkColorTable* ctable = bitmap.getColorTable();
+ if (NULL != ctable) {
+ if (ctable->count() == 0) {
+ return false;
+ }
+ // check if we can store in fewer than 8 bits
+ bitDepth = computeBitDepth(ctable->count());
+ }
+
png_structp png_ptr;
png_infop info_ptr;
@@ -587,12 +749,12 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap,
* currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
*/
- png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), 8,
- hasAlpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
+ png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(),
+ bitDepth, colorType,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_BASE);
-#if 0 // need to support this some day <reed>
+#if 0 // need to support this some day
/* set the palette if there is one. REQUIRED for indexed-color images */
palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH
* png_sizeof (png_color));
@@ -620,15 +782,6 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap,
png_write_end(png_ptr, info_ptr);
-#if 0
- /* If you png_malloced a palette, free it here (don't free info_ptr->palette,
- as recommended in versions 1.0.5m and earlier of this example; if
- libpng mallocs info_ptr->palette, libpng will free it). If you
- allocated it with malloc() instead of png_malloc(), use free() instead
- of png_free(). */
- png_free(png_ptr, palette);
-#endif
-
/* clean up after the write, and free any memory allocated */
png_destroy_write_struct(&png_ptr, &info_ptr);
return true;
@@ -640,4 +793,3 @@ SkImageEncoder* SkImageEncoder_PNG_Factory() {
}
#endif /* SK_SUPPORT_IMAGE_ENCODE */
-
diff --git a/skia/images/SkImageDecoder_wbmp.cpp b/skia/images/SkImageDecoder_wbmp.cpp
index d2fea75..9d188f6 100644
--- a/skia/images/SkImageDecoder_wbmp.cpp
+++ b/skia/images/SkImageDecoder_wbmp.cpp
@@ -1,5 +1,5 @@
/**
-** Copyright 2006, Google Inc.
+** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
diff --git a/skia/images/SkImageRef.cpp b/skia/images/SkImageRef.cpp
index 05960a2..bd7a07d 100644
--- a/skia/images/SkImageRef.cpp
+++ b/skia/images/SkImageRef.cpp
@@ -58,7 +58,7 @@ bool SkImageRef::getInfo(SkBitmap* bitmap) {
bool SkImageRef::onDecode(SkImageDecoder* codec, SkStream* stream,
SkBitmap* bitmap, SkBitmap::Config config,
SkImageDecoder::Mode mode) {
- return codec->onDecode(stream, bitmap, config, mode);
+ return codec->decode(stream, bitmap, config, mode);
}
bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) {
@@ -68,6 +68,14 @@ bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) {
return false;
}
+ /* As soon as we really know our config, we record it, so that on
+ subsequent calls to the codec, we are sure we will always get the same
+ result.
+ */
+ if (SkBitmap::kNo_Config != fBitmap.config()) {
+ fConfig = fBitmap.config();
+ }
+
if (NULL != fBitmap.getPixels() ||
(SkBitmap::kNo_Config != fBitmap.config() &&
SkImageDecoder::kDecodeBounds_Mode == mode)) {
diff --git a/skia/images/SkMovie_gif.cpp b/skia/images/SkMovie_gif.cpp
index 907ea82..c7db017 100644
--- a/skia/images/SkMovie_gif.cpp
+++ b/skia/images/SkMovie_gif.cpp
@@ -1,6 +1,6 @@
/* libs/graphics/images/SkImageDecoder_libgif.cpp
**
-** Copyright 2006, Google Inc.
+** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -143,7 +143,7 @@ bool SkGIFMovie::onGetBitmap(SkBitmap* bm)
if (NULL == gif)
return false;
- // should we check for the Image cmap or the global (SColorMap) first? <reed>
+ // should we check for the Image cmap or the global (SColorMap) first?
ColorMapObject* cmap = gif->SColorMap;
if (cmap == NULL)
cmap = gif->Image.ColorMap;
@@ -154,15 +154,22 @@ bool SkGIFMovie::onGetBitmap(SkBitmap* bm)
return false;
}
- SavedImage* gif_image = fCurrSavedImage;
const int width = gif->SWidth;
const int height = gif->SHeight;
- SkBitmap::Config config = SkBitmap::kIndex8_Config;
+ if (width <= 0 || height <= 0) {
+ return false;
+ }
+
+ SavedImage* gif_image = fCurrSavedImage;
+ SkBitmap::Config config = SkBitmap::kIndex8_Config;
SkColorTable* colorTable = SkNEW_ARGS(SkColorTable, (cmap->ColorCount));
+ SkAutoUnref aur(colorTable);
+
bm->setConfig(config, width, height, 0);
- bm->allocPixels(colorTable);
- colorTable->unref();
+ if (!bm->allocPixels(colorTable)) {
+ return false;
+ }
int transparent = -1;
for (int i = 0; i < gif_image->ExtensionBlockCount; ++i) {
diff --git a/skia/images/SkScaledBitmapSampler.cpp b/skia/images/SkScaledBitmapSampler.cpp
index 529be61..15f4432 100644
--- a/skia/images/SkScaledBitmapSampler.cpp
+++ b/skia/images/SkScaledBitmapSampler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2007, Google Inc.
+ * Copyright 2007, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/skia/images/SkStream.cpp b/skia/images/SkStream.cpp
index 5c1eebe..b199a1b 100644
--- a/skia/images/SkStream.cpp
+++ b/skia/images/SkStream.cpp
@@ -1,6 +1,6 @@
/* libs/graphics/images/SkStream.cpp
**
-** Copyright 2006, Google Inc.
+** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -248,7 +248,7 @@ size_t SkFILEStream::read(void* buffer, size_t size)
return 0;
}
-////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
SkMemoryStream::SkMemoryStream()
{
@@ -343,19 +343,20 @@ size_t SkMemoryStream::seek(size_t offset)
/////////////////////////////////////////////////////////////////////////////////////////////////////////
-SkBufferStream::SkBufferStream(SkStream& proxy, size_t bufferSize)
+SkBufferStream::SkBufferStream(SkStream* proxy, size_t bufferSize)
: fProxy(proxy)
{
- SkASSERT(&proxy != NULL);
+ SkASSERT(proxy != NULL);
+ proxy->ref();
this->init(NULL, bufferSize);
}
-SkBufferStream::SkBufferStream(SkStream& proxy, void* buffer, size_t bufferSize)
+SkBufferStream::SkBufferStream(SkStream* proxy, void* buffer, size_t bufferSize)
: fProxy(proxy)
{
- SkASSERT(&proxy != NULL);
+ SkASSERT(proxy != NULL);
SkASSERT(buffer == NULL || bufferSize != 0); // init(addr, 0) makes no sense, we must know how big their buffer is
-
+ proxy->ref();
this->init(buffer, bufferSize);
}
@@ -382,6 +383,7 @@ void SkBufferStream::init(void* buffer, size_t bufferSize)
SkBufferStream::~SkBufferStream()
{
+ fProxy->unref();
if (fWeOwnTheBuffer)
sk_free(fBuffer);
}
@@ -389,31 +391,43 @@ SkBufferStream::~SkBufferStream()
bool SkBufferStream::rewind()
{
fBufferOffset = fBufferSize = fOrigBufferSize;
- return fProxy.rewind();
+ return fProxy->rewind();
}
const char* SkBufferStream::getFileName()
{
- return fProxy.getFileName();
+ return fProxy->getFileName();
}
#ifdef SK_DEBUG
// #define SK_TRACE_BUFFERSTREAM
#endif
-size_t SkBufferStream::read(void* buffer, size_t size)
-{
+size_t SkBufferStream::read(void* buffer, size_t size) {
#ifdef SK_TRACE_BUFFERSTREAM
SkDebugf("Request %d", size);
#endif
- if (buffer == NULL && size == 0)
- return fProxy.read(buffer, size); // requesting total size
+ if (buffer == NULL && size == 0) {
+ return fProxy->read(buffer, size); // requesting total size
+ }
+
+ if (0 == size) {
+ return 0;
+ }
- if (buffer == NULL || size == 0)
- {
- fBufferOffset += size;
- return fProxy.read(buffer, size);
+ // skip size bytes
+ if (NULL == buffer) {
+ size_t remaining = fBufferSize - fBufferOffset;
+ if (remaining >= size) {
+ fBufferOffset += size;
+ return size;
+ }
+ // if we get here, we are being asked to skip beyond our current buffer
+ // so reset our offset to force a read next time, and skip the diff
+ // in our proxy
+ fBufferOffset = fOrigBufferSize;
+ return remaining + fProxy->read(NULL, size - remaining);
}
size_t s = size;
@@ -441,7 +455,7 @@ size_t SkBufferStream::read(void* buffer, size_t size)
if (size < fBufferSize) // lets try to read more than the request
{
- s = fProxy.read(fBuffer, fBufferSize);
+ s = fProxy->read(fBuffer, fBufferSize);
#ifdef SK_TRACE_BUFFERSTREAM
SkDebugf(" read %d into fBuffer", s);
#endif
@@ -461,7 +475,7 @@ size_t SkBufferStream::read(void* buffer, size_t size)
}
else // just do a direct read
{
- actuallyRead += fProxy.read(buffer, size);
+ actuallyRead += fProxy->read(buffer, size);
#ifdef SK_TRACE_BUFFERSTREAM
SkDebugf(" direct read %d", size);
#endif
@@ -475,7 +489,7 @@ size_t SkBufferStream::read(void* buffer, size_t size)
const void* SkBufferStream::getMemoryBase()
{
- return fProxy.getMemoryBase();
+ return fProxy->getMemoryBase();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -729,20 +743,63 @@ bool SkDebugWStream::write(const void* buffer, size_t size)
#include "SkRandom.h"
-void SkWStream::UnitTest()
-{
+#ifdef SK_SUPPORT_UNITTEST
+#define MAX_SIZE (256 * 1024)
+
+static void random_fill(SkRandom& rand, void* buffer, size_t size) {
+ char* p = (char*)buffer;
+ char* stop = p + size;
+ while (p < stop) {
+ *p++ = (char)(rand.nextU() >> 8);
+ }
+}
+
+static void test_buffer() {
+ SkRandom rand;
+ SkAutoMalloc am(MAX_SIZE * 2);
+ char* storage = (char*)am.get();
+ char* storage2 = storage + MAX_SIZE;
+
+ random_fill(rand, storage, MAX_SIZE);
+
+ for (int sizeTimes = 0; sizeTimes < 100; sizeTimes++) {
+ int size = rand.nextU() % MAX_SIZE;
+ if (size == 0) {
+ size = MAX_SIZE;
+ }
+ for (int times = 0; times < 100; times++) {
+ int bufferSize = 1 + (rand.nextU() & 0xFFFF);
+ SkMemoryStream mstream(storage, size);
+ SkBufferStream bstream(&mstream, bufferSize);
+
+ int bytesRead = 0;
+ while (bytesRead < size) {
+ int s = 17 + (rand.nextU() & 0xFFFF);
+ int ss = bstream.read(storage2, s);
+ SkASSERT(ss > 0 && ss <= s);
+ SkASSERT(bytesRead + ss <= size);
+ SkASSERT(memcmp(storage + bytesRead, storage2, ss) == 0);
+ bytesRead += ss;
+ }
+ SkASSERT(bytesRead == size);
+ }
+ }
+}
+#endif
+
+void SkStream::UnitTest() {
#ifdef SK_SUPPORT_UNITTEST
{
static const char s[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char copy[sizeof(s)];
SkRandom rand;
-
+
for (int i = 0; i < 65; i++)
{
char* copyPtr = copy;
SkMemoryStream mem(s, sizeof(s));
- SkBufferStream buff(mem, i);
-
+ SkBufferStream buff(&mem, i);
+
do {
copyPtr += buff.read(copyPtr, rand.nextU() & 15);
} while (copyPtr < copy + sizeof(s));
@@ -750,6 +807,13 @@ void SkWStream::UnitTest()
SkASSERT(memcmp(s, copy, sizeof(s)) == 0);
}
}
+ test_buffer();
+#endif
+}
+
+void SkWStream::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
{
SkDebugWStream s;
diff --git a/skia/images/bmpdecoderhelper.cpp b/skia/images/bmpdecoderhelper.cpp
index e390731..acabf44 100644
--- a/skia/images/bmpdecoderhelper.cpp
+++ b/skia/images/bmpdecoderhelper.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2007, Google Inc.
+ * Copyright 2007, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/skia/images/bmpdecoderhelper.h b/skia/images/bmpdecoderhelper.h
index 7da1326..07f0ae5 100644
--- a/skia/images/bmpdecoderhelper.h
+++ b/skia/images/bmpdecoderhelper.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2007, Google Inc.
+ * Copyright 2007, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,8 @@
#define IMAGE_CODEC_BMPDECODERHELPER_H__
///////////////////////////////////////////////////////////////////////////////
-// Some glue code that should be removed soon.
+// this section is my current "glue" between google3 code and android.
+// will be fixed soon
#include "SkTypes.h"
#include <limits.h>