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