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