/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #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(©Bits); 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); this->notifyPixelsChanged(); 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)); } SK_DEFINE_PIXEL_REF_REGISTRAR(SkFlipPixelRef) /////////////////////////////////////////////////////////////////////////////// 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(); } }