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 "SkBitmap.h"
9#include "SkCanvas.h"
10#include "SkImagePriv.h"
11#include "SkImage_Base.h"
12
13static SkImage_Base* as_IB(SkImage* image) {
14    return static_cast<SkImage_Base*>(image);
15}
16
17static const SkImage_Base* as_IB(const SkImage* image) {
18    return static_cast<const SkImage_Base*>(image);
19}
20
21uint32_t SkImage::NextUniqueID() {
22    static int32_t gUniqueID;
23
24    // never return 0;
25    uint32_t id;
26    do {
27        id = sk_atomic_inc(&gUniqueID) + 1;
28    } while (0 == id);
29    return id;
30}
31
32void SkImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
33                   const SkPaint* paint) {
34    as_IB(this)->onDraw(canvas, x, y, paint);
35}
36
37void SkImage::draw(SkCanvas* canvas, const SkRect* src, const SkRect& dst,
38                   const SkPaint* paint) {
39    as_IB(this)->onDrawRectToRect(canvas, src, dst, paint);
40}
41
42const void* SkImage::peekPixels(SkImageInfo* info, size_t* rowBytes) const {
43    SkImageInfo infoStorage;
44    size_t rowBytesStorage;
45    if (NULL == info) {
46        info = &infoStorage;
47    }
48    if (NULL == rowBytes) {
49        rowBytes = &rowBytesStorage;
50    }
51    return as_IB(this)->onPeekPixels(info, rowBytes);
52}
53
54bool SkImage::readPixels(SkBitmap* bitmap, const SkIRect* subset) const {
55    if (NULL == bitmap) {
56        return false;
57    }
58
59    SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
60
61    // trim against the bitmap, if its already been allocated
62    if (bitmap->pixelRef()) {
63        bounds.fRight = SkMin32(bounds.fRight, bitmap->width());
64        bounds.fBottom = SkMin32(bounds.fBottom, bitmap->height());
65        if (bounds.isEmpty()) {
66            return false;
67        }
68    }
69
70    if (subset && !bounds.intersect(*subset)) {
71        // perhaps we could return true + empty-bitmap?
72        return false;
73    }
74    return as_IB(this)->onReadPixels(bitmap, bounds);
75}
76
77GrTexture* SkImage::getTexture() {
78    return as_IB(this)->onGetTexture();
79}
80
81SkData* SkImage::encode(SkImageEncoder::Type type, int quality) const {
82    SkBitmap bm;
83    if (as_IB(this)->getROPixels(&bm)) {
84        return SkImageEncoder::EncodeData(bm, type, quality);
85    }
86    return NULL;
87}
88
89///////////////////////////////////////////////////////////////////////////////
90
91static bool raster_canvas_supports(const SkImageInfo& info) {
92    switch (info.fColorType) {
93        case kN32_SkColorType:
94            return kUnpremul_SkAlphaType != info.fAlphaType;
95        case kRGB_565_SkColorType:
96            return true;
97        case kAlpha_8_SkColorType:
98            return true;
99        default:
100            break;
101    }
102    return false;
103}
104
105bool SkImage_Base::onReadPixels(SkBitmap* bitmap, const SkIRect& subset) const {
106    if (bitmap->pixelRef()) {
107        const SkImageInfo info = bitmap->info();
108        if (kUnknown_SkColorType == info.colorType()) {
109            return false;
110        }
111        if (!raster_canvas_supports(info)) {
112            return false;
113        }
114    } else {
115        const SkImageInfo info = SkImageInfo::MakeN32Premul(subset.width(), subset.height());
116        SkBitmap tmp;
117        if (!tmp.allocPixels(info)) {
118            return false;
119        }
120        *bitmap = tmp;
121    }
122
123    SkRect srcR, dstR;
124    srcR.set(subset);
125    dstR = srcR;
126    dstR.offset(-dstR.left(), -dstR.top());
127
128    SkCanvas canvas(*bitmap);
129
130    SkPaint paint;
131    paint.setXfermodeMode(SkXfermode::kClear_Mode);
132    canvas.drawRect(dstR, paint);
133
134    const_cast<SkImage_Base*>(this)->onDrawRectToRect(&canvas, &srcR, dstR, NULL);
135    return true;
136}
137