blob: 0573a8383604bafd28e01fbc2afc42f107dd4568 [file] [log] [blame]
reed@google.comf6627b72012-07-27 18:02:50 +00001#include "SkImage.h"
2
3#include "SkBitmap.h"
4
5///////////////////////////////////////////////////////////////////////////////
6
7class SkImage_Base : public SkImage {
8public:
9 SkImage_Base(int width, int height) : INHERITED(width, height) {}
10
11 virtual const SkBitmap* asABitmap() { return NULL; }
12
13private:
14 typedef SkImage INHERITED;
15};
16
17static SkImage_Base* asIB(SkImage* image) {
18 return static_cast<SkImage_Base*>(image);
19}
20
21///////////////////////////////////////////////////////////////////////////////
22
23static SkBitmap::Config InfoToConfig(const SkImage::Info& info, bool* isOpaque) {
24 switch (info.fColorType) {
25 case SkImage::kAlpha_8_ColorType:
26 switch (info.fAlphaType) {
27 case SkImage::kIgnore_AlphaType:
28 // makes no sense
29 return SkBitmap::kNo_Config;
30
31 case SkImage::kOpaque_AlphaType:
32 *isOpaque = true;
33 return SkBitmap::kA8_Config;
34
35 case SkImage::kPremul_AlphaType:
36 case SkImage::kUnpremul_AlphaType:
37 *isOpaque = false;
38 return SkBitmap::kA8_Config;
39 }
40 break;
41
42 case SkImage::kRGB_565_ColorType:
43 // we ignore fAlpahType, though some would not make sense
44 *isOpaque = true;
45 return SkBitmap::kRGB_565_Config;
46
47 case SkImage::kRGBA_8888_ColorType:
48 case SkImage::kBGRA_8888_ColorType:
49 // not supported yet
50 return SkBitmap::kNo_Config;
51
52 case SkImage::kPMColor_ColorType:
53 switch (info.fAlphaType) {
54 case SkImage::kIgnore_AlphaType:
55 case SkImage::kUnpremul_AlphaType:
56 // not supported yet
57 return SkBitmap::kNo_Config;
58 case SkImage::kOpaque_AlphaType:
59 *isOpaque = true;
60 return SkBitmap::kARGB_8888_Config;
61 case SkImage::kPremul_AlphaType:
62 *isOpaque = false;
63 return SkBitmap::kARGB_8888_Config;
64 }
65 break;
66 }
67 SkASSERT(!"how did we get here");
68 return SkBitmap::kNo_Config;
69}
70
71static int BytesPerPixel(SkImage::ColorType ct) {
72 static const uint8_t gColorTypeBytesPerPixel[] = {
73 1, // kAlpha_8_ColorType
74 2, // kRGB_565_ColorType
75 4, // kRGBA_8888_ColorType
76 4, // kBGRA_8888_ColorType
77 4, // kPMColor_ColorType
78 };
79
80 SkASSERT((size_t)ct < SK_ARRAY_COUNT(gColorTypeBytesPerPixel));
81 return gColorTypeBytesPerPixel[ct];
82}
83
84static size_t ComputeMinRowBytes(const SkImage::Info& info) {
85 return info.fWidth * BytesPerPixel(info.fColorType);
86}
87
88class SkImage_Raster : public SkImage_Base {
89public:
90 static bool ValidArgs(const Info& info, SkColorSpace* cs, size_t rowBytes) {
91 const int maxDimension = SK_MaxS32 >> 2;
92 const size_t kMaxPixelByteSize = SK_MaxS32;
93
94 if (info.fWidth < 0 || info.fHeight < 0) {
95 return false;
96 }
97 if (info.fWidth > maxDimension || info.fHeight > maxDimension) {
98 return false;
99 }
100 if ((unsigned)info.fColorType > (unsigned)kLastEnum_ColorType) {
101 return false;
102 }
103 if ((unsigned)info.fAlphaType > (unsigned)kLastEnum_AlphaType) {
104 return false;
105 }
106
107 bool isOpaque;
108 if (InfoToConfig(info, &isOpaque) == SkBitmap::kNo_Config) {
109 return false;
110 }
111
112 // TODO: check colorspace
113
114 if (rowBytes < ComputeMinRowBytes(info)) {
115 return false;
116 }
117
118 int64_t size = (int64_t)info.fHeight * rowBytes;
119 if (size > kMaxPixelByteSize) {
120 return false;
121 }
122 return true;
123 }
124
125 static SkImage* NewEmpty();
126
127 SkImage_Raster(const SkImage::Info&, SkColorSpace*, SkData*, size_t rb);
128 virtual ~SkImage_Raster();
129
130 virtual const SkBitmap* asABitmap() SK_OVERRIDE;
131
132private:
133 SkImage_Raster() : INHERITED(0, 0) {}
134
135 SkBitmap fBitmap;
136
137 typedef SkImage_Base INHERITED;
138};
139
140///////////////////////////////////////////////////////////////////////////////
141
142#include "SkData.h"
143#include "SkDataPixelRef.h"
144
145SkImage* SkImage_Raster::NewEmpty() {
146 // Returns lazily created singleton
147 static SkImage* gEmpty;
148 if (NULL == gEmpty) {
149 gEmpty = SkNEW(SkImage_Raster);
150 }
151 gEmpty->ref();
152 return gEmpty;
153}
154
155SkImage_Raster::SkImage_Raster(const Info& info, SkColorSpace* cs,
156 SkData* data, size_t rowBytes)
157 : INHERITED(info.fWidth, info.fHeight) {
158 bool isOpaque;
159 SkBitmap::Config config = InfoToConfig(info, &isOpaque);
160
161 fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes);
162 fBitmap.setPixelRef(SkNEW_ARGS(SkDataPixelRef, (data)))->unref();
163 fBitmap.setIsOpaque(isOpaque);
164 fBitmap.setImmutable(); // Yea baby!
165}
166
167SkImage_Raster::~SkImage_Raster() {}
168
169const SkBitmap* SkImage_Raster::asABitmap() {
170 return &fBitmap;
171}
172
173///////////////////////////////////////////////////////////////////////////////
174
175SkImage* SkImage::NewRasterCopy(const SkImage::Info& info, SkColorSpace* cs,
176 const void* pixels, size_t rowBytes) {
177 if (!SkImage_Raster::ValidArgs(info, cs, rowBytes)) {
178 return NULL;
179 }
180 if (0 == info.fWidth && 0 == info.fHeight) {
181 return SkImage_Raster::NewEmpty();
182 }
183 // check this after empty-check
184 if (NULL == pixels) {
185 return NULL;
186 }
187
188 // Here we actually make a copy of the caller's pixel data
189 SkAutoDataUnref data(SkData::NewWithCopy(pixels, info.fHeight * rowBytes));
190 return SkNEW_ARGS(SkImage_Raster, (info, cs, data, rowBytes));
191}
192
193
194SkImage* SkImage::NewRasterData(const SkImage::Info& info, SkColorSpace* cs,
195 SkData* pixelData, size_t rowBytes) {
196 if (!SkImage_Raster::ValidArgs(info, cs, rowBytes)) {
197 return NULL;
198 }
199 if (0 == info.fWidth && 0 == info.fHeight) {
200 return SkImage_Raster::NewEmpty();
201 }
202 // check this after empty-check
203 if (NULL == pixelData) {
204 return NULL;
205 }
206
207 // did they give us enough data?
208 size_t size = info.fHeight * rowBytes;
209 if (pixelData->size() < size) {
210 return NULL;
211 }
212
213 SkAutoDataUnref data(pixelData);
214 return SkNEW_ARGS(SkImage_Raster, (info, cs, data, rowBytes));
215}
216
217///////////////////////////////////////////////////////////////////////////////
218
219#include "SkCanvas.h"
220
221uint32_t SkImage::NextUniqueID() {
222 static int32_t gUniqueID;
223
224 // never return 0;
225 uint32_t id;
226 do {
227 id = sk_atomic_inc(&gUniqueID) + 1;
228 } while (0 == id);
229 return id;
230}
231
232void SkImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
233 const SkPaint* paint) {
234 const SkBitmap* bitmap = asIB(this)->asABitmap();
235 if (bitmap) {
236 canvas->drawBitmap(*bitmap, x, y, paint);
237 }
238}
239