1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2007 The Android Open Source Project 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/core/SkMask.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/private/SkMalloc.h" 11cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 12cb93a386Sopenharmony_ci#include "src/core/SkSafeMath.h" 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_ci#include <climits> 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_ci/** returns the product if it is positive and fits in 31 bits. Otherwise this 17cb93a386Sopenharmony_ci returns 0. 18cb93a386Sopenharmony_ci */ 19cb93a386Sopenharmony_cistatic int32_t safeMul32(int32_t a, int32_t b) { 20cb93a386Sopenharmony_ci int64_t size = sk_64_mul(a, b); 21cb93a386Sopenharmony_ci if (size > 0 && SkTFitsIn<int32_t>(size)) { 22cb93a386Sopenharmony_ci return size; 23cb93a386Sopenharmony_ci } 24cb93a386Sopenharmony_ci return 0; 25cb93a386Sopenharmony_ci} 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_cisize_t SkMask::computeImageSize() const { 28cb93a386Sopenharmony_ci return safeMul32(fBounds.height(), fRowBytes); 29cb93a386Sopenharmony_ci} 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_cisize_t SkMask::computeTotalImageSize() const { 32cb93a386Sopenharmony_ci size_t size = this->computeImageSize(); 33cb93a386Sopenharmony_ci if (fFormat == SkMask::k3D_Format) { 34cb93a386Sopenharmony_ci size = safeMul32(SkToS32(size), 3); 35cb93a386Sopenharmony_ci } 36cb93a386Sopenharmony_ci return size; 37cb93a386Sopenharmony_ci} 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci/** We explicitly use this allocator for SkBimap pixels, so that we can 40cb93a386Sopenharmony_ci freely assign memory allocated by one class to the other. 41cb93a386Sopenharmony_ci*/ 42cb93a386Sopenharmony_ciuint8_t* SkMask::AllocImage(size_t size, AllocType at) { 43cb93a386Sopenharmony_ci size_t aligned_size = SkSafeMath::Align4(size); 44cb93a386Sopenharmony_ci unsigned flags = SK_MALLOC_THROW; 45cb93a386Sopenharmony_ci if (at == kZeroInit_Alloc) { 46cb93a386Sopenharmony_ci flags |= SK_MALLOC_ZERO_INITIALIZE; 47cb93a386Sopenharmony_ci } 48cb93a386Sopenharmony_ci return static_cast<uint8_t*>(sk_malloc_flags(aligned_size, flags)); 49cb93a386Sopenharmony_ci} 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci/** We explicitly use this allocator for SkBimap pixels, so that we can 52cb93a386Sopenharmony_ci freely assign memory allocated by one class to the other. 53cb93a386Sopenharmony_ci*/ 54cb93a386Sopenharmony_civoid SkMask::FreeImage(void* image) { 55cb93a386Sopenharmony_ci sk_free(image); 56cb93a386Sopenharmony_ci} 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ciSkMask SkMask::PrepareDestination(int radiusX, int radiusY, const SkMask& src) { 59cb93a386Sopenharmony_ci SkSafeMath safe; 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci SkMask dst; 62cb93a386Sopenharmony_ci dst.fImage = nullptr; 63cb93a386Sopenharmony_ci dst.fFormat = SkMask::kA8_Format; 64cb93a386Sopenharmony_ci // dstW = srcW + 2 * radiusX; 65cb93a386Sopenharmony_ci size_t dstW = safe.add(src.fBounds.width(), safe.add(radiusX, radiusX)); 66cb93a386Sopenharmony_ci // dstH = srcH + 2 * radiusY; 67cb93a386Sopenharmony_ci size_t dstH = safe.add(src.fBounds.height(), safe.add(radiusY, radiusY)); 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_ci size_t toAlloc = safe.mul(dstW, dstH); 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci // We can only deal with masks that fit in INT_MAX and sides that fit in int. 72cb93a386Sopenharmony_ci if (!SkTFitsIn<int>(dstW) || !SkTFitsIn<int>(dstH) || toAlloc > INT_MAX || !safe) { 73cb93a386Sopenharmony_ci dst.fBounds.setEmpty(); 74cb93a386Sopenharmony_ci dst.fRowBytes = 0; 75cb93a386Sopenharmony_ci return dst; 76cb93a386Sopenharmony_ci } 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ci dst.fBounds.setWH(SkTo<int>(dstW), SkTo<int>(dstH)); 79cb93a386Sopenharmony_ci dst.fBounds.offset(src.fBounds.x(), src.fBounds.y()); 80cb93a386Sopenharmony_ci dst.fBounds.offset(-radiusX, -radiusY); 81cb93a386Sopenharmony_ci dst.fRowBytes = SkTo<uint32_t>(dstW); 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci if (src.fImage != nullptr) { 84cb93a386Sopenharmony_ci dst.fImage = SkMask::AllocImage(toAlloc); 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci return dst; 88cb93a386Sopenharmony_ci} 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_cistatic const int gMaskFormatToShift[] = { 94cb93a386Sopenharmony_ci ~0, // BW -- not supported 95cb93a386Sopenharmony_ci 0, // A8 96cb93a386Sopenharmony_ci 0, // 3D 97cb93a386Sopenharmony_ci 2, // ARGB32 98cb93a386Sopenharmony_ci 1, // LCD16 99cb93a386Sopenharmony_ci 0, // SDF 100cb93a386Sopenharmony_ci}; 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_cistatic int maskFormatToShift(SkMask::Format format) { 103cb93a386Sopenharmony_ci SkASSERT((unsigned)format < SK_ARRAY_COUNT(gMaskFormatToShift)); 104cb93a386Sopenharmony_ci SkASSERT(SkMask::kBW_Format != format); 105cb93a386Sopenharmony_ci return gMaskFormatToShift[format]; 106cb93a386Sopenharmony_ci} 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_civoid* SkMask::getAddr(int x, int y) const { 109cb93a386Sopenharmony_ci SkASSERT(kBW_Format != fFormat); 110cb93a386Sopenharmony_ci SkASSERT(fBounds.contains(x, y)); 111cb93a386Sopenharmony_ci SkASSERT(fImage); 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci char* addr = (char*)fImage; 114cb93a386Sopenharmony_ci addr += (y - fBounds.fTop) * fRowBytes; 115cb93a386Sopenharmony_ci addr += (x - fBounds.fLeft) << maskFormatToShift(fFormat); 116cb93a386Sopenharmony_ci return addr; 117cb93a386Sopenharmony_ci} 118