epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 1 | |
| 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.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 8 | #include "SkBitmapDevice.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 9 | #include "SkDevice.h" |
bungeman@google.com | 532470f | 2013-01-22 19:25:14 +0000 | [diff] [blame] | 10 | #include "SkDeviceProperties.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 11 | #include "SkDraw.h" |
reed@google.com | 32d25b6 | 2011-12-20 16:19:00 +0000 | [diff] [blame] | 12 | #include "SkImageFilter.h" |
reed@google.com | a7d9485 | 2011-03-30 21:23:07 +0000 | [diff] [blame] | 13 | #include "SkMetaData.h" |
bsalomon@google.com | 405d0f4 | 2012-08-29 21:26:13 +0000 | [diff] [blame] | 14 | #include "SkRasterClip.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 15 | #include "SkRect.h" |
commit-bot@chromium.org | f2bfd54 | 2013-04-25 15:27:00 +0000 | [diff] [blame] | 16 | #include "SkRRect.h" |
reed@google.com | 33535f3 | 2012-09-25 15:37:50 +0000 | [diff] [blame] | 17 | #include "SkShader.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 18 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 19 | SK_DEFINE_INST_COUNT(SkBaseDevice) |
| 20 | SK_DEFINE_INST_COUNT(SkBitmapDevice) |
robertphillips@google.com | 15e9d3e | 2012-06-21 20:25:03 +0000 | [diff] [blame] | 21 | |
mike@reedtribe.org | ea4ac97 | 2011-04-26 11:48:33 +0000 | [diff] [blame] | 22 | /////////////////////////////////////////////////////////////////////////////// |
vandebo@chromium.org | 8c1d88d | 2010-11-11 00:49:41 +0000 | [diff] [blame] | 23 | |
reed@google.com | b0a34d8 | 2012-07-11 19:57:55 +0000 | [diff] [blame] | 24 | #define CHECK_FOR_NODRAW_ANNOTATION(paint) \ |
| 25 | do { if (paint.isNoDrawAnnotation()) { return; } } while (0) |
| 26 | |
| 27 | /////////////////////////////////////////////////////////////////////////////// |
| 28 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 29 | SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) |
| 30 | : fBitmap(bitmap) { |
reed@google.com | 6ba4572 | 2013-06-21 18:30:53 +0000 | [diff] [blame] | 31 | SkASSERT(SkBitmap::kARGB_4444_Config != bitmap.config()); |
bungeman@google.com | 532470f | 2013-01-22 19:25:14 +0000 | [diff] [blame] | 32 | } |
| 33 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 34 | SkBaseDevice::SkBaseDevice() |
| 35 | : fLeakyProperties(SkDeviceProperties::MakeDefault()) |
robertphillips@google.com | 40a1ae4 | 2012-07-13 15:36:15 +0000 | [diff] [blame] | 36 | #ifdef SK_DEBUG |
rmistry@google.com | fbfcd56 | 2012-08-23 18:09:54 +0000 | [diff] [blame] | 37 | , fAttachedToCanvas(false) |
robertphillips@google.com | 40a1ae4 | 2012-07-13 15:36:15 +0000 | [diff] [blame] | 38 | #endif |
| 39 | { |
reed@google.com | 6f8f292 | 2011-03-04 22:27:10 +0000 | [diff] [blame] | 40 | fOrigin.setZero(); |
reed@google.com | af951c9 | 2011-06-16 19:10:39 +0000 | [diff] [blame] | 41 | fMetaData = NULL; |
reed@android.com | f2b98d6 | 2010-12-20 18:26:13 +0000 | [diff] [blame] | 42 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 43 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 44 | SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties) |
| 45 | : SkBaseDevice(deviceProperties) |
| 46 | , fBitmap(bitmap) { |
bungeman@google.com | 532470f | 2013-01-22 19:25:14 +0000 | [diff] [blame] | 47 | } |
| 48 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 49 | SkBaseDevice::SkBaseDevice(const SkDeviceProperties& deviceProperties) |
bungeman@google.com | 532470f | 2013-01-22 19:25:14 +0000 | [diff] [blame] | 50 | : fLeakyProperties(deviceProperties) |
| 51 | #ifdef SK_DEBUG |
| 52 | , fAttachedToCanvas(false) |
robertphillips@google.com | 40a1ae4 | 2012-07-13 15:36:15 +0000 | [diff] [blame] | 53 | #endif |
| 54 | { |
reed@google.com | af951c9 | 2011-06-16 19:10:39 +0000 | [diff] [blame] | 55 | fOrigin.setZero(); |
| 56 | fMetaData = NULL; |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 57 | } |
| 58 | |
| 59 | SkBitmapDevice::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 | |
| 68 | SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque, |
| 69 | const SkDeviceProperties& deviceProperties) |
| 70 | : SkBaseDevice(deviceProperties) { |
reed@google.com | af951c9 | 2011-06-16 19:10:39 +0000 | [diff] [blame] | 71 | |
| 72 | fBitmap.setConfig(config, width, height); |
| 73 | fBitmap.allocPixels(); |
| 74 | fBitmap.setIsOpaque(isOpaque); |
| 75 | if (!isOpaque) { |
junov@google.com | dbfac8a | 2012-12-06 21:47:40 +0000 | [diff] [blame] | 76 | fBitmap.eraseColor(SK_ColorTRANSPARENT); |
reed@google.com | af951c9 | 2011-06-16 19:10:39 +0000 | [diff] [blame] | 77 | } |
| 78 | } |
| 79 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 80 | SkBaseDevice::~SkBaseDevice() { |
reed@google.com | a7d9485 | 2011-03-30 21:23:07 +0000 | [diff] [blame] | 81 | delete fMetaData; |
| 82 | } |
| 83 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 84 | SkBitmapDevice::~SkBitmapDevice() { |
| 85 | } |
| 86 | |
| 87 | void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { |
reed@google.com | 97af1a6 | 2012-08-28 12:19:02 +0000 | [diff] [blame] | 88 | 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.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 94 | SkBaseDevice* SkBaseDevice::createCompatibleDevice(SkBitmap::Config config, |
| 95 | int width, int height, |
| 96 | bool isOpaque) { |
bsalomon@google.com | e97f085 | 2011-06-17 13:10:25 +0000 | [diff] [blame] | 97 | return this->onCreateCompatibleDevice(config, width, height, |
| 98 | isOpaque, kGeneral_Usage); |
| 99 | } |
| 100 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 101 | SkBaseDevice* SkBaseDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config, |
| 102 | int width, int height, |
| 103 | bool isOpaque) { |
bsalomon@google.com | e97f085 | 2011-06-17 13:10:25 +0000 | [diff] [blame] | 104 | return this->onCreateCompatibleDevice(config, width, height, |
| 105 | isOpaque, kSaveLayer_Usage); |
| 106 | } |
| 107 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 108 | SkBaseDevice* 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.com | e97f085 | 2011-06-17 13:10:25 +0000 | [diff] [blame] | 114 | } |
| 115 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 116 | SkMetaData& SkBaseDevice::getMetaData() { |
reed@google.com | a7d9485 | 2011-03-30 21:23:07 +0000 | [diff] [blame] | 117 | // 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.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 125 | void SkBitmapDevice::lockPixels() { |
reed@google.com | 9c49bc3 | 2011-07-07 13:42:37 +0000 | [diff] [blame] | 126 | if (fBitmap.lockPixelsAreWritable()) { |
| 127 | fBitmap.lockPixels(); |
| 128 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 129 | } |
| 130 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 131 | void SkBitmapDevice::unlockPixels() { |
reed@google.com | 9c49bc3 | 2011-07-07 13:42:37 +0000 | [diff] [blame] | 132 | if (fBitmap.lockPixelsAreWritable()) { |
| 133 | fBitmap.unlockPixels(); |
| 134 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 135 | } |
| 136 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 137 | const SkBitmap& SkBaseDevice::accessBitmap(bool changePixels) { |
| 138 | const SkBitmap& bitmap = this->onAccessBitmap(); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 139 | if (changePixels) { |
junov@chromium.org | 1f9767c | 2012-02-07 16:27:57 +0000 | [diff] [blame] | 140 | bitmap.notifyPixelsChanged(); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 141 | } |
junov@chromium.org | 1f9767c | 2012-02-07 16:27:57 +0000 | [diff] [blame] | 142 | return bitmap; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 143 | } |
| 144 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 145 | void SkBitmapDevice::getGlobalBounds(SkIRect* bounds) const { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 146 | if (bounds) { |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 147 | const SkIPoint& origin = this->getOrigin(); |
| 148 | bounds->setXYWH(origin.x(), origin.y(), |
reed@google.com | d51bfa0 | 2011-08-30 15:56:11 +0000 | [diff] [blame] | 149 | fBitmap.width(), fBitmap.height()); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 150 | } |
| 151 | } |
| 152 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 153 | void SkBitmapDevice::clear(SkColor color) { |
bsalomon@google.com | 398109c | 2011-04-14 18:40:27 +0000 | [diff] [blame] | 154 | fBitmap.eraseColor(color); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 155 | } |
| 156 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 157 | const SkBitmap& SkBitmapDevice::onAccessBitmap() { |
| 158 | return fBitmap; |
robertphillips@google.com | 3fffb2e | 2012-10-09 22:30:18 +0000 | [diff] [blame] | 159 | } |
| 160 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 161 | bool SkBitmapDevice::canHandleImageFilter(SkImageFilter*) { |
reed@google.com | 8926b16 | 2012-03-23 15:36:36 +0000 | [diff] [blame] | 162 | return false; |
| 163 | } |
| 164 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 165 | bool SkBitmapDevice::filterImage(SkImageFilter* filter, const SkBitmap& src, |
| 166 | const SkMatrix& ctm, SkBitmap* result, |
| 167 | SkIPoint* offset) { |
reed@google.com | 76dd277 | 2012-01-05 21:15:07 +0000 | [diff] [blame] | 168 | return false; |
| 169 | } |
| 170 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 171 | bool SkBitmapDevice::allowImageFilter(SkImageFilter*) { |
reed@google.com | b55deeb | 2012-01-06 14:43:09 +0000 | [diff] [blame] | 172 | return true; |
| 173 | } |
| 174 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 175 | /////////////////////////////////////////////////////////////////////////////// |
| 176 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 177 | bool SkBaseDevice::readPixels(SkBitmap* bitmap, int x, int y, |
| 178 | SkCanvas::Config8888 config8888) { |
bsalomon@google.com | c698097 | 2011-11-02 19:57:21 +0000 | [diff] [blame] | 179 | if (SkBitmap::kARGB_8888_Config != bitmap->config() || |
| 180 | NULL != bitmap->getTexture()) { |
reed@android.com | f2b98d6 | 2010-12-20 18:26:13 +0000 | [diff] [blame] | 181 | return false; |
| 182 | } |
| 183 | |
bsalomon@google.com | c698097 | 2011-11-02 19:57:21 +0000 | [diff] [blame] | 184 | 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.com | f2b98d6 | 2010-12-20 18:26:13 +0000 | [diff] [blame] | 190 | return false; |
| 191 | } |
| 192 | |
| 193 | SkBitmap tmp; |
bsalomon@google.com | c698097 | 2011-11-02 19:57:21 +0000 | [diff] [blame] | 194 | 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.com | 1a8ddf0 | 2011-11-02 19:34:16 +0000 | [diff] [blame] | 204 | } |
bsalomon@google.com | ace7bd5 | 2011-11-02 19:39:51 +0000 | [diff] [blame] | 205 | |
bsalomon@google.com | c698097 | 2011-11-02 19:57:21 +0000 | [diff] [blame] | 206 | SkIRect subrect = srcRect; |
| 207 | subrect.offset(-x, -y); |
| 208 | SkBitmap bmpSubset; |
| 209 | bmp->extractSubset(&bmpSubset, subrect); |
| 210 | |
bsalomon@google.com | 6850eab | 2011-11-03 20:29:47 +0000 | [diff] [blame] | 211 | bool result = this->onReadPixels(bmpSubset, |
| 212 | srcRect.fLeft, |
| 213 | srcRect.fTop, |
| 214 | config8888); |
bsalomon@google.com | c698097 | 2011-11-02 19:57:21 +0000 | [diff] [blame] | 215 | if (result && bmp == &tmp) { |
| 216 | tmp.swap(*bitmap); |
| 217 | } |
| 218 | return result; |
| 219 | } |
| 220 | |
commit-bot@chromium.org | 5dc14c1 | 2013-07-15 13:00:45 +0000 | [diff] [blame] | 221 | #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A) |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 222 | const SkCanvas::Config8888 SkBaseDevice::kPMColorAlias = |
commit-bot@chromium.org | 5dc14c1 | 2013-07-15 13:00:45 +0000 | [diff] [blame] | 223 | SkCanvas::kBGRA_Premul_Config8888; |
| 224 | #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A) |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 225 | const SkCanvas::Config8888 SkBaseDevice::kPMColorAlias = |
commit-bot@chromium.org | 5dc14c1 | 2013-07-15 13:00:45 +0000 | [diff] [blame] | 226 | SkCanvas::kRGBA_Premul_Config8888; |
bsalomon@google.com | 6850eab | 2011-11-03 20:29:47 +0000 | [diff] [blame] | 227 | #else |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 228 | const SkCanvas::Config8888 SkBaseDevice::kPMColorAlias = |
commit-bot@chromium.org | 5dc14c1 | 2013-07-15 13:00:45 +0000 | [diff] [blame] | 229 | (SkCanvas::Config8888) -1; |
bsalomon@google.com | 6850eab | 2011-11-03 20:29:47 +0000 | [diff] [blame] | 230 | #endif |
| 231 | |
bsalomon@google.com | d58a1cd | 2011-11-10 20:57:43 +0000 | [diff] [blame] | 232 | #include <SkConfig8888.h> |
bsalomon@google.com | 6850eab | 2011-11-03 20:29:47 +0000 | [diff] [blame] | 233 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 234 | bool SkBitmapDevice::onReadPixels(const SkBitmap& bitmap, |
| 235 | int x, int y, |
| 236 | SkCanvas::Config8888 config8888) { |
bsalomon@google.com | 910267d | 2011-11-02 20:06:25 +0000 | [diff] [blame] | 237 | 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.com | c698097 | 2011-11-02 19:57:21 +0000 | [diff] [blame] | 240 | |
bsalomon@google.com | 910267d | 2011-11-02 20:06:25 +0000 | [diff] [blame] | 241 | SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(), |
| 242 | bitmap.height()); |
bsalomon@google.com | c698097 | 2011-11-02 19:57:21 +0000 | [diff] [blame] | 243 | 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.org | 74b4619 | 2012-01-28 01:45:11 +0000 | [diff] [blame] | 251 | subset.copyTo(&subset, SkBitmap::kARGB_8888_Config); |
bsalomon@google.com | c698097 | 2011-11-02 19:57:21 +0000 | [diff] [blame] | 252 | } |
bsalomon@google.com | 910267d | 2011-11-02 20:06:25 +0000 | [diff] [blame] | 253 | SkAutoLockPixels alp(bitmap); |
bsalomon@google.com | 6850eab | 2011-11-03 20:29:47 +0000 | [diff] [blame] | 254 | uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels()); |
bsalomon@google.com | fb0d741 | 2012-02-22 21:25:34 +0000 | [diff] [blame] | 255 | SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset); |
bsalomon@google.com | 6850eab | 2011-11-03 20:29:47 +0000 | [diff] [blame] | 256 | return true; |
reed@android.com | f2b98d6 | 2010-12-20 18:26:13 +0000 | [diff] [blame] | 257 | } |
| 258 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 259 | void SkBitmapDevice::writePixels(const SkBitmap& bitmap, |
| 260 | int x, int y, |
| 261 | SkCanvas::Config8888 config8888) { |
bsalomon@google.com | d58a1cd | 2011-11-10 20:57:43 +0000 | [diff] [blame] | 262 | 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.com | f2b98d6 | 2010-12-20 18:26:13 +0000 | [diff] [blame] | 317 | SkPaint paint; |
| 318 | paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
bsalomon@google.com | 405d0f4 | 2012-08-29 21:26:13 +0000 | [diff] [blame] | 319 | 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.com | f2b98d6 | 2010-12-20 18:26:13 +0000 | [diff] [blame] | 326 | } |
| 327 | |
| 328 | /////////////////////////////////////////////////////////////////////////////// |
| 329 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 330 | void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 331 | draw.drawPaint(paint); |
| 332 | } |
| 333 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 334 | void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, |
| 335 | const SkPoint pts[], const SkPaint& paint) { |
epoger@google.com | b58772f | 2013-03-08 09:09:10 +0000 | [diff] [blame] | 336 | CHECK_FOR_NODRAW_ANNOTATION(paint); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 337 | draw.drawPoints(mode, count, pts, paint); |
| 338 | } |
| 339 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 340 | void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) { |
reed@google.com | b0a34d8 | 2012-07-11 19:57:55 +0000 | [diff] [blame] | 341 | CHECK_FOR_NODRAW_ANNOTATION(paint); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 342 | draw.drawRect(r, paint); |
| 343 | } |
| 344 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 345 | void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { |
jvanverth@google.com | 46d3d39 | 2013-01-22 13:34:01 +0000 | [diff] [blame] | 346 | CHECK_FOR_NODRAW_ANNOTATION(paint); |
| 347 | |
| 348 | SkPath path; |
| 349 | path.addOval(oval); |
reed@google.com | f186757 | 2013-02-12 15:44:10 +0000 | [diff] [blame] | 350 | // 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.com | 46d3d39 | 2013-01-22 13:34:01 +0000 | [diff] [blame] | 353 | } |
| 354 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 355 | void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) { |
commit-bot@chromium.org | f2bfd54 | 2013-04-25 15:27:00 +0000 | [diff] [blame] | 356 | 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.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 365 | void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path, |
| 366 | const SkPaint& paint, const SkMatrix* prePathMatrix, |
| 367 | bool pathIsMutable) { |
reed@google.com | b0a34d8 | 2012-07-11 19:57:55 +0000 | [diff] [blame] | 368 | CHECK_FOR_NODRAW_ANNOTATION(paint); |
reed@android.com | f2b98d6 | 2010-12-20 18:26:13 +0000 | [diff] [blame] | 369 | draw.drawPath(path, paint, prePathMatrix, pathIsMutable); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 370 | } |
| 371 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 372 | void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, |
| 373 | const SkMatrix& matrix, const SkPaint& paint) { |
robertphillips@google.com | 9bf380c | 2013-07-25 12:10:42 +0000 | [diff] [blame] | 374 | draw.drawBitmap(bitmap, matrix, paint); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 375 | } |
| 376 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 377 | void 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.com | 33535f3 | 2012-09-25 15:37:50 +0000 | [diff] [blame] | 381 | SkMatrix matrix; |
| 382 | SkRect bitmapBounds, tmpSrc, tmpDst; |
| 383 | SkBitmap tmpBitmap; |
skia.committer@gmail.com | 7064e9a | 2012-09-26 02:01:18 +0000 | [diff] [blame] | 384 | |
reed@google.com | 6f54724 | 2013-01-16 15:15:24 +0000 | [diff] [blame] | 385 | bitmapBounds.isetWH(bitmap.width(), bitmap.height()); |
skia.committer@gmail.com | 7064e9a | 2012-09-26 02:01:18 +0000 | [diff] [blame] | 386 | |
reed@google.com | 33535f3 | 2012-09-25 15:37:50 +0000 | [diff] [blame] | 387 | // 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.com | 7064e9a | 2012-09-26 02:01:18 +0000 | [diff] [blame] | 394 | |
reed@google.com | 33535f3 | 2012-09-25 15:37:50 +0000 | [diff] [blame] | 395 | const SkRect* dstPtr = &dst; |
| 396 | const SkBitmap* bitmapPtr = &bitmap; |
skia.committer@gmail.com | 7064e9a | 2012-09-26 02:01:18 +0000 | [diff] [blame] | 397 | |
reed@google.com | 33535f3 | 2012-09-25 15:37:50 +0000 | [diff] [blame] | 398 | // 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.com | 7064e9a | 2012-09-26 02:01:18 +0000 | [diff] [blame] | 409 | |
reed@google.com | 33535f3 | 2012-09-25 15:37:50 +0000 | [diff] [blame] | 410 | // 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.com | 7064e9a | 2012-09-26 02:01:18 +0000 | [diff] [blame] | 418 | |
reed@google.com | 33535f3 | 2012-09-25 15:37:50 +0000 | [diff] [blame] | 419 | // 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.com | 7064e9a | 2012-09-26 02:01:18 +0000 | [diff] [blame] | 430 | |
reed@google.com | 3c95d5b | 2013-01-15 20:57:45 +0000 | [diff] [blame] | 431 | SkRect extractedBitmapBounds; |
reed@google.com | 6f54724 | 2013-01-16 15:15:24 +0000 | [diff] [blame] | 432 | extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); |
reed@google.com | 3c95d5b | 2013-01-15 20:57:45 +0000 | [diff] [blame] | 433 | if (extractedBitmapBounds == tmpSrc) { |
| 434 | // no fractional part in src, we can just call drawBitmap |
| 435 | goto USE_DRAWBITMAP; |
| 436 | } |
reed@google.com | 6f54724 | 2013-01-16 15:15:24 +0000 | [diff] [blame] | 437 | } else { |
| 438 | USE_DRAWBITMAP: |
reed@google.com | 3c95d5b | 2013-01-15 20:57:45 +0000 | [diff] [blame] | 439 | // 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.com | 9bf380c | 2013-07-25 12:10:42 +0000 | [diff] [blame] | 442 | this->drawBitmap(draw, *bitmapPtr, matrix, paint); |
reed@google.com | 3c95d5b | 2013-01-15 20:57:45 +0000 | [diff] [blame] | 443 | return; |
| 444 | } |
skia.committer@gmail.com | ff21c2e | 2013-01-16 07:05:56 +0000 | [diff] [blame] | 445 | |
reed@google.com | 33535f3 | 2012-09-25 15:37:50 +0000 | [diff] [blame] | 446 | // 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.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 464 | void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, |
| 465 | int x, int y, const SkPaint& paint) { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 466 | draw.drawSprite(bitmap, x, y, paint); |
| 467 | } |
| 468 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 469 | void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len, |
| 470 | SkScalar x, SkScalar y, const SkPaint& paint) { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 471 | draw.drawText((const char*)text, len, x, y, paint); |
| 472 | } |
| 473 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 474 | void 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.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 477 | draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint); |
| 478 | } |
| 479 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 480 | void 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.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 484 | draw.drawTextOnPath((const char*)text, len, path, matrix, paint); |
| 485 | } |
| 486 | |
djsollen@google.com | 56c6977 | 2011-11-08 19:00:26 +0000 | [diff] [blame] | 487 | #ifdef SK_BUILD_FOR_ANDROID |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 488 | void 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.com | cd9d69b | 2011-03-14 20:30:14 +0000 | [diff] [blame] | 491 | draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix); |
| 492 | } |
| 493 | #endif |
| 494 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 495 | void 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.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 501 | draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode, |
| 502 | indices, indexCount, paint); |
| 503 | } |
| 504 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 505 | void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, |
| 506 | int x, int y, const SkPaint& paint) { |
reed@google.com | 76dd277 | 2012-01-05 21:15:07 +0000 | [diff] [blame] | 507 | const SkBitmap& src = device->accessBitmap(false); |
| 508 | draw.drawSprite(src, x, y, paint); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 509 | } |
| 510 | |
reed@android.com | f2b98d6 | 2010-12-20 18:26:13 +0000 | [diff] [blame] | 511 | /////////////////////////////////////////////////////////////////////////////// |
| 512 | |
robertphillips@google.com | 1f2f338 | 2013-08-29 11:54:56 +0000 | [diff] [blame^] | 513 | bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { |
reed@google.com | 6fc3c1f | 2011-09-30 20:31:25 +0000 | [diff] [blame] | 514 | if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { |
reed@google.com | f67e4cf | 2011-03-15 20:56:58 +0000 | [diff] [blame] | 515 | // we're cool with the paint as is |
| 516 | return false; |
| 517 | } |
| 518 | |
| 519 | if (SkBitmap::kARGB_8888_Config != fBitmap.config() || |
reed@google.com | f67e4cf | 2011-03-15 20:56:58 +0000 | [diff] [blame] | 520 | paint.getRasterizer() || |
reed@google.com | f67e4cf | 2011-03-15 20:56:58 +0000 | [diff] [blame] | 521 | paint.getPathEffect() || |
| 522 | paint.isFakeBoldText() || |
mike@reedtribe.org | e303fcf | 2011-11-17 02:16:43 +0000 | [diff] [blame] | 523 | paint.getStyle() != SkPaint::kFill_Style || |
| 524 | !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) { |
reed@google.com | f67e4cf | 2011-03-15 20:56:58 +0000 | [diff] [blame] | 525 | // 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 | } |