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