- optional parameters added to descriptorProc and allocPixels
- clip options to image decoders
- check for xfermode in blitter_a8
- UNROLL loops in blitrow

reviewed by reed@google.com



git-svn-id: http://skia.googlecode.com/svn/trunk@841 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
djsollen@google.com 2011-02-23 20:46:31 +00:00
Родитель 819c921b04
Коммит 57f4969724
26 изменённых файлов: 580 добавлений и 133 удалений

Просмотреть файл

@ -462,10 +462,15 @@ public:
int extractMipLevel(SkBitmap* dst, SkFixed sx, SkFixed sy); int extractMipLevel(SkBitmap* dst, SkFixed sx, SkFixed sy);
void extractAlpha(SkBitmap* dst) const { void extractAlpha(SkBitmap* dst) const {
this->extractAlpha(dst, NULL, NULL); this->extractAlpha(dst, NULL, NULL, NULL);
} }
void extractAlpha(SkBitmap* dst, const SkPaint* paint, void extractAlpha(SkBitmap* dst, const SkPaint* paint,
SkIPoint* offset) const {
this->extractAlpha(dst, paint, NULL, offset);
}
void extractAlpha(SkBitmap* dst, const SkPaint* paint, Allocator* allocator,
SkIPoint* offset) const; SkIPoint* offset) const;
void flatten(SkFlattenableWriteBuffer&) const; void flatten(SkFlattenableWriteBuffer&) const;

Просмотреть файл

@ -855,7 +855,7 @@ private:
void descriptorProc(const SkMatrix* deviceMatrix, void descriptorProc(const SkMatrix* deviceMatrix,
void (*proc)(const SkDescriptor*, void*), void (*proc)(const SkDescriptor*, void*),
void* context) const; void* context, bool ignoreGamma = false) const;
const SkRect& computeStrokeFastBounds(const SkRect& orig, const SkRect& computeStrokeFastBounds(const SkRect& orig,
SkRect* storage) const; SkRect* storage) const;

Просмотреть файл

@ -119,6 +119,18 @@ public:
virtual Factory getFactory() const { return NULL; } virtual Factory getFactory() const { return NULL; }
virtual void flatten(SkFlattenableWriteBuffer&) const; virtual void flatten(SkFlattenableWriteBuffer&) const;
/** Acquire a "global" ref on this object.
* The default implementation just calls ref(), but subclasses can override
* this method to implement additional behavior.
*/
virtual void globalRef(void* data=NULL);
/** Release a "global" ref on this object.
* The default implementation just calls unref(), but subclasses can override
* this method to implement additional behavior.
*/
virtual void globalUnref();
static Factory NameToFactory(const char name[]); static Factory NameToFactory(const char name[]);
static const char* FactoryToName(Factory); static const char* FactoryToName(Factory);
static void Register(const char name[], Factory); static void Register(const char name[], Factory);

Просмотреть файл

@ -177,6 +177,11 @@ public:
*/ */
virtual void setMemory(const void* data, size_t length, virtual void setMemory(const void* data, size_t length,
bool copyData = false); bool copyData = false);
/** Replace any memory buffer with the specified buffer. The caller
must have allocated data with sk_malloc or sk_realloc, since it
will be freed with sk_free.
*/
void setMemoryOwned(const void* data, size_t length);
void skipToAlign4(); void skipToAlign4();
virtual bool rewind(); virtual bool rewind();
virtual size_t read(void* buffer, size_t size); virtual size_t read(void* buffer, size_t size);

Просмотреть файл

@ -62,8 +62,10 @@ private:
// See also SkTScopedPtr. // See also SkTScopedPtr.
template <typename T> class SkAutoTDelete : SkNoncopyable { template <typename T> class SkAutoTDelete : SkNoncopyable {
public: public:
SkAutoTDelete(T* obj) : fObj(obj) {} SkAutoTDelete(T* obj, bool deleteWhenDone = true) : fObj(obj) {
~SkAutoTDelete() { delete fObj; } fDeleteWhenDone = deleteWhenDone;
}
~SkAutoTDelete() { if (fDeleteWhenDone) delete fObj; }
T* get() const { return fObj; } T* get() const { return fObj; }
void free() { delete fObj; fObj = NULL; } void free() { delete fObj; fObj = NULL; }
@ -71,6 +73,7 @@ public:
private: private:
T* fObj; T* fObj;
bool fDeleteWhenDone;
}; };
template <typename T> class SkAutoTDeleteArray : SkNoncopyable { template <typename T> class SkAutoTDeleteArray : SkNoncopyable {

Просмотреть файл

@ -57,6 +57,12 @@ public:
*/ */
bool getInfo(SkBitmap* bm); bool getInfo(SkBitmap* bm);
/** Return true if the image can be decoded and is opaque. Calling this
method will decode and set the pixels in the specified bitmap and
sets the isOpaque flag.
*/
bool isOpaque(SkBitmap* bm);
SkImageDecoderFactory* getDecoderFactory() const { return fFactory; } SkImageDecoderFactory* getDecoderFactory() const { return fFactory; }
// returns the factory parameter // returns the factory parameter
SkImageDecoderFactory* setDecoderFactory(SkImageDecoderFactory*); SkImageDecoderFactory* setDecoderFactory(SkImageDecoderFactory*);

Просмотреть файл

@ -41,11 +41,13 @@ void skjpeg_error_exit(j_common_ptr cinfo);
/* Our source struct for directing jpeg to our stream object. /* Our source struct for directing jpeg to our stream object.
*/ */
struct skjpeg_source_mgr : jpeg_source_mgr { struct skjpeg_source_mgr : jpeg_source_mgr {
skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder); skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder, bool ownStream);
~skjpeg_source_mgr();
SkStream* fStream; SkStream* fStream;
const void* fMemoryBase; void* fMemoryBase;
size_t fMemoryBaseSize; size_t fMemoryBaseSize;
bool fUnrefStream;
SkImageDecoder* fDecoder; SkImageDecoder* fDecoder;
enum { enum {
kBufferSize = 1024 kBufferSize = 1024

Просмотреть файл

@ -1186,7 +1186,7 @@ static bool GetBitmapAlpha(const SkBitmap& src, uint8_t SK_RESTRICT alpha[],
#include "SkMatrix.h" #include "SkMatrix.h"
void SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint, void SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
SkIPoint* offset) const { Allocator *allocator, SkIPoint* offset) const {
SkDEBUGCODE(this->validate();) SkDEBUGCODE(this->validate();)
SkMatrix identity; SkMatrix identity;
@ -1210,7 +1210,7 @@ void SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
NO_FILTER_CASE: NO_FILTER_CASE:
dst->setConfig(SkBitmap::kA8_Config, this->width(), this->height(), dst->setConfig(SkBitmap::kA8_Config, this->width(), this->height(),
srcM.fRowBytes); srcM.fRowBytes);
dst->allocPixels(); dst->allocPixels(allocator, NULL);
GetBitmapAlpha(*this, dst->getAddr8(0, 0), srcM.fRowBytes); GetBitmapAlpha(*this, dst->getAddr8(0, 0), srcM.fRowBytes);
if (offset) { if (offset) {
offset->set(0, 0); offset->set(0, 0);
@ -1229,7 +1229,7 @@ void SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
dst->setConfig(SkBitmap::kA8_Config, dstM.fBounds.width(), dst->setConfig(SkBitmap::kA8_Config, dstM.fBounds.width(),
dstM.fBounds.height(), dstM.fRowBytes); dstM.fBounds.height(), dstM.fRowBytes);
dst->allocPixels(); dst->allocPixels(allocator, NULL);
memcpy(dst->getPixels(), dstM.fImage, dstM.computeImageSize()); memcpy(dst->getPixels(), dstM.fImage, dstM.computeImageSize());
if (offset) { if (offset) {
offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop); offset->set(dstM.fBounds.fLeft, dstM.fBounds.fTop);

Просмотреть файл

@ -2,6 +2,8 @@
#include "SkColorPriv.h" #include "SkColorPriv.h"
#include "SkUtils.h" #include "SkUtils.h"
#define UNROLL
static void S32_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst, static void S32_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst,
const SkPMColor* SK_RESTRICT src, const SkPMColor* SK_RESTRICT src,
int count, U8CPU alpha) { int count, U8CPU alpha) {
@ -16,11 +18,28 @@ static void S32_Blend_BlitRow32(SkPMColor* SK_RESTRICT dst,
if (count > 0) { if (count > 0) {
unsigned src_scale = SkAlpha255To256(alpha); unsigned src_scale = SkAlpha255To256(alpha);
unsigned dst_scale = 256 - src_scale; unsigned dst_scale = 256 - src_scale;
#ifdef UNROLL
if (count & 1) {
*dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale);
dst += 1;
count -= 1;
}
const SkPMColor* SK_RESTRICT srcEnd = src + count;
while (src != srcEnd) {
*dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale);
dst += 1;
*dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale);
dst += 1;
}
#else
do { do {
*dst = SkAlphaMulQ(*src, src_scale) + SkAlphaMulQ(*dst, dst_scale); *dst = SkAlphaMulQ(*src, src_scale) + SkAlphaMulQ(*dst, dst_scale);
src += 1; src += 1;
dst += 1; dst += 1;
} while (--count > 0); } while (--count > 0);
#endif
} }
} }
@ -31,6 +50,21 @@ static void S32A_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst,
int count, U8CPU alpha) { int count, U8CPU alpha) {
SkASSERT(255 == alpha); SkASSERT(255 == alpha);
if (count > 0) { if (count > 0) {
#ifdef UNROLL
if (count & 1) {
*dst = SkPMSrcOver(*(src++), *dst);
dst += 1;
count -= 1;
}
const SkPMColor* SK_RESTRICT srcEnd = src + count;
while (src != srcEnd) {
*dst = SkPMSrcOver(*(src++), *dst);
dst += 1;
*dst = SkPMSrcOver(*(src++), *dst);
dst += 1;
}
#else
do { do {
#ifdef TEST_SRC_ALPHA #ifdef TEST_SRC_ALPHA
SkPMColor sc = *src; SkPMColor sc = *src;
@ -48,6 +82,7 @@ static void S32A_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst,
src += 1; src += 1;
dst += 1; dst += 1;
} while (--count > 0); } while (--count > 0);
#endif
} }
} }
@ -56,11 +91,27 @@ static void S32A_Blend_BlitRow32(SkPMColor* SK_RESTRICT dst,
int count, U8CPU alpha) { int count, U8CPU alpha) {
SkASSERT(alpha <= 255); SkASSERT(alpha <= 255);
if (count > 0) { if (count > 0) {
#ifdef UNROLL
if (count & 1) {
*dst = SkBlendARGB32(*(src++), *dst, alpha);
dst += 1;
count -= 1;
}
const SkPMColor* SK_RESTRICT srcEnd = src + count;
while (src != srcEnd) {
*dst = SkBlendARGB32(*(src++), *dst, alpha);
dst += 1;
*dst = SkBlendARGB32(*(src++), *dst, alpha);
dst += 1;
}
#else
do { do {
*dst = SkBlendARGB32(*src, *dst, alpha); *dst = SkBlendARGB32(*src, *dst, alpha);
src += 1; src += 1;
dst += 1; dst += 1;
} while (--count > 0); } while (--count > 0);
#endif
} }
} }

Просмотреть файл

@ -249,7 +249,7 @@ SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint&
} }
SkA8_Shader_Blitter::~SkA8_Shader_Blitter() { SkA8_Shader_Blitter::~SkA8_Shader_Blitter() {
SkSafeUnref(fXfermode); if (fXfermode) SkSafeUnref(fXfermode);
sk_free(fBuffer); sk_free(fBuffer);
} }
@ -342,7 +342,9 @@ void SkA8_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
while (--height >= 0) { while (--height >= 0) {
fShader->shadeSpan(x, y, span, width); fShader->shadeSpan(x, y, span, width);
fXfermode->xferA8(device, span, width, alpha); if (fXfermode) {
fXfermode->xferA8(device, span, width, alpha);
}
y += 1; y += 1;
device += fDevice.rowBytes(); device += fDevice.rowBytes();

Просмотреть файл

@ -1233,10 +1233,14 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
void SkPaint::descriptorProc(const SkMatrix* deviceMatrix, void SkPaint::descriptorProc(const SkMatrix* deviceMatrix,
void (*proc)(const SkDescriptor*, void*), void (*proc)(const SkDescriptor*, void*),
void* context) const { void* context, bool ignoreGamma) const {
SkScalerContext::Rec rec; SkScalerContext::Rec rec;
SkScalerContext::MakeRec(*this, deviceMatrix, &rec); SkScalerContext::MakeRec(*this, deviceMatrix, &rec);
if (ignoreGamma) {
rec.fFlags &= ~(SkScalerContext::kGammaForBlack_Flag |
SkScalerContext::kGammaForWhite_Flag);
}
size_t descSize = sizeof(rec); size_t descSize = sizeof(rec);
int entryCount = 1; int entryCount = 1;
@ -1645,4 +1649,3 @@ const SkPath* SkTextToPathIter::next(SkScalar* xpos) {
} }
return NULL; return NULL;
} }

Просмотреть файл

@ -128,3 +128,10 @@ const char* SkPixelRef::FactoryToName(Factory fact) {
return NULL; return NULL;
} }
void SkPixelRef::globalRef(void* data) {
this->ref();
}
void SkPixelRef::globalUnref() {
this->unref();
}

Просмотреть файл

@ -272,6 +272,18 @@ SkMemoryStream::~SkMemoryStream()
sk_free((void*)fSrc); sk_free((void*)fSrc);
} }
void SkMemoryStream::setMemoryOwned(const void* src, size_t size)
{
if (fWeOwnTheData)
sk_free((void*)fSrc);
fSize = size;
fOffset = 0;
fWeOwnTheData = true;
fSrc = src;
}
void SkMemoryStream::setMemory(const void* src, size_t size, bool copyData) void SkMemoryStream::setMemory(const void* src, size_t size, bool copyData)
{ {
if (fWeOwnTheData) if (fWeOwnTheData)

Просмотреть файл

@ -74,8 +74,8 @@ SkPixelRef* SkFlipPixelRef::Create(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkFlipPixelRef, (buffer)); return SkNEW_ARGS(SkFlipPixelRef, (buffer));
} }
static SkPixelRef::Registrar::Registrar reg("SkFlipPixelRef", static SkPixelRef::Registrar reg("SkFlipPixelRef",
SkFlipPixelRef::Create); SkFlipPixelRef::Create);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -125,4 +125,3 @@ void SkFlipPixelRef::CopyBitsFromAddr(const SkBitmap& dst, const SkRegion& clip,
iter.next(); iter.next();
} }
} }

Просмотреть файл

@ -71,4 +71,3 @@ SkMovie* SkMovie::DecodeStream(SkStream* stream) {
} }
return NULL; return NULL;
} }

Просмотреть файл

@ -117,6 +117,11 @@ static const ColorMapObject* find_colormap(const GifFileType* gif) {
if (NULL == cmap) { if (NULL == cmap) {
cmap = gif->SColorMap; cmap = gif->SColorMap;
} }
if (NULL == cmap) {
// no colormap found
return NULL;
}
// some sanity checks // some sanity checks
if (cmap && ((unsigned)cmap->ColorCount > 256 || if (cmap && ((unsigned)cmap->ColorCount > 256 ||
cmap->ColorCount != (1 << cmap->BitsPerPixel))) { cmap->ColorCount != (1 << cmap->BitsPerPixel))) {

Просмотреть файл

@ -223,13 +223,9 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
if (config == SkBitmap::kARGB_8888_Config) { if (config == SkBitmap::kARGB_8888_Config) {
cinfo.out_color_space = JCS_RGBA_8888; cinfo.out_color_space = JCS_RGBA_8888;
} else if (config == SkBitmap::kRGB_565_Config) { } else if (config == SkBitmap::kRGB_565_Config) {
if (sampleSize == 1) { cinfo.out_color_space = JCS_RGB_565;
// SkScaledBitmapSampler can't handle RGB_565 yet, if (this->getDitherImage()) {
// so don't even try. cinfo.dither_mode = JDITHER_ORDERED;
cinfo.out_color_space = JCS_RGB_565;
if (this->getDitherImage()) {
cinfo.dither_mode = JDITHER_ORDERED;
}
} }
} }
#endif #endif
@ -319,8 +315,8 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
#ifdef ANDROID_RGB #ifdef ANDROID_RGB
} else if (JCS_RGBA_8888 == cinfo.out_color_space) { } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
sc = SkScaledBitmapSampler::kRGBX; sc = SkScaledBitmapSampler::kRGBX;
//} else if (JCS_RGB_565 == cinfo.out_color_space) { } else if (JCS_RGB_565 == cinfo.out_color_space) {
// sc = SkScaledBitmapSampler::kRGB_565; sc = SkScaledBitmapSampler::kRGB_565;
#endif #endif
} else if (1 == cinfo.out_color_components && } else if (1 == cinfo.out_color_components &&
JCS_GRAYSCALE == cinfo.out_color_space) { JCS_GRAYSCALE == cinfo.out_color_space) {

Просмотреть файл

@ -57,6 +57,16 @@ bool SkImageRef::getInfo(SkBitmap* bitmap) {
return true; return true;
} }
bool SkImageRef::isOpaque(SkBitmap* bitmap) {
if (bitmap && bitmap->pixelRef() == this) {
bitmap->lockPixels();
bitmap->setIsOpaque(fBitmap.isOpaque());
bitmap->unlockPixels();
return true;
}
return false;
}
SkImageDecoderFactory* SkImageRef::setDecoderFactory( SkImageDecoderFactory* SkImageRef::setDecoderFactory(
SkImageDecoderFactory* fact) { SkImageDecoderFactory* fact) {
SkRefCnt_SafeAssign(fFactory, fact); SkRefCnt_SafeAssign(fFactory, fact);

Просмотреть файл

@ -50,8 +50,8 @@ SkPixelRef* SkImageRef_GlobalPool::Create(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkImageRef_GlobalPool, (buffer)); return SkNEW_ARGS(SkImageRef_GlobalPool, (buffer));
} }
static SkPixelRef::Registrar::Registrar reg("SkImageRef_GlobalPool", static SkPixelRef::Registrar reg("SkImageRef_GlobalPool",
SkImageRef_GlobalPool::Create); SkImageRef_GlobalPool::Create);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// global imagerefpool wrappers // global imagerefpool wrappers
@ -80,4 +80,3 @@ void SkImageRef_GlobalPool::DumpPool() {
SkAutoMutexAcquire ac(gImageRefMutex); SkAutoMutexAcquire ac(gImageRefMutex);
gGlobalImageRefPool.dump(); gGlobalImageRefPool.dump();
} }

Просмотреть файл

@ -21,6 +21,24 @@ static void sk_init_source(j_decompress_ptr cinfo) {
skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src; skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
src->next_input_byte = (const JOCTET*)src->fBuffer; src->next_input_byte = (const JOCTET*)src->fBuffer;
src->bytes_in_buffer = 0; src->bytes_in_buffer = 0;
src->current_offset = 0;
src->fStream->rewind();
}
static boolean sk_seek_input_data(j_decompress_ptr cinfo, long byte_offset) {
skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
if (byte_offset > src->current_offset) {
(void)src->fStream->skip(byte_offset - src->current_offset);
} else {
src->fStream->rewind();
(void)src->fStream->skip(byte_offset);
}
src->current_offset = byte_offset;
src->next_input_byte = (const JOCTET*)src->fBuffer;
src->bytes_in_buffer = 0;
return TRUE;
} }
static boolean sk_fill_input_buffer(j_decompress_ptr cinfo) { static boolean sk_fill_input_buffer(j_decompress_ptr cinfo) {
@ -35,6 +53,7 @@ static boolean sk_fill_input_buffer(j_decompress_ptr cinfo) {
return FALSE; return FALSE;
} }
src->current_offset += bytes;
src->next_input_byte = (const JOCTET*)src->fBuffer; src->next_input_byte = (const JOCTET*)src->fBuffer;
src->bytes_in_buffer = bytes; src->bytes_in_buffer = bytes;
return TRUE; return TRUE;
@ -52,6 +71,7 @@ static void sk_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
cinfo->err->error_exit((j_common_ptr)cinfo); cinfo->err->error_exit((j_common_ptr)cinfo);
return; return;
} }
src->current_offset += bytes;
bytesToSkip -= bytes; bytesToSkip -= bytes;
} }
src->next_input_byte = (const JOCTET*)src->fBuffer; src->next_input_byte = (const JOCTET*)src->fBuffer;
@ -83,7 +103,9 @@ static void sk_term_source(j_decompress_ptr /*cinfo*/) {}
static void skmem_init_source(j_decompress_ptr cinfo) { static void skmem_init_source(j_decompress_ptr cinfo) {
skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src; skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
src->next_input_byte = (const JOCTET*)src->fMemoryBase; src->next_input_byte = (const JOCTET*)src->fMemoryBase;
src->start_input_byte = (const JOCTET*)src->fMemoryBase;
src->bytes_in_buffer = src->fMemoryBaseSize; src->bytes_in_buffer = src->fMemoryBaseSize;
src->current_offset = src->fMemoryBaseSize;
} }
static boolean skmem_fill_input_buffer(j_decompress_ptr cinfo) { static boolean skmem_fill_input_buffer(j_decompress_ptr cinfo) {
@ -108,31 +130,34 @@ static void skmem_term_source(j_decompress_ptr /*cinfo*/) {}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
skjpeg_source_mgr::skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder) : fStream(stream) { skjpeg_source_mgr::skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder,
bool ownStream) : fStream(stream) {
fDecoder = decoder; fDecoder = decoder;
const void* baseAddr = stream->getMemoryBase(); const void* baseAddr = stream->getMemoryBase();
if (baseAddr && false) { size_t bufferSize = 4096;
fMemoryBase = baseAddr; size_t len;
fMemoryBaseSize = stream->getLength(); fMemoryBase = NULL;
fUnrefStream = ownStream;
fMemoryBaseSize = 0;
init_source = skmem_init_source; init_source = sk_init_source;
fill_input_buffer = skmem_fill_input_buffer; fill_input_buffer = sk_fill_input_buffer;
skip_input_data = skmem_skip_input_data; skip_input_data = sk_skip_input_data;
resync_to_restart = skmem_resync_to_restart; resync_to_restart = sk_resync_to_restart;
term_source = skmem_term_source; term_source = sk_term_source;
} else { seek_input_data = sk_seek_input_data;
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); // SkDebugf("**************** use memorybase %p %d\n", fMemoryBase, fMemoryBaseSize);
} }
skjpeg_source_mgr::~skjpeg_source_mgr() {
if (fMemoryBase) {
sk_free(fMemoryBase);
}
if (fUnrefStream) {
fStream->unref();
}
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
static void sk_init_destination(j_compress_ptr cinfo) { static void sk_init_destination(j_compress_ptr cinfo) {

Просмотреть файл

@ -20,6 +20,7 @@
#include "SkColorPriv.h" #include "SkColorPriv.h"
#include "SkStream.h" #include "SkStream.h"
#include "SkTemplates.h" #include "SkTemplates.h"
#include "SkUtils.h"
#include "gif_lib.h" #include "gif_lib.h"
@ -35,7 +36,9 @@ protected:
private: private:
GifFileType* fGIF; GifFileType* fGIF;
SavedImage* fCurrSavedImage; int fCurrIndex;
int fLastDrawIndex;
SkBitmap fBackup;
}; };
static int Decode(GifFileType* fileType, GifByteType* out, int size) { static int Decode(GifFileType* fileType, GifByteType* out, int size) {
@ -54,7 +57,8 @@ SkGIFMovie::SkGIFMovie(SkStream* stream)
DGifCloseFile(fGIF); DGifCloseFile(fGIF);
fGIF = NULL; fGIF = NULL;
} }
fCurrSavedImage = NULL; fCurrIndex = -1;
fLastDrawIndex = -1;
} }
SkGIFMovie::~SkGIFMovie() SkGIFMovie::~SkGIFMovie()
@ -105,29 +109,242 @@ bool SkGIFMovie::onSetTime(SkMSec time)
dur += savedimage_duration(&fGIF->SavedImages[i]); dur += savedimage_duration(&fGIF->SavedImages[i]);
if (dur >= time) if (dur >= time)
{ {
SavedImage* prev = fCurrSavedImage; fCurrIndex = i;
fCurrSavedImage = &fGIF->SavedImages[i]; return fLastDrawIndex != fCurrIndex;
return prev != fCurrSavedImage;
} }
} }
fCurrSavedImage = &fGIF->SavedImages[fGIF->ImageCount - 1]; fCurrIndex = fGIF->ImageCount - 1;
return true; return true;
} }
static void copyLine(uint32_t* dst, const unsigned char* src, const ColorMapObject* cmap,
int transparent, int width)
{
for (; width > 0; width--, src++, dst++) {
if (*src != transparent) {
const GifColorType& col = cmap->Colors[*src];
*dst = SkPackARGB32(0xFF, col.Red, col.Green, col.Blue);
}
}
}
static void copyInterlaceGroup(SkBitmap* bm, const unsigned char*& src,
const ColorMapObject* cmap, int transparent, int copyWidth,
int copyHeight, const GifImageDesc& imageDesc, int rowStep,
int startRow)
{
int row;
// every 'rowStep'th row, starting with row 'startRow'
for (row = startRow; row < copyHeight; row += rowStep) {
uint32_t* dst = bm->getAddr32(imageDesc.Left, imageDesc.Top + row);
copyLine(dst, src, cmap, transparent, copyWidth);
src += imageDesc.Width;
}
// pad for rest height
src += imageDesc.Width * ((imageDesc.Height - row + rowStep - 1) / rowStep);
}
static void blitInterlace(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap,
int transparent)
{
int width = bm->width();
int height = bm->height();
GifWord copyWidth = frame->ImageDesc.Width;
if (frame->ImageDesc.Left + copyWidth > width) {
copyWidth = width - frame->ImageDesc.Left;
}
GifWord copyHeight = frame->ImageDesc.Height;
if (frame->ImageDesc.Top + copyHeight > height) {
copyHeight = height - frame->ImageDesc.Top;
}
// deinterlace
const unsigned char* src = (unsigned char*)frame->RasterBits;
// group 1 - every 8th row, starting with row 0
copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 8, 0);
// group 2 - every 8th row, starting with row 4
copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 8, 4);
// group 3 - every 4th row, starting with row 2
copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 4, 2);
copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 2, 1);
}
static void blitNormal(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap,
int transparent)
{
int width = bm->width();
int height = bm->height();
const unsigned char* src = (unsigned char*)frame->RasterBits;
uint32_t* dst = bm->getAddr32(frame->ImageDesc.Left, frame->ImageDesc.Top);
GifWord copyWidth = frame->ImageDesc.Width;
if (frame->ImageDesc.Left + copyWidth > width) {
copyWidth = width - frame->ImageDesc.Left;
}
GifWord copyHeight = frame->ImageDesc.Height;
if (frame->ImageDesc.Top + copyHeight > height) {
copyHeight = height - frame->ImageDesc.Top;
}
int srcPad, dstPad;
dstPad = width - copyWidth;
srcPad = frame->ImageDesc.Width - copyWidth;
for (; copyHeight > 0; copyHeight--) {
copyLine(dst, src, cmap, transparent, copyWidth);
src += frame->ImageDesc.Width;
dst += width;
}
}
static void fillRect(SkBitmap* bm, GifWord left, GifWord top, GifWord width, GifWord height,
uint32_t col)
{
int bmWidth = bm->width();
int bmHeight = bm->height();
uint32_t* dst = bm->getAddr32(left, top);
GifWord copyWidth = width;
if (left + copyWidth > bmWidth) {
copyWidth = bmWidth - left;
}
GifWord copyHeight = height;
if (top + copyHeight > bmHeight) {
copyHeight = bmHeight - top;
}
for (; copyHeight > 0; copyHeight--) {
sk_memset32(dst, col, copyWidth);
dst += bmWidth;
}
}
static void drawFrame(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap)
{
int transparent = -1;
for (int i = 0; i < frame->ExtensionBlockCount; ++i) {
ExtensionBlock* eb = frame->ExtensionBlocks + i;
if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
eb->ByteCount == 4) {
bool has_transparency = ((eb->Bytes[0] & 1) == 1);
if (has_transparency) {
transparent = (unsigned char)eb->Bytes[3];
}
}
}
if (frame->ImageDesc.ColorMap != NULL) {
// use local color table
cmap = frame->ImageDesc.ColorMap;
}
if (cmap == NULL || cmap->ColorCount != (1 << cmap->BitsPerPixel)) {
SkASSERT(!"bad colortable setup");
return;
}
if (frame->ImageDesc.Interlace) {
blitInterlace(bm, frame, cmap, transparent);
} else {
blitNormal(bm, frame, cmap, transparent);
}
}
static bool checkIfWillBeCleared(const SavedImage* frame)
{
for (int i = 0; i < frame->ExtensionBlockCount; ++i) {
ExtensionBlock* eb = frame->ExtensionBlocks + i;
if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
eb->ByteCount == 4) {
// check disposal method
int disposal = ((eb->Bytes[0] >> 2) & 7);
if (disposal == 2 || disposal == 3) {
return true;
}
}
}
return false;
}
static void getTransparencyAndDisposalMethod(const SavedImage* frame, bool* trans, int* disposal)
{
*trans = false;
*disposal = 0;
for (int i = 0; i < frame->ExtensionBlockCount; ++i) {
ExtensionBlock* eb = frame->ExtensionBlocks + i;
if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
eb->ByteCount == 4) {
*trans = ((eb->Bytes[0] & 1) == 1);
*disposal = ((eb->Bytes[0] >> 2) & 7);
}
}
}
// return true if area of 'target' is completely covers area of 'covered'
static bool checkIfCover(const SavedImage* target, const SavedImage* covered)
{
if (target->ImageDesc.Left <= covered->ImageDesc.Left
&& covered->ImageDesc.Left + covered->ImageDesc.Width <=
target->ImageDesc.Left + target->ImageDesc.Width
&& target->ImageDesc.Top <= covered->ImageDesc.Top
&& covered->ImageDesc.Top + covered->ImageDesc.Height <=
target->ImageDesc.Top + target->ImageDesc.Height) {
return true;
}
return false;
}
static void disposeFrameIfNeeded(SkBitmap* bm, const SavedImage* cur, const SavedImage* next,
SkBitmap* backup, SkColor color)
{
// We can skip disposal process if next frame is not transparent
// and completely covers current area
bool curTrans;
int curDisposal;
getTransparencyAndDisposalMethod(cur, &curTrans, &curDisposal);
bool nextTrans;
int nextDisposal;
getTransparencyAndDisposalMethod(next, &nextTrans, &nextDisposal);
if ((curDisposal == 2 || curDisposal == 3)
&& (nextTrans || !checkIfCover(next, cur))) {
switch (curDisposal) {
// restore to background color
// -> 'background' means background under this image.
case 2:
fillRect(bm, cur->ImageDesc.Left, cur->ImageDesc.Top,
cur->ImageDesc.Width, cur->ImageDesc.Height,
color);
break;
// restore to previous
case 3:
bm->swap(*backup);
break;
}
}
// Save current image if next frame's disposal method == 3
if (nextDisposal == 3) {
const uint32_t* src = bm->getAddr32(0, 0);
uint32_t* dst = backup->getAddr32(0, 0);
int cnt = bm->width() * bm->height();
memcpy(dst, src, cnt*sizeof(uint32_t));
}
}
bool SkGIFMovie::onGetBitmap(SkBitmap* bm) bool SkGIFMovie::onGetBitmap(SkBitmap* bm)
{ {
GifFileType* gif = fGIF; const GifFileType* gif = fGIF;
if (NULL == gif) if (NULL == gif)
return false; return false;
// should we check for the Image cmap or the global (SColorMap) first? if (gif->ImageCount < 1) {
ColorMapObject* cmap = gif->SColorMap;
if (cmap == NULL)
cmap = gif->Image.ColorMap;
if (cmap == NULL || gif->ImageCount < 1 || cmap->ColorCount != (1 << cmap->BitsPerPixel))
{
SkASSERT(!"bad colortable setup");
return false; return false;
} }
@ -137,76 +354,79 @@ bool SkGIFMovie::onGetBitmap(SkBitmap* bm)
return false; return false;
} }
SavedImage* gif_image = fCurrSavedImage; // no need to draw
SkBitmap::Config config = SkBitmap::kIndex8_Config; if (fLastDrawIndex >= 0 && fLastDrawIndex == fCurrIndex) {
return true;
SkColorTable* colorTable = SkNEW_ARGS(SkColorTable, (cmap->ColorCount));
SkAutoUnref aur(colorTable);
bm->setConfig(config, width, height, 0);
if (!bm->allocPixels(colorTable)) {
return false;
} }
int transparent = -1; int startIndex = fLastDrawIndex + 1;
for (int i = 0; i < gif_image->ExtensionBlockCount; ++i) { if (fLastDrawIndex < 0 || !bm->readyToDraw()) {
ExtensionBlock* eb = gif_image->ExtensionBlocks + i; // first time
if (eb->Function == 0xF9 &&
eb->ByteCount == 4) { startIndex = 0;
bool has_transparency = ((eb->Bytes[0] & 1) == 1);
if (has_transparency) { // create bitmap
transparent = (unsigned char)eb->Bytes[3]; bm->setConfig(SkBitmap::kARGB_8888_Config, width, height, 0);
if (!bm->allocPixels(NULL)) {
return false;
} }
} // create bitmap for backup
fBackup.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0);
if (!fBackup.allocPixels(NULL)) {
return false;
}
} else if (startIndex > fCurrIndex) {
// rewind to 1st frame for repeat
startIndex = 0;
} }
SkPMColor* colorPtr = colorTable->lockColors(); int lastIndex = fCurrIndex;
if (lastIndex < 0) {
if (transparent >= 0) // first time
memset(colorPtr, 0, cmap->ColorCount * 4); lastIndex = 0;
else } else if (lastIndex > fGIF->ImageCount - 1) {
colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag); // this block must not be reached.
lastIndex = fGIF->ImageCount - 1;
for (int index = 0; index < cmap->ColorCount; index++)
{
if (transparent != index)
colorPtr[index] = SkPackARGB32(0xFF, cmap->Colors[index].Red,
cmap->Colors[index].Green, cmap->Colors[index].Blue);
} }
colorTable->unlockColors(true);
unsigned char* in = (unsigned char*)gif_image->RasterBits; SkColor bgColor = SkPackARGB32(0, 0, 0, 0);
unsigned char* out = bm->getAddr8(0, 0); if (gif->SColorMap != NULL) {
if (gif->Image.Interlace) { const GifColorType& col = gif->SColorMap->Colors[fGIF->SBackGroundColor];
bgColor = SkColorSetARGB(0xFF, col.Red, col.Green, col.Blue);
// deinterlace
int row;
// group 1 - every 8th row, starting with row 0
for (row = 0; row < height; row += 8) {
memcpy(out + width * row, in, width);
in += width;
}
// group 2 - every 8th row, starting with row 4
for (row = 4; row < height; row += 8) {
memcpy(out + width * row, in, width);
in += width;
}
// group 3 - every 4th row, starting with row 2
for (row = 2; row < height; row += 4) {
memcpy(out + width * row, in, width);
in += width;
}
for (row = 1; row < height; row += 2) {
memcpy(out + width * row, in, width);
in += width;
}
} else {
memcpy(out, in, width * height);
} }
static SkColor paintingColor = SkPackARGB32(0, 0, 0, 0);
// draw each frames - not intelligent way
for (int i = startIndex; i <= lastIndex; i++) {
const SavedImage* cur = &fGIF->SavedImages[i];
if (i == 0) {
bool trans;
int disposal;
getTransparencyAndDisposalMethod(cur, &trans, &disposal);
if (!trans && gif->SColorMap != NULL) {
paintingColor = bgColor;
} else {
paintingColor = SkColorSetARGB(0, 0, 0, 0);
}
bm->eraseColor(paintingColor);
fBackup.eraseColor(paintingColor);
} else {
// Dispose previous frame before move to next frame.
const SavedImage* prev = &fGIF->SavedImages[i-1];
disposeFrameIfNeeded(bm, prev, cur, &fBackup, paintingColor);
}
// Draw frame
// We can skip this process if this index is not last and disposal
// method == 2 or method == 3
if (i == lastIndex || !checkIfWillBeCleared(cur)) {
drawFrame(bm, cur, gif->SColorMap);
}
}
// save index
fLastDrawIndex = lastIndex;
return true; return true;
} }

Просмотреть файл

@ -93,6 +93,18 @@ static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow,
return false; return false;
} }
static bool Sample_D565_D565(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int, const SkPMColor[]) {
uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
uint16_t* SK_RESTRICT castedSrc = (uint16_t*) src;
for (int x = 0; x < width; x++) {
dst[x] = castedSrc[0];
castedSrc += deltaSrc >> 1;
}
return false;
}
static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow, static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src, const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int y, const SkPMColor[]) { int width, int deltaSrc, int y, const SkPMColor[]) {
@ -335,21 +347,25 @@ bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither,
Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888,
Sample_RGBA_D8888, Sample_RGBA_D8888, Sample_RGBA_D8888, Sample_RGBA_D8888,
Sample_Index_D8888, Sample_Index_D8888, Sample_Index_D8888, Sample_Index_D8888,
NULL, NULL,
// 565 (no alpha distinction) // 565 (no alpha distinction)
Sample_Gray_D565, Sample_Gray_D565_D, Sample_Gray_D565, Sample_Gray_D565_D,
Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D,
Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D,
Sample_Index_D565, Sample_Index_D565_D, Sample_Index_D565, Sample_Index_D565_D,
Sample_D565_D565, Sample_D565_D565,
// 4444 // 4444
Sample_Gray_D4444, Sample_Gray_D4444_D, Sample_Gray_D4444, Sample_Gray_D4444_D,
Sample_RGBx_D4444, Sample_RGBx_D4444_D, Sample_RGBx_D4444, Sample_RGBx_D4444_D,
Sample_RGBA_D4444, Sample_RGBA_D4444_D, Sample_RGBA_D4444, Sample_RGBA_D4444_D,
Sample_Index_D4444, Sample_Index_D4444_D, Sample_Index_D4444, Sample_Index_D4444_D,
NULL, NULL,
// Index8 // Index8
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
Sample_Index_DI, Sample_Index_DI, Sample_Index_DI, Sample_Index_DI,
NULL, NULL,
}; };
fCTable = ctable; fCTable = ctable;
@ -379,6 +395,10 @@ bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither,
fSrcPixelSize = 1; fSrcPixelSize = 1;
index += 6; index += 6;
break; break;
case SkScaledBitmapSampler::kRGB_565:
fSrcPixelSize = 2;
index += 8;
break;
default: default:
return false; return false;
} }
@ -388,13 +408,13 @@ bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither,
index += 0; index += 0;
break; break;
case SkBitmap::kRGB_565_Config: case SkBitmap::kRGB_565_Config:
index += 8; index += 10;
break; break;
case SkBitmap::kARGB_4444_Config: case SkBitmap::kARGB_4444_Config:
index += 16; index += 20;
break; break;
case SkBitmap::kIndex8_Config: case SkBitmap::kIndex8_Config:
index += 24; index += 30;
break; break;
default: default:
return false; return false;

Просмотреть файл

@ -21,7 +21,8 @@ public:
kIndex, // 1 byte per pixel kIndex, // 1 byte per pixel
kRGB, // 3 bytes per pixel kRGB, // 3 bytes per pixel
kRGBX, // 4 byes per pixel (ignore 4th) kRGBX, // 4 byes per pixel (ignore 4th)
kRGBA // 4 bytes per pixel kRGBA, // 4 bytes per pixel
kRGB_565 // 2 bytes per pixel
}; };
// Given a dst bitmap (with pixels already allocated) and a src-config, // Given a dst bitmap (with pixels already allocated) and a src-config,

Просмотреть файл

@ -1,5 +1,6 @@
#include "SkImageRef_ashmem.h" #include "SkImageRef_ashmem.h"
#include "SkImageDecoder.h" #include "SkImageDecoder.h"
#include "SkFlattenable.h"
#include "SkThread.h" #include "SkThread.h"
#include <sys/mman.h> #include <sys/mman.h>
@ -36,7 +37,7 @@ SkImageRef_ashmem::SkImageRef_ashmem(SkStream* stream,
} }
SkImageRef_ashmem::~SkImageRef_ashmem() { SkImageRef_ashmem::~SkImageRef_ashmem() {
fCT->safeUnref(); SkSafeUnref(fCT);
this->closeFD(); this->closeFD();
} }
@ -201,3 +202,36 @@ void SkImageRef_ashmem::onUnlockPixels() {
fBitmap.setPixels(NULL, NULL); fBitmap.setPixels(NULL, NULL);
} }
void SkImageRef_ashmem::flatten(SkFlattenableWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
const char* uri = getURI();
if (uri) {
size_t len = strlen(uri);
buffer.write32(len);
buffer.writePad(uri, len);
} else {
buffer.write32(0);
}
}
SkImageRef_ashmem::SkImageRef_ashmem(SkFlattenableReadBuffer& buffer)
: INHERITED(buffer) {
fRec.fFD = -1;
fRec.fAddr = NULL;
fRec.fSize = 0;
fRec.fPinned = false;
fCT = NULL;
size_t length = buffer.readU32();
if (length) {
char* buf = (char*) malloc(length);
buffer.read(buf, length);
setURI(buf, length);
}
}
SkPixelRef* SkImageRef_ashmem::Create(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkImageRef_ashmem, (buffer));
}
static SkPixelRef::Registrar reg("SkImageRef_ashmem",
SkImageRef_ashmem::Create);

Просмотреть файл

@ -15,6 +15,13 @@ public:
SkImageRef_ashmem(SkStream*, SkBitmap::Config, int sampleSize = 1); SkImageRef_ashmem(SkStream*, SkBitmap::Config, int sampleSize = 1);
virtual ~SkImageRef_ashmem(); virtual ~SkImageRef_ashmem();
// overrides
virtual void flatten(SkFlattenableWriteBuffer&) const;
virtual Factory getFactory() const {
return Create;
}
static SkPixelRef* Create(SkFlattenableReadBuffer&);
protected: protected:
virtual bool onDecode(SkImageDecoder* codec, SkStream* stream, virtual bool onDecode(SkImageDecoder* codec, SkStream* stream,
SkBitmap* bitmap, SkBitmap::Config config, SkBitmap* bitmap, SkBitmap::Config config,
@ -24,6 +31,7 @@ protected:
virtual void onUnlockPixels(); virtual void onUnlockPixels();
private: private:
SkImageRef_ashmem(SkFlattenableReadBuffer&);
void closeFD(); void closeFD();
SkColorTable* fCT; SkColorTable* fCT;

Просмотреть файл

@ -235,15 +235,27 @@ static void drawNineViaRects(SkCanvas* canvas, const SkRect& dst,
const int32_t srcY[4] = { const int32_t srcY[4] = {
0, margins.fTop, bitmap.height() - margins.fBottom, bitmap.height() 0, margins.fTop, bitmap.height() - margins.fBottom, bitmap.height()
}; };
const SkScalar dstX[4] = { SkScalar dstX[4] = {
dst.fLeft, dst.fLeft + SkIntToScalar(margins.fLeft), dst.fLeft, dst.fLeft + SkIntToScalar(margins.fLeft),
dst.fRight - SkIntToScalar(margins.fRight), dst.fRight dst.fRight - SkIntToScalar(margins.fRight), dst.fRight
}; };
const SkScalar dstY[4] = { SkScalar dstY[4] = {
dst.fTop, dst.fTop + SkIntToScalar(margins.fTop), dst.fTop, dst.fTop + SkIntToScalar(margins.fTop),
dst.fBottom - SkIntToScalar(margins.fBottom), dst.fBottom dst.fBottom - SkIntToScalar(margins.fBottom), dst.fBottom
}; };
if (dstX[1] > dstX[2]) {
dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * SkIntToScalar(margins.fLeft) /
(SkIntToScalar(margins.fLeft) + SkIntToScalar(margins.fRight));
dstX[2] = dstX[1];
}
if (dstY[1] > dstY[2]) {
dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * SkIntToScalar(margins.fTop) /
(SkIntToScalar(margins.fTop) + SkIntToScalar(margins.fBottom));
dstY[2] = dstY[1];
}
SkIRect s; SkIRect s;
SkRect d; SkRect d;
for (int y = 0; y < 3; y++) { for (int y = 0; y < 3; y++) {
@ -279,6 +291,17 @@ void SkNinePatch::DrawNine(SkCanvas* canvas, const SkRect& bounds,
yDivs[0] = margins.fTop; yDivs[0] = margins.fTop;
yDivs[1] = bitmap.height() - margins.fBottom; yDivs[1] = bitmap.height() - margins.fBottom;
if (xDivs[0] > xDivs[1]) {
xDivs[0] = bitmap.width() * margins.fLeft /
(margins.fLeft + margins.fRight);
xDivs[1] = xDivs[0];
}
if (yDivs[0] > yDivs[1]) {
yDivs[0] = bitmap.height() * margins.fTop /
(margins.fTop + margins.fBottom);
yDivs[1] = yDivs[0];
}
SkNinePatch::DrawMesh(canvas, bounds, bitmap, SkNinePatch::DrawMesh(canvas, bounds, bitmap,
xDivs, 2, yDivs, 2, paint); xDivs, 2, yDivs, 2, paint);
} else { } else {