1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SkFlipPixelRef.h"
9#include "SkFlattenable.h"
10#include "SkRegion.h"
11
12SkFlipPixelRef::SkFlipPixelRef(SkBitmap::Config config, int width, int height)
13: fFlipper(width, height) {
14    fConfig = config;
15    fSize = SkBitmap::ComputeSize(config, width, height);
16    fStorage = sk_malloc_throw(fSize << 1);
17    fPage0 = fStorage;
18    fPage1 = (char*)fStorage + fSize;
19}
20
21SkFlipPixelRef::~SkFlipPixelRef() {
22    sk_free(fStorage);
23}
24
25const SkRegion& SkFlipPixelRef::beginUpdate(SkBitmap* device) {
26    void*       writeAddr;
27    const void* readAddr;
28    this->getFrontBack(&readAddr, &writeAddr);
29
30    device->setConfig(fConfig, fFlipper.width(), fFlipper.height());
31    device->setPixels(writeAddr);
32
33    SkRegion    copyBits;
34    const SkRegion& dirty = fFlipper.update(&copyBits);
35
36    SkFlipPixelRef::CopyBitsFromAddr(*device, copyBits, readAddr);
37    return dirty;
38}
39
40void SkFlipPixelRef::endUpdate() {
41    this->swapPages();
42}
43
44///////////////////////////////////////////////////////////////////////////////
45
46void* SkFlipPixelRef::onLockPixels(SkColorTable** ct) {
47    fMutex.acquire();
48    *ct = NULL;
49    return fPage0;
50}
51
52void SkFlipPixelRef::onUnlockPixels() {
53    fMutex.release();
54}
55
56void SkFlipPixelRef::swapPages() {
57    fMutex.acquire();
58    SkTSwap<void*>(fPage0, fPage1);
59    this->notifyPixelsChanged();
60    fMutex.release();
61}
62
63void SkFlipPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const {
64    this->INHERITED::flatten(buffer);
65
66    buffer.write32(fSize);
67    // only need to write page0
68    buffer.writePad(fPage0, fSize);
69}
70
71SkFlipPixelRef::SkFlipPixelRef(SkFlattenableReadBuffer& buffer)
72        : INHERITED(buffer, NULL) {
73    fSize = buffer.readU32();
74    fStorage = sk_malloc_throw(fSize << 1);
75    fPage0 = fStorage;
76    fPage1 = (char*)fStorage + fSize;
77    buffer.read(fPage0, fSize);
78}
79
80SkPixelRef* SkFlipPixelRef::Create(SkFlattenableReadBuffer& buffer) {
81    return SkNEW_ARGS(SkFlipPixelRef, (buffer));
82}
83
84SK_DEFINE_PIXEL_REF_REGISTRAR(SkFlipPixelRef)
85
86///////////////////////////////////////////////////////////////////////////////
87
88static void copyRect(const SkBitmap& dst, const SkIRect& rect,
89                     const void* srcAddr, int shift) {
90    const size_t offset = rect.fTop * dst.rowBytes() + (rect.fLeft << shift);
91    char* dstP = static_cast<char*>(dst.getPixels()) + offset;
92    const char* srcP = static_cast<const char*>(srcAddr) + offset;
93    const size_t rb = dst.rowBytes();
94    const size_t bytes = rect.width() << shift;
95
96    int height = rect.height();
97    while (--height >= 0) {
98        memcpy(dstP, srcP, bytes);
99        dstP += rb;
100        srcP += rb;
101    }
102}
103
104static int getShift(SkBitmap::Config config) {
105    switch (config) {
106        case SkBitmap::kARGB_8888_Config:
107            return 2;
108        case SkBitmap::kRGB_565_Config:
109        case SkBitmap::kARGB_4444_Config:
110            return 1;
111        case SkBitmap::kIndex8_Config:
112        case SkBitmap::kA8_Config:
113            return 0;
114        default:
115            return -1;  // signal not supported
116    }
117}
118
119void SkFlipPixelRef::CopyBitsFromAddr(const SkBitmap& dst, const SkRegion& clip,
120                                      const void* srcAddr) {
121    const int shift = getShift(dst.config());
122    if (shift < 0) {
123        return;
124    }
125
126    const SkIRect bounds = {0, 0, dst.width(), dst.height()};
127    SkRegion::Cliperator iter(clip, bounds);
128
129    while (!iter.done()) {
130        copyRect(dst, iter.rect(), srcAddr, shift);
131        iter.next();
132    }
133}
134