LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkPixmap.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 33 228 14.5 %
Date: 2017-07-14 16:53:18 Functions: 4 13 30.8 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "SkBitmap.h"
       9             : #include "SkCanvas.h"
      10             : #include "SkColorPriv.h"
      11             : #include "SkConvertPixels.h"
      12             : #include "SkData.h"
      13             : #include "SkImageInfoPriv.h"
      14             : #include "SkHalf.h"
      15             : #include "SkMask.h"
      16             : #include "SkNx.h"
      17             : #include "SkPM4f.h"
      18             : #include "SkPixmap.h"
      19             : #include "SkReadPixelsRec.h"
      20             : #include "SkSurface.h"
      21             : #include "SkUtils.h"
      22             : 
      23         152 : void SkAutoPixmapUnlock::reset(const SkPixmap& pm, void (*unlock)(void*), void* ctx) {
      24         152 :     SkASSERT(pm.addr() != nullptr);
      25             : 
      26         152 :     this->unlock();
      27         152 :     fPixmap = pm;
      28         152 :     fUnlockProc = unlock;
      29         152 :     fUnlockContext = ctx;
      30         152 :     fIsLocked = true;
      31         152 : }
      32             : 
      33             : /////////////////////////////////////////////////////////////////////////////////////////////////
      34             : 
      35         141 : void SkPixmap::reset() {
      36         141 :     fPixels = nullptr;
      37         141 :     fCTable = nullptr;
      38         141 :     fRowBytes = 0;
      39         141 :     fInfo = SkImageInfo::MakeUnknown();
      40         141 : }
      41             : 
      42         918 : void SkPixmap::reset(const SkImageInfo& info, const void* addr, size_t rowBytes, SkColorTable* ct) {
      43         918 :     if (addr) {
      44         918 :         SkASSERT(info.validRowBytes(rowBytes));
      45             :     }
      46         918 :     fPixels = addr;
      47         918 :     fCTable = ct;
      48         918 :     fRowBytes = rowBytes;
      49         918 :     fInfo = info;
      50         918 : }
      51             : 
      52           0 : bool SkPixmap::reset(const SkMask& src) {
      53           0 :     if (SkMask::kA8_Format == src.fFormat) {
      54           0 :         this->reset(SkImageInfo::MakeA8(src.fBounds.width(), src.fBounds.height()),
      55           0 :                     src.fImage, src.fRowBytes, nullptr);
      56           0 :         return true;
      57             :     }
      58           0 :     this->reset();
      59           0 :     return false;
      60             : }
      61             : 
      62           0 : void SkPixmap::setColorSpace(sk_sp<SkColorSpace> cs) {
      63           0 :     fInfo = fInfo.makeColorSpace(std::move(cs));
      64           0 : }
      65             : 
      66          36 : bool SkPixmap::extractSubset(SkPixmap* result, const SkIRect& subset) const {
      67             :     SkIRect srcRect, r;
      68          36 :     srcRect.set(0, 0, this->width(), this->height());
      69          36 :     if (!r.intersect(srcRect, subset)) {
      70           0 :         return false;   // r is empty (i.e. no intersection)
      71             :     }
      72             : 
      73             :     // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have
      74             :     // exited above.
      75          36 :     SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width()));
      76          36 :     SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height()));
      77             : 
      78          36 :     const void* pixels = nullptr;
      79          36 :     if (fPixels) {
      80          36 :         const size_t bpp = fInfo.bytesPerPixel();
      81          36 :         pixels = (const uint8_t*)fPixels + r.fTop * fRowBytes + r.fLeft * bpp;
      82             :     }
      83          36 :     result->reset(fInfo.makeWH(r.width(), r.height()), pixels, fRowBytes, fCTable);
      84          36 :     return true;
      85             : }
      86             : 
      87           0 : bool SkPixmap::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, int x, int y)
      88             : const {
      89           0 :     if (!SkImageInfoValidConversion(dstInfo, fInfo)) {
      90           0 :         return false;
      91             :     }
      92             : 
      93           0 :     SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, x, y);
      94           0 :     if (!rec.trim(fInfo.width(), fInfo.height())) {
      95           0 :         return false;
      96             :     }
      97             : 
      98           0 :     const void* srcPixels = this->addr(rec.fX, rec.fY);
      99           0 :     const SkImageInfo srcInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
     100           0 :     SkConvertPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, srcInfo, srcPixels, this->rowBytes(),
     101           0 :                     this->ctable(), SkTransferFunctionBehavior::kRespect);
     102           0 :     return true;
     103             : }
     104             : 
     105           0 : static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) {
     106           0 :     unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) |
     107           0 :     (SkR32To4444(r) << SK_R4444_SHIFT) |
     108           0 :     (SkG32To4444(g) << SK_G4444_SHIFT) |
     109           0 :     (SkB32To4444(b) << SK_B4444_SHIFT);
     110           0 :     return SkToU16(pixel);
     111             : }
     112             : 
     113           0 : bool SkPixmap::erase(SkColor color, const SkIRect& inArea) const {
     114           0 :     if (nullptr == fPixels) {
     115           0 :         return false;
     116             :     }
     117             :     SkIRect area;
     118           0 :     if (!area.intersect(this->bounds(), inArea)) {
     119           0 :         return false;
     120             :     }
     121             : 
     122           0 :     U8CPU a = SkColorGetA(color);
     123           0 :     U8CPU r = SkColorGetR(color);
     124           0 :     U8CPU g = SkColorGetG(color);
     125           0 :     U8CPU b = SkColorGetB(color);
     126             : 
     127           0 :     int height = area.height();
     128           0 :     const int width = area.width();
     129           0 :     const int rowBytes = this->rowBytes();
     130             : 
     131           0 :     switch (this->colorType()) {
     132             :         case kGray_8_SkColorType: {
     133           0 :             if (255 != a) {
     134           0 :                 r = SkMulDiv255Round(r, a);
     135           0 :                 g = SkMulDiv255Round(g, a);
     136           0 :                 b = SkMulDiv255Round(b, a);
     137             :             }
     138           0 :             int gray = SkComputeLuminance(r, g, b);
     139           0 :             uint8_t* p = this->writable_addr8(area.fLeft, area.fTop);
     140           0 :             while (--height >= 0) {
     141           0 :                 memset(p, gray, width);
     142           0 :                 p += rowBytes;
     143             :             }
     144           0 :             break;
     145             :         }
     146             :         case kAlpha_8_SkColorType: {
     147           0 :             uint8_t* p = this->writable_addr8(area.fLeft, area.fTop);
     148           0 :             while (--height >= 0) {
     149           0 :                 memset(p, a, width);
     150           0 :                 p += rowBytes;
     151             :             }
     152           0 :             break;
     153             :         }
     154             :         case kARGB_4444_SkColorType:
     155             :         case kRGB_565_SkColorType: {
     156           0 :             uint16_t* p = this->writable_addr16(area.fLeft, area.fTop);
     157             :             uint16_t v;
     158             : 
     159             :             // make rgb premultiplied
     160           0 :             if (255 != a) {
     161           0 :                 r = SkMulDiv255Round(r, a);
     162           0 :                 g = SkMulDiv255Round(g, a);
     163           0 :                 b = SkMulDiv255Round(b, a);
     164             :             }
     165             : 
     166           0 :             if (kARGB_4444_SkColorType == this->colorType()) {
     167           0 :                 v = pack_8888_to_4444(a, r, g, b);
     168             :             } else {
     169           0 :                 v = SkPackRGB16(r >> (8 - SK_R16_BITS),
     170             :                                 g >> (8 - SK_G16_BITS),
     171           0 :                                 b >> (8 - SK_B16_BITS));
     172             :             }
     173           0 :             while (--height >= 0) {
     174           0 :                 sk_memset16(p, v, width);
     175           0 :                 p = (uint16_t*)((char*)p + rowBytes);
     176             :             }
     177           0 :             break;
     178             :         }
     179             :         case kBGRA_8888_SkColorType:
     180             :         case kRGBA_8888_SkColorType: {
     181           0 :             uint32_t* p = this->writable_addr32(area.fLeft, area.fTop);
     182             : 
     183           0 :             if (255 != a && kPremul_SkAlphaType == this->alphaType()) {
     184           0 :                 r = SkMulDiv255Round(r, a);
     185           0 :                 g = SkMulDiv255Round(g, a);
     186           0 :                 b = SkMulDiv255Round(b, a);
     187             :             }
     188           0 :             uint32_t v = kRGBA_8888_SkColorType == this->colorType()
     189           0 :                              ? SkPackARGB_as_RGBA(a, r, g, b)
     190           0 :                              : SkPackARGB_as_BGRA(a, r, g, b);
     191             : 
     192           0 :             while (--height >= 0) {
     193           0 :                 sk_memset32(p, v, width);
     194           0 :                 p = (uint32_t*)((char*)p + rowBytes);
     195             :             }
     196           0 :             break;
     197             :         }
     198             :         case kRGBA_F16_SkColorType:
     199             :             // The colorspace is unspecified, so assume linear just like getColor().
     200           0 :             this->erase(SkColor4f{(1 / 255.0f) * r,
     201           0 :                                   (1 / 255.0f) * g,
     202           0 :                                   (1 / 255.0f) * b,
     203           0 :                                   (1 / 255.0f) * a}, &area);
     204           0 :             break;
     205             :         default:
     206           0 :             return false; // no change, so don't call notifyPixelsChanged()
     207             :     }
     208           0 :     return true;
     209             : }
     210             : 
     211           0 : bool SkPixmap::erase(const SkColor4f& origColor, const SkIRect* subset) const {
     212           0 :     SkPixmap pm;
     213           0 :     if (subset) {
     214           0 :         if (!this->extractSubset(&pm, *subset)) {
     215           0 :             return false;
     216             :         }
     217             :     } else {
     218           0 :         pm = *this;
     219             :     }
     220             : 
     221           0 :     const SkColor4f color = origColor.pin();
     222             : 
     223           0 :     if (kRGBA_F16_SkColorType != pm.colorType()) {
     224           0 :         return pm.erase(color.toSkColor());
     225             :     }
     226             : 
     227           0 :     const uint64_t half4 = color.premul().toF16();
     228           0 :     for (int y = 0; y < pm.height(); ++y) {
     229           0 :         sk_memset64(pm.writable_addr64(0, y), half4, pm.width());
     230             :     }
     231           0 :     return true;
     232             : }
     233             : 
     234           0 : bool SkPixmap::scalePixels(const SkPixmap& dst, SkFilterQuality quality) const {
     235             :     // Can't do anthing with empty src or dst
     236           0 :     if (this->width() <= 0 || this->height() <= 0 || dst.width() <= 0 || dst.height() <= 0) {
     237           0 :         return false;
     238             :     }
     239             : 
     240             :     // no scaling involved?
     241           0 :     if (dst.width() == this->width() && dst.height() == this->height()) {
     242           0 :         return this->readPixels(dst);
     243             :     }
     244             : 
     245           0 :     SkBitmap bitmap;
     246           0 :     if (!bitmap.installPixels(*this)) {
     247           0 :         return false;
     248             :     }
     249           0 :     bitmap.setIsVolatile(true); // so we don't try to cache it
     250             : 
     251           0 :     auto surface(SkSurface::MakeRasterDirect(dst.info(), dst.writable_addr(), dst.rowBytes()));
     252           0 :     if (!surface) {
     253           0 :         return false;
     254             :     }
     255             : 
     256           0 :     SkPaint paint;
     257           0 :     paint.setFilterQuality(quality);
     258           0 :     paint.setBlendMode(SkBlendMode::kSrc);
     259           0 :     surface->getCanvas()->drawBitmapRect(bitmap, SkRect::MakeIWH(dst.width(), dst.height()),
     260           0 :                                          &paint);
     261           0 :     return true;
     262             : }
     263             : 
     264             : //////////////////////////////////////////////////////////////////////////////////////////////////
     265             : 
     266           0 : SkColor SkPixmap::getColor(int x, int y) const {
     267           0 :     SkASSERT(this->addr());
     268           0 :     SkASSERT((unsigned)x < (unsigned)this->width());
     269           0 :     SkASSERT((unsigned)y < (unsigned)this->height());
     270           0 :     switch (this->colorType()) {
     271             :         case kGray_8_SkColorType: {
     272           0 :             uint8_t value = *this->addr8(x, y);
     273           0 :             return SkColorSetRGB(value, value, value);
     274             :         }
     275             :         case kAlpha_8_SkColorType: {
     276           0 :             return SkColorSetA(0, *this->addr8(x, y));
     277             :         }
     278             :         case kIndex_8_SkColorType: {
     279           0 :             SkASSERT(this->ctable());
     280           0 :             SkPMColor pmColor = (*this->ctable())[*this->addr8(x, y)];
     281           0 :             return SkUnPreMultiply::PMColorToColor(pmColor);
     282             :         }
     283             :         case kRGB_565_SkColorType: {
     284           0 :             return SkPixel16ToColor(*this->addr16(x, y));
     285             :         }
     286             :         case kARGB_4444_SkColorType: {
     287           0 :             uint16_t value = *this->addr16(x, y);
     288           0 :             SkPMColor c = SkPixel4444ToPixel32(value);
     289           0 :             return SkUnPreMultiply::PMColorToColor(c);
     290             :         }
     291             :         case kBGRA_8888_SkColorType: {
     292           0 :             uint32_t value = *this->addr32(x, y);
     293           0 :             SkPMColor c = SkSwizzle_BGRA_to_PMColor(value);
     294           0 :             return SkUnPreMultiply::PMColorToColor(c);
     295             :         }
     296             :         case kRGBA_8888_SkColorType: {
     297           0 :             uint32_t value = *this->addr32(x, y);
     298           0 :             SkPMColor c = SkSwizzle_RGBA_to_PMColor(value);
     299           0 :             return SkUnPreMultiply::PMColorToColor(c);
     300             :         }
     301             :         case kRGBA_F16_SkColorType: {
     302             :              const uint64_t* addr =
     303           0 :                  (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x;
     304           0 :              Sk4f p4 = SkHalfToFloat_finite_ftz(*addr);
     305           0 :              if (p4[3]) {
     306           0 :                  float inva = 1 / p4[3];
     307           0 :                  p4 = p4 * Sk4f(inva, inva, inva, 1);
     308             :              }
     309             :              SkColor c;
     310           0 :              SkNx_cast<uint8_t>(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c);
     311             :              // p4 is RGBA, but we want BGRA, so we need to swap next
     312           0 :              return SkSwizzle_RB(c);
     313             :         }
     314             :         default:
     315           0 :             SkDEBUGFAIL("");
     316           0 :             return SkColorSetARGB(0, 0, 0, 0);
     317             :     }
     318             : }
     319             : 
     320           0 : bool SkPixmap::computeIsOpaque() const {
     321           0 :     const int height = this->height();
     322           0 :     const int width = this->width();
     323             : 
     324           0 :     switch (this->colorType()) {
     325             :         case kAlpha_8_SkColorType: {
     326           0 :             unsigned a = 0xFF;
     327           0 :             for (int y = 0; y < height; ++y) {
     328           0 :                 const uint8_t* row = this->addr8(0, y);
     329           0 :                 for (int x = 0; x < width; ++x) {
     330           0 :                     a &= row[x];
     331             :                 }
     332           0 :                 if (0xFF != a) {
     333           0 :                     return false;
     334             :                 }
     335             :             }
     336           0 :             return true;
     337             :         } break;
     338             :         case kIndex_8_SkColorType: {
     339           0 :             const SkColorTable* ctable = this->ctable();
     340           0 :             if (nullptr == ctable) {
     341           0 :                 return false;
     342             :             }
     343           0 :             const SkPMColor* table = ctable->readColors();
     344           0 :             SkPMColor c = (SkPMColor)~0;
     345           0 :             for (int i = ctable->count() - 1; i >= 0; --i) {
     346           0 :                 c &= table[i];
     347             :             }
     348           0 :             return 0xFF == SkGetPackedA32(c);
     349             :         } break;
     350             :         case kRGB_565_SkColorType:
     351             :         case kGray_8_SkColorType:
     352           0 :             return true;
     353             :             break;
     354             :         case kARGB_4444_SkColorType: {
     355           0 :             unsigned c = 0xFFFF;
     356           0 :             for (int y = 0; y < height; ++y) {
     357           0 :                 const SkPMColor16* row = this->addr16(0, y);
     358           0 :                 for (int x = 0; x < width; ++x) {
     359           0 :                     c &= row[x];
     360             :                 }
     361           0 :                 if (0xF != SkGetPackedA4444(c)) {
     362           0 :                     return false;
     363             :                 }
     364             :             }
     365           0 :             return true;
     366             :         } break;
     367             :         case kBGRA_8888_SkColorType:
     368             :         case kRGBA_8888_SkColorType: {
     369           0 :             SkPMColor c = (SkPMColor)~0;
     370           0 :             for (int y = 0; y < height; ++y) {
     371           0 :                 const SkPMColor* row = this->addr32(0, y);
     372           0 :                 for (int x = 0; x < width; ++x) {
     373           0 :                     c &= row[x];
     374             :                 }
     375           0 :                 if (0xFF != SkGetPackedA32(c)) {
     376           0 :                     return false;
     377             :                 }
     378             :             }
     379           0 :             return true;
     380             :         }
     381             :         case kRGBA_F16_SkColorType: {
     382           0 :             const SkHalf* row = (const SkHalf*)this->addr();
     383           0 :             for (int y = 0; y < height; ++y) {
     384           0 :                 for (int x = 0; x < width; ++x) {
     385           0 :                     if (row[4 * x + 3] < SK_Half1) {
     386           0 :                         return false;
     387             :                     }
     388             :                 }
     389           0 :                 row += this->rowBytes() >> 1;
     390             :             }
     391           0 :             return true;
     392             :         }
     393             :         default:
     394           0 :             break;
     395             :     }
     396           0 :     return false;
     397             : }

Generated by: LCOV version 1.13