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