SkCanvas.cpp revision 90c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cb
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2008 The Android Open Source Project
48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkCanvas.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBounder.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkDevice.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkDraw.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkDrawFilter.h"
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkDrawLooper.h"
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPicture.h"
170017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com#include "SkRasterClip.h"
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScalarCompare.h"
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTemplates.h"
2052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com#include "SkTextFormatParams.h"
21a076e9be17654a60310e72c4f70fcd5337f56dbfreed@google.com#include "SkTLazy.h"
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkUtils.h"
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//#define SK_TRACE_SAVERESTORE
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_TRACE_SAVERESTORE
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static int gLayerCounter;
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static int gRecCounter;
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static int gCanvasCounter;
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define inc_layer()
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define dec_layer()
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define inc_rec()
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define dec_rec()
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define inc_canvas()
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define dec_canvas()
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
472c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.orgtypedef SkTLazy<SkPaint> SkLazyPaint;
482c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Helpers for computing fast bounds for quickReject tests
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic SkCanvas::EdgeType paint2EdgeType(const SkPaint* paint) {
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return paint != NULL && paint->isAntiAlias() ?
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType;
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*  This is the record we keep for each SkDevice that the user installs.
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    The clip/matrix/proc are fields that reflect the top of the save/restore
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    stack. Whenever the canvas changes, it marks a dirty flag, and then before
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    these are used (assuming we're not on a layer) we rebuild these cache
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    values: they reflect the top of the save stack, but translated and clipped
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    by the device's XY offset and bitmap-bounds.
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstruct DeviceCM {
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DeviceCM*           fNext;
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDevice*           fDevice;
69045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    SkRasterClip        fClip;
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkMatrix*     fMatrix;
716f8f292aa768869a9e85c314b124875f57504f2creed@google.com    SkPaint*            fPaint; // may be null (in the future)
72f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    // optional, related to canvas' external matrix
73f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    const SkMatrix*     fMVMatrix;
74f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    const SkMatrix*     fExtMatrix;
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7688edf1e50794e6d8cd7cc671ffce4f5e329ef888bungeman@google.com    DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint)
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            : fNext(NULL) {
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (NULL != device) {
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            device->ref();
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            device->lockPixels();
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
824b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com        fDevice = device;
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
8488edf1e50794e6d8cd7cc671ffce4f5e329ef888bungeman@google.com    }
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8688edf1e50794e6d8cd7cc671ffce4f5e329ef888bungeman@google.com    ~DeviceCM() {
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (NULL != fDevice) {
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fDevice->unlockPixels();
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fDevice->unref();
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
9188edf1e50794e6d8cd7cc671ffce4f5e329ef888bungeman@google.com        SkDELETE(fPaint);
9288edf1e50794e6d8cd7cc671ffce4f5e329ef888bungeman@google.com    }
934b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
94045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
95045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com                  const SkClipStack& clipStack, SkRasterClip* updateClip) {
966f8f292aa768869a9e85c314b124875f57504f2creed@google.com        int x = fDevice->getOrigin().x();
976f8f292aa768869a9e85c314b124875f57504f2creed@google.com        int y = fDevice->getOrigin().y();
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int width = fDevice->width();
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int height = fDevice->height();
1004b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if ((x | y) == 0) {
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fMatrix = &totalMatrix;
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fClip = totalClip;
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fMatrixStorage = totalMatrix;
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fMatrixStorage.postTranslate(SkIntToScalar(-x),
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                         SkIntToScalar(-y));
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fMatrix = &fMatrixStorage;
1094b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            totalClip.translate(-x, -y, &fClip);
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
113045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // intersect clip, but don't translate it (yet)
1164b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (updateClip) {
118045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com            updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                           SkRegion::kDifference_Op);
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1214b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
122045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (!fClip.isEmpty()) {
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkIRect deviceR;
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            deviceR.set(0, 0, width, height);
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(deviceR.contains(fClip.getBounds()));
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
131f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        // default is to assume no external matrix
132f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        fMVMatrix = NULL;
133f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        fExtMatrix = NULL;
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
135f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com
136f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    // can only be called after calling updateMC()
137f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    void updateExternalMatrix(const SkMatrix& extM, const SkMatrix& extI) {
138f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        fMVMatrixStorage.setConcat(extI, *fMatrix);
139f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        fMVMatrix = &fMVMatrixStorage;
140f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        fExtMatrix = &extM; // assumes extM has long life-time (owned by canvas)
141f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    }
142f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
144f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    SkMatrix    fMatrixStorage, fMVMatrixStorage;
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*  This is the record we keep for each save/restore level in the stack.
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Since a level optionally copies the matrix and/or stack, we have pointers
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for these fields. If the value is copied for this level, the copy is
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    stored in the ...Storage field, and the pointer points to that. If the
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    value is not copied for this level, we ignore ...Storage, and just point
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    at the corresponding value in the previous level in the stack.
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkCanvas::MCRec {
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    MCRec*          fNext;
1570017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    SkMatrix*       fMatrix;        // points to either fMatrixStorage or prev MCRec
1580017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    SkRasterClip*   fRasterClip;    // points to either fRegionStorage or prev MCRec
1590017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    SkDrawFilter*   fFilter;        // the current filter (or null)
1604b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DeviceCM*   fLayer;
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /*  If there are any layers in the stack, this points to the top-most
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        one that is at or below this level in the stack (so we know what
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        bitmap/device to draw into from this level. This value is NOT
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        reference counted, since the real owner is either our fLayer field,
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        or a previous one in a lower level.)
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
16888edf1e50794e6d8cd7cc671ffce4f5e329ef888bungeman@google.com    DeviceCM*   fTopLayer;
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    MCRec(const MCRec* prev, int flags) {
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (NULL != prev) {
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (flags & SkCanvas::kMatrix_SaveFlag) {
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fMatrixStorage = *prev->fMatrix;
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fMatrix = &fMatrixStorage;
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else {
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fMatrix = prev->fMatrix;
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1784b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (flags & SkCanvas::kClip_SaveFlag) {
1800017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com                fRasterClipStorage = *prev->fRasterClip;
1810017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com                fRasterClip = &fRasterClipStorage;
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else {
1830017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com                fRasterClip = prev->fRasterClip;
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fFilter = prev->fFilter;
18782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            SkSafeRef(fFilter);
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fTopLayer = prev->fTopLayer;
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {   // no prev
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fMatrixStorage.reset();
1924b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fMatrix     = &fMatrixStorage;
1940017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            fRasterClip = &fRasterClipStorage;
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fFilter     = NULL;
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fTopLayer   = NULL;
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fLayer = NULL;
1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // don't bother initializing fNext
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        inc_rec();
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ~MCRec() {
20482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        SkSafeUnref(fFilter);
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDELETE(fLayer);
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dec_rec();
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2084b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
2100017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    SkMatrix        fMatrixStorage;
2110017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    SkRasterClip    fRasterClipStorage;
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkDrawIter : public SkDraw {
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
2168a0b0291ae4260ef2a46f4341c18a702c0ce3f8btomhudson@google.com    SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
2174370aedf7f55af74e9ebb4ad1c2e010c08236dfajunov@google.com        canvas = canvas->canvasForDrawIter();
2188a0b0291ae4260ef2a46f4341c18a702c0ce3f8btomhudson@google.com        fCanvas = canvas;
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        canvas->updateDeviceCMCache();
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
22190c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com        fClipStack = &canvas->fClipStack;
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBounder = canvas->getBounder();
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrLayer = canvas->fMCRec->fTopLayer;
2248a0b0291ae4260ef2a46f4341c18a702c0ce3f8btomhudson@google.com        fSkipEmptyClips = skipEmptyClips;
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2264b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool next() {
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // skip over recs with empty clips
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fSkipEmptyClips) {
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fCurrLayer = fCurrLayer->fNext;
2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
235f68c5e2f9f05b3af2bae0979ace2684b6041b6e3reed@google.com        const DeviceCM* rec = fCurrLayer;
236f68c5e2f9f05b3af2bae0979ace2684b6041b6e3reed@google.com        if (rec && rec->fDevice) {
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fMatrix = rec->fMatrix;
239045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com            fClip   = &((SkRasterClip*)&rec->fClip)->forceGetBW();
240045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com            fRC     = &rec->fClip;
2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fDevice = rec->fDevice;
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fBitmap = &fDevice->accessBitmap(true);
2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fPaint  = rec->fPaint;
244f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com            fMVMatrix = rec->fMVMatrix;
245f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com            fExtMatrix = rec->fExtMatrix;
246f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com            SkDEBUGCODE(this->validate();)
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fCurrLayer = rec->fNext;
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (fBounder) {
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fBounder->setClip(fClip);
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // fCurrLayer may be NULL now
253199f108f14a5f60a9c2205ffa79b26102a206ad0reed@android.com
254d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com            fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip, *fClipStack);
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return true;
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2594b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDevice* getDevice() const { return fDevice; }
2616f8f292aa768869a9e85c314b124875f57504f2creed@google.com    int getX() const { return fDevice->getOrigin().x(); }
2626f8f292aa768869a9e85c314b124875f57504f2creed@google.com    int getY() const { return fDevice->getOrigin().y(); }
2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkMatrix& getMatrix() const { return *fMatrix; }
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkRegion& getClip() const { return *fClip; }
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkPaint* getPaint() const { return fPaint; }
2666f8f292aa768869a9e85c314b124875f57504f2creed@google.com
2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
2688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkCanvas*       fCanvas;
2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const DeviceCM* fCurrLayer;
2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkPaint*  fPaint;     // May be null.
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBool8         fSkipEmptyClips;
2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    typedef SkDraw INHERITED;
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass AutoDrawLooper {
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
2808926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint,
2818926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com                   bool skipLayerForImageFilter = false) : fOrigPaint(paint) {
2824e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fCanvas = canvas;
2834e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fLooper = paint.getLooper();
2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fFilter = canvas->getDrawFilter();
2854e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fPaint = NULL;
2864e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fSaveCount = canvas->getSaveCount();
2878926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        fDoClearImageFilter = false;
2884e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fDone = false;
2898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2908926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
2918926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            SkPaint tmp;
2928926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            tmp.setImageFilter(fOrigPaint.getImageFilter());
2938926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            // it would be nice if we had a guess at the bounds, instead of null
2948926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            (void)canvas->internalSaveLayer(NULL, &tmp,
2958926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com                                    SkCanvas::kARGB_ClipLayer_SaveFlag, true);
2968926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            // we'll clear the imageFilter for the actual draws in next(), so
2978926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            // it will only be applied during the restore().
2988926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            fDoClearImageFilter = true;
2998926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        }
3008926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com
3014e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        if (fLooper) {
3024e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            fLooper->init(canvas);
3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
3048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
30574b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
3064e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    ~AutoDrawLooper() {
3078926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        if (fDoClearImageFilter) {
3088926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            fCanvas->internalRestore();
3098926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        }
3104e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        SkASSERT(fCanvas->getSaveCount() == fSaveCount);
3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
31274b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
3134e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    const SkPaint& paint() const {
3144e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        SkASSERT(fPaint);
3154e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        return *fPaint;
3164e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    }
31774b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
3184e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    bool next(SkDrawFilter::Type drawType);
31974b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
3212c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    SkLazyPaint     fLazyPaint;
3222c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    SkCanvas*       fCanvas;
3232c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    const SkPaint&  fOrigPaint;
3242c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    SkDrawLooper*   fLooper;
3252c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    SkDrawFilter*   fFilter;
3262c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    const SkPaint*  fPaint;
3272c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    int             fSaveCount;
3288926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    bool            fDoClearImageFilter;
3292c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    bool            fDone;
3308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3324e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.combool AutoDrawLooper::next(SkDrawFilter::Type drawType) {
333632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com    fPaint = NULL;
3344e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    if (fDone) {
3354e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        return false;
3364e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    }
337632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com
3388926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    if (fLooper || fFilter || fDoClearImageFilter) {
339632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com        SkPaint* paint = fLazyPaint.set(fOrigPaint);
3408926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com
3418926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        if (fDoClearImageFilter) {
3428926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            paint->setImageFilter(NULL);
3438926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        }
3448926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com
345632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com        if (fLooper && !fLooper->next(fCanvas, paint)) {
346632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com            fDone = true;
347632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com            return false;
348632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com        }
349632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com        if (fFilter) {
350632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com            fFilter->filter(paint, drawType);
351632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com            if (NULL == fLooper) {
352632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com                // no looper means we only draw once
353632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com                fDone = true;
354632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com            }
355632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com        }
356632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com        fPaint = paint;
3578926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com
3588926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        // if we only came in here for the imagefilter, mark us as done
3598926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        if (!fLooper && !fFilter) {
3608926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            fDone = true;
3618926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        }
362632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com    } else {
3634e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fDone = true;
3644e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fPaint = &fOrigPaint;
3654e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    }
3664e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com
367632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com    // call this after any possible paint modifiers
368632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com    if (fPaint->nothingToDraw()) {
3694e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fPaint = NULL;
3704e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        return false;
3714e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    }
3724e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    return true;
3734e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com}
3744e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com
3758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*  Stack helper for managing a SkBounder. In the destructor, if we were
3768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    given a bounder, we call its commit() method, signifying that we are
3778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    done accumulating bounds for that draw.
3788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
3798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkAutoBounderCommit {
3808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
3818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {}
3828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ~SkAutoBounderCommit() {
3838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (NULL != fBounder) {
3848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fBounder->commit();
3858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
3868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBounder*  fBounder;
3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h"
3928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass AutoValidator {
3948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    AutoValidator(SkDevice* device) : fDevice(device) {}
3968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ~AutoValidator() {
3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const SkBitmap& bm = fDevice->accessBitmap(false);
3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (bm.config() == SkBitmap::kARGB_4444_Config) {
4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            for (int y = 0; y < bm.height(); y++) {
4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                const SkPMColor16* p = bm.getAddr16(0, y);
4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                for (int x = 0; x < bm.width(); x++) {
4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    SkPMColor16 c = p[x];
4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    SkPMColor16Assert(c);
4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
4118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDevice* fDevice;
4128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////// macros to place around the internal draw calls //////////////////
4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4168926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com#define LOOPER_BEGIN_DRAWDEVICE(paint, type)                        \
4178926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com/*    AutoValidator   validator(fMCRec->fTopLayer->fDevice); */     \
4188926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    AutoDrawLooper  looper(this, paint, true);                      \
4198926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    while (looper.next(type)) {                                     \
4208926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        SkAutoBounderCommit ac(fBounder);                           \
4218926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        SkDrawIter          iter(this);
4228926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com
4234e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com#define LOOPER_BEGIN(paint, type)                                   \
4248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*    AutoValidator   validator(fMCRec->fTopLayer->fDevice); */     \
4254e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    AutoDrawLooper  looper(this, paint);                            \
4264e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    while (looper.next(type)) {                                     \
4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAutoBounderCommit ac(fBounder);                           \
4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDrawIter          iter(this);
4294b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
4304e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com#define LOOPER_END    }
4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////////
4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDevice* SkCanvas::init(SkDevice* device) {
4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fBounder = NULL;
4363c898186c9082c535e589807752a0a9dc5d28aa0vandebo@chromium.org    fLocalBoundsCompareType.setEmpty();
4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
4383c898186c9082c535e589807752a0a9dc5d28aa0vandebo@chromium.org    fLocalBoundsCompareTypeBW.setEmpty();
439ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
440199f108f14a5f60a9c2205ffa79b26102a206ad0reed@android.com    fLastDeviceToGainFocus = NULL;
441447bcfa8898ce10e7b6493ba9e3e23e08bd13f01agl@chromium.org    fDeviceCMDirty = false;
442b0a7ace7cb2a7559bbc254a7c93698bc71bbd245junov@chromium.org    fSaveLayerCount = 0;
4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec = (MCRec*)fMCStack.push_back();
4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    new (fMCRec) MCRec(NULL, 0);
4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL));
4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->fTopLayer = fMCRec->fLayer;
4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->fNext = NULL;
4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4513c898186c9082c535e589807752a0a9dc5d28aa0vandebo@chromium.org    fExternalMatrix.reset();
4523c898186c9082c535e589807752a0a9dc5d28aa0vandebo@chromium.org    fExternalInverse.reset();
453f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    fUseExternalMatrix = false;
454f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com
4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return this->setDevice(device);
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
458cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.comSkCanvas::SkCanvas()
459cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
4608d84fac294682647694b0d2d8a87ac2bd19b6aabvandebo@chromium.org    inc_canvas();
46174b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
4628d84fac294682647694b0d2d8a87ac2bd19b6aabvandebo@chromium.org    this->init(NULL);
4638d84fac294682647694b0d2d8a87ac2bd19b6aabvandebo@chromium.org}
4648d84fac294682647694b0d2d8a87ac2bd19b6aabvandebo@chromium.org
4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCanvas::SkCanvas(SkDevice* device)
466ea4ac97dec2eb291139bd906939e0d2e05cdd7efmike@reedtribe.org        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    inc_canvas();
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->init(device);
4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCanvas::SkCanvas(const SkBitmap& bitmap)
4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    inc_canvas();
4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
476cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com    this->init(SkNEW_ARGS(SkDevice, (bitmap)))->unref();
4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCanvas::~SkCanvas() {
4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // free up the contents of our deque
4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->restoreToCount(1);    // restore everything but the last
482b0a7ace7cb2a7559bbc254a7c93698bc71bbd245junov@chromium.org    SkASSERT(0 == fSaveLayerCount);
4837c2029367cea5479fa3b74fb0ca2b0297b42b709reed@google.com
4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->internalRestore();    // restore the last, since we're going away
4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4868d84fac294682647694b0d2d8a87ac2bd19b6aabvandebo@chromium.org    SkSafeUnref(fBounder);
487b70ae310bbdaa1b26786773aabce5548c1f48563vandebo@chromium.org
4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dec_canvas();
4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkBounder* SkCanvas::setBounder(SkBounder* bounder) {
4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt_SafeAssign(fBounder, bounder);
4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return bounder;
4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDrawFilter* SkCanvas::getDrawFilter() const {
4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCRec->fFilter;
4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return filter;
5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
507bf6c1e4aff4d233f6502157fb73459cf69d0ab37junov@chromium.orgvoid SkCanvas::flush() {
508bf6c1e4aff4d233f6502157fb73459cf69d0ab37junov@chromium.org    SkDevice* device = this->getDevice();
509bf6c1e4aff4d233f6502157fb73459cf69d0ab37junov@chromium.org    if (device) {
510bf6c1e4aff4d233f6502157fb73459cf69d0ab37junov@chromium.org        device->flush();
511bf6c1e4aff4d233f6502157fb73459cf69d0ab37junov@chromium.org    }
512bf6c1e4aff4d233f6502157fb73459cf69d0ab37junov@chromium.org}
513bf6c1e4aff4d233f6502157fb73459cf69d0ab37junov@chromium.org
514210ce003a5ec039dda80de0569fb47ca4efc4dc7reed@google.comSkISize SkCanvas::getDeviceSize() const {
515210ce003a5ec039dda80de0569fb47ca4efc4dc7reed@google.com    SkDevice* d = this->getDevice();
516210ce003a5ec039dda80de0569fb47ca4efc4dc7reed@google.com    return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
517210ce003a5ec039dda80de0569fb47ca4efc4dc7reed@google.com}
518210ce003a5ec039dda80de0569fb47ca4efc4dc7reed@google.com
5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDevice* SkCanvas::getDevice() const {
5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // return root device
5214c09d5cd4b9e6f0be1352f62288efdedc1bc3de3reed@google.com    SkDeque::F2BIter iter(fMCStack);
5224c09d5cd4b9e6f0be1352f62288efdedc1bc3de3reed@google.com    MCRec*           rec = (MCRec*)iter.next();
5238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(rec && rec->fLayer);
5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return rec->fLayer->fDevice;
5258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5270b53d59a24f667350b4282f88470713902409030reed@google.comSkDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
5280b53d59a24f667350b4282f88470713902409030reed@google.com    if (updateMatrixClip) {
5290b53d59a24f667350b4282f88470713902409030reed@google.com        const_cast<SkCanvas*>(this)->updateDeviceCMCache();
5300b53d59a24f667350b4282f88470713902409030reed@google.com    }
5319266fed56a46a4edc710a52c7be8d46fd7c2bc7areed@google.com    return fMCRec->fTopLayer->fDevice;
5329266fed56a46a4edc710a52c7be8d46fd7c2bc7areed@google.com}
5339266fed56a46a4edc710a52c7be8d46fd7c2bc7areed@google.com
5348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDevice* SkCanvas::setDevice(SkDevice* device) {
5358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // return root device
5364c09d5cd4b9e6f0be1352f62288efdedc1bc3de3reed@google.com    SkDeque::F2BIter iter(fMCStack);
5374c09d5cd4b9e6f0be1352f62288efdedc1bc3de3reed@google.com    MCRec*           rec = (MCRec*)iter.next();
5388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(rec && rec->fLayer);
5398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDevice*       rootDevice = rec->fLayer->fDevice;
5408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (rootDevice == device) {
5428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return device;
5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5444b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /* Notify the devices that they are going in/out of scope, so they can do
5468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com       things like lock/unlock their pixels, etc.
5478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
5488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (device) {
5498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        device->lockPixels();
5508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (rootDevice) {
5528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        rootDevice->unlockPixels();
5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rootDevice = device;
5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
5594b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
5608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /*  Now we update our initial region to have the bounds of the new device,
5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        and then intersect all of the clips in our stack with these bounds,
5628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        to ensure that we can't draw outside of the device's bounds (and trash
5638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                                                     memory).
5644b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    NOTE: this is only a partial-fix, since if the new device is larger than
5668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        the previous one, we don't know how to "enlarge" the clips in our stack,
5674b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com        so drawing may be artificially restricted. Without keeping a history of
5688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
5698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        reconstruct the correct clips, so this approximation will have to do.
5708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        The caller really needs to restore() back to the base if they want to
5718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        accurately take advantage of the new device bounds.
5728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
5738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
57442aea289cbf801997b653a906a37a7f7e948b645reed@google.com    SkIRect bounds;
57542aea289cbf801997b653a906a37a7f7e948b645reed@google.com    if (device) {
5768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        bounds.set(0, 0, device->width(), device->height());
57742aea289cbf801997b653a906a37a7f7e948b645reed@google.com    } else {
57842aea289cbf801997b653a906a37a7f7e948b645reed@google.com        bounds.setEmpty();
5798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
58042aea289cbf801997b653a906a37a7f7e948b645reed@google.com    // now jam our 1st clip to be bounds, and intersect the rest with that
58142aea289cbf801997b653a906a37a7f7e948b645reed@google.com    rec->fRasterClip->setRect(bounds);
58242aea289cbf801997b653a906a37a7f7e948b645reed@google.com    while ((rec = (MCRec*)iter.next()) != NULL) {
58342aea289cbf801997b653a906a37a7f7e948b645reed@google.com        (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op);
58442aea289cbf801997b653a906a37a7f7e948b645reed@google.com    }
58542aea289cbf801997b653a906a37a7f7e948b645reed@google.com
5868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return device;
5878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
589af951c9bc4cbb6e60b430194fe5127ebe99c53fbreed@google.comSkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) {
590af951c9bc4cbb6e60b430194fe5127ebe99c53fbreed@google.com    SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap)));
5918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    device->unref();
5928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return device;
5938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5956850eab42ba4c2a7033a99824b02a2846ce0ef2absalomon@google.combool SkCanvas::readPixels(SkBitmap* bitmap,
5966850eab42ba4c2a7033a99824b02a2846ce0ef2absalomon@google.com                          int x, int y,
5976850eab42ba4c2a7033a99824b02a2846ce0ef2absalomon@google.com                          Config8888 config8888) {
59851df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    SkDevice* device = this->getDevice();
59951df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    if (!device) {
60051df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com        return false;
60151df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    }
6026850eab42ba4c2a7033a99824b02a2846ce0ef2absalomon@google.com    return device->readPixels(bitmap, x, y, config8888);
60351df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com}
60451df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com
605c69809745e6496564639e42ef998ad39adf7dfb8bsalomon@google.combool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
606ace7bd5623354ffabbd224d5b76550bab159c296bsalomon@google.com    SkDevice* device = this->getDevice();
60774b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
608daba14b7d4fc96b915c45d82713b22729c0d0f37bsalomon@google.com    SkIRect bounds;
609c69809745e6496564639e42ef998ad39adf7dfb8bsalomon@google.com    bounds.set(0, 0, device->width(), device->height());
610daba14b7d4fc96b915c45d82713b22729c0d0f37bsalomon@google.com    if (!bounds.intersect(srcRect)) {
611daba14b7d4fc96b915c45d82713b22729c0d0f37bsalomon@google.com        return false;
612c69809745e6496564639e42ef998ad39adf7dfb8bsalomon@google.com    }
613c69809745e6496564639e42ef998ad39adf7dfb8bsalomon@google.com
614c69809745e6496564639e42ef998ad39adf7dfb8bsalomon@google.com    SkBitmap tmp;
615c69809745e6496564639e42ef998ad39adf7dfb8bsalomon@google.com    tmp.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(),
616c69809745e6496564639e42ef998ad39adf7dfb8bsalomon@google.com                                               bounds.height());
617c69809745e6496564639e42ef998ad39adf7dfb8bsalomon@google.com    if (this->readPixels(&tmp, bounds.fLeft, bounds.fTop)) {
618c69809745e6496564639e42ef998ad39adf7dfb8bsalomon@google.com        bitmap->swap(tmp);
619c69809745e6496564639e42ef998ad39adf7dfb8bsalomon@google.com        return true;
620c69809745e6496564639e42ef998ad39adf7dfb8bsalomon@google.com    } else {
62151df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com        return false;
62251df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    }
62351df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com}
62451df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com
625d58a1cd00b969a7755c375f55cf80f4d49d3047bbsalomon@google.comvoid SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y,
626d58a1cd00b969a7755c375f55cf80f4d49d3047bbsalomon@google.com                           Config8888 config8888) {
62751df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    SkDevice* device = this->getDevice();
62851df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    if (device) {
629d58a1cd00b969a7755c375f55cf80f4d49d3047bbsalomon@google.com        device->writePixels(bitmap, x, y, config8888);
63051df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    }
63151df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com}
63251df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com
6334370aedf7f55af74e9ebb4ad1c2e010c08236dfajunov@google.comSkCanvas* SkCanvas::canvasForDrawIter() {
6344370aedf7f55af74e9ebb4ad1c2e010c08236dfajunov@google.com    return this;
6354370aedf7f55af74e9ebb4ad1c2e010c08236dfajunov@google.com}
6364370aedf7f55af74e9ebb4ad1c2e010c08236dfajunov@google.com
6378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
6388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::updateDeviceCMCache() {
6408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fDeviceCMDirty) {
6418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const SkMatrix& totalMatrix = this->getTotalMatrix();
642045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        const SkRasterClip& totalClip = *fMCRec->fRasterClip;
6438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        DeviceCM*       layer = fMCRec->fTopLayer;
6444b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
6458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (NULL == layer->fNext) {   // only one layer
64646799cd9f0bded51a189d77731b25af159ab4609reed@google.com            layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
647f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com            if (fUseExternalMatrix) {
648f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                layer->updateExternalMatrix(fExternalMatrix,
649f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                                            fExternalInverse);
650f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com            }
6518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
652045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com            SkRasterClip clip(totalClip);
6538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            do {
65446799cd9f0bded51a189d77731b25af159ab4609reed@google.com                layer->updateMC(totalMatrix, clip, fClipStack, &clip);
655f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                if (fUseExternalMatrix) {
656f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                    layer->updateExternalMatrix(fExternalMatrix,
657f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                                                fExternalInverse);
658f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                }
6598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } while ((layer = layer->fNext) != NULL);
6608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fDeviceCMDirty = false;
6628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
665f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comvoid SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix,
666d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com                                    const SkRegion& clip,
667d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com                                    const SkClipStack& clipStack) {
6688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(device);
669199f108f14a5f60a9c2205ffa79b26102a206ad0reed@android.com    if (fLastDeviceToGainFocus != device) {
670d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com        device->gainFocus(this, matrix, clip, clipStack);
671199f108f14a5f60a9c2205ffa79b26102a206ad0reed@android.com        fLastDeviceToGainFocus = device;
672199f108f14a5f60a9c2205ffa79b26102a206ad0reed@android.com    }
6738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
6768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCanvas::internalSave(SaveFlags flags) {
6788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int saveCount = this->getSaveCount(); // record this before the actual save
6794b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
6808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    MCRec* newTop = (MCRec*)fMCStack.push_back();
6818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    new (newTop) MCRec(fMCRec, flags);    // balanced in restore()
6824b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
6838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    newTop->fNext = fMCRec;
6848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec = newTop;
6854b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
6865c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    fClipStack.save();
6875c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
6885c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
6898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return saveCount;
6908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCanvas::save(SaveFlags flags) {
6938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // call shared impl
6948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return this->internalSave(flags);
6958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define C32MASK (1 << SkBitmap::kARGB_8888_Config)
6988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define C16MASK (1 << SkBitmap::kRGB_565_Config)
6998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define C8MASK  (1 << SkBitmap::kA8_Config)
7008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic SkBitmap::Config resolve_config(SkCanvas* canvas,
7028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                       const SkIRect& bounds,
7038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                       SkCanvas::SaveFlags flags,
7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                       bool* isOpaque) {
7058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0;
7068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if 0
7088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // loop through and union all the configs we may draw into
7098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t configMask = 0;
7108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int i = canvas->countLayerDevices() - 1; i >= 0; --i)
7118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
7128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDevice* device = canvas->getLayerDevice(i);
7138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (device->intersects(bounds))
7148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            configMask |= 1 << device->config();
7158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // if the caller wants alpha or fullcolor, we can't return 565
7188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (flags & (SkCanvas::kFullColorLayer_SaveFlag |
7198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                 SkCanvas::kHasAlphaLayer_SaveFlag))
7208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        configMask &= ~C16MASK;
7218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    switch (configMask) {
7238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    case C8MASK:    // if we only have A8, return that
7248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return SkBitmap::kA8_Config;
7258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    case C16MASK:   // if we only have 565, return that
7278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return SkBitmap::kRGB_565_Config;
7288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    default:
7308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return SkBitmap::kARGB_8888_Config; // default answer
7318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
7338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkBitmap::kARGB_8888_Config; // default answer
7348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
7358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
7388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
7398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
741a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.orgbool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
742a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org                               SkIRect* intersection) {
743bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    SkIRect clipBounds;
744bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    if (!this->getClipDeviceBounds(&clipBounds)) {
745a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org        return false;
746f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    }
747bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    SkIRect ir;
7488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL != bounds) {
7498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRect r;
7504b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
7518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->getTotalMatrix().mapRect(&r, *bounds);
7528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        r.roundOut(&ir);
7538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // early exit if the layer's bounds are clipped out
7548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (!ir.intersect(clipBounds)) {
755bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com            if (bounds_affects_clip(flags)) {
7560017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com                fMCRec->fRasterClip->setEmpty();
757bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com            }
758a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org            return false;
7598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
7608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {    // no user bounds, so just use the clip
7618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        ir = clipBounds;
7628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7645c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op);
765a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org
7668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // early exit if the clip is now empty
7678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (bounds_affects_clip(flags) &&
7680017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com        !fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) {
769a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org        return false;
770a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org    }
771a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org
772a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org    if (intersection) {
773a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org        *intersection = ir;
774a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org    }
775a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org    return true;
776a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org}
777a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org
778a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.orgint SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
779a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org                        SaveFlags flags) {
7808926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    return this->internalSaveLayer(bounds, paint, flags, false);
7818926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com}
7828926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com
7838926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.comint SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint,
7848926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com                                SaveFlags flags, bool justForImageFilter) {
785a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org    // do this before we create the layer. We don't call the public save() since
786a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org    // that would invoke a possibly overridden virtual
787a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org    int count = this->internalSave(flags);
788a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org
789a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org    fDeviceCMDirty = true;
790a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org
791a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org    SkIRect ir;
792a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org    if (!this->clipRectBounds(bounds, flags, &ir)) {
7938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return count;
7948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
796b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com    // Kill the imagefilter if our device doesn't allow it
797b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com    SkLazyPaint lazyP;
798b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com    if (paint && paint->getImageFilter()) {
799b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com        if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
8008926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            if (justForImageFilter) {
8018926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com                // early exit if the layer was just for the imageFilter
8028926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com                return count;
8038926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            }
804b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com            SkPaint* p = lazyP.set(*paint);
805b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com            p->setImageFilter(NULL);
806b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com            paint = p;
807b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com        }
808b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com    }
809b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com
8108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool isOpaque;
8118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque);
8128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
81376dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com    SkDevice* device;
81476dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com    if (paint && paint->getImageFilter()) {
81576dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com        device = this->createCompatibleDevice(config, ir.width(), ir.height(),
81676dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com                                              isOpaque);
81776dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com    } else {
81876dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com        device = this->createLayerDevice(config, ir.width(), ir.height(),
81976dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com                                         isOpaque);
82076dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com    }
821e25c68402b38ac01dc1ae196ae8a5265b773c5f2bungeman@google.com    if (NULL == device) {
822e25c68402b38ac01dc1ae196ae8a5265b773c5f2bungeman@google.com        SkDebugf("Unable to create device for layer.");
823e25c68402b38ac01dc1ae196ae8a5265b773c5f2bungeman@google.com        return count;
824e25c68402b38ac01dc1ae196ae8a5265b773c5f2bungeman@google.com    }
825e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com
8266f8f292aa768869a9e85c314b124875f57504f2creed@google.com    device->setOrigin(ir.fLeft, ir.fTop);
8278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint));
8288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    device->unref();
8298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    layer->fNext = fMCRec->fTopLayer;
8318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->fLayer = layer;
8328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->fTopLayer = layer;    // this field is NOT an owner of layer
8338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
834b0a7ace7cb2a7559bbc254a7c93698bc71bbd245junov@chromium.org    fSaveLayerCount += 1;
8358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return count;
8368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
8398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                             SaveFlags flags) {
8408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (0xFF == alpha) {
8418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->saveLayer(bounds, NULL, flags);
8428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
8438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPaint tmpPaint;
8448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        tmpPaint.setAlpha(alpha);
8458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->saveLayer(bounds, &tmpPaint, flags);
8468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::restore() {
8508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // check for underflow
8518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fMCStack.count() > 1) {
8528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->internalRestore();
8538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::internalRestore() {
8578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(fMCStack.count() != 0);
8588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
8608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
861ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
8628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8635c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    fClipStack.restore();
86488edf1e50794e6d8cd7cc671ffce4f5e329ef888bungeman@google.com    // reserve our layer (if any)
8658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DeviceCM* layer = fMCRec->fLayer;   // may be null
8668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // now detach it from fMCRec so we can pop(). Gets freed after its drawn
8678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->fLayer = NULL;
8688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // now do the normal restore()
8708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->~MCRec();       // balanced in save()
8718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCStack.pop_back();
8728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec = (MCRec*)fMCStack.back();
8738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /*  Time to draw the layer's offscreen. We can't call the public drawSprite,
8758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        since if we're being recorded, we don't want to record this (the
8768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        recorder will have already recorded the restore).
8778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
8788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL != layer) {
8798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (layer->fNext) {
8806f8f292aa768869a9e85c314b124875f57504f2creed@google.com            const SkIPoint& origin = layer->fDevice->getOrigin();
8818926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
8828926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com                                     layer->fPaint);
8838926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            // reset this, since internalDrawDevice will have set it to true
8848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fDeviceCMDirty = true;
8857c2029367cea5479fa3b74fb0ca2b0297b42b709reed@google.com
886b0a7ace7cb2a7559bbc254a7c93698bc71bbd245junov@chromium.org            SkASSERT(fSaveLayerCount > 0);
887b0a7ace7cb2a7559bbc254a7c93698bc71bbd245junov@chromium.org            fSaveLayerCount -= 1;
8888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
8898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDELETE(layer);
89088edf1e50794e6d8cd7cc671ffce4f5e329ef888bungeman@google.com    }
8915c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
8925c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
8938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCanvas::getSaveCount() const {
8968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCStack.count();
8978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::restoreToCount(int count) {
9008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // sanity check
9018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count < 1) {
9028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        count = 1;
9038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
90474b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
905b9d1c6a3c43a2cbcbd612f4ec4aaf604a1fa6444reed@google.com    int n = this->getSaveCount() - count;
906b9d1c6a3c43a2cbcbd612f4ec4aaf604a1fa6444reed@google.com    for (int i = 0; i < n; ++i) {
9078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->restore();
9088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9117c2029367cea5479fa3b74fb0ca2b0297b42b709reed@google.combool SkCanvas::isDrawingToLayer() const {
912b0a7ace7cb2a7559bbc254a7c93698bc71bbd245junov@chromium.org    return fSaveLayerCount > 0;
9137c2029367cea5479fa3b74fb0ca2b0297b42b709reed@google.com}
9147c2029367cea5479fa3b74fb0ca2b0297b42b709reed@google.com
9158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////
9168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// can't draw it if its empty, or its too big for a fixed-point width or height
9188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic bool reject_bitmap(const SkBitmap& bitmap) {
919a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com    return  bitmap.width() <= 0 || bitmap.height() <= 0
920a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com#ifndef SK_ALLOW_OVER_32K_BITMAPS
921a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com            || bitmap.width() > 32767 || bitmap.height() > 32767
922a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com#endif
923a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com            ;
9248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
926f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comvoid SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
9278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                const SkMatrix& matrix, const SkPaint* paint) {
9288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (reject_bitmap(bitmap)) {
9298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
9308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9322c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    SkLazyPaint lazy;
9338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL == paint) {
9342c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org        paint = lazy.init();
9358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9362c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    this->commonDrawBitmap(bitmap, srcRect, matrix, *paint);
9378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
93976dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com#include "SkImageFilter.h"
94076dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com
94176dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.comclass DeviceImageFilterProxy : public SkImageFilter::Proxy {
94276dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.compublic:
94376dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com    DeviceImageFilterProxy(SkDevice* device) : fDevice(device) {}
94474b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
9458926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE {
9468926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
9478926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com                                               w, h, false);
9488926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    }
9498926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    virtual bool canHandleImageFilter(SkImageFilter* filter) SK_OVERRIDE {
9508926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        return fDevice->canHandleImageFilter(filter);
9518926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    }
9528926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    virtual bool filterImage(SkImageFilter* filter, const SkBitmap& src,
95376dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com                             const SkMatrix& ctm,
9548926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com                             SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
9558926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        return fDevice->filterImage(filter, src, ctm, result, offset);
9568926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    }
9578926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com
95876dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.comprivate:
95976dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com    SkDevice* fDevice;
96076dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com};
96176dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com
9628926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.comvoid SkCanvas::internalDrawDevice(SkDevice* srcDev, int x, int y,
9638926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com                                  const SkPaint* paint) {
9648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPaint tmp;
9658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL == paint) {
9668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        tmp.setDither(true);
9678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        paint = &tmp;
9688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9694b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
9708926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
9718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
972b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com        SkDevice* dstDev = iter.fDevice;
97376dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com        paint = &looper.paint();
97476dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com        SkImageFilter* filter = paint->getImageFilter();
97576dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com        SkIPoint pos = { x - iter.getX(), y - iter.getY() };
9768926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        if (filter && !dstDev->canHandleImageFilter(filter)) {
977b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com            DeviceImageFilterProxy proxy(dstDev);
97876dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com            SkBitmap dst;
979b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com            const SkBitmap& src = srcDev->accessBitmap(false);
98076dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com            if (filter->filterImage(&proxy, src, *iter.fMatrix, &dst, &pos)) {
9815efe0cb04961ef98fbe520ee732fbe50b4195ad3tomhudson@google.com                SkPaint tmpUnfiltered(*paint);
9825efe0cb04961ef98fbe520ee732fbe50b4195ad3tomhudson@google.com                tmpUnfiltered.setImageFilter(NULL);
9835efe0cb04961ef98fbe520ee732fbe50b4195ad3tomhudson@google.com                dstDev->drawSprite(iter, dst, pos.x(), pos.y(), tmpUnfiltered);
98476dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com            }
98576dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com        } else {
986b55deeb1c7c692023603639a9b29c0e3de124eacreed@google.com            dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
98776dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com        }
9888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9894e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
9908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9928926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.comvoid SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
9938926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com                          const SkPaint* paint) {
9948926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    SkDEBUGCODE(bitmap.validate();)
9958926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com
9968926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    if (reject_bitmap(bitmap)) {
9978926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        return;
9988926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    }
9998926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com
10008926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    SkPaint tmp;
10018926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    if (NULL == paint) {
10028926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        paint = &tmp;
10038926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    }
10048926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com
10058926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
10068926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com
10078926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    while (iter.next()) {
10088926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        paint = &looper.paint();
10098926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        SkImageFilter* filter = paint->getImageFilter();
10108926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        SkIPoint pos = { x - iter.getX(), y - iter.getY() };
10118926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
10128926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            DeviceImageFilterProxy proxy(iter.fDevice);
10138926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            SkBitmap dst;
10145efe0cb04961ef98fbe520ee732fbe50b4195ad3tomhudson@google.com            if (filter->filterImage(&proxy, bitmap, *iter.fMatrix,
10155efe0cb04961ef98fbe520ee732fbe50b4195ad3tomhudson@google.com                                    &dst, &pos)) {
10165efe0cb04961ef98fbe520ee732fbe50b4195ad3tomhudson@google.com                SkPaint tmpUnfiltered(*paint);
10175efe0cb04961ef98fbe520ee732fbe50b4195ad3tomhudson@google.com                tmpUnfiltered.setImageFilter(NULL);
10185efe0cb04961ef98fbe520ee732fbe50b4195ad3tomhudson@google.com                iter.fDevice->drawSprite(iter, dst, pos.x(), pos.y(),
10195efe0cb04961ef98fbe520ee732fbe50b4195ad3tomhudson@google.com                                         tmpUnfiltered);
10208926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            }
10218926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        } else {
10228926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com            iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
10238926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        }
10248926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    }
10258926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com    LOOPER_END
10268926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com}
10278926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com
10288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////
10298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::translate(SkScalar dx, SkScalar dy) {
10318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
10328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
1033ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
10348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCRec->fMatrix->preTranslate(dx, dy);
10358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::scale(SkScalar sx, SkScalar sy) {
10388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
10398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
1040ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
10418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCRec->fMatrix->preScale(sx, sy);
10428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::rotate(SkScalar degrees) {
10458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
10468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
1047ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
10488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCRec->fMatrix->preRotate(degrees);
10498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::skew(SkScalar sx, SkScalar sy) {
10528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
10538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
1054ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
10558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCRec->fMatrix->preSkew(sx, sy);
10568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::concat(const SkMatrix& matrix) {
10598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
10608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
1061ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
10628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCRec->fMatrix->preConcat(matrix);
10638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::setMatrix(const SkMatrix& matrix) {
10668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
10678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
1068ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
10698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *fMCRec->fMatrix = matrix;
10708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// this is not virtual, so it must call a virtual method so that subclasses
10738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// will see its action
10748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::resetMatrix() {
10758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix matrix;
10764b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
10778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    matrix.reset();
10788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->setMatrix(matrix);
10798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
10828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1083c42d35daa77febcd6791b5dcb0d5f7ec0f5aa84creed@google.combool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
10845c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    AutoValidateClip avc(this);
10855c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
10868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
10878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
1088ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
10898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fMCRec->fMatrix->rectStaysRect()) {
109198de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // for these simpler matrices, we can stay a rect ever after applying
109298de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // the matrix. This means we don't have to a) make a path, and b) tell
109398de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // the region code to scan-convert the path, only to discover that it
109498de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // is really just a rect.
10958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRect      r;
10968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMCRec->fMatrix->mapRect(&r, rect);
10980017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com        fClipStack.clipDevRect(r, op, doAA);
10990017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com        return fMCRec->fRasterClip->op(r, op, doAA);
11008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
110198de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // since we're rotate or some such thing, we convert the rect to a path
110298de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // and clip against that, since it can handle any matrix. However, to
110398de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // avoid recursion in the case where we are subclassed (e.g. Pictures)
110498de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // we explicitly call "our" version of clipPath.
11058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPath  path;
11068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        path.addRect(rect);
1108c42d35daa77febcd6791b5dcb0d5f7ec0f5aa84creed@google.com        return this->SkCanvas::clipPath(path, op, doAA);
11098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
11108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11120017708a5bcb6d0fbff0fac565085bef65de7433reed@google.comstatic bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip,
1113c42d35daa77febcd6791b5dcb0d5f7ec0f5aa84creed@google.com                           const SkPath& devPath, SkRegion::Op op, bool doAA) {
1114759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com    // base is used to limit the size (and therefore memory allocation) of the
1115759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com    // region that results from scan converting devPath.
1116759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com    SkRegion base;
1117759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com
1118819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    if (SkRegion::kIntersect_Op == op) {
1119759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com        // since we are intersect, we can do better (tighter) with currRgn's
1120759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com        // bounds, than just using the device. However, if currRgn is complex,
1121759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com        // our region blitter may hork, so we do that case in two steps.
11220017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com        if (currClip->isRect()) {
11230017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            return currClip->setPath(devPath, *currClip, doAA);
1124759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com        } else {
11250017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            base.setRect(currClip->getBounds());
11260017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            SkRasterClip clip;
11270017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            clip.setPath(devPath, base, doAA);
11280017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            return currClip->op(clip, op);
1129759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com        }
1130819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    } else {
1131a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org        const SkDevice* device = canvas->getDevice();
1132a907ac3e3e3458fbb5d673c3feafb31fd7647b38junov@chromium.org        base.setRect(0, 0, device->width(), device->height());
1133819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com
1134819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        if (SkRegion::kReplace_Op == op) {
11350017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            return currClip->setPath(devPath, base, doAA);
1136819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        } else {
11370017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            SkRasterClip clip;
11380017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            clip.setPath(devPath, base, doAA);
11390017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            return currClip->op(clip, op);
1140819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        }
1141819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    }
1142819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com}
1143819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com
1144c42d35daa77febcd6791b5dcb0d5f7ec0f5aa84creed@google.combool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
11455c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    AutoValidateClip avc(this);
11465c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
11478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
11488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
1149ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
11508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath devPath;
11528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path.transform(*fMCRec->fMatrix, &devPath);
11538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1154fe701129857924f76a0d752d4c964b3c5e4b49fereed@google.com    // Check if the transfomation, or the original path itself
1155fe701129857924f76a0d752d4c964b3c5e4b49fereed@google.com    // made us empty. Note this can also happen if we contained NaN
1156fe701129857924f76a0d752d4c964b3c5e4b49fereed@google.com    // values. computing the bounds detects this, and will set our
1157fe701129857924f76a0d752d4c964b3c5e4b49fereed@google.com    // bounds to empty if that is the case. (see SkRect::set(pts, count))
1158fe701129857924f76a0d752d4c964b3c5e4b49fereed@google.com    if (devPath.getBounds().isEmpty()) {
1159fe701129857924f76a0d752d4c964b3c5e4b49fereed@google.com        // resetting the path will remove any NaN or other wanky values
1160fe701129857924f76a0d752d4c964b3c5e4b49fereed@google.com        // that might upset our scan converter.
1161fe701129857924f76a0d752d4c964b3c5e4b49fereed@google.com        devPath.reset();
1162fe701129857924f76a0d752d4c964b3c5e4b49fereed@google.com    }
1163fe701129857924f76a0d752d4c964b3c5e4b49fereed@google.com
11645c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    // if we called path.swap() we could avoid a deep copy of this path
11650017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    fClipStack.clipDevPath(devPath, op, doAA);
11665c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
11670017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA);
11688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
11715c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    AutoValidateClip avc(this);
11725c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
11738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
11748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
1175ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
11768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11775c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    // todo: signal fClipStack that we have a region, and therefore (I guess)
11785c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    // we have to ignore it, and use the region directly?
11795c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    fClipStack.clipDevRect(rgn.getBounds());
11805c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
11810017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    return fMCRec->fRasterClip->op(rgn, op);
11828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1184819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com#ifdef SK_DEBUG
1185819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.comvoid SkCanvas::validateClip() const {
1186819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    // construct clipRgn from the clipstack
1187819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    const SkDevice* device = this->getDevice();
1188819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    SkIRect ir;
1189819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    ir.set(0, 0, device->width(), device->height());
11900017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    SkRasterClip tmpClip(ir);
1191819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com
1192819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    SkClipStack::B2FIter                iter(fClipStack);
1193819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    const SkClipStack::B2FIter::Clip*   clip;
1194819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    while ((clip = iter.next()) != NULL) {
1195819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        if (clip->fPath) {
11960017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA);
1197819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        } else if (clip->fRect) {
1198819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com            clip->fRect->round(&ir);
11990017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            tmpClip.op(ir, clip->fOp);
1200819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        } else {
12010017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            tmpClip.setEmpty();
1202819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        }
1203819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    }
1204819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com
12056f8f292aa768869a9e85c314b124875f57504f2creed@google.com#if 0   // enable this locally for testing
1206819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    // now compare against the current rgn
1207819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    const SkRegion& rgn = this->getTotalClip();
12080017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    SkASSERT(rgn == tmpClip);
120902878b844c5cd3f17d48842da3ccf44a66621501reed@google.com#endif
1210819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com}
1211819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com#endif
1212819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com
121390c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.comvoid SkCanvas::replayClips(ClipVisitor* visitor) const {
121490c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com    SkClipStack::B2FIter                iter(fClipStack);
121590c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com    const SkClipStack::B2FIter::Clip*   clip;
121690c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com
121790c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com    SkRect empty = {};
121890c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com    while ((clip = iter.next()) != NULL) {
121990c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com        if (clip->fPath) {
122090c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com            visitor->clipPath(*clip->fPath, clip->fOp, clip->fDoAA);
122190c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com        } else if (clip->fRect) {
122290c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com            visitor->clipRect(*clip->fRect, clip->fOp, clip->fDoAA);
122390c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com        } else {
122490c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com            visitor->clipRect(empty, SkRegion::kIntersect_Op, false);
122590c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com        }
122690c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com    }
122790c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com}
122890c07ea1d0aa6b7f20252c43fe23ee5ddc1d23cbreed@google.com
12295c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com///////////////////////////////////////////////////////////////////////////////
12305c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
1231ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.comvoid SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const {
12328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRect r;
1233ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType :
1234ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com            fLocalBoundsCompareTypeBW;
1235ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com
1236ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    if (!this->getClipBounds(&r, et)) {
1237ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com        rCompare.setEmpty();
12388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
1239ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com        rCompare.set(SkScalarToCompareType(r.fLeft),
1240ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com                     SkScalarToCompareType(r.fTop),
1241ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com                     SkScalarToCompareType(r.fRight),
1242ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com                     SkScalarToCompareType(r.fBottom));
12438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1246d252db03d9650013b545ef9781fe993c07f8f314reed@android.com/*  current impl ignores edgetype, and relies on
1247d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    getLocalClipBoundsCompareType(), which always returns a value assuming
1248d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    antialiasing (worst case)
1249d252db03d9650013b545ef9781fe993c07f8f314reed@android.com */
1250ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.combool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
1251116b2bcd2c4c4d4670c7b7e2ea597414713c37fbwjmaclean@chromium.org
12521607863b608b7db6c813228768ed5d72997bbc82reed@google.com    if (!rect.isFinite())
1253116b2bcd2c4c4d4670c7b7e2ea597414713c37fbwjmaclean@chromium.org        return true;
1254116b2bcd2c4c4d4670c7b7e2ea597414713c37fbwjmaclean@chromium.org
12550017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    if (fMCRec->fRasterClip->isEmpty()) {
12568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
12578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12598d430185e08d2067584837a76b7193b803fee7a0tomhudson@google.com    if (fMCRec->fMatrix->hasPerspective()) {
1260a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        SkRect dst;
1261a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        fMCRec->fMatrix->mapRect(&dst, rect);
1262a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        SkIRect idst;
1263a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        dst.roundOut(&idst);
12640017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com        return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
1265a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com    } else {
1266ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com        const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et);
1267d252db03d9650013b545ef9781fe993c07f8f314reed@android.com
1268a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        // for speed, do the most likely reject compares first
1269a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        SkScalarCompareType userT = SkScalarToCompareType(rect.fTop);
1270a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom);
1271a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        if (userT >= clipR.fBottom || userB <= clipR.fTop) {
1272a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com            return true;
1273a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        }
1274a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft);
1275a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        SkScalarCompareType userR = SkScalarToCompareType(rect.fRight);
1276a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        if (userL >= clipR.fRight || userR <= clipR.fLeft) {
1277a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com            return true;
1278a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        }
1279a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        return false;
12808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::quickReject(const SkPath& path, EdgeType et) const {
1284d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    return path.isEmpty() || this->quickReject(path.getBounds(), et);
12858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1287fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.comstatic inline int pinIntForScalar(int x) {
1288fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com#ifdef SK_SCALAR_IS_FIXED
1289fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com    if (x < SK_MinS16) {
1290fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com        x = SK_MinS16;
1291fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com    } else if (x > SK_MaxS16) {
1292fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com        x = SK_MaxS16;
1293fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com    }
1294fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com#endif
1295fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com    return x;
1296fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com}
1297fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com
12988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const {
1299bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    SkIRect ibounds;
1300bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    if (!getClipDeviceBounds(&ibounds)) {
13018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
13028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
13038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1304d9c0f0b57affec7a472879c5919acac6637d926areed@android.com    SkMatrix inverse;
1305d9c0f0b57affec7a472879c5919acac6637d926areed@android.com    // if we can't invert the CTM, we can't return local clip bounds
1306d9c0f0b57affec7a472879c5919acac6637d926areed@android.com    if (!fMCRec->fMatrix->invert(&inverse)) {
130772dcd3a3c16a68f98bc345a4263678d43bc3daebreed@android.com        if (bounds) {
130872dcd3a3c16a68f98bc345a4263678d43bc3daebreed@android.com            bounds->setEmpty();
130972dcd3a3c16a68f98bc345a4263678d43bc3daebreed@android.com        }
1310d9c0f0b57affec7a472879c5919acac6637d926areed@android.com        return false;
1311d9c0f0b57affec7a472879c5919acac6637d926areed@android.com    }
1312d9c0f0b57affec7a472879c5919acac6637d926areed@android.com
13138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL != bounds) {
1314bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com        SkRect r;
13158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // adjust it outwards if we are antialiasing
13168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int inset = (kAA_EdgeType == et);
1317fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com
1318fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com        // SkRect::iset() will correctly assert if we pass a value out of range
1319fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com        // (when SkScalar==fixed), so we pin to legal values. This does not
1320fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com        // really returnt the correct answer, but its the best we can do given
1321fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com        // that we've promised to return SkRect (even though we support devices
1322fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com        // that can be larger than 32K in width or height).
1323fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com        r.iset(pinIntForScalar(ibounds.fLeft - inset),
1324fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com               pinIntForScalar(ibounds.fTop - inset),
1325fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com               pinIntForScalar(ibounds.fRight + inset),
1326fa4d5bd09f8f1a4a92b5ae0324800dd672760898reed@google.com               pinIntForScalar(ibounds.fBottom + inset));
13278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        inverse.mapRect(bounds, r);
13288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
13298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
13308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
13318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1332bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.combool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
13330017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    const SkRasterClip& clip = *fMCRec->fRasterClip;
1334bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    if (clip.isEmpty()) {
1335bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com        if (bounds) {
1336bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com            bounds->setEmpty();
1337bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com        }
1338bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com        return false;
1339bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    }
1340bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com
1341bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    if (NULL != bounds) {
1342bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com        *bounds = clip.getBounds();
1343bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    }
1344bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    return true;
1345bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com}
1346bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com
13478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkMatrix& SkCanvas::getTotalMatrix() const {
13488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return *fMCRec->fMatrix;
13498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
13508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1351bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.comSkCanvas::ClipType SkCanvas::getClipType() const {
13520017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType;
13530017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    if (fMCRec->fRasterClip->isRect()) return kRect_ClipType;
1354bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    return kComplex_ClipType;
1355bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com}
1356bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com
13578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkRegion& SkCanvas::getTotalClip() const {
13580017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    return fMCRec->fRasterClip->forceGetBW();
13598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
13608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1361f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comvoid SkCanvas::setExternalMatrix(const SkMatrix* matrix) {
1362f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    if (NULL == matrix || matrix->isIdentity()) {
1363f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        if (fUseExternalMatrix) {
1364f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com            fDeviceCMDirty = true;
1365f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        }
1366f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        fUseExternalMatrix = false;
1367f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    } else {
1368f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        fUseExternalMatrix = true;
1369f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        fDeviceCMDirty = true;  // |= (fExternalMatrix != *matrix)
13704b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
1371f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        fExternalMatrix = *matrix;
1372fc9a3be3d2b97aba6aad27e0b9a9f105f08287b9reed@google.com        if (!matrix->invert(&fExternalInverse)) {
1373fc9a3be3d2b97aba6aad27e0b9a9f105f08287b9reed@google.com            fExternalInverse.reset();
1374fc9a3be3d2b97aba6aad27e0b9a9f105f08287b9reed@google.com        }
1375f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    }
1376f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com}
13778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1378e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.comSkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config,
1379e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com                                      int width, int height,
1380e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com                                      bool isOpaque) {
138188edf1e50794e6d8cd7cc671ffce4f5e329ef888bungeman@google.com    SkDevice* device = this->getTopDevice();
1382cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com    if (device) {
1383cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com        return device->createCompatibleDeviceForSaveLayer(config, width, height,
1384cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com                                                          isOpaque);
1385e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    } else {
1386cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com        return NULL;
1387e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    }
13888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
13898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
139074b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.orgSkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config,
1391e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com                                           int width, int height,
1392e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com                                           bool isOpaque) {
1393e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    SkDevice* device = this->getDevice();
1394e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    if (device) {
1395cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com        return device->createCompatibleDevice(config, width, height, isOpaque);
1396e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    } else {
1397e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com        return NULL;
1398e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    }
1399e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com}
1400e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com
1401e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com
14028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
14038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//  These are the virtual drawing methods
14048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
14058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14062a98181f048c11f21f52fbd99f803f5fd6118261reed@google.comvoid SkCanvas::clear(SkColor color) {
14072a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com    SkDrawIter  iter(this);
14082a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com
14092a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com    while (iter.next()) {
14102a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com        iter.fDevice->clear(color);
14112a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com    }
14122a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com}
14132a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com
14148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPaint(const SkPaint& paint) {
1415fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com    this->internalDrawPaint(paint);
1416fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com}
1417fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com
1418fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.comvoid SkCanvas::internalDrawPaint(const SkPaint& paint) {
14194e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type)
14208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
14224e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        iter.fDevice->drawPaint(iter, looper.paint());
14238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14254e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
14268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
14278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
14298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                          const SkPaint& paint) {
14308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((long)count <= 0) {
14318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
14328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(pts != NULL);
14358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14364e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type)
14374b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
14388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
14394e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
14408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14414b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
14424e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
14438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
14448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
14468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (paint.canComputeFastBounds()) {
14478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRect storage;
14488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (this->quickReject(paint.computeFastBounds(r, &storage),
14498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              paint2EdgeType(&paint))) {
14508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
14518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
14528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14534b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
14544e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type)
14558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
14574e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        iter.fDevice->drawRect(iter, r, looper.paint());
14588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14604e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
14618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
14628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1464fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com    if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
1465d252db03d9650013b545ef9781fe993c07f8f314reed@android.com        SkRect storage;
1466d252db03d9650013b545ef9781fe993c07f8f314reed@android.com        const SkRect& bounds = path.getBounds();
1467d252db03d9650013b545ef9781fe993c07f8f314reed@android.com        if (this->quickReject(paint.computeFastBounds(bounds, &storage),
14688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              paint2EdgeType(&paint))) {
14698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
14708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
14718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1472fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com    if (path.isEmpty()) {
1473fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com        if (path.isInverseFillType()) {
1474fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com            this->internalDrawPaint(paint);
1475fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com        }
1476fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com        return;
1477fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com    }
14788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14794e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
14808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
14824e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        iter.fDevice->drawPath(iter, path, looper.paint());
14838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14854e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
14868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
14878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
14898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                          const SkPaint* paint) {
14908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(bitmap.validate();)
14918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14923d60812865bb034851da777a91413ab584929887reed@google.com    if (NULL == paint || paint->canComputeFastBounds()) {
14939efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com        SkRect bounds = {
14949efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com            x, y,
14959efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com            x + SkIntToScalar(bitmap.width()),
14969efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com            y + SkIntToScalar(bitmap.height())
14979efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com        };
14989efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com        if (paint) {
14999efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com            (void)paint->computeFastBounds(bounds, &bounds);
15009efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com        }
15019efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com        if (this->quickReject(bounds, paint2EdgeType(paint))) {
15028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
15038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
15048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
15054b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
15068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix matrix;
15078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    matrix.setTranslate(x, y);
1508f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    this->internalDrawBitmap(bitmap, NULL, matrix, paint);
15098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
15108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15119987ec3791336bad6af5cbe513564786b2df55aareed@google.com// this one is non-virtual, so it can be called safely by other canvas apis
15129987ec3791336bad6af5cbe513564786b2df55aareed@google.comvoid SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
15139987ec3791336bad6af5cbe513564786b2df55aareed@google.com                                      const SkRect& dst, const SkPaint* paint) {
15148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) {
15158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
15168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
151774b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
15188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // do this now, to avoid the cost of calling extract for RLE bitmaps
15193d60812865bb034851da777a91413ab584929887reed@google.com    if (NULL == paint || paint->canComputeFastBounds()) {
15209efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com        SkRect storage;
15219efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com        const SkRect* bounds = &dst;
15229efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com        if (paint) {
15239efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com            bounds = &paint->computeFastBounds(dst, &storage);
15249efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com        }
15259efd9a048aebaa6681afb76b18e1a7dd642078d3reed@google.com        if (this->quickReject(*bounds, paint2EdgeType(paint))) {
15263d60812865bb034851da777a91413ab584929887reed@google.com            return;
15273d60812865bb034851da777a91413ab584929887reed@google.com        }
15288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
15293d60812865bb034851da777a91413ab584929887reed@google.com
15308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkBitmap* bitmapPtr = &bitmap;
153174b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
15328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix matrix;
1533878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com    SkRect tmpSrc;
1534878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com    if (src) {
1535878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        tmpSrc.set(*src);
1536878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        // if the extract process clipped off the top or left of the
1537878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        // original, we adjust for that here to get the position right.
1538878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        if (tmpSrc.fLeft > 0) {
1539878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com            tmpSrc.fRight -= tmpSrc.fLeft;
1540878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com            tmpSrc.fLeft = 0;
1541fead49e3c43e67cf9648ec1999b34da959e1e36breed@android.com        }
1542878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        if (tmpSrc.fTop > 0) {
1543878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com            tmpSrc.fBottom -= tmpSrc.fTop;
1544878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com            tmpSrc.fTop = 0;
1545878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        }
1546878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com    } else {
1547878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()),
1548878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com                   SkIntToScalar(bitmap.height()));
15498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1550878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
155174b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
1552f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    // ensure that src is "valid" before we pass it to our internal routines
1553f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    // and to SkDevice. i.e. sure it is contained inside the original bitmap.
1554f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    SkIRect tmpISrc;
1555f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    if (src) {
1556f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        tmpISrc.set(0, 0, bitmap.width(), bitmap.height());
15572ade0863c3af14d274561cc7cb6e628bb9862761reed@google.com        if (!tmpISrc.intersect(*src)) {
15582ade0863c3af14d274561cc7cb6e628bb9862761reed@google.com            return;
15592ade0863c3af14d274561cc7cb6e628bb9862761reed@google.com        }
1560f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        src = &tmpISrc;
1561f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    }
1562f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    this->internalDrawBitmap(*bitmapPtr, src, matrix, paint);
15638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
15648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15659987ec3791336bad6af5cbe513564786b2df55aareed@google.comvoid SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
15669987ec3791336bad6af5cbe513564786b2df55aareed@google.com                              const SkRect& dst, const SkPaint* paint) {
15679987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkDEBUGCODE(bitmap.validate();)
15689987ec3791336bad6af5cbe513564786b2df55aareed@google.com    this->internalDrawBitmapRect(bitmap, src, dst, paint);
15699987ec3791336bad6af5cbe513564786b2df55aareed@google.com}
15709987ec3791336bad6af5cbe513564786b2df55aareed@google.com
15718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
15728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                const SkPaint* paint) {
15738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(bitmap.validate();)
1574f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    this->internalDrawBitmap(bitmap, NULL, matrix, paint);
15758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
15768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1577f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comvoid SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
1578f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                                const SkMatrix& matrix, const SkPaint& paint) {
15798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(bitmap.validate();)
15809b0390626f73cc88c05c90de64bfe0481e808f14reed@android.com
15814e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type)
15829b0390626f73cc88c05c90de64bfe0481e808f14reed@android.com
15838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
15844e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint());
15858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
15869b0390626f73cc88c05c90de64bfe0481e808f14reed@android.com
15874e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
15888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
15898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15909987ec3791336bad6af5cbe513564786b2df55aareed@google.comvoid SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
15919987ec3791336bad6af5cbe513564786b2df55aareed@google.com                                      const SkIRect& center, const SkRect& dst,
15929987ec3791336bad6af5cbe513564786b2df55aareed@google.com                                      const SkPaint* paint) {
15933d60812865bb034851da777a91413ab584929887reed@google.com    if (NULL == paint || paint->canComputeFastBounds()) {
159460abb078e5597c9c6ceaba1ef495c4916ff4df0ddjsollen@google.com        SkRect storage;
159560abb078e5597c9c6ceaba1ef495c4916ff4df0ddjsollen@google.com        const SkRect* bounds = &dst;
159660abb078e5597c9c6ceaba1ef495c4916ff4df0ddjsollen@google.com        if (paint) {
159760abb078e5597c9c6ceaba1ef495c4916ff4df0ddjsollen@google.com            bounds = &paint->computeFastBounds(dst, &storage);
159860abb078e5597c9c6ceaba1ef495c4916ff4df0ddjsollen@google.com        }
159960abb078e5597c9c6ceaba1ef495c4916ff4df0ddjsollen@google.com        if (this->quickReject(*bounds, paint2EdgeType(paint))) {
16003d60812865bb034851da777a91413ab584929887reed@google.com            return;
16013d60812865bb034851da777a91413ab584929887reed@google.com        }
16023d60812865bb034851da777a91413ab584929887reed@google.com    }
16033d60812865bb034851da777a91413ab584929887reed@google.com
16049987ec3791336bad6af5cbe513564786b2df55aareed@google.com    const int32_t w = bitmap.width();
16059987ec3791336bad6af5cbe513564786b2df55aareed@google.com    const int32_t h = bitmap.height();
16069987ec3791336bad6af5cbe513564786b2df55aareed@google.com
16079987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkIRect c = center;
16089987ec3791336bad6af5cbe513564786b2df55aareed@google.com    // pin center to the bounds of the bitmap
16099987ec3791336bad6af5cbe513564786b2df55aareed@google.com    c.fLeft = SkMax32(0, center.fLeft);
16109987ec3791336bad6af5cbe513564786b2df55aareed@google.com    c.fTop = SkMax32(0, center.fTop);
16119987ec3791336bad6af5cbe513564786b2df55aareed@google.com    c.fRight = SkPin32(center.fRight, c.fLeft, w);
16129987ec3791336bad6af5cbe513564786b2df55aareed@google.com    c.fBottom = SkPin32(center.fBottom, c.fTop, h);
16139987ec3791336bad6af5cbe513564786b2df55aareed@google.com
16149987ec3791336bad6af5cbe513564786b2df55aareed@google.com    const int32_t srcX[4] = { 0, c.fLeft, c.fRight, w };
16159987ec3791336bad6af5cbe513564786b2df55aareed@google.com    const int32_t srcY[4] = { 0, c.fTop, c.fBottom, h };
16169987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkScalar dstX[4] = {
16179987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
16189987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
16199987ec3791336bad6af5cbe513564786b2df55aareed@google.com    };
16209987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkScalar dstY[4] = {
16219987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
16229987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
16239987ec3791336bad6af5cbe513564786b2df55aareed@google.com    };
162474b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
16259987ec3791336bad6af5cbe513564786b2df55aareed@google.com    if (dstX[1] > dstX[2]) {
16269987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
16279987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dstX[2] = dstX[1];
16289987ec3791336bad6af5cbe513564786b2df55aareed@google.com    }
162974b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
16309987ec3791336bad6af5cbe513564786b2df55aareed@google.com    if (dstY[1] > dstY[2]) {
16319987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
16329987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dstY[2] = dstY[1];
16339987ec3791336bad6af5cbe513564786b2df55aareed@google.com    }
163474b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org
16359987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkIRect s;
16369987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkRect  d;
16379987ec3791336bad6af5cbe513564786b2df55aareed@google.com    for (int y = 0; y < 3; y++) {
16389987ec3791336bad6af5cbe513564786b2df55aareed@google.com        s.fTop = srcY[y];
16399987ec3791336bad6af5cbe513564786b2df55aareed@google.com        s.fBottom = srcY[y+1];
16409987ec3791336bad6af5cbe513564786b2df55aareed@google.com        d.fTop = dstY[y];
16419987ec3791336bad6af5cbe513564786b2df55aareed@google.com        d.fBottom = dstY[y+1];
16429987ec3791336bad6af5cbe513564786b2df55aareed@google.com        for (int x = 0; x < 3; x++) {
16439987ec3791336bad6af5cbe513564786b2df55aareed@google.com            s.fLeft = srcX[x];
16449987ec3791336bad6af5cbe513564786b2df55aareed@google.com            s.fRight = srcX[x+1];
16459987ec3791336bad6af5cbe513564786b2df55aareed@google.com            d.fLeft = dstX[x];
16469987ec3791336bad6af5cbe513564786b2df55aareed@google.com            d.fRight = dstX[x+1];
16479987ec3791336bad6af5cbe513564786b2df55aareed@google.com            this->internalDrawBitmapRect(bitmap, &s, d, paint);
16489987ec3791336bad6af5cbe513564786b2df55aareed@google.com        }
16499987ec3791336bad6af5cbe513564786b2df55aareed@google.com    }
16509987ec3791336bad6af5cbe513564786b2df55aareed@google.com}
16519987ec3791336bad6af5cbe513564786b2df55aareed@google.com
16529987ec3791336bad6af5cbe513564786b2df55aareed@google.comvoid SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
16539987ec3791336bad6af5cbe513564786b2df55aareed@google.com                              const SkRect& dst, const SkPaint* paint) {
16549987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkDEBUGCODE(bitmap.validate();)
16559987ec3791336bad6af5cbe513564786b2df55aareed@google.com
16569987ec3791336bad6af5cbe513564786b2df55aareed@google.com    // Need a device entry-point, so gpu can use a mesh
16579987ec3791336bad6af5cbe513564786b2df55aareed@google.com    this->internalDrawBitmapNine(bitmap, center, dst, paint);
16589987ec3791336bad6af5cbe513564786b2df55aareed@google.com}
16599987ec3791336bad6af5cbe513564786b2df55aareed@google.com
1660f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.comclass SkDeviceFilteredPaint {
1661f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.compublic:
1662f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com    SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) {
1663f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com        SkDevice::TextFlags flags;
1664f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com        if (device->filterTextFlags(paint, &flags)) {
1665a076e9be17654a60310e72c4f70fcd5337f56dbfreed@google.com            SkPaint* newPaint = fLazy.set(paint);
1666f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com            newPaint->setFlags(flags.fFlags);
1667f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com            newPaint->setHinting(flags.fHinting);
1668f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com            fPaint = newPaint;
1669f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com        } else {
1670f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com            fPaint = &paint;
1671f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com        }
1672f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com    }
1673f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com
1674f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com    const SkPaint& paint() const { return *fPaint; }
1675f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com
1676f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.comprivate:
16772c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    const SkPaint*  fPaint;
16782c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    SkLazyPaint     fLazy;
1679f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com};
1680f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com
168152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.comvoid SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
168252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                        const SkRect& r, SkScalar textSize) {
168317b78946096265d80215a6c946286ecaa35ea7edepoger@google.com    if (paint.getStyle() == SkPaint::kFill_Style) {
168452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        draw.fDevice->drawRect(draw, r, paint);
168552c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    } else {
168652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        SkPaint p(paint);
168717b78946096265d80215a6c946286ecaa35ea7edepoger@google.com        p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
168852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        draw.fDevice->drawRect(draw, r, p);
168952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    }
169052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com}
169152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
169252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.comvoid SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
169352c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                                   const char text[], size_t byteLength,
169452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                                   SkScalar x, SkScalar y) {
169552c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    SkASSERT(byteLength == 0 || text != NULL);
169652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
169752c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    // nothing to draw
169852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    if (text == NULL || byteLength == 0 ||
169952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        draw.fClip->isEmpty() ||
170052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
170152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        return;
170252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    }
170352c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
170452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    SkScalar    width = 0;
170552c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    SkPoint     start;
170652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
170752c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    start.set(0, 0);    // to avoid warning
170852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
170952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                            SkPaint::kStrikeThruText_Flag)) {
171052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        width = paint.measureText(text, byteLength);
171152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
171252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        SkScalar offsetX = 0;
171352c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
171452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            offsetX = SkScalarHalf(width);
171552c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
171652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            offsetX = width;
171752c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        }
171852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        start.set(x - offsetX, y);
171952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    }
172052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
172152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    if (0 == width) {
172252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        return;
172352c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    }
172452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
172552c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    uint32_t flags = paint.getFlags();
172652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
172752c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    if (flags & (SkPaint::kUnderlineText_Flag |
172852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                 SkPaint::kStrikeThruText_Flag)) {
172952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        SkScalar textSize = paint.getTextSize();
173052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
173152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        SkRect   r;
173252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
173352c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        r.fLeft = start.fX;
173452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        r.fRight = start.fX + width;
173552c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
173652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        if (flags & SkPaint::kUnderlineText_Flag) {
173752c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
173852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                                             start.fY);
173952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            r.fTop = offset;
174052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            r.fBottom = offset + height;
174152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            DrawRect(draw, paint, r, textSize);
174252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        }
174352c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        if (flags & SkPaint::kStrikeThruText_Flag) {
174452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
174552c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                                             start.fY);
174652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            r.fTop = offset;
174752c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            r.fBottom = offset + height;
174852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            DrawRect(draw, paint, r, textSize);
174952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        }
175052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    }
175152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com}
175252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
17538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawText(const void* text, size_t byteLength,
17548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SkScalar x, SkScalar y, const SkPaint& paint) {
17554e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
17568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
17584e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1759f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com        iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
176052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        DrawTextDecorations(iter, dfp.paint(),
176152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                            static_cast<const char*>(text), byteLength, x, y);
17628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
17638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17644e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
17658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
17668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPosText(const void* text, size_t byteLength,
17688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                           const SkPoint pos[], const SkPaint& paint) {
17694e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
17704b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
17718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
17724e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
17738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
1774f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com                                  dfp.paint());
17758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
17764b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
17774e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
17788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
17798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPosTextH(const void* text, size_t byteLength,
17818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const SkScalar xpos[], SkScalar constY,
17828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const SkPaint& paint) {
17834e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
17844b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
17858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
17864e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
17878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
1788f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com                                  dfp.paint());
17898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
17904b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
17914e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
17928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
17938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
17958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              const SkPath& path, const SkMatrix* matrix,
17968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              const SkPaint& paint) {
17974e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
17988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
18008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
18014e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                                     matrix, looper.paint());
18028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
18038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18044e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
18058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
18068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
180756c69773aea56c6c6bd47bc7e7970dd081205184djsollen@google.com#ifdef SK_BUILD_FOR_ANDROID
1808cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.comvoid SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength,
1809cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com                                 const SkPoint pos[], const SkPaint& paint,
1810cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com                                 const SkPath& path, const SkMatrix* matrix) {
18114e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1812cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com
1813cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com    while (iter.next()) {
1814cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com        iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos,
18154e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                                        looper.paint(), path, matrix);
1816cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com    }
1817cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com
18184e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
1819cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com}
1820cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com#endif
1821cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com
18228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
18238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const SkPoint verts[], const SkPoint texs[],
18248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const SkColor colors[], SkXfermode* xmode,
18258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const uint16_t indices[], int indexCount,
18268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const SkPaint& paint) {
18274e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
18284b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
18298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
18308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
18314e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                                   colors, xmode, indices, indexCount,
18324e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                                   looper.paint());
18338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
18344b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
18354e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
18368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
18378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1838cb60844b34766aad4151df5e87c144d4a57e9abereed@android.comvoid SkCanvas::drawData(const void* data, size_t length) {
1839cb60844b34766aad4151df5e87c144d4a57e9abereed@android.com    // do nothing. Subclasses may do something with the data
1840cb60844b34766aad4151df5e87c144d4a57e9abereed@android.com}
1841cb60844b34766aad4151df5e87c144d4a57e9abereed@android.com
18428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
18438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// These methods are NOT virtual, and therefore must call back into virtual
18448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// methods, rather than actually drawing themselves.
18458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
18468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
1848845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com                        SkXfermode::Mode mode) {
18498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPaint paint;
18508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    paint.setARGB(a, r, g, b);
1852845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com    if (SkXfermode::kSrcOver_Mode != mode) {
18530baf19375466cfc24c96532df406e7c5b1d1aae8reed@android.com        paint.setXfermodeMode(mode);
18548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
18558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPaint(paint);
18568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
18578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1858845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.comvoid SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
18598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPaint paint;
18608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    paint.setColor(c);
1862845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com    if (SkXfermode::kSrcOver_Mode != mode) {
18630baf19375466cfc24c96532df406e7c5b1d1aae8reed@android.com        paint.setXfermodeMode(mode);
18648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
18658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPaint(paint);
18668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
18678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
18698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint pt;
18704b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
18718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pt.set(x, y);
18728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
18738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
18748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
18768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint pt;
18778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPaint paint;
18784b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
18798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pt.set(x, y);
18808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    paint.setColor(color);
18818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
18828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
18838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
18858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        const SkPaint& paint) {
18868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint pts[2];
18874b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
18888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pts[0].set(x0, y0);
18898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pts[1].set(x1, y1);
18908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPoints(kLines_PointMode, 2, pts, paint);
18918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
18928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
18948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              SkScalar right, SkScalar bottom,
18958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              const SkPaint& paint) {
18968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRect  r;
18978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    r.set(left, top, right, bottom);
18998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawRect(r, paint);
19008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
19018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
19028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
19038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                          const SkPaint& paint) {
19048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (radius < 0) {
19058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        radius = 0;
19068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
19078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
19088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRect  r;
19098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    r.set(cx - radius, cy - radius, cx + radius, cy + radius);
19104b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
19118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (paint.canComputeFastBounds()) {
19128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRect storage;
19138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (this->quickReject(paint.computeFastBounds(r, &storage),
19148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              paint2EdgeType(&paint))) {
19158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
19168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
19178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
19184b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
19198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath  path;
19208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path.addOval(r);
19218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPath(path, paint);
19228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
19238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
19248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
19258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                             const SkPaint& paint) {
19268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (rx > 0 && ry > 0) {
19278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (paint.canComputeFastBounds()) {
19288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkRect storage;
19298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (this->quickReject(paint.computeFastBounds(r, &storage),
19308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                  paint2EdgeType(&paint))) {
19318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return;
19328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
19338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
19348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
19358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPath  path;
19368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
19378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->drawPath(path, paint);
19388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
19398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->drawRect(r, paint);
19408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
19418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
19428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
19438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
19448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (paint.canComputeFastBounds()) {
19458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRect storage;
19468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (this->quickReject(paint.computeFastBounds(oval, &storage),
19478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              paint2EdgeType(&paint))) {
19488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
19498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
19508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
19518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
19528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath  path;
19538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path.addOval(oval);
19548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPath(path, paint);
19558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
19568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
19578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
19588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                       SkScalar sweepAngle, bool useCenter,
19598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                       const SkPaint& paint) {
19608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
19618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->drawOval(oval, paint);
19628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
19638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPath  path;
19648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (useCenter) {
19658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            path.moveTo(oval.centerX(), oval.centerY());
19668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
19678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        path.arcTo(oval, startAngle, sweepAngle, !useCenter);
19688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (useCenter) {
19698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            path.close();
19708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
19718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->drawPath(path, paint);
19728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
19738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
19748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
19758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
19768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                const SkPath& path, SkScalar hOffset,
19778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                SkScalar vOffset, const SkPaint& paint) {
19788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix    matrix;
19794b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
19808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    matrix.setTranslate(hOffset, vOffset);
19818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawTextOnPath(text, byteLength, path, &matrix, paint);
19828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
19838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1984f76bacff7f66724072c67edb185abf9e3add11a0reed@android.com///////////////////////////////////////////////////////////////////////////////
1985f76bacff7f66724072c67edb185abf9e3add11a0reed@android.com
19868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPicture(SkPicture& picture) {
19878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int saveCount = save();
19888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    picture.draw(this);
19898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    restoreToCount(saveCount);
19908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
19918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
19928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
19938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
19948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
19958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
1996d642329293cce602ac24df8f585c14a98795da87reed@google.com    SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
19978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
19988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(canvas);
19998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
20008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
20018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDone = !fImpl->next();
20028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
20038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
20048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCanvas::LayerIter::~LayerIter() {
20058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fImpl->~SkDrawIter();
20068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
20078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
20088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::LayerIter::next() {
20098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDone = !fImpl->next();
20108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
20118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
20128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDevice* SkCanvas::LayerIter::device() const {
20138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fImpl->getDevice();
20148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
20158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
20168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkMatrix& SkCanvas::LayerIter::matrix() const {
20178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fImpl->getMatrix();
20188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
20198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
20208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkPaint& SkCanvas::LayerIter::paint() const {
20218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkPaint* paint = fImpl->getPaint();
20228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL == paint) {
20238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        paint = &fDefaultPaint;
20248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
20258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return *paint;
20268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
20278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
20288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
20298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCanvas::LayerIter::x() const { return fImpl->getX(); }
20308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCanvas::LayerIter::y() const { return fImpl->getY(); }
2031