1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc. 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 "include/core/SkStream.h" 9cb93a386Sopenharmony_ci#include "include/private/SkColorData.h" 10cb93a386Sopenharmony_ci#include "src/codec/SkBmpStandardCodec.h" 11cb93a386Sopenharmony_ci#include "src/codec/SkCodecPriv.h" 12cb93a386Sopenharmony_ci#include "src/core/SkMathPriv.h" 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_ci/* 15cb93a386Sopenharmony_ci * Creates an instance of the decoder 16cb93a386Sopenharmony_ci * Called only by NewFromStream 17cb93a386Sopenharmony_ci */ 18cb93a386Sopenharmony_ciSkBmpStandardCodec::SkBmpStandardCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream, 19cb93a386Sopenharmony_ci uint16_t bitsPerPixel, uint32_t numColors, 20cb93a386Sopenharmony_ci uint32_t bytesPerColor, uint32_t offset, 21cb93a386Sopenharmony_ci SkCodec::SkScanlineOrder rowOrder, 22cb93a386Sopenharmony_ci bool isOpaque, bool inIco) 23cb93a386Sopenharmony_ci : INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder) 24cb93a386Sopenharmony_ci , fColorTable(nullptr) 25cb93a386Sopenharmony_ci , fNumColors(numColors) 26cb93a386Sopenharmony_ci , fBytesPerColor(bytesPerColor) 27cb93a386Sopenharmony_ci , fOffset(offset) 28cb93a386Sopenharmony_ci , fSwizzler(nullptr) 29cb93a386Sopenharmony_ci , fIsOpaque(isOpaque) 30cb93a386Sopenharmony_ci , fInIco(inIco) 31cb93a386Sopenharmony_ci , fAndMaskRowBytes(fInIco ? SkAlign4(compute_row_bytes(this->dimensions().width(), 1)) : 0) 32cb93a386Sopenharmony_ci{} 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci/* 35cb93a386Sopenharmony_ci * Initiates the bitmap decode 36cb93a386Sopenharmony_ci */ 37cb93a386Sopenharmony_ciSkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, 38cb93a386Sopenharmony_ci void* dst, size_t dstRowBytes, 39cb93a386Sopenharmony_ci const Options& opts, 40cb93a386Sopenharmony_ci int* rowsDecoded) { 41cb93a386Sopenharmony_ci if (opts.fSubset) { 42cb93a386Sopenharmony_ci // Subsets are not supported. 43cb93a386Sopenharmony_ci return kUnimplemented; 44cb93a386Sopenharmony_ci } 45cb93a386Sopenharmony_ci if (dstInfo.dimensions() != this->dimensions()) { 46cb93a386Sopenharmony_ci SkCodecPrintf("Error: scaling not supported.\n"); 47cb93a386Sopenharmony_ci return kInvalidScale; 48cb93a386Sopenharmony_ci } 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_ci Result result = this->prepareToDecode(dstInfo, opts); 51cb93a386Sopenharmony_ci if (kSuccess != result) { 52cb93a386Sopenharmony_ci return result; 53cb93a386Sopenharmony_ci } 54cb93a386Sopenharmony_ci int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts); 55cb93a386Sopenharmony_ci if (rows != dstInfo.height()) { 56cb93a386Sopenharmony_ci *rowsDecoded = rows; 57cb93a386Sopenharmony_ci return kIncompleteInput; 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci return kSuccess; 60cb93a386Sopenharmony_ci} 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ci/* 63cb93a386Sopenharmony_ci * Process the color table for the bmp input 64cb93a386Sopenharmony_ci */ 65cb93a386Sopenharmony_ci bool SkBmpStandardCodec::createColorTable(SkColorType dstColorType, SkAlphaType dstAlphaType) { 66cb93a386Sopenharmony_ci // Allocate memory for color table 67cb93a386Sopenharmony_ci uint32_t colorBytes = 0; 68cb93a386Sopenharmony_ci SkPMColor colorTable[256]; 69cb93a386Sopenharmony_ci if (this->bitsPerPixel() <= 8) { 70cb93a386Sopenharmony_ci // Inform the caller of the number of colors 71cb93a386Sopenharmony_ci uint32_t maxColors = 1 << this->bitsPerPixel(); 72cb93a386Sopenharmony_ci // Don't bother reading more than maxColors. 73cb93a386Sopenharmony_ci const uint32_t numColorsToRead = 74cb93a386Sopenharmony_ci fNumColors == 0 ? maxColors : std::min(fNumColors, maxColors); 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ci // Read the color table from the stream 77cb93a386Sopenharmony_ci colorBytes = numColorsToRead * fBytesPerColor; 78cb93a386Sopenharmony_ci std::unique_ptr<uint8_t[]> cBuffer(new uint8_t[colorBytes]); 79cb93a386Sopenharmony_ci if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) { 80cb93a386Sopenharmony_ci SkCodecPrintf("Error: unable to read color table.\n"); 81cb93a386Sopenharmony_ci return false; 82cb93a386Sopenharmony_ci } 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ci SkColorType packColorType = dstColorType; 85cb93a386Sopenharmony_ci SkAlphaType packAlphaType = dstAlphaType; 86cb93a386Sopenharmony_ci if (this->colorXform()) { 87cb93a386Sopenharmony_ci packColorType = kBGRA_8888_SkColorType; 88cb93a386Sopenharmony_ci packAlphaType = kUnpremul_SkAlphaType; 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_ci // Choose the proper packing function 92cb93a386Sopenharmony_ci bool isPremul = (kPremul_SkAlphaType == packAlphaType) && !fIsOpaque; 93cb93a386Sopenharmony_ci PackColorProc packARGB = choose_pack_color_proc(isPremul, packColorType); 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_ci // Fill in the color table 96cb93a386Sopenharmony_ci uint32_t i = 0; 97cb93a386Sopenharmony_ci for (; i < numColorsToRead; i++) { 98cb93a386Sopenharmony_ci uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor); 99cb93a386Sopenharmony_ci uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1); 100cb93a386Sopenharmony_ci uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2); 101cb93a386Sopenharmony_ci uint8_t alpha; 102cb93a386Sopenharmony_ci if (fIsOpaque) { 103cb93a386Sopenharmony_ci alpha = 0xFF; 104cb93a386Sopenharmony_ci } else { 105cb93a386Sopenharmony_ci alpha = get_byte(cBuffer.get(), i*fBytesPerColor + 3); 106cb93a386Sopenharmony_ci } 107cb93a386Sopenharmony_ci colorTable[i] = packARGB(alpha, red, green, blue); 108cb93a386Sopenharmony_ci } 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci // To avoid segmentation faults on bad pixel data, fill the end of the 111cb93a386Sopenharmony_ci // color table with black. This is the same the behavior as the 112cb93a386Sopenharmony_ci // chromium decoder. 113cb93a386Sopenharmony_ci for (; i < maxColors; i++) { 114cb93a386Sopenharmony_ci colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0); 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ci if (this->colorXform() && !this->xformOnDecode()) { 118cb93a386Sopenharmony_ci this->applyColorXform(colorTable, colorTable, maxColors); 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci // Set the color table 122cb93a386Sopenharmony_ci fColorTable.reset(new SkColorTable(colorTable, maxColors)); 123cb93a386Sopenharmony_ci } 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci // Bmp-in-Ico files do not use an offset to indicate where the pixel data 126cb93a386Sopenharmony_ci // begins. Pixel data always begins immediately after the color table. 127cb93a386Sopenharmony_ci if (!fInIco) { 128cb93a386Sopenharmony_ci // Check that we have not read past the pixel array offset 129cb93a386Sopenharmony_ci if(fOffset < colorBytes) { 130cb93a386Sopenharmony_ci // This may occur on OS 2.1 and other old versions where the color 131cb93a386Sopenharmony_ci // table defaults to max size, and the bmp tries to use a smaller 132cb93a386Sopenharmony_ci // color table. This is invalid, and our decision is to indicate 133cb93a386Sopenharmony_ci // an error, rather than try to guess the intended size of the 134cb93a386Sopenharmony_ci // color table. 135cb93a386Sopenharmony_ci SkCodecPrintf("Error: pixel data offset less than color table size.\n"); 136cb93a386Sopenharmony_ci return false; 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci // After reading the color table, skip to the start of the pixel array 140cb93a386Sopenharmony_ci if (stream()->skip(fOffset - colorBytes) != fOffset - colorBytes) { 141cb93a386Sopenharmony_ci SkCodecPrintf("Error: unable to skip to image data.\n"); 142cb93a386Sopenharmony_ci return false; 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci // Return true on success 147cb93a386Sopenharmony_ci return true; 148cb93a386Sopenharmony_ci} 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_cistatic SkEncodedInfo make_info(SkEncodedInfo::Color color, 151cb93a386Sopenharmony_ci SkEncodedInfo::Alpha alpha, int bitsPerPixel) { 152cb93a386Sopenharmony_ci // This is just used for the swizzler, which does not need the width or height. 153cb93a386Sopenharmony_ci return SkEncodedInfo::Make(0, 0, color, alpha, bitsPerPixel); 154cb93a386Sopenharmony_ci} 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ciSkEncodedInfo SkBmpStandardCodec::swizzlerInfo() const { 157cb93a386Sopenharmony_ci const auto& info = this->getEncodedInfo(); 158cb93a386Sopenharmony_ci if (fInIco) { 159cb93a386Sopenharmony_ci if (this->bitsPerPixel() <= 8) { 160cb93a386Sopenharmony_ci return make_info(SkEncodedInfo::kPalette_Color, 161cb93a386Sopenharmony_ci info.alpha(), this->bitsPerPixel()); 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci if (this->bitsPerPixel() == 24) { 164cb93a386Sopenharmony_ci return make_info(SkEncodedInfo::kBGR_Color, 165cb93a386Sopenharmony_ci SkEncodedInfo::kOpaque_Alpha, 8); 166cb93a386Sopenharmony_ci } 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci return make_info(info.color(), info.alpha(), info.bitsPerComponent()); 170cb93a386Sopenharmony_ci} 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_civoid SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts) { 173cb93a386Sopenharmony_ci // In the case of bmp-in-icos, we will report BGRA to the client, 174cb93a386Sopenharmony_ci // since we may be required to apply an alpha mask after the decode. 175cb93a386Sopenharmony_ci // However, the swizzler needs to know the actual format of the bmp. 176cb93a386Sopenharmony_ci SkEncodedInfo encodedInfo = this->swizzlerInfo(); 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci // Get a pointer to the color table if it exists 179cb93a386Sopenharmony_ci const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci SkImageInfo swizzlerInfo = dstInfo; 182cb93a386Sopenharmony_ci SkCodec::Options swizzlerOptions = opts; 183cb93a386Sopenharmony_ci if (this->colorXform()) { 184cb93a386Sopenharmony_ci swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType); 185cb93a386Sopenharmony_ci if (kPremul_SkAlphaType == dstInfo.alphaType()) { 186cb93a386Sopenharmony_ci swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType); 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci 189cb93a386Sopenharmony_ci swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized; 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci fSwizzler = SkSwizzler::Make(encodedInfo, colorPtr, swizzlerInfo, swizzlerOptions); 193cb93a386Sopenharmony_ci SkASSERT(fSwizzler); 194cb93a386Sopenharmony_ci} 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ciSkCodec::Result SkBmpStandardCodec::onPrepareToDecode(const SkImageInfo& dstInfo, 197cb93a386Sopenharmony_ci const SkCodec::Options& options) { 198cb93a386Sopenharmony_ci if (this->xformOnDecode()) { 199cb93a386Sopenharmony_ci this->resetXformBuffer(dstInfo.width()); 200cb93a386Sopenharmony_ci } 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_ci // Create the color table if necessary and prepare the stream for decode 203cb93a386Sopenharmony_ci // Note that if it is non-NULL, inputColorCount will be modified 204cb93a386Sopenharmony_ci if (!this->createColorTable(dstInfo.colorType(), dstInfo.alphaType())) { 205cb93a386Sopenharmony_ci SkCodecPrintf("Error: could not create color table.\n"); 206cb93a386Sopenharmony_ci return SkCodec::kInvalidInput; 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci // Initialize a swizzler 210cb93a386Sopenharmony_ci this->initializeSwizzler(dstInfo, options); 211cb93a386Sopenharmony_ci return SkCodec::kSuccess; 212cb93a386Sopenharmony_ci} 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_ci/* 215cb93a386Sopenharmony_ci * Performs the bitmap decoding for standard input format 216cb93a386Sopenharmony_ci */ 217cb93a386Sopenharmony_ciint SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, 218cb93a386Sopenharmony_ci const Options& opts) { 219cb93a386Sopenharmony_ci // Iterate over rows of the image 220cb93a386Sopenharmony_ci const int height = dstInfo.height(); 221cb93a386Sopenharmony_ci for (int y = 0; y < height; y++) { 222cb93a386Sopenharmony_ci // Read a row of the input 223cb93a386Sopenharmony_ci if (this->stream()->read(this->srcBuffer(), this->srcRowBytes()) != this->srcRowBytes()) { 224cb93a386Sopenharmony_ci SkCodecPrintf("Warning: incomplete input stream.\n"); 225cb93a386Sopenharmony_ci return y; 226cb93a386Sopenharmony_ci } 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci // Decode the row in destination format 229cb93a386Sopenharmony_ci uint32_t row = this->getDstRow(y, dstInfo.height()); 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ci void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes); 232cb93a386Sopenharmony_ci 233cb93a386Sopenharmony_ci if (this->xformOnDecode()) { 234cb93a386Sopenharmony_ci SkASSERT(this->colorXform()); 235cb93a386Sopenharmony_ci fSwizzler->swizzle(this->xformBuffer(), this->srcBuffer()); 236cb93a386Sopenharmony_ci this->applyColorXform(dstRow, this->xformBuffer(), fSwizzler->swizzleWidth()); 237cb93a386Sopenharmony_ci } else { 238cb93a386Sopenharmony_ci fSwizzler->swizzle(dstRow, this->srcBuffer()); 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci } 241cb93a386Sopenharmony_ci 242cb93a386Sopenharmony_ci if (fInIco && fIsOpaque) { 243cb93a386Sopenharmony_ci const int startScanline = this->currScanline(); 244cb93a386Sopenharmony_ci if (startScanline < 0) { 245cb93a386Sopenharmony_ci // We are not performing a scanline decode. 246cb93a386Sopenharmony_ci // Just decode the entire ICO mask and return. 247cb93a386Sopenharmony_ci decodeIcoMask(this->stream(), dstInfo, dst, dstRowBytes); 248cb93a386Sopenharmony_ci return height; 249cb93a386Sopenharmony_ci } 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ci // In order to perform a scanline ICO decode, we must be able 252cb93a386Sopenharmony_ci // to skip ahead in the stream in order to apply the AND mask 253cb93a386Sopenharmony_ci // to the requested scanlines. 254cb93a386Sopenharmony_ci // We will do this by taking advantage of the fact that 255cb93a386Sopenharmony_ci // SkIcoCodec always uses a SkMemoryStream as its underlying 256cb93a386Sopenharmony_ci // representation of the stream. 257cb93a386Sopenharmony_ci const void* memoryBase = this->stream()->getMemoryBase(); 258cb93a386Sopenharmony_ci SkASSERT(nullptr != memoryBase); 259cb93a386Sopenharmony_ci SkASSERT(this->stream()->hasLength()); 260cb93a386Sopenharmony_ci SkASSERT(this->stream()->hasPosition()); 261cb93a386Sopenharmony_ci 262cb93a386Sopenharmony_ci const size_t length = this->stream()->getLength(); 263cb93a386Sopenharmony_ci const size_t currPosition = this->stream()->getPosition(); 264cb93a386Sopenharmony_ci 265cb93a386Sopenharmony_ci // Calculate how many bytes we must skip to reach the AND mask. 266cb93a386Sopenharmony_ci const int remainingScanlines = this->dimensions().height() - startScanline - height; 267cb93a386Sopenharmony_ci const size_t bytesToSkip = remainingScanlines * this->srcRowBytes() + 268cb93a386Sopenharmony_ci startScanline * fAndMaskRowBytes; 269cb93a386Sopenharmony_ci const size_t subStreamStartPosition = currPosition + bytesToSkip; 270cb93a386Sopenharmony_ci if (subStreamStartPosition >= length) { 271cb93a386Sopenharmony_ci // FIXME: How can we indicate that this decode was actually incomplete? 272cb93a386Sopenharmony_ci return height; 273cb93a386Sopenharmony_ci } 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_ci // Create a subStream to pass to decodeIcoMask(). It is useful to encapsulate 276cb93a386Sopenharmony_ci // the memory base into a stream in order to safely handle incomplete images 277cb93a386Sopenharmony_ci // without reading out of bounds memory. 278cb93a386Sopenharmony_ci const void* subStreamMemoryBase = SkTAddOffset<const void>(memoryBase, 279cb93a386Sopenharmony_ci subStreamStartPosition); 280cb93a386Sopenharmony_ci const size_t subStreamLength = length - subStreamStartPosition; 281cb93a386Sopenharmony_ci // This call does not transfer ownership of the subStreamMemoryBase. 282cb93a386Sopenharmony_ci SkMemoryStream subStream(subStreamMemoryBase, subStreamLength, false); 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci // FIXME: If decodeIcoMask does not succeed, is there a way that we can 285cb93a386Sopenharmony_ci // indicate the decode was incomplete? 286cb93a386Sopenharmony_ci decodeIcoMask(&subStream, dstInfo, dst, dstRowBytes); 287cb93a386Sopenharmony_ci } 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci return height; 290cb93a386Sopenharmony_ci} 291cb93a386Sopenharmony_ci 292cb93a386Sopenharmony_civoid SkBmpStandardCodec::decodeIcoMask(SkStream* stream, const SkImageInfo& dstInfo, 293cb93a386Sopenharmony_ci void* dst, size_t dstRowBytes) { 294cb93a386Sopenharmony_ci // BMP in ICO have transparency, so this cannot be 565. The below code depends 295cb93a386Sopenharmony_ci // on the output being an SkPMColor. 296cb93a386Sopenharmony_ci SkASSERT(kRGBA_8888_SkColorType == dstInfo.colorType() || 297cb93a386Sopenharmony_ci kBGRA_8888_SkColorType == dstInfo.colorType() || 298cb93a386Sopenharmony_ci kRGBA_F16_SkColorType == dstInfo.colorType()); 299cb93a386Sopenharmony_ci 300cb93a386Sopenharmony_ci // If we are sampling, make sure that we only mask the sampled pixels. 301cb93a386Sopenharmony_ci // We do not need to worry about sampling in the y-dimension because that 302cb93a386Sopenharmony_ci // should be handled by SkSampledCodec. 303cb93a386Sopenharmony_ci const int sampleX = fSwizzler->sampleX(); 304cb93a386Sopenharmony_ci const int sampledWidth = get_scaled_dimension(this->dimensions().width(), sampleX); 305cb93a386Sopenharmony_ci const int srcStartX = get_start_coord(sampleX); 306cb93a386Sopenharmony_ci 307cb93a386Sopenharmony_ci 308cb93a386Sopenharmony_ci SkPMColor* dstPtr = (SkPMColor*) dst; 309cb93a386Sopenharmony_ci for (int y = 0; y < dstInfo.height(); y++) { 310cb93a386Sopenharmony_ci // The srcBuffer will at least be large enough 311cb93a386Sopenharmony_ci if (stream->read(this->srcBuffer(), fAndMaskRowBytes) != fAndMaskRowBytes) { 312cb93a386Sopenharmony_ci SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n"); 313cb93a386Sopenharmony_ci return; 314cb93a386Sopenharmony_ci } 315cb93a386Sopenharmony_ci 316cb93a386Sopenharmony_ci auto applyMask = [dstInfo](void* dstRow, int x, uint64_t bit) { 317cb93a386Sopenharmony_ci if (kRGBA_F16_SkColorType == dstInfo.colorType()) { 318cb93a386Sopenharmony_ci uint64_t* dst64 = (uint64_t*) dstRow; 319cb93a386Sopenharmony_ci dst64[x] &= bit - 1; 320cb93a386Sopenharmony_ci } else { 321cb93a386Sopenharmony_ci uint32_t* dst32 = (uint32_t*) dstRow; 322cb93a386Sopenharmony_ci dst32[x] &= bit - 1; 323cb93a386Sopenharmony_ci } 324cb93a386Sopenharmony_ci }; 325cb93a386Sopenharmony_ci 326cb93a386Sopenharmony_ci int row = this->getDstRow(y, dstInfo.height()); 327cb93a386Sopenharmony_ci 328cb93a386Sopenharmony_ci void* dstRow = SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes); 329cb93a386Sopenharmony_ci 330cb93a386Sopenharmony_ci int srcX = srcStartX; 331cb93a386Sopenharmony_ci for (int dstX = 0; dstX < sampledWidth; dstX++) { 332cb93a386Sopenharmony_ci int quotient; 333cb93a386Sopenharmony_ci int modulus; 334cb93a386Sopenharmony_ci SkTDivMod(srcX, 8, "ient, &modulus); 335cb93a386Sopenharmony_ci uint32_t shift = 7 - modulus; 336cb93a386Sopenharmony_ci uint64_t alphaBit = (this->srcBuffer()[quotient] >> shift) & 0x1; 337cb93a386Sopenharmony_ci applyMask(dstRow, dstX, alphaBit); 338cb93a386Sopenharmony_ci srcX += sampleX; 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci } 341cb93a386Sopenharmony_ci} 342