// https://bug.skia.org/2894
DEF_TEST(BitmapCache_add_rect, reporter) {
    SkResourceCache::DiscardableFactory factory = SkResourceCache::GetDiscardableFactory();
    SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator();

    SkAutoTDelete<SkResourceCache> cache;
    if (factory) {
        cache.reset(new SkResourceCache(factory));
    } else {
        const size_t byteLimit = 100 * 1024;
        cache.reset(new SkResourceCache(byteLimit));
    }
    SkBitmap cachedBitmap;
    make_bitmap(&cachedBitmap, SkImageInfo::MakeN32Premul(5, 5), allocator);
    cachedBitmap.setImmutable();

    SkBitmap bm;
    SkIRect rect = SkIRect::MakeWH(5, 5);
    uint32_t cachedID = cachedBitmap.getGenerationID();
    SkPixelRef* cachedPR = cachedBitmap.pixelRef();

    // Wrong subset size
    REPORTER_ASSERT(reporter, !SkBitmapCache::Add(cachedPR, SkIRect::MakeWH(4, 6), cachedBitmap, cache));
    REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedID, rect, &bm, cache));
    // Wrong offset value
    REPORTER_ASSERT(reporter, !SkBitmapCache::Add(cachedPR, SkIRect::MakeXYWH(-1, 0, 5, 5), cachedBitmap, cache));
    REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedID, rect, &bm, cache));

    // Should not be in the cache
    REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedID, rect, &bm, cache));

    REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedPR, rect, cachedBitmap, cache));
    // Should be in the cache, we just added it
    REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedID, rect, &bm, cache));
}
    virtual Result onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
                               const Options&,
                               SkPMColor ctableEntries[], int* ctableCount) override {
        SkMemoryStream stream(fData->data(), fData->size(), false);
        SkAutoTUnref<BareMemoryAllocator> allocator(SkNEW_ARGS(BareMemoryAllocator,
                                                               (info, pixels, rowBytes)));
        fDecoder->setAllocator(allocator);
        fDecoder->setRequireUnpremultipliedColors(kUnpremul_SkAlphaType == info.alphaType());

        SkBitmap bm;
        const SkImageDecoder::Result result = fDecoder->decode(&stream, &bm, info.colorType(),
                                                               SkImageDecoder::kDecodePixels_Mode);
        if (SkImageDecoder::kFailure == result) {
            return kInvalidInput;
        }

        SkASSERT(info.colorType() == bm.info().colorType());

        if (kIndex_8_SkColorType == info.colorType()) {
            SkASSERT(ctableEntries);

            SkColorTable* ctable = bm.getColorTable();
            if (NULL == ctable) {
                return kInvalidConversion;
            }
            const int count = ctable->count();
            memcpy(ctableEntries, ctable->readColors(), count * sizeof(SkPMColor));
            *ctableCount = count;
        }
        if (SkImageDecoder::kPartialSuccess == result) {
            return kIncompleteInput;
        }
        return kSuccess;
    }
Example #3
0
void SkPicturePlayback::draw(SkCanvas* canvas,
                             SkPicture::AbortCallback* callback,
                             const SkReadBuffer* buffer) {
    AutoResetOpID aroi(this);
    SkASSERT(0 == fCurOffset);

    SkAutoTDelete<SkReadBuffer> reader;
    if (buffer) {
        reader.reset(buffer->clone(fPictureData->opData()->bytes(),
                                   fPictureData->opData()->size()));
    } else {
        reader.reset(new SkReadBuffer(fPictureData->opData()->bytes(),
                                      fPictureData->opData()->size()));
    }

    // Record this, so we can concat w/ it if we encounter a setMatrix()
    SkMatrix initialMatrix = canvas->getTotalMatrix();

    SkAutoCanvasRestore acr(canvas, false);

    while (!reader->eof()) {
        if (callback && callback->abort()) {
            return;
        }

        fCurOffset = reader->offset();
        uint32_t size;
        DrawType op = ReadOpAndSize(reader, &size);

        this->handleOp(reader, op, size, canvas, initialMatrix);
    }
}
void BitmapRegionDecoderBench::onDraw(const int n, SkCanvas* canvas) {
    SkAutoTDelete<SkBitmap> bitmap;
    for (int i = 0; i < n; i++) {
        bitmap.reset(fBRD->decodeRegion(fSubset.left(), fSubset.top(), fSubset.width(),
                fSubset.height(), fSampleSize, fColorType));
        SkASSERT(nullptr != bitmap.get());
    }
}
Example #5
0
 void onDraw(SkCanvas* canvas) override {
     SkDrawable* const* drawables = NULL;
     int drawableCount = 0;
     if (fDrawableList) {
         drawables = fDrawableList->begin();
         drawableCount = fDrawableList->count();
     }
     SkRecordDraw(*fRecord, canvas, NULL, drawables, drawableCount, fBBH, NULL/*callback*/);
 }
Example #6
0
    void runTest(skiatest::Reporter* reporter) {
        SkAutoTDelete<SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t> > result;
        result.reset(getAdvanceData((void*)this, fAdvancesLen, fSubset, fSubsetLen, getAdvance));

        SkString stringResult = stringify_advance_data(result);
        if (!stringResult.equals(fExpected)) {
            ERRORF(reporter, "Expected: %s\n  Result: %s\n", fExpected, stringResult.c_str());
        }
    }
SkBitmapRegionDecoder* SkBitmapRegionDecoder::Create(
        SkStreamRewindable* stream, Strategy strategy) {
    SkAutoTDelete<SkStreamRewindable> streamDeleter(stream);
    switch (strategy) {
        case kCanvas_Strategy: {
            SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(streamDeleter.detach()));
            if (nullptr == codec) {
                SkCodecPrintf("Error: Failed to create decoder.\n");
                return nullptr;
            }

            SkEncodedFormat format = codec->getEncodedFormat();
            switch (format) {
                case SkEncodedFormat::kJPEG_SkEncodedFormat:
                case SkEncodedFormat::kPNG_SkEncodedFormat:
                    break;
                default:
                    // FIXME: Support webp using a special case.  Webp does not support
                    //        scanline decoding.
                    return nullptr;
            }

            // If the image is a jpeg or a png, the scanline ordering should always be
            // kTopDown or kNone.  It is relevant to check because this implementation
            // only supports these two scanline orderings.
            SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder() ||
                    SkCodec::kNone_SkScanlineOrder == codec->getScanlineOrder());

            return new SkBitmapRegionCanvas(codec.detach());
        }
        case kAndroidCodec_Strategy: {
            SkAutoTDelete<SkAndroidCodec> codec =
                    SkAndroidCodec::NewFromStream(streamDeleter.detach());
            if (nullptr == codec) {
                SkCodecPrintf("Error: Failed to create codec.\n");
                return NULL;
            }

            SkEncodedFormat format = codec->getEncodedFormat();
            switch (format) {
                case SkEncodedFormat::kJPEG_SkEncodedFormat:
                case SkEncodedFormat::kPNG_SkEncodedFormat:
                case SkEncodedFormat::kWEBP_SkEncodedFormat:
                    break;
                default:
                    return nullptr;
            }

            return new SkBitmapRegionCodec(codec.detach());
        }
        default:
            SkASSERT(false);
            return nullptr;
    }
}
Example #8
0
void AndroidCodecBench::onDraw(int n, SkCanvas* canvas) {
    SkAutoTDelete<SkAndroidCodec> codec;
    SkAndroidCodec::AndroidOptions options;
    options.fSampleSize = fSampleSize;
    for (int i = 0; i < n; i++) {
        codec.reset(SkAndroidCodec::NewFromData(fData));
#ifdef SK_DEBUG
        const SkCodec::Result result =
#endif
        codec->getAndroidPixels(fInfo, fPixelStorage.get(), fInfo.minRowBytes(), &options);
        SkASSERT(result == SkCodec::kSuccess || result == SkCodec::kIncompleteInput);
    }
}
Example #9
0
/**
 * Extract either the color or image data from a SkBitmap into a SkStream.
 * @param bitmap        Bitmap to extract data from.
 * @param srcRect       Region in the bitmap to extract.
 * @param extractAlpha  Set to true to extract the alpha data or false to
 *                      extract the color data.
 * @param isTransparent Pointer to a bool to output whether the alpha is
 *                      completely transparent. May be NULL. Only valid when
 *                      extractAlpha == true.
 * @return              Unencoded image data, or NULL if either data was not
 *                      available or alpha data was requested but the image was
 *                      entirely transparent or opaque.
 */
static SkStream* extract_image_data(const SkBitmap& bitmap,
                                    const SkIRect& srcRect,
                                    bool extractAlpha, bool* isTransparent) {
    SkColorType colorType = bitmap.colorType();
    if (extractAlpha && (kIndex_8_SkColorType == colorType ||
                         kRGB_565_SkColorType == colorType)) {
        if (isTransparent != NULL) {
            *isTransparent = false;
        }
        return NULL;
    }

    SkAutoLockPixels lock(bitmap);
    if (NULL == bitmap.getPixels()) {
        return NULL;
    }

    bool isOpaque = true;
    bool transparent = extractAlpha;
    SkAutoTDelete<SkStream> stream;

    switch (colorType) {
        case kIndex_8_SkColorType:
            if (!extractAlpha) {
                stream.reset(extract_index8_image(bitmap, srcRect));
            }
            break;
        case kARGB_4444_SkColorType:
            stream.reset(extract_argb4444_data(bitmap, srcRect, extractAlpha,
                                               &isOpaque, &transparent));
            break;
        case kRGB_565_SkColorType:
            if (!extractAlpha) {
                stream.reset(extract_rgb565_image(bitmap, srcRect));
            }
            break;
        case kN32_SkColorType:
            stream.reset(extract_argb8888_data(bitmap, srcRect, extractAlpha,
                                               &isOpaque, &transparent));
            break;
        case kAlpha_8_SkColorType:
            if (!extractAlpha) {
                stream.reset(create_black_image());
            } else {
                stream.reset(extract_a8_alpha(bitmap, srcRect,
                                              &isOpaque, &transparent));
            }
            break;
        default:
            SkASSERT(false);
    }

    if (isTransparent != NULL) {
        *isTransparent = transparent;
    }
    if (extractAlpha && (transparent || isOpaque)) {
        return NULL;
    }
    return stream.detach();
}
Example #10
0
    SkPicture* onNewPictureSnapshot() override {
        SkBigPicture::SnapshotArray* pictList = NULL;
        if (fDrawableList) {
            // TODO: should we plumb-down the BBHFactory and recordFlags from our host
            //       PictureRecorder?
            pictList = fDrawableList->newDrawableSnapshot();
        }

        SkAutoTUnref<SkLayerInfo> saveLayerData;

        if (fBBH && fDoSaveLayerInfo) {
            saveLayerData.reset(SkNEW(SkLayerInfo));

            SkBBoxHierarchy* bbh = NULL;    // we've already computed fBBH (received in constructor)
            // TODO: update saveLayer info computation to reuse the already computed
            // bounds in 'fBBH'
            SkRecordComputeLayers(fBounds, *fRecord, pictList, bbh, saveLayerData);
        }

        size_t subPictureBytes = 0;
        for (int i = 0; pictList && i < pictList->count(); i++) {
            subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]);
        }
        // SkBigPicture will take ownership of a ref on both fRecord and fBBH.
        // We're not willing to give up our ownership, so we must ref them for SkPicture.
        return SkNEW_ARGS(SkBigPicture, (fBounds,
                                         SkRef(fRecord.get()),
                                         pictList,
                                         SkSafeRef(fBBH.get()),
                                         saveLayerData.detach(),
                                         subPictureBytes));
    }
Example #11
0
void CodecBench::onDraw(const int n, SkCanvas* canvas) {
    SkAutoTDelete<SkCodec> codec;
    SkPMColor colorTable[256];
    int colorCount;
    for (int i = 0; i < n; i++) {
        colorCount = 256;
        codec.reset(SkCodec::NewFromData(fData));
#ifdef SK_DEBUG
        const SkCodec::Result result =
#endif
        codec->getPixels(fInfo, fPixelStorage.get(), fInfo.minRowBytes(),
                         nullptr, colorTable, &colorCount);
        SkASSERT(result == SkCodec::kSuccess
                 || result == SkCodec::kIncompleteInput);
    }
}
Example #12
0
bool FrontBufferedStream::isAtEnd() const {
    if (fOffset < fBufferedSoFar) {
        // Even if the underlying stream is at the end, this stream has been
        // rewound after buffering, so it is not at the end.
        return false;
    }

    return fStream->isAtEnd();
}
Example #13
0
bool GrGLShaderBuilder::GenProgram(GrGpuGL* gpu,
                                   GrGLUniformManager* uman,
                                   const GrGLProgramDesc& desc,
                                   const GrEffectStage* inColorStages[],
                                   const GrEffectStage* inCoverageStages[],
                                   GenProgramOutput* output) {
    SkAutoTDelete<GrGLShaderBuilder> builder;
    if (desc.getHeader().fHasVertexCode ||!gpu->shouldUseFixedFunctionTexturing()) {
        builder.reset(SkNEW_ARGS(GrGLFullShaderBuilder, (gpu, uman, desc)));
    } else {
        builder.reset(SkNEW_ARGS(GrGLFragmentOnlyShaderBuilder, (gpu, uman, desc)));
    }
    if (builder->genProgram(inColorStages, inCoverageStages)) {
        *output = builder->getOutput();
        return true;
    }
    return false;
}
Example #14
0
// static
SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
                                    const SkIRect& srcRect) {
    if (bitmap.colorType() == kUnknown_SkColorType) {
        return NULL;
    }

    bool isTransparent = false;
    SkAutoTDelete<SkStream> alphaData;
    if (!bitmap.isOpaque()) {
        // Note that isOpaque is not guaranteed to return false for bitmaps
        // with alpha support but a completely opaque alpha channel,
        // so alphaData may still be NULL if we have a completely opaque
        // (or transparent) bitmap.
        alphaData.reset(
                extract_image_data(bitmap, srcRect, true, &isTransparent));
    }
    if (isTransparent) {
        return NULL;
    }

    SkPDFImage* image;
    SkColorType colorType = bitmap.colorType();
    if (alphaData.get() != NULL && (kN32_SkColorType == colorType ||
                                    kARGB_4444_SkColorType == colorType)) {
        if (kN32_SkColorType == colorType) {
            image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false,
                                            SkIRect::MakeWH(srcRect.width(),
                                                            srcRect.height())));
        } else {
            SkBitmap unpremulBitmap = unpremultiply_bitmap(bitmap, srcRect);
            image = SkNEW_ARGS(SkPDFImage, (NULL, unpremulBitmap, false,
                                            SkIRect::MakeWH(srcRect.width(),
                                                            srcRect.height())));
        }
    } else {
        image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false, srcRect));
    }
    if (alphaData.get() != NULL) {
        SkAutoTUnref<SkPDFImage> mask(
                SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, true, srcRect)));
        image->insert("SMask", new SkPDFObjRef(mask))->unref();
    }
    return image;
}
Example #15
0
HRESULT StreamFontFileLoader::CreateStreamFromKey(
    void const* fontFileReferenceKey,
    UINT32 fontFileReferenceKeySize,
    IDWriteFontFileStream** fontFileStream)
{
    SkTScopedComPtr<SkDWriteFontFileStreamWrapper> stream;
    HR(SkDWriteFontFileStreamWrapper::Create(fStream->duplicate(), &stream));
    *fontFileStream = stream.release();
    return S_OK;
}
Example #16
0
/**
 * Creates a ExtGState with the SMask set to the luminosityShader in
 * luminosity mode. The shader pattern extends to the bbox.
 */
SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState() {
    SkRect bbox;
    bbox.set(fState.get()->fBBox);

    SkAutoTUnref<SkPDFObject> luminosityShader(
            SkPDFShader::GetPDFShaderByState(
                 fState->CreateAlphaToLuminosityState()));

    SkAutoTUnref<SkStream> alphaStream(create_pattern_fill_content(-1, bbox));

    SkAutoTUnref<SkPDFResourceDict>
        resources(get_gradient_resource_dict(luminosityShader, NULL));

    SkAutoTUnref<SkPDFFormXObject> alphaMask(
            new SkPDFFormXObject(alphaStream.get(), bbox, resources.get()));

    return SkPDFGraphicState::GetSMaskGraphicState(
            alphaMask.get(), false,
            SkPDFGraphicState::kLuminosity_SMaskMode);
}
SkBitmapRegionDecoder* SkBitmapRegionDecoder::Create(
        SkStreamRewindable* stream, Strategy strategy) {
    SkAutoTDelete<SkStreamRewindable> streamDeleter(stream);
    switch (strategy) {
        case kCanvas_Strategy: {
            SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(streamDeleter.detach()));
            if (nullptr == codec) {
                SkCodecPrintf("Error: Failed to create decoder.\n");
                return nullptr;
            }

            if (SkEncodedFormat::kWEBP_SkEncodedFormat == codec->getEncodedFormat()) {
                // FIXME: Support webp using a special case.  Webp does not support
                //        scanline decoding.
                return nullptr;
            }

            switch (codec->getScanlineOrder()) {
                case SkCodec::kTopDown_SkScanlineOrder:
                case SkCodec::kNone_SkScanlineOrder:
                    break;
                default:
                    SkCodecPrintf("Error: Scanline ordering not supported.\n");
                    return nullptr;
            }
            return new SkBitmapRegionCanvas(codec.detach());
        }
        case kAndroidCodec_Strategy: {
            SkAutoTDelete<SkAndroidCodec> codec =
                    SkAndroidCodec::NewFromStream(streamDeleter.detach());
            if (NULL == codec) {
                SkCodecPrintf("Error: Failed to create codec.\n");
                return NULL;
            }
            return new SkBitmapRegionCodec(codec.detach());
        }
        default:
            SkASSERT(false);
            return nullptr;
    }
}
Example #18
0
/*
 * Tries to handle the image with PIEX. If PIEX returns kOk and finds the preview image, create a
 * SkJpegCodec. If PIEX returns kFail, then the file is invalid, return nullptr. In other cases,
 * fallback to create SkRawCodec for DNG images.
 */
SkCodec* SkRawCodec::NewFromStream(SkStream* stream) {
    SkAutoTDelete<SkRawStream> rawStream;
    if (is_asset_stream(*stream)) {
        rawStream.reset(new SkRawAssetStream(stream));
    } else {
        rawStream.reset(new SkRawBufferedStream(stream));
    }

    // Does not take the ownership of rawStream.
    SkPiexStream piexStream(rawStream.get());
    ::piex::PreviewImageData imageData;
    if (::piex::IsRaw(&piexStream)) {
        ::piex::Error error = ::piex::GetPreviewImageData(&piexStream, &imageData);

        if (error == ::piex::Error::kOk && imageData.preview.length > 0) {
            // transferBuffer() is destructive to the rawStream. Abandon the rawStream after this
            // function call.
            // FIXME: one may avoid the copy of memoryStream and use the buffered rawStream.
            SkMemoryStream* memoryStream =
                rawStream->transferBuffer(imageData.preview.offset, imageData.preview.length);
            return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nullptr;
        } else if (error == ::piex::Error::kFail) {
            return nullptr;
        }
    }

    // Takes the ownership of the rawStream.
    SkAutoTDelete<SkDngImage> dngImage(SkDngImage::NewFromStream(rawStream.release()));
    if (!dngImage) {
        return nullptr;
    }

    return new SkRawCodec(dngImage.release());
}
Example #19
0
bool SkImage_Generator::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
                                     int srcX, int srcY, CachingHint chint) const {
    SkBitmap bm;
    if (kDisallow_CachingHint == chint) {
        if (fCache->lockAsBitmapOnlyIfAlreadyCached(&bm)) {
            return bm.readPixels(dstInfo, dstPixels, dstRB, srcX, srcY);
        } else {
            // Try passing the caller's buffer directly down to the generator. If this fails we
            // may still succeed in the general case, as the generator may prefer some other
            // config, which we could then convert via SkBitmap::readPixels.
            if (fCache->directGeneratePixels(dstInfo, dstPixels, dstRB, srcX, srcY)) {
                return true;
            }
            // else fall through
        }
    }

    if (this->getROPixels(&bm, chint)) {
        return bm.readPixels(dstInfo, dstPixels, dstRB, srcX, srcY);
    }
    return false;
}
Example #20
0
size_t FrontBufferedStream::read(void* voidDst, size_t size) {
    // Cast voidDst to a char* for easy addition.
    char* dst = reinterpret_cast<char*>(voidDst);
    SkDEBUGCODE(const size_t totalSize = size;)
    const size_t start = fOffset;

    // First, read any data that was previously buffered.
    if (fOffset < fBufferedSoFar) {
        const size_t bytesCopied = this->readFromBuffer(dst, size);

        // Update the remaining number of bytes needed to read
        // and the destination buffer.
        size -= bytesCopied;
        SkASSERT(size + (fOffset - start) == totalSize);
        if (dst != NULL) {
            dst += bytesCopied;
        }
    }

    // Buffer any more data that should be buffered, and copy it to the
    // destination.
    if (size > 0 && fBufferedSoFar < fBufferSize && !fStream->isAtEnd()) {
        const size_t buffered = this->bufferAndWriteTo(dst, size);

        // Update the remaining number of bytes needed to read
        // and the destination buffer.
        size -= buffered;
        SkASSERT(size + (fOffset - start) == totalSize);
        if (dst != NULL) {
            dst += buffered;
        }
    }

    if (size > 0 && !fStream->isAtEnd()) {
        SkDEBUGCODE(const size_t bytesReadDirectly =) this->readDirectlyFromStream(dst, size);
        SkDEBUGCODE(size -= bytesReadDirectly;)
Example #21
0
size_t FrontBufferedStream::readDirectlyFromStream(char* dst, size_t size) {
    SkASSERT(size > 0);
    // If we get here, we have buffered all that can be buffered.
    SkASSERT(fBufferSize == fBufferedSoFar && fOffset >= fBufferSize);

    const size_t bytesReadDirectly = fStream->read(dst, size);
    fOffset += bytesReadDirectly;

    // If we have read past the end of the buffer, rewinding is no longer
    // supported, so we can go ahead and free the memory.
    if (bytesReadDirectly > 0) {
        sk_free(fBuffer.detach());
    }

    return bytesReadDirectly;
}
Example #22
0
size_t FrontBufferedStream::bufferAndWriteTo(char* dst, size_t size) {
    SkASSERT(size > 0);
    SkASSERT(fOffset >= fBufferedSoFar);
    SkASSERT(fBuffer);
    // Data needs to be buffered. Buffer up to the lesser of the size requested
    // and the remainder of the max buffer size.
    const size_t bytesToBuffer = SkTMin(size, fBufferSize - fBufferedSoFar);
    char* buffer = fBuffer + fOffset;
    const size_t buffered = fStream->read(buffer, bytesToBuffer);

    fBufferedSoFar += buffered;
    fOffset = fBufferedSoFar;
    SkASSERT(fBufferedSoFar <= fBufferSize);

    // Copy the buffer to the destination buffer and update the amount read.
    if (dst != NULL) {
        memcpy(dst, buffer, buffered);
    }

    return buffered;
}
void DecodingBench::onDraw(const int n, SkCanvas* canvas) {
    SkBitmap bitmap;
    // Declare the allocator before the decoder, so it will outlive the
    // decoder, which will unref it.
    UseExistingAllocator allocator(fBitmap.pixelRef());
    SkAutoTDelete<SkImageDecoder> decoder;
    SkAutoTDelete<SkStreamRewindable> stream;
    for (int i = 0; i < n; i++) {
        // create a new stream and a new decoder to mimic the behavior of
        // CodecBench.
        stream.reset(new SkMemoryStream(fData));
        decoder.reset(SkImageDecoder::Factory(stream));
        decoder->setAllocator(&allocator);
        decoder->decode(stream, &bitmap, fColorType,
                        SkImageDecoder::kDecodePixels_Mode);
    }
}
Example #24
0
SkData* SkImage_Generator::onRefEncoded(GrContext* ctx) const {
    return fCache->refEncoded(ctx);
}
Example #25
0
Error HWUISink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
    // Do all setup in this function because we don't know the size
    // for the RenderNode and RenderProxy during the constructor.
    // In practice this doesn't seem too expensive.
    const SkISize size = src.size();

    // Based on android::SurfaceTexture_init()
    android::sp<android::IGraphicBufferProducer> producer;
    android::sp<android::IGraphicBufferConsumer> consumer;
    android::BufferQueue::createBufferQueue(&producer, &consumer);

    // Consumer setup

    android::sp<android::CpuConsumer> cpuConsumer =
        new android::CpuConsumer(consumer, 1);
    cpuConsumer->setName(android::String8("SkiaTestClient"));
    cpuConsumer->setDefaultBufferSize(size.width(), size.height());

    // Producer setup

    android::sp<android::Surface> surface = new android::Surface(producer);
    native_window_set_buffers_dimensions(surface.get(), size.width(), size.height());
    native_window_set_buffers_format(surface.get(), android::PIXEL_FORMAT_RGBA_8888);
    native_window_set_usage(surface.get(), GRALLOC_USAGE_SW_READ_OFTEN |
                                           GRALLOC_USAGE_SW_WRITE_NEVER |
                                           GRALLOC_USAGE_HW_RENDER);

    // RenderNode setup based on hwui/tests/main.cpp:TreeContentAnimation
    SkAutoTDelete<android::uirenderer::RenderNode> rootNode
        (new android::uirenderer::RenderNode());
    rootNode->incStrong(nullptr);

    // Values set here won't be applied until the framework has called
    // RenderNode::pushStagingPropertiesChanges() during RenderProxy::syncAndDrawFrame().
    rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, size.width(), size.height());
    rootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::X |
                                     android::uirenderer::RenderNode::Y);
    rootNode->mutateStagingProperties().setClipToBounds(false);
    rootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::GENERIC);

    // RenderProxy setup based on hwui/tests/main.cpp:TreeContentAnimation
    ContextFactory factory;
    SkAutoTDelete<android::uirenderer::renderthread::RenderProxy> proxy
        (new android::uirenderer::renderthread::RenderProxy(false, rootNode, &factory));
    proxy->loadSystemProperties();

    proxy->initialize(surface.get());

    float lightX = size.width() / 2.0f;
    android::uirenderer::Vector3 lightVector { lightX, dp(-200.0f), dp(800.0f) };
    proxy->setup(size.width(), size.height(), lightVector, dp(800.0f), 255 * 0.075f, 255 * 0.15f,
                 kDensity);

    // Do the draw

    SkAutoTDelete<android::uirenderer::DisplayListRenderer> renderer
        (new android::uirenderer::DisplayListRenderer());
    renderer->setViewport(size.width(), size.height());
    renderer->prepare();
    renderer->clipRect(0, 0, size.width(), size.height(), SkRegion::Op::kReplace_Op);

    Error err = src.draw(renderer->asSkCanvas());
    if (!err.isEmpty()) {
        return err;
    }

    renderer->finish();
    rootNode->setStagingDisplayList(renderer->finishRecording());

    proxy->syncAndDrawFrame();
    proxy->fence();

    // Capture pixels

    SkImageInfo destinationConfig =
        SkImageInfo::Make(size.width(), size.height(),
                          kRGBA_8888_SkColorType, kPremul_SkAlphaType);
    dst->allocPixels(destinationConfig);
    sk_memset32((uint32_t*) dst->getPixels(), SK_ColorRED, size.width() * size.height());

    android::CpuConsumer::LockedBuffer nativeBuffer;
    android::status_t retval = cpuConsumer->lockNextBuffer(&nativeBuffer);
    if (retval == android::BAD_VALUE) {
        SkDebugf("HWUISink::draw() got no buffer; returning transparent");
        // No buffer ready to read - commonly triggered by dm sending us
        // a no-op source, or calling code that doesn't do anything on this
        // backend.
        dst->eraseColor(SK_ColorTRANSPARENT);
        return "";
    } else if (retval) {
        return SkStringPrintf("Failed to lock buffer to read pixels: %d.", retval);
    }

    // Move the pixels into the destination SkBitmap

    SK_ALWAYSBREAK(nativeBuffer.format == android::PIXEL_FORMAT_RGBA_8888 &&
                   "Native buffer not RGBA!");
    SkImageInfo nativeConfig =
        SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
                          kRGBA_8888_SkColorType, kPremul_SkAlphaType);

    // Android stride is in pixels, Skia stride is in bytes
    SkBitmap nativeWrapper;
    bool success =
        nativeWrapper.installPixels(nativeConfig, nativeBuffer.data, nativeBuffer.stride * 4);
    if (!success) {
        return "Failed to wrap HWUI buffer in a SkBitmap";
    }

    SK_ALWAYSBREAK(dst->colorType() == kRGBA_8888_SkColorType &&
                   "Destination buffer not RGBA!");
    success =
        nativeWrapper.readPixels(destinationConfig, dst->getPixels(), dst->rowBytes(), 0, 0);
    if (!success) {
        return "Failed to extract pixels from HWUI buffer";
    }

    cpuConsumer->unlockBuffer(nativeBuffer);
    return "";
}
Example #26
0
int tool_main(int argc, char** argv) {
    SetupCrashHandler();
    SkString usage;
    usage.printf("Time drawing .skp files.\n"
                 "\tPossible arguments for --filter: [%s]\n\t\t[%s]",
                 filterTypesUsage().c_str(), filterFlagsUsage().c_str());
    SkCommandLineFlags::SetUsage(usage.c_str());
    SkCommandLineFlags::Parse(argc, argv);

    if (FLAGS_repeat < 1) {
        SkString error;
        error.printf("--repeats must be >= 1. Was %i\n", FLAGS_repeat);
        gLogger.logError(error);
        exit(-1);
    }

    if (FLAGS_logFile.count() == 1) {
        if (!gLogger.SetLogFile(FLAGS_logFile[0])) {
            SkString str;
            str.printf("Could not open %s for writing.\n", FLAGS_logFile[0]);
            gLogger.logError(str);
            // TODO(borenet): We're disabling this for now, due to
            // write-protected Android devices.  The very short-term
            // solution is to ignore the fact that we have no log file.
            //exit(-1);
        }
    }

    SkAutoTDelete<PictureJSONResultsWriter> jsonWriter;
    if (FLAGS_jsonLog.count() == 1) {
        SkASSERT(FLAGS_builderName.count() == 1 && FLAGS_gitHash.count() == 1);
        jsonWriter.reset(SkNEW(PictureJSONResultsWriter(
                        FLAGS_jsonLog[0],
                        FLAGS_builderName[0],
                        FLAGS_buildNumber,
                        FLAGS_timestamp,
                        FLAGS_gitHash[0],
                        FLAGS_gitNumber)));
        gWriter.add(jsonWriter.get());
    }

    gWriter.add(&gLogWriter);


#if SK_ENABLE_INST_COUNT
    gPrintInstCount = true;
#endif
    SkAutoGraphics ag;

    sk_tools::PictureBenchmark benchmark;

    setup_benchmark(&benchmark);

    int failures = 0;
    for (int i = 0; i < FLAGS_readPath.count(); ++i) {
        failures += process_input(FLAGS_readPath[i], benchmark);
    }

    if (failures != 0) {
        SkString err;
        err.printf("Failed to run %i benchmarks.\n", failures);
        gLogger.logError(err);
        return 1;
    }
#if SK_LAZY_CACHE_STATS
    if (FLAGS_trackDeferredCaching) {
        SkDebugf("Total cache hit rate: %f\n",
                 (double) gTotalCacheHits / (gTotalCacheHits + gTotalCacheMisses));
    }
#endif
    gWriter.end();
    return 0;
}
Example #27
0
GrTexture* SkImage_Generator::asTextureRef(GrContext* ctx, const GrTextureParams& params) const {
    return fCache->lockAsTexture(ctx, params, this);
}
Example #28
0
bool SkImage_Generator::getROPixels(SkBitmap* bitmap, CachingHint chint) const {
    return fCache->lockAsBitmap(bitmap, this, chint);
}
Example #29
0
ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOptions options) {
    for (int i = 0; i < fContexts.count(); ++i) {
        Context& context = fContexts[i];
        if (context.fType == type &&
            context.fOptions == options &&
            !context.fAbandoned) {
            if (context.fGLContext) {
                context.fGLContext->makeCurrent();
            }
            return ContextInfo(context.fGrContext, context.fGLContext);
        }
    }
    SkAutoTDelete<GLTestContext> glCtx;
    sk_sp<GrContext> grCtx;
    GrBackendContext backendContext = 0;
    sk_sp<const GrGLInterface> glInterface;
#ifdef SK_VULKAN
    sk_sp<const GrVkBackendContext> vkBackend;
#endif
    GrBackend backend = ContextTypeBackend(type);
    switch (backend) {
        case kOpenGL_GrBackend:
            switch (type) {
                case kGL_ContextType:
                    glCtx.reset(CreatePlatformGLTestContext(kGL_GrGLStandard));
                    break;
                case kGLES_ContextType:
                    glCtx.reset(CreatePlatformGLTestContext(kGLES_GrGLStandard));
                    break;
#if SK_ANGLE
#   ifdef SK_BUILD_FOR_WIN
                case kANGLE_ContextType:
                    glCtx.reset(CreateANGLEDirect3DGLTestContext());
                    break;
#   endif
                case kANGLE_GL_ContextType:
                    glCtx.reset(CreateANGLEOpenGLGLTestContext());
                    break;
#endif
#if SK_COMMAND_BUFFER
                case kCommandBuffer_ContextType:
                    glCtx.reset(CommandBufferGLTestContext::Create());
                    break;
#endif
#if SK_MESA
                case kMESA_ContextType:
                    glCtx.reset(CreateMesaGLTestContext());
                    break;
#endif
                case kNullGL_ContextType:
                    glCtx.reset(CreateNullGLTestContext());
                    break;
                case kDebugGL_ContextType:
                    glCtx.reset(CreateDebugGLTestContext());
                    break;
                default:
                    return ContextInfo();
            }
            if (nullptr == glCtx.get()) {
                return ContextInfo();
            }
            glInterface.reset(SkRef(glCtx->gl()));
            // Block NVPR from non-NVPR types.
            if (!(kEnableNVPR_ContextOptions & options)) {
                glInterface.reset(GrGLInterfaceRemoveNVPR(glInterface.get()));
                if (!glInterface) {
                    return ContextInfo();
                }
            }
            backendContext = reinterpret_cast<GrBackendContext>(glInterface.get());
            glCtx->makeCurrent();
            break;
#ifdef SK_VULKAN
        case kVulkan_GrBackend:
            SkASSERT(kVulkan_ContextType == type);
            if ((kEnableNVPR_ContextOptions & options) ||
                (kRequireSRGBSupport_ContextOptions & options)) {
                return ContextInfo();
            }
            vkBackend.reset(GrVkBackendContext::Create());
            if (!vkBackend) {
                return ContextInfo();
            }
            backendContext = reinterpret_cast<GrBackendContext>(vkBackend.get());
            // There is some bug (either in Skia or the NV Vulkan driver) where VkDevice
            // destruction will hang occaisonally. For some reason having an existing GL
            // context fixes this.
            if (!fSentinelGLContext) {
                fSentinelGLContext.reset(CreatePlatformGLTestContext(kGL_GrGLStandard));
                if (!fSentinelGLContext) {
                    fSentinelGLContext.reset(CreatePlatformGLTestContext(kGLES_GrGLStandard));
                }
            }
            break;
#endif
        default:
            return ContextInfo();
    }

    grCtx.reset(GrContext::Create(backend, backendContext, fGlobalOptions));
    if (!grCtx.get()) {
        return ContextInfo();
    }
    if (kEnableNVPR_ContextOptions & options) {
        if (!grCtx->caps()->shaderCaps()->pathRenderingSupport()) {
            return ContextInfo();
        }
    }
    if (kRequireSRGBSupport_ContextOptions & options) {
        if (!grCtx->caps()->srgbSupport()) {
            return ContextInfo();
        }
    }

    Context& context = fContexts.push_back();
    context.fGLContext = glCtx.release();
    context.fGrContext = SkRef(grCtx.get());
    context.fType = type;
    context.fOptions = options;
    context.fAbandoned = false;
    return ContextInfo(context.fGrContext, context.fGLContext);
}
static int filter_picture(const SkString& inFile, const SkString& outFile) {
    SkAutoTDelete<SkPicture> inPicture;

    SkFILEStream inStream(inFile.c_str());
    if (inStream.isValid()) {
        inPicture.reset(SkPicture::CreateFromStream(&inStream));
    }

    if (NULL == inPicture.get()) {
        SkDebugf("Could not read file %s\n", inFile.c_str());
        return -1;
    }

    int localCount[SK_ARRAY_COUNT(gOptTable)];

    memset(localCount, 0, sizeof(localCount));

    SkDebugCanvas debugCanvas(inPicture->width(), inPicture->height());
    debugCanvas.setBounds(inPicture->width(), inPicture->height());
    inPicture->draw(&debugCanvas);

    // delete the initial save and restore since replaying the commands will
    // re-add them
    if (debugCanvas.getSize() > 1) {
        debugCanvas.deleteDrawCommandAt(0);
        debugCanvas.deleteDrawCommandAt(debugCanvas.getSize()-1);
    }

    bool changed = true;
    int numBefore = debugCanvas.getSize();

    while (changed) {
        changed = false;
        for (int i = 0; i < debugCanvas.getSize(); ++i) {
            for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
                if ((*gOptTable[opt].fCheck)(&debugCanvas, i)) {
                    (*gOptTable[opt].fApply)(&debugCanvas, i);

                    ++gOptTable[opt].fNumTimesApplied;
                    ++localCount[opt];

                    if (debugCanvas.getSize() == i) {
                        // the optimization removed all the remaining operations
                        break;
                    }

                    opt = 0;          // try all the opts all over again
                    changed = true;
                }
            }
        }
    }

    int numAfter = debugCanvas.getSize();

    if (!outFile.isEmpty()) {
        SkPicture outPicture;

        SkCanvas* canvas = outPicture.beginRecording(inPicture->width(), inPicture->height());
        debugCanvas.draw(canvas);
        outPicture.endRecording();

        SkFILEWStream outStream(outFile.c_str());

        outPicture.serialize(&outStream);
    }

    bool someOptFired = false;
    for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
        if (0 != localCount[opt]) {
            SkDebugf("%d: %d ", opt, localCount[opt]);
            someOptFired = true;
        }
    }

    if (!someOptFired) {
        SkDebugf("No opts fired\n");
    } else {
        SkDebugf("\t before: %d after: %d delta: %d\n",
                 numBefore, numAfter, numBefore-numAfter);
    }

    return 0;
}