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 "SkDeviceProperties.h"
11 #include "SkDraw.h"
12 #include "SkRasterClip.h"
13 #include "SkShader.h"
14 #include "SkSurface.h"
15 
16 #define CHECK_FOR_ANNOTATION(paint) \
17     do { if (paint.getAnnotation()) { return; } } while (0)
18 
valid_for_bitmap_device(const SkImageInfo & info,SkAlphaType * newAlphaType)19 static bool valid_for_bitmap_device(const SkImageInfo& info,
20                                     SkAlphaType* newAlphaType) {
21     if (info.width() < 0 || info.height() < 0) {
22         return false;
23     }
24 
25     // TODO: can we stop supporting kUnknown in SkBitmkapDevice?
26     if (kUnknown_SkColorType == info.colorType()) {
27         if (newAlphaType) {
28             *newAlphaType = kUnknown_SkAlphaType;
29         }
30         return true;
31     }
32 
33     switch (info.alphaType()) {
34         case kPremul_SkAlphaType:
35         case kOpaque_SkAlphaType:
36             break;
37         default:
38             return false;
39     }
40 
41     SkAlphaType canonicalAlphaType = info.alphaType();
42 
43     switch (info.colorType()) {
44         case kAlpha_8_SkColorType:
45             break;
46         case kRGB_565_SkColorType:
47             canonicalAlphaType = kOpaque_SkAlphaType;
48             break;
49         case kN32_SkColorType:
50             break;
51         default:
52             return false;
53     }
54 
55     if (newAlphaType) {
56         *newAlphaType = canonicalAlphaType;
57     }
58     return true;
59 }
60 
SkBitmapDevice(const SkBitmap & bitmap)61 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
62     SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
63 }
64 
SkBitmapDevice(const SkBitmap & bitmap,const SkDeviceProperties & deviceProperties)65 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties)
66     : SkBaseDevice(deviceProperties)
67     , fBitmap(bitmap)
68 {
69     SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
70 }
71 
Create(const SkImageInfo & origInfo,const SkDeviceProperties * props)72 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
73                                        const SkDeviceProperties* props) {
74     SkAlphaType newAT = origInfo.alphaType();
75     if (!valid_for_bitmap_device(origInfo, &newAT)) {
76         return NULL;
77     }
78 
79     const SkImageInfo info = origInfo.makeAlphaType(newAT);
80     SkBitmap bitmap;
81 
82     if (kUnknown_SkColorType == info.colorType()) {
83         if (!bitmap.setInfo(info)) {
84             return NULL;
85         }
86     } else {
87         if (!bitmap.tryAllocPixels(info)) {
88             return NULL;
89         }
90         if (!bitmap.info().isOpaque()) {
91             bitmap.eraseColor(SK_ColorTRANSPARENT);
92         }
93     }
94 
95     if (props) {
96         return SkNEW_ARGS(SkBitmapDevice, (bitmap, *props));
97     } else {
98         return SkNEW_ARGS(SkBitmapDevice, (bitmap));
99     }
100 }
101 
imageInfo() const102 SkImageInfo SkBitmapDevice::imageInfo() const {
103     return fBitmap.info();
104 }
105 
setNewSize(const SkISize & size)106 void SkBitmapDevice::setNewSize(const SkISize& size) {
107     SkASSERT(!fBitmap.pixelRef());
108     fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight));
109 }
110 
replaceBitmapBackendForRasterSurface(const SkBitmap & bm)111 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
112     SkASSERT(bm.width() == fBitmap.width());
113     SkASSERT(bm.height() == fBitmap.height());
114     fBitmap = bm;   // intent is to use bm's pixelRef (and rowbytes/config)
115     fBitmap.lockPixels();
116 }
117 
onCreateDevice(const CreateInfo & cinfo,const SkPaint *)118 SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
119     SkDeviceProperties leaky(cinfo.fPixelGeometry);
120     return SkBitmapDevice::Create(cinfo.fInfo, &leaky);
121 }
122 
lockPixels()123 void SkBitmapDevice::lockPixels() {
124     if (fBitmap.lockPixelsAreWritable()) {
125         fBitmap.lockPixels();
126     }
127 }
128 
unlockPixels()129 void SkBitmapDevice::unlockPixels() {
130     if (fBitmap.lockPixelsAreWritable()) {
131         fBitmap.unlockPixels();
132     }
133 }
134 
onAccessBitmap()135 const SkBitmap& SkBitmapDevice::onAccessBitmap() {
136     return fBitmap;
137 }
138 
onAccessPixels(SkImageInfo * info,size_t * rowBytes)139 void* SkBitmapDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) {
140     if (fBitmap.getPixels()) {
141         *info = fBitmap.info();
142         *rowBytes = fBitmap.rowBytes();
143         return fBitmap.getPixels();
144     }
145     return NULL;
146 }
147 
148 #include "SkConfig8888.h"
149 #include "SkPixelRef.h"
150 
onWritePixels(const SkImageInfo & srcInfo,const void * srcPixels,size_t srcRowBytes,int x,int y)151 bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
152                                    size_t srcRowBytes, int x, int y) {
153     // since we don't stop creating un-pixeled devices yet, check for no pixels here
154     if (NULL == fBitmap.getPixels()) {
155         return false;
156     }
157 
158     const SkImageInfo dstInfo = fBitmap.info().makeWH(srcInfo.width(), srcInfo.height());
159 
160     void* dstPixels = fBitmap.getAddr(x, y);
161     size_t dstRowBytes = fBitmap.rowBytes();
162 
163     if (SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
164         fBitmap.notifyPixelsChanged();
165         return true;
166     }
167     return false;
168 }
169 
onReadPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int x,int y)170 bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
171                                   int x, int y) {
172     return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y);
173 }
174 
175 ///////////////////////////////////////////////////////////////////////////////
176 
drawPaint(const SkDraw & draw,const SkPaint & paint)177 void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
178     draw.drawPaint(paint);
179 }
180 
drawPoints(const SkDraw & draw,SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)181 void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
182                                 const SkPoint pts[], const SkPaint& paint) {
183     CHECK_FOR_ANNOTATION(paint);
184     draw.drawPoints(mode, count, pts, paint);
185 }
186 
drawRect(const SkDraw & draw,const SkRect & r,const SkPaint & paint)187 void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
188     CHECK_FOR_ANNOTATION(paint);
189     draw.drawRect(r, paint);
190 }
191 
drawOval(const SkDraw & draw,const SkRect & oval,const SkPaint & paint)192 void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
193     CHECK_FOR_ANNOTATION(paint);
194 
195     SkPath path;
196     path.addOval(oval);
197     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
198     // required to override drawOval.
199     this->drawPath(draw, path, paint, NULL, true);
200 }
201 
drawRRect(const SkDraw & draw,const SkRRect & rrect,const SkPaint & paint)202 void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
203     CHECK_FOR_ANNOTATION(paint);
204 
205 #ifdef SK_IGNORE_BLURRED_RRECT_OPT
206     SkPath  path;
207 
208     path.addRRect(rrect);
209     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
210     // required to override drawRRect.
211     this->drawPath(draw, path, paint, NULL, true);
212 #else
213     draw.drawRRect(rrect, paint);
214 #endif
215 }
216 
drawPath(const SkDraw & draw,const SkPath & path,const SkPaint & paint,const SkMatrix * prePathMatrix,bool pathIsMutable)217 void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
218                               const SkPaint& paint, const SkMatrix* prePathMatrix,
219                               bool pathIsMutable) {
220     CHECK_FOR_ANNOTATION(paint);
221     draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
222 }
223 
drawBitmap(const SkDraw & draw,const SkBitmap & bitmap,const SkMatrix & matrix,const SkPaint & paint)224 void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
225                                 const SkMatrix& matrix, const SkPaint& paint) {
226     draw.drawBitmap(bitmap, matrix, NULL, paint);
227 }
228 
drawBitmapRect(const SkDraw & draw,const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint & paint,SkCanvas::DrawBitmapRectFlags flags)229 void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
230                                     const SkRect* src, const SkRect& dst,
231                                     const SkPaint& paint,
232                                     SkCanvas::DrawBitmapRectFlags flags) {
233     SkMatrix    matrix;
234     SkRect      bitmapBounds, tmpSrc, tmpDst;
235     SkBitmap    tmpBitmap;
236 
237     bitmapBounds.isetWH(bitmap.width(), bitmap.height());
238 
239     // Compute matrix from the two rectangles
240     if (src) {
241         tmpSrc = *src;
242     } else {
243         tmpSrc = bitmapBounds;
244     }
245     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
246 
247     const SkRect* dstPtr = &dst;
248     const SkBitmap* bitmapPtr = &bitmap;
249 
250     // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
251     // needed (if the src was clipped). No check needed if src==null.
252     if (src) {
253         if (!bitmapBounds.contains(*src)) {
254             if (!tmpSrc.intersect(bitmapBounds)) {
255                 return; // nothing to draw
256             }
257             // recompute dst, based on the smaller tmpSrc
258             matrix.mapRect(&tmpDst, tmpSrc);
259             dstPtr = &tmpDst;
260         }
261 
262         // since we may need to clamp to the borders of the src rect within
263         // the bitmap, we extract a subset.
264         const SkIRect srcIR = tmpSrc.roundOut();
265         if(bitmap.pixelRef()->getTexture()) {
266             // Accelerated source canvas, don't use extractSubset but readPixels to get the subset.
267             // This way, the pixels are copied in CPU memory instead of GPU memory.
268             bitmap.pixelRef()->readPixels(&tmpBitmap, &srcIR);
269         } else {
270             if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
271                 return;
272             }
273         }
274         bitmapPtr = &tmpBitmap;
275 
276         // Since we did an extract, we need to adjust the matrix accordingly
277         SkScalar dx = 0, dy = 0;
278         if (srcIR.fLeft > 0) {
279             dx = SkIntToScalar(srcIR.fLeft);
280         }
281         if (srcIR.fTop > 0) {
282             dy = SkIntToScalar(srcIR.fTop);
283         }
284         if (dx || dy) {
285             matrix.preTranslate(dx, dy);
286         }
287 
288         SkRect extractedBitmapBounds;
289         extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
290         if (extractedBitmapBounds == tmpSrc) {
291             // no fractional part in src, we can just call drawBitmap
292             goto USE_DRAWBITMAP;
293         }
294     } else {
295         USE_DRAWBITMAP:
296         // We can go faster by just calling drawBitmap, which will concat the
297         // matrix with the CTM, and try to call drawSprite if it can. If not,
298         // it will make a shader and call drawRect, as we do below.
299         draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
300         return;
301     }
302 
303     // construct a shader, so we can call drawRect with the dst
304     SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
305                                                SkShader::kClamp_TileMode,
306                                                SkShader::kClamp_TileMode,
307                                                &matrix);
308     if (NULL == s) {
309         return;
310     }
311 
312     SkPaint paintWithShader(paint);
313     paintWithShader.setStyle(SkPaint::kFill_Style);
314     paintWithShader.setShader(s)->unref();
315 
316     // Call ourself, in case the subclass wanted to share this setup code
317     // but handle the drawRect code themselves.
318     this->drawRect(draw, *dstPtr, paintWithShader);
319 }
320 
drawSprite(const SkDraw & draw,const SkBitmap & bitmap,int x,int y,const SkPaint & paint)321 void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
322                                 int x, int y, const SkPaint& paint) {
323     draw.drawSprite(bitmap, x, y, paint);
324 }
325 
drawText(const SkDraw & draw,const void * text,size_t len,SkScalar x,SkScalar y,const SkPaint & paint)326 void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
327                               SkScalar x, SkScalar y, const SkPaint& paint) {
328     draw.drawText((const char*)text, len, x, y, paint);
329 }
330 
drawPosText(const SkDraw & draw,const void * text,size_t len,const SkScalar xpos[],int scalarsPerPos,const SkPoint & offset,const SkPaint & paint)331 void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
332                                  const SkScalar xpos[], int scalarsPerPos,
333                                  const SkPoint& offset, const SkPaint& paint) {
334     draw.drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint);
335 }
336 
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)337 void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
338                                   int vertexCount,
339                                   const SkPoint verts[], const SkPoint textures[],
340                                   const SkColor colors[], SkXfermode* xmode,
341                                   const uint16_t indices[], int indexCount,
342                                   const SkPaint& paint) {
343     draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
344                       indices, indexCount, paint);
345 }
346 
drawDevice(const SkDraw & draw,SkBaseDevice * device,int x,int y,const SkPaint & paint)347 void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
348                                 int x, int y, const SkPaint& paint) {
349     const SkBitmap& src = device->accessBitmap(false);
350     draw.drawSprite(src, x, y, paint);
351 }
352 
newSurface(const SkImageInfo & info,const SkSurfaceProps & props)353 SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
354     return SkSurface::NewRaster(info, &props);
355 }
356 
peekPixels(SkImageInfo * info,size_t * rowBytes)357 const void* SkBitmapDevice::peekPixels(SkImageInfo* info, size_t* rowBytes) {
358     const SkImageInfo bmInfo = fBitmap.info();
359     if (fBitmap.getPixels() && (kUnknown_SkColorType != bmInfo.colorType())) {
360         if (info) {
361             *info = bmInfo;
362         }
363         if (rowBytes) {
364             *rowBytes = fBitmap.rowBytes();
365         }
366         return fBitmap.getPixels();
367     }
368     return NULL;
369 }
370 
getImageFilterCache()371 SkImageFilter::Cache* SkBitmapDevice::getImageFilterCache() {
372     SkImageFilter::Cache* cache = SkImageFilter::Cache::Get();
373     cache->ref();
374     return cache;
375 }
376 
377 ///////////////////////////////////////////////////////////////////////////////
378 
onShouldDisableLCD(const SkPaint & paint) const379 bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const {
380     if (kN32_SkColorType != fBitmap.colorType() ||
381         paint.getRasterizer() ||
382         paint.getPathEffect() ||
383         paint.isFakeBoldText() ||
384         paint.getStyle() != SkPaint::kFill_Style ||
385         !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode))
386     {
387         return true;
388     }
389     return false;
390 }
391