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
64 #if 0
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 #endif
72
Create(const SkImageInfo & origInfo,const SkDeviceProperties * props)73 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
74 const SkDeviceProperties* props) {
75 SkAlphaType newAT = origInfo.alphaType();
76 if (!valid_for_bitmap_device(origInfo, &newAT)) {
77 return NULL;
78 }
79
80 const SkImageInfo info = origInfo.makeAlphaType(newAT);
81 SkBitmap bitmap;
82
83 if (kUnknown_SkColorType == info.colorType()) {
84 if (!bitmap.setInfo(info)) {
85 return NULL;
86 }
87 } else {
88 if (!bitmap.tryAllocPixels(info)) {
89 return NULL;
90 }
91 if (!bitmap.info().isOpaque()) {
92 bitmap.eraseColor(SK_ColorTRANSPARENT);
93 }
94 }
95
96 if (props && false) {
97 // return SkNEW_ARGS(SkBitmapDevice, (bitmap, *props));
98 } else {
99 return SkNEW_ARGS(SkBitmapDevice, (bitmap));
100 }
101 }
102
imageInfo() const103 SkImageInfo SkBitmapDevice::imageInfo() const {
104 return fBitmap.info();
105 }
106
replaceBitmapBackendForRasterSurface(const SkBitmap & bm)107 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
108 SkASSERT(bm.width() == fBitmap.width());
109 SkASSERT(bm.height() == fBitmap.height());
110 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config)
111 fBitmap.lockPixels();
112 }
113
onCreateDevice(const SkImageInfo & info,Usage usage)114 SkBaseDevice* SkBitmapDevice::onCreateDevice(const SkImageInfo& info, Usage usage) {
115 return SkBitmapDevice::Create(info);// &this->getDeviceProperties());
116 }
117
lockPixels()118 void SkBitmapDevice::lockPixels() {
119 if (fBitmap.lockPixelsAreWritable()) {
120 fBitmap.lockPixels();
121 }
122 }
123
unlockPixels()124 void SkBitmapDevice::unlockPixels() {
125 if (fBitmap.lockPixelsAreWritable()) {
126 fBitmap.unlockPixels();
127 }
128 }
129
clear(SkColor color)130 void SkBitmapDevice::clear(SkColor color) {
131 fBitmap.eraseColor(color);
132 }
133
onAccessBitmap()134 const SkBitmap& SkBitmapDevice::onAccessBitmap() {
135 return fBitmap;
136 }
137
onAccessPixels(SkImageInfo * info,size_t * rowBytes)138 void* SkBitmapDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) {
139 if (fBitmap.getPixels()) {
140 *info = fBitmap.info();
141 *rowBytes = fBitmap.rowBytes();
142 return fBitmap.getPixels();
143 }
144 return NULL;
145 }
146
147 #include "SkConfig8888.h"
148 #include "SkPixelRef.h"
149
onWritePixels(const SkImageInfo & srcInfo,const void * srcPixels,size_t srcRowBytes,int x,int y)150 bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
151 size_t srcRowBytes, int x, int y) {
152 // since we don't stop creating un-pixeled devices yet, check for no pixels here
153 if (NULL == fBitmap.getPixels()) {
154 return false;
155 }
156
157 const SkImageInfo dstInfo = fBitmap.info().makeWH(srcInfo.width(), srcInfo.height());
158
159 void* dstPixels = fBitmap.getAddr(x, y);
160 size_t dstRowBytes = fBitmap.rowBytes();
161
162 if (SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
163 fBitmap.notifyPixelsChanged();
164 return true;
165 }
166 return false;
167 }
168
onReadPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int x,int y)169 bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
170 int x, int y) {
171 return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y);
172 }
173
174 ///////////////////////////////////////////////////////////////////////////////
175
drawPaint(const SkDraw & draw,const SkPaint & paint)176 void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
177 draw.drawPaint(paint);
178 }
179
drawPoints(const SkDraw & draw,SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)180 void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
181 const SkPoint pts[], const SkPaint& paint) {
182 CHECK_FOR_ANNOTATION(paint);
183 draw.drawPoints(mode, count, pts, paint);
184 }
185
drawRect(const SkDraw & draw,const SkRect & r,const SkPaint & paint)186 void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
187 CHECK_FOR_ANNOTATION(paint);
188 draw.drawRect(r, paint);
189 }
190
drawOval(const SkDraw & draw,const SkRect & oval,const SkPaint & paint)191 void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
192 CHECK_FOR_ANNOTATION(paint);
193
194 SkPath path;
195 path.addOval(oval);
196 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
197 // required to override drawOval.
198 this->drawPath(draw, path, paint, NULL, true);
199 }
200
drawRRect(const SkDraw & draw,const SkRRect & rrect,const SkPaint & paint)201 void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
202 CHECK_FOR_ANNOTATION(paint);
203
204 #ifdef SK_IGNORE_BLURRED_RRECT_OPT
205 SkPath path;
206
207 path.addRRect(rrect);
208 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
209 // required to override drawRRect.
210 this->drawPath(draw, path, paint, NULL, true);
211 #else
212 draw.drawRRect(rrect, paint);
213 #endif
214 }
215
drawPath(const SkDraw & draw,const SkPath & path,const SkPaint & paint,const SkMatrix * prePathMatrix,bool pathIsMutable)216 void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
217 const SkPaint& paint, const SkMatrix* prePathMatrix,
218 bool pathIsMutable) {
219 CHECK_FOR_ANNOTATION(paint);
220 draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
221 }
222
drawBitmap(const SkDraw & draw,const SkBitmap & bitmap,const SkMatrix & matrix,const SkPaint & paint)223 void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
224 const SkMatrix& matrix, const SkPaint& paint) {
225 draw.drawBitmap(bitmap, matrix, paint);
226 }
227
drawBitmapRect(const SkDraw & draw,const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint & paint,SkCanvas::DrawBitmapRectFlags flags)228 void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
229 const SkRect* src, const SkRect& dst,
230 const SkPaint& paint,
231 SkCanvas::DrawBitmapRectFlags flags) {
232 SkMatrix matrix;
233 SkRect bitmapBounds, tmpSrc, tmpDst;
234 SkBitmap tmpBitmap;
235
236 bitmapBounds.isetWH(bitmap.width(), bitmap.height());
237
238 // Compute matrix from the two rectangles
239 if (src) {
240 tmpSrc = *src;
241 } else {
242 tmpSrc = bitmapBounds;
243 }
244 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
245
246 const SkRect* dstPtr = &dst;
247 const SkBitmap* bitmapPtr = &bitmap;
248
249 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
250 // needed (if the src was clipped). No check needed if src==null.
251 if (src) {
252 if (!bitmapBounds.contains(*src)) {
253 if (!tmpSrc.intersect(bitmapBounds)) {
254 return; // nothing to draw
255 }
256 // recompute dst, based on the smaller tmpSrc
257 matrix.mapRect(&tmpDst, tmpSrc);
258 dstPtr = &tmpDst;
259 }
260
261 // since we may need to clamp to the borders of the src rect within
262 // the bitmap, we extract a subset.
263 SkIRect srcIR;
264 tmpSrc.roundOut(&srcIR);
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 this->drawBitmap(draw, *bitmapPtr, matrix, 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[],SkScalar y,int scalarsPerPos,const SkPaint & paint)331 void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
332 const SkScalar xpos[], SkScalar y,
333 int scalarsPerPos, const SkPaint& paint) {
334 draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
335 }
336
drawTextOnPath(const SkDraw & draw,const void * text,size_t len,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)337 void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text,
338 size_t len, const SkPath& path,
339 const SkMatrix* matrix,
340 const SkPaint& paint) {
341 draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
342 }
343
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)344 void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
345 int vertexCount,
346 const SkPoint verts[], const SkPoint textures[],
347 const SkColor colors[], SkXfermode* xmode,
348 const uint16_t indices[], int indexCount,
349 const SkPaint& paint) {
350 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
351 indices, indexCount, paint);
352 }
353
drawDevice(const SkDraw & draw,SkBaseDevice * device,int x,int y,const SkPaint & paint)354 void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
355 int x, int y, const SkPaint& paint) {
356 const SkBitmap& src = device->accessBitmap(false);
357 draw.drawSprite(src, x, y, paint);
358 }
359
newSurface(const SkImageInfo & info,const SkSurfaceProps & props)360 SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
361 return SkSurface::NewRaster(info, &props);
362 }
363
peekPixels(SkImageInfo * info,size_t * rowBytes)364 const void* SkBitmapDevice::peekPixels(SkImageInfo* info, size_t* rowBytes) {
365 const SkImageInfo bmInfo = fBitmap.info();
366 if (fBitmap.getPixels() && (kUnknown_SkColorType != bmInfo.colorType())) {
367 if (info) {
368 *info = bmInfo;
369 }
370 if (rowBytes) {
371 *rowBytes = fBitmap.rowBytes();
372 }
373 return fBitmap.getPixels();
374 }
375 return NULL;
376 }
377
getImageFilterCache()378 SkImageFilter::Cache* SkBitmapDevice::getImageFilterCache() {
379 SkImageFilter::Cache* cache = SkImageFilter::Cache::Get();
380 cache->ref();
381 return cache;
382 }
383
384 ///////////////////////////////////////////////////////////////////////////////
385
filterTextFlags(const SkPaint & paint,TextFlags * flags)386 bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
387 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
388 // we're cool with the paint as is
389 return false;
390 }
391
392 if (kN32_SkColorType != fBitmap.colorType() ||
393 paint.getRasterizer() ||
394 paint.getPathEffect() ||
395 paint.isFakeBoldText() ||
396 paint.getStyle() != SkPaint::kFill_Style ||
397 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
398 // turn off lcd, but turn on kGenA8
399 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
400 flags->fFlags |= SkPaint::kGenA8FromLCD_Flag;
401 return true;
402 }
403 // we're cool with the paint as is
404 return false;
405 }
406