• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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