static inline void draw_replacement_bitmap(GrCachedLayer* layer, SkCanvas* canvas) { // Some image filter can totally filter away a layer (e.g., SkPictureImageFilter's with // no picture). if (!layer->texture()) { return; } SkBitmap bm; GrWrapTextureInBitmap(layer->texture(), !layer->isAtlased() ? layer->rect().width() : layer->texture()->width(), !layer->isAtlased() ? layer->rect().height() : layer->texture()->height(), false, &bm); canvas->save(); canvas->setMatrix(SkMatrix::I()); if (layer->isAtlased()) { const SkRect src = SkRect::Make(layer->rect()); const SkRect dst = SkRect::Make(layer->srcIR()); SkASSERT(layer->offset().isZero()); canvas->drawBitmapRect(bm, src, dst, layer->paint(), SkCanvas::kStrict_SrcRectConstraint); } else { canvas->drawBitmap(bm, SkIntToScalar(layer->srcIR().fLeft + layer->offset().fX), SkIntToScalar(layer->srcIR().fTop + layer->offset().fY), layer->paint()); } canvas->restore(); }
bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { #if SK_SUPPORT_GPU SkBitmap input = src; SkASSERT(fInputCount == 1); SkIPoint srcOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(0, proxy, src, ctx, &input, &srcOffset)) { return false; } GrTexture* srcTexture = input.getTexture(); SkIRect bounds; if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) { return false; } SkRect srcRect = SkRect::Make(bounds); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); GrContext* context = srcTexture->getContext(); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag, desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kRGBA_8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; } // setup new clip GrClip clip(dstRect); GrFragmentProcessor* fp; offset->fX = bounds.left(); offset->fY = bounds.top(); bounds.offset(-srcOffset); SkMatrix matrix(ctx.ctm()); matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); GrPaint paint; if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) { SkASSERT(fp); paint.addColorFragmentProcessor(fp)->unref(); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (drawContext) { drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; } } #endif return false; }
void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override { SkRect dst = SkRect::MakeXYWH(x, y, this->subset().width(), this->subset().height()); SkBitmap bm; GrWrapTextureInBitmap(fTexture, fTexture->width(), fTexture->height(), this->isOpaque(), &bm); canvas->drawBitmapRect(bm, this->subset(), dst, paint, SkCanvas::kStrict_SrcRectConstraint); }
void onDraw(SkCanvas* canvas, int x, int y, const SkPaint* paint) const override { SkRect dst = SkRect::MakeXYWH(x, y, this->subset().width(), this->subset().height()); SkBitmap bm; static const bool kUnknownOpacity = false; GrWrapTextureInBitmap(fTexture, fTexture->width(), fTexture->height(), kUnknownOpacity, &bm); canvas->drawBitmapRect(bm, this->subset(), dst, paint, SkCanvas::kStrict_SrcRectConstraint); }
bool SkBlurImageFilter::filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { #if SK_SUPPORT_GPU SkBitmap input = src; SkIPoint srcOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPUDeprecated(0, proxy, src, ctx, &input, &srcOffset)) { return false; } SkIRect srcBounds = input.bounds(); srcBounds.offset(srcOffset); SkIRect dstBounds; if (!this->applyCropRect(this->mapContext(ctx), srcBounds, &dstBounds)) { return false; } if (!srcBounds.intersect(dstBounds)) { return false; } SkVector sigma = map_sigma(fSigma, ctx.ctm()); if (sigma.x() == 0 && sigma.y() == 0) { input.extractSubset(result, srcBounds); offset->fX = srcBounds.x(); offset->fY = srcBounds.y(); return true; } offset->fX = dstBounds.fLeft; offset->fY = dstBounds.fTop; srcBounds.offset(-srcOffset); dstBounds.offset(-srcOffset); SkRect srcBoundsF(SkRect::Make(srcBounds)); GrTexture* inputTexture = input.getTexture(); SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(inputTexture->getContext(), inputTexture, false, SkRect::Make(dstBounds), &srcBoundsF, sigma.x(), sigma.y())); if (!tex) { return false; } GrWrapTextureInBitmap(tex, dstBounds.width(), dstBounds.height(), false, result); return true; #else SkDEBUGFAIL("Should not call in GPU-less build"); return false; #endif }
bool SkXfermodeImageFilter::filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { GrContext* context = nullptr; SkBitmap background = src; SkIPoint backgroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPUDeprecated(0, proxy, src, ctx, &background, &backgroundOffset)) { background.reset(); } GrTexture* backgroundTex = background.getTexture(); if (backgroundTex) { context = backgroundTex->getContext(); } SkBitmap foreground = src; SkIPoint foregroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPUDeprecated(1, proxy, src, ctx, &foreground, &foregroundOffset)) { foreground.reset(); } GrTexture* foregroundTex = foreground.getTexture(); if (foregroundTex) { context = foregroundTex->getContext(); } if (!context) { return false; } SkIRect bounds = background.bounds().makeOffset(backgroundOffset.x(), backgroundOffset.y()); bounds.join(foreground.bounds().makeOffset(foregroundOffset.x(), foregroundOffset.y())); if (bounds.isEmpty()) { return false; } GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; } GrPaint paint; SkAutoTUnref<const GrFragmentProcessor> bgFP; if (backgroundTex) { SkMatrix backgroundMatrix; backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height()); backgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX), SkIntToScalar(-backgroundOffset.fY)); bgFP.reset(GrTextureDomainEffect::Create( backgroundTex, backgroundMatrix, GrTextureDomain::MakeTexelDomain(backgroundTex, background.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode)); } else { bgFP.reset(GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, GrConstColorProcessor::kIgnore_InputMode)); } if (foregroundTex) { SkMatrix foregroundMatrix; foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height()); foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), SkIntToScalar(-foregroundOffset.fY)); SkAutoTUnref<const GrFragmentProcessor> foregroundFP; foregroundFP.reset(GrTextureDomainEffect::Create( foregroundTex, foregroundMatrix, GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode)); paint.addColorFragmentProcessor(foregroundFP.get()); // A null fMode is interpreted to mean kSrcOver_Mode (to match raster). SkAutoTUnref<SkXfermode> mode(SkSafeRef(fMode.get())); if (!mode) { // It would be awesome to use SkXfermode::Create here but it knows better // than us and won't return a kSrcOver_Mode SkXfermode. That means we // have to get one the hard way. struct ProcCoeff rec; rec.fProc = SkXfermode::GetProc(SkXfermode::kSrcOver_Mode); SkXfermode::ModeAsCoeff(SkXfermode::kSrcOver_Mode, &rec.fSC, &rec.fDC); mode.reset(new SkProcCoeffXfermode(rec, SkXfermode::kSrcOver_Mode)); } SkAutoTUnref<const GrFragmentProcessor> xferFP(mode->getFragmentProcessorForImageFilter(bgFP)); // A null 'xferFP' here means kSrc_Mode was used in which case we can just proceed if (xferFP) { paint.addColorFragmentProcessor(xferFP); } } else { paint.addColorFragmentProcessor(bgFP); } paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (!drawContext) { return false; } SkMatrix matrix; matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(bounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; }
bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkBitmap background = src; SkIPoint backgroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(0, proxy, src, ctx, &background, &backgroundOffset)) { return false; } GrTexture* backgroundTex = background.getTexture(); if (nullptr == backgroundTex) { SkASSERT(false); return false; } SkBitmap foreground = src; SkIPoint foregroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(1, proxy, src, ctx, &foreground, &foregroundOffset)) { return false; } GrTexture* foregroundTex = foreground.getTexture(); GrContext* context = foregroundTex->getContext(); SkIRect bounds = background.bounds().makeOffset(backgroundOffset.x(), backgroundOffset.y()); bounds.join(foreground.bounds().makeOffset(foregroundOffset.x(), foregroundOffset.y())); if (bounds.isEmpty()) { return false; } const GrFragmentProcessor* xferFP = nullptr; GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; } GrPaint paint; SkMatrix backgroundMatrix; backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height()); backgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX), SkIntToScalar(-backgroundOffset.fY)); SkAutoTUnref<const GrFragmentProcessor> bgFP(GrTextureDomainEffect::Create( backgroundTex, backgroundMatrix, GrTextureDomain::MakeTexelDomain(backgroundTex, background.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode) ); if (!fMode || !fMode->asFragmentProcessor(&xferFP, bgFP)) { // canFilterImageGPU() should've taken care of this SkASSERT(false); return false; } SkMatrix foregroundMatrix; foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height()); foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), SkIntToScalar(-foregroundOffset.fY)); SkAutoTUnref<const GrFragmentProcessor> foregroundFP(GrTextureDomainEffect::Create( foregroundTex, foregroundMatrix, GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode) ); paint.addColorFragmentProcessor(foregroundFP.get()); if (xferFP) { paint.addColorFragmentProcessor(xferFP)->unref(); } paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (!drawContext) { return false; } SkMatrix matrix; matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(bounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; }
bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkBitmap colorBM = src; SkIPoint colorOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(1, proxy, src, ctx, &colorBM, &colorOffset)) { return false; } SkBitmap displacementBM = src; SkIPoint displacementOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(0, proxy, src, ctx, &displacementBM, &displacementOffset)) { return false; } SkIRect bounds; // Since GrDisplacementMapEffect does bounds checking on color pixel access, we don't need to // pad the color bitmap to bounds here. if (!this->applyCropRect(ctx, colorBM, colorOffset, &bounds)) { return false; } SkIRect displBounds; if (!this->applyCropRect(ctx, proxy, displacementBM, &displacementOffset, &displBounds, &displacementBM)) { return false; } if (!bounds.intersect(displBounds)) { return false; } GrTexture* color = colorBM.getTexture(); GrTexture* displacement = displacementBM.getTexture(); GrContext* context = color->getContext(); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; } SkVector scale = SkVector::Make(fScale, fScale); ctx.ctm().mapVectors(&scale, 1); GrPaint paint; SkMatrix offsetMatrix = GrCoordTransform::MakeDivByTextureWHMatrix(displacement); offsetMatrix.preTranslate(SkIntToScalar(colorOffset.fX - displacementOffset.fX), SkIntToScalar(colorOffset.fY - displacementOffset.fY)); paint.addColorFragmentProcessor( GrDisplacementMapEffect::Create(fXChannelSelector, fYChannelSelector, scale, displacement, offsetMatrix, color, colorBM.dimensions()))->unref(); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkIRect colorBounds = bounds; colorBounds.offset(-colorOffset); SkMatrix matrix; matrix.setTranslate(-SkIntToScalar(colorBounds.x()), -SkIntToScalar(colorBounds.y())); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (!drawContext) { return false; } drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(colorBounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; }
SkShader* SkImage_Gpu::onNewShader(SkShader::TileMode tileX, SkShader::TileMode tileY, const SkMatrix* localMatrix) const { SkBitmap bm; GrWrapTextureInBitmap(fTexture, this->width(), this->height(), this->isOpaque(), &bm); return SkShader::CreateBitmapShader(bm, tileX, tileY, localMatrix); }
/** Tests calling copyTo on a texture backed bitmap. Tests that all BGRA_8888/RGBA_8888 combinations of src and dst work. This test should be removed when SkGrPixelRef is removed. */ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BitmapCopy_Texture, reporter, ctxInfo) { static const SkPMColor kData[] = { 0xFF112233, 0xAF224499, 0xEF004466, 0x80773311 }; uint32_t swizData[SK_ARRAY_COUNT(kData)]; for (size_t i = 0; i < SK_ARRAY_COUNT(kData); ++i) { swizData[i] = SkSwizzle_RB(kData[i]); } static const GrPixelConfig kSrcConfigs[] = { kRGBA_8888_GrPixelConfig, kBGRA_8888_GrPixelConfig, }; for (size_t srcC = 0; srcC < SK_ARRAY_COUNT(kSrcConfigs); ++srcC) { for (int rt = 0; rt < 2; ++rt) { GrSurfaceDesc desc; desc.fConfig = kSrcConfigs[srcC]; desc.fFlags = rt ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags; desc.fWidth = 2; desc.fHeight = 2; desc.fOrigin = kTopLeft_GrSurfaceOrigin; const void* srcData = (kSkia8888_GrPixelConfig == desc.fConfig) ? kData : swizData; SkAutoTUnref<GrTexture> texture( ctxInfo.grContext()->textureProvider()->createTexture(desc, SkBudgeted::kNo, srcData, 0)); if (!texture) { continue; } SkBitmap srcBmp; GrWrapTextureInBitmap(texture, 2, 2, false, &srcBmp); if (srcBmp.isNull()) { ERRORF(reporter, "Could not wrap texture in bitmap."); continue; } static const SkColorType kDstCTs[] = { kRGBA_8888_SkColorType, kBGRA_8888_SkColorType }; for (size_t dCT = 0; dCT < SK_ARRAY_COUNT(kDstCTs); ++dCT) { SkBitmap dstBmp; if (!srcBmp.copyTo(&dstBmp, kDstCTs[dCT])) { ERRORF(reporter, "CopyTo failed."); } if (dstBmp.colorType() != kDstCTs[dCT]) { ERRORF(reporter, "SkBitmap::CopyTo did not respect passed in color type."); } SkAutoLockPixels alp(dstBmp); uint8_t* dstBmpPixels = static_cast<uint8_t*>(dstBmp.getPixels()); const uint32_t* refData; #if defined(SK_PMCOLOR_IS_RGBA) refData = (kRGBA_8888_SkColorType == dstBmp.colorType()) ? kData : swizData; #elif defined(SK_PMCOLOR_IS_BGRA) refData = (kBGRA_8888_SkColorType == dstBmp.colorType()) ? kData : swizData; #else #error "PM Color must be BGRA or RGBA to use GPU backend." #endif bool foundError = false; for (int y = 0; y < 2 && !foundError; ++y) { uint32_t* dstBmpRow = reinterpret_cast<uint32_t*>(dstBmpPixels); for (int x = 0; x < 2 && !foundError; ++x) { if (refData[2 * y + x] != dstBmpRow[x]) { ERRORF(reporter, "Expected pixel 0x%08x, found 0x%08x.", refData[2 * y + x], dstBmpRow[x]); foundError = true; } } dstBmpPixels += dstBmp.rowBytes(); } } } } }
static sk_sp<SkImage> makebm(SkCanvas* origCanvas, SkBitmap* resultBM, int w, int h) { SkImageInfo info = SkImageInfo::MakeN32Premul(w, h); SkAutoTUnref<SkSurface> surface(origCanvas->newSurface(info)); if (nullptr == surface) { // picture canvas will return null, so fall-back to raster surface.reset(SkSurface::NewRaster(info)); } SkCanvas* canvas = surface->getCanvas(); canvas->clear(SK_ColorTRANSPARENT); SkScalar wScalar = SkIntToScalar(w); SkScalar hScalar = SkIntToScalar(h); SkPoint pt = { wScalar / 2, hScalar / 2 }; SkScalar radius = 4 * SkMaxScalar(wScalar, hScalar); SkColor colors[] = { SK_ColorRED, SK_ColorYELLOW, SK_ColorGREEN, SK_ColorMAGENTA, SK_ColorBLUE, SK_ColorCYAN, SK_ColorRED}; SkScalar pos[] = {0, SK_Scalar1 / 6, 2 * SK_Scalar1 / 6, 3 * SK_Scalar1 / 6, 4 * SK_Scalar1 / 6, 5 * SK_Scalar1 / 6, SK_Scalar1}; SkPaint paint; SkRect rect = SkRect::MakeWH(wScalar, hScalar); SkMatrix mat = SkMatrix::I(); for (int i = 0; i < 4; ++i) { paint.setShader(SkGradientShader::MakeRadial( pt, radius, colors, pos, SK_ARRAY_COUNT(colors), SkShader::kRepeat_TileMode, 0, &mat)); canvas->drawRect(rect, paint); rect.inset(wScalar / 8, hScalar / 8); mat.postScale(SK_Scalar1 / 4, SK_Scalar1 / 4); } auto image = surface->makeImageSnapshot(); SkBitmap tempBM; #if SK_SUPPORT_GPU if (GrTexture* texture = as_IB(image)->peekTexture()) { GrWrapTextureInBitmap(texture, image->width(), image->height(), image->isOpaque(), &tempBM); } else #endif { image->asLegacyBitmap(&tempBM, SkImage::kRO_LegacyBitmapMode); } // Let backends know we won't change this, so they don't have to deep copy it defensively. tempBM.setImmutable(); *resultBM = tempBM; return image; }
bool make_oversized_texture_bitmap(GrContext* ctx, TestPixels* result, int width, int height, GrPixelConfig config, PIXEL_TYPE outerRingColor, PIXEL_TYPE innerRingColor, PIXEL_TYPE checkColor1, PIXEL_TYPE checkColor2, PIXEL_TYPE padColor) { SkASSERT(0 == width % 2 && 0 == height % 2); SkASSERT(width >= 6 && height >= 6); #if SK_SUPPORT_GPU if (!ctx) { return false; } /** Put arbitrary pad to the right and below the bitmap content. */ static const int kXPad = 10; static const int kYPad = 17; size_t rowBytes = (width + kXPad) * sizeof(PIXEL_TYPE); SkAutoTMalloc<PIXEL_TYPE> pixels(rowBytes*(height + kYPad)); PIXEL_TYPE* scanline = pixels.get(); for (int x = 0; x < width; ++x) { scanline[x] = outerRingColor; } for (int x = width; x < width + kXPad; ++x) { scanline[x] = padColor; } scanline = (PIXEL_TYPE*)((char*)scanline + rowBytes); scanline[0] = outerRingColor; for (int x = 1; x < width; ++x) { scanline[x] = innerRingColor; } for (int x = width; x < width + kXPad; ++x) { scanline[x] = padColor; } for (int y = 2; y < height / 2 + 1; ++y) { scanline = (PIXEL_TYPE*)((char*)scanline + rowBytes); scanline[0] = outerRingColor; scanline[1] = innerRingColor; for (int x = 2; x < width / 2 + 1; ++x) { scanline[x] = checkColor1; } for (int x = width / 2 + 1; x < width; ++x) { scanline[x] = checkColor2; } for (int x = width; x < width + kXPad; ++x) { scanline[x] = padColor; } } for (int y = height / 2 + 1; y < height; ++y) { scanline = (PIXEL_TYPE*)((char*)scanline + rowBytes); scanline[0] = outerRingColor; scanline[1] = innerRingColor; for (int x = 2; x < width / 2 + 1; ++x) { scanline[x] = checkColor2; } for (int x = width / 2 + 1; x < width; ++x) { scanline[x] = checkColor1; } for (int x = width; x < width + kXPad; ++x) { scanline[x] = padColor; } } for (int y = height; y < height + kYPad; ++y) { scanline = (PIXEL_TYPE*)((char*)scanline + rowBytes); for (int x = 0; x < width + kXPad; ++x) { scanline[x] = padColor; } } GrSurfaceDesc desc; desc.fConfig = config; desc.fWidth = width + kXPad; desc.fHeight = height + kYPad; SkAutoTUnref<GrTexture> texture(ctx->textureProvider()->createTexture( desc, SkBudgeted::kYes, pixels.get(), rowBytes)); if (!texture) { return false; } GrWrapTextureInBitmap(texture, width, height, true, &result->fBitmap); result->fType = TestPixels::kBitmap; result->fBitmap.setImmutable(); result->fRect.set(2, 2, width, height); return true; #else return false; #endif }