SkSurface_Raster.cpp revision 982542dce8acbd2f3e7642268b21e76b93230daf
1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkSurface_Base.h"
9#include "SkImagePriv.h"
10#include "SkCanvas.h"
11#include "SkDevice.h"
12#include "SkMallocPixelRef.h"
13
14static const size_t kIgnoreRowBytesValue = (size_t)~0;
15
16class SkSurface_Raster : public SkSurface_Base {
17public:
18    static bool Valid(const SkImageInfo&, size_t rb = kIgnoreRowBytesValue);
19
20    SkSurface_Raster(const SkImageInfo&, void*, size_t rb,
21                     void (*releaseProc)(void* pixels, void* context), void* context);
22    SkSurface_Raster(SkPixelRef*);
23
24    virtual SkCanvas* onNewCanvas() SK_OVERRIDE;
25    virtual SkSurface* onNewSurface(const SkImageInfo&) SK_OVERRIDE;
26    virtual SkImage* onNewImageSnapshot() SK_OVERRIDE;
27    virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y,
28                        const SkPaint*) SK_OVERRIDE;
29    virtual void onCopyOnWrite(ContentChangeMode) SK_OVERRIDE;
30
31private:
32    SkBitmap    fBitmap;
33    bool        fWeOwnThePixels;
34
35    typedef SkSurface_Base INHERITED;
36};
37
38///////////////////////////////////////////////////////////////////////////////
39
40bool SkSurface_Raster::Valid(const SkImageInfo& info, size_t rowBytes) {
41    static const size_t kMaxTotalSize = SK_MaxS32;
42
43    int shift = 0;
44    switch (info.fColorType) {
45        case kAlpha_8_SkColorType:
46            shift = 0;
47            break;
48        case kRGB_565_SkColorType:
49            shift = 1;
50            break;
51        case kN32_SkColorType:
52            shift = 2;
53            break;
54        default:
55            return false;
56    }
57
58    if (kIgnoreRowBytesValue == rowBytes) {
59        return true;
60    }
61
62    uint64_t minRB = (uint64_t)info.fWidth << shift;
63    if (minRB > rowBytes) {
64        return false;
65    }
66
67    size_t alignedRowBytes = rowBytes >> shift << shift;
68    if (alignedRowBytes != rowBytes) {
69        return false;
70    }
71
72    uint64_t size = sk_64_mul(info.fHeight, rowBytes);
73    if (size > kMaxTotalSize) {
74        return false;
75    }
76
77    return true;
78}
79
80SkSurface_Raster::SkSurface_Raster(const SkImageInfo& info, void* pixels, size_t rb,
81                                   void (*releaseProc)(void* pixels, void* context), void* context)
82    : INHERITED(info)
83{
84    fBitmap.installPixels(info, pixels, rb, NULL, releaseProc, context);
85    fWeOwnThePixels = false;    // We are "Direct"
86}
87
88SkSurface_Raster::SkSurface_Raster(SkPixelRef* pr)
89    : INHERITED(pr->info().fWidth, pr->info().fHeight)
90{
91    const SkImageInfo& info = pr->info();
92
93    fBitmap.setInfo(info, info.minRowBytes());
94    fBitmap.setPixelRef(pr);
95    fWeOwnThePixels = true;
96
97    if (!info.isOpaque()) {
98        fBitmap.eraseColor(SK_ColorTRANSPARENT);
99    }
100}
101
102SkCanvas* SkSurface_Raster::onNewCanvas() {
103    return SkNEW_ARGS(SkCanvas, (fBitmap));
104}
105
106SkSurface* SkSurface_Raster::onNewSurface(const SkImageInfo& info) {
107    return SkSurface::NewRaster(info);
108}
109
110void SkSurface_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
111                              const SkPaint* paint) {
112    canvas->drawBitmap(fBitmap, x, y, paint);
113}
114
115SkImage* SkSurface_Raster::onNewImageSnapshot() {
116    return SkNewImageFromBitmap(fBitmap, fWeOwnThePixels);
117}
118
119void SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) {
120    // are we sharing pixelrefs with the image?
121    SkASSERT(NULL != this->getCachedImage());
122    if (SkBitmapImageGetPixelRef(this->getCachedImage()) == fBitmap.pixelRef()) {
123        SkASSERT(fWeOwnThePixels);
124        if (kDiscard_ContentChangeMode == mode) {
125            fBitmap.setPixelRef(NULL);
126            fBitmap.allocPixels();
127        } else {
128            SkBitmap prev(fBitmap);
129            prev.deepCopyTo(&fBitmap);
130        }
131        // Now fBitmap is a deep copy of itself (and therefore different from
132        // what is being used by the image. Next we update the canvas to use
133        // this as its backend, so we can't modify the image's pixels anymore.
134        SkASSERT(NULL != this->getCachedCanvas());
135        this->getCachedCanvas()->getDevice()->replaceBitmapBackendForRasterSurface(fBitmap);
136    }
137}
138
139///////////////////////////////////////////////////////////////////////////////
140
141SkSurface* SkSurface::NewRasterDirectReleaseProc(const SkImageInfo& info, void* pixels, size_t rb,
142                                                 void (*releaseProc)(void* pixels, void* context),
143                                                 void* context) {
144    if (NULL == releaseProc) {
145        context = NULL;
146    }
147    if (!SkSurface_Raster::Valid(info, rb)) {
148        return NULL;
149    }
150    if (NULL == pixels) {
151        return NULL;
152    }
153
154    return SkNEW_ARGS(SkSurface_Raster, (info, pixels, rb, releaseProc, context));
155}
156
157SkSurface* SkSurface::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
158    return NewRasterDirectReleaseProc(info, pixels, rowBytes, NULL, NULL);
159}
160
161SkSurface* SkSurface::NewRaster(const SkImageInfo& info) {
162    if (!SkSurface_Raster::Valid(info)) {
163        return NULL;
164    }
165
166    SkAutoTUnref<SkPixelRef> pr(SkMallocPixelRef::NewAllocate(info, 0, NULL));
167    if (NULL == pr.get()) {
168        return NULL;
169    }
170    return SkNEW_ARGS(SkSurface_Raster, (pr));
171}
172