blob: 69b0f6afa1d789aea11afd1cabaae6610b99a62d [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkDevice.h"
bungeman@google.com532470f2013-01-22 19:25:14 +000010#include "SkDeviceProperties.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkDraw.h"
reed@google.com32d25b62011-12-20 16:19:00 +000012#include "SkImageFilter.h"
reed@google.coma7d94852011-03-30 21:23:07 +000013#include "SkMetaData.h"
bsalomon@google.com405d0f42012-08-29 21:26:13 +000014#include "SkRasterClip.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkRect.h"
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +000016#include "SkRRect.h"
reed@google.com33535f32012-09-25 15:37:50 +000017#include "SkShader.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000018
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000019SK_DEFINE_INST_COUNT(SkBaseDevice)
20SK_DEFINE_INST_COUNT(SkBitmapDevice)
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000021
mike@reedtribe.orgea4ac972011-04-26 11:48:33 +000022///////////////////////////////////////////////////////////////////////////////
vandebo@chromium.org8c1d88d2010-11-11 00:49:41 +000023
reed@google.comb0a34d82012-07-11 19:57:55 +000024#define CHECK_FOR_NODRAW_ANNOTATION(paint) \
25 do { if (paint.isNoDrawAnnotation()) { return; } } while (0)
26
27///////////////////////////////////////////////////////////////////////////////
28
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000029SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
30 : fBitmap(bitmap) {
reed@google.com6ba45722013-06-21 18:30:53 +000031 SkASSERT(SkBitmap::kARGB_4444_Config != bitmap.config());
bungeman@google.com532470f2013-01-22 19:25:14 +000032}
33
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000034SkBaseDevice::SkBaseDevice()
35 : fLeakyProperties(SkDeviceProperties::MakeDefault())
robertphillips@google.com40a1ae42012-07-13 15:36:15 +000036#ifdef SK_DEBUG
rmistry@google.comfbfcd562012-08-23 18:09:54 +000037 , fAttachedToCanvas(false)
robertphillips@google.com40a1ae42012-07-13 15:36:15 +000038#endif
39{
reed@google.com6f8f2922011-03-04 22:27:10 +000040 fOrigin.setZero();
reed@google.comaf951c92011-06-16 19:10:39 +000041 fMetaData = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +000042}
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000044SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties)
45 : SkBaseDevice(deviceProperties)
46 , fBitmap(bitmap) {
bungeman@google.com532470f2013-01-22 19:25:14 +000047}
48
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000049SkBaseDevice::SkBaseDevice(const SkDeviceProperties& deviceProperties)
bungeman@google.com532470f2013-01-22 19:25:14 +000050 : fLeakyProperties(deviceProperties)
51#ifdef SK_DEBUG
52 , fAttachedToCanvas(false)
robertphillips@google.com40a1ae42012-07-13 15:36:15 +000053#endif
54{
reed@google.comaf951c92011-06-16 19:10:39 +000055 fOrigin.setZero();
56 fMetaData = NULL;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000057}
58
59SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
60 fBitmap.setConfig(config, width, height);
61 fBitmap.allocPixels();
62 fBitmap.setIsOpaque(isOpaque);
63 if (!isOpaque) {
64 fBitmap.eraseColor(SK_ColorTRANSPARENT);
65 }
66}
67
68SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque,
69 const SkDeviceProperties& deviceProperties)
70 : SkBaseDevice(deviceProperties) {
reed@google.comaf951c92011-06-16 19:10:39 +000071
72 fBitmap.setConfig(config, width, height);
73 fBitmap.allocPixels();
74 fBitmap.setIsOpaque(isOpaque);
75 if (!isOpaque) {
junov@google.comdbfac8a2012-12-06 21:47:40 +000076 fBitmap.eraseColor(SK_ColorTRANSPARENT);
reed@google.comaf951c92011-06-16 19:10:39 +000077 }
78}
79
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000080SkBaseDevice::~SkBaseDevice() {
reed@google.coma7d94852011-03-30 21:23:07 +000081 delete fMetaData;
82}
83
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000084SkBitmapDevice::~SkBitmapDevice() {
85}
86
87void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
reed@google.com97af1a62012-08-28 12:19:02 +000088 SkASSERT(bm.width() == fBitmap.width());
89 SkASSERT(bm.height() == fBitmap.height());
90 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config)
91 fBitmap.lockPixels();
92}
93
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000094SkBaseDevice* SkBaseDevice::createCompatibleDevice(SkBitmap::Config config,
95 int width, int height,
96 bool isOpaque) {
bsalomon@google.come97f0852011-06-17 13:10:25 +000097 return this->onCreateCompatibleDevice(config, width, height,
98 isOpaque, kGeneral_Usage);
99}
100
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000101SkBaseDevice* SkBaseDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config,
102 int width, int height,
103 bool isOpaque) {
bsalomon@google.come97f0852011-06-17 13:10:25 +0000104 return this->onCreateCompatibleDevice(config, width, height,
105 isOpaque, kSaveLayer_Usage);
106}
107
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000108SkBaseDevice* SkBitmapDevice::onCreateCompatibleDevice(SkBitmap::Config config,
109 int width, int height,
110 bool isOpaque,
111 Usage usage) {
112 return SkNEW_ARGS(SkBitmapDevice,(config, width, height, isOpaque,
113 this->getDeviceProperties()));
bsalomon@google.come97f0852011-06-17 13:10:25 +0000114}
115
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000116SkMetaData& SkBaseDevice::getMetaData() {
reed@google.coma7d94852011-03-30 21:23:07 +0000117 // metadata users are rare, so we lazily allocate it. If that changes we
118 // can decide to just make it a field in the device (rather than a ptr)
119 if (NULL == fMetaData) {
120 fMetaData = new SkMetaData;
121 }
122 return *fMetaData;
123}
124
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000125void SkBitmapDevice::lockPixels() {
reed@google.com9c49bc32011-07-07 13:42:37 +0000126 if (fBitmap.lockPixelsAreWritable()) {
127 fBitmap.lockPixels();
128 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129}
130
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000131void SkBitmapDevice::unlockPixels() {
reed@google.com9c49bc32011-07-07 13:42:37 +0000132 if (fBitmap.lockPixelsAreWritable()) {
133 fBitmap.unlockPixels();
134 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135}
136
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000137const SkBitmap& SkBaseDevice::accessBitmap(bool changePixels) {
138 const SkBitmap& bitmap = this->onAccessBitmap();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139 if (changePixels) {
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000140 bitmap.notifyPixelsChanged();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141 }
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000142 return bitmap;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143}
144
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000145void SkBitmapDevice::getGlobalBounds(SkIRect* bounds) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146 if (bounds) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000147 const SkIPoint& origin = this->getOrigin();
148 bounds->setXYWH(origin.x(), origin.y(),
reed@google.comd51bfa02011-08-30 15:56:11 +0000149 fBitmap.width(), fBitmap.height());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150 }
151}
152
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000153void SkBitmapDevice::clear(SkColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000154 fBitmap.eraseColor(color);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155}
156
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000157const SkBitmap& SkBitmapDevice::onAccessBitmap() {
158 return fBitmap;
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000159}
160
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000161bool SkBitmapDevice::canHandleImageFilter(SkImageFilter*) {
reed@google.com8926b162012-03-23 15:36:36 +0000162 return false;
163}
164
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000165bool SkBitmapDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
166 const SkMatrix& ctm, SkBitmap* result,
167 SkIPoint* offset) {
reed@google.com76dd2772012-01-05 21:15:07 +0000168 return false;
169}
170
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000171bool SkBitmapDevice::allowImageFilter(SkImageFilter*) {
reed@google.comb55deeb2012-01-06 14:43:09 +0000172 return true;
173}
174
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175///////////////////////////////////////////////////////////////////////////////
176
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000177bool SkBaseDevice::readPixels(SkBitmap* bitmap, int x, int y,
178 SkCanvas::Config8888 config8888) {
bsalomon@google.comc6980972011-11-02 19:57:21 +0000179 if (SkBitmap::kARGB_8888_Config != bitmap->config() ||
180 NULL != bitmap->getTexture()) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000181 return false;
182 }
183
bsalomon@google.comc6980972011-11-02 19:57:21 +0000184 const SkBitmap& src = this->accessBitmap(false);
185
186 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(),
187 bitmap->height());
188 SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height());
189 if (!srcRect.intersect(devbounds)) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000190 return false;
191 }
192
193 SkBitmap tmp;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000194 SkBitmap* bmp;
195 if (bitmap->isNull()) {
196 tmp.setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(),
197 bitmap->height());
198 if (!tmp.allocPixels()) {
199 return false;
200 }
201 bmp = &tmp;
202 } else {
203 bmp = bitmap;
bsalomon@google.com1a8ddf02011-11-02 19:34:16 +0000204 }
bsalomon@google.comace7bd52011-11-02 19:39:51 +0000205
bsalomon@google.comc6980972011-11-02 19:57:21 +0000206 SkIRect subrect = srcRect;
207 subrect.offset(-x, -y);
208 SkBitmap bmpSubset;
209 bmp->extractSubset(&bmpSubset, subrect);
210
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000211 bool result = this->onReadPixels(bmpSubset,
212 srcRect.fLeft,
213 srcRect.fTop,
214 config8888);
bsalomon@google.comc6980972011-11-02 19:57:21 +0000215 if (result && bmp == &tmp) {
216 tmp.swap(*bitmap);
217 }
218 return result;
219}
220
commit-bot@chromium.org5dc14c12013-07-15 13:00:45 +0000221#if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000222 const SkCanvas::Config8888 SkBaseDevice::kPMColorAlias =
commit-bot@chromium.org5dc14c12013-07-15 13:00:45 +0000223 SkCanvas::kBGRA_Premul_Config8888;
224#elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000225 const SkCanvas::Config8888 SkBaseDevice::kPMColorAlias =
commit-bot@chromium.org5dc14c12013-07-15 13:00:45 +0000226 SkCanvas::kRGBA_Premul_Config8888;
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000227#else
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000228 const SkCanvas::Config8888 SkBaseDevice::kPMColorAlias =
commit-bot@chromium.org5dc14c12013-07-15 13:00:45 +0000229 (SkCanvas::Config8888) -1;
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000230#endif
231
bsalomon@google.comd58a1cd2011-11-10 20:57:43 +0000232#include <SkConfig8888.h>
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000233
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000234bool SkBitmapDevice::onReadPixels(const SkBitmap& bitmap,
235 int x, int y,
236 SkCanvas::Config8888 config8888) {
bsalomon@google.com910267d2011-11-02 20:06:25 +0000237 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
238 SkASSERT(!bitmap.isNull());
239 SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
bsalomon@google.comc6980972011-11-02 19:57:21 +0000240
bsalomon@google.com910267d2011-11-02 20:06:25 +0000241 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(),
242 bitmap.height());
bsalomon@google.comc6980972011-11-02 19:57:21 +0000243 const SkBitmap& src = this->accessBitmap(false);
244
245 SkBitmap subset;
246 if (!src.extractSubset(&subset, srcRect)) {
247 return false;
248 }
249 if (SkBitmap::kARGB_8888_Config != subset.config()) {
250 // It'd be preferable to do this directly to bitmap.
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000251 subset.copyTo(&subset, SkBitmap::kARGB_8888_Config);
bsalomon@google.comc6980972011-11-02 19:57:21 +0000252 }
bsalomon@google.com910267d2011-11-02 20:06:25 +0000253 SkAutoLockPixels alp(bitmap);
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000254 uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
bsalomon@google.comfb0d7412012-02-22 21:25:34 +0000255 SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset);
bsalomon@google.com6850eab2011-11-03 20:29:47 +0000256 return true;
reed@android.comf2b98d62010-12-20 18:26:13 +0000257}
258
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000259void SkBitmapDevice::writePixels(const SkBitmap& bitmap,
260 int x, int y,
261 SkCanvas::Config8888 config8888) {
bsalomon@google.comd58a1cd2011-11-10 20:57:43 +0000262 if (bitmap.isNull() || bitmap.getTexture()) {
263 return;
264 }
265 const SkBitmap* sprite = &bitmap;
266 // check whether we have to handle a config8888 that doesn't match SkPMColor
267 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
268 SkCanvas::kNative_Premul_Config8888 != config8888 &&
269 kPMColorAlias != config8888) {
270
271 // We're going to have to convert from a config8888 to the native config
272 // First we clip to the device bounds.
273 SkBitmap dstBmp = this->accessBitmap(true);
274 SkIRect spriteRect = SkIRect::MakeXYWH(x, y,
275 bitmap.width(), bitmap.height());
276 SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height());
277 if (!spriteRect.intersect(devRect)) {
278 return;
279 }
280
281 // write directly to the device if it has pixels and is SkPMColor
282 bool drawSprite;
283 if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) {
284 // we can write directly to the dst when doing the conversion
285 dstBmp.extractSubset(&dstBmp, spriteRect);
286 drawSprite = false;
287 } else {
288 // we convert to a temporary bitmap and draw that as a sprite
289 dstBmp.setConfig(SkBitmap::kARGB_8888_Config,
290 spriteRect.width(),
291 spriteRect.height());
292 if (!dstBmp.allocPixels()) {
293 return;
294 }
295 drawSprite = true;
296 }
297
298 // copy pixels to dstBmp and convert from config8888 to native config.
299 SkAutoLockPixels alp(bitmap);
300 uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x,
301 spriteRect.fTop - y);
302 SkCopyConfig8888ToBitmap(dstBmp,
303 srcPixels,
304 bitmap.rowBytes(),
305 config8888);
306
307 if (drawSprite) {
308 // we've clipped the sprite when we made a copy
309 x = spriteRect.fLeft;
310 y = spriteRect.fTop;
311 sprite = &dstBmp;
312 } else {
313 return;
314 }
315 }
316
reed@android.comf2b98d62010-12-20 18:26:13 +0000317 SkPaint paint;
318 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
bsalomon@google.com405d0f42012-08-29 21:26:13 +0000319 SkRasterClip clip(SkIRect::MakeWH(fBitmap.width(), fBitmap.height()));
320 SkDraw draw;
321 draw.fRC = &clip;
322 draw.fClip = &clip.bwRgn();
323 draw.fBitmap = &fBitmap; // canvas should have already called accessBitmap
324 draw.fMatrix = &SkMatrix::I();
325 this->drawSprite(draw, *sprite, x, y, paint);
reed@android.comf2b98d62010-12-20 18:26:13 +0000326}
327
328///////////////////////////////////////////////////////////////////////////////
329
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000330void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 draw.drawPaint(paint);
332}
333
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000334void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
335 const SkPoint pts[], const SkPaint& paint) {
epoger@google.comb58772f2013-03-08 09:09:10 +0000336 CHECK_FOR_NODRAW_ANNOTATION(paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 draw.drawPoints(mode, count, pts, paint);
338}
339
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000340void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
reed@google.comb0a34d82012-07-11 19:57:55 +0000341 CHECK_FOR_NODRAW_ANNOTATION(paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 draw.drawRect(r, paint);
343}
344
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000345void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000346 CHECK_FOR_NODRAW_ANNOTATION(paint);
347
348 SkPath path;
349 path.addOval(oval);
reed@google.comf1867572013-02-12 15:44:10 +0000350 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
351 // required to override drawOval.
352 this->drawPath(draw, path, paint, NULL, true);
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000353}
354
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000355void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +0000356 CHECK_FOR_NODRAW_ANNOTATION(paint);
357
358 SkPath path;
359 path.addRRect(rrect);
360 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
361 // required to override drawRRect.
362 this->drawPath(draw, path, paint, NULL, true);
363}
364
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000365void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
366 const SkPaint& paint, const SkMatrix* prePathMatrix,
367 bool pathIsMutable) {
reed@google.comb0a34d82012-07-11 19:57:55 +0000368 CHECK_FOR_NODRAW_ANNOTATION(paint);
reed@android.comf2b98d62010-12-20 18:26:13 +0000369 draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370}
371
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000372void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
373 const SkMatrix& matrix, const SkPaint& paint) {
robertphillips@google.com9bf380c2013-07-25 12:10:42 +0000374 draw.drawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375}
376
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000377void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
378 const SkRect* src, const SkRect& dst,
379 const SkPaint& paint,
380 SkCanvas::DrawBitmapRectFlags flags) {
reed@google.com33535f32012-09-25 15:37:50 +0000381 SkMatrix matrix;
382 SkRect bitmapBounds, tmpSrc, tmpDst;
383 SkBitmap tmpBitmap;
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +0000384
reed@google.com6f547242013-01-16 15:15:24 +0000385 bitmapBounds.isetWH(bitmap.width(), bitmap.height());
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +0000386
reed@google.com33535f32012-09-25 15:37:50 +0000387 // Compute matrix from the two rectangles
388 if (src) {
389 tmpSrc = *src;
390 } else {
391 tmpSrc = bitmapBounds;
392 }
393 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +0000394
reed@google.com33535f32012-09-25 15:37:50 +0000395 const SkRect* dstPtr = &dst;
396 const SkBitmap* bitmapPtr = &bitmap;
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +0000397
reed@google.com33535f32012-09-25 15:37:50 +0000398 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
399 // needed (if the src was clipped). No check needed if src==null.
400 if (src) {
401 if (!bitmapBounds.contains(*src)) {
402 if (!tmpSrc.intersect(bitmapBounds)) {
403 return; // nothing to draw
404 }
405 // recompute dst, based on the smaller tmpSrc
406 matrix.mapRect(&tmpDst, tmpSrc);
407 dstPtr = &tmpDst;
408 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +0000409
reed@google.com33535f32012-09-25 15:37:50 +0000410 // since we may need to clamp to the borders of the src rect within
411 // the bitmap, we extract a subset.
412 SkIRect srcIR;
413 tmpSrc.roundOut(&srcIR);
414 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
415 return;
416 }
417 bitmapPtr = &tmpBitmap;
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +0000418
reed@google.com33535f32012-09-25 15:37:50 +0000419 // Since we did an extract, we need to adjust the matrix accordingly
420 SkScalar dx = 0, dy = 0;
421 if (srcIR.fLeft > 0) {
422 dx = SkIntToScalar(srcIR.fLeft);
423 }
424 if (srcIR.fTop > 0) {
425 dy = SkIntToScalar(srcIR.fTop);
426 }
427 if (dx || dy) {
428 matrix.preTranslate(dx, dy);
429 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +0000430
reed@google.com3c95d5b2013-01-15 20:57:45 +0000431 SkRect extractedBitmapBounds;
reed@google.com6f547242013-01-16 15:15:24 +0000432 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
reed@google.com3c95d5b2013-01-15 20:57:45 +0000433 if (extractedBitmapBounds == tmpSrc) {
434 // no fractional part in src, we can just call drawBitmap
435 goto USE_DRAWBITMAP;
436 }
reed@google.com6f547242013-01-16 15:15:24 +0000437 } else {
438 USE_DRAWBITMAP:
reed@google.com3c95d5b2013-01-15 20:57:45 +0000439 // We can go faster by just calling drawBitmap, which will concat the
440 // matrix with the CTM, and try to call drawSprite if it can. If not,
441 // it will make a shader and call drawRect, as we do below.
robertphillips@google.com9bf380c2013-07-25 12:10:42 +0000442 this->drawBitmap(draw, *bitmapPtr, matrix, paint);
reed@google.com3c95d5b2013-01-15 20:57:45 +0000443 return;
444 }
skia.committer@gmail.comff21c2e2013-01-16 07:05:56 +0000445
reed@google.com33535f32012-09-25 15:37:50 +0000446 // construct a shader, so we can call drawRect with the dst
447 SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
448 SkShader::kClamp_TileMode,
449 SkShader::kClamp_TileMode);
450 if (NULL == s) {
451 return;
452 }
453 s->setLocalMatrix(matrix);
454
455 SkPaint paintWithShader(paint);
456 paintWithShader.setStyle(SkPaint::kFill_Style);
457 paintWithShader.setShader(s)->unref();
458
459 // Call ourself, in case the subclass wanted to share this setup code
460 // but handle the drawRect code themselves.
461 this->drawRect(draw, *dstPtr, paintWithShader);
462}
463
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000464void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
465 int x, int y, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466 draw.drawSprite(bitmap, x, y, paint);
467}
468
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000469void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
470 SkScalar x, SkScalar y, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000471 draw.drawText((const char*)text, len, x, y, paint);
472}
473
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000474void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
475 const SkScalar xpos[], SkScalar y,
476 int scalarsPerPos, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000477 draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
478}
479
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000480void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text,
481 size_t len, const SkPath& path,
482 const SkMatrix* matrix,
483 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000484 draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
485}
486
djsollen@google.com56c69772011-11-08 19:00:26 +0000487#ifdef SK_BUILD_FOR_ANDROID
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000488void SkBitmapDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
489 const SkPoint pos[], const SkPaint& paint,
490 const SkPath& path, const SkMatrix* matrix) {
djsollen@google.comcd9d69b2011-03-14 20:30:14 +0000491 draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix);
492}
493#endif
494
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000495void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
496 int vertexCount,
497 const SkPoint verts[], const SkPoint textures[],
498 const SkColor colors[], SkXfermode* xmode,
499 const uint16_t indices[], int indexCount,
500 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000501 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
502 indices, indexCount, paint);
503}
504
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000505void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
506 int x, int y, const SkPaint& paint) {
reed@google.com76dd2772012-01-05 21:15:07 +0000507 const SkBitmap& src = device->accessBitmap(false);
508 draw.drawSprite(src, x, y, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509}
510
reed@android.comf2b98d62010-12-20 18:26:13 +0000511///////////////////////////////////////////////////////////////////////////////
512
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000513bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
reed@google.com6fc3c1f2011-09-30 20:31:25 +0000514 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
reed@google.comf67e4cf2011-03-15 20:56:58 +0000515 // we're cool with the paint as is
516 return false;
517 }
518
519 if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
reed@google.comf67e4cf2011-03-15 20:56:58 +0000520 paint.getRasterizer() ||
reed@google.comf67e4cf2011-03-15 20:56:58 +0000521 paint.getPathEffect() ||
522 paint.isFakeBoldText() ||
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +0000523 paint.getStyle() != SkPaint::kFill_Style ||
524 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
reed@google.comf67e4cf2011-03-15 20:56:58 +0000525 // turn off lcd
526 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
527 flags->fHinting = paint.getHinting();
528 return true;
529 }
530 // we're cool with the paint as is
531 return false;
532}