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 "SkDevice.h"
9 #include "SkDraw.h"
10 #include "SkImageFilter.h"
11 #include "SkMetaData.h"
12 #include "SkRect.h"
13
14 ///////////////////////////////////////////////////////////////////////////////
15
SkDevice(const SkBitmap & bitmap)16 SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
17 fOrigin.setZero();
18 fMetaData = NULL;
19 }
20
SkDevice(SkBitmap::Config config,int width,int height,bool isOpaque)21 SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
22 fOrigin.setZero();
23 fMetaData = NULL;
24
25 fBitmap.setConfig(config, width, height);
26 fBitmap.allocPixels();
27 fBitmap.setIsOpaque(isOpaque);
28 if (!isOpaque) {
29 fBitmap.eraseColor(0);
30 }
31 }
32
~SkDevice()33 SkDevice::~SkDevice() {
34 delete fMetaData;
35 }
36
createCompatibleDevice(SkBitmap::Config config,int width,int height,bool isOpaque)37 SkDevice* SkDevice::createCompatibleDevice(SkBitmap::Config config,
38 int width, int height,
39 bool isOpaque) {
40 return this->onCreateCompatibleDevice(config, width, height,
41 isOpaque, kGeneral_Usage);
42 }
43
createCompatibleDeviceForSaveLayer(SkBitmap::Config config,int width,int height,bool isOpaque)44 SkDevice* SkDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config,
45 int width, int height,
46 bool isOpaque) {
47 return this->onCreateCompatibleDevice(config, width, height,
48 isOpaque, kSaveLayer_Usage);
49 }
50
onCreateCompatibleDevice(SkBitmap::Config config,int width,int height,bool isOpaque,Usage usage)51 SkDevice* SkDevice::onCreateCompatibleDevice(SkBitmap::Config config,
52 int width, int height,
53 bool isOpaque,
54 Usage usage) {
55 return SkNEW_ARGS(SkDevice,(config, width, height, isOpaque));
56 }
57
getMetaData()58 SkMetaData& SkDevice::getMetaData() {
59 // metadata users are rare, so we lazily allocate it. If that changes we
60 // can decide to just make it a field in the device (rather than a ptr)
61 if (NULL == fMetaData) {
62 fMetaData = new SkMetaData;
63 }
64 return *fMetaData;
65 }
66
lockPixels()67 void SkDevice::lockPixels() {
68 if (fBitmap.lockPixelsAreWritable()) {
69 fBitmap.lockPixels();
70 }
71 }
72
unlockPixels()73 void SkDevice::unlockPixels() {
74 if (fBitmap.lockPixelsAreWritable()) {
75 fBitmap.unlockPixels();
76 }
77 }
78
accessBitmap(bool changePixels)79 const SkBitmap& SkDevice::accessBitmap(bool changePixels) {
80 const SkBitmap& bitmap = this->onAccessBitmap(&fBitmap);
81 if (changePixels) {
82 bitmap.notifyPixelsChanged();
83 }
84 return bitmap;
85 }
86
getGlobalBounds(SkIRect * bounds) const87 void SkDevice::getGlobalBounds(SkIRect* bounds) const {
88 if (bounds) {
89 bounds->setXYWH(fOrigin.x(), fOrigin.y(),
90 fBitmap.width(), fBitmap.height());
91 }
92 }
93
clear(SkColor color)94 void SkDevice::clear(SkColor color) {
95 fBitmap.eraseColor(color);
96 }
97
onAccessBitmap(SkBitmap * bitmap)98 const SkBitmap& SkDevice::onAccessBitmap(SkBitmap* bitmap) {return *bitmap;}
99
setMatrixClip(const SkMatrix & matrix,const SkRegion & region,const SkClipStack & clipStack)100 void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region,
101 const SkClipStack& clipStack) {
102 }
103
filterImage(SkImageFilter *,const SkBitmap & src,const SkMatrix & ctm,SkBitmap * result,SkIPoint * offset)104 bool SkDevice::filterImage(SkImageFilter*, const SkBitmap& src,
105 const SkMatrix& ctm,
106 SkBitmap* result, SkIPoint* offset) {
107 return false;
108 }
109
allowImageFilter(SkImageFilter *)110 bool SkDevice::allowImageFilter(SkImageFilter*) {
111 return true;
112 }
113
114 ///////////////////////////////////////////////////////////////////////////////
115
readPixels(SkBitmap * bitmap,int x,int y,SkCanvas::Config8888 config8888)116 bool SkDevice::readPixels(SkBitmap* bitmap, int x, int y,
117 SkCanvas::Config8888 config8888) {
118 if (SkBitmap::kARGB_8888_Config != bitmap->config() ||
119 NULL != bitmap->getTexture()) {
120 return false;
121 }
122
123 const SkBitmap& src = this->accessBitmap(false);
124
125 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(),
126 bitmap->height());
127 SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height());
128 if (!srcRect.intersect(devbounds)) {
129 return false;
130 }
131
132 SkBitmap tmp;
133 SkBitmap* bmp;
134 if (bitmap->isNull()) {
135 tmp.setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(),
136 bitmap->height());
137 if (!tmp.allocPixels()) {
138 return false;
139 }
140 bmp = &tmp;
141 } else {
142 bmp = bitmap;
143 }
144
145 SkIRect subrect = srcRect;
146 subrect.offset(-x, -y);
147 SkBitmap bmpSubset;
148 bmp->extractSubset(&bmpSubset, subrect);
149
150 bool result = this->onReadPixels(bmpSubset,
151 srcRect.fLeft,
152 srcRect.fTop,
153 config8888);
154 if (result && bmp == &tmp) {
155 tmp.swap(*bitmap);
156 }
157 return result;
158 }
159
160 #ifdef SK_CPU_LENDIAN
161 #if 24 == SK_A32_SHIFT && 16 == SK_R32_SHIFT && \
162 8 == SK_G32_SHIFT && 0 == SK_B32_SHIFT
163 const SkCanvas::Config8888 SkDevice::kPMColorAlias =
164 SkCanvas::kBGRA_Premul_Config8888;
165 #elif 24 == SK_A32_SHIFT && 0 == SK_R32_SHIFT && \
166 8 == SK_G32_SHIFT && 16 == SK_B32_SHIFT
167 const SkCanvas::Config8888 SkDevice::kPMColorAlias =
168 SkCanvas::kRGBA_Premul_Config8888;
169 #else
170 const SkCanvas::Config8888 SkDevice::kPMColorAlias =
171 (SkCanvas::Config8888) -1;
172 #endif
173 #else
174 #if 0 == SK_A32_SHIFT && 8 == SK_R32_SHIFT && \
175 16 == SK_G32_SHIFT && 24 == SK_B32_SHIFT
176 const SkCanvas::Config8888 SkDevice::kPMColorAlias =
177 SkCanvas::kBGRA_Premul_Config8888;
178 #elif 0 == SK_A32_SHIFT && 24 == SK_R32_SHIFT && \
179 16 == SK_G32_SHIFT && 8 == SK_B32_SHIFT
180 const SkCanvas::Config8888 SkDevice::kPMColorAlias =
181 SkCanvas::kRGBA_Premul_Config8888;
182 #else
183 const SkCanvas::Config8888 SkDevice::kPMColorAlias =
184 (SkCanvas::Config8888) -1;
185 #endif
186 #endif
187
188 #include <SkConfig8888.h>
189
onReadPixels(const SkBitmap & bitmap,int x,int y,SkCanvas::Config8888 config8888)190 bool SkDevice::onReadPixels(const SkBitmap& bitmap,
191 int x, int y,
192 SkCanvas::Config8888 config8888) {
193 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
194 SkASSERT(!bitmap.isNull());
195 SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
196
197 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(),
198 bitmap.height());
199 const SkBitmap& src = this->accessBitmap(false);
200
201 SkBitmap subset;
202 if (!src.extractSubset(&subset, srcRect)) {
203 return false;
204 }
205 if (SkBitmap::kARGB_8888_Config != subset.config()) {
206 // It'd be preferable to do this directly to bitmap.
207 subset.copyTo(&subset, SkBitmap::kARGB_8888_Config);
208 }
209 SkAutoLockPixels alp(bitmap);
210 uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
211 SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset);
212 return true;
213 }
214
writePixels(const SkBitmap & bitmap,int x,int y,SkCanvas::Config8888 config8888)215 void SkDevice::writePixels(const SkBitmap& bitmap,
216 int x, int y,
217 SkCanvas::Config8888 config8888) {
218 if (bitmap.isNull() || bitmap.getTexture()) {
219 return;
220 }
221 const SkBitmap* sprite = &bitmap;
222 // check whether we have to handle a config8888 that doesn't match SkPMColor
223 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
224 SkCanvas::kNative_Premul_Config8888 != config8888 &&
225 kPMColorAlias != config8888) {
226
227 // We're going to have to convert from a config8888 to the native config
228 // First we clip to the device bounds.
229 SkBitmap dstBmp = this->accessBitmap(true);
230 SkIRect spriteRect = SkIRect::MakeXYWH(x, y,
231 bitmap.width(), bitmap.height());
232 SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height());
233 if (!spriteRect.intersect(devRect)) {
234 return;
235 }
236
237 // write directly to the device if it has pixels and is SkPMColor
238 bool drawSprite;
239 if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) {
240 // we can write directly to the dst when doing the conversion
241 dstBmp.extractSubset(&dstBmp, spriteRect);
242 drawSprite = false;
243 } else {
244 // we convert to a temporary bitmap and draw that as a sprite
245 dstBmp.setConfig(SkBitmap::kARGB_8888_Config,
246 spriteRect.width(),
247 spriteRect.height());
248 if (!dstBmp.allocPixels()) {
249 return;
250 }
251 drawSprite = true;
252 }
253
254 // copy pixels to dstBmp and convert from config8888 to native config.
255 SkAutoLockPixels alp(bitmap);
256 uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x,
257 spriteRect.fTop - y);
258 SkCopyConfig8888ToBitmap(dstBmp,
259 srcPixels,
260 bitmap.rowBytes(),
261 config8888);
262
263 if (drawSprite) {
264 // we've clipped the sprite when we made a copy
265 x = spriteRect.fLeft;
266 y = spriteRect.fTop;
267 sprite = &dstBmp;
268 } else {
269 return;
270 }
271 }
272
273 SkPaint paint;
274 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
275 SkCanvas canvas(this);
276 canvas.drawSprite(*sprite, x, y, &paint);
277 }
278
279 ///////////////////////////////////////////////////////////////////////////////
280
drawPaint(const SkDraw & draw,const SkPaint & paint)281 void SkDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
282 draw.drawPaint(paint);
283 }
284
drawPoints(const SkDraw & draw,SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)285 void SkDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
286 const SkPoint pts[], const SkPaint& paint) {
287 draw.drawPoints(mode, count, pts, paint);
288 }
289
drawRect(const SkDraw & draw,const SkRect & r,const SkPaint & paint)290 void SkDevice::drawRect(const SkDraw& draw, const SkRect& r,
291 const SkPaint& paint) {
292 draw.drawRect(r, paint);
293 }
294
drawPath(const SkDraw & draw,const SkPath & path,const SkPaint & paint,const SkMatrix * prePathMatrix,bool pathIsMutable)295 void SkDevice::drawPath(const SkDraw& draw, const SkPath& path,
296 const SkPaint& paint, const SkMatrix* prePathMatrix,
297 bool pathIsMutable) {
298 draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
299 }
300
drawBitmap(const SkDraw & draw,const SkBitmap & bitmap,const SkIRect * srcRect,const SkMatrix & matrix,const SkPaint & paint)301 void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
302 const SkIRect* srcRect,
303 const SkMatrix& matrix, const SkPaint& paint) {
304 SkBitmap tmp; // storage if we need a subset of bitmap
305 const SkBitmap* bitmapPtr = &bitmap;
306
307 if (srcRect) {
308 if (!bitmap.extractSubset(&tmp, *srcRect)) {
309 return; // extraction failed
310 }
311 bitmapPtr = &tmp;
312 }
313 draw.drawBitmap(*bitmapPtr, matrix, paint);
314 }
315
drawSprite(const SkDraw & draw,const SkBitmap & bitmap,int x,int y,const SkPaint & paint)316 void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
317 int x, int y, const SkPaint& paint) {
318 draw.drawSprite(bitmap, x, y, paint);
319 }
320
drawText(const SkDraw & draw,const void * text,size_t len,SkScalar x,SkScalar y,const SkPaint & paint)321 void SkDevice::drawText(const SkDraw& draw, const void* text, size_t len,
322 SkScalar x, SkScalar y, const SkPaint& paint) {
323 draw.drawText((const char*)text, len, x, y, paint);
324 }
325
drawPosText(const SkDraw & draw,const void * text,size_t len,const SkScalar xpos[],SkScalar y,int scalarsPerPos,const SkPaint & paint)326 void SkDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
327 const SkScalar xpos[], SkScalar y,
328 int scalarsPerPos, const SkPaint& paint) {
329 draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
330 }
331
drawTextOnPath(const SkDraw & draw,const void * text,size_t len,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)332 void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text,
333 size_t len, const SkPath& path,
334 const SkMatrix* matrix,
335 const SkPaint& paint) {
336 draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
337 }
338
339 #ifdef SK_BUILD_FOR_ANDROID
drawPosTextOnPath(const SkDraw & draw,const void * text,size_t len,const SkPoint pos[],const SkPaint & paint,const SkPath & path,const SkMatrix * matrix)340 void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
341 const SkPoint pos[], const SkPaint& paint,
342 const SkPath& path, const SkMatrix* matrix) {
343 draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix);
344 }
345 #endif
346
drawVertices(const SkDraw & draw,SkCanvas::VertexMode vmode,int vertexCount,const SkPoint verts[],const SkPoint textures[],const SkColor colors[],SkXfermode * xmode,const uint16_t indices[],int indexCount,const SkPaint & paint)347 void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
348 int vertexCount,
349 const SkPoint verts[], const SkPoint textures[],
350 const SkColor colors[], SkXfermode* xmode,
351 const uint16_t indices[], int indexCount,
352 const SkPaint& paint) {
353 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
354 indices, indexCount, paint);
355 }
356
drawDevice(const SkDraw & draw,SkDevice * device,int x,int y,const SkPaint & paint)357 void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device,
358 int x, int y, const SkPaint& paint) {
359 const SkBitmap& src = device->accessBitmap(false);
360 draw.drawSprite(src, x, y, paint);
361 }
362
363 ///////////////////////////////////////////////////////////////////////////////
364
filterTextFlags(const SkPaint & paint,TextFlags * flags)365 bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
366 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
367 // we're cool with the paint as is
368 return false;
369 }
370
371 if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
372 paint.getRasterizer() ||
373 paint.getPathEffect() ||
374 paint.isFakeBoldText() ||
375 paint.getStyle() != SkPaint::kFill_Style ||
376 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
377 // turn off lcd
378 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
379 flags->fHinting = paint.getHinting();
380 return true;
381 }
382 // we're cool with the paint as is
383 return false;
384 }
385
386