reed | 92fc2ae | 2015-05-22 08:06:21 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2015 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 | |
reed | 7aefe03 | 2015-06-08 10:22:22 -0700 | [diff] [blame] | 8 | #include "SkColorPriv.h" |
reed | 95d343f | 2015-05-23 13:21:06 -0700 | [diff] [blame] | 9 | #include "SkConfig8888.h" |
fmalita | 3a94c6c | 2016-02-04 13:09:59 -0800 | [diff] [blame] | 10 | #include "SkData.h" |
reed | 183b57f | 2015-06-05 14:33:17 -0700 | [diff] [blame] | 11 | #include "SkMask.h" |
reed | 92fc2ae | 2015-05-22 08:06:21 -0700 | [diff] [blame] | 12 | #include "SkPixmap.h" |
reed | 7aefe03 | 2015-06-08 10:22:22 -0700 | [diff] [blame] | 13 | #include "SkUtils.h" |
reed | 92fc2ae | 2015-05-22 08:06:21 -0700 | [diff] [blame] | 14 | |
| 15 | void SkAutoPixmapUnlock::reset(const SkPixmap& pm, void (*unlock)(void*), void* ctx) { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 16 | SkASSERT(pm.addr() != nullptr); |
reed | 92fc2ae | 2015-05-22 08:06:21 -0700 | [diff] [blame] | 17 | |
| 18 | this->unlock(); |
| 19 | fPixmap = pm; |
| 20 | fUnlockProc = unlock; |
| 21 | fUnlockContext = ctx; |
| 22 | fIsLocked = true; |
| 23 | } |
reed | 95d343f | 2015-05-23 13:21:06 -0700 | [diff] [blame] | 24 | |
| 25 | ///////////////////////////////////////////////////////////////////////////////////////////////// |
| 26 | |
reed | 884e97c | 2015-05-26 11:31:54 -0700 | [diff] [blame] | 27 | void SkPixmap::reset() { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 28 | fPixels = nullptr; |
| 29 | fCTable = nullptr; |
reed | 884e97c | 2015-05-26 11:31:54 -0700 | [diff] [blame] | 30 | fRowBytes = 0; |
| 31 | fInfo = SkImageInfo::MakeUnknown(); |
| 32 | } |
| 33 | |
| 34 | void SkPixmap::reset(const SkImageInfo& info, const void* addr, size_t rowBytes, SkColorTable* ct) { |
| 35 | if (addr) { |
| 36 | SkASSERT(info.validRowBytes(rowBytes)); |
| 37 | } |
| 38 | fPixels = addr; |
| 39 | fCTable = ct; |
| 40 | fRowBytes = rowBytes; |
| 41 | fInfo = info; |
| 42 | } |
| 43 | |
reed | 183b57f | 2015-06-05 14:33:17 -0700 | [diff] [blame] | 44 | bool SkPixmap::reset(const SkMask& src) { |
| 45 | if (SkMask::kA8_Format == src.fFormat) { |
| 46 | this->reset(SkImageInfo::MakeA8(src.fBounds.width(), src.fBounds.height()), |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 47 | src.fImage, src.fRowBytes, nullptr); |
reed | 183b57f | 2015-06-05 14:33:17 -0700 | [diff] [blame] | 48 | return true; |
| 49 | } |
| 50 | this->reset(); |
| 51 | return false; |
| 52 | } |
| 53 | |
| 54 | bool SkPixmap::extractSubset(SkPixmap* result, const SkIRect& subset) const { |
| 55 | SkIRect srcRect, r; |
| 56 | srcRect.set(0, 0, this->width(), this->height()); |
| 57 | if (!r.intersect(srcRect, subset)) { |
| 58 | return false; // r is empty (i.e. no intersection) |
| 59 | } |
| 60 | |
| 61 | // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have |
| 62 | // exited above. |
| 63 | SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width())); |
| 64 | SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height())); |
| 65 | |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 66 | const void* pixels = nullptr; |
reed | 183b57f | 2015-06-05 14:33:17 -0700 | [diff] [blame] | 67 | if (fPixels) { |
| 68 | const size_t bpp = fInfo.bytesPerPixel(); |
| 69 | pixels = (const uint8_t*)fPixels + r.fTop * fRowBytes + r.fLeft * bpp; |
| 70 | } |
| 71 | result->reset(fInfo.makeWH(r.width(), r.height()), pixels, fRowBytes, fCTable); |
| 72 | return true; |
| 73 | } |
| 74 | |
reed | 95d343f | 2015-05-23 13:21:06 -0700 | [diff] [blame] | 75 | bool SkPixmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB, |
| 76 | int x, int y) const { |
| 77 | if (kUnknown_SkColorType == requestedDstInfo.colorType()) { |
| 78 | return false; |
| 79 | } |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 80 | if (nullptr == dstPixels || dstRB < requestedDstInfo.minRowBytes()) { |
reed | 95d343f | 2015-05-23 13:21:06 -0700 | [diff] [blame] | 81 | return false; |
| 82 | } |
| 83 | if (0 == requestedDstInfo.width() || 0 == requestedDstInfo.height()) { |
| 84 | return false; |
| 85 | } |
| 86 | |
| 87 | SkIRect srcR = SkIRect::MakeXYWH(x, y, requestedDstInfo.width(), requestedDstInfo.height()); |
| 88 | if (!srcR.intersect(0, 0, this->width(), this->height())) { |
| 89 | return false; |
| 90 | } |
| 91 | |
| 92 | // the intersect may have shrunk info's logical size |
| 93 | const SkImageInfo dstInfo = requestedDstInfo.makeWH(srcR.width(), srcR.height()); |
| 94 | |
| 95 | // if x or y are negative, then we have to adjust pixels |
| 96 | if (x > 0) { |
| 97 | x = 0; |
| 98 | } |
| 99 | if (y > 0) { |
| 100 | y = 0; |
| 101 | } |
| 102 | // here x,y are either 0 or negative |
| 103 | dstPixels = ((char*)dstPixels - y * dstRB - x * dstInfo.bytesPerPixel()); |
| 104 | |
| 105 | const SkImageInfo srcInfo = this->info().makeWH(dstInfo.width(), dstInfo.height()); |
| 106 | const void* srcPixels = this->addr(srcR.x(), srcR.y()); |
| 107 | return SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRB, |
| 108 | srcInfo, srcPixels, this->rowBytes(), this->ctable()); |
| 109 | } |
reed | 183b57f | 2015-06-05 14:33:17 -0700 | [diff] [blame] | 110 | |
reed | 7aefe03 | 2015-06-08 10:22:22 -0700 | [diff] [blame] | 111 | static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) { |
| 112 | unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) | |
| 113 | (SkR32To4444(r) << SK_R4444_SHIFT) | |
| 114 | (SkG32To4444(g) << SK_G4444_SHIFT) | |
| 115 | (SkB32To4444(b) << SK_B4444_SHIFT); |
| 116 | return SkToU16(pixel); |
| 117 | } |
| 118 | |
| 119 | bool SkPixmap::erase(SkColor color, const SkIRect& inArea) const { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 120 | if (nullptr == fPixels) { |
reed | 7aefe03 | 2015-06-08 10:22:22 -0700 | [diff] [blame] | 121 | return false; |
| 122 | } |
| 123 | SkIRect area; |
| 124 | if (!area.intersect(this->bounds(), inArea)) { |
| 125 | return false; |
| 126 | } |
| 127 | |
| 128 | U8CPU a = SkColorGetA(color); |
| 129 | U8CPU r = SkColorGetR(color); |
| 130 | U8CPU g = SkColorGetG(color); |
| 131 | U8CPU b = SkColorGetB(color); |
| 132 | |
| 133 | int height = area.height(); |
| 134 | const int width = area.width(); |
| 135 | const int rowBytes = this->rowBytes(); |
| 136 | |
| 137 | switch (this->colorType()) { |
| 138 | case kGray_8_SkColorType: { |
| 139 | if (255 != a) { |
| 140 | r = SkMulDiv255Round(r, a); |
| 141 | g = SkMulDiv255Round(g, a); |
| 142 | b = SkMulDiv255Round(b, a); |
| 143 | } |
| 144 | int gray = SkComputeLuminance(r, g, b); |
| 145 | uint8_t* p = this->writable_addr8(area.fLeft, area.fTop); |
| 146 | while (--height >= 0) { |
| 147 | memset(p, gray, width); |
| 148 | p += rowBytes; |
| 149 | } |
| 150 | break; |
| 151 | } |
| 152 | case kAlpha_8_SkColorType: { |
| 153 | uint8_t* p = this->writable_addr8(area.fLeft, area.fTop); |
| 154 | while (--height >= 0) { |
| 155 | memset(p, a, width); |
| 156 | p += rowBytes; |
| 157 | } |
| 158 | break; |
| 159 | } |
| 160 | case kARGB_4444_SkColorType: |
| 161 | case kRGB_565_SkColorType: { |
| 162 | uint16_t* p = this->writable_addr16(area.fLeft, area.fTop); |
| 163 | uint16_t v; |
| 164 | |
| 165 | // make rgb premultiplied |
| 166 | if (255 != a) { |
benjaminwagner | a1bb8e0 | 2015-12-11 14:08:58 -0800 | [diff] [blame] | 167 | r = SkMulDiv255Round(r, a); |
| 168 | g = SkMulDiv255Round(g, a); |
| 169 | b = SkMulDiv255Round(b, a); |
reed | 7aefe03 | 2015-06-08 10:22:22 -0700 | [diff] [blame] | 170 | } |
| 171 | |
| 172 | if (kARGB_4444_SkColorType == this->colorType()) { |
| 173 | v = pack_8888_to_4444(a, r, g, b); |
| 174 | } else { |
| 175 | v = SkPackRGB16(r >> (8 - SK_R16_BITS), |
| 176 | g >> (8 - SK_G16_BITS), |
| 177 | b >> (8 - SK_B16_BITS)); |
| 178 | } |
| 179 | while (--height >= 0) { |
| 180 | sk_memset16(p, v, width); |
| 181 | p = (uint16_t*)((char*)p + rowBytes); |
| 182 | } |
| 183 | break; |
| 184 | } |
| 185 | case kBGRA_8888_SkColorType: |
| 186 | case kRGBA_8888_SkColorType: { |
| 187 | uint32_t* p = this->writable_addr32(area.fLeft, area.fTop); |
| 188 | |
| 189 | if (255 != a && kPremul_SkAlphaType == this->alphaType()) { |
benjaminwagner | a1bb8e0 | 2015-12-11 14:08:58 -0800 | [diff] [blame] | 190 | r = SkMulDiv255Round(r, a); |
| 191 | g = SkMulDiv255Round(g, a); |
| 192 | b = SkMulDiv255Round(b, a); |
reed | 7aefe03 | 2015-06-08 10:22:22 -0700 | [diff] [blame] | 193 | } |
benjaminwagner | a1bb8e0 | 2015-12-11 14:08:58 -0800 | [diff] [blame] | 194 | uint32_t v = kRGBA_8888_SkColorType == this->colorType() |
| 195 | ? SkPackARGB_as_RGBA(a, r, g, b) |
| 196 | : SkPackARGB_as_BGRA(a, r, g, b); |
| 197 | |
reed | 7aefe03 | 2015-06-08 10:22:22 -0700 | [diff] [blame] | 198 | while (--height >= 0) { |
| 199 | sk_memset32(p, v, width); |
| 200 | p = (uint32_t*)((char*)p + rowBytes); |
| 201 | } |
| 202 | break; |
| 203 | } |
| 204 | default: |
| 205 | return false; // no change, so don't call notifyPixelsChanged() |
| 206 | } |
| 207 | return true; |
| 208 | } |
| 209 | |
reed | 0955303 | 2015-11-23 12:32:16 -0800 | [diff] [blame] | 210 | #include "SkBitmap.h" |
| 211 | #include "SkCanvas.h" |
| 212 | #include "SkSurface.h" |
| 213 | #include "SkXfermode.h" |
| 214 | |
| 215 | bool SkPixmap::scalePixels(const SkPixmap& dst, SkFilterQuality quality) const { |
| 216 | // Can't do anthing with empty src or dst |
| 217 | if (this->width() <= 0 || this->height() <= 0 || dst.width() <= 0 || dst.height() <= 0) { |
| 218 | return false; |
| 219 | } |
| 220 | |
| 221 | // no scaling involved? |
| 222 | if (dst.width() == this->width() && dst.height() == this->height()) { |
| 223 | return this->readPixels(dst); |
| 224 | } |
| 225 | |
| 226 | SkBitmap bitmap; |
halcanary | e36ec87 | 2015-12-09 11:36:59 -0800 | [diff] [blame] | 227 | if (!bitmap.installPixels(*this)) { |
reed | 0955303 | 2015-11-23 12:32:16 -0800 | [diff] [blame] | 228 | return false; |
| 229 | } |
| 230 | bitmap.setIsVolatile(true); // so we don't try to cache it |
| 231 | |
| 232 | SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterDirect(dst.info(), dst.writable_addr(), |
| 233 | dst.rowBytes())); |
| 234 | if (!surface) { |
| 235 | return false; |
| 236 | } |
| 237 | |
| 238 | SkPaint paint; |
| 239 | paint.setFilterQuality(quality); |
| 240 | paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
| 241 | surface->getCanvas()->drawBitmapRect(bitmap, SkRect::MakeIWH(dst.width(), dst.height()), |
| 242 | &paint); |
| 243 | return true; |
| 244 | } |
| 245 | |
reed | 183b57f | 2015-06-05 14:33:17 -0700 | [diff] [blame] | 246 | ////////////////////////////////////////////////////////////////////////////////////////////////// |
| 247 | |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 248 | SkAutoPixmapStorage::SkAutoPixmapStorage() : fStorage(nullptr) {} |
reed | 183b57f | 2015-06-05 14:33:17 -0700 | [diff] [blame] | 249 | |
| 250 | SkAutoPixmapStorage::~SkAutoPixmapStorage() { |
reed | 7aefe03 | 2015-06-08 10:22:22 -0700 | [diff] [blame] | 251 | this->freeStorage(); |
reed | 183b57f | 2015-06-05 14:33:17 -0700 | [diff] [blame] | 252 | } |
| 253 | |
| 254 | bool SkAutoPixmapStorage::tryAlloc(const SkImageInfo& info) { |
reed | 7aefe03 | 2015-06-08 10:22:22 -0700 | [diff] [blame] | 255 | this->freeStorage(); |
reed | 183b57f | 2015-06-05 14:33:17 -0700 | [diff] [blame] | 256 | |
| 257 | size_t rb = info.minRowBytes(); |
| 258 | size_t size = info.getSafeSize(rb); |
| 259 | if (0 == size) { |
| 260 | return false; |
| 261 | } |
reed | 7aefe03 | 2015-06-08 10:22:22 -0700 | [diff] [blame] | 262 | void* pixels = sk_malloc_flags(size, 0); |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 263 | if (nullptr == pixels) { |
reed | 183b57f | 2015-06-05 14:33:17 -0700 | [diff] [blame] | 264 | return false; |
| 265 | } |
reed | 7aefe03 | 2015-06-08 10:22:22 -0700 | [diff] [blame] | 266 | this->reset(info, pixels, rb); |
| 267 | fStorage = pixels; |
reed | 183b57f | 2015-06-05 14:33:17 -0700 | [diff] [blame] | 268 | return true; |
| 269 | } |
| 270 | |
| 271 | void SkAutoPixmapStorage::alloc(const SkImageInfo& info) { |
| 272 | if (!this->tryAlloc(info)) { |
| 273 | sk_throw(); |
| 274 | } |
| 275 | } |
fmalita | 3a94c6c | 2016-02-04 13:09:59 -0800 | [diff] [blame] | 276 | |
| 277 | const SkData* SkAutoPixmapStorage::detachPixelsAsData() { |
| 278 | if (!fStorage) { |
| 279 | return nullptr; |
| 280 | } |
| 281 | |
| 282 | const SkData* data = SkData::NewFromMalloc(fStorage, this->getSafeSize()); |
| 283 | fStorage = nullptr; |
| 284 | this->INHERITED::reset(); |
| 285 | |
| 286 | return data; |
| 287 | } |