1/* 2 * Copyright 2010 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 "include/private/SkImageInfoPriv.h" 9#include "src/core/SkReadBuffer.h" 10#include "src/core/SkSafeMath.h" 11#include "src/core/SkWriteBuffer.h" 12 13int SkColorTypeBytesPerPixel(SkColorType ct) { 14 switch (ct) { 15 case kUnknown_SkColorType: return 0; 16 case kAlpha_8_SkColorType: return 1; 17 case kRGB_565_SkColorType: return 2; 18 case kARGB_4444_SkColorType: return 2; 19 case kRGBA_8888_SkColorType: return 4; 20 case kBGRA_8888_SkColorType: return 4; 21 case kRGB_888x_SkColorType: return 4; 22 case kRGBA_1010102_SkColorType: return 4; 23 case kRGB_101010x_SkColorType: return 4; 24 case kBGRA_1010102_SkColorType: return 4; 25 case kBGR_101010x_SkColorType: return 4; 26 case kGray_8_SkColorType: return 1; 27 case kRGBA_F16Norm_SkColorType: return 8; 28 case kRGBA_F16_SkColorType: return 8; 29 case kRGBA_F32_SkColorType: return 16; 30 case kR8G8_unorm_SkColorType: return 2; 31 case kA16_unorm_SkColorType: return 2; 32 case kR16G16_unorm_SkColorType: return 4; 33 case kA16_float_SkColorType: return 2; 34 case kR16G16_float_SkColorType: return 4; 35 case kR16G16B16A16_unorm_SkColorType: return 8; 36 case kSRGBA_8888_SkColorType: return 4; 37 } 38 SkUNREACHABLE; 39} 40 41bool SkColorTypeIsAlwaysOpaque(SkColorType ct) { 42 return !(SkColorTypeChannelFlags(ct) & kAlpha_SkColorChannelFlag); 43} 44 45/////////////////////////////////////////////////////////////////////////////////////////////////// 46 47int SkColorInfo::bytesPerPixel() const { return SkColorTypeBytesPerPixel(fColorType); } 48 49int SkColorInfo::shiftPerPixel() const { return SkColorTypeShiftPerPixel(fColorType); } 50 51/////////////////////////////////////////////////////////////////////////////////////////////////// 52 53size_t SkImageInfo::computeOffset(int x, int y, size_t rowBytes) const { 54 SkASSERT((unsigned)x < (unsigned)this->width()); 55 SkASSERT((unsigned)y < (unsigned)this->height()); 56 return SkColorTypeComputeOffset(this->colorType(), x, y, rowBytes); 57} 58 59size_t SkImageInfo::computeByteSize(size_t rowBytes) const { 60 if (0 == this->height()) { 61 return 0; 62 } 63 SkSafeMath safe; 64 size_t bytes = safe.add(safe.mul(safe.addInt(this->height(), -1), rowBytes), 65 safe.mul(this->width(), this->bytesPerPixel())); 66 67 // The CPU backend implements some memory operations on images using instructions that take a 68 // signed 32-bit offset from the base. If we ever make an image larger than that, overflow can 69 // cause us to read/write memory that starts 2GB *before* the buffer. (crbug.com/1264705) 70 constexpr size_t kMaxSigned32BitSize = SK_MaxS32; 71 return (safe.ok() && (bytes <= kMaxSigned32BitSize)) ? bytes : SIZE_MAX; 72} 73 74SkImageInfo SkImageInfo::MakeS32(int width, int height, SkAlphaType at) { 75 return SkImageInfo({width, height}, {kN32_SkColorType, at, SkColorSpace::MakeSRGB()}); 76} 77 78void SkImageInfo::dump(std::string& desc, int depth) const { 79 std::string split(depth, '\t'); 80 desc += split + "\n SkImageInfo:{ \n"; 81 desc += split + "\t fColorSpace: Omit\n"; 82 desc += split + "\t fDimensions:{fWidth:" + std::to_string(fDimensions.fWidth) + 83 " fHeight:" + std::to_string(fDimensions.fHeight) + "}\n"; 84 desc += split + "\t fColorType: " + std::to_string(static_cast<int>(fColorInfo.colorType())) + "\n"; 85 desc += split + "\t fAlphaType: " + std::to_string(static_cast<int>(fColorInfo.alphaType())) + "\n"; 86 desc += split + "}\n"; 87} 88 89#ifdef SK_DEBUG 90void SkImageInfo::validate() const { 91 SkASSERT(fDimensions.width() >= 0); 92 SkASSERT(fDimensions.height() >= 0); 93 SkASSERT(SkColorTypeIsValid(this->colorType())); 94 SkASSERT(SkAlphaTypeIsValid(this->alphaType())); 95} 96#endif 97 98bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType, 99 SkAlphaType* canonical) { 100 switch (colorType) { 101 case kUnknown_SkColorType: 102 alphaType = kUnknown_SkAlphaType; 103 break; 104 case kAlpha_8_SkColorType: // fall-through 105 case kA16_unorm_SkColorType: // fall-through 106 case kA16_float_SkColorType: 107 if (kUnpremul_SkAlphaType == alphaType) { 108 alphaType = kPremul_SkAlphaType; 109 } 110 [[fallthrough]]; 111 case kARGB_4444_SkColorType: 112 case kRGBA_8888_SkColorType: 113 case kSRGBA_8888_SkColorType: 114 case kBGRA_8888_SkColorType: 115 case kRGBA_1010102_SkColorType: 116 case kBGRA_1010102_SkColorType: 117 case kRGBA_F16Norm_SkColorType: 118 case kRGBA_F16_SkColorType: 119 case kRGBA_F32_SkColorType: 120 case kR16G16B16A16_unorm_SkColorType: 121 if (kUnknown_SkAlphaType == alphaType) { 122 return false; 123 } 124 break; 125 case kGray_8_SkColorType: 126 case kR8G8_unorm_SkColorType: 127 case kR16G16_unorm_SkColorType: 128 case kR16G16_float_SkColorType: 129 case kRGB_565_SkColorType: 130 case kRGB_888x_SkColorType: 131 case kRGB_101010x_SkColorType: 132 case kBGR_101010x_SkColorType: 133 alphaType = kOpaque_SkAlphaType; 134 break; 135 } 136 if (canonical) { 137 *canonical = alphaType; 138 } 139 return true; 140} 141 142/////////////////////////////////////////////////////////////////////////////////////////////////// 143 144#include "src/image/SkReadPixelsRec.h" 145 146bool SkReadPixelsRec::trim(int srcWidth, int srcHeight) { 147 if (nullptr == fPixels || fRowBytes < fInfo.minRowBytes()) { 148 return false; 149 } 150 if (0 >= fInfo.width() || 0 >= fInfo.height()) { 151 return false; 152 } 153 154 int x = fX; 155 int y = fY; 156 SkIRect srcR = SkIRect::MakeXYWH(x, y, fInfo.width(), fInfo.height()); 157 if (!srcR.intersect({0, 0, srcWidth, srcHeight})) { 158 return false; 159 } 160 161 // if x or y are negative, then we have to adjust pixels 162 if (x > 0) { 163 x = 0; 164 } 165 if (y > 0) { 166 y = 0; 167 } 168 // here x,y are either 0 or negative 169 // we negate and add them so UBSAN (pointer-overflow) doesn't get confused. 170 fPixels = ((char*)fPixels + -y*fRowBytes + -x*fInfo.bytesPerPixel()); 171 // the intersect may have shrunk info's logical size 172 fInfo = fInfo.makeDimensions(srcR.size()); 173 fX = srcR.x(); 174 fY = srcR.y(); 175 176 return true; 177} 178 179/////////////////////////////////////////////////////////////////////////////////////////////////// 180 181#include "src/core/SkWritePixelsRec.h" 182 183bool SkWritePixelsRec::trim(int dstWidth, int dstHeight) { 184 if (nullptr == fPixels || fRowBytes < fInfo.minRowBytes()) { 185 return false; 186 } 187 if (0 >= fInfo.width() || 0 >= fInfo.height()) { 188 return false; 189 } 190 191 int x = fX; 192 int y = fY; 193 SkIRect dstR = SkIRect::MakeXYWH(x, y, fInfo.width(), fInfo.height()); 194 if (!dstR.intersect({0, 0, dstWidth, dstHeight})) { 195 return false; 196 } 197 198 // if x or y are negative, then we have to adjust pixels 199 if (x > 0) { 200 x = 0; 201 } 202 if (y > 0) { 203 y = 0; 204 } 205 // here x,y are either 0 or negative 206 // we negate and add them so UBSAN (pointer-overflow) doesn't get confused. 207 fPixels = ((const char*)fPixels + -y*fRowBytes + -x*fInfo.bytesPerPixel()); 208 // the intersect may have shrunk info's logical size 209 fInfo = fInfo.makeDimensions(dstR.size()); 210 fX = dstR.x(); 211 fY = dstR.y(); 212 213 return true; 214} 215