Esempio n. 1
0
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);
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
    }
}