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 "SkImageGenerator.h"
11#include "SkImagePriv.h"
12#include "SkImage_Base.h"
13#include "SkReadPixelsRec.h"
14#include "SkString.h"
15#include "SkSurface.h"
16
17uint32_t SkImage::NextUniqueID() {
18    static int32_t gUniqueID;
19
20    // never return 0;
21    uint32_t id;
22    do {
23        id = sk_atomic_inc(&gUniqueID) + 1;
24    } while (0 == id);
25    return id;
26}
27
28const void* SkImage::peekPixels(SkImageInfo* info, size_t* rowBytes) const {
29    SkImageInfo infoStorage;
30    size_t rowBytesStorage;
31    if (NULL == info) {
32        info = &infoStorage;
33    }
34    if (NULL == rowBytes) {
35        rowBytes = &rowBytesStorage;
36    }
37    return as_IB(this)->onPeekPixels(info, rowBytes);
38}
39
40bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
41                           int srcX, int srcY) const {
42    SkReadPixelsRec rec(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
43    if (!rec.trim(this->width(), this->height())) {
44        return false;
45    }
46    return as_IB(this)->onReadPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
47}
48
49GrTexture* SkImage::getTexture() const {
50    return as_IB(this)->onGetTexture();
51}
52
53SkShader* SkImage::newShader(SkShader::TileMode tileX,
54                             SkShader::TileMode tileY,
55                             const SkMatrix* localMatrix) const {
56    return as_IB(this)->onNewShader(tileX, tileY, localMatrix);
57}
58
59SkData* SkImage::encode(SkImageEncoder::Type type, int quality) const {
60    SkBitmap bm;
61    if (as_IB(this)->getROPixels(&bm)) {
62        return SkImageEncoder::EncodeData(bm, type, quality);
63    }
64    return NULL;
65}
66
67SkImage* SkImage::NewFromData(SkData* data) {
68    if (NULL == data) {
69        return NULL;
70    }
71    SkImageGenerator* generator = SkImageGenerator::NewFromData(data);
72    return generator ? SkImage::NewFromGenerator(generator) : NULL;
73}
74
75SkSurface* SkImage::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) const {
76    if (NULL == props) {
77        props = &as_IB(this)->props();
78    }
79    return as_IB(this)->onNewSurface(info, *props);
80}
81
82const char* SkImage::toString(SkString* str) const {
83    str->appendf("image: (id:%d (%d, %d) %s)", this->uniqueID(), this->width(), this->height(),
84                 this->isOpaque() ? "opaque" : "");
85    return str->c_str();
86}
87
88SkImage* SkImage::newImage(int newWidth, int newHeight, const SkIRect* subset,
89                           SkFilterQuality quality) const {
90    if (newWidth <= 0 || newHeight <= 0) {
91        return NULL;
92    }
93
94    const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
95
96    if (subset) {
97        if (!bounds.contains(*subset)) {
98            return NULL;
99        }
100        if (bounds == *subset) {
101            subset = NULL;  // and fall through to check below
102        }
103    }
104
105    if (NULL == subset && this->width() == newWidth && this->height() == newHeight) {
106        return SkRef(const_cast<SkImage*>(this));
107    }
108
109    return as_IB(this)->onNewImage(newWidth, newHeight, subset, quality);
110}
111
112///////////////////////////////////////////////////////////////////////////////
113
114static bool raster_canvas_supports(const SkImageInfo& info) {
115    switch (info.colorType()) {
116        case kN32_SkColorType:
117            return kUnpremul_SkAlphaType != info.alphaType();
118        case kRGB_565_SkColorType:
119            return true;
120        case kAlpha_8_SkColorType:
121            return true;
122        default:
123            break;
124    }
125    return false;
126}
127
128bool SkImage_Base::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
129                                int srcX, int srcY) const {
130    if (!raster_canvas_supports(dstInfo)) {
131        return false;
132    }
133
134    SkBitmap bm;
135    bm.installPixels(dstInfo, dstPixels, dstRowBytes);
136    SkCanvas canvas(bm);
137
138    SkPaint paint;
139    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
140    canvas.drawImage(this, -SkIntToScalar(srcX), -SkIntToScalar(srcY), &paint);
141
142    return true;
143}
144
145SkImage* SkImage_Base::onNewImage(int newWidth, int newHeight, const SkIRect* subset,
146                                  SkFilterQuality quality) const {
147    const bool opaque = this->isOpaque();
148    const SkImageInfo info = SkImageInfo::Make(newWidth, newHeight, kN32_SkColorType,
149                                               opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
150    SkAutoTUnref<SkSurface> surface(this->newSurface(info, NULL));
151    if (!surface.get()) {
152        return NULL;
153    }
154
155    SkRect src;
156    if (subset) {
157        src.set(*subset);
158    } else {
159        src = SkRect::MakeIWH(this->width(), this->height());
160    }
161
162    surface->getCanvas()->scale(newWidth / src.width(), newHeight / src.height());
163    surface->getCanvas()->translate(-src.x(), -src.y());
164
165    SkPaint paint;
166    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
167    paint.setFilterQuality(quality);
168    surface->getCanvas()->drawImage(this, 0, 0, &paint);
169    return surface->newImageSnapshot();
170}
171
172//////////////////////////////////////////////////////////////////////////////////////
173
174#if !SK_SUPPORT_GPU
175
176SkImage* SkImage::NewFromTexture(GrContext*, const GrBackendTextureDesc&, SkAlphaType) {
177    return NULL;
178}
179
180SkImage* SkImage::NewFromTextureCopy(GrContext*, const GrBackendTextureDesc&, SkAlphaType) {
181    return NULL;
182}
183
184#endif
185