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