1 /*
2 * Copyright 2013 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 "SkBitmapDevice.h"
9 #include "SkConfig8888.h"
10 #include "SkDraw.h"
11 #include "SkRasterClip.h"
12 #include "SkShader.h"
13 #include "SkSurface.h"
14
15 #define CHECK_FOR_ANNOTATION(paint) \
16 do { if (paint.getAnnotation()) { return; } } while (0)
17
valid_for_bitmap_device(const SkImageInfo & info,SkAlphaType * newAlphaType)18 static bool valid_for_bitmap_device(const SkImageInfo& info,
19 SkAlphaType* newAlphaType) {
20 if (info.width() < 0 || info.height() < 0) {
21 return false;
22 }
23
24 // TODO: can we stop supporting kUnknown in SkBitmkapDevice?
25 if (kUnknown_SkColorType == info.colorType()) {
26 if (newAlphaType) {
27 *newAlphaType = kIgnore_SkAlphaType;
28 }
29 return true;
30 }
31
32 switch (info.alphaType()) {
33 case kPremul_SkAlphaType:
34 case kOpaque_SkAlphaType:
35 break;
36 default:
37 return false;
38 }
39
40 SkAlphaType canonicalAlphaType = info.alphaType();
41
42 switch (info.colorType()) {
43 case kAlpha_8_SkColorType:
44 break;
45 case kRGB_565_SkColorType:
46 canonicalAlphaType = kOpaque_SkAlphaType;
47 break;
48 case kN32_SkColorType:
49 break;
50 default:
51 return false;
52 }
53
54 if (newAlphaType) {
55 *newAlphaType = canonicalAlphaType;
56 }
57 return true;
58 }
59
SkBitmapDevice(const SkBitmap & bitmap)60 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
61 SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
62 }
63
SkBitmapDevice(const SkBitmap & bitmap,const SkDeviceProperties & deviceProperties)64 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties)
65 : SkBaseDevice(deviceProperties)
66 , fBitmap(bitmap)
67 {
68 SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
69 }
70
Create(const SkImageInfo & origInfo,const SkDeviceProperties * props)71 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
72 const SkDeviceProperties* props) {
73 SkImageInfo info = origInfo;
74 if (!valid_for_bitmap_device(info, &info.fAlphaType)) {
75 return NULL;
76 }
77
78 SkBitmap bitmap;
79
80 if (kUnknown_SkColorType == info.colorType()) {
81 if (!bitmap.setInfo(info)) {
82 return NULL;
83 }
84 } else {
85 if (!bitmap.allocPixels(info)) {
86 return NULL;
87 }
88 if (!bitmap.info().isOpaque()) {
89 bitmap.eraseColor(SK_ColorTRANSPARENT);
90 }
91 }
92
93 if (props) {
94 return SkNEW_ARGS(SkBitmapDevice, (bitmap, *props));
95 } else {
96 return SkNEW_ARGS(SkBitmapDevice, (bitmap));
97 }
98 }
99
imageInfo() const100 SkImageInfo SkBitmapDevice::imageInfo() const {
101 return fBitmap.info();
102 }
103
replaceBitmapBackendForRasterSurface(const SkBitmap & bm)104 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
105 SkASSERT(bm.width() == fBitmap.width());
106 SkASSERT(bm.height() == fBitmap.height());
107 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config)
108 fBitmap.lockPixels();
109 }
110
onCreateDevice(const SkImageInfo & info,Usage usage)111 SkBaseDevice* SkBitmapDevice::onCreateDevice(const SkImageInfo& info, Usage usage) {
112 return SkBitmapDevice::Create(info, &this->getDeviceProperties());
113 }
114
lockPixels()115 void SkBitmapDevice::lockPixels() {
116 if (fBitmap.lockPixelsAreWritable()) {
117 fBitmap.lockPixels();
118 }
119 }
120
unlockPixels()121 void SkBitmapDevice::unlockPixels() {
122 if (fBitmap.lockPixelsAreWritable()) {
123 fBitmap.unlockPixels();
124 }
125 }
126
clear(SkColor color)127 void SkBitmapDevice::clear(SkColor color) {
128 fBitmap.eraseColor(color);
129 }
130
onAccessBitmap()131 const SkBitmap& SkBitmapDevice::onAccessBitmap() {
132 return fBitmap;
133 }
134
canHandleImageFilter(const SkImageFilter *)135 bool SkBitmapDevice::canHandleImageFilter(const SkImageFilter*) {
136 return false;
137 }
138
filterImage(const SkImageFilter * filter,const SkBitmap & src,const SkImageFilter::Context & ctx,SkBitmap * result,SkIPoint * offset)139 bool SkBitmapDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src,
140 const SkImageFilter::Context& ctx, SkBitmap* result,
141 SkIPoint* offset) {
142 return false;
143 }
144
allowImageFilter(const SkImageFilter *)145 bool SkBitmapDevice::allowImageFilter(const SkImageFilter*) {
146 return true;
147 }
148
onAccessPixels(SkImageInfo * info,size_t * rowBytes)149 void* SkBitmapDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) {
150 if (fBitmap.getPixels()) {
151 *info = fBitmap.info();
152 *rowBytes = fBitmap.rowBytes();
153 return fBitmap.getPixels();
154 }
155 return NULL;
156 }
157
rect_memcpy(void * dst,size_t dstRB,const void * src,size_t srcRB,size_t bytesPerRow,int rowCount)158 static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, size_t bytesPerRow,
159 int rowCount) {
160 SkASSERT(bytesPerRow <= srcRB);
161 SkASSERT(bytesPerRow <= dstRB);
162 for (int i = 0; i < rowCount; ++i) {
163 memcpy(dst, src, bytesPerRow);
164 dst = (char*)dst + dstRB;
165 src = (const char*)src + srcRB;
166 }
167 }
168
169 #include "SkConfig8888.h"
170
copy_pixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,const SkImageInfo & srcInfo,const void * srcPixels,size_t srcRowBytes)171 static bool copy_pixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
172 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes) {
173 if (srcInfo.dimensions() != dstInfo.dimensions()) {
174 return false;
175 }
176 if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel()) {
177 SkDstPixelInfo dstPI;
178 dstPI.fColorType = dstInfo.colorType();
179 dstPI.fAlphaType = dstInfo.alphaType();
180 dstPI.fPixels = dstPixels;
181 dstPI.fRowBytes = dstRowBytes;
182
183 SkSrcPixelInfo srcPI;
184 srcPI.fColorType = srcInfo.colorType();
185 srcPI.fAlphaType = srcInfo.alphaType();
186 srcPI.fPixels = srcPixels;
187 srcPI.fRowBytes = srcRowBytes;
188
189 return srcPI.convertPixelsTo(&dstPI, srcInfo.width(), srcInfo.height());
190 }
191 if (srcInfo.colorType() == dstInfo.colorType()) {
192 switch (srcInfo.colorType()) {
193 case kRGB_565_SkColorType:
194 case kAlpha_8_SkColorType:
195 break;
196 case kARGB_4444_SkColorType:
197 if (srcInfo.alphaType() != dstInfo.alphaType()) {
198 return false;
199 }
200 break;
201 default:
202 return false;
203 }
204 rect_memcpy(dstPixels, dstRowBytes, srcPixels, srcRowBytes,
205 srcInfo.width() * srcInfo.bytesPerPixel(), srcInfo.height());
206 }
207 // TODO: add support for more conversions as needed
208 return false;
209 }
210
onWritePixels(const SkImageInfo & srcInfo,const void * srcPixels,size_t srcRowBytes,int x,int y)211 bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
212 size_t srcRowBytes, int x, int y) {
213 // since we don't stop creating un-pixeled devices yet, check for no pixels here
214 if (NULL == fBitmap.getPixels()) {
215 return false;
216 }
217
218 SkImageInfo dstInfo = fBitmap.info();
219 dstInfo.fWidth = srcInfo.width();
220 dstInfo.fHeight = srcInfo.height();
221
222 void* dstPixels = fBitmap.getAddr(x, y);
223 size_t dstRowBytes = fBitmap.rowBytes();
224
225 if (copy_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
226 fBitmap.notifyPixelsChanged();
227 return true;
228 }
229 return false;
230 }
231
onReadPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int x,int y)232 bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
233 int x, int y) {
234 // since we don't stop creating un-pixeled devices yet, check for no pixels here
235 if (NULL == fBitmap.getPixels()) {
236 return false;
237 }
238
239 SkImageInfo srcInfo = fBitmap.info();
240
241 // perhaps can relax these in the future
242 if (4 != dstInfo.bytesPerPixel()) {
243 return false;
244 }
245 if (4 != srcInfo.bytesPerPixel()) {
246 return false;
247 }
248
249 srcInfo.fWidth = dstInfo.width();
250 srcInfo.fHeight = dstInfo.height();
251
252 const void* srcPixels = fBitmap.getAddr(x, y);
253 const size_t srcRowBytes = fBitmap.rowBytes();
254
255 return copy_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes);
256 }
257
258 ///////////////////////////////////////////////////////////////////////////////
259
drawPaint(const SkDraw & draw,const SkPaint & paint)260 void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
261 draw.drawPaint(paint);
262 }
263
drawPoints(const SkDraw & draw,SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)264 void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
265 const SkPoint pts[], const SkPaint& paint) {
266 CHECK_FOR_ANNOTATION(paint);
267 draw.drawPoints(mode, count, pts, paint);
268 }
269
drawRect(const SkDraw & draw,const SkRect & r,const SkPaint & paint)270 void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
271 CHECK_FOR_ANNOTATION(paint);
272 draw.drawRect(r, paint);
273 }
274
drawOval(const SkDraw & draw,const SkRect & oval,const SkPaint & paint)275 void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
276 CHECK_FOR_ANNOTATION(paint);
277
278 SkPath path;
279 path.addOval(oval);
280 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
281 // required to override drawOval.
282 this->drawPath(draw, path, paint, NULL, true);
283 }
284
drawRRect(const SkDraw & draw,const SkRRect & rrect,const SkPaint & paint)285 void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
286 CHECK_FOR_ANNOTATION(paint);
287
288 #ifdef SK_IGNORE_BLURRED_RRECT_OPT
289 SkPath path;
290
291 path.addRRect(rrect);
292 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
293 // required to override drawRRect.
294 this->drawPath(draw, path, paint, NULL, true);
295 #else
296 draw.drawRRect(rrect, paint);
297 #endif
298 }
299
drawPath(const SkDraw & draw,const SkPath & path,const SkPaint & paint,const SkMatrix * prePathMatrix,bool pathIsMutable)300 void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
301 const SkPaint& paint, const SkMatrix* prePathMatrix,
302 bool pathIsMutable) {
303 CHECK_FOR_ANNOTATION(paint);
304 draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
305 }
306
drawBitmap(const SkDraw & draw,const SkBitmap & bitmap,const SkMatrix & matrix,const SkPaint & paint)307 void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
308 const SkMatrix& matrix, const SkPaint& paint) {
309 draw.drawBitmap(bitmap, matrix, paint);
310 }
311
drawBitmapRect(const SkDraw & draw,const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint & paint,SkCanvas::DrawBitmapRectFlags flags)312 void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
313 const SkRect* src, const SkRect& dst,
314 const SkPaint& paint,
315 SkCanvas::DrawBitmapRectFlags flags) {
316 SkMatrix matrix;
317 SkRect bitmapBounds, tmpSrc, tmpDst;
318 SkBitmap tmpBitmap;
319
320 bitmapBounds.isetWH(bitmap.width(), bitmap.height());
321
322 // Compute matrix from the two rectangles
323 if (src) {
324 tmpSrc = *src;
325 } else {
326 tmpSrc = bitmapBounds;
327 }
328 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
329
330 const SkRect* dstPtr = &dst;
331 const SkBitmap* bitmapPtr = &bitmap;
332
333 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
334 // needed (if the src was clipped). No check needed if src==null.
335 if (src) {
336 if (!bitmapBounds.contains(*src)) {
337 if (!tmpSrc.intersect(bitmapBounds)) {
338 return; // nothing to draw
339 }
340 // recompute dst, based on the smaller tmpSrc
341 matrix.mapRect(&tmpDst, tmpSrc);
342 dstPtr = &tmpDst;
343 }
344
345 // since we may need to clamp to the borders of the src rect within
346 // the bitmap, we extract a subset.
347 SkIRect srcIR;
348 tmpSrc.roundOut(&srcIR);
349 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
350 return;
351 }
352 bitmapPtr = &tmpBitmap;
353
354 // Since we did an extract, we need to adjust the matrix accordingly
355 SkScalar dx = 0, dy = 0;
356 if (srcIR.fLeft > 0) {
357 dx = SkIntToScalar(srcIR.fLeft);
358 }
359 if (srcIR.fTop > 0) {
360 dy = SkIntToScalar(srcIR.fTop);
361 }
362 if (dx || dy) {
363 matrix.preTranslate(dx, dy);
364 }
365
366 SkRect extractedBitmapBounds;
367 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
368 if (extractedBitmapBounds == tmpSrc) {
369 // no fractional part in src, we can just call drawBitmap
370 goto USE_DRAWBITMAP;
371 }
372 } else {
373 USE_DRAWBITMAP:
374 // We can go faster by just calling drawBitmap, which will concat the
375 // matrix with the CTM, and try to call drawSprite if it can. If not,
376 // it will make a shader and call drawRect, as we do below.
377 this->drawBitmap(draw, *bitmapPtr, matrix, paint);
378 return;
379 }
380
381 // construct a shader, so we can call drawRect with the dst
382 SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
383 SkShader::kClamp_TileMode,
384 SkShader::kClamp_TileMode,
385 &matrix);
386 if (NULL == s) {
387 return;
388 }
389
390 SkPaint paintWithShader(paint);
391 paintWithShader.setStyle(SkPaint::kFill_Style);
392 paintWithShader.setShader(s)->unref();
393
394 // Call ourself, in case the subclass wanted to share this setup code
395 // but handle the drawRect code themselves.
396 this->drawRect(draw, *dstPtr, paintWithShader);
397 }
398
drawSprite(const SkDraw & draw,const SkBitmap & bitmap,int x,int y,const SkPaint & paint)399 void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
400 int x, int y, const SkPaint& paint) {
401 draw.drawSprite(bitmap, x, y, paint);
402 }
403
drawText(const SkDraw & draw,const void * text,size_t len,SkScalar x,SkScalar y,const SkPaint & paint)404 void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
405 SkScalar x, SkScalar y, const SkPaint& paint) {
406 draw.drawText((const char*)text, len, x, y, paint);
407 }
408
drawPosText(const SkDraw & draw,const void * text,size_t len,const SkScalar xpos[],SkScalar y,int scalarsPerPos,const SkPaint & paint)409 void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
410 const SkScalar xpos[], SkScalar y,
411 int scalarsPerPos, const SkPaint& paint) {
412 draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
413 }
414
drawTextOnPath(const SkDraw & draw,const void * text,size_t len,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)415 void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text,
416 size_t len, const SkPath& path,
417 const SkMatrix* matrix,
418 const SkPaint& paint) {
419 draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
420 }
421
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)422 void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
423 int vertexCount,
424 const SkPoint verts[], const SkPoint textures[],
425 const SkColor colors[], SkXfermode* xmode,
426 const uint16_t indices[], int indexCount,
427 const SkPaint& paint) {
428 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
429 indices, indexCount, paint);
430 }
431
drawDevice(const SkDraw & draw,SkBaseDevice * device,int x,int y,const SkPaint & paint)432 void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
433 int x, int y, const SkPaint& paint) {
434 const SkBitmap& src = device->accessBitmap(false);
435 draw.drawSprite(src, x, y, paint);
436 }
437
newSurface(const SkImageInfo & info)438 SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info) {
439 return SkSurface::NewRaster(info);
440 }
441
peekPixels(SkImageInfo * info,size_t * rowBytes)442 const void* SkBitmapDevice::peekPixels(SkImageInfo* info, size_t* rowBytes) {
443 const SkImageInfo bmInfo = fBitmap.info();
444 if (fBitmap.getPixels() && (kUnknown_SkColorType != bmInfo.colorType())) {
445 if (info) {
446 *info = bmInfo;
447 }
448 if (rowBytes) {
449 *rowBytes = fBitmap.rowBytes();
450 }
451 return fBitmap.getPixels();
452 }
453 return NULL;
454 }
455
456 ///////////////////////////////////////////////////////////////////////////////
457
filterTextFlags(const SkPaint & paint,TextFlags * flags)458 bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
459 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
460 // we're cool with the paint as is
461 return false;
462 }
463
464 if (kN32_SkColorType != fBitmap.colorType() ||
465 paint.getRasterizer() ||
466 paint.getPathEffect() ||
467 paint.isFakeBoldText() ||
468 paint.getStyle() != SkPaint::kFill_Style ||
469 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
470 // turn off lcd
471 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
472 flags->fHinting = paint.getHinting();
473 return true;
474 }
475 // we're cool with the paint as is
476 return false;
477 }
478