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