blob: a7ca7b718171c73434e43233dae0d5ab7d75d4cc [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"
mtkleincd495412015-11-05 09:46:23 -080011#include "SkMallocPixelRef.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkMatrix.h"
13#include "SkPaint.h"
14#include "SkPath.h"
reed884e97c2015-05-26 11:31:54 -070015#include "SkPixelRef.h"
bungemand3ebb482015-08-05 13:57:49 -070016#include "SkPixmap.h"
robertphillips@google.com53238bc2013-08-30 13:12:10 +000017#include "SkShader.h"
reed@google.com76f10a32014-02-05 15:32:21 +000018#include "SkSurface.h"
bungemand3ebb482015-08-05 13:57:49 -070019#include "SkXfermode.h"
20
21class SkColorTable;
robertphillips@google.com53238bc2013-08-30 13:12:10 +000022
reed@google.com44699382013-10-31 17:28:30 +000023#define CHECK_FOR_ANNOTATION(paint) \
24 do { if (paint.getAnnotation()) { return; } } while (0)
robertphillips@google.com53238bc2013-08-30 13:12:10 +000025
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000026static 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) {
reed44977482015-02-27 10:23:00 -080035 *newAlphaType = kUnknown_SkAlphaType;
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000036 }
37 return true;
38 }
skia.committer@gmail.com969588f2014-02-16 03:01:56 +000039
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000040 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;
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +000056 case kN32_SkColorType:
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000057 break;
58 default:
59 return false;
60 }
61
62 if (newAlphaType) {
63 *newAlphaType = canonicalAlphaType;
64 }
65 return true;
66}
67
robertphillips9a53fd72015-06-22 09:46:59 -070068SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
69 : INHERITED(SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType))
70 , fBitmap(bitmap) {
halcanary96fcdcc2015-08-27 07:41:13 -070071 SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
robertphillips@google.com53238bc2013-08-30 13:12:10 +000072}
73
robertphillips9a53fd72015-06-22 09:46:59 -070074SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) {
75 return Create(info, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType));
76}
77
robertphillipsfcf78292015-06-19 11:49:52 -070078SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps)
robertphillips9a53fd72015-06-22 09:46:59 -070079 : INHERITED(surfaceProps)
80 , fBitmap(bitmap) {
halcanary96fcdcc2015-08-27 07:41:13 -070081 SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
robertphillips@google.com53238bc2013-08-30 13:12:10 +000082}
83
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000084SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
robertphillips9a53fd72015-06-22 09:46:59 -070085 const SkSurfaceProps& surfaceProps) {
reede5ea5002014-09-03 11:54:58 -070086 SkAlphaType newAT = origInfo.alphaType();
87 if (!valid_for_bitmap_device(origInfo, &newAT)) {
halcanary96fcdcc2015-08-27 07:41:13 -070088 return nullptr;
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000089 }
robertphillips@google.com53238bc2013-08-30 13:12:10 +000090
reede5ea5002014-09-03 11:54:58 -070091 const SkImageInfo info = origInfo.makeAlphaType(newAT);
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000092 SkBitmap bitmap;
93
94 if (kUnknown_SkColorType == info.colorType()) {
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +000095 if (!bitmap.setInfo(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -070096 return nullptr;
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000097 }
lsalzman04d975a2016-01-08 11:20:14 -080098 } else if (info.isOpaque()) {
mtkleincd495412015-11-05 09:46:23 -080099 // If this bitmap is opaque, we don't have any sensible default color,
100 // so we just return uninitialized pixels.
reed84825042014-09-02 12:50:45 -0700101 if (!bitmap.tryAllocPixels(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700102 return nullptr;
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000103 }
mtkleincd495412015-11-05 09:46:23 -0800104 } else {
105 // This bitmap has transparency, so we'll zero the pixels (to transparent).
106 // We use a ZeroedPRFactory as a faster alloc-then-eraseColor(SK_ColorTRANSPARENT).
107 SkMallocPixelRef::ZeroedPRFactory factory;
108 if (!bitmap.tryAllocPixels(info, &factory, nullptr/*color table*/)) {
109 return nullptr;
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000110 }
111 }
112
halcanary385fe4d2015-08-26 13:07:48 -0700113 return new SkBitmapDevice(bitmap, surfaceProps);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000114}
115
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000116SkImageInfo SkBitmapDevice::imageInfo() const {
117 return fBitmap.info();
118}
119
mtkleinfeaadee2015-04-08 11:25:48 -0700120void SkBitmapDevice::setNewSize(const SkISize& size) {
121 SkASSERT(!fBitmap.pixelRef());
122 fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight));
123}
124
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000125void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
126 SkASSERT(bm.width() == fBitmap.width());
127 SkASSERT(bm.height() == fBitmap.height());
128 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config)
129 fBitmap.lockPixels();
130}
131
reed76033be2015-03-14 10:54:31 -0700132SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
robertphillips9a53fd72015-06-22 09:46:59 -0700133 const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
134 return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000135}
136
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000137const SkBitmap& SkBitmapDevice::onAccessBitmap() {
138 return fBitmap;
139}
140
reed884e97c2015-05-26 11:31:54 -0700141bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) {
reed6e764852015-06-05 14:11:32 -0700142 if (fBitmap.lockPixelsAreWritable() && this->onPeekPixels(pmap)) {
143 fBitmap.notifyPixelsChanged();
144 return true;
145 }
146 return false;
reed9572a102015-05-26 19:22:17 -0700147}
148
149bool SkBitmapDevice::onPeekPixels(SkPixmap* pmap) {
reed884e97c2015-05-26 11:31:54 -0700150 const SkImageInfo info = fBitmap.info();
151 if (fBitmap.getPixels() && (kUnknown_SkColorType != info.colorType())) {
halcanary96fcdcc2015-08-27 07:41:13 -0700152 SkColorTable* ctable = nullptr;
reed884e97c2015-05-26 11:31:54 -0700153 pmap->reset(fBitmap.info(), fBitmap.getPixels(), fBitmap.rowBytes(), ctable);
154 return true;
reed@google.com9c135db2014-03-12 18:28:35 +0000155 }
reed884e97c2015-05-26 11:31:54 -0700156 return false;
reed@google.com9c135db2014-03-12 18:28:35 +0000157}
158
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000159bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
160 size_t srcRowBytes, int x, int y) {
reed@google.com0d30c512014-03-14 14:02:58 +0000161 // since we don't stop creating un-pixeled devices yet, check for no pixels here
halcanary96fcdcc2015-08-27 07:41:13 -0700162 if (nullptr == fBitmap.getPixels()) {
reed@google.com0d30c512014-03-14 14:02:58 +0000163 return false;
164 }
165
reede5ea5002014-09-03 11:54:58 -0700166 const SkImageInfo dstInfo = fBitmap.info().makeWH(srcInfo.width(), srcInfo.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000167
168 void* dstPixels = fBitmap.getAddr(x, y);
169 size_t dstRowBytes = fBitmap.rowBytes();
170
reedb184f7f2014-07-13 04:32:32 -0700171 if (SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000172 fBitmap.notifyPixelsChanged();
173 return true;
174 }
175 return false;
176}
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000177
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000178bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
179 int x, int y) {
reedb184f7f2014-07-13 04:32:32 -0700180 return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000181}
182
reedcd1d41e2015-05-25 21:21:27 -0700183void SkBitmapDevice::onAttachToCanvas(SkCanvas* canvas) {
184 INHERITED::onAttachToCanvas(canvas);
185 if (fBitmap.lockPixelsAreWritable()) {
186 fBitmap.lockPixels();
187 }
188}
189
190void SkBitmapDevice::onDetachFromCanvas() {
191 INHERITED::onDetachFromCanvas();
192 if (fBitmap.lockPixelsAreWritable()) {
193 fBitmap.unlockPixels();
194 }
195}
196
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000197///////////////////////////////////////////////////////////////////////////////
198
199void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
200 draw.drawPaint(paint);
201}
202
203void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
204 const SkPoint pts[], const SkPaint& paint) {
reed@google.com44699382013-10-31 17:28:30 +0000205 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000206 draw.drawPoints(mode, count, pts, paint);
207}
208
209void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
reed@google.com44699382013-10-31 17:28:30 +0000210 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000211 draw.drawRect(r, paint);
212}
213
214void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
reed@google.com44699382013-10-31 17:28:30 +0000215 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000216
217 SkPath path;
218 path.addOval(oval);
219 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
220 // required to override drawOval.
halcanary96fcdcc2015-08-27 07:41:13 -0700221 this->drawPath(draw, path, paint, nullptr, true);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000222}
223
224void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
reed@google.com44699382013-10-31 17:28:30 +0000225 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000226
robertphillips@google.com50a76002013-11-12 01:16:56 +0000227#ifdef SK_IGNORE_BLURRED_RRECT_OPT
228 SkPath path;
229
230 path.addRRect(rrect);
231 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
232 // required to override drawRRect.
halcanary96fcdcc2015-08-27 07:41:13 -0700233 this->drawPath(draw, path, paint, nullptr, true);
robertphillips@google.com50a76002013-11-12 01:16:56 +0000234#else
scroggo@google.coma8e33a92013-11-08 18:02:53 +0000235 draw.drawRRect(rrect, paint);
robertphillips@google.com50a76002013-11-12 01:16:56 +0000236#endif
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000237}
238
239void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
240 const SkPaint& paint, const SkMatrix* prePathMatrix,
241 bool pathIsMutable) {
reed@google.com44699382013-10-31 17:28:30 +0000242 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000243 draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
244}
245
246void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
247 const SkMatrix& matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -0700248 draw.drawBitmap(bitmap, matrix, nullptr, paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000249}
250
251void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
252 const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -0700253 const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000254 SkMatrix matrix;
255 SkRect bitmapBounds, tmpSrc, tmpDst;
256 SkBitmap tmpBitmap;
257
258 bitmapBounds.isetWH(bitmap.width(), bitmap.height());
259
260 // Compute matrix from the two rectangles
261 if (src) {
262 tmpSrc = *src;
263 } else {
264 tmpSrc = bitmapBounds;
265 }
266 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
267
268 const SkRect* dstPtr = &dst;
269 const SkBitmap* bitmapPtr = &bitmap;
270
271 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
272 // needed (if the src was clipped). No check needed if src==null.
273 if (src) {
274 if (!bitmapBounds.contains(*src)) {
275 if (!tmpSrc.intersect(bitmapBounds)) {
276 return; // nothing to draw
277 }
278 // recompute dst, based on the smaller tmpSrc
279 matrix.mapRect(&tmpDst, tmpSrc);
280 dstPtr = &tmpDst;
281 }
282
283 // since we may need to clamp to the borders of the src rect within
284 // the bitmap, we extract a subset.
reedb07a94f2014-11-19 05:03:18 -0800285 const SkIRect srcIR = tmpSrc.roundOut();
piotaixr0e977052014-09-17 16:24:04 -0700286 if(bitmap.pixelRef()->getTexture()) {
287 // Accelerated source canvas, don't use extractSubset but readPixels to get the subset.
288 // This way, the pixels are copied in CPU memory instead of GPU memory.
bsalomon9d22fd62016-01-11 11:14:17 -0800289 bitmap.pixelRef()->readPixels(&tmpBitmap, kN32_SkColorType, &srcIR);
piotaixr0e977052014-09-17 16:24:04 -0700290 } else {
291 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
292 return;
293 }
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000294 }
295 bitmapPtr = &tmpBitmap;
296
297 // Since we did an extract, we need to adjust the matrix accordingly
298 SkScalar dx = 0, dy = 0;
299 if (srcIR.fLeft > 0) {
300 dx = SkIntToScalar(srcIR.fLeft);
301 }
302 if (srcIR.fTop > 0) {
303 dy = SkIntToScalar(srcIR.fTop);
304 }
305 if (dx || dy) {
306 matrix.preTranslate(dx, dy);
307 }
308
309 SkRect extractedBitmapBounds;
310 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
311 if (extractedBitmapBounds == tmpSrc) {
312 // no fractional part in src, we can just call drawBitmap
313 goto USE_DRAWBITMAP;
314 }
315 } else {
316 USE_DRAWBITMAP:
317 // We can go faster by just calling drawBitmap, which will concat the
318 // matrix with the CTM, and try to call drawSprite if it can. If not,
319 // it will make a shader and call drawRect, as we do below.
reed03939122014-12-15 13:42:51 -0800320 draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000321 return;
322 }
323
324 // construct a shader, so we can call drawRect with the dst
325 SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
326 SkShader::kClamp_TileMode,
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000327 SkShader::kClamp_TileMode,
328 &matrix);
halcanary96fcdcc2015-08-27 07:41:13 -0700329 if (nullptr == s) {
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000330 return;
331 }
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000332
333 SkPaint paintWithShader(paint);
334 paintWithShader.setStyle(SkPaint::kFill_Style);
335 paintWithShader.setShader(s)->unref();
336
337 // Call ourself, in case the subclass wanted to share this setup code
338 // but handle the drawRect code themselves.
339 this->drawRect(draw, *dstPtr, paintWithShader);
340}
341
342void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
343 int x, int y, const SkPaint& paint) {
344 draw.drawSprite(bitmap, x, y, paint);
345}
346
347void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
348 SkScalar x, SkScalar y, const SkPaint& paint) {
349 draw.drawText((const char*)text, len, x, y, paint);
350}
351
352void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
fmalita05c4a432014-09-29 06:29:53 -0700353 const SkScalar xpos[], int scalarsPerPos,
354 const SkPoint& offset, const SkPaint& paint) {
355 draw.drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000356}
357
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000358void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
359 int vertexCount,
360 const SkPoint verts[], const SkPoint textures[],
361 const SkColor colors[], SkXfermode* xmode,
362 const uint16_t indices[], int indexCount,
363 const SkPaint& paint) {
364 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
365 indices, indexCount, paint);
366}
367
368void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
369 int x, int y, const SkPaint& paint) {
reed9572a102015-05-26 19:22:17 -0700370 draw.drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000371}
372
reed4a8126e2014-09-22 07:29:03 -0700373SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
374 return SkSurface::NewRaster(info, &props);
reed@google.com76f10a32014-02-05 15:32:21 +0000375}
376
senorblancobe129b22014-08-08 07:14:35 -0700377SkImageFilter::Cache* SkBitmapDevice::getImageFilterCache() {
378 SkImageFilter::Cache* cache = SkImageFilter::Cache::Get();
senorblanco55b6d8b2014-07-30 11:26:46 -0700379 cache->ref();
380 return cache;
381}
382
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000383///////////////////////////////////////////////////////////////////////////////
384
reedb2db8982014-11-13 12:41:02 -0800385bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const {
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000386 if (kN32_SkColorType != fBitmap.colorType() ||
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000387 paint.getRasterizer() ||
388 paint.getPathEffect() ||
389 paint.isFakeBoldText() ||
390 paint.getStyle() != SkPaint::kFill_Style ||
reedb2db8982014-11-13 12:41:02 -0800391 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode))
392 {
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000393 return true;
394 }
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000395 return false;
396}