Exemple #1
0
// check if scaling to dstInfo size from srcInfo size using sampleSize is possible
static bool scaling_supported(const SkISize& dstDim, const SkISize& srcDim,
                              int* sampleX, int* sampleY) {
    SkScaledCodec::ComputeSampleSize(dstDim, srcDim, sampleX, sampleY);
    const int dstWidth = dstDim.width();
    const int dstHeight = dstDim.height();
    const int srcWidth = srcDim.width();
    const int srcHeight = srcDim.height();
     // only support down sampling, not up sampling
    if (dstWidth > srcWidth || dstHeight  > srcHeight) {
        return false;
    }
    // check that srcWidth is scaled down by an integer value
    if (get_scaled_dimension(srcWidth, *sampleX) != dstWidth) {
        return false;
    }
    // check that src height is scaled down by an integer value
    if (get_scaled_dimension(srcHeight, *sampleY) != dstHeight) {
        return false;
    }
    // sampleX and sampleY should be equal unless the original sampleSize requested was larger
    // than srcWidth or srcHeight. If so, the result of this is dstWidth or dstHeight = 1.
    // This functionality allows for tall thin images to still be scaled down by scaling factors.
    if (*sampleX != *sampleY){
        if (1 != dstWidth && 1 != dstHeight) {
            return false;
        }
    }
    return true;
}
    void onDraw(int loops, SkCanvas* canvas) override {
        canvas->clear(SK_ColorBLACK);

        SkISize size = canvas->getDeviceSize();

        int offX = (size.width() - kWindowSize) / kNumStepsX;
        int offY = (size.height() - kWindowSize) / kNumStepsY;

        SkPaint paint;

        paint.setColor(SK_ColorBLUE);

        canvas->drawCircle(SkIntToScalar(size.width()/2),
                           SkIntToScalar(size.height()/2),
                           SkIntToScalar(size.width()/2),
                           paint);

        SkBitmap bitmap;

        bitmap.setInfo(SkImageInfo::MakeN32Premul(kWindowSize, kWindowSize));

        for (int i = 0; i < loops; i++) {
            for (int x = 0; x < kNumStepsX; ++x) {
                for (int y = 0; y < kNumStepsY; ++y) {
                    canvas->readPixels(&bitmap, x * offX, y * offY);
                }
            }
        }
    }
Exemple #3
0
void GMSampleView::onDrawContent(SkCanvas* canvas) {
    SkPictureRecorder recorder;
    SkCanvas* origCanvas = canvas;

    if (false) {
        SkISize size = fGM->getISize();
        canvas = recorder.beginRecording(SkRect::MakeIWH(size.width(), size.height()));
    }

    {
        SkAutoCanvasRestore acr(canvas, fShowSize);
        fGM->drawContent(canvas);
    }

    if (origCanvas != canvas) {
        sk_sp<SkPicture> pic = recorder.finishRecordingAsPicture();
        if (false) {
            pic = round_trip_serialize(pic.get());
        }
        origCanvas->drawPicture(pic);
        canvas = origCanvas;
    }

    if (fShowSize) {
        SkISize size = fGM->getISize();
        SkRect r = SkRect::MakeWH(SkIntToScalar(size.width()),
                                  SkIntToScalar(size.height()));
        SkPaint paint;
        paint.setColor(0x40FF8833);
        canvas->drawRect(r, paint);
    }
}
// This function is used to scale an image and extract a scaled fragment.
//
// ALGORITHM
//
// Because the scaled image size has to be integers, we approximate the real
// scale with the following formula (only X direction is shown):
//
// scaledImageWidth = round(scaleX * imageRect.width())
// approximateScaleX = scaledImageWidth / imageRect.width()
//
// With this method we maintain a constant scale factor among fragments in
// the scaled image. This allows fragments to stitch together to form the
// full scaled image. The downside is there will be a small difference
// between |scaleX| and |approximateScaleX|.
//
// A scaled image fragment is identified by:
//
// - Scaled image size
// - Scaled image fragment rectangle (IntRect)
//
// Scaled image size has been determined and the next step is to compute the
// rectangle for the scaled image fragment which needs to be an IntRect.
//
// scaledSrcRect = srcRect * (approximateScaleX, approximateScaleY)
// enclosingScaledSrcRect = enclosingIntRect(scaledSrcRect)
//
// Finally we extract the scaled image fragment using
// (scaledImageSize, enclosingScaledSrcRect).
//
SkBitmap NativeImageSkia::extractScaledImageFragment(const SkRect& srcRect, float scaleX, float scaleY, SkRect* scaledSrcRect) const
{
    SkISize imageSize = SkISize::Make(bitmap().width(), bitmap().height());
    SkISize scaledImageSize = SkISize::Make(clampToInteger(roundf(imageSize.width() * scaleX)),
        clampToInteger(roundf(imageSize.height() * scaleY)));

    SkRect imageRect = SkRect::MakeWH(imageSize.width(), imageSize.height());
    SkRect scaledImageRect = SkRect::MakeWH(scaledImageSize.width(), scaledImageSize.height());

    SkMatrix scaleTransform;
    scaleTransform.setRectToRect(imageRect, scaledImageRect, SkMatrix::kFill_ScaleToFit);
    scaleTransform.mapRect(scaledSrcRect, srcRect);

    bool ok = scaledSrcRect->intersect(scaledImageRect);
    ASSERT_UNUSED(ok, ok);
    SkIRect enclosingScaledSrcRect = enclosingIntRect(*scaledSrcRect);

    // |enclosingScaledSrcRect| can be larger than |scaledImageSize| because
    // of float inaccuracy so clip to get inside.
    ok = enclosingScaledSrcRect.intersect(SkIRect::MakeSize(scaledImageSize));
    ASSERT_UNUSED(ok, ok);

    // scaledSrcRect is relative to the pixel snapped fragment we're extracting.
    scaledSrcRect->offset(-enclosingScaledSrcRect.x(), -enclosingScaledSrcRect.y());

    return resizedBitmap(scaledImageSize, enclosingScaledSrcRect);
}
Exemple #5
0
static SkISize best_scaled_dimensions(const SkISize& origDims, const SkISize& nativeDims,
                                      const SkISize& scaledCodecDims, float desiredScale) {
    if (nativeDims == scaledCodecDims) {
        // does not matter which to return if equal. Return here to skip below calculations
        return nativeDims;
    }
    float idealWidth = origDims.width() * desiredScale;
    float idealHeight = origDims.height() * desiredScale;

    // calculate difference between native dimensions and ideal dimensions
    float nativeWDiff = SkTAbs(idealWidth - nativeDims.width());
    float nativeHDiff = SkTAbs(idealHeight - nativeDims.height());
    float nativeDiff = nativeWDiff + nativeHDiff;

    // Native scaling is preferred to sampling.  If we can scale natively to
    // within one of the ideal value, we should choose to scale natively.
    if (nativeWDiff < 1.0f && nativeHDiff < 1.0f) {
        return nativeDims;
    }

    // calculate difference between scaledCodec dimensions and ideal dimensions
    float scaledCodecWDiff = SkTAbs(idealWidth - scaledCodecDims.width());
    float scaledCodecHDiff = SkTAbs(idealHeight - scaledCodecDims.height());
    float scaledCodecDiff = scaledCodecWDiff + scaledCodecHDiff;

    // return dimensions closest to ideal dimensions.
    // If the differences are equal, return nativeDims, as native scaling is more efficient.
    return nativeDiff > scaledCodecDiff ? scaledCodecDims : nativeDims;
}
Exemple #6
0
static void test_dimensions(skiatest::Reporter* r, const char path[]) {
    // Create the codec from the resource file
    SkAutoTDelete<SkStream> stream(resource(path));
    if (!stream) {
        SkDebugf("Missing resource '%s'\n", path);
        return;
    }
    SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.detach()));
    if (!codec) {
        ERRORF(r, "Unable to create codec '%s'", path);
        return;
    }

    // Check that the decode is successful for a variety of scales
    for (float scale = -0.05f; scale < 2.0f; scale += 0.05f) {
        // Scale the output dimensions
        SkISize scaledDims = codec->getScaledDimensions(scale);
        SkImageInfo scaledInfo = codec->getInfo().makeWH(scaledDims.width(), scaledDims.height());

        // Set up for the decode
        size_t rowBytes = scaledDims.width() * sizeof(SkPMColor);
        size_t totalBytes = scaledInfo.getSafeSize(rowBytes);
        SkAutoTMalloc<SkPMColor> pixels(totalBytes);

        SkImageGenerator::Result result =
                codec->getPixels(scaledInfo, pixels.get(), rowBytes, NULL, NULL, NULL);
        REPORTER_ASSERT(r, SkImageGenerator::kSuccess == result);
    }
}
Exemple #7
0
static void test_dimensions(skiatest::Reporter* r, const char path[]) {
    // Create the codec from the resource file
    SkAutoTDelete<SkStream> stream(resource(path));
    if (!stream) {
        SkDebugf("Missing resource '%s'\n", path);
        return;
    }
    SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(stream.detach()));
    if (!codec) {
        ERRORF(r, "Unable to create codec '%s'", path);
        return;
    }

    // Check that the decode is successful for a variety of scales
    for (int sampleSize = 1; sampleSize < 32; sampleSize++) {
        // Scale the output dimensions
        SkISize scaledDims = codec->getSampledDimensions(sampleSize);
        SkImageInfo scaledInfo = codec->getInfo()
                .makeWH(scaledDims.width(), scaledDims.height())
                .makeColorType(kN32_SkColorType);

        // Set up for the decode
        size_t rowBytes = scaledDims.width() * sizeof(SkPMColor);
        size_t totalBytes = scaledInfo.getSafeSize(rowBytes);
        SkAutoTMalloc<SkPMColor> pixels(totalBytes);

        SkAndroidCodec::AndroidOptions options;
        options.fSampleSize = sampleSize;
        SkCodec::Result result =
                codec->getAndroidPixels(scaledInfo, pixels.get(), rowBytes, &options);
        REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    }
}
Exemple #8
0
void Viewer::setupCurrentSlide(int previousSlide) {
    if (fCurrentSlide == previousSlide) {
        return; // no change; do nothing
    }

    fGesture.reset();
    fDefaultMatrix.reset();
    fDefaultMatrixInv.reset();

    if (fWindow->supportsContentRect() && fWindow->scaleContentToFit()) {
        const SkRect contentRect = fWindow->getContentRect();
        const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions();
        const SkRect slideBounds = SkRect::MakeIWH(slideSize.width(), slideSize.height());
        if (contentRect.width() > 0 && contentRect.height() > 0) {
            fDefaultMatrix.setRectToRect(slideBounds, contentRect, SkMatrix::kStart_ScaleToFit);
            SkAssertResult(fDefaultMatrix.invert(&fDefaultMatrixInv));
        }
    }

    if (fWindow->supportsContentRect()) {
        const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions();
        SkRect windowRect = fWindow->getContentRect();
        fDefaultMatrixInv.mapRect(&windowRect);
        fGesture.setTransLimit(SkRect::MakeWH(slideSize.width(), slideSize.height()), windowRect);
    }

    this->updateTitle();
    this->updateUIState();
    fSlides[fCurrentSlide]->load();
    if (previousSlide >= 0) {
        fSlides[previousSlide]->unload();
    }
    fWindow->inval();
}
 void drawClippedRect(SkCanvas* canvas, int x, int y, const SkPaint& paint) {
     canvas->save();
     canvas->clipRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
                      SkIntToScalar(fSize.width()), SkIntToScalar(fSize.height())));
     SkRect r = SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
                                 SkIntToScalar(fSize.width()),
                                 SkIntToScalar(fSize.height()));
     canvas->drawRect(r, paint);
     canvas->restore();
 }
Exemple #10
0
 void make_bitmap() {
     fBitmap.allocN32Pixels(fSize.width(), fSize.height());
     SkCanvas canvas(fBitmap);
     canvas.clear(0x00000000);
     SkPaint paint;
     paint.setAntiAlias(true);
     SkShader* shader = MakeLinear(fSize);
     paint.setShader(shader);
     SkRect r = { 0, 0, SkIntToScalar(fSize.width()), SkIntToScalar(fSize.height()) };
     canvas.drawRect(r, paint);
     shader->unref();
 }
SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatrix* localM) const {
    SkASSERT(fPicture && fPicture->width() > 0 && fPicture->height() > 0);

    SkMatrix m;
    m.setConcat(matrix, this->getLocalMatrix());
    if (localM) {
        m.preConcat(*localM);
    }

    // Use a rotation-invariant scale
    SkPoint scale;
    if (!SkDecomposeUpper2x2(m, NULL, &scale, NULL)) {
        // Decomposition failed, use an approximation.
        scale.set(SkScalarSqrt(m.getScaleX() * m.getScaleX() + m.getSkewX() * m.getSkewX()),
                  SkScalarSqrt(m.getScaleY() * m.getScaleY() + m.getSkewY() * m.getSkewY()));
    }
    SkSize scaledSize = SkSize::Make(scale.x() * fPicture->width(), scale.y() * fPicture->height());

    SkISize tileSize = scaledSize.toRound();
    if (tileSize.isEmpty()) {
        return NULL;
    }

    // The actual scale, compensating for rounding.
    SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fPicture->width(),
                                    SkIntToScalar(tileSize.height()) / fPicture->height());

    SkAutoMutexAcquire ama(fCachedBitmapShaderMutex);

    if (!fCachedBitmapShader || tileScale != fCachedTileScale) {
        SkBitmap bm;
        if (!bm.allocN32Pixels(tileSize.width(), tileSize.height())) {
            return NULL;
        }
        bm.eraseColor(SK_ColorTRANSPARENT);

        SkCanvas canvas(bm);
        canvas.scale(tileScale.width(), tileScale.height());
        canvas.drawPicture(fPicture);

        fCachedTileScale = tileScale;

        SkMatrix shaderMatrix = this->getLocalMatrix();
        shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
        fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy, &shaderMatrix));
    }

    // Increment the ref counter inside the mutex to ensure the returned pointer is still valid.
    // Otherwise, the pointer may have been overwritten on a different thread before the object's
    // ref count was incremented.
    fCachedBitmapShader.get()->ref();
    return fCachedBitmapShader;
}
GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(sk_sp<GrTextureProxy> proxy,
                                                     const SkIRect& bounds,
                                                     const SkISize& kernelSize,
                                                     const SkScalar* kernel,
                                                     SkScalar gain,
                                                     SkScalar bias,
                                                     const SkIPoint& kernelOffset,
                                                     GrTextureDomain::Mode tileMode,
                                                     bool convolveAlpha)
        // To advertise either the modulation or opaqueness optimizations we'd have to examine the
        // parameters.
        : INHERITED(kGrMatrixConvolutionEffect_ClassID, kNone_OptimizationFlags)
        , fCoordTransform(proxy.get())
        , fDomain(proxy.get(), GrTextureDomain::MakeTexelDomainForMode(bounds, tileMode), tileMode)
        , fTextureSampler(std::move(proxy))
        , fKernelSize(kernelSize)
        , fGain(SkScalarToFloat(gain))
        , fBias(SkScalarToFloat(bias) / 255.0f)
        , fConvolveAlpha(convolveAlpha) {
    this->addCoordTransform(&fCoordTransform);
    this->addTextureSampler(&fTextureSampler);
    for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) {
        fKernel[i] = SkScalarToFloat(kernel[i]);
    }
    fKernelOffset[0] = static_cast<float>(kernelOffset.x());
    fKernelOffset[1] = static_cast<float>(kernelOffset.y());
}
Exemple #13
0
SkBitmap DeferredImageDecoder::createLazyDecodingBitmap()
{
    SkISize fullSize = SkISize::Make(m_actualDecoder->size().width(), m_actualDecoder->size().height());
    ASSERT(!fullSize.isEmpty());

    SkIRect fullRect = SkIRect::MakeSize(fullSize);

    // Creates a lazily decoded SkPixelRef that references the entire image without scaling.
    SkBitmap bitmap;
    bitmap.setConfig(SkBitmap::kARGB_8888_Config, fullSize.width(), fullSize.height());

    m_frameGenerator = ImageFrameGenerator::create(fullSize, m_data.release(), m_allDataReceived);
    m_actualDecoder.clear();

    bitmap.setPixelRef(new LazyDecodingPixelRef(m_frameGenerator, fullSize, fullRect))->unref();

    // Use the URI to identify this as a lazily decoded SkPixelRef of type LazyDecodingPixelRef.
    // FIXME: It would be more useful to give the actual image URI.
    bitmap.pixelRef()->setURI(labelLazyDecoded);

    // Inform the bitmap that we will never change the pixels. This is a performance hint
    // subsystems that may try to cache this bitmap (e.g. pictures, pipes, gpu, pdf, etc.)
    bitmap.setImmutable();

    // FIXME: Setting bitmap.setIsOpaque() is big performance gain if possible. We can
    // do so safely if the image is fully loaded and it is a JPEG image, or if the image was
    // decoded before.

    return bitmap;
}
std::unique_ptr<GrFragmentProcessor> GrMatrixConvolutionEffect::TestCreate(GrProcessorTestData* d) {
    int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
                                        : GrProcessorUnitTest::kAlphaTextureIdx;
    sk_sp<GrTextureProxy> proxy = d->textureProxy(texIdx);

    int width = d->fRandom->nextRangeU(1, MAX_KERNEL_SIZE);
    int height = d->fRandom->nextRangeU(1, MAX_KERNEL_SIZE / width);
    SkISize kernelSize = SkISize::Make(width, height);
    std::unique_ptr<SkScalar[]> kernel(new SkScalar[width * height]);
    for (int i = 0; i < width * height; i++) {
        kernel.get()[i] = d->fRandom->nextSScalar1();
    }
    SkScalar gain = d->fRandom->nextSScalar1();
    SkScalar bias = d->fRandom->nextSScalar1();
    SkIPoint kernelOffset = SkIPoint::Make(d->fRandom->nextRangeU(0, kernelSize.width()),
                                           d->fRandom->nextRangeU(0, kernelSize.height()));
    SkIRect bounds = SkIRect::MakeXYWH(d->fRandom->nextRangeU(0, proxy->width()),
                                       d->fRandom->nextRangeU(0, proxy->height()),
                                       d->fRandom->nextRangeU(0, proxy->width()),
                                       d->fRandom->nextRangeU(0, proxy->height()));
    GrTextureDomain::Mode tileMode =
            static_cast<GrTextureDomain::Mode>(d->fRandom->nextRangeU(0, 2));
    bool convolveAlpha = d->fRandom->nextBool();
    return GrMatrixConvolutionEffect::Make(std::move(proxy),
                                           bounds,
                                           kernelSize,
                                           kernel.get(),
                                           gain,
                                           bias,
                                           kernelOffset,
                                           tileMode,
                                           convolveAlpha);
}
Exemple #15
0
bool SkRasterClip::op(const SkPath& path, const SkISize& size, SkRegion::Op op, bool doAA) {
    // base is used to limit the size (and therefore memory allocation) of the
    // region that results from scan converting devPath.
    SkRegion base;
    
    if (SkRegion::kIntersect_Op == op) {
        // since we are intersect, we can do better (tighter) with currRgn's
        // bounds, than just using the device. However, if currRgn is complex,
        // our region blitter may hork, so we do that case in two steps.
        if (this->isRect()) {
            // FIXME: we should also be able to do this when this->isBW(),
            // but relaxing the test above triggers GM asserts in
            // SkRgnBuilder::blitH(). We need to investigate what's going on.
            return this->setPath(path, this->bwRgn(), doAA);
        } else {
            base.setRect(this->getBounds());
            SkRasterClip clip;
            clip.setPath(path, base, doAA);
            return this->op(clip, op);
        }
    } else {
        base.setRect(0, 0, size.width(), size.height());
        
        if (SkRegion::kReplace_Op == op) {
            return this->setPath(path, base, doAA);
        } else {
            SkRasterClip clip;
            clip.setPath(path, base, doAA);
            return this->op(clip, op);
        }
    }
}
 PassOwnPtr<ScaledImageFragment> createCompleteImage(const SkISize& size)
 {
     SkBitmap bitmap;
     bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
     bitmap.allocPixels();
     return ScaledImageFragment::createComplete(size, 0, bitmap);
 }
bool ImageFrameGenerator::decodeAndScale(size_t index, const SkImageInfo& info, void* pixels, size_t rowBytes)
{
    // Prevent concurrent decode or scale operations on the same image data.
    MutexLocker lock(m_decodeMutex);

    if (m_decodeFailed)
        return false;

    TRACE_EVENT1("blink", "ImageFrameGenerator::decodeAndScale", "frame index", static_cast<int>(index));

    m_externalAllocator = adoptPtr(new ExternalMemoryAllocator(info, pixels, rowBytes));

    // This implementation does not support scaling so check the requested size.
    SkISize scaledSize = SkISize::Make(info.width(), info.height());
    ASSERT(m_fullSize == scaledSize);

    SkBitmap bitmap = tryToResumeDecode(index, scaledSize);
    if (bitmap.isNull())
        return false;

    // Don't keep the allocator because it contains a pointer to memory
    // that we do not own.
    m_externalAllocator.clear();

    // Check to see if the decoder has written directly to the pixel memory
    // provided. If not, make a copy.
    ASSERT(bitmap.width() == scaledSize.width());
    ASSERT(bitmap.height() == scaledSize.height());
    SkAutoLockPixels bitmapLock(bitmap);
    if (bitmap.getPixels() != pixels)
        return bitmap.copyPixelsTo(pixels, rowBytes * info.height(), rowBytes);
    return true;
}
Exemple #18
0
/**
 * Write the canvas to the specified path.
 * @param canvas Must be non-null. Canvas to be written to a file.
 * @param path Path for the file to be written. Should have no extension; write() will append
 *             an appropriate one. Passed in by value so it can be modified.
 * @param jsonSummaryPtr If not null, add image results to this summary.
 * @return bool True if the Canvas is written to a file.
 *
 * TODO(epoger): Right now, all canvases must pass through this function in order to be appended
 * to the ImageResultsSummary.  We need some way to add bitmaps to the ImageResultsSummary
 * even if --writePath has not been specified (and thus this function is not called).
 *
 * One fix would be to pass in these path elements separately, and allow this function to be
 * called even if --writePath was not specified...
 *  const char *outputDir   // NULL if we don't want to write image files to disk
 *  const char *filename    // name we use within JSON summary, and as the filename within outputDir
 */
static bool write(SkCanvas* canvas, const SkString* path, ImageResultsSummary *jsonSummaryPtr) {
    SkASSERT(canvas != NULL);
    if (NULL == canvas) {
        return false;
    }

    SkASSERT(path != NULL);  // TODO(epoger): we want to remove this constraint, as noted above
    SkString fullPathname(*path);
    fullPathname.append(".png");

    SkBitmap bitmap;
    SkISize size = canvas->getDeviceSize();
    sk_tools::setup_bitmap(&bitmap, size.width(), size.height());

    canvas->readPixels(&bitmap, 0, 0);
    sk_tools::force_all_opaque(bitmap);

    if (NULL != jsonSummaryPtr) {
        // EPOGER: This is a hacky way of constructing the filename associated with the
        // image checksum; we assume that outputDir is not NULL, and we remove outputDir
        // from fullPathname.
        //
        // EPOGER: what about including the config type within hashFilename?  That way,
        // we could combine results of different config types without conflicting filenames.
        SkString hashFilename;
        sk_tools::get_basename(&hashFilename, fullPathname);
        jsonSummaryPtr->add(hashFilename.c_str(), bitmap);
    }

    return SkImageEncoder::EncodeFile(fullPathname.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
}
bool Canvas2DLayerBridge::restoreSurface()
{
    ASSERT(!m_destructionInProgress);
    if (m_destructionInProgress)
        return false;
    ASSERT(m_layer && !m_isSurfaceValid);

    WebGraphicsContext3D* sharedContext = 0;
    m_layer->clearTexture();
    m_contextProvider = adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider());
    if (m_contextProvider)
        sharedContext = m_contextProvider->context3d();

    if (sharedContext && !sharedContext->isContextLost()) {
        SkISize skSize = m_canvas->getBaseLayerSize();
        IntSize size(skSize.width(), skSize.height());
        RefPtr<SkSurface> surface(createSkSurface(m_contextProvider->grContext(), size, m_msaaSampleCount, m_opacityMode));
        if (surface.get()) {
            m_surface = surface.release();
            m_canvas->setSurface(m_surface.get());
            m_isSurfaceValid = true;
            // FIXME: draw sad canvas picture into new buffer crbug.com/243842
        }
    }

    return m_isSurfaceValid;
}
sk_sp<SkImageFilter> SkMatrixConvolutionImageFilter::Make(const SkISize& kernelSize,
                                                          const SkScalar* kernel,
                                                          SkScalar gain,
                                                          SkScalar bias,
                                                          const SkIPoint& kernelOffset,
                                                          TileMode tileMode,
                                                          bool convolveAlpha,
                                                          sk_sp<SkImageFilter> input,
                                                          const CropRect* cropRect) {
    if (kernelSize.width() < 1 || kernelSize.height() < 1) {
        return nullptr;
    }
    if (gMaxKernelSize / kernelSize.fWidth < kernelSize.fHeight) {
        return nullptr;
    }
    if (!kernel) {
        return nullptr;
    }
    if ((kernelOffset.fX < 0) || (kernelOffset.fX >= kernelSize.fWidth) ||
        (kernelOffset.fY < 0) || (kernelOffset.fY >= kernelSize.fHeight)) {
        return nullptr;
    }
    return sk_sp<SkImageFilter>(new SkMatrixConvolutionImageFilter(kernelSize, kernel, gain,
                                                                   bias, kernelOffset,
                                                                   tileMode, convolveAlpha,
                                                                   std::move(input), cropRect));
}
Exemple #21
0
/*
 * Read enough of the stream to initialize the SkGifCodec.
 * Returns a bool representing success or failure.
 *
 * @param codecOut
 * If it returned true, and codecOut was not nullptr,
 * codecOut will be set to a new SkGifCodec.
 *
 * @param gifOut
 * If it returned true, and codecOut was nullptr,
 * gifOut must be non-nullptr and gifOut will be set to a new
 * GifFileType pointer.
 *
 * @param stream
 * Deleted on failure.
 * codecOut will take ownership of it in the case where we created a codec.
 * Ownership is unchanged when we returned a gifOut.
 *
 */
bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, GifFileType** gifOut) {
    SkAutoTDelete<SkStream> streamDeleter(stream);

    // Read gif header, logical screen descriptor, and global color table
    SkAutoTCallVProc<GifFileType, CloseGif> gif(open_gif(stream));

    if (nullptr == gif) {
        gif_error("DGifOpen failed.\n");
        return false;
    }

    // Read through gif extensions to get to the image data.  Set the
    // transparent index based on the extension data.
    uint32_t transIndex;
    SkCodec::Result result = ReadUpToFirstImage(gif, &transIndex);
    if (kSuccess != result){
        return false;
    }

    // Read the image descriptor
    if (GIF_ERROR == DGifGetImageDesc(gif)) {
        return false;
    }
    // If reading the image descriptor is successful, the image count will be
    // incremented.
    SkASSERT(gif->ImageCount >= 1);

    if (nullptr != codecOut) {
        SkISize size;
        SkIRect frameRect;
        if (!GetDimensions(gif, &size, &frameRect)) {
            gif_error("Invalid gif size.\n");
            return false;
        }
        bool frameIsSubset = (size != frameRect.size());

        // Determine the encoded alpha type.  The transIndex might be valid if it less
        // than 256.  We are not certain that the index is valid until we process the color
        // table, since some gifs have color tables with less than 256 colors.  If
        // there might be a valid transparent index, we must indicate that the image has
        // alpha.
        // In the case where we must support alpha, we indicate kBinary, since every
        // pixel will either be fully opaque or fully transparent.
        SkEncodedInfo::Alpha alpha = (transIndex < 256) ? SkEncodedInfo::kBinary_Alpha :
                SkEncodedInfo::kOpaque_Alpha;

        // Return the codec
        // Use kPalette since Gifs are encoded with a color table.
        // Use 8-bits per component, since this is the output we get from giflib.
        // FIXME: Gifs can actually be encoded with 4-bits per pixel.  Can we support this?
        SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, alpha, 8);
        *codecOut = new SkGifCodec(size.width(), size.height(), info, streamDeleter.release(),
                gif.release(), transIndex, frameRect, frameIsSubset);
    } else {
        SkASSERT(nullptr != gifOut);
        streamDeleter.release();
        *gifOut = gif.release();
    }
    return true;
}
SkFlattenable* SkMatrixConvolutionImageFilter::CreateProc(SkReadBuffer& buffer) {
    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
    SkISize kernelSize;
    kernelSize.fWidth = buffer.readInt();
    kernelSize.fHeight = buffer.readInt();
    const int count = buffer.getArrayCount();

    const int64_t kernelArea = sk_64_mul(kernelSize.width(), kernelSize.height());
    if (!buffer.validate(kernelArea == count)) {
        return nullptr;
    }
    SkAutoSTArray<16, SkScalar> kernel(count);
    if (!buffer.readScalarArray(kernel.get(), count)) {
        return nullptr;
    }
    SkScalar gain = buffer.readScalar();
    SkScalar bias = buffer.readScalar();
    SkIPoint kernelOffset;
    kernelOffset.fX = buffer.readInt();
    kernelOffset.fY = buffer.readInt();
    TileMode tileMode = (TileMode)buffer.readInt();
    bool convolveAlpha = buffer.readBool();
    return Create(kernelSize, kernel.get(), gain, bias, kernelOffset, tileMode, convolveAlpha,
                  common.getInput(0), &common.cropRect());
}
// unused
static void TestNWayCanvasStateConsistency(
    skiatest::Reporter* reporter,
    const TestData& d,
    CanvasTestStep* testStep,
    const SkCanvas& referenceCanvas) {

    SkBitmap indirectStore1;
    createBitmap(&indirectStore1, 0xFFFFFFFF);
    SkCanvas indirectCanvas1(indirectStore1);

    SkBitmap indirectStore2;
    createBitmap(&indirectStore2, 0xFFFFFFFF);
    SkCanvas indirectCanvas2(indirectStore2);

    SkISize canvasSize = referenceCanvas.getDeviceSize();
    SkNWayCanvas nWayCanvas(canvasSize.width(), canvasSize.height());
    nWayCanvas.addCanvas(&indirectCanvas1);
    nWayCanvas.addCanvas(&indirectCanvas2);

    testStep->setAssertMessageFormat(kNWayDrawAssertMessageFormat);
    testStep->draw(&nWayCanvas, d, reporter);
    // Verify that the SkNWayCanvas reports consitent state
    testStep->setAssertMessageFormat(kNWayStateAssertMessageFormat);
    AssertCanvasStatesEqual(reporter, d, &nWayCanvas, &referenceCanvas, testStep);
    // Verify that the indirect canvases report consitent state
    testStep->setAssertMessageFormat(kNWayIndirect1StateAssertMessageFormat);
    AssertCanvasStatesEqual(reporter, d, &indirectCanvas1, &referenceCanvas, testStep);
    testStep->setAssertMessageFormat(kNWayIndirect2StateAssertMessageFormat);
    AssertCanvasStatesEqual(reporter, d, &indirectCanvas2, &referenceCanvas, testStep);
}
Exemple #24
0
static void test_mipmap_generation(int width, int height, int expectedMipLevelCount,
                                   skiatest::Reporter* reporter) {
    SkBitmap bm;
    bm.allocN32Pixels(width, height);
    bm.eraseColor(SK_ColorWHITE);
    SkAutoTUnref<SkMipMap> mm(SkMipMap::Build(bm, nullptr));

    const int mipLevelCount = mm->countLevels();
    REPORTER_ASSERT(reporter, mipLevelCount == expectedMipLevelCount);
    REPORTER_ASSERT(reporter, mipLevelCount == SkMipMap::ComputeLevelCount(width, height));
    for (int i = 0; i < mipLevelCount; ++i) {
        SkMipMap::Level level;
        REPORTER_ASSERT(reporter, mm->getLevel(i, &level));
        // Make sure the mipmaps contain valid data and that the sizes are correct
        REPORTER_ASSERT(reporter, level.fPixmap.addr());
        SkISize size = SkMipMap::ComputeLevelSize(width, height, i);
        REPORTER_ASSERT(reporter, level.fPixmap.width() == size.width());
        REPORTER_ASSERT(reporter, level.fPixmap.height() == size.height());

        // + 1 because SkMipMap does not include the base mipmap level.
        int twoToTheMipLevel = 1 << (i + 1);
        int currentWidth = width / twoToTheMipLevel;
        int currentHeight = height / twoToTheMipLevel;
        REPORTER_ASSERT(reporter, level.fPixmap.width() == currentWidth);
        REPORTER_ASSERT(reporter, level.fPixmap.height() == currentHeight);
    }
}
static bool write_bitmap(const char outName[], const SkBitmap& bm) {
    SkISize size = opaqueSize(bm);
    SkBitmap dst;
    setup_bitmap(&dst, size.width(), size.height());

    for (int y = 0 ; y < dst.height(); y++) {
        for (int x = 0 ; x < dst.width(); x++) {
            SkColor color = bm.getColor(x, y);
            if (SkColorGetA(color) != 0xff) {
                int a = SkColorGetA(color);
                int r = SkColorGetR(color);
                int g = SkColorGetG(color);
                int b = SkColorGetB(color);
                if (a == 0) {
                    r = g = b = 0;
                } else {
                    r = (r * a) / 255;
                    g = (g * a) / 255;
                    b = (b * a) / 255;
                    a = 255;
                }
                color = SkColorSetARGB((U8CPU)a, (U8CPU)r, (U8CPU)g, (U8CPU)b);
            }
            *dst.getAddr32(x, y) = color;
        }
    }

    return SkImageEncoder::EncodeFile(outName, dst, SkImageEncoder::kPNG_Type, 100);
}
std::unique_ptr<SkImageGenerator>
SkPictureImageGenerator::Make(const SkISize& size, sk_sp<SkPicture> picture, const SkMatrix* matrix,
                              const SkPaint* paint, SkImage::BitDepth bitDepth,
                              sk_sp<SkColorSpace> colorSpace) {
    if (!picture || size.isEmpty()) {
        return nullptr;
    }

    if (SkImage::BitDepth::kF16 == bitDepth && (!colorSpace || !colorSpace->gammaIsLinear())) {
        return nullptr;
    }

    if (colorSpace && (!colorSpace->gammaCloseToSRGB() && !colorSpace->gammaIsLinear())) {
        return nullptr;
    }

    SkColorType colorType = kN32_SkColorType;
    if (SkImage::BitDepth::kF16 == bitDepth) {
        colorType = kRGBA_F16_SkColorType;
    }

    SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType,
                                         kPremul_SkAlphaType, std::move(colorSpace));
    return std::unique_ptr<SkImageGenerator>(
                             new SkPictureImageGenerator(info, std::move(picture), matrix, paint));
}
static sk_sp<SkSpecialImage> apply_morphology(
                                          GrContext* context,
                                          SkSpecialImage* input,
                                          const SkIRect& rect,
                                          GrMorphologyEffect::Type morphType,
                                          SkISize radius,
                                          const SkImageFilter::OutputProperties& outputProperties) {
    sk_sp<GrTextureProxy> srcTexture(input->asTextureProxyRef(context));
    SkASSERT(srcTexture);
    sk_sp<SkColorSpace> colorSpace = sk_ref_sp(outputProperties.colorSpace());
    GrPixelConfig config = SkColorType2GrPixelConfig(outputProperties.colorType());

    // setup new clip
    const GrFixedClip clip(SkIRect::MakeWH(srcTexture->width(), srcTexture->height()));

    const SkIRect dstRect = SkIRect::MakeWH(rect.width(), rect.height());
    SkIRect srcRect = rect;

    SkASSERT(radius.width() > 0 || radius.height() > 0);

    if (radius.fWidth > 0) {
        sk_sp<GrRenderTargetContext> dstRTContext(
            context->contextPriv().makeDeferredRenderTargetContext(
                SkBackingFit::kApprox, rect.width(), rect.height(), config, colorSpace));
        if (!dstRTContext) {
            return nullptr;
        }

        apply_morphology_pass(dstRTContext.get(), clip, std::move(srcTexture), srcRect, dstRect,
                              radius.fWidth, morphType, GrMorphologyEffect::Direction::kX);
        SkIRect clearRect = SkIRect::MakeXYWH(dstRect.fLeft, dstRect.fBottom,
                                              dstRect.width(), radius.fHeight);
        GrColor clearColor =
                GrMorphologyEffect::Type::kErode == morphType ? SK_ColorWHITE : SK_ColorTRANSPARENT;
        dstRTContext->clear(&clearRect, clearColor, GrRenderTargetContext::CanClearFullscreen::kNo);

        srcTexture = dstRTContext->asTextureProxyRef();
        srcRect = dstRect;
    }
    if (radius.fHeight > 0) {
        sk_sp<GrRenderTargetContext> dstRTContext(
            context->contextPriv().makeDeferredRenderTargetContext(
                SkBackingFit::kApprox, rect.width(), rect.height(), config, colorSpace));
        if (!dstRTContext) {
            return nullptr;
        }

        apply_morphology_pass(dstRTContext.get(), clip, std::move(srcTexture), srcRect, dstRect,
                              radius.fHeight, morphType, GrMorphologyEffect::Direction::kY);

        srcTexture = dstRTContext->asTextureProxyRef();
    }

    return SkSpecialImage::MakeDeferredFromGpu(context,
                                               SkIRect::MakeWH(rect.width(), rect.height()),
                                               kNeedNewImageUniqueID_SpecialImage,
                                               std::move(srcTexture), std::move(colorSpace),
                                               &input->props());
}
bool GrAtlasManager::initAtlas(GrMaskFormat format) {
    int index = MaskFormatToAtlasIndex(format);
    if (fAtlases[index] == nullptr) {
        GrPixelConfig config = mask_format_to_pixel_config(format);
        SkISize atlasDimensions = fAtlasConfigs.atlasDimensions(format);
        SkISize numPlots = fAtlasConfigs.numPlots(format);

        fAtlases[index] = GrDrawOpAtlas::Make(
                fProxyProvider, config, atlasDimensions.width(), atlasDimensions.height(),
                numPlots.width(), numPlots.height(), fAllowMultitexturing,
                &GrGlyphCache::HandleEviction, fGlyphCache);
        if (!fAtlases[index]) {
            return false;
        }
    }
    return true;
}
 void drawRect(SkCanvas* canvas, int x, int y, const SkPaint& paint, const SkISize& size) {
     canvas->save();
     canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
     SkRect r = SkRect::MakeWH(SkIntToScalar(size.width()),
                               SkIntToScalar(size.height()));
     canvas->drawRect(r, paint);
     canvas->restore();
 }
Exemple #30
0
void GM::drawSizeBounds(SkCanvas* canvas, SkColor color) {
    SkISize size = this->getISize();
    SkRect r = SkRect::MakeWH(SkIntToScalar(size.width()),
                              SkIntToScalar(size.height()));
    SkPaint paint;
    paint.setColor(color);
    canvas->drawRect(r, paint);
}