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 8 #include "SkColorPriv.h" 9 #include "SkConfig8888.h" 10 #include "SkData.h" 11 #include "SkMask.h" 12 #include "SkPixmap.h" 13 #include "SkUtils.h" 14 #include "SkPM4f.h" 15 16 void SkAutoPixmapUnlock::reset(const SkPixmap& pm, void (*unlock)(void*), void* ctx) { 17 SkASSERT(pm.addr() != nullptr); 18 19 this->unlock(); 20 fPixmap = pm; 21 fUnlockProc = unlock; 22 fUnlockContext = ctx; 23 fIsLocked = true; 24 } 25 26 ///////////////////////////////////////////////////////////////////////////////////////////////// 27 28 void SkPixmap::reset() { 29 fPixels = nullptr; 30 fCTable = nullptr; 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 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()), 48 src.fImage, src.fRowBytes, nullptr); 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 } 61 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 67 const void* pixels = nullptr; 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 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 } 81 if (nullptr == dstPixels || dstRB < requestedDstInfo.minRowBytes()) { 82 return false; 83 } 84 if (0 == requestedDstInfo.width() || 0 == requestedDstInfo.height()) { 85 return false; 86 } 87 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 } 92 93 // the intersect may have shrunk info's logical size 94 const SkImageInfo dstInfo = requestedDstInfo.makeWH(srcR.width(), srcR.height()); 95 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 } 111 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 { 121 if (nullptr == fPixels) { 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(); 137 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; 165 166 // make rgb premultiplied 167 if (255 != a) { 168 r = SkMulDiv255Round(r, a); 169 g = SkMulDiv255Round(g, a); 170 b = SkMulDiv255Round(b, a); 171 } 172 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); 189 190 if (255 != a && kPremul_SkAlphaType == this->alphaType()) { 191 r = SkMulDiv255Round(r, a); 192 g = SkMulDiv255Round(g, a); 193 b = SkMulDiv255Round(b, a); 194 } 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 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 211 #include "SkNx.h" 212 #include "SkHalf.h" 213 214 static void sk_memset64(uint64_t dst[], uint64_t value, int count) { 215 for (int i = 0; i < count; ++i) { 216 dst[i] = value; 217 } 218 } 219 220 bool SkPixmap::erase(const SkColor4f& origColor, const SkIRect* subset) const { 221 SkPixmap pm; 222 if (subset) { 223 if (!this->extractSubset(&pm, *subset)) { 224 return false; 225 } 226 } else { 227 pm = *this; 228 } 229 230 const SkColor4f color = origColor.pin(); 231 232 if (kRGBA_F16_SkColorType != pm.colorType()) { 233 Sk4f c4 = Sk4f::Load(color.vec()); 234 SkColor c; 235 (c4 * Sk4f(255) + Sk4f(0.5f)).store(&c); 236 return pm.erase(c); 237 } 238 239 const uint64_t half4 = color.premul().toF16(); 240 for (int y = 0; y < pm.height(); ++y) { 241 sk_memset64(pm.writable_addr64(0, y), half4, pm.width()); 242 } 243 return true; 244 } 245 246 #include "SkBitmap.h" 247 #include "SkCanvas.h" 248 #include "SkSurface.h" 249 #include "SkXfermode.h" 250 251 bool SkPixmap::scalePixels(const SkPixmap& dst, SkFilterQuality quality) const { 252 // Can't do anthing with empty src or dst 253 if (this->width() <= 0 || this->height() <= 0 || dst.width() <= 0 || dst.height() <= 0) { 254 return false; 255 } 256 257 // no scaling involved? 258 if (dst.width() == this->width() && dst.height() == this->height()) { 259 return this->readPixels(dst); 260 } 261 262 SkBitmap bitmap; 263 if (!bitmap.installPixels(*this)) { 264 return false; 265 } 266 bitmap.setIsVolatile(true); // so we don't try to cache it 267 268 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterDirect(dst.info(), dst.writable_addr(), 269 dst.rowBytes())); 270 if (!surface) { 271 return false; 272 } 273 274 SkPaint paint; 275 paint.setFilterQuality(quality); 276 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 277 surface->getCanvas()->drawBitmapRect(bitmap, SkRect::MakeIWH(dst.width(), dst.height()), 278 &paint); 279 return true; 280 } 281 282 ////////////////////////////////////////////////////////////////////////////////////////////////// 283 284 SkAutoPixmapStorage::SkAutoPixmapStorage() : fStorage(nullptr) {} 285 286 SkAutoPixmapStorage::~SkAutoPixmapStorage() { 287 this->freeStorage(); 288 } 289 290 bool SkAutoPixmapStorage::tryAlloc(const SkImageInfo& info) { 291 this->freeStorage(); 292 293 size_t rb = info.minRowBytes(); 294 size_t size = info.getSafeSize(rb); 295 if (0 == size) { 296 return false; 297 } 298 void* pixels = sk_malloc_flags(size, 0); 299 if (nullptr == pixels) { 300 return false; 301 } 302 this->reset(info, pixels, rb); 303 fStorage = pixels; 304 return true; 305 } 306 307 void SkAutoPixmapStorage::alloc(const SkImageInfo& info) { 308 if (!this->tryAlloc(info)) { 309 sk_throw(); 310 } 311 } 312 313 const SkData* SkAutoPixmapStorage::detachPixelsAsData() { 314 if (!fStorage) { 315 return nullptr; 316 } 317 318 const SkData* data = SkData::NewFromMalloc(fStorage, this->getSafeSize()); 319 fStorage = nullptr; 320 this->INHERITED::reset(); 321 322 return data; 323 } 324