blob: dfe1756c4c7c2f443cee7e2db529d24b47ec50fb [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"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkMatrix.h"
12#include "SkPaint.h"
13#include "SkPath.h"
reed884e97c2015-05-26 11:31:54 -070014#include "SkPixelRef.h"
bungemand3ebb482015-08-05 13:57:49 -070015#include "SkPixmap.h"
robertphillips@google.com53238bc2013-08-30 13:12:10 +000016#include "SkShader.h"
reed@google.com76f10a32014-02-05 15:32:21 +000017#include "SkSurface.h"
bungemand3ebb482015-08-05 13:57:49 -070018#include "SkXfermode.h"
19
20class SkColorTable;
robertphillips@google.com53238bc2013-08-30 13:12:10 +000021
reed@google.com44699382013-10-31 17:28:30 +000022#define CHECK_FOR_ANNOTATION(paint) \
23 do { if (paint.getAnnotation()) { return; } } while (0)
robertphillips@google.com53238bc2013-08-30 13:12:10 +000024
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000025static bool valid_for_bitmap_device(const SkImageInfo& info,
26 SkAlphaType* newAlphaType) {
27 if (info.width() < 0 || info.height() < 0) {
28 return false;
29 }
30
31 // TODO: can we stop supporting kUnknown in SkBitmkapDevice?
32 if (kUnknown_SkColorType == info.colorType()) {
33 if (newAlphaType) {
reed44977482015-02-27 10:23:00 -080034 *newAlphaType = kUnknown_SkAlphaType;
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000035 }
36 return true;
37 }
skia.committer@gmail.com969588f2014-02-16 03:01:56 +000038
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000039 switch (info.alphaType()) {
40 case kPremul_SkAlphaType:
41 case kOpaque_SkAlphaType:
42 break;
43 default:
44 return false;
45 }
46
47 SkAlphaType canonicalAlphaType = info.alphaType();
48
49 switch (info.colorType()) {
50 case kAlpha_8_SkColorType:
51 break;
52 case kRGB_565_SkColorType:
53 canonicalAlphaType = kOpaque_SkAlphaType;
54 break;
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +000055 case kN32_SkColorType:
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000056 break;
57 default:
58 return false;
59 }
60
61 if (newAlphaType) {
62 *newAlphaType = canonicalAlphaType;
63 }
64 return true;
65}
66
robertphillips9a53fd72015-06-22 09:46:59 -070067SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
68 : INHERITED(SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType))
69 , fBitmap(bitmap) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000070 SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
robertphillips@google.com53238bc2013-08-30 13:12:10 +000071}
72
robertphillips9a53fd72015-06-22 09:46:59 -070073SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) {
74 return Create(info, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType));
75}
76
robertphillipsfcf78292015-06-19 11:49:52 -070077SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps)
robertphillips9a53fd72015-06-22 09:46:59 -070078 : INHERITED(surfaceProps)
79 , fBitmap(bitmap) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000080 SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
robertphillips@google.com53238bc2013-08-30 13:12:10 +000081}
82
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000083SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
robertphillips9a53fd72015-06-22 09:46:59 -070084 const SkSurfaceProps& surfaceProps) {
reede5ea5002014-09-03 11:54:58 -070085 SkAlphaType newAT = origInfo.alphaType();
86 if (!valid_for_bitmap_device(origInfo, &newAT)) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000087 return NULL;
88 }
robertphillips@google.com53238bc2013-08-30 13:12:10 +000089
reede5ea5002014-09-03 11:54:58 -070090 const SkImageInfo info = origInfo.makeAlphaType(newAT);
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000091 SkBitmap bitmap;
92
93 if (kUnknown_SkColorType == info.colorType()) {
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +000094 if (!bitmap.setInfo(info)) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000095 return NULL;
96 }
97 } else {
reed84825042014-09-02 12:50:45 -070098 if (!bitmap.tryAllocPixels(info)) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +000099 return NULL;
100 }
101 if (!bitmap.info().isOpaque()) {
102 bitmap.eraseColor(SK_ColorTRANSPARENT);
103 }
104 }
105
robertphillips9a53fd72015-06-22 09:46:59 -0700106 return SkNEW_ARGS(SkBitmapDevice, (bitmap, surfaceProps));
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000107}
108
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000109SkImageInfo SkBitmapDevice::imageInfo() const {
110 return fBitmap.info();
111}
112
mtkleinfeaadee2015-04-08 11:25:48 -0700113void SkBitmapDevice::setNewSize(const SkISize& size) {
114 SkASSERT(!fBitmap.pixelRef());
115 fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight));
116}
117
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000118void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
119 SkASSERT(bm.width() == fBitmap.width());
120 SkASSERT(bm.height() == fBitmap.height());
121 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config)
122 fBitmap.lockPixels();
123}
124
reed76033be2015-03-14 10:54:31 -0700125SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
robertphillips9a53fd72015-06-22 09:46:59 -0700126 const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
127 return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000128}
129
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000130const SkBitmap& SkBitmapDevice::onAccessBitmap() {
131 return fBitmap;
132}
133
reed884e97c2015-05-26 11:31:54 -0700134bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) {
reed6e764852015-06-05 14:11:32 -0700135 if (fBitmap.lockPixelsAreWritable() && this->onPeekPixels(pmap)) {
136 fBitmap.notifyPixelsChanged();
137 return true;
138 }
139 return false;
reed9572a102015-05-26 19:22:17 -0700140}
141
142bool SkBitmapDevice::onPeekPixels(SkPixmap* pmap) {
reed884e97c2015-05-26 11:31:54 -0700143 const SkImageInfo info = fBitmap.info();
144 if (fBitmap.getPixels() && (kUnknown_SkColorType != info.colorType())) {
145 SkColorTable* ctable = NULL;
146 pmap->reset(fBitmap.info(), fBitmap.getPixels(), fBitmap.rowBytes(), ctable);
147 return true;
reed@google.com9c135db2014-03-12 18:28:35 +0000148 }
reed884e97c2015-05-26 11:31:54 -0700149 return false;
reed@google.com9c135db2014-03-12 18:28:35 +0000150}
151
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000152bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
153 size_t srcRowBytes, int x, int y) {
reed@google.com0d30c512014-03-14 14:02:58 +0000154 // since we don't stop creating un-pixeled devices yet, check for no pixels here
155 if (NULL == fBitmap.getPixels()) {
156 return false;
157 }
158
reede5ea5002014-09-03 11:54:58 -0700159 const SkImageInfo dstInfo = fBitmap.info().makeWH(srcInfo.width(), srcInfo.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000160
161 void* dstPixels = fBitmap.getAddr(x, y);
162 size_t dstRowBytes = fBitmap.rowBytes();
163
reedb184f7f2014-07-13 04:32:32 -0700164 if (SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000165 fBitmap.notifyPixelsChanged();
166 return true;
167 }
168 return false;
169}
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000170
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000171bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
172 int x, int y) {
reedb184f7f2014-07-13 04:32:32 -0700173 return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000174}
175
reedcd1d41e2015-05-25 21:21:27 -0700176void SkBitmapDevice::onAttachToCanvas(SkCanvas* canvas) {
177 INHERITED::onAttachToCanvas(canvas);
178 if (fBitmap.lockPixelsAreWritable()) {
179 fBitmap.lockPixels();
180 }
181}
182
183void SkBitmapDevice::onDetachFromCanvas() {
184 INHERITED::onDetachFromCanvas();
185 if (fBitmap.lockPixelsAreWritable()) {
186 fBitmap.unlockPixels();
187 }
188}
189
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000190///////////////////////////////////////////////////////////////////////////////
191
192void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
193 draw.drawPaint(paint);
194}
195
196void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
197 const SkPoint pts[], const SkPaint& paint) {
reed@google.com44699382013-10-31 17:28:30 +0000198 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000199 draw.drawPoints(mode, count, pts, paint);
200}
201
202void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
reed@google.com44699382013-10-31 17:28:30 +0000203 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000204 draw.drawRect(r, paint);
205}
206
207void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
reed@google.com44699382013-10-31 17:28:30 +0000208 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000209
210 SkPath path;
211 path.addOval(oval);
212 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
213 // required to override drawOval.
214 this->drawPath(draw, path, paint, NULL, true);
215}
216
217void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
reed@google.com44699382013-10-31 17:28:30 +0000218 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000219
robertphillips@google.com50a76002013-11-12 01:16:56 +0000220#ifdef SK_IGNORE_BLURRED_RRECT_OPT
221 SkPath path;
222
223 path.addRRect(rrect);
224 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
225 // required to override drawRRect.
226 this->drawPath(draw, path, paint, NULL, true);
227#else
scroggo@google.coma8e33a92013-11-08 18:02:53 +0000228 draw.drawRRect(rrect, paint);
robertphillips@google.com50a76002013-11-12 01:16:56 +0000229#endif
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000230}
231
232void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
233 const SkPaint& paint, const SkMatrix* prePathMatrix,
234 bool pathIsMutable) {
reed@google.com44699382013-10-31 17:28:30 +0000235 CHECK_FOR_ANNOTATION(paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000236 draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
237}
238
239void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
240 const SkMatrix& matrix, const SkPaint& paint) {
reed03939122014-12-15 13:42:51 -0800241 draw.drawBitmap(bitmap, matrix, NULL, paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000242}
243
244void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
245 const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -0700246 const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000247 SkMatrix matrix;
248 SkRect bitmapBounds, tmpSrc, tmpDst;
249 SkBitmap tmpBitmap;
250
251 bitmapBounds.isetWH(bitmap.width(), bitmap.height());
252
253 // Compute matrix from the two rectangles
254 if (src) {
255 tmpSrc = *src;
256 } else {
257 tmpSrc = bitmapBounds;
258 }
259 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
260
261 const SkRect* dstPtr = &dst;
262 const SkBitmap* bitmapPtr = &bitmap;
263
264 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
265 // needed (if the src was clipped). No check needed if src==null.
266 if (src) {
267 if (!bitmapBounds.contains(*src)) {
268 if (!tmpSrc.intersect(bitmapBounds)) {
269 return; // nothing to draw
270 }
271 // recompute dst, based on the smaller tmpSrc
272 matrix.mapRect(&tmpDst, tmpSrc);
273 dstPtr = &tmpDst;
274 }
275
276 // since we may need to clamp to the borders of the src rect within
277 // the bitmap, we extract a subset.
reedb07a94f2014-11-19 05:03:18 -0800278 const SkIRect srcIR = tmpSrc.roundOut();
piotaixr0e977052014-09-17 16:24:04 -0700279 if(bitmap.pixelRef()->getTexture()) {
280 // Accelerated source canvas, don't use extractSubset but readPixels to get the subset.
281 // This way, the pixels are copied in CPU memory instead of GPU memory.
282 bitmap.pixelRef()->readPixels(&tmpBitmap, &srcIR);
283 } else {
284 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
285 return;
286 }
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000287 }
288 bitmapPtr = &tmpBitmap;
289
290 // Since we did an extract, we need to adjust the matrix accordingly
291 SkScalar dx = 0, dy = 0;
292 if (srcIR.fLeft > 0) {
293 dx = SkIntToScalar(srcIR.fLeft);
294 }
295 if (srcIR.fTop > 0) {
296 dy = SkIntToScalar(srcIR.fTop);
297 }
298 if (dx || dy) {
299 matrix.preTranslate(dx, dy);
300 }
301
302 SkRect extractedBitmapBounds;
303 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
304 if (extractedBitmapBounds == tmpSrc) {
305 // no fractional part in src, we can just call drawBitmap
306 goto USE_DRAWBITMAP;
307 }
308 } else {
309 USE_DRAWBITMAP:
310 // We can go faster by just calling drawBitmap, which will concat the
311 // matrix with the CTM, and try to call drawSprite if it can. If not,
312 // it will make a shader and call drawRect, as we do below.
reed03939122014-12-15 13:42:51 -0800313 draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000314 return;
315 }
316
317 // construct a shader, so we can call drawRect with the dst
318 SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
319 SkShader::kClamp_TileMode,
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000320 SkShader::kClamp_TileMode,
321 &matrix);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000322 if (NULL == s) {
323 return;
324 }
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000325
326 SkPaint paintWithShader(paint);
327 paintWithShader.setStyle(SkPaint::kFill_Style);
328 paintWithShader.setShader(s)->unref();
329
330 // Call ourself, in case the subclass wanted to share this setup code
331 // but handle the drawRect code themselves.
332 this->drawRect(draw, *dstPtr, paintWithShader);
333}
334
335void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
336 int x, int y, const SkPaint& paint) {
337 draw.drawSprite(bitmap, x, y, paint);
338}
339
340void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
341 SkScalar x, SkScalar y, const SkPaint& paint) {
342 draw.drawText((const char*)text, len, x, y, paint);
343}
344
345void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
fmalita05c4a432014-09-29 06:29:53 -0700346 const SkScalar xpos[], int scalarsPerPos,
347 const SkPoint& offset, const SkPaint& paint) {
348 draw.drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000349}
350
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000351void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
352 int vertexCount,
353 const SkPoint verts[], const SkPoint textures[],
354 const SkColor colors[], SkXfermode* xmode,
355 const uint16_t indices[], int indexCount,
356 const SkPaint& paint) {
357 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
358 indices, indexCount, paint);
359}
360
361void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
362 int x, int y, const SkPaint& paint) {
reed9572a102015-05-26 19:22:17 -0700363 draw.drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint);
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000364}
365
reed4a8126e2014-09-22 07:29:03 -0700366SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
367 return SkSurface::NewRaster(info, &props);
reed@google.com76f10a32014-02-05 15:32:21 +0000368}
369
senorblancobe129b22014-08-08 07:14:35 -0700370SkImageFilter::Cache* SkBitmapDevice::getImageFilterCache() {
371 SkImageFilter::Cache* cache = SkImageFilter::Cache::Get();
senorblanco55b6d8b2014-07-30 11:26:46 -0700372 cache->ref();
373 return cache;
374}
375
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000376///////////////////////////////////////////////////////////////////////////////
377
reedb2db8982014-11-13 12:41:02 -0800378bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const {
commit-bot@chromium.orgcba73782014-05-29 15:57:47 +0000379 if (kN32_SkColorType != fBitmap.colorType() ||
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000380 paint.getRasterizer() ||
381 paint.getPathEffect() ||
382 paint.isFakeBoldText() ||
383 paint.getStyle() != SkPaint::kFill_Style ||
reedb2db8982014-11-13 12:41:02 -0800384 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode))
385 {
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000386 return true;
387 }
robertphillips@google.com53238bc2013-08-30 13:12:10 +0000388 return false;
389}