bool SkScaledCodec::onDimensionsSupported(const SkISize& dim) { // Check with fCodec first. No need to call the non-virtual version, which // just checks if it matches the original, since a match means this method // will not be called. if (fCodec->onDimensionsSupported(dim)) { return true; } // FIXME: These variables are unused, but are needed by scaling_supported. // This class could also cache these values, and avoid calling this in // onGetPixels (since getPixels already calls it). int sampleX; int sampleY; return scaling_supported(dim, this->getInfo().dimensions(), &sampleX, &sampleY); }
SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, size_t rowBytes, const Options& options, SkPMColor ctable[], int* ctableCount) { if (options.fSubset) { // Subsets are not supported. return kUnimplemented; } Result result = fScanlineDecoder->start(requestedInfo, &options, ctable, ctableCount); if (kSuccess == result) { // native decode supported return fScanlineDecoder->getScanlines(dst, requestedInfo.height(), rowBytes); } if (kInvalidScale != result) { // no scaling requested return result; } // scaling requested int sampleX; int sampleY; if (!scaling_supported(requestedInfo, fScanlineDecoder->getInfo(), &sampleX, &sampleY)) { return kInvalidScale; } // set first sample pixel in y direction int Y0 = sampleY >> 1; int dstHeight = requestedInfo.height(); int srcHeight = fScanlineDecoder->getInfo().height(); SkImageInfo info = requestedInfo; // use original height as scanlineDecoder does not support y sampling natively info = info.makeWH(requestedInfo.width(), srcHeight); // update scanlineDecoder with new info result = fScanlineDecoder->start(info, &options, ctable, ctableCount); if (kSuccess != result) { return result; } const bool requiresPostYSampling = fScanlineDecoder->requiresPostYSampling(); if (requiresPostYSampling) { SkAutoMalloc storage(srcHeight * rowBytes); uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); result = fScanlineDecoder->getScanlines(storagePtr, srcHeight, rowBytes); if (kSuccess != result) { return result; } storagePtr += Y0 * rowBytes; for (int y = 0; y < dstHeight; y++) { memcpy(dst, storagePtr, rowBytes); storagePtr += sampleY * rowBytes; dst = SkTAddOffset<void>(dst, rowBytes); } } else { // does not require post y sampling result = fScanlineDecoder->skipScanlines(Y0); if (kSuccess != result) { return result; } for (int y = 0; y < dstHeight; y++) { result = fScanlineDecoder->getScanlines(dst, 1, rowBytes); if (kSuccess != result) { return result; } if (y < dstHeight - 1) { result = fScanlineDecoder->skipScanlines(sampleY - 1); if (kSuccess != result) { return result; } } dst = SkTAddOffset<void>(dst, rowBytes); } } return kSuccess; }
SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, size_t rowBytes, const Options& options, SkPMColor ctable[], int* ctableCount, int* rowsDecoded) { if (options.fSubset) { // Subsets are not supported. return kUnimplemented; } if (fCodec->dimensionsSupported(requestedInfo.dimensions())) { // Make sure that the parent class does not fill on an incomplete decode, since // fCodec will take care of filling the uninitialized lines. *rowsDecoded = requestedInfo.height(); return fCodec->getPixels(requestedInfo, dst, rowBytes, &options, ctable, ctableCount); } // scaling requested int sampleX; int sampleY; if (!scaling_supported(requestedInfo.dimensions(), fCodec->getInfo().dimensions(), &sampleX, &sampleY)) { // onDimensionsSupported would have returned false, meaning we should never reach here. SkASSERT(false); return kInvalidScale; } // set first sample pixel in y direction const int Y0 = get_start_coord(sampleY); const int dstHeight = requestedInfo.height(); const int srcWidth = fCodec->getInfo().width(); const int srcHeight = fCodec->getInfo().height(); const SkImageInfo info = requestedInfo.makeWH(srcWidth, srcHeight); Result result = fCodec->startScanlineDecode(info, &options, ctable, ctableCount); if (kSuccess != result) { return result; } SkSampler* sampler = fCodec->getSampler(true); if (!sampler) { return kUnimplemented; } if (sampler->setSampleX(sampleX) != requestedInfo.width()) { return kInvalidScale; } switch(fCodec->getScanlineOrder()) { case SkCodec::kTopDown_SkScanlineOrder: { if (!fCodec->skipScanlines(Y0)) { *rowsDecoded = 0; return kIncompleteInput; } for (int y = 0; y < dstHeight; y++) { if (1 != fCodec->getScanlines(dst, 1, rowBytes)) { // The failed call to getScanlines() will take care of // filling the failed row, so we indicate that we have // decoded (y + 1) rows. *rowsDecoded = y + 1; return kIncompleteInput; } if (y < dstHeight - 1) { if (!fCodec->skipScanlines(sampleY - 1)) { *rowsDecoded = y + 1; return kIncompleteInput; } } dst = SkTAddOffset<void>(dst, rowBytes); } return kSuccess; } case SkCodec::kBottomUp_SkScanlineOrder: case SkCodec::kOutOfOrder_SkScanlineOrder: { Result result = kSuccess; int y; for (y = 0; y < srcHeight; y++) { int srcY = fCodec->nextScanline(); if (is_coord_necessary(srcY, sampleY, dstHeight)) { void* dstPtr = SkTAddOffset<void>(dst, rowBytes * get_dst_coord(srcY, sampleY)); if (1 != fCodec->getScanlines(dstPtr, 1, rowBytes)) { result = kIncompleteInput; break; } } else { if (!fCodec->skipScanlines(1)) { result = kIncompleteInput; break; } } } // We handle filling uninitialized memory here instead of in the parent class. // The parent class does not know that we are sampling. if (kIncompleteInput == result) { const uint32_t fillValue = fCodec->getFillValue(requestedInfo.colorType(), requestedInfo.alphaType()); for (; y < srcHeight; y++) { int srcY = fCodec->outputScanline(y); if (is_coord_necessary(srcY, sampleY, dstHeight)) { void* dstRow = SkTAddOffset<void>(dst, rowBytes * get_dst_coord(srcY, sampleY)); SkSampler::Fill(requestedInfo.makeWH(requestedInfo.width(), 1), dstRow, rowBytes, fillValue, options.fZeroInitialized); } } *rowsDecoded = dstHeight; } return result; } case SkCodec::kNone_SkScanlineOrder: { SkAutoMalloc storage(srcHeight * rowBytes); uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); int scanlines = fCodec->getScanlines(storagePtr, srcHeight, rowBytes); storagePtr += Y0 * rowBytes; scanlines -= Y0; int y = 0; while (y < dstHeight && scanlines > 0) { memcpy(dst, storagePtr, rowBytes); storagePtr += sampleY * rowBytes; dst = SkTAddOffset<void>(dst, rowBytes); scanlines -= sampleY; y++; } if (y < dstHeight) { // fCodec has already handled filling uninitialized memory. *rowsDecoded = dstHeight; return kIncompleteInput; } return kSuccess; } default: SkASSERT(false); return kUnimplemented; } }