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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/gpu/SkGpuDevice.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2047 @@
     1.4 +/*
     1.5 + * Copyright 2011 Google Inc.
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +
    1.11 +#include "SkGpuDevice.h"
    1.12 +
    1.13 +#include "effects/GrBicubicEffect.h"
    1.14 +#include "effects/GrTextureDomain.h"
    1.15 +#include "effects/GrSimpleTextureEffect.h"
    1.16 +
    1.17 +#include "GrContext.h"
    1.18 +#include "GrBitmapTextContext.h"
    1.19 +#include "GrDistanceFieldTextContext.h"
    1.20 +
    1.21 +#include "SkGrTexturePixelRef.h"
    1.22 +
    1.23 +#include "SkBounder.h"
    1.24 +#include "SkColorFilter.h"
    1.25 +#include "SkDeviceImageFilterProxy.h"
    1.26 +#include "SkDrawProcs.h"
    1.27 +#include "SkGlyphCache.h"
    1.28 +#include "SkImageFilter.h"
    1.29 +#include "SkMaskFilter.h"
    1.30 +#include "SkPathEffect.h"
    1.31 +#include "SkPicture.h"
    1.32 +#include "SkRRect.h"
    1.33 +#include "SkStroke.h"
    1.34 +#include "SkSurface.h"
    1.35 +#include "SkTLazy.h"
    1.36 +#include "SkUtils.h"
    1.37 +#include "SkErrorInternals.h"
    1.38 +
    1.39 +#define CACHE_COMPATIBLE_DEVICE_TEXTURES 1
    1.40 +
    1.41 +#if 0
    1.42 +    extern bool (*gShouldDrawProc)();
    1.43 +    #define CHECK_SHOULD_DRAW(draw, forceI)                     \
    1.44 +        do {                                                    \
    1.45 +            if (gShouldDrawProc && !gShouldDrawProc()) return;  \
    1.46 +            this->prepareDraw(draw, forceI);                    \
    1.47 +        } while (0)
    1.48 +#else
    1.49 +    #define CHECK_SHOULD_DRAW(draw, forceI) this->prepareDraw(draw, forceI)
    1.50 +#endif
    1.51 +
    1.52 +// This constant represents the screen alignment criterion in texels for
    1.53 +// requiring texture domain clamping to prevent color bleeding when drawing
    1.54 +// a sub region of a larger source image.
    1.55 +#define COLOR_BLEED_TOLERANCE 0.001f
    1.56 +
    1.57 +#define DO_DEFERRED_CLEAR()             \
    1.58 +    do {                                \
    1.59 +        if (fNeedClear) {               \
    1.60 +            this->clear(SK_ColorTRANSPARENT); \
    1.61 +        }                               \
    1.62 +    } while (false)                     \
    1.63 +
    1.64 +///////////////////////////////////////////////////////////////////////////////
    1.65 +
    1.66 +#define CHECK_FOR_ANNOTATION(paint) \
    1.67 +    do { if (paint.getAnnotation()) { return; } } while (0)
    1.68 +
    1.69 +///////////////////////////////////////////////////////////////////////////////
    1.70 +
    1.71 +
    1.72 +class SkGpuDevice::SkAutoCachedTexture : public ::SkNoncopyable {
    1.73 +public:
    1.74 +    SkAutoCachedTexture()
    1.75 +        : fDevice(NULL)
    1.76 +        , fTexture(NULL) {
    1.77 +    }
    1.78 +
    1.79 +    SkAutoCachedTexture(SkGpuDevice* device,
    1.80 +                        const SkBitmap& bitmap,
    1.81 +                        const GrTextureParams* params,
    1.82 +                        GrTexture** texture)
    1.83 +        : fDevice(NULL)
    1.84 +        , fTexture(NULL) {
    1.85 +        SkASSERT(NULL != texture);
    1.86 +        *texture = this->set(device, bitmap, params);
    1.87 +    }
    1.88 +
    1.89 +    ~SkAutoCachedTexture() {
    1.90 +        if (NULL != fTexture) {
    1.91 +            GrUnlockAndUnrefCachedBitmapTexture(fTexture);
    1.92 +        }
    1.93 +    }
    1.94 +
    1.95 +    GrTexture* set(SkGpuDevice* device,
    1.96 +                   const SkBitmap& bitmap,
    1.97 +                   const GrTextureParams* params) {
    1.98 +        if (NULL != fTexture) {
    1.99 +            GrUnlockAndUnrefCachedBitmapTexture(fTexture);
   1.100 +            fTexture = NULL;
   1.101 +        }
   1.102 +        fDevice = device;
   1.103 +        GrTexture* result = (GrTexture*)bitmap.getTexture();
   1.104 +        if (NULL == result) {
   1.105 +            // Cannot return the native texture so look it up in our cache
   1.106 +            fTexture = GrLockAndRefCachedBitmapTexture(device->context(), bitmap, params);
   1.107 +            result = fTexture;
   1.108 +        }
   1.109 +        return result;
   1.110 +    }
   1.111 +
   1.112 +private:
   1.113 +    SkGpuDevice* fDevice;
   1.114 +    GrTexture*   fTexture;
   1.115 +};
   1.116 +
   1.117 +///////////////////////////////////////////////////////////////////////////////
   1.118 +
   1.119 +struct GrSkDrawProcs : public SkDrawProcs {
   1.120 +public:
   1.121 +    GrContext* fContext;
   1.122 +    GrTextContext* fTextContext;
   1.123 +    GrFontScaler* fFontScaler;  // cached in the skia glyphcache
   1.124 +};
   1.125 +
   1.126 +///////////////////////////////////////////////////////////////////////////////
   1.127 +
   1.128 +static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
   1.129 +    switch (config) {
   1.130 +        case kAlpha_8_GrPixelConfig:
   1.131 +            *isOpaque = false;
   1.132 +            return SkBitmap::kA8_Config;
   1.133 +        case kRGB_565_GrPixelConfig:
   1.134 +            *isOpaque = true;
   1.135 +            return SkBitmap::kRGB_565_Config;
   1.136 +        case kRGBA_4444_GrPixelConfig:
   1.137 +            *isOpaque = false;
   1.138 +            return SkBitmap::kARGB_4444_Config;
   1.139 +        case kSkia8888_GrPixelConfig:
   1.140 +            // we don't currently have a way of knowing whether
   1.141 +            // a 8888 is opaque based on the config.
   1.142 +            *isOpaque = false;
   1.143 +            return SkBitmap::kARGB_8888_Config;
   1.144 +        default:
   1.145 +            *isOpaque = false;
   1.146 +            return SkBitmap::kNo_Config;
   1.147 +    }
   1.148 +}
   1.149 +
   1.150 +/*
   1.151 + * GrRenderTarget does not know its opaqueness, only its config, so we have
   1.152 + * to make conservative guesses when we return an "equivalent" bitmap.
   1.153 + */
   1.154 +static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
   1.155 +    bool isOpaque;
   1.156 +    SkBitmap::Config config = grConfig2skConfig(renderTarget->config(), &isOpaque);
   1.157 +
   1.158 +    SkBitmap bitmap;
   1.159 +    bitmap.setConfig(config, renderTarget->width(), renderTarget->height(), 0,
   1.160 +                     isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   1.161 +    return bitmap;
   1.162 +}
   1.163 +
   1.164 +SkGpuDevice* SkGpuDevice::Create(GrSurface* surface) {
   1.165 +    SkASSERT(NULL != surface);
   1.166 +    if (NULL == surface->asRenderTarget() || NULL == surface->getContext()) {
   1.167 +        return NULL;
   1.168 +    }
   1.169 +    if (surface->asTexture()) {
   1.170 +        return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asTexture()));
   1.171 +    } else {
   1.172 +        return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asRenderTarget()));
   1.173 +    }
   1.174 +}
   1.175 +
   1.176 +SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
   1.177 +    : SkBitmapDevice(make_bitmap(context, texture->asRenderTarget())) {
   1.178 +    this->initFromRenderTarget(context, texture->asRenderTarget(), false);
   1.179 +}
   1.180 +
   1.181 +SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
   1.182 +    : SkBitmapDevice(make_bitmap(context, renderTarget)) {
   1.183 +    this->initFromRenderTarget(context, renderTarget, false);
   1.184 +}
   1.185 +
   1.186 +void SkGpuDevice::initFromRenderTarget(GrContext* context,
   1.187 +                                       GrRenderTarget* renderTarget,
   1.188 +                                       bool cached) {
   1.189 +    fDrawProcs = NULL;
   1.190 +
   1.191 +    fContext = context;
   1.192 +    fContext->ref();
   1.193 +
   1.194 +    fMainTextContext = SkNEW_ARGS(GrDistanceFieldTextContext, (fContext, fLeakyProperties));
   1.195 +    fFallbackTextContext = SkNEW_ARGS(GrBitmapTextContext, (fContext, fLeakyProperties));
   1.196 +
   1.197 +    fRenderTarget = NULL;
   1.198 +    fNeedClear = false;
   1.199 +
   1.200 +    SkASSERT(NULL != renderTarget);
   1.201 +    fRenderTarget = renderTarget;
   1.202 +    fRenderTarget->ref();
   1.203 +
   1.204 +    // Hold onto to the texture in the pixel ref (if there is one) because the texture holds a ref
   1.205 +    // on the RT but not vice-versa.
   1.206 +    // TODO: Remove this trickery once we figure out how to make SkGrPixelRef do this without
   1.207 +    // busting chrome (for a currently unknown reason).
   1.208 +    GrSurface* surface = fRenderTarget->asTexture();
   1.209 +    if (NULL == surface) {
   1.210 +        surface = fRenderTarget;
   1.211 +    }
   1.212 +
   1.213 +    SkImageInfo info;
   1.214 +    surface->asImageInfo(&info);
   1.215 +    SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, surface, cached));
   1.216 +
   1.217 +    this->setPixelRef(pr)->unref();
   1.218 +}
   1.219 +
   1.220 +SkGpuDevice* SkGpuDevice::Create(GrContext* context, const SkImageInfo& origInfo,
   1.221 +                                 int sampleCount) {
   1.222 +    if (kUnknown_SkColorType == origInfo.colorType() ||
   1.223 +        origInfo.width() < 0 || origInfo.height() < 0) {
   1.224 +        return NULL;
   1.225 +    }
   1.226 +
   1.227 +    SkImageInfo info = origInfo;
   1.228 +    // TODO: perhas we can loosen this check now that colortype is more detailed
   1.229 +    // e.g. can we support both RGBA and BGRA here?
   1.230 +    if (kRGB_565_SkColorType == info.colorType()) {
   1.231 +        info.fAlphaType = kOpaque_SkAlphaType;  // force this setting
   1.232 +    } else {
   1.233 +        info.fColorType = kPMColor_SkColorType;
   1.234 +        if (kOpaque_SkAlphaType != info.alphaType()) {
   1.235 +            info.fAlphaType = kPremul_SkAlphaType;  // force this setting
   1.236 +        }
   1.237 +    }
   1.238 +
   1.239 +    GrTextureDesc desc;
   1.240 +    desc.fFlags = kRenderTarget_GrTextureFlagBit;
   1.241 +    desc.fWidth = info.width();
   1.242 +    desc.fHeight = info.height();
   1.243 +    desc.fConfig = SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType());
   1.244 +    desc.fSampleCnt = sampleCount;
   1.245 +
   1.246 +    SkAutoTUnref<GrTexture> texture(context->createUncachedTexture(desc, NULL, 0));
   1.247 +    if (!texture.get()) {
   1.248 +        return NULL;
   1.249 +    }
   1.250 +
   1.251 +    return SkNEW_ARGS(SkGpuDevice, (context, texture.get()));
   1.252 +}
   1.253 +
   1.254 +#ifdef SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG
   1.255 +static SkBitmap make_bitmap(SkBitmap::Config config, int width, int height) {
   1.256 +    SkBitmap bm;
   1.257 +    bm.setConfig(SkImageInfo::Make(width, height,
   1.258 +                                   SkBitmapConfigToColorType(config),
   1.259 +                                   kPremul_SkAlphaType));
   1.260 +    return bm;
   1.261 +}
   1.262 +SkGpuDevice::SkGpuDevice(GrContext* context,
   1.263 +                         SkBitmap::Config config,
   1.264 +                         int width,
   1.265 +                         int height,
   1.266 +                         int sampleCount)
   1.267 +    : SkBitmapDevice(make_bitmap(config, width, height))
   1.268 +{
   1.269 +    fDrawProcs = NULL;
   1.270 +
   1.271 +    fContext = context;
   1.272 +    fContext->ref();
   1.273 +
   1.274 +    fMainTextContext = SkNEW_ARGS(GrDistanceFieldTextContext, (fContext, fLeakyProperties));
   1.275 +    fFallbackTextContext = SkNEW_ARGS(GrBitmapTextContext, (fContext, fLeakyProperties));
   1.276 +
   1.277 +    fRenderTarget = NULL;
   1.278 +    fNeedClear = false;
   1.279 +
   1.280 +    if (config != SkBitmap::kRGB_565_Config) {
   1.281 +        config = SkBitmap::kARGB_8888_Config;
   1.282 +    }
   1.283 +
   1.284 +    GrTextureDesc desc;
   1.285 +    desc.fFlags = kRenderTarget_GrTextureFlagBit;
   1.286 +    desc.fWidth = width;
   1.287 +    desc.fHeight = height;
   1.288 +    desc.fConfig = SkBitmapConfig2GrPixelConfig(config);
   1.289 +    desc.fSampleCnt = sampleCount;
   1.290 +
   1.291 +    SkImageInfo info;
   1.292 +    if (!GrPixelConfig2ColorType(desc.fConfig, &info.fColorType)) {
   1.293 +        sk_throw();
   1.294 +    }
   1.295 +    info.fWidth = width;
   1.296 +    info.fHeight = height;
   1.297 +    info.fAlphaType = kPremul_SkAlphaType;
   1.298 +
   1.299 +    SkAutoTUnref<GrTexture> texture(fContext->createUncachedTexture(desc, NULL, 0));
   1.300 +
   1.301 +    if (NULL != texture) {
   1.302 +        fRenderTarget = texture->asRenderTarget();
   1.303 +        fRenderTarget->ref();
   1.304 +
   1.305 +        SkASSERT(NULL != fRenderTarget);
   1.306 +
   1.307 +        // wrap the bitmap with a pixelref to expose our texture
   1.308 +        SkGrPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, texture));
   1.309 +        this->setPixelRef(pr)->unref();
   1.310 +    } else {
   1.311 +        GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
   1.312 +                 width, height);
   1.313 +        SkASSERT(false);
   1.314 +    }
   1.315 +}
   1.316 +#endif
   1.317 +
   1.318 +SkGpuDevice::~SkGpuDevice() {
   1.319 +    if (fDrawProcs) {
   1.320 +        delete fDrawProcs;
   1.321 +    }
   1.322 +
   1.323 +    delete fMainTextContext;
   1.324 +    delete fFallbackTextContext;
   1.325 +
   1.326 +    // The GrContext takes a ref on the target. We don't want to cause the render
   1.327 +    // target to be unnecessarily kept alive.
   1.328 +    if (fContext->getRenderTarget() == fRenderTarget) {
   1.329 +        fContext->setRenderTarget(NULL);
   1.330 +    }
   1.331 +
   1.332 +    if (fContext->getClip() == &fClipData) {
   1.333 +        fContext->setClip(NULL);
   1.334 +    }
   1.335 +
   1.336 +    SkSafeUnref(fRenderTarget);
   1.337 +    fContext->unref();
   1.338 +}
   1.339 +
   1.340 +///////////////////////////////////////////////////////////////////////////////
   1.341 +
   1.342 +void SkGpuDevice::makeRenderTargetCurrent() {
   1.343 +    DO_DEFERRED_CLEAR();
   1.344 +    fContext->setRenderTarget(fRenderTarget);
   1.345 +}
   1.346 +
   1.347 +///////////////////////////////////////////////////////////////////////////////
   1.348 +
   1.349 +namespace {
   1.350 +GrPixelConfig config8888_to_grconfig_and_flags(SkCanvas::Config8888 config8888, uint32_t* flags) {
   1.351 +    switch (config8888) {
   1.352 +        case SkCanvas::kNative_Premul_Config8888:
   1.353 +            *flags = 0;
   1.354 +            return kSkia8888_GrPixelConfig;
   1.355 +        case SkCanvas::kNative_Unpremul_Config8888:
   1.356 +            *flags = GrContext::kUnpremul_PixelOpsFlag;
   1.357 +            return kSkia8888_GrPixelConfig;
   1.358 +        case SkCanvas::kBGRA_Premul_Config8888:
   1.359 +            *flags = 0;
   1.360 +            return kBGRA_8888_GrPixelConfig;
   1.361 +        case SkCanvas::kBGRA_Unpremul_Config8888:
   1.362 +            *flags = GrContext::kUnpremul_PixelOpsFlag;
   1.363 +            return kBGRA_8888_GrPixelConfig;
   1.364 +        case SkCanvas::kRGBA_Premul_Config8888:
   1.365 +            *flags = 0;
   1.366 +            return kRGBA_8888_GrPixelConfig;
   1.367 +        case SkCanvas::kRGBA_Unpremul_Config8888:
   1.368 +            *flags = GrContext::kUnpremul_PixelOpsFlag;
   1.369 +            return kRGBA_8888_GrPixelConfig;
   1.370 +        default:
   1.371 +            GrCrash("Unexpected Config8888.");
   1.372 +            *flags = 0; // suppress warning
   1.373 +            return kSkia8888_GrPixelConfig;
   1.374 +    }
   1.375 +}
   1.376 +}
   1.377 +
   1.378 +bool SkGpuDevice::onReadPixels(const SkBitmap& bitmap,
   1.379 +                               int x, int y,
   1.380 +                               SkCanvas::Config8888 config8888) {
   1.381 +    DO_DEFERRED_CLEAR();
   1.382 +    SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
   1.383 +    SkASSERT(!bitmap.isNull());
   1.384 +    SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
   1.385 +
   1.386 +    SkAutoLockPixels alp(bitmap);
   1.387 +    GrPixelConfig config;
   1.388 +    uint32_t flags;
   1.389 +    config = config8888_to_grconfig_and_flags(config8888, &flags);
   1.390 +    return fContext->readRenderTargetPixels(fRenderTarget,
   1.391 +                                            x, y,
   1.392 +                                            bitmap.width(),
   1.393 +                                            bitmap.height(),
   1.394 +                                            config,
   1.395 +                                            bitmap.getPixels(),
   1.396 +                                            bitmap.rowBytes(),
   1.397 +                                            flags);
   1.398 +}
   1.399 +
   1.400 +#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
   1.401 +void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y,
   1.402 +                              SkCanvas::Config8888 config8888) {
   1.403 +    SkAutoLockPixels alp(bitmap);
   1.404 +    if (!bitmap.readyToDraw()) {
   1.405 +        return;
   1.406 +    }
   1.407 +
   1.408 +    GrPixelConfig config;
   1.409 +    uint32_t flags;
   1.410 +    if (SkBitmap::kARGB_8888_Config == bitmap.config()) {
   1.411 +        config = config8888_to_grconfig_and_flags(config8888, &flags);
   1.412 +    } else {
   1.413 +        flags = 0;
   1.414 +        config= SkBitmapConfig2GrPixelConfig(bitmap.config());
   1.415 +    }
   1.416 +
   1.417 +    fRenderTarget->writePixels(x, y, bitmap.width(), bitmap.height(),
   1.418 +                               config, bitmap.getPixels(), bitmap.rowBytes(), flags);
   1.419 +}
   1.420 +#endif
   1.421 +
   1.422 +bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
   1.423 +                                int x, int y) {
   1.424 +    // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
   1.425 +    GrPixelConfig config = SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType());
   1.426 +    if (kUnknown_GrPixelConfig == config) {
   1.427 +        return false;
   1.428 +    }
   1.429 +    uint32_t flags = 0;
   1.430 +    if (kUnpremul_SkAlphaType == info.alphaType()) {
   1.431 +        flags = GrContext::kUnpremul_PixelOpsFlag;
   1.432 +    }
   1.433 +    fRenderTarget->writePixels(x, y, info.width(), info.height(), config, pixels, rowBytes, flags);
   1.434 +
   1.435 +    // need to bump our genID for compatibility with clients that "know" we have a bitmap
   1.436 +    this->onAccessBitmap().notifyPixelsChanged();
   1.437 +
   1.438 +    return true;
   1.439 +}
   1.440 +
   1.441 +void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) {
   1.442 +    INHERITED::onAttachToCanvas(canvas);
   1.443 +
   1.444 +    // Canvas promises that this ptr is valid until onDetachFromCanvas is called
   1.445 +    fClipData.fClipStack = canvas->getClipStack();
   1.446 +}
   1.447 +
   1.448 +void SkGpuDevice::onDetachFromCanvas() {
   1.449 +    INHERITED::onDetachFromCanvas();
   1.450 +    fClipData.fClipStack = NULL;
   1.451 +}
   1.452 +
   1.453 +// call this every draw call, to ensure that the context reflects our state,
   1.454 +// and not the state from some other canvas/device
   1.455 +void SkGpuDevice::prepareDraw(const SkDraw& draw, bool forceIdentity) {
   1.456 +    SkASSERT(NULL != fClipData.fClipStack);
   1.457 +
   1.458 +    fContext->setRenderTarget(fRenderTarget);
   1.459 +
   1.460 +    SkASSERT(draw.fClipStack && draw.fClipStack == fClipData.fClipStack);
   1.461 +
   1.462 +    if (forceIdentity) {
   1.463 +        fContext->setIdentityMatrix();
   1.464 +    } else {
   1.465 +        fContext->setMatrix(*draw.fMatrix);
   1.466 +    }
   1.467 +    fClipData.fOrigin = this->getOrigin();
   1.468 +
   1.469 +    fContext->setClip(&fClipData);
   1.470 +
   1.471 +    DO_DEFERRED_CLEAR();
   1.472 +}
   1.473 +
   1.474 +GrRenderTarget* SkGpuDevice::accessRenderTarget() {
   1.475 +    DO_DEFERRED_CLEAR();
   1.476 +    return fRenderTarget;
   1.477 +}
   1.478 +
   1.479 +///////////////////////////////////////////////////////////////////////////////
   1.480 +
   1.481 +SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
   1.482 +SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
   1.483 +SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
   1.484 +SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
   1.485 +SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
   1.486 +                  shader_type_mismatch);
   1.487 +SK_COMPILE_ASSERT(SkShader::kTwoPointConical_BitmapType == 5,
   1.488 +                  shader_type_mismatch);
   1.489 +SK_COMPILE_ASSERT(SkShader::kLinear_BitmapType == 6, shader_type_mismatch);
   1.490 +SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 6, shader_type_mismatch);
   1.491 +
   1.492 +namespace {
   1.493 +
   1.494 +// converts a SkPaint to a GrPaint, ignoring the skPaint's shader
   1.495 +// justAlpha indicates that skPaint's alpha should be used rather than the color
   1.496 +// Callers may subsequently modify the GrPaint. Setting constantColor indicates
   1.497 +// that the final paint will draw the same color at every pixel. This allows
   1.498 +// an optimization where the the color filter can be applied to the skPaint's
   1.499 +// color once while converting to GrPaint and then ignored.
   1.500 +inline bool skPaint2GrPaintNoShader(SkGpuDevice* dev,
   1.501 +                                    const SkPaint& skPaint,
   1.502 +                                    bool justAlpha,
   1.503 +                                    bool constantColor,
   1.504 +                                    GrPaint* grPaint) {
   1.505 +
   1.506 +    grPaint->setDither(skPaint.isDither());
   1.507 +    grPaint->setAntiAlias(skPaint.isAntiAlias());
   1.508 +
   1.509 +    SkXfermode::Coeff sm;
   1.510 +    SkXfermode::Coeff dm;
   1.511 +
   1.512 +    SkXfermode* mode = skPaint.getXfermode();
   1.513 +    GrEffectRef* xferEffect = NULL;
   1.514 +    if (SkXfermode::AsNewEffectOrCoeff(mode, &xferEffect, &sm, &dm)) {
   1.515 +        if (NULL != xferEffect) {
   1.516 +            grPaint->addColorEffect(xferEffect)->unref();
   1.517 +            sm = SkXfermode::kOne_Coeff;
   1.518 +            dm = SkXfermode::kZero_Coeff;
   1.519 +        }
   1.520 +    } else {
   1.521 +        //SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
   1.522 +#if 0
   1.523 +        return false;
   1.524 +#else
   1.525 +        // Fall back to src-over
   1.526 +        sm = SkXfermode::kOne_Coeff;
   1.527 +        dm = SkXfermode::kISA_Coeff;
   1.528 +#endif
   1.529 +    }
   1.530 +    grPaint->setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm));
   1.531 +
   1.532 +    if (justAlpha) {
   1.533 +        uint8_t alpha = skPaint.getAlpha();
   1.534 +        grPaint->setColor(GrColorPackRGBA(alpha, alpha, alpha, alpha));
   1.535 +        // justAlpha is currently set to true only if there is a texture,
   1.536 +        // so constantColor should not also be true.
   1.537 +        SkASSERT(!constantColor);
   1.538 +    } else {
   1.539 +        grPaint->setColor(SkColor2GrColor(skPaint.getColor()));
   1.540 +    }
   1.541 +
   1.542 +    SkColorFilter* colorFilter = skPaint.getColorFilter();
   1.543 +    if (NULL != colorFilter) {
   1.544 +        // if the source color is a constant then apply the filter here once rather than per pixel
   1.545 +        // in a shader.
   1.546 +        if (constantColor) {
   1.547 +            SkColor filtered = colorFilter->filterColor(skPaint.getColor());
   1.548 +            grPaint->setColor(SkColor2GrColor(filtered));
   1.549 +        } else {
   1.550 +            SkAutoTUnref<GrEffectRef> effect(colorFilter->asNewEffect(dev->context()));
   1.551 +            if (NULL != effect.get()) {
   1.552 +                grPaint->addColorEffect(effect);
   1.553 +            }
   1.554 +        }
   1.555 +    }
   1.556 +
   1.557 +    return true;
   1.558 +}
   1.559 +
   1.560 +// This function is similar to skPaint2GrPaintNoShader but also converts
   1.561 +// skPaint's shader to a GrTexture/GrEffectStage if possible. The texture to
   1.562 +// be used is set on grPaint and returned in param act. constantColor has the
   1.563 +// same meaning as in skPaint2GrPaintNoShader.
   1.564 +inline bool skPaint2GrPaintShader(SkGpuDevice* dev,
   1.565 +                                  const SkPaint& skPaint,
   1.566 +                                  bool constantColor,
   1.567 +                                  GrPaint* grPaint) {
   1.568 +    SkShader* shader = skPaint.getShader();
   1.569 +    if (NULL == shader) {
   1.570 +        return skPaint2GrPaintNoShader(dev, skPaint, false, constantColor, grPaint);
   1.571 +    }
   1.572 +
   1.573 +    // SkShader::asNewEffect() may do offscreen rendering. Setup default drawing state and require
   1.574 +    // the shader to set a render target .
   1.575 +    GrContext::AutoWideOpenIdentityDraw awo(dev->context(), NULL);
   1.576 +
   1.577 +    // setup the shader as the first color effect on the paint
   1.578 +    SkAutoTUnref<GrEffectRef> effect(shader->asNewEffect(dev->context(), skPaint));
   1.579 +    if (NULL != effect.get()) {
   1.580 +        grPaint->addColorEffect(effect);
   1.581 +        // Now setup the rest of the paint.
   1.582 +        return skPaint2GrPaintNoShader(dev, skPaint, true, false, grPaint);
   1.583 +    } else {
   1.584 +        // We still don't have SkColorShader::asNewEffect() implemented.
   1.585 +        SkShader::GradientInfo info;
   1.586 +        SkColor                color;
   1.587 +
   1.588 +        info.fColors = &color;
   1.589 +        info.fColorOffsets = NULL;
   1.590 +        info.fColorCount = 1;
   1.591 +        if (SkShader::kColor_GradientType == shader->asAGradient(&info)) {
   1.592 +            SkPaint copy(skPaint);
   1.593 +            copy.setShader(NULL);
   1.594 +            // modulate the paint alpha by the shader's solid color alpha
   1.595 +            U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
   1.596 +            copy.setColor(SkColorSetA(color, newA));
   1.597 +            return skPaint2GrPaintNoShader(dev, copy, false, constantColor, grPaint);
   1.598 +        } else {
   1.599 +            return false;
   1.600 +        }
   1.601 +    }
   1.602 +}
   1.603 +}
   1.604 +
   1.605 +///////////////////////////////////////////////////////////////////////////////
   1.606 +
   1.607 +SkBitmap::Config SkGpuDevice::config() const {
   1.608 +    if (NULL == fRenderTarget) {
   1.609 +        return SkBitmap::kNo_Config;
   1.610 +    }
   1.611 +
   1.612 +    bool isOpaque;
   1.613 +    return grConfig2skConfig(fRenderTarget->config(), &isOpaque);
   1.614 +}
   1.615 +
   1.616 +void SkGpuDevice::clear(SkColor color) {
   1.617 +    SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
   1.618 +    fContext->clear(&rect, SkColor2GrColor(color), true, fRenderTarget);
   1.619 +    fNeedClear = false;
   1.620 +}
   1.621 +
   1.622 +void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
   1.623 +    CHECK_SHOULD_DRAW(draw, false);
   1.624 +
   1.625 +    GrPaint grPaint;
   1.626 +    if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   1.627 +        return;
   1.628 +    }
   1.629 +
   1.630 +    fContext->drawPaint(grPaint);
   1.631 +}
   1.632 +
   1.633 +// must be in SkCanvas::PointMode order
   1.634 +static const GrPrimitiveType gPointMode2PrimtiveType[] = {
   1.635 +    kPoints_GrPrimitiveType,
   1.636 +    kLines_GrPrimitiveType,
   1.637 +    kLineStrip_GrPrimitiveType
   1.638 +};
   1.639 +
   1.640 +void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
   1.641 +                             size_t count, const SkPoint pts[], const SkPaint& paint) {
   1.642 +    CHECK_FOR_ANNOTATION(paint);
   1.643 +    CHECK_SHOULD_DRAW(draw, false);
   1.644 +
   1.645 +    SkScalar width = paint.getStrokeWidth();
   1.646 +    if (width < 0) {
   1.647 +        return;
   1.648 +    }
   1.649 +
   1.650 +    // we only handle hairlines and paints without path effects or mask filters,
   1.651 +    // else we let the SkDraw call our drawPath()
   1.652 +    if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) {
   1.653 +        draw.drawPoints(mode, count, pts, paint, true);
   1.654 +        return;
   1.655 +    }
   1.656 +
   1.657 +    GrPaint grPaint;
   1.658 +    if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   1.659 +        return;
   1.660 +    }
   1.661 +
   1.662 +    fContext->drawVertices(grPaint,
   1.663 +                           gPointMode2PrimtiveType[mode],
   1.664 +                           SkToS32(count),
   1.665 +                           (GrPoint*)pts,
   1.666 +                           NULL,
   1.667 +                           NULL,
   1.668 +                           NULL,
   1.669 +                           0);
   1.670 +}
   1.671 +
   1.672 +///////////////////////////////////////////////////////////////////////////////
   1.673 +
   1.674 +void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
   1.675 +                           const SkPaint& paint) {
   1.676 +    CHECK_FOR_ANNOTATION(paint);
   1.677 +    CHECK_SHOULD_DRAW(draw, false);
   1.678 +
   1.679 +    bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
   1.680 +    SkScalar width = paint.getStrokeWidth();
   1.681 +
   1.682 +    /*
   1.683 +        We have special code for hairline strokes, miter-strokes, bevel-stroke
   1.684 +        and fills. Anything else we just call our path code.
   1.685 +     */
   1.686 +    bool usePath = doStroke && width > 0 &&
   1.687 +                   (paint.getStrokeJoin() == SkPaint::kRound_Join ||
   1.688 +                    (paint.getStrokeJoin() == SkPaint::kBevel_Join && rect.isEmpty()));
   1.689 +    // another two reasons we might need to call drawPath...
   1.690 +    if (paint.getMaskFilter() || paint.getPathEffect()) {
   1.691 +        usePath = true;
   1.692 +    }
   1.693 +    if (!usePath && paint.isAntiAlias() && !fContext->getMatrix().rectStaysRect()) {
   1.694 +#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
   1.695 +        if (doStroke) {
   1.696 +#endif
   1.697 +            usePath = true;
   1.698 +#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
   1.699 +        } else {
   1.700 +            usePath = !fContext->getMatrix().preservesRightAngles();
   1.701 +        }
   1.702 +#endif
   1.703 +    }
   1.704 +    // until we can both stroke and fill rectangles
   1.705 +    if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) {
   1.706 +        usePath = true;
   1.707 +    }
   1.708 +
   1.709 +    if (usePath) {
   1.710 +        SkPath path;
   1.711 +        path.addRect(rect);
   1.712 +        this->drawPath(draw, path, paint, NULL, true);
   1.713 +        return;
   1.714 +    }
   1.715 +
   1.716 +    GrPaint grPaint;
   1.717 +    if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   1.718 +        return;
   1.719 +    }
   1.720 +
   1.721 +    if (!doStroke) {
   1.722 +        fContext->drawRect(grPaint, rect);
   1.723 +    } else {
   1.724 +        SkStrokeRec stroke(paint);
   1.725 +        fContext->drawRect(grPaint, rect, &stroke);
   1.726 +    }
   1.727 +}
   1.728 +
   1.729 +///////////////////////////////////////////////////////////////////////////////
   1.730 +
   1.731 +void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
   1.732 +                           const SkPaint& paint) {
   1.733 +    CHECK_FOR_ANNOTATION(paint);
   1.734 +    CHECK_SHOULD_DRAW(draw, false);
   1.735 +
   1.736 +    GrPaint grPaint;
   1.737 +    if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   1.738 +        return;
   1.739 +    }
   1.740 +
   1.741 +    SkStrokeRec stroke(paint);
   1.742 +    if (paint.getMaskFilter()) {
   1.743 +        // try to hit the fast path for drawing filtered round rects
   1.744 +
   1.745 +        SkRRect devRRect;
   1.746 +        if (rect.transform(fContext->getMatrix(), &devRRect)) {
   1.747 +            if (devRRect.allCornersCircular()) {
   1.748 +                SkRect maskRect;
   1.749 +                if (paint.getMaskFilter()->canFilterMaskGPU(devRRect.rect(),
   1.750 +                                            draw.fClip->getBounds(),
   1.751 +                                            fContext->getMatrix(),
   1.752 +                                            &maskRect)) {
   1.753 +                    SkIRect finalIRect;
   1.754 +                    maskRect.roundOut(&finalIRect);
   1.755 +                    if (draw.fClip->quickReject(finalIRect)) {
   1.756 +                        // clipped out
   1.757 +                        return;
   1.758 +                    }
   1.759 +                    if (NULL != draw.fBounder && !draw.fBounder->doIRect(finalIRect)) {
   1.760 +                        // nothing to draw
   1.761 +                        return;
   1.762 +                    }
   1.763 +                    if (paint.getMaskFilter()->directFilterRRectMaskGPU(fContext, &grPaint,
   1.764 +                                                                        stroke, devRRect)) {
   1.765 +                        return;
   1.766 +                    }
   1.767 +                }
   1.768 +
   1.769 +            }
   1.770 +        }
   1.771 +
   1.772 +    }
   1.773 +
   1.774 +    bool usePath = !rect.isSimple();
   1.775 +    // another two reasons we might need to call drawPath...
   1.776 +    if (paint.getMaskFilter() || paint.getPathEffect()) {
   1.777 +        usePath = true;
   1.778 +    }
   1.779 +    // until we can rotate rrects...
   1.780 +    if (!usePath && !fContext->getMatrix().rectStaysRect()) {
   1.781 +        usePath = true;
   1.782 +    }
   1.783 +
   1.784 +    if (usePath) {
   1.785 +        SkPath path;
   1.786 +        path.addRRect(rect);
   1.787 +        this->drawPath(draw, path, paint, NULL, true);
   1.788 +        return;
   1.789 +    }
   1.790 +
   1.791 +    fContext->drawRRect(grPaint, rect, stroke);
   1.792 +}
   1.793 +
   1.794 +/////////////////////////////////////////////////////////////////////////////
   1.795 +
   1.796 +void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval,
   1.797 +                           const SkPaint& paint) {
   1.798 +    CHECK_FOR_ANNOTATION(paint);
   1.799 +    CHECK_SHOULD_DRAW(draw, false);
   1.800 +
   1.801 +    bool usePath = false;
   1.802 +    // some basic reasons we might need to call drawPath...
   1.803 +    if (paint.getMaskFilter() || paint.getPathEffect()) {
   1.804 +        usePath = true;
   1.805 +    }
   1.806 +
   1.807 +    if (usePath) {
   1.808 +        SkPath path;
   1.809 +        path.addOval(oval);
   1.810 +        this->drawPath(draw, path, paint, NULL, true);
   1.811 +        return;
   1.812 +    }
   1.813 +
   1.814 +    GrPaint grPaint;
   1.815 +    if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   1.816 +        return;
   1.817 +    }
   1.818 +    SkStrokeRec stroke(paint);
   1.819 +
   1.820 +    fContext->drawOval(grPaint, oval, stroke);
   1.821 +}
   1.822 +
   1.823 +#include "SkMaskFilter.h"
   1.824 +#include "SkBounder.h"
   1.825 +
   1.826 +///////////////////////////////////////////////////////////////////////////////
   1.827 +
   1.828 +// helpers for applying mask filters
   1.829 +namespace {
   1.830 +
   1.831 +// Draw a mask using the supplied paint. Since the coverage/geometry
   1.832 +// is already burnt into the mask this boils down to a rect draw.
   1.833 +// Return true if the mask was successfully drawn.
   1.834 +bool draw_mask(GrContext* context, const SkRect& maskRect,
   1.835 +               GrPaint* grp, GrTexture* mask) {
   1.836 +    GrContext::AutoMatrix am;
   1.837 +    if (!am.setIdentity(context, grp)) {
   1.838 +        return false;
   1.839 +    }
   1.840 +
   1.841 +    SkMatrix matrix;
   1.842 +    matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop);
   1.843 +    matrix.postIDiv(mask->width(), mask->height());
   1.844 +
   1.845 +    grp->addCoverageEffect(GrSimpleTextureEffect::Create(mask, matrix))->unref();
   1.846 +    context->drawRect(*grp, maskRect);
   1.847 +    return true;
   1.848 +}
   1.849 +
   1.850 +bool draw_with_mask_filter(GrContext* context, const SkPath& devPath,
   1.851 +                           SkMaskFilter* filter, const SkRegion& clip, SkBounder* bounder,
   1.852 +                           GrPaint* grp, SkPaint::Style style) {
   1.853 +    SkMask  srcM, dstM;
   1.854 +
   1.855 +    if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), filter, &context->getMatrix(), &srcM,
   1.856 +                            SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) {
   1.857 +        return false;
   1.858 +    }
   1.859 +    SkAutoMaskFreeImage autoSrc(srcM.fImage);
   1.860 +
   1.861 +    if (!filter->filterMask(&dstM, srcM, context->getMatrix(), NULL)) {
   1.862 +        return false;
   1.863 +    }
   1.864 +    // this will free-up dstM when we're done (allocated in filterMask())
   1.865 +    SkAutoMaskFreeImage autoDst(dstM.fImage);
   1.866 +
   1.867 +    if (clip.quickReject(dstM.fBounds)) {
   1.868 +        return false;
   1.869 +    }
   1.870 +    if (bounder && !bounder->doIRect(dstM.fBounds)) {
   1.871 +        return false;
   1.872 +    }
   1.873 +
   1.874 +    // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
   1.875 +    // the current clip (and identity matrix) and GrPaint settings
   1.876 +    GrTextureDesc desc;
   1.877 +    desc.fWidth = dstM.fBounds.width();
   1.878 +    desc.fHeight = dstM.fBounds.height();
   1.879 +    desc.fConfig = kAlpha_8_GrPixelConfig;
   1.880 +
   1.881 +    GrAutoScratchTexture ast(context, desc);
   1.882 +    GrTexture* texture = ast.texture();
   1.883 +
   1.884 +    if (NULL == texture) {
   1.885 +        return false;
   1.886 +    }
   1.887 +    texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
   1.888 +                               dstM.fImage, dstM.fRowBytes);
   1.889 +
   1.890 +    SkRect maskRect = SkRect::Make(dstM.fBounds);
   1.891 +
   1.892 +    return draw_mask(context, maskRect, grp, texture);
   1.893 +}
   1.894 +
   1.895 +// Create a mask of 'devPath' and place the result in 'mask'. Return true on
   1.896 +// success; false otherwise.
   1.897 +bool create_mask_GPU(GrContext* context,
   1.898 +                     const SkRect& maskRect,
   1.899 +                     const SkPath& devPath,
   1.900 +                     const SkStrokeRec& stroke,
   1.901 +                     bool doAA,
   1.902 +                     GrAutoScratchTexture* mask) {
   1.903 +    GrTextureDesc desc;
   1.904 +    desc.fFlags = kRenderTarget_GrTextureFlagBit;
   1.905 +    desc.fWidth = SkScalarCeilToInt(maskRect.width());
   1.906 +    desc.fHeight = SkScalarCeilToInt(maskRect.height());
   1.907 +    // We actually only need A8, but it often isn't supported as a
   1.908 +    // render target so default to RGBA_8888
   1.909 +    desc.fConfig = kRGBA_8888_GrPixelConfig;
   1.910 +    if (context->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
   1.911 +        desc.fConfig = kAlpha_8_GrPixelConfig;
   1.912 +    }
   1.913 +
   1.914 +    mask->set(context, desc);
   1.915 +    if (NULL == mask->texture()) {
   1.916 +        return false;
   1.917 +    }
   1.918 +
   1.919 +    GrTexture* maskTexture = mask->texture();
   1.920 +    SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
   1.921 +
   1.922 +    GrContext::AutoRenderTarget art(context, maskTexture->asRenderTarget());
   1.923 +    GrContext::AutoClip ac(context, clipRect);
   1.924 +
   1.925 +    context->clear(NULL, 0x0, true);
   1.926 +
   1.927 +    GrPaint tempPaint;
   1.928 +    if (doAA) {
   1.929 +        tempPaint.setAntiAlias(true);
   1.930 +        // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst
   1.931 +        // blend coeff of zero requires dual source blending support in order
   1.932 +        // to properly blend partially covered pixels. This means the AA
   1.933 +        // code path may not be taken. So we use a dst blend coeff of ISA. We
   1.934 +        // could special case AA draws to a dst surface with known alpha=0 to
   1.935 +        // use a zero dst coeff when dual source blending isn't available.
   1.936 +        tempPaint.setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
   1.937 +    }
   1.938 +
   1.939 +    GrContext::AutoMatrix am;
   1.940 +
   1.941 +    // Draw the mask into maskTexture with the path's top-left at the origin using tempPaint.
   1.942 +    SkMatrix translate;
   1.943 +    translate.setTranslate(-maskRect.fLeft, -maskRect.fTop);
   1.944 +    am.set(context, translate);
   1.945 +    context->drawPath(tempPaint, devPath, stroke);
   1.946 +    return true;
   1.947 +}
   1.948 +
   1.949 +SkBitmap wrap_texture(GrTexture* texture) {
   1.950 +    SkImageInfo info;
   1.951 +    texture->asImageInfo(&info);
   1.952 +
   1.953 +    SkBitmap result;
   1.954 +    result.setConfig(info);
   1.955 +    result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
   1.956 +    return result;
   1.957 +}
   1.958 +
   1.959 +};
   1.960 +
   1.961 +void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
   1.962 +                           const SkPaint& paint, const SkMatrix* prePathMatrix,
   1.963 +                           bool pathIsMutable) {
   1.964 +    CHECK_FOR_ANNOTATION(paint);
   1.965 +    CHECK_SHOULD_DRAW(draw, false);
   1.966 +
   1.967 +    GrPaint grPaint;
   1.968 +    if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
   1.969 +        return;
   1.970 +    }
   1.971 +
   1.972 +    // If we have a prematrix, apply it to the path, optimizing for the case
   1.973 +    // where the original path can in fact be modified in place (even though
   1.974 +    // its parameter type is const).
   1.975 +    SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
   1.976 +    SkTLazy<SkPath> tmpPath;
   1.977 +    SkTLazy<SkPath> effectPath;
   1.978 +
   1.979 +    if (prePathMatrix) {
   1.980 +        SkPath* result = pathPtr;
   1.981 +
   1.982 +        if (!pathIsMutable) {
   1.983 +            result = tmpPath.init();
   1.984 +            pathIsMutable = true;
   1.985 +        }
   1.986 +        // should I push prePathMatrix on our MV stack temporarily, instead
   1.987 +        // of applying it here? See SkDraw.cpp
   1.988 +        pathPtr->transform(*prePathMatrix, result);
   1.989 +        pathPtr = result;
   1.990 +    }
   1.991 +    // at this point we're done with prePathMatrix
   1.992 +    SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
   1.993 +
   1.994 +    SkStrokeRec stroke(paint);
   1.995 +    SkPathEffect* pathEffect = paint.getPathEffect();
   1.996 +    const SkRect* cullRect = NULL;  // TODO: what is our bounds?
   1.997 +    if (pathEffect && pathEffect->filterPath(effectPath.init(), *pathPtr, &stroke,
   1.998 +                                             cullRect)) {
   1.999 +        pathPtr = effectPath.get();
  1.1000 +        pathIsMutable = true;
  1.1001 +    }
  1.1002 +
  1.1003 +    if (paint.getMaskFilter()) {
  1.1004 +        if (!stroke.isHairlineStyle()) {
  1.1005 +            SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init();
  1.1006 +            if (stroke.applyToPath(strokedPath, *pathPtr)) {
  1.1007 +                pathPtr = strokedPath;
  1.1008 +                pathIsMutable = true;
  1.1009 +                stroke.setFillStyle();
  1.1010 +            }
  1.1011 +        }
  1.1012 +
  1.1013 +        // avoid possibly allocating a new path in transform if we can
  1.1014 +        SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init();
  1.1015 +
  1.1016 +        // transform the path into device space
  1.1017 +        pathPtr->transform(fContext->getMatrix(), devPathPtr);
  1.1018 +
  1.1019 +        SkRect maskRect;
  1.1020 +        if (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(),
  1.1021 +                                                    draw.fClip->getBounds(),
  1.1022 +                                                    fContext->getMatrix(),
  1.1023 +                                                    &maskRect)) {
  1.1024 +            // The context's matrix may change while creating the mask, so save the CTM here to
  1.1025 +            // pass to filterMaskGPU.
  1.1026 +            const SkMatrix ctm = fContext->getMatrix();
  1.1027 +
  1.1028 +            SkIRect finalIRect;
  1.1029 +            maskRect.roundOut(&finalIRect);
  1.1030 +            if (draw.fClip->quickReject(finalIRect)) {
  1.1031 +                // clipped out
  1.1032 +                return;
  1.1033 +            }
  1.1034 +            if (NULL != draw.fBounder && !draw.fBounder->doIRect(finalIRect)) {
  1.1035 +                // nothing to draw
  1.1036 +                return;
  1.1037 +            }
  1.1038 +
  1.1039 +            if (paint.getMaskFilter()->directFilterMaskGPU(fContext, &grPaint,
  1.1040 +                                                           stroke, *devPathPtr)) {
  1.1041 +                // the mask filter was able to draw itself directly, so there's nothing
  1.1042 +                // left to do.
  1.1043 +                return;
  1.1044 +            }
  1.1045 +
  1.1046 +            GrAutoScratchTexture mask;
  1.1047 +
  1.1048 +            if (create_mask_GPU(fContext, maskRect, *devPathPtr, stroke,
  1.1049 +                                grPaint.isAntiAlias(), &mask)) {
  1.1050 +                GrTexture* filtered;
  1.1051 +
  1.1052 +                if (paint.getMaskFilter()->filterMaskGPU(mask.texture(),
  1.1053 +                                                         ctm, maskRect, &filtered, true)) {
  1.1054 +                    // filterMaskGPU gives us ownership of a ref to the result
  1.1055 +                    SkAutoTUnref<GrTexture> atu(filtered);
  1.1056 +
  1.1057 +                    // If the scratch texture that we used as the filter src also holds the filter
  1.1058 +                    // result then we must detach so that this texture isn't recycled for a later
  1.1059 +                    // draw.
  1.1060 +                    if (filtered == mask.texture()) {
  1.1061 +                        mask.detach();
  1.1062 +                        filtered->unref(); // detach transfers GrAutoScratchTexture's ref to us.
  1.1063 +                    }
  1.1064 +
  1.1065 +                    if (draw_mask(fContext, maskRect, &grPaint, filtered)) {
  1.1066 +                        // This path is completely drawn
  1.1067 +                        return;
  1.1068 +                    }
  1.1069 +                }
  1.1070 +            }
  1.1071 +        }
  1.1072 +
  1.1073 +        // draw the mask on the CPU - this is a fallthrough path in case the
  1.1074 +        // GPU path fails
  1.1075 +        SkPaint::Style style = stroke.isHairlineStyle() ? SkPaint::kStroke_Style :
  1.1076 +                                                          SkPaint::kFill_Style;
  1.1077 +        draw_with_mask_filter(fContext, *devPathPtr, paint.getMaskFilter(),
  1.1078 +                              *draw.fClip, draw.fBounder, &grPaint, style);
  1.1079 +        return;
  1.1080 +    }
  1.1081 +
  1.1082 +    fContext->drawPath(grPaint, *pathPtr, stroke);
  1.1083 +}
  1.1084 +
  1.1085 +static const int kBmpSmallTileSize = 1 << 10;
  1.1086 +
  1.1087 +static inline int get_tile_count(const SkIRect& srcRect, int tileSize)  {
  1.1088 +    int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1;
  1.1089 +    int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1;
  1.1090 +    return tilesX * tilesY;
  1.1091 +}
  1.1092 +
  1.1093 +static int determine_tile_size(const SkBitmap& bitmap, const SkIRect& src, int maxTileSize) {
  1.1094 +    if (maxTileSize <= kBmpSmallTileSize) {
  1.1095 +        return maxTileSize;
  1.1096 +    }
  1.1097 +
  1.1098 +    size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize);
  1.1099 +    size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize);
  1.1100 +
  1.1101 +    maxTileTotalTileSize *= maxTileSize * maxTileSize;
  1.1102 +    smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize;
  1.1103 +
  1.1104 +    if (maxTileTotalTileSize > 2 * smallTotalTileSize) {
  1.1105 +        return kBmpSmallTileSize;
  1.1106 +    } else {
  1.1107 +        return maxTileSize;
  1.1108 +    }
  1.1109 +}
  1.1110 +
  1.1111 +// Given a bitmap, an optional src rect, and a context with a clip and matrix determine what
  1.1112 +// pixels from the bitmap are necessary.
  1.1113 +static void determine_clipped_src_rect(const GrContext* context,
  1.1114 +                                       const SkBitmap& bitmap,
  1.1115 +                                       const SkRect* srcRectPtr,
  1.1116 +                                       SkIRect* clippedSrcIRect) {
  1.1117 +    const GrClipData* clip = context->getClip();
  1.1118 +    clip->getConservativeBounds(context->getRenderTarget(), clippedSrcIRect, NULL);
  1.1119 +    SkMatrix inv;
  1.1120 +    if (!context->getMatrix().invert(&inv)) {
  1.1121 +        clippedSrcIRect->setEmpty();
  1.1122 +        return;
  1.1123 +    }
  1.1124 +    SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect);
  1.1125 +    inv.mapRect(&clippedSrcRect);
  1.1126 +    if (NULL != srcRectPtr) {
  1.1127 +        // we've setup src space 0,0 to map to the top left of the src rect.
  1.1128 +        clippedSrcRect.offset(srcRectPtr->fLeft, srcRectPtr->fTop);
  1.1129 +        if (!clippedSrcRect.intersect(*srcRectPtr)) {
  1.1130 +            clippedSrcIRect->setEmpty();
  1.1131 +            return;
  1.1132 +        }
  1.1133 +    }
  1.1134 +    clippedSrcRect.roundOut(clippedSrcIRect);
  1.1135 +    SkIRect bmpBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
  1.1136 +    if (!clippedSrcIRect->intersect(bmpBounds)) {
  1.1137 +        clippedSrcIRect->setEmpty();
  1.1138 +    }
  1.1139 +}
  1.1140 +
  1.1141 +bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap,
  1.1142 +                                   const GrTextureParams& params,
  1.1143 +                                   const SkRect* srcRectPtr,
  1.1144 +                                   int maxTileSize,
  1.1145 +                                   int* tileSize,
  1.1146 +                                   SkIRect* clippedSrcRect) const {
  1.1147 +    // if bitmap is explictly texture backed then just use the texture
  1.1148 +    if (NULL != bitmap.getTexture()) {
  1.1149 +        return false;
  1.1150 +    }
  1.1151 +
  1.1152 +    // if it's larger than the max tile size, then we have no choice but tiling.
  1.1153 +    if (bitmap.width() > maxTileSize || bitmap.height() > maxTileSize) {
  1.1154 +        determine_clipped_src_rect(fContext, bitmap, srcRectPtr, clippedSrcRect);
  1.1155 +        *tileSize = determine_tile_size(bitmap, *clippedSrcRect, maxTileSize);
  1.1156 +        return true;
  1.1157 +    }
  1.1158 +
  1.1159 +    if (bitmap.width() * bitmap.height() < 4 * kBmpSmallTileSize * kBmpSmallTileSize) {
  1.1160 +        return false;
  1.1161 +    }
  1.1162 +
  1.1163 +    // if the entire texture is already in our cache then no reason to tile it
  1.1164 +    if (GrIsBitmapInCache(fContext, bitmap, &params)) {
  1.1165 +        return false;
  1.1166 +    }
  1.1167 +
  1.1168 +    // At this point we know we could do the draw by uploading the entire bitmap
  1.1169 +    // as a texture. However, if the texture would be large compared to the
  1.1170 +    // cache size and we don't require most of it for this draw then tile to
  1.1171 +    // reduce the amount of upload and cache spill.
  1.1172 +
  1.1173 +    // assumption here is that sw bitmap size is a good proxy for its size as
  1.1174 +    // a texture
  1.1175 +    size_t bmpSize = bitmap.getSize();
  1.1176 +    size_t cacheSize;
  1.1177 +    fContext->getTextureCacheLimits(NULL, &cacheSize);
  1.1178 +    if (bmpSize < cacheSize / 2) {
  1.1179 +        return false;
  1.1180 +    }
  1.1181 +
  1.1182 +    // Figure out how much of the src we will need based on the src rect and clipping.
  1.1183 +    determine_clipped_src_rect(fContext, bitmap, srcRectPtr, clippedSrcRect);
  1.1184 +    *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile.
  1.1185 +    size_t usedTileBytes = get_tile_count(*clippedSrcRect, kBmpSmallTileSize) *
  1.1186 +                           kBmpSmallTileSize * kBmpSmallTileSize;
  1.1187 +
  1.1188 +    return usedTileBytes < 2 * bmpSize;
  1.1189 +}
  1.1190 +
  1.1191 +void SkGpuDevice::drawBitmap(const SkDraw& origDraw,
  1.1192 +                             const SkBitmap& bitmap,
  1.1193 +                             const SkMatrix& m,
  1.1194 +                             const SkPaint& paint) {
  1.1195 +    SkMatrix concat;
  1.1196 +    SkTCopyOnFirstWrite<SkDraw> draw(origDraw);
  1.1197 +    if (!m.isIdentity()) {
  1.1198 +        concat.setConcat(*draw->fMatrix, m);
  1.1199 +        draw.writable()->fMatrix = &concat;
  1.1200 +    }
  1.1201 +    this->drawBitmapCommon(*draw, bitmap, NULL, NULL, paint, SkCanvas::kNone_DrawBitmapRectFlag);
  1.1202 +}
  1.1203 +
  1.1204 +// This method outsets 'iRect' by 'outset' all around and then clamps its extents to
  1.1205 +// 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner
  1.1206 +// of 'iRect' for all possible outsets/clamps.
  1.1207 +static inline void clamped_outset_with_offset(SkIRect* iRect,
  1.1208 +                                              int outset,
  1.1209 +                                              SkPoint* offset,
  1.1210 +                                              const SkIRect& clamp) {
  1.1211 +    iRect->outset(outset, outset);
  1.1212 +
  1.1213 +    int leftClampDelta = clamp.fLeft - iRect->fLeft;
  1.1214 +    if (leftClampDelta > 0) {
  1.1215 +        offset->fX -= outset - leftClampDelta;
  1.1216 +        iRect->fLeft = clamp.fLeft;
  1.1217 +    } else {
  1.1218 +        offset->fX -= outset;
  1.1219 +    }
  1.1220 +
  1.1221 +    int topClampDelta = clamp.fTop - iRect->fTop;
  1.1222 +    if (topClampDelta > 0) {
  1.1223 +        offset->fY -= outset - topClampDelta;
  1.1224 +        iRect->fTop = clamp.fTop;
  1.1225 +    } else {
  1.1226 +        offset->fY -= outset;
  1.1227 +    }
  1.1228 +
  1.1229 +    if (iRect->fRight > clamp.fRight) {
  1.1230 +        iRect->fRight = clamp.fRight;
  1.1231 +    }
  1.1232 +    if (iRect->fBottom > clamp.fBottom) {
  1.1233 +        iRect->fBottom = clamp.fBottom;
  1.1234 +    }
  1.1235 +}
  1.1236 +
  1.1237 +void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
  1.1238 +                                   const SkBitmap& bitmap,
  1.1239 +                                   const SkRect* srcRectPtr,
  1.1240 +                                   const SkSize* dstSizePtr,
  1.1241 +                                   const SkPaint& paint,
  1.1242 +                                   SkCanvas::DrawBitmapRectFlags flags) {
  1.1243 +    CHECK_SHOULD_DRAW(draw, false);
  1.1244 +
  1.1245 +    SkRect srcRect;
  1.1246 +    SkSize dstSize;
  1.1247 +    // If there is no src rect, or the src rect contains the entire bitmap then we're effectively
  1.1248 +    // in the (easier) bleed case, so update flags.
  1.1249 +    if (NULL == srcRectPtr) {
  1.1250 +        SkScalar w = SkIntToScalar(bitmap.width());
  1.1251 +        SkScalar h = SkIntToScalar(bitmap.height());
  1.1252 +        dstSize.fWidth = w;
  1.1253 +        dstSize.fHeight = h;
  1.1254 +        srcRect.set(0, 0, w, h);
  1.1255 +        flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag);
  1.1256 +    } else {
  1.1257 +        SkASSERT(NULL != dstSizePtr);
  1.1258 +        srcRect = *srcRectPtr;
  1.1259 +        dstSize = *dstSizePtr;
  1.1260 +        if (srcRect.fLeft <= 0 && srcRect.fTop <= 0 &&
  1.1261 +            srcRect.fRight >= bitmap.width() && srcRect.fBottom >= bitmap.height()) {
  1.1262 +            flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag);
  1.1263 +        }
  1.1264 +    }
  1.1265 +
  1.1266 +    if (paint.getMaskFilter()){
  1.1267 +        // Convert the bitmap to a shader so that the rect can be drawn
  1.1268 +        // through drawRect, which supports mask filters.
  1.1269 +        SkBitmap        tmp;    // subset of bitmap, if necessary
  1.1270 +        const SkBitmap* bitmapPtr = &bitmap;
  1.1271 +        SkMatrix localM;
  1.1272 +        if (NULL != srcRectPtr) {
  1.1273 +            localM.setTranslate(-srcRectPtr->fLeft, -srcRectPtr->fTop);
  1.1274 +            localM.postScale(dstSize.fWidth / srcRectPtr->width(),
  1.1275 +                             dstSize.fHeight / srcRectPtr->height());
  1.1276 +            // In bleed mode we position and trim the bitmap based on the src rect which is
  1.1277 +            // already accounted for in 'm' and 'srcRect'. In clamp mode we need to chop out
  1.1278 +            // the desired portion of the bitmap and then update 'm' and 'srcRect' to
  1.1279 +            // compensate.
  1.1280 +            if (!(SkCanvas::kBleed_DrawBitmapRectFlag & flags)) {
  1.1281 +                SkIRect iSrc;
  1.1282 +                srcRect.roundOut(&iSrc);
  1.1283 +
  1.1284 +                SkPoint offset = SkPoint::Make(SkIntToScalar(iSrc.fLeft),
  1.1285 +                                               SkIntToScalar(iSrc.fTop));
  1.1286 +
  1.1287 +                if (!bitmap.extractSubset(&tmp, iSrc)) {
  1.1288 +                    return;     // extraction failed
  1.1289 +                }
  1.1290 +                bitmapPtr = &tmp;
  1.1291 +                srcRect.offset(-offset.fX, -offset.fY);
  1.1292 +
  1.1293 +                // The source rect has changed so update the matrix
  1.1294 +                localM.preTranslate(offset.fX, offset.fY);
  1.1295 +            }
  1.1296 +        } else {
  1.1297 +            localM.reset();
  1.1298 +        }
  1.1299 +
  1.1300 +        SkPaint paintWithShader(paint);
  1.1301 +        paintWithShader.setShader(SkShader::CreateBitmapShader(*bitmapPtr,
  1.1302 +            SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
  1.1303 +        paintWithShader.getShader()->setLocalMatrix(localM);
  1.1304 +        SkRect dstRect = {0, 0, dstSize.fWidth, dstSize.fHeight};
  1.1305 +        this->drawRect(draw, dstRect, paintWithShader);
  1.1306 +
  1.1307 +        return;
  1.1308 +    }
  1.1309 +
  1.1310 +    // If there is no mask filter than it is OK to handle the src rect -> dst rect scaling using
  1.1311 +    // the view matrix rather than a local matrix.
  1.1312 +    SkMatrix m;
  1.1313 +    m.setScale(dstSize.fWidth / srcRect.width(),
  1.1314 +               dstSize.fHeight / srcRect.height());
  1.1315 +    fContext->concatMatrix(m);
  1.1316 +
  1.1317 +    GrTextureParams params;
  1.1318 +    SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
  1.1319 +    GrTextureParams::FilterMode textureFilterMode;
  1.1320 +
  1.1321 +    int tileFilterPad;
  1.1322 +    bool doBicubic = false;
  1.1323 +
  1.1324 +    switch(paintFilterLevel) {
  1.1325 +        case SkPaint::kNone_FilterLevel:
  1.1326 +            tileFilterPad = 0;
  1.1327 +            textureFilterMode = GrTextureParams::kNone_FilterMode;
  1.1328 +            break;
  1.1329 +        case SkPaint::kLow_FilterLevel:
  1.1330 +            tileFilterPad = 1;
  1.1331 +            textureFilterMode = GrTextureParams::kBilerp_FilterMode;
  1.1332 +            break;
  1.1333 +        case SkPaint::kMedium_FilterLevel:
  1.1334 +            tileFilterPad = 1;
  1.1335 +            if (fContext->getMatrix().getMinStretch() < SK_Scalar1) {
  1.1336 +                textureFilterMode = GrTextureParams::kMipMap_FilterMode;
  1.1337 +            } else {
  1.1338 +                // Don't trigger MIP level generation unnecessarily.
  1.1339 +                textureFilterMode = GrTextureParams::kBilerp_FilterMode;
  1.1340 +            }
  1.1341 +            break;
  1.1342 +        case SkPaint::kHigh_FilterLevel:
  1.1343 +            // Minification can look bad with the bicubic effect.
  1.1344 +            if (fContext->getMatrix().getMinStretch() >= SK_Scalar1) {
  1.1345 +                // We will install an effect that does the filtering in the shader.
  1.1346 +                textureFilterMode = GrTextureParams::kNone_FilterMode;
  1.1347 +                tileFilterPad = GrBicubicEffect::kFilterTexelPad;
  1.1348 +                doBicubic = true;
  1.1349 +            } else {
  1.1350 +                textureFilterMode = GrTextureParams::kMipMap_FilterMode;
  1.1351 +                tileFilterPad = 1;
  1.1352 +            }
  1.1353 +            break;
  1.1354 +        default:
  1.1355 +            SkErrorInternals::SetError( kInvalidPaint_SkError,
  1.1356 +                                        "Sorry, I don't understand the filtering "
  1.1357 +                                        "mode you asked for.  Falling back to "
  1.1358 +                                        "MIPMaps.");
  1.1359 +            tileFilterPad = 1;
  1.1360 +            textureFilterMode = GrTextureParams::kMipMap_FilterMode;
  1.1361 +            break;
  1.1362 +    }
  1.1363 +
  1.1364 +    params.setFilterMode(textureFilterMode);
  1.1365 +
  1.1366 +    int maxTileSize = fContext->getMaxTextureSize() - 2 * tileFilterPad;
  1.1367 +    int tileSize;
  1.1368 +
  1.1369 +    SkIRect clippedSrcRect;
  1.1370 +    if (this->shouldTileBitmap(bitmap, params, srcRectPtr, maxTileSize, &tileSize,
  1.1371 +                               &clippedSrcRect)) {
  1.1372 +        this->drawTiledBitmap(bitmap, srcRect, clippedSrcRect, params, paint, flags, tileSize,
  1.1373 +                              doBicubic);
  1.1374 +    } else {
  1.1375 +        // take the simple case
  1.1376 +        this->internalDrawBitmap(bitmap, srcRect, params, paint, flags, doBicubic);
  1.1377 +    }
  1.1378 +}
  1.1379 +
  1.1380 +// Break 'bitmap' into several tiles to draw it since it has already
  1.1381 +// been determined to be too large to fit in VRAM
  1.1382 +void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
  1.1383 +                                  const SkRect& srcRect,
  1.1384 +                                  const SkIRect& clippedSrcIRect,
  1.1385 +                                  const GrTextureParams& params,
  1.1386 +                                  const SkPaint& paint,
  1.1387 +                                  SkCanvas::DrawBitmapRectFlags flags,
  1.1388 +                                  int tileSize,
  1.1389 +                                  bool bicubic) {
  1.1390 +    SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
  1.1391 +
  1.1392 +    int nx = bitmap.width() / tileSize;
  1.1393 +    int ny = bitmap.height() / tileSize;
  1.1394 +    for (int x = 0; x <= nx; x++) {
  1.1395 +        for (int y = 0; y <= ny; y++) {
  1.1396 +            SkRect tileR;
  1.1397 +            tileR.set(SkIntToScalar(x * tileSize),
  1.1398 +                      SkIntToScalar(y * tileSize),
  1.1399 +                      SkIntToScalar((x + 1) * tileSize),
  1.1400 +                      SkIntToScalar((y + 1) * tileSize));
  1.1401 +
  1.1402 +            if (!SkRect::Intersects(tileR, clippedSrcRect)) {
  1.1403 +                continue;
  1.1404 +            }
  1.1405 +
  1.1406 +            if (!tileR.intersect(srcRect)) {
  1.1407 +                continue;
  1.1408 +            }
  1.1409 +
  1.1410 +            SkBitmap tmpB;
  1.1411 +            SkIRect iTileR;
  1.1412 +            tileR.roundOut(&iTileR);
  1.1413 +            SkPoint offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft),
  1.1414 +                                           SkIntToScalar(iTileR.fTop));
  1.1415 +
  1.1416 +            // Adjust the context matrix to draw at the right x,y in device space
  1.1417 +            SkMatrix tmpM;
  1.1418 +            GrContext::AutoMatrix am;
  1.1419 +            tmpM.setTranslate(offset.fX - srcRect.fLeft, offset.fY - srcRect.fTop);
  1.1420 +            am.setPreConcat(fContext, tmpM);
  1.1421 +
  1.1422 +            if (SkPaint::kNone_FilterLevel != paint.getFilterLevel() || bicubic) {
  1.1423 +                SkIRect iClampRect;
  1.1424 +
  1.1425 +                if (SkCanvas::kBleed_DrawBitmapRectFlag & flags) {
  1.1426 +                    // In bleed mode we want to always expand the tile on all edges
  1.1427 +                    // but stay within the bitmap bounds
  1.1428 +                    iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height());
  1.1429 +                } else {
  1.1430 +                    // In texture-domain/clamp mode we only want to expand the
  1.1431 +                    // tile on edges interior to "srcRect" (i.e., we want to
  1.1432 +                    // not bleed across the original clamped edges)
  1.1433 +                    srcRect.roundOut(&iClampRect);
  1.1434 +                }
  1.1435 +                int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1;
  1.1436 +                clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect);
  1.1437 +            }
  1.1438 +
  1.1439 +            if (bitmap.extractSubset(&tmpB, iTileR)) {
  1.1440 +                // now offset it to make it "local" to our tmp bitmap
  1.1441 +                tileR.offset(-offset.fX, -offset.fY);
  1.1442 +
  1.1443 +                this->internalDrawBitmap(tmpB, tileR, params, paint, flags, bicubic);
  1.1444 +            }
  1.1445 +        }
  1.1446 +    }
  1.1447 +}
  1.1448 +
  1.1449 +static bool has_aligned_samples(const SkRect& srcRect,
  1.1450 +                                const SkRect& transformedRect) {
  1.1451 +    // detect pixel disalignment
  1.1452 +    if (SkScalarAbs(SkScalarRoundToScalar(transformedRect.left()) -
  1.1453 +            transformedRect.left()) < COLOR_BLEED_TOLERANCE &&
  1.1454 +        SkScalarAbs(SkScalarRoundToScalar(transformedRect.top()) -
  1.1455 +            transformedRect.top()) < COLOR_BLEED_TOLERANCE &&
  1.1456 +        SkScalarAbs(transformedRect.width() - srcRect.width()) <
  1.1457 +            COLOR_BLEED_TOLERANCE &&
  1.1458 +        SkScalarAbs(transformedRect.height() - srcRect.height()) <
  1.1459 +            COLOR_BLEED_TOLERANCE) {
  1.1460 +        return true;
  1.1461 +    }
  1.1462 +    return false;
  1.1463 +}
  1.1464 +
  1.1465 +static bool may_color_bleed(const SkRect& srcRect,
  1.1466 +                            const SkRect& transformedRect,
  1.1467 +                            const SkMatrix& m) {
  1.1468 +    // Only gets called if has_aligned_samples returned false.
  1.1469 +    // So we can assume that sampling is axis aligned but not texel aligned.
  1.1470 +    SkASSERT(!has_aligned_samples(srcRect, transformedRect));
  1.1471 +    SkRect innerSrcRect(srcRect), innerTransformedRect,
  1.1472 +        outerTransformedRect(transformedRect);
  1.1473 +    innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf);
  1.1474 +    m.mapRect(&innerTransformedRect, innerSrcRect);
  1.1475 +
  1.1476 +    // The gap between outerTransformedRect and innerTransformedRect
  1.1477 +    // represents the projection of the source border area, which is
  1.1478 +    // problematic for color bleeding.  We must check whether any
  1.1479 +    // destination pixels sample the border area.
  1.1480 +    outerTransformedRect.inset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
  1.1481 +    innerTransformedRect.outset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
  1.1482 +    SkIRect outer, inner;
  1.1483 +    outerTransformedRect.round(&outer);
  1.1484 +    innerTransformedRect.round(&inner);
  1.1485 +    // If the inner and outer rects round to the same result, it means the
  1.1486 +    // border does not overlap any pixel centers. Yay!
  1.1487 +    return inner != outer;
  1.1488 +}
  1.1489 +
  1.1490 +
  1.1491 +/*
  1.1492 + *  This is called by drawBitmap(), which has to handle images that may be too
  1.1493 + *  large to be represented by a single texture.
  1.1494 + *
  1.1495 + *  internalDrawBitmap assumes that the specified bitmap will fit in a texture
  1.1496 + *  and that non-texture portion of the GrPaint has already been setup.
  1.1497 + */
  1.1498 +void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
  1.1499 +                                     const SkRect& srcRect,
  1.1500 +                                     const GrTextureParams& params,
  1.1501 +                                     const SkPaint& paint,
  1.1502 +                                     SkCanvas::DrawBitmapRectFlags flags,
  1.1503 +                                     bool bicubic) {
  1.1504 +    SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
  1.1505 +             bitmap.height() <= fContext->getMaxTextureSize());
  1.1506 +
  1.1507 +    GrTexture* texture;
  1.1508 +    SkAutoCachedTexture act(this, bitmap, &params, &texture);
  1.1509 +    if (NULL == texture) {
  1.1510 +        return;
  1.1511 +    }
  1.1512 +
  1.1513 +    SkRect dstRect = {0, 0, srcRect.width(), srcRect.height() };
  1.1514 +    SkRect paintRect;
  1.1515 +    SkScalar wInv = SkScalarInvert(SkIntToScalar(texture->width()));
  1.1516 +    SkScalar hInv = SkScalarInvert(SkIntToScalar(texture->height()));
  1.1517 +    paintRect.setLTRB(SkScalarMul(srcRect.fLeft,   wInv),
  1.1518 +                      SkScalarMul(srcRect.fTop,    hInv),
  1.1519 +                      SkScalarMul(srcRect.fRight,  wInv),
  1.1520 +                      SkScalarMul(srcRect.fBottom, hInv));
  1.1521 +
  1.1522 +    bool needsTextureDomain = false;
  1.1523 +    if (!(flags & SkCanvas::kBleed_DrawBitmapRectFlag) &&
  1.1524 +        (bicubic || params.filterMode() != GrTextureParams::kNone_FilterMode)) {
  1.1525 +        // Need texture domain if drawing a sub rect
  1.1526 +        needsTextureDomain = srcRect.width() < bitmap.width() ||
  1.1527 +                             srcRect.height() < bitmap.height();
  1.1528 +        if (!bicubic && needsTextureDomain && fContext->getMatrix().rectStaysRect()) {
  1.1529 +            const SkMatrix& matrix = fContext->getMatrix();
  1.1530 +            // sampling is axis-aligned
  1.1531 +            SkRect transformedRect;
  1.1532 +            matrix.mapRect(&transformedRect, srcRect);
  1.1533 +
  1.1534 +            if (has_aligned_samples(srcRect, transformedRect)) {
  1.1535 +                // We could also turn off filtering here (but we already did a cache lookup with
  1.1536 +                // params).
  1.1537 +                needsTextureDomain = false;
  1.1538 +            } else {
  1.1539 +                needsTextureDomain = may_color_bleed(srcRect, transformedRect, matrix);
  1.1540 +            }
  1.1541 +        }
  1.1542 +    }
  1.1543 +
  1.1544 +    SkRect textureDomain = SkRect::MakeEmpty();
  1.1545 +    SkAutoTUnref<GrEffectRef> effect;
  1.1546 +    if (needsTextureDomain) {
  1.1547 +        // Use a constrained texture domain to avoid color bleeding
  1.1548 +        SkScalar left, top, right, bottom;
  1.1549 +        if (srcRect.width() > SK_Scalar1) {
  1.1550 +            SkScalar border = SK_ScalarHalf / texture->width();
  1.1551 +            left = paintRect.left() + border;
  1.1552 +            right = paintRect.right() - border;
  1.1553 +        } else {
  1.1554 +            left = right = SkScalarHalf(paintRect.left() + paintRect.right());
  1.1555 +        }
  1.1556 +        if (srcRect.height() > SK_Scalar1) {
  1.1557 +            SkScalar border = SK_ScalarHalf / texture->height();
  1.1558 +            top = paintRect.top() + border;
  1.1559 +            bottom = paintRect.bottom() - border;
  1.1560 +        } else {
  1.1561 +            top = bottom = SkScalarHalf(paintRect.top() + paintRect.bottom());
  1.1562 +        }
  1.1563 +        textureDomain.setLTRB(left, top, right, bottom);
  1.1564 +        if (bicubic) {
  1.1565 +            effect.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), textureDomain));
  1.1566 +        } else {
  1.1567 +            effect.reset(GrTextureDomainEffect::Create(texture,
  1.1568 +                                                       SkMatrix::I(),
  1.1569 +                                                       textureDomain,
  1.1570 +                                                       GrTextureDomain::kClamp_Mode,
  1.1571 +                                                       params.filterMode()));
  1.1572 +        }
  1.1573 +    } else if (bicubic) {
  1.1574 +        SkASSERT(GrTextureParams::kNone_FilterMode == params.filterMode());
  1.1575 +        SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() };
  1.1576 +        effect.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), tileModes));
  1.1577 +    } else {
  1.1578 +        effect.reset(GrSimpleTextureEffect::Create(texture, SkMatrix::I(), params));
  1.1579 +    }
  1.1580 +
  1.1581 +    // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring
  1.1582 +    // the rest from the SkPaint.
  1.1583 +    GrPaint grPaint;
  1.1584 +    grPaint.addColorEffect(effect);
  1.1585 +    bool alphaOnly = !(SkBitmap::kA8_Config == bitmap.config());
  1.1586 +    if (!skPaint2GrPaintNoShader(this, paint, alphaOnly, false, &grPaint)) {
  1.1587 +        return;
  1.1588 +    }
  1.1589 +
  1.1590 +    fContext->drawRectToRect(grPaint, dstRect, paintRect, NULL);
  1.1591 +}
  1.1592 +
  1.1593 +static bool filter_texture(SkBaseDevice* device, GrContext* context,
  1.1594 +                           GrTexture* texture, const SkImageFilter* filter,
  1.1595 +                           int w, int h, const SkImageFilter::Context& ctx,
  1.1596 +                           SkBitmap* result, SkIPoint* offset) {
  1.1597 +    SkASSERT(filter);
  1.1598 +    SkDeviceImageFilterProxy proxy(device);
  1.1599 +
  1.1600 +    if (filter->canFilterImageGPU()) {
  1.1601 +        // Save the render target and set it to NULL, so we don't accidentally draw to it in the
  1.1602 +        // filter.  Also set the clip wide open and the matrix to identity.
  1.1603 +        GrContext::AutoWideOpenIdentityDraw awo(context, NULL);
  1.1604 +        return filter->filterImageGPU(&proxy, wrap_texture(texture), ctx, result, offset);
  1.1605 +    } else {
  1.1606 +        return false;
  1.1607 +    }
  1.1608 +}
  1.1609 +
  1.1610 +void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
  1.1611 +                             int left, int top, const SkPaint& paint) {
  1.1612 +    // drawSprite is defined to be in device coords.
  1.1613 +    CHECK_SHOULD_DRAW(draw, true);
  1.1614 +
  1.1615 +    SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
  1.1616 +    if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
  1.1617 +        return;
  1.1618 +    }
  1.1619 +
  1.1620 +    int w = bitmap.width();
  1.1621 +    int h = bitmap.height();
  1.1622 +
  1.1623 +    GrTexture* texture;
  1.1624 +    // draw sprite uses the default texture params
  1.1625 +    SkAutoCachedTexture act(this, bitmap, NULL, &texture);
  1.1626 +
  1.1627 +    SkImageFilter* filter = paint.getImageFilter();
  1.1628 +    // This bitmap will own the filtered result as a texture.
  1.1629 +    SkBitmap filteredBitmap;
  1.1630 +
  1.1631 +    if (NULL != filter) {
  1.1632 +        SkIPoint offset = SkIPoint::Make(0, 0);
  1.1633 +        SkMatrix matrix(*draw.fMatrix);
  1.1634 +        matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
  1.1635 +        SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
  1.1636 +        SkImageFilter::Context ctx(matrix, clipBounds);
  1.1637 +        if (filter_texture(this, fContext, texture, filter, w, h, ctx, &filteredBitmap,
  1.1638 +                           &offset)) {
  1.1639 +            texture = (GrTexture*) filteredBitmap.getTexture();
  1.1640 +            w = filteredBitmap.width();
  1.1641 +            h = filteredBitmap.height();
  1.1642 +            left += offset.x();
  1.1643 +            top += offset.y();
  1.1644 +        } else {
  1.1645 +            return;
  1.1646 +        }
  1.1647 +    }
  1.1648 +
  1.1649 +    GrPaint grPaint;
  1.1650 +    grPaint.addColorTextureEffect(texture, SkMatrix::I());
  1.1651 +
  1.1652 +    if(!skPaint2GrPaintNoShader(this, paint, true, false, &grPaint)) {
  1.1653 +        return;
  1.1654 +    }
  1.1655 +
  1.1656 +    fContext->drawRectToRect(grPaint,
  1.1657 +                             SkRect::MakeXYWH(SkIntToScalar(left),
  1.1658 +                                              SkIntToScalar(top),
  1.1659 +                                              SkIntToScalar(w),
  1.1660 +                                              SkIntToScalar(h)),
  1.1661 +                             SkRect::MakeXYWH(0,
  1.1662 +                                              0,
  1.1663 +                                              SK_Scalar1 * w / texture->width(),
  1.1664 +                                              SK_Scalar1 * h / texture->height()));
  1.1665 +}
  1.1666 +
  1.1667 +void SkGpuDevice::drawBitmapRect(const SkDraw& origDraw, const SkBitmap& bitmap,
  1.1668 +                                 const SkRect* src, const SkRect& dst,
  1.1669 +                                 const SkPaint& paint,
  1.1670 +                                 SkCanvas::DrawBitmapRectFlags flags) {
  1.1671 +    SkMatrix    matrix;
  1.1672 +    SkRect      bitmapBounds, tmpSrc;
  1.1673 +
  1.1674 +    bitmapBounds.set(0, 0,
  1.1675 +                     SkIntToScalar(bitmap.width()),
  1.1676 +                     SkIntToScalar(bitmap.height()));
  1.1677 +
  1.1678 +    // Compute matrix from the two rectangles
  1.1679 +    if (NULL != src) {
  1.1680 +        tmpSrc = *src;
  1.1681 +    } else {
  1.1682 +        tmpSrc = bitmapBounds;
  1.1683 +    }
  1.1684 +
  1.1685 +    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
  1.1686 +
  1.1687 +    // clip the tmpSrc to the bounds of the bitmap. No check needed if src==null.
  1.1688 +    if (NULL != src) {
  1.1689 +        if (!bitmapBounds.contains(tmpSrc)) {
  1.1690 +            if (!tmpSrc.intersect(bitmapBounds)) {
  1.1691 +                return; // nothing to draw
  1.1692 +            }
  1.1693 +        }
  1.1694 +    }
  1.1695 +
  1.1696 +    SkRect tmpDst;
  1.1697 +    matrix.mapRect(&tmpDst, tmpSrc);
  1.1698 +
  1.1699 +    SkTCopyOnFirstWrite<SkDraw> draw(origDraw);
  1.1700 +    if (0 != tmpDst.fLeft || 0 != tmpDst.fTop) {
  1.1701 +        // Translate so that tempDst's top left is at the origin.
  1.1702 +        matrix = *origDraw.fMatrix;
  1.1703 +        matrix.preTranslate(tmpDst.fLeft, tmpDst.fTop);
  1.1704 +        draw.writable()->fMatrix = &matrix;
  1.1705 +    }
  1.1706 +    SkSize dstSize;
  1.1707 +    dstSize.fWidth = tmpDst.width();
  1.1708 +    dstSize.fHeight = tmpDst.height();
  1.1709 +
  1.1710 +    this->drawBitmapCommon(*draw, bitmap, &tmpSrc, &dstSize, paint, flags);
  1.1711 +}
  1.1712 +
  1.1713 +void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
  1.1714 +                             int x, int y, const SkPaint& paint) {
  1.1715 +    // clear of the source device must occur before CHECK_SHOULD_DRAW
  1.1716 +    SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
  1.1717 +    if (dev->fNeedClear) {
  1.1718 +        // TODO: could check here whether we really need to draw at all
  1.1719 +        dev->clear(0x0);
  1.1720 +    }
  1.1721 +
  1.1722 +    // drawDevice is defined to be in device coords.
  1.1723 +    CHECK_SHOULD_DRAW(draw, true);
  1.1724 +
  1.1725 +    GrRenderTarget* devRT = dev->accessRenderTarget();
  1.1726 +    GrTexture* devTex;
  1.1727 +    if (NULL == (devTex = devRT->asTexture())) {
  1.1728 +        return;
  1.1729 +    }
  1.1730 +
  1.1731 +    const SkBitmap& bm = dev->accessBitmap(false);
  1.1732 +    int w = bm.width();
  1.1733 +    int h = bm.height();
  1.1734 +
  1.1735 +    SkImageFilter* filter = paint.getImageFilter();
  1.1736 +    // This bitmap will own the filtered result as a texture.
  1.1737 +    SkBitmap filteredBitmap;
  1.1738 +
  1.1739 +    if (NULL != filter) {
  1.1740 +        SkIPoint offset = SkIPoint::Make(0, 0);
  1.1741 +        SkMatrix matrix(*draw.fMatrix);
  1.1742 +        matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
  1.1743 +        SkIRect clipBounds = SkIRect::MakeWH(devTex->width(), devTex->height());
  1.1744 +        SkImageFilter::Context ctx(matrix, clipBounds);
  1.1745 +        if (filter_texture(this, fContext, devTex, filter, w, h, ctx, &filteredBitmap,
  1.1746 +                           &offset)) {
  1.1747 +            devTex = filteredBitmap.getTexture();
  1.1748 +            w = filteredBitmap.width();
  1.1749 +            h = filteredBitmap.height();
  1.1750 +            x += offset.fX;
  1.1751 +            y += offset.fY;
  1.1752 +        } else {
  1.1753 +            return;
  1.1754 +        }
  1.1755 +    }
  1.1756 +
  1.1757 +    GrPaint grPaint;
  1.1758 +    grPaint.addColorTextureEffect(devTex, SkMatrix::I());
  1.1759 +
  1.1760 +    if (!skPaint2GrPaintNoShader(this, paint, true, false, &grPaint)) {
  1.1761 +        return;
  1.1762 +    }
  1.1763 +
  1.1764 +    SkRect dstRect = SkRect::MakeXYWH(SkIntToScalar(x),
  1.1765 +                                      SkIntToScalar(y),
  1.1766 +                                      SkIntToScalar(w),
  1.1767 +                                      SkIntToScalar(h));
  1.1768 +
  1.1769 +    // The device being drawn may not fill up its texture (e.g. saveLayer uses approximate
  1.1770 +    // scratch texture).
  1.1771 +    SkRect srcRect = SkRect::MakeWH(SK_Scalar1 * w / devTex->width(),
  1.1772 +                                    SK_Scalar1 * h / devTex->height());
  1.1773 +
  1.1774 +    fContext->drawRectToRect(grPaint, dstRect, srcRect);
  1.1775 +}
  1.1776 +
  1.1777 +bool SkGpuDevice::canHandleImageFilter(const SkImageFilter* filter) {
  1.1778 +    return filter->canFilterImageGPU();
  1.1779 +}
  1.1780 +
  1.1781 +bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src,
  1.1782 +                              const SkImageFilter::Context& ctx,
  1.1783 +                              SkBitmap* result, SkIPoint* offset) {
  1.1784 +    // want explicitly our impl, so guard against a subclass of us overriding it
  1.1785 +    if (!this->SkGpuDevice::canHandleImageFilter(filter)) {
  1.1786 +        return false;
  1.1787 +    }
  1.1788 +
  1.1789 +    SkAutoLockPixels alp(src, !src.getTexture());
  1.1790 +    if (!src.getTexture() && !src.readyToDraw()) {
  1.1791 +        return false;
  1.1792 +    }
  1.1793 +
  1.1794 +    GrTexture* texture;
  1.1795 +    // We assume here that the filter will not attempt to tile the src. Otherwise, this cache lookup
  1.1796 +    // must be pushed upstack.
  1.1797 +    SkAutoCachedTexture act(this, src, NULL, &texture);
  1.1798 +
  1.1799 +    return filter_texture(this, fContext, texture, filter, src.width(), src.height(), ctx,
  1.1800 +                          result, offset);
  1.1801 +}
  1.1802 +
  1.1803 +///////////////////////////////////////////////////////////////////////////////
  1.1804 +
  1.1805 +// must be in SkCanvas::VertexMode order
  1.1806 +static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
  1.1807 +    kTriangles_GrPrimitiveType,
  1.1808 +    kTriangleStrip_GrPrimitiveType,
  1.1809 +    kTriangleFan_GrPrimitiveType,
  1.1810 +};
  1.1811 +
  1.1812 +void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
  1.1813 +                              int vertexCount, const SkPoint vertices[],
  1.1814 +                              const SkPoint texs[], const SkColor colors[],
  1.1815 +                              SkXfermode* xmode,
  1.1816 +                              const uint16_t indices[], int indexCount,
  1.1817 +                              const SkPaint& paint) {
  1.1818 +    CHECK_SHOULD_DRAW(draw, false);
  1.1819 +
  1.1820 +    GrPaint grPaint;
  1.1821 +    // we ignore the shader if texs is null.
  1.1822 +    if (NULL == texs) {
  1.1823 +        if (!skPaint2GrPaintNoShader(this, paint, false, NULL == colors, &grPaint)) {
  1.1824 +            return;
  1.1825 +        }
  1.1826 +    } else {
  1.1827 +        if (!skPaint2GrPaintShader(this, paint, NULL == colors, &grPaint)) {
  1.1828 +            return;
  1.1829 +        }
  1.1830 +    }
  1.1831 +
  1.1832 +    if (NULL != xmode && NULL != texs && NULL != colors) {
  1.1833 +        if (!SkXfermode::IsMode(xmode, SkXfermode::kModulate_Mode)) {
  1.1834 +            SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
  1.1835 +#if 0
  1.1836 +            return
  1.1837 +#endif
  1.1838 +        }
  1.1839 +    }
  1.1840 +
  1.1841 +    SkAutoSTMalloc<128, GrColor> convertedColors(0);
  1.1842 +    if (NULL != colors) {
  1.1843 +        // need to convert byte order and from non-PM to PM
  1.1844 +        convertedColors.reset(vertexCount);
  1.1845 +        for (int i = 0; i < vertexCount; ++i) {
  1.1846 +            convertedColors[i] = SkColor2GrColor(colors[i]);
  1.1847 +        }
  1.1848 +        colors = convertedColors.get();
  1.1849 +    }
  1.1850 +    fContext->drawVertices(grPaint,
  1.1851 +                           gVertexMode2PrimitiveType[vmode],
  1.1852 +                           vertexCount,
  1.1853 +                           (GrPoint*) vertices,
  1.1854 +                           (GrPoint*) texs,
  1.1855 +                           colors,
  1.1856 +                           indices,
  1.1857 +                           indexCount);
  1.1858 +}
  1.1859 +
  1.1860 +///////////////////////////////////////////////////////////////////////////////
  1.1861 +
  1.1862 +void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
  1.1863 +                          size_t byteLength, SkScalar x, SkScalar y,
  1.1864 +                          const SkPaint& paint) {
  1.1865 +    CHECK_SHOULD_DRAW(draw, false);
  1.1866 +
  1.1867 +    if (fMainTextContext->canDraw(paint)) {
  1.1868 +        GrPaint grPaint;
  1.1869 +        if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
  1.1870 +            return;
  1.1871 +        }
  1.1872 +
  1.1873 +        SkDEBUGCODE(this->validate();)
  1.1874 +
  1.1875 +        fMainTextContext->drawText(grPaint, paint, (const char *)text, byteLength, x, y);
  1.1876 +    } else if (fFallbackTextContext && fFallbackTextContext->canDraw(paint)) {
  1.1877 +        GrPaint grPaint;
  1.1878 +        if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
  1.1879 +            return;
  1.1880 +        }
  1.1881 +
  1.1882 +        SkDEBUGCODE(this->validate();)
  1.1883 +
  1.1884 +        fFallbackTextContext->drawText(grPaint, paint, (const char *)text, byteLength, x, y);
  1.1885 +    } else {
  1.1886 +        // this guy will just call our drawPath()
  1.1887 +        draw.drawText_asPaths((const char*)text, byteLength, x, y, paint);
  1.1888 +    }
  1.1889 +}
  1.1890 +
  1.1891 +void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
  1.1892 +                             size_t byteLength, const SkScalar pos[],
  1.1893 +                             SkScalar constY, int scalarsPerPos,
  1.1894 +                             const SkPaint& paint) {
  1.1895 +    CHECK_SHOULD_DRAW(draw, false);
  1.1896 +
  1.1897 +    if (fMainTextContext->canDraw(paint)) {
  1.1898 +        GrPaint grPaint;
  1.1899 +        if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
  1.1900 +            return;
  1.1901 +        }
  1.1902 +
  1.1903 +        SkDEBUGCODE(this->validate();)
  1.1904 +
  1.1905 +        fMainTextContext->drawPosText(grPaint, paint, (const char *)text, byteLength, pos,
  1.1906 +                                      constY, scalarsPerPos);
  1.1907 +    } else if (fFallbackTextContext && fFallbackTextContext->canDraw(paint)) {
  1.1908 +        GrPaint grPaint;
  1.1909 +        if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
  1.1910 +            return;
  1.1911 +        }
  1.1912 +
  1.1913 +        SkDEBUGCODE(this->validate();)
  1.1914 +
  1.1915 +        fFallbackTextContext->drawPosText(grPaint, paint, (const char *)text, byteLength, pos,
  1.1916 +                                          constY, scalarsPerPos);
  1.1917 +    } else {
  1.1918 +        draw.drawPosText_asPaths((const char*)text, byteLength, pos, constY,
  1.1919 +                                 scalarsPerPos, paint);
  1.1920 +    }
  1.1921 +}
  1.1922 +
  1.1923 +void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
  1.1924 +                                size_t len, const SkPath& path,
  1.1925 +                                const SkMatrix* m, const SkPaint& paint) {
  1.1926 +    CHECK_SHOULD_DRAW(draw, false);
  1.1927 +
  1.1928 +    SkASSERT(draw.fDevice == this);
  1.1929 +    draw.drawTextOnPath((const char*)text, len, path, m, paint);
  1.1930 +}
  1.1931 +
  1.1932 +///////////////////////////////////////////////////////////////////////////////
  1.1933 +
  1.1934 +bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
  1.1935 +    if (!paint.isLCDRenderText()) {
  1.1936 +        // we're cool with the paint as is
  1.1937 +        return false;
  1.1938 +    }
  1.1939 +
  1.1940 +    if (paint.getShader() ||
  1.1941 +        paint.getXfermode() || // unless its srcover
  1.1942 +        paint.getMaskFilter() ||
  1.1943 +        paint.getRasterizer() ||
  1.1944 +        paint.getColorFilter() ||
  1.1945 +        paint.getPathEffect() ||
  1.1946 +        paint.isFakeBoldText() ||
  1.1947 +        paint.getStyle() != SkPaint::kFill_Style) {
  1.1948 +        // turn off lcd
  1.1949 +        flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
  1.1950 +        flags->fHinting = paint.getHinting();
  1.1951 +        return true;
  1.1952 +    }
  1.1953 +    // we're cool with the paint as is
  1.1954 +    return false;
  1.1955 +}
  1.1956 +
  1.1957 +void SkGpuDevice::flush() {
  1.1958 +    DO_DEFERRED_CLEAR();
  1.1959 +    fContext->resolveRenderTarget(fRenderTarget);
  1.1960 +}
  1.1961 +
  1.1962 +///////////////////////////////////////////////////////////////////////////////
  1.1963 +
  1.1964 +SkBaseDevice* SkGpuDevice::onCreateDevice(const SkImageInfo& info, Usage usage) {
  1.1965 +    GrTextureDesc desc;
  1.1966 +    desc.fConfig = fRenderTarget->config();
  1.1967 +    desc.fFlags = kRenderTarget_GrTextureFlagBit;
  1.1968 +    desc.fWidth = info.width();
  1.1969 +    desc.fHeight = info.height();
  1.1970 +    desc.fSampleCnt = fRenderTarget->numSamples();
  1.1971 +
  1.1972 +    SkAutoTUnref<GrTexture> texture;
  1.1973 +    // Skia's convention is to only clear a device if it is non-opaque.
  1.1974 +    bool needClear = !info.isOpaque();
  1.1975 +
  1.1976 +#if CACHE_COMPATIBLE_DEVICE_TEXTURES
  1.1977 +    // layers are never draw in repeat modes, so we can request an approx
  1.1978 +    // match and ignore any padding.
  1.1979 +    const GrContext::ScratchTexMatch match = (kSaveLayer_Usage == usage) ?
  1.1980 +                                                GrContext::kApprox_ScratchTexMatch :
  1.1981 +                                                GrContext::kExact_ScratchTexMatch;
  1.1982 +    texture.reset(fContext->lockAndRefScratchTexture(desc, match));
  1.1983 +#else
  1.1984 +    texture.reset(fContext->createUncachedTexture(desc, NULL, 0));
  1.1985 +#endif
  1.1986 +    if (NULL != texture.get()) {
  1.1987 +        return SkNEW_ARGS(SkGpuDevice,(fContext, texture, needClear));
  1.1988 +    } else {
  1.1989 +        GrPrintf("---- failed to create compatible device texture [%d %d]\n",
  1.1990 +                 info.width(), info.height());
  1.1991 +        return NULL;
  1.1992 +    }
  1.1993 +}
  1.1994 +
  1.1995 +SkSurface* SkGpuDevice::newSurface(const SkImageInfo& info) {
  1.1996 +    return SkSurface::NewRenderTarget(fContext, info, fRenderTarget->numSamples());
  1.1997 +}
  1.1998 +
  1.1999 +SkGpuDevice::SkGpuDevice(GrContext* context,
  1.2000 +                         GrTexture* texture,
  1.2001 +                         bool needClear)
  1.2002 +    : SkBitmapDevice(make_bitmap(context, texture->asRenderTarget())) {
  1.2003 +
  1.2004 +    SkASSERT(texture && texture->asRenderTarget());
  1.2005 +    // This constructor is called from onCreateDevice. It has locked the RT in the texture
  1.2006 +    // cache. We pass true for the third argument so that it will get unlocked.
  1.2007 +    this->initFromRenderTarget(context, texture->asRenderTarget(), true);
  1.2008 +    fNeedClear = needClear;
  1.2009 +}
  1.2010 +
  1.2011 +class GPUAccelData : public SkPicture::AccelData {
  1.2012 +public:
  1.2013 +    GPUAccelData(Key key) : INHERITED(key) { }
  1.2014 +
  1.2015 +protected:
  1.2016 +
  1.2017 +private:
  1.2018 +    typedef SkPicture::AccelData INHERITED;
  1.2019 +};
  1.2020 +
  1.2021 +// In the future this may not be a static method if we need to incorporate the
  1.2022 +// clip and matrix state into the key
  1.2023 +SkPicture::AccelData::Key SkGpuDevice::ComputeAccelDataKey() {
  1.2024 +    static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
  1.2025 +
  1.2026 +    return gGPUID;
  1.2027 +}
  1.2028 +
  1.2029 +void SkGpuDevice::EXPERIMENTAL_optimize(SkPicture* picture) {
  1.2030 +    SkPicture::AccelData::Key key = ComputeAccelDataKey();
  1.2031 +
  1.2032 +    GPUAccelData* data = SkNEW_ARGS(GPUAccelData, (key));
  1.2033 +
  1.2034 +    picture->EXPERIMENTAL_addAccelData(data);
  1.2035 +}
  1.2036 +
  1.2037 +bool SkGpuDevice::EXPERIMENTAL_drawPicture(const SkPicture& picture) {
  1.2038 +    SkPicture::AccelData::Key key = ComputeAccelDataKey();
  1.2039 +
  1.2040 +    const SkPicture::AccelData* data = picture.EXPERIMENTAL_getAccelData(key);
  1.2041 +    if (NULL == data) {
  1.2042 +        return false;
  1.2043 +    }
  1.2044 +
  1.2045 +#if 0
  1.2046 +    const GPUAccelData *gpuData = static_cast<const GPUAccelData*>(data);
  1.2047 +#endif
  1.2048 +
  1.2049 +    return false;
  1.2050 +}

mercurial