| OLD | NEW | 
|    1 /* |    1 /* | 
|    2  * Copyright 2013 Google Inc. |    2  * Copyright 2013 Google Inc. | 
|    3  * |    3  * | 
|    4  * Use of this source code is governed by a BSD-style license that can be |    4  * Use of this source code is governed by a BSD-style license that can be | 
|    5  * found in the LICENSE file. |    5  * found in the LICENSE file. | 
|    6  */ |    6  */ | 
|    7  |    7  | 
|    8 #include "SkMipMap.h" |    8 #include "SkMipMap.h" | 
|    9 #include "SkBitmap.h" |    9 #include "SkBitmap.h" | 
|   10 #include "SkColorPriv.h" |   10 #include "SkColorPriv.h" | 
|   11  |   11  | 
|   12 #ifdef SK_SUPPORT_LEGACY_MIPLEVEL_BUILDER |  | 
|   13  |  | 
|   14 static void downsample32_nocheck(void* dst, int, int, const void* srcPtr, const 
     SkPixmap& srcPM) { |  | 
|   15     const uint32_t* p = static_cast<const uint32_t*>(srcPtr); |  | 
|   16     const uint32_t* baseP = p; |  | 
|   17     uint32_t c, ag, rb; |  | 
|   18  |  | 
|   19     c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF; |  | 
|   20     p += 1; |  | 
|   21  |  | 
|   22     c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; |  | 
|   23  |  | 
|   24     p = baseP; |  | 
|   25     p += srcPM.rowBytes() >> 2; |  | 
|   26  |  | 
|   27     c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; |  | 
|   28     p += 1; |  | 
|   29  |  | 
|   30     c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; |  | 
|   31  |  | 
|   32     *(uint32_t*)dst = ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00); |  | 
|   33 } |  | 
|   34  |  | 
|   35 static void downsample32_check(void* dst, int x, int y, const void* srcPtr, cons
     t SkPixmap& srcPM) { |  | 
|   36     const uint32_t* p = static_cast<const uint32_t*>(srcPtr); |  | 
|   37     const uint32_t* baseP = p; |  | 
|   38  |  | 
|   39     x <<= 1; |  | 
|   40     y <<= 1; |  | 
|   41     SkASSERT(srcPM.addr32(x, y) == p); |  | 
|   42  |  | 
|   43     SkPMColor c, ag, rb; |  | 
|   44  |  | 
|   45     c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF; |  | 
|   46     if (x < srcPM.width() - 1) { |  | 
|   47         p += 1; |  | 
|   48     } |  | 
|   49     c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; |  | 
|   50  |  | 
|   51     p = baseP; |  | 
|   52     if (y < srcPM.height() - 1) { |  | 
|   53         p += srcPM.rowBytes() >> 2; |  | 
|   54     } |  | 
|   55     c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; |  | 
|   56     if (x < srcPM.width() - 1) { |  | 
|   57         p += 1; |  | 
|   58     } |  | 
|   59     c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; |  | 
|   60  |  | 
|   61     *((uint32_t*)dst) = ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00); |  | 
|   62 } |  | 
|   63  |  | 
|   64 static inline uint32_t expand16(U16CPU c) { |  | 
|   65     return (c & ~SK_G16_MASK_IN_PLACE) | ((c & SK_G16_MASK_IN_PLACE) << 16); |  | 
|   66 } |  | 
|   67  |  | 
|   68 // returns dirt in the top 16bits, but we don't care, since we only |  | 
|   69 // store the low 16bits. |  | 
|   70 static inline U16CPU pack16(uint32_t c) { |  | 
|   71     return (c & ~SK_G16_MASK_IN_PLACE) | ((c >> 16) & SK_G16_MASK_IN_PLACE); |  | 
|   72 } |  | 
|   73  |  | 
|   74 static void downsample16(void* dst, int x, int y, const void* srcPtr, const SkPi
     xmap& srcPM) { |  | 
|   75     const uint16_t* p = static_cast<const uint16_t*>(srcPtr); |  | 
|   76     const uint16_t* baseP = p; |  | 
|   77  |  | 
|   78     x <<= 1; |  | 
|   79     y <<= 1; |  | 
|   80     SkASSERT(srcPM.addr16(x, y) == p); |  | 
|   81  |  | 
|   82     SkPMColor c; |  | 
|   83  |  | 
|   84     c = expand16(*p); |  | 
|   85     if (x < srcPM.width() - 1) { |  | 
|   86         p += 1; |  | 
|   87     } |  | 
|   88     c += expand16(*p); |  | 
|   89  |  | 
|   90     p = baseP; |  | 
|   91     if (y < srcPM.height() - 1) { |  | 
|   92         p += srcPM.rowBytes() >> 1; |  | 
|   93     } |  | 
|   94     c += expand16(*p); |  | 
|   95     if (x < srcPM.width() - 1) { |  | 
|   96         p += 1; |  | 
|   97     } |  | 
|   98     c += expand16(*p); |  | 
|   99  |  | 
|  100     *((uint16_t*)dst) = (uint16_t)pack16(c >> 2); |  | 
|  101 } |  | 
|  102  |  | 
|  103 static uint32_t expand4444(U16CPU c) { |  | 
|  104     return (c & 0xF0F) | ((c & ~0xF0F) << 12); |  | 
|  105 } |  | 
|  106  |  | 
|  107 static U16CPU collaps4444(uint32_t c) { |  | 
|  108     return (c & 0xF0F) | ((c >> 12) & ~0xF0F); |  | 
|  109 } |  | 
|  110  |  | 
|  111 static void downsample4444(void* dst, int x, int y, const void* srcPtr, const Sk
     Pixmap& srcPM) { |  | 
|  112     const uint16_t* p = static_cast<const uint16_t*>(srcPtr); |  | 
|  113     const uint16_t* baseP = p; |  | 
|  114  |  | 
|  115     x <<= 1; |  | 
|  116     y <<= 1; |  | 
|  117     SkASSERT(srcPM.addr16(x, y) == p); |  | 
|  118  |  | 
|  119     uint32_t c; |  | 
|  120  |  | 
|  121     c = expand4444(*p); |  | 
|  122     if (x < srcPM.width() - 1) { |  | 
|  123         p += 1; |  | 
|  124     } |  | 
|  125     c += expand4444(*p); |  | 
|  126  |  | 
|  127     p = baseP; |  | 
|  128     if (y < srcPM.height() - 1) { |  | 
|  129         p += srcPM.rowBytes() >> 1; |  | 
|  130     } |  | 
|  131     c += expand4444(*p); |  | 
|  132     if (x < srcPM.width() - 1) { |  | 
|  133         p += 1; |  | 
|  134     } |  | 
|  135     c += expand4444(*p); |  | 
|  136  |  | 
|  137     *((uint16_t*)dst) = (uint16_t)collaps4444(c >> 2); |  | 
|  138 } |  | 
|  139  |  | 
|  140 static void downsample8_nocheck(void* dst, int, int, const void* srcPtr, const S
     kPixmap& srcPM) { |  | 
|  141     const size_t rb = srcPM.rowBytes(); |  | 
|  142     const uint8_t* p = static_cast<const uint8_t*>(srcPtr); |  | 
|  143     *(uint8_t*)dst = (p[0] + p[1] + p[rb] + p[rb + 1]) >> 2; |  | 
|  144 } |  | 
|  145  |  | 
|  146 static void downsample8_check(void* dst, int x, int y, const void* srcPtr, const
      SkPixmap& srcPM) { |  | 
|  147     const uint8_t* p = static_cast<const uint8_t*>(srcPtr); |  | 
|  148     const uint8_t* baseP = p; |  | 
|  149  |  | 
|  150     x <<= 1; |  | 
|  151     y <<= 1; |  | 
|  152     SkASSERT(srcPM.addr8(x, y) == p); |  | 
|  153  |  | 
|  154     unsigned c = *p; |  | 
|  155     if (x < srcPM.width() - 1) { |  | 
|  156         p += 1; |  | 
|  157     } |  | 
|  158     c += *p; |  | 
|  159  |  | 
|  160     p = baseP; |  | 
|  161     if (y < srcPM.height() - 1) { |  | 
|  162         p += srcPM.rowBytes(); |  | 
|  163     } |  | 
|  164     c += *p; |  | 
|  165     if (x < srcPM.width() - 1) { |  | 
|  166         p += 1; |  | 
|  167     } |  | 
|  168     c += *p; |  | 
|  169  |  | 
|  170     *(uint8_t*)dst = c >> 2; |  | 
|  171 } |  | 
|  172  |  | 
|  173 size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) { |  | 
|  174     if (levelCount < 0) { |  | 
|  175         return 0; |  | 
|  176     } |  | 
|  177     int64_t size = sk_64_mul(levelCount + 1, sizeof(Level)) + pixelSize; |  | 
|  178     if (!sk_64_isS32(size)) { |  | 
|  179         return 0; |  | 
|  180     } |  | 
|  181     return sk_64_asS32(size); |  | 
|  182 } |  | 
|  183  |  | 
|  184 typedef void SkDownSampleProc(void*, int x, int y, const void* srcPtr, const SkP
     ixmap& srcPM); |  | 
|  185  |  | 
|  186 SkMipMap* SkMipMap::Build(const SkPixmap& src, SkDiscardableFactoryProc fact) { |  | 
|  187     SkDownSampleProc* proc_nocheck, *proc_check; |  | 
|  188  |  | 
|  189     const SkColorType ct = src.colorType(); |  | 
|  190     const SkAlphaType at = src.alphaType(); |  | 
|  191     switch (ct) { |  | 
|  192         case kRGBA_8888_SkColorType: |  | 
|  193         case kBGRA_8888_SkColorType: |  | 
|  194             proc_check = downsample32_check; |  | 
|  195             proc_nocheck = downsample32_nocheck; |  | 
|  196             break; |  | 
|  197         case kRGB_565_SkColorType: |  | 
|  198             proc_check = downsample16; |  | 
|  199             proc_nocheck = proc_check; |  | 
|  200             break; |  | 
|  201         case kARGB_4444_SkColorType: |  | 
|  202             proc_check = downsample4444; |  | 
|  203             proc_nocheck = proc_check; |  | 
|  204             break; |  | 
|  205         case kAlpha_8_SkColorType: |  | 
|  206         case kGray_8_SkColorType: |  | 
|  207             proc_check = downsample8_check; |  | 
|  208             proc_nocheck = downsample8_nocheck; |  | 
|  209             break; |  | 
|  210         default: |  | 
|  211             return nullptr; // don't build mipmaps for any other colortypes (yet
     ) |  | 
|  212     } |  | 
|  213  |  | 
|  214     // whip through our loop to compute the exact size needed |  | 
|  215     size_t  size = 0; |  | 
|  216     int     countLevels = 0; |  | 
|  217     { |  | 
|  218         int width = src.width(); |  | 
|  219         int height = src.height(); |  | 
|  220         for (;;) { |  | 
|  221             width >>= 1; |  | 
|  222             height >>= 1; |  | 
|  223             if (0 == width || 0 == height) { |  | 
|  224                 break; |  | 
|  225             } |  | 
|  226             size += SkColorTypeMinRowBytes(ct, width) * height; |  | 
|  227             countLevels += 1; |  | 
|  228         } |  | 
|  229     } |  | 
|  230     if (0 == countLevels) { |  | 
|  231         return nullptr; |  | 
|  232     } |  | 
|  233  |  | 
|  234     size_t storageSize = SkMipMap::AllocLevelsSize(countLevels, size); |  | 
|  235     if (0 == storageSize) { |  | 
|  236         return nullptr; |  | 
|  237     } |  | 
|  238  |  | 
|  239     SkMipMap* mipmap; |  | 
|  240     if (fact) { |  | 
|  241         SkDiscardableMemory* dm = fact(storageSize); |  | 
|  242         if (nullptr == dm) { |  | 
|  243             return nullptr; |  | 
|  244         } |  | 
|  245         mipmap = new SkMipMap(storageSize, dm); |  | 
|  246     } else { |  | 
|  247         mipmap = new SkMipMap(sk_malloc_throw(storageSize), storageSize); |  | 
|  248     } |  | 
|  249  |  | 
|  250     // init |  | 
|  251     mipmap->fCount = countLevels; |  | 
|  252     mipmap->fLevels = (Level*)mipmap->writable_data(); |  | 
|  253  |  | 
|  254     Level* levels = mipmap->fLevels; |  | 
|  255     uint8_t*    baseAddr = (uint8_t*)&levels[countLevels]; |  | 
|  256     uint8_t*    addr = baseAddr; |  | 
|  257     int         width = src.width(); |  | 
|  258     int         height = src.height(); |  | 
|  259     uint32_t    rowBytes; |  | 
|  260     SkPixmap    srcPM(src); |  | 
|  261  |  | 
|  262     for (int i = 0; i < countLevels; ++i) { |  | 
|  263         width >>= 1; |  | 
|  264         height >>= 1; |  | 
|  265         rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); |  | 
|  266  |  | 
|  267         levels[i].fPixmap = SkPixmap(SkImageInfo::Make(width, height, ct, at), a
     ddr, rowBytes); |  | 
|  268         levels[i].fScale    = (float)width / src.width(); |  | 
|  269  |  | 
|  270         SkPixmap dstPM(SkImageInfo::Make(width, height, ct, at), addr, rowBytes)
     ; |  | 
|  271  |  | 
|  272         const int widthEven = width & ~1; |  | 
|  273         const int heightEven = height & ~1; |  | 
|  274         const size_t pixelSize = srcPM.info().bytesPerPixel(); |  | 
|  275  |  | 
|  276         const void* srcBasePtr = srcPM.addr(); |  | 
|  277         void* dstBasePtr = dstPM.writable_addr(); |  | 
|  278         for (int y = 0; y < heightEven; y++) { |  | 
|  279             const void* srcPtr = srcBasePtr; |  | 
|  280             void* dstPtr = dstBasePtr; |  | 
|  281             for (int x = 0; x < widthEven; x++) { |  | 
|  282                 proc_nocheck(dstPtr, x, y, srcPtr, srcPM); |  | 
|  283                 srcPtr = (char*)srcPtr + pixelSize * 2; |  | 
|  284                 dstPtr = (char*)dstPtr + pixelSize; |  | 
|  285             } |  | 
|  286             if (width & 1) { |  | 
|  287                 proc_check(dstPtr, widthEven, y, srcPtr, srcPM); |  | 
|  288             } |  | 
|  289  |  | 
|  290             srcBasePtr = (char*)srcBasePtr + srcPM.rowBytes() * 2; |  | 
|  291             dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); |  | 
|  292         } |  | 
|  293         if (height & 1) { |  | 
|  294             const void* srcPtr = srcBasePtr; |  | 
|  295             void* dstPtr = dstBasePtr; |  | 
|  296             for (int x = 0; x < width; x++) { |  | 
|  297                 proc_check(dstPtr, x, heightEven, srcPtr, srcPM); |  | 
|  298                 srcPtr = (char*)srcPtr + pixelSize * 2; |  | 
|  299                 dstPtr = (char*)dstPtr + pixelSize; |  | 
|  300             } |  | 
|  301         } |  | 
|  302         srcPM = dstPM; |  | 
|  303         addr += height * rowBytes; |  | 
|  304     } |  | 
|  305     SkASSERT(addr == baseAddr + size); |  | 
|  306      |  | 
|  307     return mipmap; |  | 
|  308 } |  | 
|  309  |  | 
|  310 #else   // new technique that handles odd dimensions better |  | 
|  311  |  | 
|  312 // |   12 // | 
|  313 // ColorTypeFilter is the "Type" we pass to some downsample template functions. |   13 // ColorTypeFilter is the "Type" we pass to some downsample template functions. | 
|  314 // It controls how we expand a pixel into a large type, with space between each 
     component, |   14 // It controls how we expand a pixel into a large type, with space between each 
     component, | 
|  315 // so we can then perform our simple filter (either box or triangle) and store t
     he intermediates |   15 // so we can then perform our simple filter (either box or triangle) and store t
     he intermediates | 
|  316 // in the expanded type. |   16 // in the expanded type. | 
|  317 // |   17 // | 
|  318  |   18  | 
|  319 struct ColorTypeFilter_8888 { |   19 struct ColorTypeFilter_8888 { | 
|  320     typedef uint32_t Type; |   20     typedef uint32_t Type; | 
|  321     static uint64_t Expand(uint32_t x) { |   21     static uint64_t Expand(uint32_t x) { | 
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  597             srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows |  297             srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows | 
|  598             dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); |  298             dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); | 
|  599         } |  299         } | 
|  600         srcPM = dstPM; |  300         srcPM = dstPM; | 
|  601         addr += height * rowBytes; |  301         addr += height * rowBytes; | 
|  602     } |  302     } | 
|  603     SkASSERT(addr == baseAddr + size); |  303     SkASSERT(addr == baseAddr + size); | 
|  604  |  304  | 
|  605     return mipmap; |  305     return mipmap; | 
|  606 } |  306 } | 
|  607 #endif |  | 
|  608  |  307  | 
|  609 /////////////////////////////////////////////////////////////////////////////// |  308 /////////////////////////////////////////////////////////////////////////////// | 
|  610  |  309  | 
|  611 bool SkMipMap::extractLevel(SkScalar scale, Level* levelPtr) const { |  310 bool SkMipMap::extractLevel(SkScalar scale, Level* levelPtr) const { | 
|  612     if (nullptr == fLevels) { |  311     if (nullptr == fLevels) { | 
|  613         return false; |  312         return false; | 
|  614     } |  313     } | 
|  615  |  314  | 
|  616     if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { |  315     if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { | 
|  617         return false; |  316         return false; | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
|  648         return nullptr; |  347         return nullptr; | 
|  649     } |  348     } | 
|  650     const SkPixmap& srcPixmap = srcUnlocker.pixmap(); |  349     const SkPixmap& srcPixmap = srcUnlocker.pixmap(); | 
|  651     // Try to catch where we might have returned nullptr for src crbug.com/49281
     8 |  350     // Try to catch where we might have returned nullptr for src crbug.com/49281
     8 | 
|  652     if (nullptr == srcPixmap.addr()) { |  351     if (nullptr == srcPixmap.addr()) { | 
|  653         sk_throw(); |  352         sk_throw(); | 
|  654     } |  353     } | 
|  655     return Build(srcPixmap, fact); |  354     return Build(srcPixmap, fact); | 
|  656 } |  355 } | 
|  657  |  356  | 
| OLD | NEW |