blob: 9da43d8c9cab5aa6fc76902bad3ff9de085eb39f [file] [log] [blame]
robertphillips@google.com53238bc2013-08-30 13:12:10 +00001/*
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"
reed884e97c2015-05-26 11:31:54 -070011#include "SkPixelRef.h"
reedfb8c1fc2015-08-04 18:44:56 -070012#include "SkRasterClip.h"
robertphillips@google.com53238bc2013-08-30 13:12:10 +000013#include "SkShader.h"
reed@google.com76f10a32014-02-05 15:32:21 +000014#include "SkSurface.h"
robertphillips@google.com53238bc2013-08-30 13:12:10 +000015
reed@google.com44699382013-10-31 17:28:30 +000016#define CHECK_FOR_ANNOTATION(paint) \
17 do { if (paint.getAnnotation()) { return; } } while (0)
robertphillips@google.com53238bc2013-08-30 13:12:10 +000018
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000019static 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) {
reed44977482015-02-27 10:23:00 -080028 *newAlphaType = kUnknown_SkAlphaType;
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000029 }
30 return true;
31 }
skia.committer@gmail.com969588f2014-02-16 03:01:56 +000032
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000033 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;
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +000049 case kN32_SkColorType:
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000050 break;
51 default:
52 return false;
53 }
54
55 if (newAlphaType) {
56 *newAlphaType = canonicalAlphaType;
57 }
58 return true;
59}
60
robertphillips9a53fd72015-06-22 09:46:59 -070061SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
62 : INHERITED(SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType))
63 , fBitmap(bitmap) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000064 SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
robertphillips@google.com53238bc2013-08-30 13:12:10 +000065}
66
robertphillips9a53fd72015-06-22 09:46:59 -070067SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) {
68 return Create(info, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType));
69}
70
robertphillipsfcf78292015-06-19 11:49:52 -070071SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps)
robertphillips9a53fd72015-06-22 09:46:59 -070072 : INHERITED(surfaceProps)
73 , fBitmap(bitmap) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000074 SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
robertphillips@google.com53238bc2013-08-30 13:12:10 +000075}
76
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000077SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
robertphillips9a53fd72015-06-22 09:46:59 -070078 const SkSurfaceProps& surfaceProps) {
reede5ea5002014-09-03 11:54:58 -070079 SkAlphaType newAT = origInfo.alphaType();
80 if (!valid_for_bitmap_device(origInfo, &newAT)) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000081 return NULL;
82 }
robertphillips@google.com53238bc2013-08-30 13:12:10 +000083
reede5ea5002014-09-03 11:54:58 -070084 const SkImageInfo info = origInfo.makeAlphaType(newAT);
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000085 SkBitmap bitmap;
86
87 if (kUnknown_SkColorType == info.colorType()) {
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +000088 if (!bitmap.setInfo(info)) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000089 return NULL;
90 }
91 } else {
reed84825042014-09-02 12:50:45 -070092 if (!bitmap.tryAllocPixels(info)) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000093 return NULL;
94 }
95 if (!bitmap.info().isOpaque()) {
96 bitmap.eraseColor(SK_ColorTRANSPARENT);
97 }
98 }
99
robertphillips9a53fd72015-06-22 09:46:59 -0700100 return SkNEW_ARGS(SkBitmapDevice, (bitmap, surfaceProps));
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000101}
102
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000103SkImageInfo SkBitmapDevice::imageInfo() const {
104 return fBitmap.info();
105}
106
mtkleinfeaadee2015-04-08 11:25:48 -0700107void SkBitmapDevice::setNewSize(const SkISize& size) {
108 SkASSERT(!fBitmap.pixelRef());
109 fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight));
110}
111
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000112void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
113 SkASSERT(bm.width() == fBitmap.width());
114 SkASSERT(bm.height() == fBitmap.height());
115 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config)
116 fBitmap.lockPixels();
117}
118
reed76033be2015-03-14 10:54:31 -0700119SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
robertphillips9a53fd72015-06-22 09:46:59 -0700120 const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
121 return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000122}
123
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000124const SkBitmap& SkBitmapDevice::onAccessBitmap() {
125 return fBitmap;
126}
127
reed884e97c2015-05-26 11:31:54 -0700128bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) {
reed6e764852015-06-05 14:11:32 -0700129 if (fBitmap.lockPixelsAreWritable() && this->onPeekPixels(pmap)) {
130 fBitmap.notifyPixelsChanged();
131 return true;
132 }
133 return false;
reed9572a102015-05-26 19:22:17 -0700134}
135
136bool SkBitmapDevice::onPeekPixels(SkPixmap* pmap) {
reed884e97c2015-05-26 11:31:54 -0700137 const SkImageInfo info = fBitmap.info();
138 if (fBitmap.getPixels() && (kUnknown_SkColorType != info.colorType())) {
139 SkColorTable* ctable = NULL;
140 pmap->reset(fBitmap.info(), fBitmap.getPixels(), fBitmap.rowBytes(), ctable);
141 return true;
reed@google.com9c135db2014-03-12 18:28:35 +0000142 }
reed884e97c2015-05-26 11:31:54 -0700143 return false;
reed@google.com9c135db2014-03-12 18:28:35 +0000144}
145
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000146bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
147 size_t srcRowBytes, int x, int y) {
reed@google.com0d30c512014-03-14 14:02:58 +0000148 // since we don't stop creating un-pixeled devices yet, check for no pixels here
149 if (NULL == fBitmap.getPixels()) {
150 return false;
151 }
152
reede5ea5002014-09-03 11:54:58 -0700153 const SkImageInfo dstInfo = fBitmap.info().makeWH(srcInfo.width(), srcInfo.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000154
155 void* dstPixels = fBitmap.getAddr(x, y);
156 size_t dstRowBytes = fBitmap.rowBytes();
157
reedb184f7f2014-07-13 04:32:32 -0700158 if (SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000159 fBitmap.notifyPixelsChanged();
160 return true;
161 }
162 return false;
163}
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000164
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000165bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
166 int x, int y) {
reedb184f7f2014-07-13 04:32:32 -0700167 return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000168}
169
reedcd1d41e2015-05-25 21:21:27 -0700170void SkBitmapDevice::onAttachToCanvas(SkCanvas* canvas) {
171 INHERITED::onAttachToCanvas(canvas);
172 if (fBitmap.lockPixelsAreWritable()) {
173 fBitmap.lockPixels();
174 }
175}
176
177void SkBitmapDevice::onDetachFromCanvas() {
178 INHERITED::onDetachFromCanvas();
179 if (fBitmap.lockPixelsAreWritable()) {
180 fBitmap.unlockPixels();
181 }
182}
183
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000184///////////////////////////////////////////////////////////////////////////////
185
186void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
187 draw.drawPaint(paint);
188}
189
190void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
191 const SkPoint pts[], const SkPaint& paint) {
reed@google.com44699382013-10-31 17:28:30 +0000192 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000193 draw.drawPoints(mode, count, pts, paint);
194}
195
196void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
reed@google.com44699382013-10-31 17:28:30 +0000197 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000198 draw.drawRect(r, paint);
199}
200
201void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
reed@google.com44699382013-10-31 17:28:30 +0000202 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000203
204 SkPath path;
205 path.addOval(oval);
206 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
207 // required to override drawOval.
208 this->drawPath(draw, path, paint, NULL, true);
209}
210
211void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
reed@google.com44699382013-10-31 17:28:30 +0000212 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000213
robertphillips@google.com50a76002013-11-12 01:16:56 +0000214#ifdef SK_IGNORE_BLURRED_RRECT_OPT
215 SkPath path;
216
217 path.addRRect(rrect);
218 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
219 // required to override drawRRect.
220 this->drawPath(draw, path, paint, NULL, true);
221#else
scroggo@google.coma8e33a92013-11-08 18:02:53 +0000222 draw.drawRRect(rrect, paint);
robertphillips@google.com50a76002013-11-12 01:16:56 +0000223#endif
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000224}
225
226void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
227 const SkPaint& paint, const SkMatrix* prePathMatrix,
228 bool pathIsMutable) {
reed@google.com44699382013-10-31 17:28:30 +0000229 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000230 draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
231}
232
233void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
234 const SkMatrix& matrix, const SkPaint& paint) {
reed03939122014-12-15 13:42:51 -0800235 draw.drawBitmap(bitmap, matrix, NULL, paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000236}
237
238void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
239 const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -0700240 const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000241 SkMatrix matrix;
242 SkRect bitmapBounds, tmpSrc, tmpDst;
243 SkBitmap tmpBitmap;
244
245 bitmapBounds.isetWH(bitmap.width(), bitmap.height());
246
247 // Compute matrix from the two rectangles
248 if (src) {
249 tmpSrc = *src;
250 } else {
251 tmpSrc = bitmapBounds;
252 }
253 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
254
255 const SkRect* dstPtr = &dst;
256 const SkBitmap* bitmapPtr = &bitmap;
257
258 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
259 // needed (if the src was clipped). No check needed if src==null.
260 if (src) {
261 if (!bitmapBounds.contains(*src)) {
262 if (!tmpSrc.intersect(bitmapBounds)) {
263 return; // nothing to draw
264 }
265 // recompute dst, based on the smaller tmpSrc
266 matrix.mapRect(&tmpDst, tmpSrc);
267 dstPtr = &tmpDst;
268 }
269
270 // since we may need to clamp to the borders of the src rect within
271 // the bitmap, we extract a subset.
reedb07a94f2014-11-19 05:03:18 -0800272 const SkIRect srcIR = tmpSrc.roundOut();
piotaixr0e977052014-09-17 16:24:04 -0700273 if(bitmap.pixelRef()->getTexture()) {
274 // Accelerated source canvas, don't use extractSubset but readPixels to get the subset.
275 // This way, the pixels are copied in CPU memory instead of GPU memory.
276 bitmap.pixelRef()->readPixels(&tmpBitmap, &srcIR);
277 } else {
278 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
279 return;
280 }
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000281 }
282 bitmapPtr = &tmpBitmap;
283
284 // Since we did an extract, we need to adjust the matrix accordingly
285 SkScalar dx = 0, dy = 0;
286 if (srcIR.fLeft > 0) {
287 dx = SkIntToScalar(srcIR.fLeft);
288 }
289 if (srcIR.fTop > 0) {
290 dy = SkIntToScalar(srcIR.fTop);
291 }
292 if (dx || dy) {
293 matrix.preTranslate(dx, dy);
294 }
295
296 SkRect extractedBitmapBounds;
297 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
298 if (extractedBitmapBounds == tmpSrc) {
299 // no fractional part in src, we can just call drawBitmap
300 goto USE_DRAWBITMAP;
301 }
302 } else {
303 USE_DRAWBITMAP:
304 // We can go faster by just calling drawBitmap, which will concat the
305 // matrix with the CTM, and try to call drawSprite if it can. If not,
306 // it will make a shader and call drawRect, as we do below.
reed03939122014-12-15 13:42:51 -0800307 draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000308 return;
309 }
310
311 // construct a shader, so we can call drawRect with the dst
312 SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
313 SkShader::kClamp_TileMode,
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000314 SkShader::kClamp_TileMode,
315 &matrix);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000316 if (NULL == s) {
317 return;
318 }
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000319
320 SkPaint paintWithShader(paint);
321 paintWithShader.setStyle(SkPaint::kFill_Style);
322 paintWithShader.setShader(s)->unref();
323
324 // Call ourself, in case the subclass wanted to share this setup code
325 // but handle the drawRect code themselves.
326 this->drawRect(draw, *dstPtr, paintWithShader);
327}
328
329void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
330 int x, int y, const SkPaint& paint) {
331 draw.drawSprite(bitmap, x, y, paint);
332}
333
334void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
335 SkScalar x, SkScalar y, const SkPaint& paint) {
336 draw.drawText((const char*)text, len, x, y, paint);
337}
338
339void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
fmalita05c4a432014-09-29 06:29:53 -0700340 const SkScalar xpos[], int scalarsPerPos,
341 const SkPoint& offset, const SkPaint& paint) {
342 draw.drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000343}
344
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000345void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
346 int vertexCount,
347 const SkPoint verts[], const SkPoint textures[],
348 const SkColor colors[], SkXfermode* xmode,
349 const uint16_t indices[], int indexCount,
350 const SkPaint& paint) {
351 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
352 indices, indexCount, paint);
353}
354
355void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
356 int x, int y, const SkPaint& paint) {
reed9572a102015-05-26 19:22:17 -0700357 draw.drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000358}
359
reed4a8126e2014-09-22 07:29:03 -0700360SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
361 return SkSurface::NewRaster(info, &props);
reed@google.com76f10a32014-02-05 15:32:21 +0000362}
363
senorblancobe129b22014-08-08 07:14:35 -0700364SkImageFilter::Cache* SkBitmapDevice::getImageFilterCache() {
365 SkImageFilter::Cache* cache = SkImageFilter::Cache::Get();
senorblanco55b6d8b2014-07-30 11:26:46 -0700366 cache->ref();
367 return cache;
368}
369
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000370///////////////////////////////////////////////////////////////////////////////
371
reedb2db8982014-11-13 12:41:02 -0800372bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const {
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000373 if (kN32_SkColorType != fBitmap.colorType() ||
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000374 paint.getRasterizer() ||
375 paint.getPathEffect() ||
376 paint.isFakeBoldText() ||
377 paint.getStyle() != SkPaint::kFill_Style ||
reedb2db8982014-11-13 12:41:02 -0800378 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode))
379 {
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000380 return true;
381 }
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000382 return false;
383}