DEF_TEST(Picture_BitmapLeak, r) { SkBitmap mut, immut; mut.allocN32Pixels(300, 200); immut.allocN32Pixels(300, 200); immut.setImmutable(); SkASSERT(!mut.isImmutable()); SkASSERT(immut.isImmutable()); // No one can hold a ref on our pixels yet. REPORTER_ASSERT(r, mut.pixelRef()->unique()); REPORTER_ASSERT(r, immut.pixelRef()->unique()); SkAutoTUnref<const SkPicture> pic; { // we want the recorder to go out of scope before our subsequent checks, so we // place it inside local braces. SkPictureRecorder rec; SkCanvas* canvas = rec.beginRecording(1920, 1200); canvas->drawBitmap(mut, 0, 0); canvas->drawBitmap(immut, 800, 600); pic.reset(rec.endRecording()); } // The picture shares the immutable pixels but copies the mutable ones. REPORTER_ASSERT(r, mut.pixelRef()->unique()); REPORTER_ASSERT(r, !immut.pixelRef()->unique()); // When the picture goes away, it's just our bitmaps holding the refs. pic.reset(NULL); REPORTER_ASSERT(r, mut.pixelRef()->unique()); REPORTER_ASSERT(r, immut.pixelRef()->unique()); }
static void drawVertices_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, SkGPipeState* state) { unsigned flags = DrawOp_unpackFlags(op32); SkCanvas::VertexMode vmode = (SkCanvas::VertexMode)reader->readU32(); int vertexCount = reader->readU32(); const SkPoint* verts = skip<SkPoint>(reader, vertexCount); const SkPoint* texs = NULL; if (flags & kDrawVertices_HasTexs_DrawOpFlag) { texs = skip<SkPoint>(reader, vertexCount); } const SkColor* colors = NULL; if (flags & kDrawVertices_HasColors_DrawOpFlag) { colors = skip<SkColor>(reader, vertexCount); } SkAutoTUnref<SkXfermode> xfer; if (flags & kDrawVertices_HasXfermode_DrawOpFlag) { SkXfermode::Mode mode = (SkXfermode::Mode)reader->readU32(); xfer.reset(SkXfermode::Create(mode)); } int indexCount = 0; const uint16_t* indices = NULL; if (flags & kDrawVertices_HasIndices_DrawOpFlag) { indexCount = reader->readU32(); indices = skipAlign<uint16_t>(reader, indexCount); } if (state->shouldDraw()) { canvas->drawVertices(vmode, vertexCount, verts, texs, colors, xfer, indices, indexCount, state->paint()); } }
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)); }
GrGpu* GrGpu::Create(GrBackend backend, GrBackendContext backendContext, GrContext* context) { const GrGLInterface* glInterface = NULL; SkAutoTUnref<const GrGLInterface> glInterfaceUnref; if (kOpenGL_GrBackend == backend) { glInterface = reinterpret_cast<const GrGLInterface*>(backendContext); if (NULL == glInterface) { glInterface = GrGLDefaultInterface(); // By calling GrGLDefaultInterface we've taken a ref on the // returned object. We only want to hold that ref until after // the GrGpu is constructed and has taken ownership. glInterfaceUnref.reset(glInterface); } if (NULL == glInterface) { #ifdef SK_DEBUG GrPrintf("No GL interface provided!\n"); #endif return NULL; } GrGLContext ctx(glInterface); if (ctx.isInitialized()) { return SkNEW_ARGS(GrGpuGL, (ctx, context)); } } return NULL; }
sk_sp<SkImage> SkImage::MakeFromBitmap(const SkBitmap& bm) { SkPixelRef* pr = bm.pixelRef(); if (nullptr == pr) { return nullptr; } #if SK_SUPPORT_GPU if (GrTexture* tex = pr->getTexture()) { SkAutoTUnref<GrTexture> unrefCopy; if (!bm.isImmutable()) { tex = GrDeepCopyTexture(tex, SkBudgeted::kNo); if (nullptr == tex) { return nullptr; } unrefCopy.reset(tex); } const SkImageInfo info = bm.info(); return sk_make_sp<SkImage_Gpu>(info.width(), info.height(), bm.getGenerationID(), info.alphaType(), tex, sk_ref_sp(info.colorSpace()), SkBudgeted::kNo); } #endif // This will check for immutable (share or copy) return SkMakeImageFromRasterBitmap(bm); }
bool SkImageGenerator::tryGenerateBitmap(SkBitmap* bitmap, const SkImageInfo* infoPtr) { const SkImageInfo info = infoPtr ? *infoPtr : this->getInfo(); const size_t rowBytes = info.minRowBytes(); const size_t pixelSize = info.getSafeSize(rowBytes); if (0 == pixelSize) { return false; } SkAutoFree pixelStorage(sk_malloc_flags(pixelSize, 0)); void* pixels = pixelStorage.get(); if (!pixels) { return false; } SkPMColor ctStorage[256]; int ctCount = 0; if (!this->getPixels(info, pixels, rowBytes, ctStorage, &ctCount)) { return false; } SkAutoTUnref<SkColorTable> ctable; if (ctCount > 0) { SkASSERT(kIndex_8_SkColorType == info.colorType()); ctable.reset(new SkColorTable(ctStorage, ctCount)); } else { SkASSERT(kIndex_8_SkColorType != info.colorType()); } return bitmap->installPixels(info, pixelStorage.detach(), rowBytes, ctable, release_malloc_proc, nullptr); }
void drawHere(SkCanvas* canvas, SkFilterQuality filter, SkScalar dx, SkScalar dy) { SkCanvas* origCanvas = canvas; SkAutoCanvasRestore acr(canvas, true); SkISize size = SkISize::Make(fImage->width(), fImage->height()); SkAutoTUnref<SkSurface> surface; if (fShowFatBits) { // scale up so we don't clip rotations SkImageInfo info = SkImageInfo::MakeN32(fImage->width() * 2, fImage->height() * 2, kOpaque_SkAlphaType); surface.reset(make_surface(canvas, info)); canvas = surface->getCanvas(); canvas->drawColor(SK_ColorWHITE); size.set(info.width(), info.height()); } else { canvas->translate(SkScalarHalf(fCell.width() - fImage->width()), SkScalarHalf(fCell.height() - fImage->height())); } this->drawTheImage(canvas, size, filter, dx, dy); if (surface) { SkAutoTUnref<SkImage> orig(surface->newImageSnapshot()); SkAutoTUnref<SkImage> zoomed(zoom_up(orig)); origCanvas->drawImage(zoomed, SkScalarHalf(fCell.width() - zoomed->width()), SkScalarHalf(fCell.height() - zoomed->height())); } }
void FatBits::drawRect(SkCanvas* canvas, SkPoint pts[2]) { SkPaint paint; fInverse.mapPoints(pts, 2); if (fGrid) { apply_grid(pts, 2); } SkRect r; r.set(pts, 2); erase(fMinSurface); this->setupPaint(&paint); paint.setColor(FAT_PIXEL_COLOR); { SkCanvas* c = fMinSurface->getCanvas(); fRectAsOval ? c->drawOval(r, paint) : c->drawRect(r, paint); } this->copyMinToMax(); SkCanvas* max = fMaxSurface->getCanvas(); fMatrix.mapPoints(pts, 2); r.set(pts, 2); this->drawRectSkeleton(max, r); fMaxSurface->draw(canvas, 0, 0, NULL); }
// Make sure the abort callback works DEF_TEST(RecordReplaceDraw_Abort, r) { SkAutoTUnref<const SkPicture> pic; { // Record two commands. SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kWidth), SkIntToScalar(kHeight)); canvas->drawRect(SkRect::MakeWH(SkIntToScalar(kWidth), SkIntToScalar(kHeight)), SkPaint()); canvas->clipRect(SkRect::MakeWH(SkIntToScalar(kWidth), SkIntToScalar(kHeight))); pic.reset(recorder.endRecording()); } SkRecord rerecord; SkRecorder canvas(&rerecord, kWidth, kHeight); JustOneDraw callback; GrRecordReplaceDraw(pic, &canvas, nullptr, SkMatrix::I(), &callback); switch (rerecord.count()) { case 3: assert_type<SkRecords::Save>(r, rerecord, 0); assert_type<SkRecords::DrawRect>(r, rerecord, 1); assert_type<SkRecords::Restore>(r, rerecord, 2); break; case 1: assert_type<SkRecords::DrawRect>(r, rerecord, 0); break; default: REPORTER_ASSERT(r, false); } }
void onDraw(SkCanvas* canvas) override { SkPaint paint; paint.setAntiAlias(true); paint.setLCDRenderText(true); paint.setSubpixelText(true); paint.setTextSize(17); static const char* gNames[] = { "Helvetica Neue", "Arial" }; SkAutoTUnref<SkFontStyleSet> fset; for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); ++i) { fset.reset(fFM->matchFamily(gNames[i])); if (fset->count() > 0) { break; } } if (nullptr == fset.get()) { return; } canvas->translate(20, 40); this->exploreFamily(canvas, paint, fset); canvas->translate(150, 0); this->iterateFamily(canvas, paint, fset); }
SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) { printf("Started\n"); SkCommandLineFlags::Parse(argc, argv); // Get the default Isolate created at startup. Isolate* isolate = Isolate::GetCurrent(); Global* global = new Global(isolate); // Set up things to look like a browser by creating // a console object that invokes our print function. const char* startupScript = "function Console() {}; \n" "Console.prototype.log = function() { \n" " var args = Array.prototype.slice.call(arguments).join(' '); \n" " print(args); \n" "}; \n" "console = new Console(); \n"; if (!global->parseScript(startupScript)) { printf("Failed to parse startup script: %s.\n", FLAGS_infile[0]); exit(1); } const char* script = "function onDraw(canvas) { \n" " canvas.fillStyle = '#00FF00'; \n" " canvas.fillRect(20, 20, 100, 100); \n" " canvas.inval(); \n" "} \n"; SkAutoTUnref<SkData> data; if (FLAGS_infile.count()) { data.reset(SkData::NewFromFileName(FLAGS_infile[0])); script = static_cast<const char*>(data->data()); } if (NULL == script) { printf("Could not load file: %s.\n", FLAGS_infile[0]); exit(1); } Path2D::AddToGlobal(global); if (!global->parseScript(script)) { printf("Failed to parse file: %s.\n", FLAGS_infile[0]); exit(1); } JsContext* jsContext = new JsContext(global); if (!jsContext->initialize()) { printf("Failed to initialize.\n"); exit(1); } SkV8ExampleWindow* win = new SkV8ExampleWindow(hwnd, jsContext); global->setWindow(win); return win; }
sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot(SkBudgeted budgeted, ForceCopyMode forceCopyMode) { GrRenderTarget* rt = fDevice->accessDrawContext()->accessRenderTarget(); SkASSERT(rt); GrTexture* tex = rt->asTexture(); SkAutoTUnref<GrTexture> copy; // If the original render target is a buffer originally created by the client, then we don't // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid // copy-on-write. if (kYes_ForceCopyMode == forceCopyMode || !tex || rt->resourcePriv().refsWrappedObjects()) { GrSurfaceDesc desc = fDevice->accessDrawContext()->desc(); GrContext* ctx = fDevice->context(); desc.fFlags = desc.fFlags & ~kRenderTarget_GrSurfaceFlag; copy.reset(ctx->textureProvider()->createTexture(desc, budgeted)); if (!copy) { return nullptr; } if (!ctx->copySurface(copy, rt)) { return nullptr; } tex = copy; } const SkImageInfo info = fDevice->imageInfo(); sk_sp<SkImage> image; if (tex) { image = sk_make_sp<SkImage_Gpu>(info.width(), info.height(), kNeedNewImageUniqueID, info.alphaType(), tex, sk_ref_sp(info.colorSpace()), budgeted); } return image; }
SkImage* SkSurface_Gpu::onNewImageSnapshot(SkBudgeted budgeted, ForceCopyMode forceCopyMode) { GrRenderTarget* rt = fDevice->accessRenderTarget(); SkASSERT(rt); GrTexture* tex = rt->asTexture(); SkAutoTUnref<GrTexture> copy; // TODO: Force a copy when the rt is an external resource. if (kYes_ForceCopyMode == forceCopyMode || !tex) { GrSurfaceDesc desc = fDevice->accessRenderTarget()->desc(); GrContext* ctx = fDevice->context(); desc.fFlags = desc.fFlags & ~kRenderTarget_GrSurfaceFlag; copy.reset(ctx->textureProvider()->createTexture(desc, budgeted)); if (!copy) { return nullptr; } if (!ctx->copySurface(copy, rt)) { return nullptr; } tex = copy; } const SkImageInfo info = fDevice->imageInfo(); SkImage* image = nullptr; if (tex) { image = new SkImage_Gpu(info.width(), info.height(), kNeedNewImageUniqueID, info.alphaType(), tex, budgeted); } return image; }
SkFlattenable* SkPictureImageFilter::CreateProc(SkReadBuffer& buffer) { SkAutoTUnref<SkPicture> picture; SkRect cropRect; if (buffer.isCrossProcess() && SkPicture::PictureIOSecurityPrecautionsEnabled()) { buffer.validate(!buffer.readBool()); } else { if (buffer.readBool()) { picture.reset(SkPicture::CreateFromBuffer(buffer)); } } buffer.readRect(&cropRect); PictureResolution pictureResolution; if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterResolution_Version)) { pictureResolution = kDeviceSpace_PictureResolution; } else { pictureResolution = (PictureResolution)buffer.readInt(); } if (kLocalSpace_PictureResolution == pictureResolution) { //filterLevel is only serialized if pictureResolution is LocalSpace SkFilterQuality filterQuality; if (buffer.isVersionLT(SkReadBuffer::kPictureImageFilterLevel_Version)) { filterQuality = kLow_SkFilterQuality; } else { filterQuality = (SkFilterQuality)buffer.readInt(); } return CreateForLocalSpace(picture, cropRect, filterQuality); } return Create(picture, cropRect); }
void FatBits::drawTriangle(SkCanvas* canvas, SkPoint pts[3]) { SkPaint paint; fInverse.mapPoints(pts, 3); if (fGrid) { apply_grid(pts, 3); } SkPath path; path.moveTo(pts[0]); path.lineTo(pts[1]); path.lineTo(pts[2]); path.close(); erase(fMinSurface); this->setupPaint(&paint); paint.setColor(FAT_PIXEL_COLOR); fMinSurface->getCanvas()->drawPath(path, paint); this->copyMinToMax(); SkCanvas* max = fMaxSurface->getCanvas(); fMatrix.mapPoints(pts, 3); this->drawTriangleSkeleton(max, pts); fMaxSurface->draw(canvas, 0, 0, NULL); }
SkImage* SkImage::NewFromBitmap(const SkBitmap& bm) { SkPixelRef* pr = bm.pixelRef(); if (nullptr == pr) { return nullptr; } #if SK_SUPPORT_GPU if (GrTexture* tex = pr->getTexture()) { SkAutoTUnref<GrTexture> unrefCopy; if (!bm.isImmutable()) { const bool notBudgeted = false; tex = GrDeepCopyTexture(tex, notBudgeted); if (nullptr == tex) { return nullptr; } unrefCopy.reset(tex); } const SkImageInfo info = bm.info(); return new SkImage_Gpu(info.width(), info.height(), bm.getGenerationID(), info.alphaType(), tex, 0, SkSurface::kNo_Budgeted); } #endif // This will check for immutable (share or copy) return SkNewImageFromRasterBitmap(bm, nullptr); }
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; }
// Tests that SkNewImageFromBitmap obeys pixelref origin. DEF_TEST(SkImageFromBitmap_extractSubset, reporter) { SkAutoTUnref<SkImage> image; { SkBitmap srcBitmap; srcBitmap.allocN32Pixels(gWidth, gHeight); srcBitmap.eraseColor(SK_ColorRED); SkBitmapDevice dev(srcBitmap); SkCanvas canvas(&dev); SkIRect r = SkIRect::MakeXYWH(5, 5, gWidth - 5, gWidth - 5); SkPaint p; p.setColor(SK_ColorGREEN); canvas.drawIRect(r, p); SkBitmap dstBitmap; srcBitmap.extractSubset(&dstBitmap, r); image.reset(SkNewImageFromBitmap(dstBitmap, true, NULL)); } SkBitmap tgt; tgt.allocN32Pixels(gWidth, gHeight); SkBitmapDevice dev(tgt); SkCanvas canvas(&dev); canvas.clear(SK_ColorTRANSPARENT); canvas.drawImage(image, 0, 0, NULL); uint32_t pixel = 0; SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); canvas.readPixels(info, &pixel, 4, 0, 0); REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN); canvas.readPixels(info, &pixel, 4, gWidth - 6, gWidth - 6); REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN); canvas.readPixels(info, &pixel, 4, gWidth - 5, gWidth - 5); REPORTER_ASSERT(reporter, pixel == SK_ColorTRANSPARENT); }
static jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jlong native_asset) { android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset); if (asset == NULL) return NULL; SkAutoTUnref<SkStreamRewindable> stream (new android::AssetStreamAdaptor(asset)); SkMovie* moov = SkMovie::DecodeStream(stream.get()); return create_jmovie(env, moov); }
static void drawPatch_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, SkGPipeState* state) { unsigned flags = DrawOp_unpackFlags(op32); const SkPoint* cubics = skip<SkPoint>(reader, SkPatchUtils::kNumCtrlPts); const SkColor* colors = NULL; if (flags & kDrawVertices_HasColors_DrawOpFlag) { colors = skip<SkColor>(reader, SkPatchUtils::kNumCorners); } const SkPoint* texCoords = NULL; if (flags & kDrawVertices_HasTexs_DrawOpFlag) { texCoords = skip<SkPoint>(reader, SkPatchUtils::kNumCorners); } SkAutoTUnref<SkXfermode> xfer; if (flags & kDrawVertices_HasXfermode_DrawOpFlag) { int mode = reader->readInt(); if (mode < 0 || mode > SkXfermode::kLastMode) { mode = SkXfermode::kModulate_Mode; } xfer.reset(SkXfermode::Create((SkXfermode::Mode)mode)); } if (state->shouldDraw()) { canvas->drawPatch(cubics, colors, texCoords, xfer, state->paint()); } }
void onPrepareDraws(Target* target) const override { // construct a cache key from the path's genID and the view matrix static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey key; int clipBoundsSize32 = fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) : 0; int strokeDataSize32 = fStroke.computeUniqueKeyFragmentData32Cnt(); GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32 + strokeDataSize32); builder[0] = fPath.getGenerationID(); builder[1] = fPath.getFillType(); // For inverse fills, the tessellation is dependent on clip bounds. if (fPath.isInverseFillType()) { memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds)); } fStroke.asUniqueKeyFragment(&builder[2 + clipBoundsSize32]); builder.finish(); GrResourceProvider* rp = target->resourceProvider(); SkAutoTUnref<GrVertexBuffer> vertexBuffer(rp->findAndRefTByUniqueKey<GrVertexBuffer>(key)); int actualCount; SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; SkScalar tol = GrPathUtils::scaleToleranceToSrc( screenSpaceTol, fViewMatrix, fPath.getBounds()); if (!cache_match(vertexBuffer.get(), tol, &actualCount)) { bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags(); actualCount = this->tessellate(&key, rp, vertexBuffer, canMapVB); } if (actualCount == 0) { return; } SkAutoTUnref<const GrGeometryProcessor> gp; { using namespace GrDefaultGeoProcFactory; Color color(fColor); LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type); Coverage::Type coverageType; if (fPipelineInfo.readsCoverage()) { coverageType = Coverage::kSolid_Type; } else { coverageType = Coverage::kNone_Type; } Coverage coverage(coverageType); gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords, fViewMatrix)); } target->initDraw(gp, this->pipeline()); SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimitiveType : kTriangles_GrPrimitiveType; GrVertices vertices; vertices.init(primitiveType, vertexBuffer.get(), 0, actualCount); target->draw(vertices); }
SkTypeface* SkFontMgr_Indirect::createTypefaceFromFontId(const SkFontIdentity& id) const { if (id.fDataId == SkFontIdentity::kInvalidDataId) { return nullptr; } SkAutoMutexAcquire ama(fDataCacheMutex); SkAutoTUnref<SkTypeface> dataTypeface; int dataTypefaceIndex = 0; for (int i = 0; i < fDataCache.count(); ++i) { const DataEntry& entry = fDataCache[i]; if (entry.fDataId == id.fDataId) { if (entry.fTtcIndex == id.fTtcIndex && !entry.fTypeface->weak_expired() && entry.fTypeface->try_ref()) { return entry.fTypeface; } if (dataTypeface.get() == nullptr && !entry.fTypeface->weak_expired() && entry.fTypeface->try_ref()) { dataTypeface.reset(entry.fTypeface); dataTypefaceIndex = entry.fTtcIndex; } } if (entry.fTypeface->weak_expired()) { fDataCache.removeShuffle(i); --i; } } // No exact match, but did find a data match. if (dataTypeface.get() != nullptr) { SkAutoTDelete<SkStreamAsset> stream(dataTypeface->openStream(nullptr)); if (stream.get() != nullptr) { return fImpl->createFromStream(stream.release(), dataTypefaceIndex); } } // No data match, request data and add entry. SkAutoTDelete<SkStreamAsset> stream(fProxy->getData(id.fDataId)); if (stream.get() == nullptr) { return nullptr; } SkAutoTUnref<SkTypeface> typeface(fImpl->createFromStream(stream.release(), id.fTtcIndex)); if (typeface.get() == nullptr) { return nullptr; } DataEntry& newEntry = fDataCache.push_back(); typeface->weak_ref(); newEntry.fDataId = id.fDataId; newEntry.fTtcIndex = id.fTtcIndex; newEntry.fTypeface = typeface.get(); // weak reference passed to new entry. return typeface.release(); }
const GrFragmentProcessor* SkImageShader::asFragmentProcessor(GrContext* context, const SkMatrix& viewM, const SkMatrix* localMatrix, SkFilterQuality filterQuality, GrProcessorDataManager* mgr) const { SkMatrix matrix; matrix.setIDiv(fImage->width(), fImage->height()); SkMatrix lmInverse; if (!this->getLocalMatrix().invert(&lmInverse)) { return nullptr; } if (localMatrix) { SkMatrix inv; if (!localMatrix->invert(&inv)) { return nullptr; } lmInverse.postConcat(inv); } matrix.preConcat(lmInverse); SkShader::TileMode tm[] = { fTileModeX, fTileModeY }; // Must set wrap and filter on the sampler before requesting a texture. In two places below // we check the matrix scale factors to determine how to interpret the filter quality setting. // This completely ignores the complexity of the drawVertices case where explicit local coords // are provided by the caller. bool doBicubic; GrTextureParams::FilterMode textureFilterMode = GrSkFilterQualityToGrFilterMode(filterQuality, viewM, this->getLocalMatrix(), &doBicubic); GrTextureParams params(tm, textureFilterMode); SkImageUsageType usageType; if (kClamp_TileMode == fTileModeX && kClamp_TileMode == fTileModeY) { usageType = kUntiled_SkImageUsageType; } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) { usageType = kTiled_Unfiltered_SkImageUsageType; } else { usageType = kTiled_Filtered_SkImageUsageType; } SkAutoTUnref<GrTexture> texture(as_IB(fImage)->asTextureRef(context, usageType)); if (!texture) { return nullptr; } SkAutoTUnref<GrFragmentProcessor> inner; if (doBicubic) { inner.reset(GrBicubicEffect::Create(mgr, texture, matrix, tm)); } else { inner.reset(GrSimpleTextureEffect::Create(mgr, texture, matrix, params)); } if (GrPixelConfigIsAlphaOnly(texture->config())) { return SkRef(inner.get()); } return GrFragmentProcessor::MulOuputByInputAlpha(inner); }
void onPrepareDraws(Target* target) const override { SkAutoTUnref<const GrGeometryProcessor> gp; { using namespace GrDefaultGeoProcFactory; Color color(this->color()); Coverage coverage(this->coverageIgnored() ? Coverage::kSolid_Type : Coverage::kNone_Type); LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type); gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords, this->viewMatrix())); } target->initDraw(gp, this->pipeline()); size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr)); const Geometry& args = fGeoData[0]; int vertexCount = kVertsPerHairlineRect; if (args.fStrokeWidth > 0) { vertexCount = kVertsPerStrokeRect; } const GrVertexBuffer* vertexBuffer; int firstVertex; void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex); if (!verts) { SkDebugf("Could not allocate vertices\n"); return; } SkPoint* vertex = reinterpret_cast<SkPoint*>(verts); GrPrimitiveType primType; if (args.fStrokeWidth > 0) {; primType = kTriangleStrip_GrPrimitiveType; init_stroke_rect_strip(vertex, args.fRect, args.fStrokeWidth); } else { // hairline primType = kLineStrip_GrPrimitiveType; vertex[0].set(args.fRect.fLeft, args.fRect.fTop); vertex[1].set(args.fRect.fRight, args.fRect.fTop); vertex[2].set(args.fRect.fRight, args.fRect.fBottom); vertex[3].set(args.fRect.fLeft, args.fRect.fBottom); vertex[4].set(args.fRect.fLeft, args.fRect.fTop); } GrVertices vertices; vertices.init(primType, vertexBuffer, firstVertex, vertexCount); target->draw(vertices); }
static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor, jobject padding, jobject bitmapFactoryOptions) { NPE_CHECK_RETURN_ZERO(env, fileDescriptor); jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); struct stat fdStat; if (fstat(descriptor, &fdStat) == -1) { doThrowIOE(env, "broken file descriptor"); return nullObjectReturn("fstat return -1"); } // Restore the descriptor's offset on exiting this function. AutoFDSeek autoRestore(descriptor); FILE* file = fdopen(descriptor, "r"); if (file == NULL) { return nullObjectReturn("Could not open file"); } SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file, SkFILEStream::kCallerRetains_Ownership)); SkAutoTUnref<SkStreamRewindable> stream; // Retain the old behavior of allowing purgeable if both purgeable and // shareable are set to true. bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions) && optionsShareable(env, bitmapFactoryOptions); if (isPurgeable) { // Copy the stream, so the image can be decoded multiple times without // continuing to modify the original file descriptor. // Copy beginning from the current position. const size_t fileSize = fileStream->getLength() - fileStream->getPosition(); void* buffer = sk_malloc_flags(fileSize, 0); if (buffer == NULL) { return nullObjectReturn("Could not make a copy for ashmem"); } SkAutoTUnref<SkData> data(SkData::NewFromMalloc(buffer, fileSize)); if (fileStream->read(buffer, fileSize) != fileSize) { return nullObjectReturn("Could not read the file."); } stream.reset(new SkMemoryStream(data)); } else { // Use a buffered stream. Although an SkFILEStream can be rewound, this // ensures that SkImageDecoder::Factory never rewinds beyond the // current position of the file descriptor. stream.reset(SkFrontBufferedStream::Create(fileStream, BYTES_TO_BUFFER)); } return doDecode(env, stream, padding, bitmapFactoryOptions, isPurgeable); }
static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader) { const BitmapShaderRec& rec = static_cast<const BitmapShaderRec&>(baseRec); SkAutoTUnref<SkShader>* result = reinterpret_cast<SkAutoTUnref<SkShader>*>(contextShader); result->reset(SkRef(rec.fShader.get())); // The bitmap shader is backed by an image generator, thus it can always re-generate its // pixels if discarded. return true; }
~ImageRenderingContext() { if (IsGpu) { SkAutoTUnref<SkImage> image; image.reset(Surface->newImageSnapshot(SkSurface::kNo_Budgeted)); image.get()->readPixels(Image->Bitmap.info(), Image->Bitmap.getPixels(), Image->Bitmap.rowBytes(), 0, 0); } Surface.reset(nullptr); }
// Test out the layer replacement functionality with and w/o a BBH void test_replacements(skiatest::Reporter* r, GrContext* context, bool doReplace) { sk_sp<SkPicture> pic; { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kWidth), SkIntToScalar(kHeight)); SkPaint paint; canvas->saveLayer(nullptr, &paint); canvas->clear(SK_ColorRED); canvas->restore(); canvas->drawRect(SkRect::MakeWH(SkIntToScalar(kWidth / 2), SkIntToScalar(kHeight / 2)), SkPaint()); pic = recorder.finishRecordingAsPicture(); } SkAutoTUnref<GrTexture> texture; SkPaint paint; GrLayerCache* layerCache = context->getLayerCache(); if (doReplace) { int key[1] = { 0 }; GrCachedLayer* layer = layerCache->findLayerOrCreate(pic->uniqueID(), 0, 2, SkIRect::MakeWH(kWidth, kHeight), SkIRect::MakeWH(kWidth, kHeight), SkMatrix::I(), key, 1, &paint); GrSurfaceDesc desc; desc.fConfig = kSkia8888_GrPixelConfig; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = kWidth; desc.fHeight = kHeight; desc.fSampleCnt = 0; // Giving the texture some initial data so the Gpu (specifically vulkan) does not complain // when reading from an uninitialized texture. SkAutoTMalloc<uint32_t> srcBuffer(kWidth*kHeight); memset(srcBuffer.get(), 0, kWidth*kHeight*sizeof(uint32_t)); texture.reset(context->textureProvider()->createTexture( desc, SkBudgeted::kNo, srcBuffer.get(), 0)); layer->setTexture(texture, SkIRect::MakeWH(kWidth, kHeight), false); } SkRecord rerecord; SkRecorder canvas(&rerecord, kWidth, kHeight); GrRecordReplaceDraw(pic.get(), &canvas, layerCache, SkMatrix::I(), nullptr/*callback*/); int numLayers = count_instances_of_type<SkRecords::SaveLayer>(rerecord); if (doReplace) { REPORTER_ASSERT(r, 0 == numLayers); } else { REPORTER_ASSERT(r, 1 == numLayers); } }
SkCanvas* PictureRenderer::setupCanvas(int width, int height) { SkCanvas* canvas; switch(fDeviceType) { case kBitmap_DeviceType: { SkBitmap bitmap; sk_tools::setup_bitmap(&bitmap, width, height); canvas = SkNEW_ARGS(SkCanvas, (bitmap)); } break; #if SK_SUPPORT_GPU #if SK_ANGLE case kAngle_DeviceType: // fall through #endif #if SK_MESA case kMesa_DeviceType: // fall through #endif case kGPU_DeviceType: case kNVPR_DeviceType: { SkAutoTUnref<GrSurface> target; if (fGrContext) { // create a render target to back the device GrTextureDesc desc; desc.fConfig = kSkia8888_GrPixelConfig; desc.fFlags = kRenderTarget_GrTextureFlagBit; desc.fWidth = width; desc.fHeight = height; desc.fSampleCnt = fSampleCount; target.reset(fGrContext->createUncachedTexture(desc, NULL, 0)); } if (NULL == target.get()) { SkASSERT(0); return NULL; } SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(target)); canvas = SkNEW_ARGS(SkCanvas, (device.get())); break; } #endif default: SkASSERT(0); return NULL; } setUpFilter(canvas, fDrawFilters); this->scaleToScaleFactor(canvas); // Pictures often lie about their extent (i.e., claim to be 100x100 but // only ever draw to 90x100). Clear here so the undrawn portion will have // a consistent color canvas->clear(SK_ColorTRANSPARENT); return canvas; }
const GrFragmentProcessor* SkBitmapProcShader::asFragmentProcessor(GrContext* context, const SkMatrix& viewM, const SkMatrix* localMatrix, SkFilterQuality filterQuality, GrProcessorDataManager* procDataManager) const { SkMatrix matrix; matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height()); SkMatrix lmInverse; if (!this->getLocalMatrix().invert(&lmInverse)) { return nullptr; } if (localMatrix) { SkMatrix inv; if (!localMatrix->invert(&inv)) { return nullptr; } lmInverse.postConcat(inv); } matrix.preConcat(lmInverse); SkShader::TileMode tm[] = { (TileMode)fTileModeX, (TileMode)fTileModeY, }; // Must set wrap and filter on the sampler before requesting a texture. In two places below // we check the matrix scale factors to determine how to interpret the filter quality setting. // This completely ignores the complexity of the drawVertices case where explicit local coords // are provided by the caller. bool doBicubic; GrTextureParams::FilterMode textureFilterMode = GrSkFilterQualityToGrFilterMode(filterQuality, viewM, this->getLocalMatrix(), &doBicubic); GrTextureParams params(tm, textureFilterMode); SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, fRawBitmap, ¶ms)); if (!texture) { SkErrorInternals::SetError( kInternalError_SkError, "Couldn't convert bitmap to texture."); return nullptr; } SkAutoTUnref<GrFragmentProcessor> inner; if (doBicubic) { inner.reset(GrBicubicEffect::Create(procDataManager, texture, matrix, tm)); } else { inner.reset(GrSimpleTextureEffect::Create(procDataManager, texture, matrix, params)); } if (kAlpha_8_SkColorType == fRawBitmap.colorType()) { return SkRef(inner.get()); } return GrExtractAlphaFragmentProcessor::Create(inner); }