gfx/skia/trunk/src/gpu/SkGpuDevice.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /*
     2  * Copyright 2011 Google Inc.
     3  *
     4  * Use of this source code is governed by a BSD-style license that can be
     5  * found in the LICENSE file.
     6  */
     8 #include "SkGpuDevice.h"
    10 #include "effects/GrBicubicEffect.h"
    11 #include "effects/GrTextureDomain.h"
    12 #include "effects/GrSimpleTextureEffect.h"
    14 #include "GrContext.h"
    15 #include "GrBitmapTextContext.h"
    16 #include "GrDistanceFieldTextContext.h"
    18 #include "SkGrTexturePixelRef.h"
    20 #include "SkBounder.h"
    21 #include "SkColorFilter.h"
    22 #include "SkDeviceImageFilterProxy.h"
    23 #include "SkDrawProcs.h"
    24 #include "SkGlyphCache.h"
    25 #include "SkImageFilter.h"
    26 #include "SkMaskFilter.h"
    27 #include "SkPathEffect.h"
    28 #include "SkPicture.h"
    29 #include "SkRRect.h"
    30 #include "SkStroke.h"
    31 #include "SkSurface.h"
    32 #include "SkTLazy.h"
    33 #include "SkUtils.h"
    34 #include "SkErrorInternals.h"
    36 #define CACHE_COMPATIBLE_DEVICE_TEXTURES 1
    38 #if 0
    39     extern bool (*gShouldDrawProc)();
    40     #define CHECK_SHOULD_DRAW(draw, forceI)                     \
    41         do {                                                    \
    42             if (gShouldDrawProc && !gShouldDrawProc()) return;  \
    43             this->prepareDraw(draw, forceI);                    \
    44         } while (0)
    45 #else
    46     #define CHECK_SHOULD_DRAW(draw, forceI) this->prepareDraw(draw, forceI)
    47 #endif
    49 // This constant represents the screen alignment criterion in texels for
    50 // requiring texture domain clamping to prevent color bleeding when drawing
    51 // a sub region of a larger source image.
    52 #define COLOR_BLEED_TOLERANCE 0.001f
    54 #define DO_DEFERRED_CLEAR()             \
    55     do {                                \
    56         if (fNeedClear) {               \
    57             this->clear(SK_ColorTRANSPARENT); \
    58         }                               \
    59     } while (false)                     \
    61 ///////////////////////////////////////////////////////////////////////////////
    63 #define CHECK_FOR_ANNOTATION(paint) \
    64     do { if (paint.getAnnotation()) { return; } } while (0)
    66 ///////////////////////////////////////////////////////////////////////////////
    69 class SkGpuDevice::SkAutoCachedTexture : public ::SkNoncopyable {
    70 public:
    71     SkAutoCachedTexture()
    72         : fDevice(NULL)
    73         , fTexture(NULL) {
    74     }
    76     SkAutoCachedTexture(SkGpuDevice* device,
    77                         const SkBitmap& bitmap,
    78                         const GrTextureParams* params,
    79                         GrTexture** texture)
    80         : fDevice(NULL)
    81         , fTexture(NULL) {
    82         SkASSERT(NULL != texture);
    83         *texture = this->set(device, bitmap, params);
    84     }
    86     ~SkAutoCachedTexture() {
    87         if (NULL != fTexture) {
    88             GrUnlockAndUnrefCachedBitmapTexture(fTexture);
    89         }
    90     }
    92     GrTexture* set(SkGpuDevice* device,
    93                    const SkBitmap& bitmap,
    94                    const GrTextureParams* params) {
    95         if (NULL != fTexture) {
    96             GrUnlockAndUnrefCachedBitmapTexture(fTexture);
    97             fTexture = NULL;
    98         }
    99         fDevice = device;
   100         GrTexture* result = (GrTexture*)bitmap.getTexture();
   101         if (NULL == result) {
   102             // Cannot return the native texture so look it up in our cache
   103             fTexture = GrLockAndRefCachedBitmapTexture(device->context(), bitmap, params);
   104             result = fTexture;
   105         }
   106         return result;
   107     }
   109 private:
   110     SkGpuDevice* fDevice;
   111     GrTexture*   fTexture;
   112 };
   114 ///////////////////////////////////////////////////////////////////////////////
   116 struct GrSkDrawProcs : public SkDrawProcs {
   117 public:
   118     GrContext* fContext;
   119     GrTextContext* fTextContext;
   120     GrFontScaler* fFontScaler;  // cached in the skia glyphcache
   121 };
   123 ///////////////////////////////////////////////////////////////////////////////
   125 static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
   126     switch (config) {
   127         case kAlpha_8_GrPixelConfig:
   128             *isOpaque = false;
   129             return SkBitmap::kA8_Config;
   130         case kRGB_565_GrPixelConfig:
   131             *isOpaque = true;
   132             return SkBitmap::kRGB_565_Config;
   133         case kRGBA_4444_GrPixelConfig:
   134             *isOpaque = false;
   135             return SkBitmap::kARGB_4444_Config;
   136         case kSkia8888_GrPixelConfig:
   137             // we don't currently have a way of knowing whether
   138             // a 8888 is opaque based on the config.
   139             *isOpaque = false;
   140             return SkBitmap::kARGB_8888_Config;
   141         default:
   142             *isOpaque = false;
   143             return SkBitmap::kNo_Config;
   144     }
   145 }
   147 /*
   148  * GrRenderTarget does not know its opaqueness, only its config, so we have
   149  * to make conservative guesses when we return an "equivalent" bitmap.
   150  */
   151 static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
   152     bool isOpaque;
   153     SkBitmap::Config config = grConfig2skConfig(renderTarget->config(), &isOpaque);
   155     SkBitmap bitmap;
   156     bitmap.setConfig(config, renderTarget->width(), renderTarget->height(), 0,
   157                      isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   158     return bitmap;
   159 }
   161 SkGpuDevice* SkGpuDevice::Create(GrSurface* surface) {
   162     SkASSERT(NULL != surface);
   163     if (NULL == surface->asRenderTarget() || NULL == surface->getContext()) {
   164         return NULL;
   165     }
   166     if (surface->asTexture()) {
   167         return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asTexture()));
   168     } else {
   169         return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asRenderTarget()));
   170     }
   171 }
   173 SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
   174     : SkBitmapDevice(make_bitmap(context, texture->asRenderTarget())) {
   175     this->initFromRenderTarget(context, texture->asRenderTarget(), false);
   176 }
   178 SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
   179     : SkBitmapDevice(make_bitmap(context, renderTarget)) {
   180     this->initFromRenderTarget(context, renderTarget, false);
   181 }
   183 void SkGpuDevice::initFromRenderTarget(GrContext* context,
   184                                        GrRenderTarget* renderTarget,
   185                                        bool cached) {
   186     fDrawProcs = NULL;
   188     fContext = context;
   189     fContext->ref();
   191     fMainTextContext = SkNEW_ARGS(GrDistanceFieldTextContext, (fContext, fLeakyProperties));
   192     fFallbackTextContext = SkNEW_ARGS(GrBitmapTextContext, (fContext, fLeakyProperties));
   194     fRenderTarget = NULL;
   195     fNeedClear = false;
   197     SkASSERT(NULL != renderTarget);
   198     fRenderTarget = renderTarget;
   199     fRenderTarget->ref();
   201     // Hold onto to the texture in the pixel ref (if there is one) because the texture holds a ref
   202     // on the RT but not vice-versa.
   203     // TODO: Remove this trickery once we figure out how to make SkGrPixelRef do this without
   204     // busting chrome (for a currently unknown reason).
   205     GrSurface* surface = fRenderTarget->asTexture();
   206     if (NULL == surface) {
   207         surface = fRenderTarget;
   208     }
   210     SkImageInfo info;
   211     surface->asImageInfo(&info);
   212     SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, surface, cached));
   214     this->setPixelRef(pr)->unref();
   215 }
   217 SkGpuDevice* SkGpuDevice::Create(GrContext* context, const SkImageInfo& origInfo,
   218                                  int sampleCount) {
   219     if (kUnknown_SkColorType == origInfo.colorType() ||
   220         origInfo.width() < 0 || origInfo.height() < 0) {
   221         return NULL;
   222     }
   224     SkImageInfo info = origInfo;
   225     // TODO: perhas we can loosen this check now that colortype is more detailed
   226     // e.g. can we support both RGBA and BGRA here?
   227     if (kRGB_565_SkColorType == info.colorType()) {
   228         info.fAlphaType = kOpaque_SkAlphaType;  // force this setting
   229     } else {
   230         info.fColorType = kPMColor_SkColorType;
   231         if (kOpaque_SkAlphaType != info.alphaType()) {
   232             info.fAlphaType = kPremul_SkAlphaType;  // force this setting
   233         }
   234     }
   236     GrTextureDesc desc;
   237     desc.fFlags = kRenderTarget_GrTextureFlagBit;
   238     desc.fWidth = info.width();
   239     desc.fHeight = info.height();
   240     desc.fConfig = SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType());
   241     desc.fSampleCnt = sampleCount;
   243     SkAutoTUnref<GrTexture> texture(context->createUncachedTexture(desc, NULL, 0));
   244     if (!texture.get()) {
   245         return NULL;
   246     }
   248     return SkNEW_ARGS(SkGpuDevice, (context, texture.get()));
   249 }
   251 #ifdef SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG
   252 static SkBitmap make_bitmap(SkBitmap::Config config, int width, int height) {
   253     SkBitmap bm;
   254     bm.setConfig(SkImageInfo::Make(width, height,
   255                                    SkBitmapConfigToColorType(config),
   256                                    kPremul_SkAlphaType));
   257     return bm;
   258 }
   259 SkGpuDevice::SkGpuDevice(GrContext* context,
   260                          SkBitmap::Config config,
   261                          int width,
   262                          int height,
   263                          int sampleCount)
   264     : SkBitmapDevice(make_bitmap(config, width, height))
   265 {
   266     fDrawProcs = NULL;
   268     fContext = context;
   269     fContext->ref();
   271     fMainTextContext = SkNEW_ARGS(GrDistanceFieldTextContext, (fContext, fLeakyProperties));
   272     fFallbackTextContext = SkNEW_ARGS(GrBitmapTextContext, (fContext, fLeakyProperties));
   274     fRenderTarget = NULL;
   275     fNeedClear = false;
   277     if (config != SkBitmap::kRGB_565_Config) {
   278         config = SkBitmap::kARGB_8888_Config;
   279     }
   281     GrTextureDesc desc;
   282     desc.fFlags = kRenderTarget_GrTextureFlagBit;
   283     desc.fWidth = width;
   284     desc.fHeight = height;
   285     desc.fConfig = SkBitmapConfig2GrPixelConfig(config);
   286     desc.fSampleCnt = sampleCount;
   288     SkImageInfo info;
   289     if (!GrPixelConfig2ColorType(desc.fConfig, &info.fColorType)) {
   290         sk_throw();
   291     }
   292     info.fWidth = width;
   293     info.fHeight = height;
   294     info.fAlphaType = kPremul_SkAlphaType;
   296     SkAutoTUnref<GrTexture> texture(fContext->createUncachedTexture(desc, NULL, 0));
   298     if (NULL != texture) {
   299         fRenderTarget = texture->asRenderTarget();
   300         fRenderTarget->ref();
   302         SkASSERT(NULL != fRenderTarget);
   304         // wrap the bitmap with a pixelref to expose our texture
   305         SkGrPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, texture));
   306         this->setPixelRef(pr)->unref();
   307     } else {
   308         GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
   309                  width, height);
   310         SkASSERT(false);
   311     }
   312 }
   313 #endif
   315 SkGpuDevice::~SkGpuDevice() {
   316     if (fDrawProcs) {
   317         delete fDrawProcs;
   318     }
   320     delete fMainTextContext;
   321     delete fFallbackTextContext;
   323     // The GrContext takes a ref on the target. We don't want to cause the render
   324     // target to be unnecessarily kept alive.
   325     if (fContext->getRenderTarget() == fRenderTarget) {
   326         fContext->setRenderTarget(NULL);
   327     }
   329     if (fContext->getClip() == &fClipData) {
   330         fContext->setClip(NULL);
   331     }
   333     SkSafeUnref(fRenderTarget);
   334     fContext->unref();
   335 }
   337 ///////////////////////////////////////////////////////////////////////////////
   339 void SkGpuDevice::makeRenderTargetCurrent() {
   340     DO_DEFERRED_CLEAR();
   341     fContext->setRenderTarget(fRenderTarget);
   342 }
   344 ///////////////////////////////////////////////////////////////////////////////
   346 namespace {
   347 GrPixelConfig config8888_to_grconfig_and_flags(SkCanvas::Config8888 config8888, uint32_t* flags) {
   348     switch (config8888) {
   349         case SkCanvas::kNative_Premul_Config8888:
   350             *flags = 0;
   351             return kSkia8888_GrPixelConfig;
   352         case SkCanvas::kNative_Unpremul_Config8888:
   353             *flags = GrContext::kUnpremul_PixelOpsFlag;
   354             return kSkia8888_GrPixelConfig;
   355         case SkCanvas::kBGRA_Premul_Config8888:
   356             *flags = 0;
   357             return kBGRA_8888_GrPixelConfig;
   358         case SkCanvas::kBGRA_Unpremul_Config8888:
   359             *flags = GrContext::kUnpremul_PixelOpsFlag;
   360             return kBGRA_8888_GrPixelConfig;
   361         case SkCanvas::kRGBA_Premul_Config8888:
   362             *flags = 0;
   363             return kRGBA_8888_GrPixelConfig;
   364         case SkCanvas::kRGBA_Unpremul_Config8888:
   365             *flags = GrContext::kUnpremul_PixelOpsFlag;
   366             return kRGBA_8888_GrPixelConfig;
   367         default:
   368             GrCrash("Unexpected Config8888.");
   369             *flags = 0; // suppress warning
   370             return kSkia8888_GrPixelConfig;
   371     }
   372 }
   373 }
   375 bool SkGpuDevice::onReadPixels(const SkBitmap& bitmap,
   376                                int x, int y,
   377                                SkCanvas::Config8888 config8888) {
   378     DO_DEFERRED_CLEAR();
   379     SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
   380     SkASSERT(!bitmap.isNull());
   381     SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
   383     SkAutoLockPixels alp(bitmap);
   384     GrPixelConfig config;
   385     uint32_t flags;
   386     config = config8888_to_grconfig_and_flags(config8888, &flags);
   387     return fContext->readRenderTargetPixels(fRenderTarget,
   388                                             x, y,
   389                                             bitmap.width(),
   390                                             bitmap.height(),
   391                                             config,
   392                                             bitmap.getPixels(),
   393                                             bitmap.rowBytes(),
   394                                             flags);
   395 }
   397 #ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
   398 void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y,
   399                               SkCanvas::Config8888 config8888) {
   400     SkAutoLockPixels alp(bitmap);
   401     if (!bitmap.readyToDraw()) {
   402         return;
   403     }
   405     GrPixelConfig config;
   406     uint32_t flags;
   407     if (SkBitmap::kARGB_8888_Config == bitmap.config()) {
   408         config = config8888_to_grconfig_and_flags(config8888, &flags);
   409     } else {
   410         flags = 0;
   411         config= SkBitmapConfig2GrPixelConfig(bitmap.config());
   412     }
   414     fRenderTarget->writePixels(x, y, bitmap.width(), bitmap.height(),
   415                                config, bitmap.getPixels(), bitmap.rowBytes(), flags);
   416 }
   417 #endif
   419 bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
   420                                 int x, int y) {
   421     // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
   422     GrPixelConfig config = SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType());
   423     if (kUnknown_GrPixelConfig == config) {
   424         return false;
   425     }
   426     uint32_t flags = 0;
   427     if (kUnpremul_SkAlphaType == info.alphaType()) {
   428         flags = GrContext::kUnpremul_PixelOpsFlag;
   429     }
   430     fRenderTarget->writePixels(x, y, info.width(), info.height(), config, pixels, rowBytes, flags);
   432     // need to bump our genID for compatibility with clients that "know" we have a bitmap
   433     this->onAccessBitmap().notifyPixelsChanged();
   435     return true;
   436 }
   438 void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) {
   439     INHERITED::onAttachToCanvas(canvas);
   441     // Canvas promises that this ptr is valid until onDetachFromCanvas is called
   442     fClipData.fClipStack = canvas->getClipStack();
   443 }
   445 void SkGpuDevice::onDetachFromCanvas() {
   446     INHERITED::onDetachFromCanvas();
   447     fClipData.fClipStack = NULL;
   448 }
   450 // call this every draw call, to ensure that the context reflects our state,
   451 // and not the state from some other canvas/device
   452 void SkGpuDevice::prepareDraw(const SkDraw& draw, bool forceIdentity) {
   453     SkASSERT(NULL != fClipData.fClipStack);
   455     fContext->setRenderTarget(fRenderTarget);
   457     SkASSERT(draw.fClipStack && draw.fClipStack == fClipData.fClipStack);
   459     if (forceIdentity) {
   460         fContext->setIdentityMatrix();
   461     } else {
   462         fContext->setMatrix(*draw.fMatrix);
   463     }
   464     fClipData.fOrigin = this->getOrigin();
   466     fContext->setClip(&fClipData);
   468     DO_DEFERRED_CLEAR();
   469 }
   471 GrRenderTarget* SkGpuDevice::accessRenderTarget() {
   472     DO_DEFERRED_CLEAR();
   473     return fRenderTarget;
   474 }
   476 ///////////////////////////////////////////////////////////////////////////////
   478 SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
   479 SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
   480 SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
   481 SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
   482 SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
   483                   shader_type_mismatch);
   484 SK_COMPILE_ASSERT(SkShader::kTwoPointConical_BitmapType == 5,
   485                   shader_type_mismatch);
   486 SK_COMPILE_ASSERT(SkShader::kLinear_BitmapType == 6, shader_type_mismatch);
   487 SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 6, shader_type_mismatch);
   489 namespace {
   491 // converts a SkPaint to a GrPaint, ignoring the skPaint's shader
   492 // justAlpha indicates that skPaint's alpha should be used rather than the color
   493 // Callers may subsequently modify the GrPaint. Setting constantColor indicates
   494 // that the final paint will draw the same color at every pixel. This allows
   495 // an optimization where the the color filter can be applied to the skPaint's
   496 // color once while converting to GrPaint and then ignored.
   497 inline bool skPaint2GrPaintNoShader(SkGpuDevice* dev,
   498                                     const SkPaint& skPaint,
   499                                     bool justAlpha,
   500                                     bool constantColor,
   501                                     GrPaint* grPaint) {
   503     grPaint->setDither(skPaint.isDither());
   504     grPaint->setAntiAlias(skPaint.isAntiAlias());
   506     SkXfermode::Coeff sm;
   507     SkXfermode::Coeff dm;
   509     SkXfermode* mode = skPaint.getXfermode();
   510     GrEffectRef* xferEffect = NULL;
   511     if (SkXfermode::AsNewEffectOrCoeff(mode, &xferEffect, &sm, &dm)) {
   512         if (NULL != xferEffect) {
   513             grPaint->addColorEffect(xferEffect)->unref();
   514             sm = SkXfermode::kOne_Coeff;
   515             dm = SkXfermode::kZero_Coeff;
   516         }
   517     } else {
   518         //SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
   519 #if 0
   520         return false;
   521 #else
   522         // Fall back to src-over
   523         sm = SkXfermode::kOne_Coeff;
   524         dm = SkXfermode::kISA_Coeff;
   525 #endif
   526     }
   527     grPaint->setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm));
   529     if (justAlpha) {
   530         uint8_t alpha = skPaint.getAlpha();
   531         grPaint->setColor(GrColorPackRGBA(alpha, alpha, alpha, alpha));
   532         // justAlpha is currently set to true only if there is a texture,
   533         // so constantColor should not also be true.
   534         SkASSERT(!constantColor);
   535     } else {
   536         grPaint->setColor(SkColor2GrColor(skPaint.getColor()));
   537     }
   539     SkColorFilter* colorFilter = skPaint.getColorFilter();
   540     if (NULL != colorFilter) {
   541         // if the source color is a constant then apply the filter here once rather than per pixel
   542         // in a shader.
   543         if (constantColor) {
   544             SkColor filtered = colorFilter->filterColor(skPaint.getColor());
   545             grPaint->setColor(SkColor2GrColor(filtered));
   546         } else {
   547             SkAutoTUnref<GrEffectRef> effect(colorFilter->asNewEffect(dev->context()));
   548             if (NULL != effect.get()) {
   549                 grPaint->addColorEffect(effect);
   550             }
   551         }
   552     }
   554     return true;
   555 }
   557 // This function is similar to skPaint2GrPaintNoShader but also converts
   558 // skPaint's shader to a GrTexture/GrEffectStage if possible. The texture to
   559 // be used is set on grPaint and returned in param act. constantColor has the
   560 // same meaning as in skPaint2GrPaintNoShader.
   561 inline bool skPaint2GrPaintShader(SkGpuDevice* dev,
   562                                   const SkPaint& skPaint,
   563                                   bool constantColor,
   564                                   GrPaint* grPaint) {
   565     SkShader* shader = skPaint.getShader();
   566     if (NULL == shader) {
   567         return skPaint2GrPaintNoShader(dev, skPaint, false, constantColor, grPaint);
   568     }
   570     // SkShader::asNewEffect() may do offscreen rendering. Setup default drawing state and require
   571     // the shader to set a render target .
   572     GrContext::AutoWideOpenIdentityDraw awo(dev->context(), NULL);
   574     // setup the shader as the first color effect on the paint
   575     SkAutoTUnref<GrEffectRef> effect(shader->asNewEffect(dev->context(), skPaint));
   576     if (NULL != effect.get()) {
   577         grPaint->addColorEffect(effect);
   578         // Now setup the rest of the paint.
   579         return skPaint2GrPaintNoShader(dev, skPaint, true, false, grPaint);
   580     } else {
   581         // We still don't have SkColorShader::asNewEffect() implemented.
   582         SkShader::GradientInfo info;
   583         SkColor                color;
   585         info.fColors = &color;
   586         info.fColorOffsets = NULL;
   587         info.fColorCount = 1;
   588         if (SkShader::kColor_GradientType == shader->asAGradient(&info)) {
   589             SkPaint copy(skPaint);
   590             copy.setShader(NULL);
   591             // modulate the paint alpha by the shader's solid color alpha
   592             U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
   593             copy.setColor(SkColorSetA(color, newA));
   594             return skPaint2GrPaintNoShader(dev, copy, false, constantColor, grPaint);
   595         } else {
   596             return false;
   597         }
   598     }
   599 }
   600 }
   602 ///////////////////////////////////////////////////////////////////////////////
   604 SkBitmap::Config SkGpuDevice::config() const {
   605     if (NULL == fRenderTarget) {
   606         return SkBitmap::kNo_Config;
   607     }
   609     bool isOpaque;
   610     return grConfig2skConfig(fRenderTarget->config(), &isOpaque);
   611 }
   613 void SkGpuDevice::clear(SkColor color) {
   614     SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
   615     fContext->clear(&rect, SkColor2GrColor(color), true, fRenderTarget);
   616     fNeedClear = false;
   617 }
   619 void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
   620     CHECK_SHOULD_DRAW(draw, false);
   622     GrPaint grPaint;
   623     if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   624         return;
   625     }
   627     fContext->drawPaint(grPaint);
   628 }
   630 // must be in SkCanvas::PointMode order
   631 static const GrPrimitiveType gPointMode2PrimtiveType[] = {
   632     kPoints_GrPrimitiveType,
   633     kLines_GrPrimitiveType,
   634     kLineStrip_GrPrimitiveType
   635 };
   637 void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
   638                              size_t count, const SkPoint pts[], const SkPaint& paint) {
   639     CHECK_FOR_ANNOTATION(paint);
   640     CHECK_SHOULD_DRAW(draw, false);
   642     SkScalar width = paint.getStrokeWidth();
   643     if (width < 0) {
   644         return;
   645     }
   647     // we only handle hairlines and paints without path effects or mask filters,
   648     // else we let the SkDraw call our drawPath()
   649     if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) {
   650         draw.drawPoints(mode, count, pts, paint, true);
   651         return;
   652     }
   654     GrPaint grPaint;
   655     if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   656         return;
   657     }
   659     fContext->drawVertices(grPaint,
   660                            gPointMode2PrimtiveType[mode],
   661                            SkToS32(count),
   662                            (GrPoint*)pts,
   663                            NULL,
   664                            NULL,
   665                            NULL,
   666                            0);
   667 }
   669 ///////////////////////////////////////////////////////////////////////////////
   671 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
   672                            const SkPaint& paint) {
   673     CHECK_FOR_ANNOTATION(paint);
   674     CHECK_SHOULD_DRAW(draw, false);
   676     bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
   677     SkScalar width = paint.getStrokeWidth();
   679     /*
   680         We have special code for hairline strokes, miter-strokes, bevel-stroke
   681         and fills. Anything else we just call our path code.
   682      */
   683     bool usePath = doStroke && width > 0 &&
   684                    (paint.getStrokeJoin() == SkPaint::kRound_Join ||
   685                     (paint.getStrokeJoin() == SkPaint::kBevel_Join && rect.isEmpty()));
   686     // another two reasons we might need to call drawPath...
   687     if (paint.getMaskFilter() || paint.getPathEffect()) {
   688         usePath = true;
   689     }
   690     if (!usePath && paint.isAntiAlias() && !fContext->getMatrix().rectStaysRect()) {
   691 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
   692         if (doStroke) {
   693 #endif
   694             usePath = true;
   695 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
   696         } else {
   697             usePath = !fContext->getMatrix().preservesRightAngles();
   698         }
   699 #endif
   700     }
   701     // until we can both stroke and fill rectangles
   702     if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) {
   703         usePath = true;
   704     }
   706     if (usePath) {
   707         SkPath path;
   708         path.addRect(rect);
   709         this->drawPath(draw, path, paint, NULL, true);
   710         return;
   711     }
   713     GrPaint grPaint;
   714     if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   715         return;
   716     }
   718     if (!doStroke) {
   719         fContext->drawRect(grPaint, rect);
   720     } else {
   721         SkStrokeRec stroke(paint);
   722         fContext->drawRect(grPaint, rect, &stroke);
   723     }
   724 }
   726 ///////////////////////////////////////////////////////////////////////////////
   728 void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
   729                            const SkPaint& paint) {
   730     CHECK_FOR_ANNOTATION(paint);
   731     CHECK_SHOULD_DRAW(draw, false);
   733     GrPaint grPaint;
   734     if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   735         return;
   736     }
   738     SkStrokeRec stroke(paint);
   739     if (paint.getMaskFilter()) {
   740         // try to hit the fast path for drawing filtered round rects
   742         SkRRect devRRect;
   743         if (rect.transform(fContext->getMatrix(), &devRRect)) {
   744             if (devRRect.allCornersCircular()) {
   745                 SkRect maskRect;
   746                 if (paint.getMaskFilter()->canFilterMaskGPU(devRRect.rect(),
   747                                             draw.fClip->getBounds(),
   748                                             fContext->getMatrix(),
   749                                             &maskRect)) {
   750                     SkIRect finalIRect;
   751                     maskRect.roundOut(&finalIRect);
   752                     if (draw.fClip->quickReject(finalIRect)) {
   753                         // clipped out
   754                         return;
   755                     }
   756                     if (NULL != draw.fBounder && !draw.fBounder->doIRect(finalIRect)) {
   757                         // nothing to draw
   758                         return;
   759                     }
   760                     if (paint.getMaskFilter()->directFilterRRectMaskGPU(fContext, &grPaint,
   761                                                                         stroke, devRRect)) {
   762                         return;
   763                     }
   764                 }
   766             }
   767         }
   769     }
   771     bool usePath = !rect.isSimple();
   772     // another two reasons we might need to call drawPath...
   773     if (paint.getMaskFilter() || paint.getPathEffect()) {
   774         usePath = true;
   775     }
   776     // until we can rotate rrects...
   777     if (!usePath && !fContext->getMatrix().rectStaysRect()) {
   778         usePath = true;
   779     }
   781     if (usePath) {
   782         SkPath path;
   783         path.addRRect(rect);
   784         this->drawPath(draw, path, paint, NULL, true);
   785         return;
   786     }
   788     fContext->drawRRect(grPaint, rect, stroke);
   789 }
   791 /////////////////////////////////////////////////////////////////////////////
   793 void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval,
   794                            const SkPaint& paint) {
   795     CHECK_FOR_ANNOTATION(paint);
   796     CHECK_SHOULD_DRAW(draw, false);
   798     bool usePath = false;
   799     // some basic reasons we might need to call drawPath...
   800     if (paint.getMaskFilter() || paint.getPathEffect()) {
   801         usePath = true;
   802     }
   804     if (usePath) {
   805         SkPath path;
   806         path.addOval(oval);
   807         this->drawPath(draw, path, paint, NULL, true);
   808         return;
   809     }
   811     GrPaint grPaint;
   812     if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   813         return;
   814     }
   815     SkStrokeRec stroke(paint);
   817     fContext->drawOval(grPaint, oval, stroke);
   818 }
   820 #include "SkMaskFilter.h"
   821 #include "SkBounder.h"
   823 ///////////////////////////////////////////////////////////////////////////////
   825 // helpers for applying mask filters
   826 namespace {
   828 // Draw a mask using the supplied paint. Since the coverage/geometry
   829 // is already burnt into the mask this boils down to a rect draw.
   830 // Return true if the mask was successfully drawn.
   831 bool draw_mask(GrContext* context, const SkRect& maskRect,
   832                GrPaint* grp, GrTexture* mask) {
   833     GrContext::AutoMatrix am;
   834     if (!am.setIdentity(context, grp)) {
   835         return false;
   836     }
   838     SkMatrix matrix;
   839     matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop);
   840     matrix.postIDiv(mask->width(), mask->height());
   842     grp->addCoverageEffect(GrSimpleTextureEffect::Create(mask, matrix))->unref();
   843     context->drawRect(*grp, maskRect);
   844     return true;
   845 }
   847 bool draw_with_mask_filter(GrContext* context, const SkPath& devPath,
   848                            SkMaskFilter* filter, const SkRegion& clip, SkBounder* bounder,
   849                            GrPaint* grp, SkPaint::Style style) {
   850     SkMask  srcM, dstM;
   852     if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), filter, &context->getMatrix(), &srcM,
   853                             SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) {
   854         return false;
   855     }
   856     SkAutoMaskFreeImage autoSrc(srcM.fImage);
   858     if (!filter->filterMask(&dstM, srcM, context->getMatrix(), NULL)) {
   859         return false;
   860     }
   861     // this will free-up dstM when we're done (allocated in filterMask())
   862     SkAutoMaskFreeImage autoDst(dstM.fImage);
   864     if (clip.quickReject(dstM.fBounds)) {
   865         return false;
   866     }
   867     if (bounder && !bounder->doIRect(dstM.fBounds)) {
   868         return false;
   869     }
   871     // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
   872     // the current clip (and identity matrix) and GrPaint settings
   873     GrTextureDesc desc;
   874     desc.fWidth = dstM.fBounds.width();
   875     desc.fHeight = dstM.fBounds.height();
   876     desc.fConfig = kAlpha_8_GrPixelConfig;
   878     GrAutoScratchTexture ast(context, desc);
   879     GrTexture* texture = ast.texture();
   881     if (NULL == texture) {
   882         return false;
   883     }
   884     texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
   885                                dstM.fImage, dstM.fRowBytes);
   887     SkRect maskRect = SkRect::Make(dstM.fBounds);
   889     return draw_mask(context, maskRect, grp, texture);
   890 }
   892 // Create a mask of 'devPath' and place the result in 'mask'. Return true on
   893 // success; false otherwise.
   894 bool create_mask_GPU(GrContext* context,
   895                      const SkRect& maskRect,
   896                      const SkPath& devPath,
   897                      const SkStrokeRec& stroke,
   898                      bool doAA,
   899                      GrAutoScratchTexture* mask) {
   900     GrTextureDesc desc;
   901     desc.fFlags = kRenderTarget_GrTextureFlagBit;
   902     desc.fWidth = SkScalarCeilToInt(maskRect.width());
   903     desc.fHeight = SkScalarCeilToInt(maskRect.height());
   904     // We actually only need A8, but it often isn't supported as a
   905     // render target so default to RGBA_8888
   906     desc.fConfig = kRGBA_8888_GrPixelConfig;
   907     if (context->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
   908         desc.fConfig = kAlpha_8_GrPixelConfig;
   909     }
   911     mask->set(context, desc);
   912     if (NULL == mask->texture()) {
   913         return false;
   914     }
   916     GrTexture* maskTexture = mask->texture();
   917     SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
   919     GrContext::AutoRenderTarget art(context, maskTexture->asRenderTarget());
   920     GrContext::AutoClip ac(context, clipRect);
   922     context->clear(NULL, 0x0, true);
   924     GrPaint tempPaint;
   925     if (doAA) {
   926         tempPaint.setAntiAlias(true);
   927         // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst
   928         // blend coeff of zero requires dual source blending support in order
   929         // to properly blend partially covered pixels. This means the AA
   930         // code path may not be taken. So we use a dst blend coeff of ISA. We
   931         // could special case AA draws to a dst surface with known alpha=0 to
   932         // use a zero dst coeff when dual source blending isn't available.
   933         tempPaint.setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
   934     }
   936     GrContext::AutoMatrix am;
   938     // Draw the mask into maskTexture with the path's top-left at the origin using tempPaint.
   939     SkMatrix translate;
   940     translate.setTranslate(-maskRect.fLeft, -maskRect.fTop);
   941     am.set(context, translate);
   942     context->drawPath(tempPaint, devPath, stroke);
   943     return true;
   944 }
   946 SkBitmap wrap_texture(GrTexture* texture) {
   947     SkImageInfo info;
   948     texture->asImageInfo(&info);
   950     SkBitmap result;
   951     result.setConfig(info);
   952     result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
   953     return result;
   954 }
   956 };
   958 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
   959                            const SkPaint& paint, const SkMatrix* prePathMatrix,
   960                            bool pathIsMutable) {
   961     CHECK_FOR_ANNOTATION(paint);
   962     CHECK_SHOULD_DRAW(draw, false);
   964     GrPaint grPaint;
   965     if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   966         return;
   967     }
   969     // If we have a prematrix, apply it to the path, optimizing for the case
   970     // where the original path can in fact be modified in place (even though
   971     // its parameter type is const).
   972     SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
   973     SkTLazy<SkPath> tmpPath;
   974     SkTLazy<SkPath> effectPath;
   976     if (prePathMatrix) {
   977         SkPath* result = pathPtr;
   979         if (!pathIsMutable) {
   980             result = tmpPath.init();
   981             pathIsMutable = true;
   982         }
   983         // should I push prePathMatrix on our MV stack temporarily, instead
   984         // of applying it here? See SkDraw.cpp
   985         pathPtr->transform(*prePathMatrix, result);
   986         pathPtr = result;
   987     }
   988     // at this point we're done with prePathMatrix
   989     SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
   991     SkStrokeRec stroke(paint);
   992     SkPathEffect* pathEffect = paint.getPathEffect();
   993     const SkRect* cullRect = NULL;  // TODO: what is our bounds?
   994     if (pathEffect && pathEffect->filterPath(effectPath.init(), *pathPtr, &stroke,
   995                                              cullRect)) {
   996         pathPtr = effectPath.get();
   997         pathIsMutable = true;
   998     }
  1000     if (paint.getMaskFilter()) {
  1001         if (!stroke.isHairlineStyle()) {
  1002             SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init();
  1003             if (stroke.applyToPath(strokedPath, *pathPtr)) {
  1004                 pathPtr = strokedPath;
  1005                 pathIsMutable = true;
  1006                 stroke.setFillStyle();
  1010         // avoid possibly allocating a new path in transform if we can
  1011         SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init();
  1013         // transform the path into device space
  1014         pathPtr->transform(fContext->getMatrix(), devPathPtr);
  1016         SkRect maskRect;
  1017         if (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(),
  1018                                                     draw.fClip->getBounds(),
  1019                                                     fContext->getMatrix(),
  1020                                                     &maskRect)) {
  1021             // The context's matrix may change while creating the mask, so save the CTM here to
  1022             // pass to filterMaskGPU.
  1023             const SkMatrix ctm = fContext->getMatrix();
  1025             SkIRect finalIRect;
  1026             maskRect.roundOut(&finalIRect);
  1027             if (draw.fClip->quickReject(finalIRect)) {
  1028                 // clipped out
  1029                 return;
  1031             if (NULL != draw.fBounder && !draw.fBounder->doIRect(finalIRect)) {
  1032                 // nothing to draw
  1033                 return;
  1036             if (paint.getMaskFilter()->directFilterMaskGPU(fContext, &grPaint,
  1037                                                            stroke, *devPathPtr)) {
  1038                 // the mask filter was able to draw itself directly, so there's nothing
  1039                 // left to do.
  1040                 return;
  1043             GrAutoScratchTexture mask;
  1045             if (create_mask_GPU(fContext, maskRect, *devPathPtr, stroke,
  1046                                 grPaint.isAntiAlias(), &mask)) {
  1047                 GrTexture* filtered;
  1049                 if (paint.getMaskFilter()->filterMaskGPU(mask.texture(),
  1050                                                          ctm, maskRect, &filtered, true)) {
  1051                     // filterMaskGPU gives us ownership of a ref to the result
  1052                     SkAutoTUnref<GrTexture> atu(filtered);
  1054                     // If the scratch texture that we used as the filter src also holds the filter
  1055                     // result then we must detach so that this texture isn't recycled for a later
  1056                     // draw.
  1057                     if (filtered == mask.texture()) {
  1058                         mask.detach();
  1059                         filtered->unref(); // detach transfers GrAutoScratchTexture's ref to us.
  1062                     if (draw_mask(fContext, maskRect, &grPaint, filtered)) {
  1063                         // This path is completely drawn
  1064                         return;
  1070         // draw the mask on the CPU - this is a fallthrough path in case the
  1071         // GPU path fails
  1072         SkPaint::Style style = stroke.isHairlineStyle() ? SkPaint::kStroke_Style :
  1073                                                           SkPaint::kFill_Style;
  1074         draw_with_mask_filter(fContext, *devPathPtr, paint.getMaskFilter(),
  1075                               *draw.fClip, draw.fBounder, &grPaint, style);
  1076         return;
  1079     fContext->drawPath(grPaint, *pathPtr, stroke);
  1082 static const int kBmpSmallTileSize = 1 << 10;
  1084 static inline int get_tile_count(const SkIRect& srcRect, int tileSize)  {
  1085     int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1;
  1086     int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1;
  1087     return tilesX * tilesY;
  1090 static int determine_tile_size(const SkBitmap& bitmap, const SkIRect& src, int maxTileSize) {
  1091     if (maxTileSize <= kBmpSmallTileSize) {
  1092         return maxTileSize;
  1095     size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize);
  1096     size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize);
  1098     maxTileTotalTileSize *= maxTileSize * maxTileSize;
  1099     smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize;
  1101     if (maxTileTotalTileSize > 2 * smallTotalTileSize) {
  1102         return kBmpSmallTileSize;
  1103     } else {
  1104         return maxTileSize;
  1108 // Given a bitmap, an optional src rect, and a context with a clip and matrix determine what
  1109 // pixels from the bitmap are necessary.
  1110 static void determine_clipped_src_rect(const GrContext* context,
  1111                                        const SkBitmap& bitmap,
  1112                                        const SkRect* srcRectPtr,
  1113                                        SkIRect* clippedSrcIRect) {
  1114     const GrClipData* clip = context->getClip();
  1115     clip->getConservativeBounds(context->getRenderTarget(), clippedSrcIRect, NULL);
  1116     SkMatrix inv;
  1117     if (!context->getMatrix().invert(&inv)) {
  1118         clippedSrcIRect->setEmpty();
  1119         return;
  1121     SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect);
  1122     inv.mapRect(&clippedSrcRect);
  1123     if (NULL != srcRectPtr) {
  1124         // we've setup src space 0,0 to map to the top left of the src rect.
  1125         clippedSrcRect.offset(srcRectPtr->fLeft, srcRectPtr->fTop);
  1126         if (!clippedSrcRect.intersect(*srcRectPtr)) {
  1127             clippedSrcIRect->setEmpty();
  1128             return;
  1131     clippedSrcRect.roundOut(clippedSrcIRect);
  1132     SkIRect bmpBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
  1133     if (!clippedSrcIRect->intersect(bmpBounds)) {
  1134         clippedSrcIRect->setEmpty();
  1138 bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap,
  1139                                    const GrTextureParams& params,
  1140                                    const SkRect* srcRectPtr,
  1141                                    int maxTileSize,
  1142                                    int* tileSize,
  1143                                    SkIRect* clippedSrcRect) const {
  1144     // if bitmap is explictly texture backed then just use the texture
  1145     if (NULL != bitmap.getTexture()) {
  1146         return false;
  1149     // if it's larger than the max tile size, then we have no choice but tiling.
  1150     if (bitmap.width() > maxTileSize || bitmap.height() > maxTileSize) {
  1151         determine_clipped_src_rect(fContext, bitmap, srcRectPtr, clippedSrcRect);
  1152         *tileSize = determine_tile_size(bitmap, *clippedSrcRect, maxTileSize);
  1153         return true;
  1156     if (bitmap.width() * bitmap.height() < 4 * kBmpSmallTileSize * kBmpSmallTileSize) {
  1157         return false;
  1160     // if the entire texture is already in our cache then no reason to tile it
  1161     if (GrIsBitmapInCache(fContext, bitmap, &params)) {
  1162         return false;
  1165     // At this point we know we could do the draw by uploading the entire bitmap
  1166     // as a texture. However, if the texture would be large compared to the
  1167     // cache size and we don't require most of it for this draw then tile to
  1168     // reduce the amount of upload and cache spill.
  1170     // assumption here is that sw bitmap size is a good proxy for its size as
  1171     // a texture
  1172     size_t bmpSize = bitmap.getSize();
  1173     size_t cacheSize;
  1174     fContext->getTextureCacheLimits(NULL, &cacheSize);
  1175     if (bmpSize < cacheSize / 2) {
  1176         return false;
  1179     // Figure out how much of the src we will need based on the src rect and clipping.
  1180     determine_clipped_src_rect(fContext, bitmap, srcRectPtr, clippedSrcRect);
  1181     *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile.
  1182     size_t usedTileBytes = get_tile_count(*clippedSrcRect, kBmpSmallTileSize) *
  1183                            kBmpSmallTileSize * kBmpSmallTileSize;
  1185     return usedTileBytes < 2 * bmpSize;
  1188 void SkGpuDevice::drawBitmap(const SkDraw& origDraw,
  1189                              const SkBitmap& bitmap,
  1190                              const SkMatrix& m,
  1191                              const SkPaint& paint) {
  1192     SkMatrix concat;
  1193     SkTCopyOnFirstWrite<SkDraw> draw(origDraw);
  1194     if (!m.isIdentity()) {
  1195         concat.setConcat(*draw->fMatrix, m);
  1196         draw.writable()->fMatrix = &concat;
  1198     this->drawBitmapCommon(*draw, bitmap, NULL, NULL, paint, SkCanvas::kNone_DrawBitmapRectFlag);
  1201 // This method outsets 'iRect' by 'outset' all around and then clamps its extents to
  1202 // 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner
  1203 // of 'iRect' for all possible outsets/clamps.
  1204 static inline void clamped_outset_with_offset(SkIRect* iRect,
  1205                                               int outset,
  1206                                               SkPoint* offset,
  1207                                               const SkIRect& clamp) {
  1208     iRect->outset(outset, outset);
  1210     int leftClampDelta = clamp.fLeft - iRect->fLeft;
  1211     if (leftClampDelta > 0) {
  1212         offset->fX -= outset - leftClampDelta;
  1213         iRect->fLeft = clamp.fLeft;
  1214     } else {
  1215         offset->fX -= outset;
  1218     int topClampDelta = clamp.fTop - iRect->fTop;
  1219     if (topClampDelta > 0) {
  1220         offset->fY -= outset - topClampDelta;
  1221         iRect->fTop = clamp.fTop;
  1222     } else {
  1223         offset->fY -= outset;
  1226     if (iRect->fRight > clamp.fRight) {
  1227         iRect->fRight = clamp.fRight;
  1229     if (iRect->fBottom > clamp.fBottom) {
  1230         iRect->fBottom = clamp.fBottom;
  1234 void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
  1235                                    const SkBitmap& bitmap,
  1236                                    const SkRect* srcRectPtr,
  1237                                    const SkSize* dstSizePtr,
  1238                                    const SkPaint& paint,
  1239                                    SkCanvas::DrawBitmapRectFlags flags) {
  1240     CHECK_SHOULD_DRAW(draw, false);
  1242     SkRect srcRect;
  1243     SkSize dstSize;
  1244     // If there is no src rect, or the src rect contains the entire bitmap then we're effectively
  1245     // in the (easier) bleed case, so update flags.
  1246     if (NULL == srcRectPtr) {
  1247         SkScalar w = SkIntToScalar(bitmap.width());
  1248         SkScalar h = SkIntToScalar(bitmap.height());
  1249         dstSize.fWidth = w;
  1250         dstSize.fHeight = h;
  1251         srcRect.set(0, 0, w, h);
  1252         flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag);
  1253     } else {
  1254         SkASSERT(NULL != dstSizePtr);
  1255         srcRect = *srcRectPtr;
  1256         dstSize = *dstSizePtr;
  1257         if (srcRect.fLeft <= 0 && srcRect.fTop <= 0 &&
  1258             srcRect.fRight >= bitmap.width() && srcRect.fBottom >= bitmap.height()) {
  1259             flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag);
  1263     if (paint.getMaskFilter()){
  1264         // Convert the bitmap to a shader so that the rect can be drawn
  1265         // through drawRect, which supports mask filters.
  1266         SkBitmap        tmp;    // subset of bitmap, if necessary
  1267         const SkBitmap* bitmapPtr = &bitmap;
  1268         SkMatrix localM;
  1269         if (NULL != srcRectPtr) {
  1270             localM.setTranslate(-srcRectPtr->fLeft, -srcRectPtr->fTop);
  1271             localM.postScale(dstSize.fWidth / srcRectPtr->width(),
  1272                              dstSize.fHeight / srcRectPtr->height());
  1273             // In bleed mode we position and trim the bitmap based on the src rect which is
  1274             // already accounted for in 'm' and 'srcRect'. In clamp mode we need to chop out
  1275             // the desired portion of the bitmap and then update 'm' and 'srcRect' to
  1276             // compensate.
  1277             if (!(SkCanvas::kBleed_DrawBitmapRectFlag & flags)) {
  1278                 SkIRect iSrc;
  1279                 srcRect.roundOut(&iSrc);
  1281                 SkPoint offset = SkPoint::Make(SkIntToScalar(iSrc.fLeft),
  1282                                                SkIntToScalar(iSrc.fTop));
  1284                 if (!bitmap.extractSubset(&tmp, iSrc)) {
  1285                     return;     // extraction failed
  1287                 bitmapPtr = &tmp;
  1288                 srcRect.offset(-offset.fX, -offset.fY);
  1290                 // The source rect has changed so update the matrix
  1291                 localM.preTranslate(offset.fX, offset.fY);
  1293         } else {
  1294             localM.reset();
  1297         SkPaint paintWithShader(paint);
  1298         paintWithShader.setShader(SkShader::CreateBitmapShader(*bitmapPtr,
  1299             SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
  1300         paintWithShader.getShader()->setLocalMatrix(localM);
  1301         SkRect dstRect = {0, 0, dstSize.fWidth, dstSize.fHeight};
  1302         this->drawRect(draw, dstRect, paintWithShader);
  1304         return;
  1307     // If there is no mask filter than it is OK to handle the src rect -> dst rect scaling using
  1308     // the view matrix rather than a local matrix.
  1309     SkMatrix m;
  1310     m.setScale(dstSize.fWidth / srcRect.width(),
  1311                dstSize.fHeight / srcRect.height());
  1312     fContext->concatMatrix(m);
  1314     GrTextureParams params;
  1315     SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
  1316     GrTextureParams::FilterMode textureFilterMode;
  1318     int tileFilterPad;
  1319     bool doBicubic = false;
  1321     switch(paintFilterLevel) {
  1322         case SkPaint::kNone_FilterLevel:
  1323             tileFilterPad = 0;
  1324             textureFilterMode = GrTextureParams::kNone_FilterMode;
  1325             break;
  1326         case SkPaint::kLow_FilterLevel:
  1327             tileFilterPad = 1;
  1328             textureFilterMode = GrTextureParams::kBilerp_FilterMode;
  1329             break;
  1330         case SkPaint::kMedium_FilterLevel:
  1331             tileFilterPad = 1;
  1332             if (fContext->getMatrix().getMinStretch() < SK_Scalar1) {
  1333                 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
  1334             } else {
  1335                 // Don't trigger MIP level generation unnecessarily.
  1336                 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
  1338             break;
  1339         case SkPaint::kHigh_FilterLevel:
  1340             // Minification can look bad with the bicubic effect.
  1341             if (fContext->getMatrix().getMinStretch() >= SK_Scalar1) {
  1342                 // We will install an effect that does the filtering in the shader.
  1343                 textureFilterMode = GrTextureParams::kNone_FilterMode;
  1344                 tileFilterPad = GrBicubicEffect::kFilterTexelPad;
  1345                 doBicubic = true;
  1346             } else {
  1347                 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
  1348                 tileFilterPad = 1;
  1350             break;
  1351         default:
  1352             SkErrorInternals::SetError( kInvalidPaint_SkError,
  1353                                         "Sorry, I don't understand the filtering "
  1354                                         "mode you asked for.  Falling back to "
  1355                                         "MIPMaps.");
  1356             tileFilterPad = 1;
  1357             textureFilterMode = GrTextureParams::kMipMap_FilterMode;
  1358             break;
  1361     params.setFilterMode(textureFilterMode);
  1363     int maxTileSize = fContext->getMaxTextureSize() - 2 * tileFilterPad;
  1364     int tileSize;
  1366     SkIRect clippedSrcRect;
  1367     if (this->shouldTileBitmap(bitmap, params, srcRectPtr, maxTileSize, &tileSize,
  1368                                &clippedSrcRect)) {
  1369         this->drawTiledBitmap(bitmap, srcRect, clippedSrcRect, params, paint, flags, tileSize,
  1370                               doBicubic);
  1371     } else {
  1372         // take the simple case
  1373         this->internalDrawBitmap(bitmap, srcRect, params, paint, flags, doBicubic);
  1377 // Break 'bitmap' into several tiles to draw it since it has already
  1378 // been determined to be too large to fit in VRAM
  1379 void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
  1380                                   const SkRect& srcRect,
  1381                                   const SkIRect& clippedSrcIRect,
  1382                                   const GrTextureParams& params,
  1383                                   const SkPaint& paint,
  1384                                   SkCanvas::DrawBitmapRectFlags flags,
  1385                                   int tileSize,
  1386                                   bool bicubic) {
  1387     SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
  1389     int nx = bitmap.width() / tileSize;
  1390     int ny = bitmap.height() / tileSize;
  1391     for (int x = 0; x <= nx; x++) {
  1392         for (int y = 0; y <= ny; y++) {
  1393             SkRect tileR;
  1394             tileR.set(SkIntToScalar(x * tileSize),
  1395                       SkIntToScalar(y * tileSize),
  1396                       SkIntToScalar((x + 1) * tileSize),
  1397                       SkIntToScalar((y + 1) * tileSize));
  1399             if (!SkRect::Intersects(tileR, clippedSrcRect)) {
  1400                 continue;
  1403             if (!tileR.intersect(srcRect)) {
  1404                 continue;
  1407             SkBitmap tmpB;
  1408             SkIRect iTileR;
  1409             tileR.roundOut(&iTileR);
  1410             SkPoint offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft),
  1411                                            SkIntToScalar(iTileR.fTop));
  1413             // Adjust the context matrix to draw at the right x,y in device space
  1414             SkMatrix tmpM;
  1415             GrContext::AutoMatrix am;
  1416             tmpM.setTranslate(offset.fX - srcRect.fLeft, offset.fY - srcRect.fTop);
  1417             am.setPreConcat(fContext, tmpM);
  1419             if (SkPaint::kNone_FilterLevel != paint.getFilterLevel() || bicubic) {
  1420                 SkIRect iClampRect;
  1422                 if (SkCanvas::kBleed_DrawBitmapRectFlag & flags) {
  1423                     // In bleed mode we want to always expand the tile on all edges
  1424                     // but stay within the bitmap bounds
  1425                     iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height());
  1426                 } else {
  1427                     // In texture-domain/clamp mode we only want to expand the
  1428                     // tile on edges interior to "srcRect" (i.e., we want to
  1429                     // not bleed across the original clamped edges)
  1430                     srcRect.roundOut(&iClampRect);
  1432                 int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1;
  1433                 clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect);
  1436             if (bitmap.extractSubset(&tmpB, iTileR)) {
  1437                 // now offset it to make it "local" to our tmp bitmap
  1438                 tileR.offset(-offset.fX, -offset.fY);
  1440                 this->internalDrawBitmap(tmpB, tileR, params, paint, flags, bicubic);
  1446 static bool has_aligned_samples(const SkRect& srcRect,
  1447                                 const SkRect& transformedRect) {
  1448     // detect pixel disalignment
  1449     if (SkScalarAbs(SkScalarRoundToScalar(transformedRect.left()) -
  1450             transformedRect.left()) < COLOR_BLEED_TOLERANCE &&
  1451         SkScalarAbs(SkScalarRoundToScalar(transformedRect.top()) -
  1452             transformedRect.top()) < COLOR_BLEED_TOLERANCE &&
  1453         SkScalarAbs(transformedRect.width() - srcRect.width()) <
  1454             COLOR_BLEED_TOLERANCE &&
  1455         SkScalarAbs(transformedRect.height() - srcRect.height()) <
  1456             COLOR_BLEED_TOLERANCE) {
  1457         return true;
  1459     return false;
  1462 static bool may_color_bleed(const SkRect& srcRect,
  1463                             const SkRect& transformedRect,
  1464                             const SkMatrix& m) {
  1465     // Only gets called if has_aligned_samples returned false.
  1466     // So we can assume that sampling is axis aligned but not texel aligned.
  1467     SkASSERT(!has_aligned_samples(srcRect, transformedRect));
  1468     SkRect innerSrcRect(srcRect), innerTransformedRect,
  1469         outerTransformedRect(transformedRect);
  1470     innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf);
  1471     m.mapRect(&innerTransformedRect, innerSrcRect);
  1473     // The gap between outerTransformedRect and innerTransformedRect
  1474     // represents the projection of the source border area, which is
  1475     // problematic for color bleeding.  We must check whether any
  1476     // destination pixels sample the border area.
  1477     outerTransformedRect.inset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
  1478     innerTransformedRect.outset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
  1479     SkIRect outer, inner;
  1480     outerTransformedRect.round(&outer);
  1481     innerTransformedRect.round(&inner);
  1482     // If the inner and outer rects round to the same result, it means the
  1483     // border does not overlap any pixel centers. Yay!
  1484     return inner != outer;
  1488 /*
  1489  *  This is called by drawBitmap(), which has to handle images that may be too
  1490  *  large to be represented by a single texture.
  1492  *  internalDrawBitmap assumes that the specified bitmap will fit in a texture
  1493  *  and that non-texture portion of the GrPaint has already been setup.
  1494  */
  1495 void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
  1496                                      const SkRect& srcRect,
  1497                                      const GrTextureParams& params,
  1498                                      const SkPaint& paint,
  1499                                      SkCanvas::DrawBitmapRectFlags flags,
  1500                                      bool bicubic) {
  1501     SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
  1502              bitmap.height() <= fContext->getMaxTextureSize());
  1504     GrTexture* texture;
  1505     SkAutoCachedTexture act(this, bitmap, &params, &texture);
  1506     if (NULL == texture) {
  1507         return;
  1510     SkRect dstRect = {0, 0, srcRect.width(), srcRect.height() };
  1511     SkRect paintRect;
  1512     SkScalar wInv = SkScalarInvert(SkIntToScalar(texture->width()));
  1513     SkScalar hInv = SkScalarInvert(SkIntToScalar(texture->height()));
  1514     paintRect.setLTRB(SkScalarMul(srcRect.fLeft,   wInv),
  1515                       SkScalarMul(srcRect.fTop,    hInv),
  1516                       SkScalarMul(srcRect.fRight,  wInv),
  1517                       SkScalarMul(srcRect.fBottom, hInv));
  1519     bool needsTextureDomain = false;
  1520     if (!(flags & SkCanvas::kBleed_DrawBitmapRectFlag) &&
  1521         (bicubic || params.filterMode() != GrTextureParams::kNone_FilterMode)) {
  1522         // Need texture domain if drawing a sub rect
  1523         needsTextureDomain = srcRect.width() < bitmap.width() ||
  1524                              srcRect.height() < bitmap.height();
  1525         if (!bicubic && needsTextureDomain && fContext->getMatrix().rectStaysRect()) {
  1526             const SkMatrix& matrix = fContext->getMatrix();
  1527             // sampling is axis-aligned
  1528             SkRect transformedRect;
  1529             matrix.mapRect(&transformedRect, srcRect);
  1531             if (has_aligned_samples(srcRect, transformedRect)) {
  1532                 // We could also turn off filtering here (but we already did a cache lookup with
  1533                 // params).
  1534                 needsTextureDomain = false;
  1535             } else {
  1536                 needsTextureDomain = may_color_bleed(srcRect, transformedRect, matrix);
  1541     SkRect textureDomain = SkRect::MakeEmpty();
  1542     SkAutoTUnref<GrEffectRef> effect;
  1543     if (needsTextureDomain) {
  1544         // Use a constrained texture domain to avoid color bleeding
  1545         SkScalar left, top, right, bottom;
  1546         if (srcRect.width() > SK_Scalar1) {
  1547             SkScalar border = SK_ScalarHalf / texture->width();
  1548             left = paintRect.left() + border;
  1549             right = paintRect.right() - border;
  1550         } else {
  1551             left = right = SkScalarHalf(paintRect.left() + paintRect.right());
  1553         if (srcRect.height() > SK_Scalar1) {
  1554             SkScalar border = SK_ScalarHalf / texture->height();
  1555             top = paintRect.top() + border;
  1556             bottom = paintRect.bottom() - border;
  1557         } else {
  1558             top = bottom = SkScalarHalf(paintRect.top() + paintRect.bottom());
  1560         textureDomain.setLTRB(left, top, right, bottom);
  1561         if (bicubic) {
  1562             effect.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), textureDomain));
  1563         } else {
  1564             effect.reset(GrTextureDomainEffect::Create(texture,
  1565                                                        SkMatrix::I(),
  1566                                                        textureDomain,
  1567                                                        GrTextureDomain::kClamp_Mode,
  1568                                                        params.filterMode()));
  1570     } else if (bicubic) {
  1571         SkASSERT(GrTextureParams::kNone_FilterMode == params.filterMode());
  1572         SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() };
  1573         effect.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), tileModes));
  1574     } else {
  1575         effect.reset(GrSimpleTextureEffect::Create(texture, SkMatrix::I(), params));
  1578     // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring
  1579     // the rest from the SkPaint.
  1580     GrPaint grPaint;
  1581     grPaint.addColorEffect(effect);
  1582     bool alphaOnly = !(SkBitmap::kA8_Config == bitmap.config());
  1583     if (!skPaint2GrPaintNoShader(this, paint, alphaOnly, false, &grPaint)) {
  1584         return;
  1587     fContext->drawRectToRect(grPaint, dstRect, paintRect, NULL);
  1590 static bool filter_texture(SkBaseDevice* device, GrContext* context,
  1591                            GrTexture* texture, const SkImageFilter* filter,
  1592                            int w, int h, const SkImageFilter::Context& ctx,
  1593                            SkBitmap* result, SkIPoint* offset) {
  1594     SkASSERT(filter);
  1595     SkDeviceImageFilterProxy proxy(device);
  1597     if (filter->canFilterImageGPU()) {
  1598         // Save the render target and set it to NULL, so we don't accidentally draw to it in the
  1599         // filter.  Also set the clip wide open and the matrix to identity.
  1600         GrContext::AutoWideOpenIdentityDraw awo(context, NULL);
  1601         return filter->filterImageGPU(&proxy, wrap_texture(texture), ctx, result, offset);
  1602     } else {
  1603         return false;
  1607 void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
  1608                              int left, int top, const SkPaint& paint) {
  1609     // drawSprite is defined to be in device coords.
  1610     CHECK_SHOULD_DRAW(draw, true);
  1612     SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
  1613     if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
  1614         return;
  1617     int w = bitmap.width();
  1618     int h = bitmap.height();
  1620     GrTexture* texture;
  1621     // draw sprite uses the default texture params
  1622     SkAutoCachedTexture act(this, bitmap, NULL, &texture);
  1624     SkImageFilter* filter = paint.getImageFilter();
  1625     // This bitmap will own the filtered result as a texture.
  1626     SkBitmap filteredBitmap;
  1628     if (NULL != filter) {
  1629         SkIPoint offset = SkIPoint::Make(0, 0);
  1630         SkMatrix matrix(*draw.fMatrix);
  1631         matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
  1632         SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
  1633         SkImageFilter::Context ctx(matrix, clipBounds);
  1634         if (filter_texture(this, fContext, texture, filter, w, h, ctx, &filteredBitmap,
  1635                            &offset)) {
  1636             texture = (GrTexture*) filteredBitmap.getTexture();
  1637             w = filteredBitmap.width();
  1638             h = filteredBitmap.height();
  1639             left += offset.x();
  1640             top += offset.y();
  1641         } else {
  1642             return;
  1646     GrPaint grPaint;
  1647     grPaint.addColorTextureEffect(texture, SkMatrix::I());
  1649     if(!skPaint2GrPaintNoShader(this, paint, true, false, &grPaint)) {
  1650         return;
  1653     fContext->drawRectToRect(grPaint,
  1654                              SkRect::MakeXYWH(SkIntToScalar(left),
  1655                                               SkIntToScalar(top),
  1656                                               SkIntToScalar(w),
  1657                                               SkIntToScalar(h)),
  1658                              SkRect::MakeXYWH(0,
  1659                                               0,
  1660                                               SK_Scalar1 * w / texture->width(),
  1661                                               SK_Scalar1 * h / texture->height()));
  1664 void SkGpuDevice::drawBitmapRect(const SkDraw& origDraw, const SkBitmap& bitmap,
  1665                                  const SkRect* src, const SkRect& dst,
  1666                                  const SkPaint& paint,
  1667                                  SkCanvas::DrawBitmapRectFlags flags) {
  1668     SkMatrix    matrix;
  1669     SkRect      bitmapBounds, tmpSrc;
  1671     bitmapBounds.set(0, 0,
  1672                      SkIntToScalar(bitmap.width()),
  1673                      SkIntToScalar(bitmap.height()));
  1675     // Compute matrix from the two rectangles
  1676     if (NULL != src) {
  1677         tmpSrc = *src;
  1678     } else {
  1679         tmpSrc = bitmapBounds;
  1682     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
  1684     // clip the tmpSrc to the bounds of the bitmap. No check needed if src==null.
  1685     if (NULL != src) {
  1686         if (!bitmapBounds.contains(tmpSrc)) {
  1687             if (!tmpSrc.intersect(bitmapBounds)) {
  1688                 return; // nothing to draw
  1693     SkRect tmpDst;
  1694     matrix.mapRect(&tmpDst, tmpSrc);
  1696     SkTCopyOnFirstWrite<SkDraw> draw(origDraw);
  1697     if (0 != tmpDst.fLeft || 0 != tmpDst.fTop) {
  1698         // Translate so that tempDst's top left is at the origin.
  1699         matrix = *origDraw.fMatrix;
  1700         matrix.preTranslate(tmpDst.fLeft, tmpDst.fTop);
  1701         draw.writable()->fMatrix = &matrix;
  1703     SkSize dstSize;
  1704     dstSize.fWidth = tmpDst.width();
  1705     dstSize.fHeight = tmpDst.height();
  1707     this->drawBitmapCommon(*draw, bitmap, &tmpSrc, &dstSize, paint, flags);
  1710 void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
  1711                              int x, int y, const SkPaint& paint) {
  1712     // clear of the source device must occur before CHECK_SHOULD_DRAW
  1713     SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
  1714     if (dev->fNeedClear) {
  1715         // TODO: could check here whether we really need to draw at all
  1716         dev->clear(0x0);
  1719     // drawDevice is defined to be in device coords.
  1720     CHECK_SHOULD_DRAW(draw, true);
  1722     GrRenderTarget* devRT = dev->accessRenderTarget();
  1723     GrTexture* devTex;
  1724     if (NULL == (devTex = devRT->asTexture())) {
  1725         return;
  1728     const SkBitmap& bm = dev->accessBitmap(false);
  1729     int w = bm.width();
  1730     int h = bm.height();
  1732     SkImageFilter* filter = paint.getImageFilter();
  1733     // This bitmap will own the filtered result as a texture.
  1734     SkBitmap filteredBitmap;
  1736     if (NULL != filter) {
  1737         SkIPoint offset = SkIPoint::Make(0, 0);
  1738         SkMatrix matrix(*draw.fMatrix);
  1739         matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
  1740         SkIRect clipBounds = SkIRect::MakeWH(devTex->width(), devTex->height());
  1741         SkImageFilter::Context ctx(matrix, clipBounds);
  1742         if (filter_texture(this, fContext, devTex, filter, w, h, ctx, &filteredBitmap,
  1743                            &offset)) {
  1744             devTex = filteredBitmap.getTexture();
  1745             w = filteredBitmap.width();
  1746             h = filteredBitmap.height();
  1747             x += offset.fX;
  1748             y += offset.fY;
  1749         } else {
  1750             return;
  1754     GrPaint grPaint;
  1755     grPaint.addColorTextureEffect(devTex, SkMatrix::I());
  1757     if (!skPaint2GrPaintNoShader(this, paint, true, false, &grPaint)) {
  1758         return;
  1761     SkRect dstRect = SkRect::MakeXYWH(SkIntToScalar(x),
  1762                                       SkIntToScalar(y),
  1763                                       SkIntToScalar(w),
  1764                                       SkIntToScalar(h));
  1766     // The device being drawn may not fill up its texture (e.g. saveLayer uses approximate
  1767     // scratch texture).
  1768     SkRect srcRect = SkRect::MakeWH(SK_Scalar1 * w / devTex->width(),
  1769                                     SK_Scalar1 * h / devTex->height());
  1771     fContext->drawRectToRect(grPaint, dstRect, srcRect);
  1774 bool SkGpuDevice::canHandleImageFilter(const SkImageFilter* filter) {
  1775     return filter->canFilterImageGPU();
  1778 bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src,
  1779                               const SkImageFilter::Context& ctx,
  1780                               SkBitmap* result, SkIPoint* offset) {
  1781     // want explicitly our impl, so guard against a subclass of us overriding it
  1782     if (!this->SkGpuDevice::canHandleImageFilter(filter)) {
  1783         return false;
  1786     SkAutoLockPixels alp(src, !src.getTexture());
  1787     if (!src.getTexture() && !src.readyToDraw()) {
  1788         return false;
  1791     GrTexture* texture;
  1792     // We assume here that the filter will not attempt to tile the src. Otherwise, this cache lookup
  1793     // must be pushed upstack.
  1794     SkAutoCachedTexture act(this, src, NULL, &texture);
  1796     return filter_texture(this, fContext, texture, filter, src.width(), src.height(), ctx,
  1797                           result, offset);
  1800 ///////////////////////////////////////////////////////////////////////////////
  1802 // must be in SkCanvas::VertexMode order
  1803 static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
  1804     kTriangles_GrPrimitiveType,
  1805     kTriangleStrip_GrPrimitiveType,
  1806     kTriangleFan_GrPrimitiveType,
  1807 };
  1809 void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
  1810                               int vertexCount, const SkPoint vertices[],
  1811                               const SkPoint texs[], const SkColor colors[],
  1812                               SkXfermode* xmode,
  1813                               const uint16_t indices[], int indexCount,
  1814                               const SkPaint& paint) {
  1815     CHECK_SHOULD_DRAW(draw, false);
  1817     GrPaint grPaint;
  1818     // we ignore the shader if texs is null.
  1819     if (NULL == texs) {
  1820         if (!skPaint2GrPaintNoShader(this, paint, false, NULL == colors, &grPaint)) {
  1821             return;
  1823     } else {
  1824         if (!skPaint2GrPaintShader(this, paint, NULL == colors, &grPaint)) {
  1825             return;
  1829     if (NULL != xmode && NULL != texs && NULL != colors) {
  1830         if (!SkXfermode::IsMode(xmode, SkXfermode::kModulate_Mode)) {
  1831             SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
  1832 #if 0
  1833             return
  1834 #endif
  1838     SkAutoSTMalloc<128, GrColor> convertedColors(0);
  1839     if (NULL != colors) {
  1840         // need to convert byte order and from non-PM to PM
  1841         convertedColors.reset(vertexCount);
  1842         for (int i = 0; i < vertexCount; ++i) {
  1843             convertedColors[i] = SkColor2GrColor(colors[i]);
  1845         colors = convertedColors.get();
  1847     fContext->drawVertices(grPaint,
  1848                            gVertexMode2PrimitiveType[vmode],
  1849                            vertexCount,
  1850                            (GrPoint*) vertices,
  1851                            (GrPoint*) texs,
  1852                            colors,
  1853                            indices,
  1854                            indexCount);
  1857 ///////////////////////////////////////////////////////////////////////////////
  1859 void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
  1860                           size_t byteLength, SkScalar x, SkScalar y,
  1861                           const SkPaint& paint) {
  1862     CHECK_SHOULD_DRAW(draw, false);
  1864     if (fMainTextContext->canDraw(paint)) {
  1865         GrPaint grPaint;
  1866         if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
  1867             return;
  1870         SkDEBUGCODE(this->validate();)
  1872         fMainTextContext->drawText(grPaint, paint, (const char *)text, byteLength, x, y);
  1873     } else if (fFallbackTextContext && fFallbackTextContext->canDraw(paint)) {
  1874         GrPaint grPaint;
  1875         if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
  1876             return;
  1879         SkDEBUGCODE(this->validate();)
  1881         fFallbackTextContext->drawText(grPaint, paint, (const char *)text, byteLength, x, y);
  1882     } else {
  1883         // this guy will just call our drawPath()
  1884         draw.drawText_asPaths((const char*)text, byteLength, x, y, paint);
  1888 void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
  1889                              size_t byteLength, const SkScalar pos[],
  1890                              SkScalar constY, int scalarsPerPos,
  1891                              const SkPaint& paint) {
  1892     CHECK_SHOULD_DRAW(draw, false);
  1894     if (fMainTextContext->canDraw(paint)) {
  1895         GrPaint grPaint;
  1896         if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
  1897             return;
  1900         SkDEBUGCODE(this->validate();)
  1902         fMainTextContext->drawPosText(grPaint, paint, (const char *)text, byteLength, pos,
  1903                                       constY, scalarsPerPos);
  1904     } else if (fFallbackTextContext && fFallbackTextContext->canDraw(paint)) {
  1905         GrPaint grPaint;
  1906         if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
  1907             return;
  1910         SkDEBUGCODE(this->validate();)
  1912         fFallbackTextContext->drawPosText(grPaint, paint, (const char *)text, byteLength, pos,
  1913                                           constY, scalarsPerPos);
  1914     } else {
  1915         draw.drawPosText_asPaths((const char*)text, byteLength, pos, constY,
  1916                                  scalarsPerPos, paint);
  1920 void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
  1921                                 size_t len, const SkPath& path,
  1922                                 const SkMatrix* m, const SkPaint& paint) {
  1923     CHECK_SHOULD_DRAW(draw, false);
  1925     SkASSERT(draw.fDevice == this);
  1926     draw.drawTextOnPath((const char*)text, len, path, m, paint);
  1929 ///////////////////////////////////////////////////////////////////////////////
  1931 bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
  1932     if (!paint.isLCDRenderText()) {
  1933         // we're cool with the paint as is
  1934         return false;
  1937     if (paint.getShader() ||
  1938         paint.getXfermode() || // unless its srcover
  1939         paint.getMaskFilter() ||
  1940         paint.getRasterizer() ||
  1941         paint.getColorFilter() ||
  1942         paint.getPathEffect() ||
  1943         paint.isFakeBoldText() ||
  1944         paint.getStyle() != SkPaint::kFill_Style) {
  1945         // turn off lcd
  1946         flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
  1947         flags->fHinting = paint.getHinting();
  1948         return true;
  1950     // we're cool with the paint as is
  1951     return false;
  1954 void SkGpuDevice::flush() {
  1955     DO_DEFERRED_CLEAR();
  1956     fContext->resolveRenderTarget(fRenderTarget);
  1959 ///////////////////////////////////////////////////////////////////////////////
  1961 SkBaseDevice* SkGpuDevice::onCreateDevice(const SkImageInfo& info, Usage usage) {
  1962     GrTextureDesc desc;
  1963     desc.fConfig = fRenderTarget->config();
  1964     desc.fFlags = kRenderTarget_GrTextureFlagBit;
  1965     desc.fWidth = info.width();
  1966     desc.fHeight = info.height();
  1967     desc.fSampleCnt = fRenderTarget->numSamples();
  1969     SkAutoTUnref<GrTexture> texture;
  1970     // Skia's convention is to only clear a device if it is non-opaque.
  1971     bool needClear = !info.isOpaque();
  1973 #if CACHE_COMPATIBLE_DEVICE_TEXTURES
  1974     // layers are never draw in repeat modes, so we can request an approx
  1975     // match and ignore any padding.
  1976     const GrContext::ScratchTexMatch match = (kSaveLayer_Usage == usage) ?
  1977                                                 GrContext::kApprox_ScratchTexMatch :
  1978                                                 GrContext::kExact_ScratchTexMatch;
  1979     texture.reset(fContext->lockAndRefScratchTexture(desc, match));
  1980 #else
  1981     texture.reset(fContext->createUncachedTexture(desc, NULL, 0));
  1982 #endif
  1983     if (NULL != texture.get()) {
  1984         return SkNEW_ARGS(SkGpuDevice,(fContext, texture, needClear));
  1985     } else {
  1986         GrPrintf("---- failed to create compatible device texture [%d %d]\n",
  1987                  info.width(), info.height());
  1988         return NULL;
  1992 SkSurface* SkGpuDevice::newSurface(const SkImageInfo& info) {
  1993     return SkSurface::NewRenderTarget(fContext, info, fRenderTarget->numSamples());
  1996 SkGpuDevice::SkGpuDevice(GrContext* context,
  1997                          GrTexture* texture,
  1998                          bool needClear)
  1999     : SkBitmapDevice(make_bitmap(context, texture->asRenderTarget())) {
  2001     SkASSERT(texture && texture->asRenderTarget());
  2002     // This constructor is called from onCreateDevice. It has locked the RT in the texture
  2003     // cache. We pass true for the third argument so that it will get unlocked.
  2004     this->initFromRenderTarget(context, texture->asRenderTarget(), true);
  2005     fNeedClear = needClear;
  2008 class GPUAccelData : public SkPicture::AccelData {
  2009 public:
  2010     GPUAccelData(Key key) : INHERITED(key) { }
  2012 protected:
  2014 private:
  2015     typedef SkPicture::AccelData INHERITED;
  2016 };
  2018 // In the future this may not be a static method if we need to incorporate the
  2019 // clip and matrix state into the key
  2020 SkPicture::AccelData::Key SkGpuDevice::ComputeAccelDataKey() {
  2021     static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
  2023     return gGPUID;
  2026 void SkGpuDevice::EXPERIMENTAL_optimize(SkPicture* picture) {
  2027     SkPicture::AccelData::Key key = ComputeAccelDataKey();
  2029     GPUAccelData* data = SkNEW_ARGS(GPUAccelData, (key));
  2031     picture->EXPERIMENTAL_addAccelData(data);
  2034 bool SkGpuDevice::EXPERIMENTAL_drawPicture(const SkPicture& picture) {
  2035     SkPicture::AccelData::Key key = ComputeAccelDataKey();
  2037     const SkPicture::AccelData* data = picture.EXPERIMENTAL_getAccelData(key);
  2038     if (NULL == data) {
  2039         return false;
  2042 #if 0
  2043     const GPUAccelData *gpuData = static_cast<const GPUAccelData*>(data);
  2044 #endif
  2046     return false;

mercurial