| |
| /* |
| * 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 "SkFlattenableBuffers.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); |
| // only need to write page0 |
| buffer.writeByteArray(fPage0, fSize); |
| } |
| |
| SkFlipPixelRef::SkFlipPixelRef(SkFlattenableReadBuffer& buffer) |
| : INHERITED(buffer, NULL) { |
| fSize = buffer.getArrayCount(); |
| fStorage = sk_malloc_throw(fSize << 1); |
| fPage0 = fStorage; |
| fPage1 = (char*)fStorage + fSize; |
| buffer.readByteArray(fPage0); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| 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(); |
| } |
| } |