SkCanvas.cpp revision 0017708a5bcb6d0fbff0fac565085bef65de7433
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;
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion            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
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void updateMC(const SkMatrix& totalMatrix, const SkRegion& totalClip,
9546799cd9f0bded51a189d77731b25af159ab4609reed@google.com                  const SkClipStack& clipStack, SkRegion* 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
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fClip.op(0, 0, 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) {
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            updateClip->op(x, y, x + width, y + height,
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                           SkRegion::kDifference_Op);
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1214b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
1228a0b0291ae4260ef2a46f4341c18a702c0ce3f8btomhudson@google.com        fDevice->setMatrixClip(*fMatrix, fClip, 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) {
2178a0b0291ae4260ef2a46f4341c18a702c0ce3f8btomhudson@google.com        fCanvas = canvas;
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        canvas->updateDeviceCMCache();
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2207d7ca79c3e6e6be7b7849b0d9a7fe26effb89c38reed@google.com        fClipStack = &canvas->getTotalClipStack();
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBounder = canvas->getBounder();
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrLayer = canvas->fMCRec->fTopLayer;
2238a0b0291ae4260ef2a46f4341c18a702c0ce3f8btomhudson@google.com        fSkipEmptyClips = skipEmptyClips;
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2254b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool next() {
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // skip over recs with empty clips
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fSkipEmptyClips) {
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fCurrLayer = fCurrLayer->fNext;
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (NULL != fCurrLayer) {
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            const DeviceCM* rec = fCurrLayer;
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fMatrix = rec->fMatrix;
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fClip   = &rec->fClip;
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fDevice = rec->fDevice;
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fBitmap = &fDevice->accessBitmap(true);
2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fPaint  = rec->fPaint;
242f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com            fMVMatrix = rec->fMVMatrix;
243f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com            fExtMatrix = rec->fExtMatrix;
244f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com            SkDEBUGCODE(this->validate();)
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fCurrLayer = rec->fNext;
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (fBounder) {
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fBounder->setClip(fClip);
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // fCurrLayer may be NULL now
251199f108f14a5f60a9c2205ffa79b26102a206ad0reed@android.com
252d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com            fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip, *fClipStack);
2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return true;
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2574b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDevice* getDevice() const { return fDevice; }
2596f8f292aa768869a9e85c314b124875f57504f2creed@google.com    int getX() const { return fDevice->getOrigin().x(); }
2606f8f292aa768869a9e85c314b124875f57504f2creed@google.com    int getY() const { return fDevice->getOrigin().y(); }
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkMatrix& getMatrix() const { return *fMatrix; }
2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkRegion& getClip() const { return *fClip; }
2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkPaint* getPaint() const { return fPaint; }
2646f8f292aa768869a9e85c314b124875f57504f2creed@google.com
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkCanvas*       fCanvas;
2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const DeviceCM* fCurrLayer;
2688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkPaint*  fPaint;     // May be null.
2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBool8         fSkipEmptyClips;
2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    typedef SkDraw INHERITED;
2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////
2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass AutoDrawLooper {
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
2784e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint) : fOrigPaint(paint) {
2794e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fCanvas = canvas;
2804e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fLooper = paint.getLooper();
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fFilter = canvas->getDrawFilter();
2824e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fPaint = NULL;
2834e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fSaveCount = canvas->getSaveCount();
2844e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fDone = false;
2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2864e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        if (fLooper) {
2874e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            fLooper->init(canvas);
2888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2904e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com
2914e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    ~AutoDrawLooper() {
2924e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        SkASSERT(fCanvas->getSaveCount() == fSaveCount);
2938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2944e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com
2954e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    const SkPaint& paint() const {
2964e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        SkASSERT(fPaint);
2974e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        return *fPaint;
2984e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    }
2994e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com
3004e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    bool next(SkDrawFilter::Type drawType);
3014e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com
3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
3032c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    SkLazyPaint     fLazyPaint;
3042c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    SkCanvas*       fCanvas;
3052c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    const SkPaint&  fOrigPaint;
3062c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    SkDrawLooper*   fLooper;
3072c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    SkDrawFilter*   fFilter;
3082c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    const SkPaint*  fPaint;
3092c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    int             fSaveCount;
3102c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    bool            fDone;
3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3134e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.combool AutoDrawLooper::next(SkDrawFilter::Type drawType) {
314632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com    fPaint = NULL;
3154e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    if (fDone) {
3164e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        return false;
3174e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    }
318632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com
319632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com    if (fLooper || fFilter) {
320632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com        SkPaint* paint = fLazyPaint.set(fOrigPaint);
321632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com        if (fLooper && !fLooper->next(fCanvas, paint)) {
322632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com            fDone = true;
323632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com            return false;
324632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com        }
325632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com        if (fFilter) {
326632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com            fFilter->filter(paint, drawType);
327632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com            if (NULL == fLooper) {
328632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com                // no looper means we only draw once
329632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com                fDone = true;
330632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com            }
331632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com        }
332632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com        fPaint = paint;
333632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com    } else {
3344e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fDone = true;
3354e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fPaint = &fOrigPaint;
3364e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    }
3374e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com
338632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com    // call this after any possible paint modifiers
339632e1a281bc66fb545dce690dff27b51cef41a8ereed@google.com    if (fPaint->nothingToDraw()) {
3404e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fPaint = NULL;
3414e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        return false;
3424e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    }
3434e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    return true;
3444e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com}
3454e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com
3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*  Stack helper for managing a SkBounder. In the destructor, if we were
3478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    given a bounder, we call its commit() method, signifying that we are
3488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    done accumulating bounds for that draw.
3498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
3508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkAutoBounderCommit {
3518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {}
3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ~SkAutoBounderCommit() {
3548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (NULL != fBounder) {
3558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fBounder->commit();
3568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
3578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
3598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBounder*  fBounder;
3608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
3618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h"
3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass AutoValidator {
3658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
3668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    AutoValidator(SkDevice* device) : fDevice(device) {}
3678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ~AutoValidator() {
3688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
3698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const SkBitmap& bm = fDevice->accessBitmap(false);
3708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (bm.config() == SkBitmap::kARGB_4444_Config) {
3718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            for (int y = 0; y < bm.height(); y++) {
3728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                const SkPMColor16* p = bm.getAddr16(0, y);
3738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                for (int x = 0; x < bm.width(); x++) {
3748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    SkPMColor16 c = p[x];
3758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    SkPMColor16Assert(c);
3768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
3778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
3788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
3798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
3808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
3828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDevice* fDevice;
3838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
3848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////// macros to place around the internal draw calls //////////////////
3868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3874e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com#define LOOPER_BEGIN(paint, type)                                   \
3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*    AutoValidator   validator(fMCRec->fTopLayer->fDevice); */     \
3894e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    AutoDrawLooper  looper(this, paint);                            \
3904e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    while (looper.next(type)) {                                     \
3918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkAutoBounderCommit ac(fBounder);                           \
3928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDrawIter          iter(this);
3934b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
3944e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com#define LOOPER_END    }
3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////////
3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDevice* SkCanvas::init(SkDevice* device) {
3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fBounder = NULL;
4003c898186c9082c535e589807752a0a9dc5d28aa0vandebo@chromium.org    fLocalBoundsCompareType.setEmpty();
4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
4023c898186c9082c535e589807752a0a9dc5d28aa0vandebo@chromium.org    fLocalBoundsCompareTypeBW.setEmpty();
403ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
404199f108f14a5f60a9c2205ffa79b26102a206ad0reed@android.com    fLastDeviceToGainFocus = NULL;
405447bcfa8898ce10e7b6493ba9e3e23e08bd13f01agl@chromium.org    fDeviceCMDirty = false;
4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec = (MCRec*)fMCStack.push_back();
4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    new (fMCRec) MCRec(NULL, 0);
4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL));
4118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->fTopLayer = fMCRec->fLayer;
4128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->fNext = NULL;
4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4143c898186c9082c535e589807752a0a9dc5d28aa0vandebo@chromium.org    fExternalMatrix.reset();
4153c898186c9082c535e589807752a0a9dc5d28aa0vandebo@chromium.org    fExternalInverse.reset();
416f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    fUseExternalMatrix = false;
417f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com
4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return this->setDevice(device);
4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
421cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.comSkCanvas::SkCanvas()
422cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
4238d84fac294682647694b0d2d8a87ac2bd19b6aabvandebo@chromium.org    inc_canvas();
424cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com
4258d84fac294682647694b0d2d8a87ac2bd19b6aabvandebo@chromium.org    this->init(NULL);
4268d84fac294682647694b0d2d8a87ac2bd19b6aabvandebo@chromium.org}
4278d84fac294682647694b0d2d8a87ac2bd19b6aabvandebo@chromium.org
4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCanvas::SkCanvas(SkDevice* device)
429ea4ac97dec2eb291139bd906939e0d2e05cdd7efmike@reedtribe.org        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    inc_canvas();
4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->init(device);
4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCanvas::SkCanvas(const SkBitmap& bitmap)
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    inc_canvas();
4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
439cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com    this->init(SkNEW_ARGS(SkDevice, (bitmap)))->unref();
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCanvas::~SkCanvas() {
4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // free up the contents of our deque
4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->restoreToCount(1);    // restore everything but the last
4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->internalRestore();    // restore the last, since we're going away
4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4478d84fac294682647694b0d2d8a87ac2bd19b6aabvandebo@chromium.org    SkSafeUnref(fBounder);
448b70ae310bbdaa1b26786773aabce5548c1f48563vandebo@chromium.org
4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dec_canvas();
4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkBounder* SkCanvas::setBounder(SkBounder* bounder) {
4538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt_SafeAssign(fBounder, bounder);
4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return bounder;
4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDrawFilter* SkCanvas::getDrawFilter() const {
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCRec->fFilter;
4598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return filter;
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDevice* SkCanvas::getDevice() const {
4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // return root device
4704c09d5cd4b9e6f0be1352f62288efdedc1bc3de3reed@google.com    SkDeque::F2BIter iter(fMCStack);
4714c09d5cd4b9e6f0be1352f62288efdedc1bc3de3reed@google.com    MCRec*           rec = (MCRec*)iter.next();
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(rec && rec->fLayer);
4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return rec->fLayer->fDevice;
4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4769266fed56a46a4edc710a52c7be8d46fd7c2bc7areed@google.comSkDevice* SkCanvas::getTopDevice() const {
4779266fed56a46a4edc710a52c7be8d46fd7c2bc7areed@google.com    return fMCRec->fTopLayer->fDevice;
4789266fed56a46a4edc710a52c7be8d46fd7c2bc7areed@google.com}
4799266fed56a46a4edc710a52c7be8d46fd7c2bc7areed@google.com
4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDevice* SkCanvas::setDevice(SkDevice* device) {
4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // return root device
4824c09d5cd4b9e6f0be1352f62288efdedc1bc3de3reed@google.com    SkDeque::F2BIter iter(fMCStack);
4834c09d5cd4b9e6f0be1352f62288efdedc1bc3de3reed@google.com    MCRec*           rec = (MCRec*)iter.next();
4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(rec && rec->fLayer);
4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDevice*       rootDevice = rec->fLayer->fDevice;
4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (rootDevice == device) {
4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return device;
4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4904b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /* Notify the devices that they are going in/out of scope, so they can do
4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com       things like lock/unlock their pixels, etc.
4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (device) {
4958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        device->lockPixels();
4968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (rootDevice) {
4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        rootDevice->unlockPixels();
4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rootDevice = device;
5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
5054b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /*  Now we update our initial region to have the bounds of the new device,
5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        and then intersect all of the clips in our stack with these bounds,
5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        to ensure that we can't draw outside of the device's bounds (and trash
5098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                                                     memory).
5104b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
5118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    NOTE: this is only a partial-fix, since if the new device is larger than
5128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        the previous one, we don't know how to "enlarge" the clips in our stack,
5134b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com        so drawing may be artificially restricted. Without keeping a history of
5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
5158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        reconstruct the correct clips, so this approximation will have to do.
5168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        The caller really needs to restore() back to the base if they want to
5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        accurately take advantage of the new device bounds.
5188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL == device) {
5210017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com        rec->fRasterClip->setEmpty();
5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        while ((rec = (MCRec*)iter.next()) != NULL) {
5230017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            (void)rec->fRasterClip->setEmpty();
5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5255c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com        fClipStack.reset();
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
5278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // compute our total bounds for all devices
5288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkIRect bounds;
5294b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        bounds.set(0, 0, device->width(), device->height());
5318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // now jam our 1st clip to be bounds, and intersect the rest with that
5330017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com        rec->fRasterClip->setRect(bounds);
5348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        while ((rec = (MCRec*)iter.next()) != NULL) {
5350017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op);
5368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return device;
5398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
541af951c9bc4cbb6e60b430194fe5127ebe99c53fbreed@google.comSkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) {
542af951c9bc4cbb6e60b430194fe5127ebe99c53fbreed@google.com    SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap)));
5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    device->unref();
5448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return device;
5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
54751df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.combool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
54851df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    SkDevice* device = this->getDevice();
54951df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    if (!device) {
55051df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com        return false;
55151df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    }
55251df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    return device->readPixels(srcRect, bitmap);
55351df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com}
55451df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com
5554b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com//////////////////////////////////////////////////////////////////////////////
5564b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
55751df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.combool SkCanvas::readPixels(SkBitmap* bitmap) {
55851df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    SkDevice* device = this->getDevice();
55951df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    if (!device) {
56051df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com        return false;
56151df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    }
56251df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    SkIRect bounds;
56351df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    bounds.set(0, 0, device->width(), device->height());
56451df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    return this->readPixels(bounds, bitmap);
56551df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com}
56651df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com
56751df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.comvoid SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
56851df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    SkDevice* device = this->getDevice();
56951df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    if (device) {
57051df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com        device->writePixels(bitmap, x, y);
57151df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com    }
57251df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com}
57351df9e3fe3c1aec370854b2718df16fc02faa1b2reed@google.com
5748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
5758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::updateDeviceCMCache() {
5778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fDeviceCMDirty) {
5788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const SkMatrix& totalMatrix = this->getTotalMatrix();
5798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const SkRegion& totalClip = this->getTotalClip();
5808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        DeviceCM*       layer = fMCRec->fTopLayer;
5814b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
5828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (NULL == layer->fNext) {   // only one layer
58346799cd9f0bded51a189d77731b25af159ab4609reed@google.com            layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
584f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com            if (fUseExternalMatrix) {
585f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                layer->updateExternalMatrix(fExternalMatrix,
586f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                                            fExternalInverse);
587f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com            }
5888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
5898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkRegion clip;
5908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            clip = totalClip;  // make a copy
5918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            do {
59246799cd9f0bded51a189d77731b25af159ab4609reed@google.com                layer->updateMC(totalMatrix, clip, fClipStack, &clip);
593f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                if (fUseExternalMatrix) {
594f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                    layer->updateExternalMatrix(fExternalMatrix,
595f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                                                fExternalInverse);
596f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                }
5978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } while ((layer = layer->fNext) != NULL);
5988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fDeviceCMDirty = false;
6008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
603f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comvoid SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix,
604d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com                                    const SkRegion& clip,
605d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com                                    const SkClipStack& clipStack) {
6068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(device);
607199f108f14a5f60a9c2205ffa79b26102a206ad0reed@android.com    if (fLastDeviceToGainFocus != device) {
608d302f1401b3c9aea094804bad4e76de98782cfe8bsalomon@google.com        device->gainFocus(this, matrix, clip, clipStack);
609199f108f14a5f60a9c2205ffa79b26102a206ad0reed@android.com        fLastDeviceToGainFocus = device;
610199f108f14a5f60a9c2205ffa79b26102a206ad0reed@android.com    }
6118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
6148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCanvas::internalSave(SaveFlags flags) {
6168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int saveCount = this->getSaveCount(); // record this before the actual save
6174b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
6188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    MCRec* newTop = (MCRec*)fMCStack.push_back();
6198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    new (newTop) MCRec(fMCRec, flags);    // balanced in restore()
6204b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
6218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    newTop->fNext = fMCRec;
6228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec = newTop;
6234b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
6245c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    fClipStack.save();
6255c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
6265c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
6278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return saveCount;
6288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCanvas::save(SaveFlags flags) {
6318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // call shared impl
6328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return this->internalSave(flags);
6338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define C32MASK (1 << SkBitmap::kARGB_8888_Config)
6368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define C16MASK (1 << SkBitmap::kRGB_565_Config)
6378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define C8MASK  (1 << SkBitmap::kA8_Config)
6388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic SkBitmap::Config resolve_config(SkCanvas* canvas,
6408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                       const SkIRect& bounds,
6418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                       SkCanvas::SaveFlags flags,
6428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                       bool* isOpaque) {
6438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0;
6448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if 0
6468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // loop through and union all the configs we may draw into
6478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t configMask = 0;
6488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int i = canvas->countLayerDevices() - 1; i >= 0; --i)
6498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
6508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDevice* device = canvas->getLayerDevice(i);
6518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (device->intersects(bounds))
6528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            configMask |= 1 << device->config();
6538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // if the caller wants alpha or fullcolor, we can't return 565
6568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (flags & (SkCanvas::kFullColorLayer_SaveFlag |
6578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                 SkCanvas::kHasAlphaLayer_SaveFlag))
6588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        configMask &= ~C16MASK;
6598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    switch (configMask) {
6618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    case C8MASK:    // if we only have A8, return that
6628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return SkBitmap::kA8_Config;
6638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    case C16MASK:   // if we only have 565, return that
6658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return SkBitmap::kRGB_565_Config;
6668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    default:
6688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return SkBitmap::kARGB_8888_Config; // default answer
6698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
6718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkBitmap::kARGB_8888_Config; // default answer
6728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
6738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
6768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
6778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
6808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SaveFlags flags) {
6818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // do this before we create the layer. We don't call the public save() since
6828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // that would invoke a possibly overridden virtual
6838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int count = this->internalSave(flags);
6848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
6868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
687bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    SkIRect clipBounds;
688bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    if (!this->getClipDeviceBounds(&clipBounds)) {
689f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        return count;
690f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    }
6918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
692bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    SkIRect ir;
6938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL != bounds) {
6948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRect r;
6954b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
6968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->getTotalMatrix().mapRect(&r, *bounds);
6978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        r.roundOut(&ir);
6988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // early exit if the layer's bounds are clipped out
6998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (!ir.intersect(clipBounds)) {
700bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com            if (bounds_affects_clip(flags)) {
7010017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com                fMCRec->fRasterClip->setEmpty();
702bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com            }
7038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return count;
7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
7058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {    // no user bounds, so just use the clip
7068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        ir = clipBounds;
7078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7095c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op);
7108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // early exit if the clip is now empty
7118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (bounds_affects_clip(flags) &&
7120017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com        !fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) {
7138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return count;
7148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool isOpaque;
7178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque);
7188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
719e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    SkDevice* device = this->createLayerDevice(config, ir.width(), ir.height(),
720e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com                                               isOpaque);
721e25c68402b38ac01dc1ae196ae8a5265b773c5f2bungeman@google.com    if (NULL == device) {
722e25c68402b38ac01dc1ae196ae8a5265b773c5f2bungeman@google.com        SkDebugf("Unable to create device for layer.");
723e25c68402b38ac01dc1ae196ae8a5265b773c5f2bungeman@google.com        return count;
724e25c68402b38ac01dc1ae196ae8a5265b773c5f2bungeman@google.com    }
725e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com
7266f8f292aa768869a9e85c314b124875f57504f2creed@google.com    device->setOrigin(ir.fLeft, ir.fTop);
7278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint));
7288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    device->unref();
7298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    layer->fNext = fMCRec->fTopLayer;
7318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->fLayer = layer;
7328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->fTopLayer = layer;    // this field is NOT an owner of layer
7338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return count;
7358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
7388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                             SaveFlags flags) {
7398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (0xFF == alpha) {
7408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->saveLayer(bounds, NULL, flags);
7418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
7428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPaint tmpPaint;
7438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        tmpPaint.setAlpha(alpha);
7448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->saveLayer(bounds, &tmpPaint, flags);
7458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::restore() {
7498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // check for underflow
7508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fMCStack.count() > 1) {
7518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->internalRestore();
7528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::internalRestore() {
7568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(fMCStack.count() != 0);
7578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
7598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
760ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
7618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7625c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    fClipStack.restore();
76388edf1e50794e6d8cd7cc671ffce4f5e329ef888bungeman@google.com    // reserve our layer (if any)
7648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DeviceCM* layer = fMCRec->fLayer;   // may be null
7658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // now detach it from fMCRec so we can pop(). Gets freed after its drawn
7668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->fLayer = NULL;
7678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // now do the normal restore()
7698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec->~MCRec();       // balanced in save()
7708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCStack.pop_back();
7718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMCRec = (MCRec*)fMCStack.back();
7728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /*  Time to draw the layer's offscreen. We can't call the public drawSprite,
7748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        since if we're being recorded, we don't want to record this (the
7758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        recorder will have already recorded the restore).
7768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
7778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL != layer) {
7788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (layer->fNext) {
7796f8f292aa768869a9e85c314b124875f57504f2creed@google.com            const SkIPoint& origin = layer->fDevice->getOrigin();
7806f8f292aa768869a9e85c314b124875f57504f2creed@google.com            this->drawDevice(layer->fDevice, origin.x(), origin.y(),
7818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                             layer->fPaint);
7828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // reset this, since drawDevice will have set it to true
7838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fDeviceCMDirty = true;
7848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
7858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDELETE(layer);
78688edf1e50794e6d8cd7cc671ffce4f5e329ef888bungeman@google.com    }
7875c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
7885c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
7898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCanvas::getSaveCount() const {
7928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCStack.count();
7938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::restoreToCount(int count) {
7968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // sanity check
7978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count < 1) {
7988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        count = 1;
7998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (fMCStack.count() > count) {
8018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->restore();
8028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////
8068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// can't draw it if its empty, or its too big for a fixed-point width or height
8088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic bool reject_bitmap(const SkBitmap& bitmap) {
809a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com    return  bitmap.width() <= 0 || bitmap.height() <= 0
810a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com#ifndef SK_ALLOW_OVER_32K_BITMAPS
811a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com            || bitmap.width() > 32767 || bitmap.height() > 32767
812a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com#endif
813a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com            ;
8148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
816f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comvoid SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
8178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                const SkMatrix& matrix, const SkPaint* paint) {
8188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (reject_bitmap(bitmap)) {
8198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
8208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8222c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    SkLazyPaint lazy;
8238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL == paint) {
8242c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org        paint = lazy.init();
8258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8262c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    this->commonDrawBitmap(bitmap, srcRect, matrix, *paint);
8278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawDevice(SkDevice* device, int x, int y,
8308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                          const SkPaint* paint) {
8318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPaint tmp;
8328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL == paint) {
8338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        tmp.setDither(true);
8348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        paint = &tmp;
8358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8364b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
8374e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
8388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
8398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.fDevice->drawDevice(iter, device, x - iter.getX(), y - iter.getY(),
8404e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                                 looper.paint());
8418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8424e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
8438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////
8468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::translate(SkScalar dx, SkScalar dy) {
8488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
8498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
850ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
8518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCRec->fMatrix->preTranslate(dx, dy);
8528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::scale(SkScalar sx, SkScalar sy) {
8558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
8568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
857ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
8588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCRec->fMatrix->preScale(sx, sy);
8598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::rotate(SkScalar degrees) {
8628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
8638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
864ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
8658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCRec->fMatrix->preRotate(degrees);
8668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::skew(SkScalar sx, SkScalar sy) {
8698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
8708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
871ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
8728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCRec->fMatrix->preSkew(sx, sy);
8738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::concat(const SkMatrix& matrix) {
8768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
8778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
878ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
8798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fMCRec->fMatrix->preConcat(matrix);
8808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::setMatrix(const SkMatrix& matrix) {
8838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
8848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
885ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
8868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *fMCRec->fMatrix = matrix;
8878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// this is not virtual, so it must call a virtual method so that subclasses
8908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// will see its action
8918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::resetMatrix() {
8928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix matrix;
8934b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
8948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    matrix.reset();
8958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->setMatrix(matrix);
8968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
8998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
900c42d35daa77febcd6791b5dcb0d5f7ec0f5aa84creed@google.combool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
9015c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    AutoValidateClip avc(this);
9025c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
9038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
9048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
905ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
9068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fMCRec->fMatrix->rectStaysRect()) {
90898de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // for these simpler matrices, we can stay a rect ever after applying
90998de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // the matrix. This means we don't have to a) make a path, and b) tell
91098de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // the region code to scan-convert the path, only to discover that it
91198de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // is really just a rect.
9128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRect      r;
9138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMCRec->fMatrix->mapRect(&r, rect);
9150017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com        fClipStack.clipDevRect(r, op, doAA);
9160017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com        return fMCRec->fRasterClip->op(r, op, doAA);
9178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
91898de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // since we're rotate or some such thing, we convert the rect to a path
91998de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // and clip against that, since it can handle any matrix. However, to
92098de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // avoid recursion in the case where we are subclassed (e.g. Pictures)
92198de2bdbd12a01aaf347ca2549801b5940613f3freed@android.com        // we explicitly call "our" version of clipPath.
9228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPath  path;
9238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        path.addRect(rect);
925c42d35daa77febcd6791b5dcb0d5f7ec0f5aa84creed@google.com        return this->SkCanvas::clipPath(path, op, doAA);
9268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9290017708a5bcb6d0fbff0fac565085bef65de7433reed@google.comstatic bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip,
930c42d35daa77febcd6791b5dcb0d5f7ec0f5aa84creed@google.com                           const SkPath& devPath, SkRegion::Op op, bool doAA) {
931759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com    // base is used to limit the size (and therefore memory allocation) of the
932759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com    // region that results from scan converting devPath.
933759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com    SkRegion base;
934759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com
935819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    if (SkRegion::kIntersect_Op == op) {
936759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com        // since we are intersect, we can do better (tighter) with currRgn's
937759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com        // bounds, than just using the device. However, if currRgn is complex,
938759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com        // our region blitter may hork, so we do that case in two steps.
9390017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com        if (currClip->isRect()) {
9400017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            return currClip->setPath(devPath, *currClip, doAA);
941759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com        } else {
9420017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            base.setRect(currClip->getBounds());
9430017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            SkRasterClip clip;
9440017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            clip.setPath(devPath, base, doAA);
9450017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            return currClip->op(clip, op);
946759876a9223ef64f9d0db235d7a46750f8193cbcreed@google.com        }
947819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    } else {
948819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        const SkBitmap& bm = canvas->getDevice()->accessBitmap(false);
949819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        base.setRect(0, 0, bm.width(), bm.height());
950819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com
951819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        if (SkRegion::kReplace_Op == op) {
9520017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            return currClip->setPath(devPath, base, doAA);
953819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        } else {
9540017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            SkRasterClip clip;
9550017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            clip.setPath(devPath, base, doAA);
9560017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            return currClip->op(clip, op);
957819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        }
958819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    }
959819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com}
960819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com
961c42d35daa77febcd6791b5dcb0d5f7ec0f5aa84creed@google.combool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
9625c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    AutoValidateClip avc(this);
9635c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
9648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
9658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
966ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
9678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath devPath;
9698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path.transform(*fMCRec->fMatrix, &devPath);
9708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9715c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    // if we called path.swap() we could avoid a deep copy of this path
9720017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    fClipStack.clipDevPath(devPath, op, doAA);
9735c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
9740017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA);
9758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
9785c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    AutoValidateClip avc(this);
9795c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
9808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDeviceCMDirty = true;
9818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLocalBoundsCompareTypeDirty = true;
982ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    fLocalBoundsCompareTypeDirtyBW = true;
9838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9845c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    // todo: signal fClipStack that we have a region, and therefore (I guess)
9855c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    // we have to ignore it, and use the region directly?
9865c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com    fClipStack.clipDevRect(rgn.getBounds());
9875c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
9880017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    return fMCRec->fRasterClip->op(rgn, op);
9898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
991819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com#ifdef SK_DEBUG
992819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.comvoid SkCanvas::validateClip() const {
993819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    // construct clipRgn from the clipstack
994819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    const SkDevice* device = this->getDevice();
995819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    SkIRect ir;
996819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    ir.set(0, 0, device->width(), device->height());
9970017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    SkRasterClip tmpClip(ir);
998819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com
999819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    SkClipStack::B2FIter                iter(fClipStack);
1000819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    const SkClipStack::B2FIter::Clip*   clip;
1001819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    while ((clip = iter.next()) != NULL) {
1002819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        if (clip->fPath) {
10030017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA);
1004819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        } else if (clip->fRect) {
1005819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com            clip->fRect->round(&ir);
10060017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            tmpClip.op(ir, clip->fOp);
1007819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        } else {
10080017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            tmpClip.setEmpty();
1009819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com        }
1010819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    }
1011819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com
10126f8f292aa768869a9e85c314b124875f57504f2creed@google.com#if 0   // enable this locally for testing
1013819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    // now compare against the current rgn
1014819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com    const SkRegion& rgn = this->getTotalClip();
10150017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    SkASSERT(rgn == tmpClip);
101602878b844c5cd3f17d48842da3ccf44a66621501reed@google.com#endif
1017819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com}
1018819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com#endif
1019819c921b0445fa9f45f18d4a560603cd9fde6ba4reed@google.com
10205c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com///////////////////////////////////////////////////////////////////////////////
10215c3d1471e4908706cd053a5e2ea9ded3a6c2eaebreed@google.com
1022ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.comvoid SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const {
10238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRect r;
1024ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType :
1025ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com            fLocalBoundsCompareTypeBW;
1026ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com
1027ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com    if (!this->getClipBounds(&r, et)) {
1028ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com        rCompare.setEmpty();
10298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
1030ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com        rCompare.set(SkScalarToCompareType(r.fLeft),
1031ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com                     SkScalarToCompareType(r.fTop),
1032ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com                     SkScalarToCompareType(r.fRight),
1033ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com                     SkScalarToCompareType(r.fBottom));
10348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
10358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1037d252db03d9650013b545ef9781fe993c07f8f314reed@android.com/*  current impl ignores edgetype, and relies on
1038d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    getLocalClipBoundsCompareType(), which always returns a value assuming
1039d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    antialiasing (worst case)
1040d252db03d9650013b545ef9781fe993c07f8f314reed@android.com */
1041ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.combool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
1042116b2bcd2c4c4d4670c7b7e2ea597414713c37fbwjmaclean@chromium.org
1043116b2bcd2c4c4d4670c7b7e2ea597414713c37fbwjmaclean@chromium.org    if (!rect.hasValidCoordinates())
1044116b2bcd2c4c4d4670c7b7e2ea597414713c37fbwjmaclean@chromium.org        return true;
1045116b2bcd2c4c4d4670c7b7e2ea597414713c37fbwjmaclean@chromium.org
10460017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    if (fMCRec->fRasterClip->isEmpty()) {
10478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
10488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
10498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10508d430185e08d2067584837a76b7193b803fee7a0tomhudson@google.com    if (fMCRec->fMatrix->hasPerspective()) {
1051a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        SkRect dst;
1052a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        fMCRec->fMatrix->mapRect(&dst, rect);
1053a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        SkIRect idst;
1054a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        dst.roundOut(&idst);
10550017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com        return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
1056a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com    } else {
1057ba09de4c4be66cc07790f23b0f3a925f47340e3ereed@android.com        const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et);
1058d252db03d9650013b545ef9781fe993c07f8f314reed@android.com
1059a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        // for speed, do the most likely reject compares first
1060a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        SkScalarCompareType userT = SkScalarToCompareType(rect.fTop);
1061a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom);
1062a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        if (userT >= clipR.fBottom || userB <= clipR.fTop) {
1063a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com            return true;
1064a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        }
1065a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft);
1066a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        SkScalarCompareType userR = SkScalarToCompareType(rect.fRight);
1067a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        if (userL >= clipR.fRight || userR <= clipR.fLeft) {
1068a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com            return true;
1069a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        }
1070a380ae4a9ac209f5676c06aeaceacc1b08817edareed@android.com        return false;
10718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
10728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::quickReject(const SkPath& path, EdgeType et) const {
1075d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    return path.isEmpty() || this->quickReject(path.getBounds(), et);
10768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
10798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /*  current impl ignores edgetype, and relies on
10808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        getLocalClipBoundsCompareType(), which always returns a value assuming
10818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        antialiasing (worst case)
10828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com     */
10838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10840017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    if (fMCRec->fRasterClip->isEmpty()) {
10858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
10868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
10874b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
1088aefd2bc75738963b9b6579897be32bfbc8fb00afreed@android.com    SkScalarCompareType userT = SkScalarToCompareType(top);
1089aefd2bc75738963b9b6579897be32bfbc8fb00afreed@android.com    SkScalarCompareType userB = SkScalarToCompareType(bottom);
10904b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
10918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // check for invalid user Y coordinates (i.e. empty)
1092d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    // reed: why do we need to do this check, since it slows us down?
10938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (userT >= userB) {
10948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
10958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
10964b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
10978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // check if we are above or below the local clip bounds
10988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
10998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return userT >= clipR.fBottom || userB <= clipR.fTop;
11008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const {
1103bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    SkIRect ibounds;
1104bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    if (!getClipDeviceBounds(&ibounds)) {
11058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
11068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
11078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1108d9c0f0b57affec7a472879c5919acac6637d926areed@android.com    SkMatrix inverse;
1109d9c0f0b57affec7a472879c5919acac6637d926areed@android.com    // if we can't invert the CTM, we can't return local clip bounds
1110d9c0f0b57affec7a472879c5919acac6637d926areed@android.com    if (!fMCRec->fMatrix->invert(&inverse)) {
111172dcd3a3c16a68f98bc345a4263678d43bc3daebreed@android.com        if (bounds) {
111272dcd3a3c16a68f98bc345a4263678d43bc3daebreed@android.com            bounds->setEmpty();
111372dcd3a3c16a68f98bc345a4263678d43bc3daebreed@android.com        }
1114d9c0f0b57affec7a472879c5919acac6637d926areed@android.com        return false;
1115d9c0f0b57affec7a472879c5919acac6637d926areed@android.com    }
1116d9c0f0b57affec7a472879c5919acac6637d926areed@android.com
11178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL != bounds) {
1118bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com        SkRect r;
11198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // adjust it outwards if we are antialiasing
11208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int inset = (kAA_EdgeType == et);
11218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        r.iset(ibounds.fLeft - inset,  ibounds.fTop - inset,
11228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com               ibounds.fRight + inset, ibounds.fBottom + inset);
11238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        inverse.mapRect(bounds, r);
11248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
11258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
11268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1128bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.combool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
11290017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    const SkRasterClip& clip = *fMCRec->fRasterClip;
1130bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    if (clip.isEmpty()) {
1131bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com        if (bounds) {
1132bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com            bounds->setEmpty();
1133bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com        }
1134bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com        return false;
1135bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    }
1136bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com
1137bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    if (NULL != bounds) {
1138bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com        *bounds = clip.getBounds();
1139bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    }
1140bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    return true;
1141bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com}
1142bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com
11438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkMatrix& SkCanvas::getTotalMatrix() const {
11448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return *fMCRec->fMatrix;
11458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1147bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.comSkCanvas::ClipType SkCanvas::getClipType() const {
11480017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType;
11490017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    if (fMCRec->fRasterClip->isRect()) return kRect_ClipType;
1150bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com    return kComplex_ClipType;
1151bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com}
1152bcb671c82a7341253864cda3a5c46d396402d7fbtomhudson@google.com
11538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkRegion& SkCanvas::getTotalClip() const {
11540017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com    return fMCRec->fRasterClip->forceGetBW();
11558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11577d7ca79c3e6e6be7b7849b0d9a7fe26effb89c38reed@google.comconst SkClipStack& SkCanvas::getTotalClipStack() const {
11587d7ca79c3e6e6be7b7849b0d9a7fe26effb89c38reed@google.com    return fClipStack;
11597d7ca79c3e6e6be7b7849b0d9a7fe26effb89c38reed@google.com}
11607d7ca79c3e6e6be7b7849b0d9a7fe26effb89c38reed@google.com
1161f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comvoid SkCanvas::setExternalMatrix(const SkMatrix* matrix) {
1162f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    if (NULL == matrix || matrix->isIdentity()) {
1163f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        if (fUseExternalMatrix) {
1164f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com            fDeviceCMDirty = true;
1165f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        }
1166f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        fUseExternalMatrix = false;
1167f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    } else {
1168f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        fUseExternalMatrix = true;
1169f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        fDeviceCMDirty = true;  // |= (fExternalMatrix != *matrix)
11704b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
1171f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        fExternalMatrix = *matrix;
1172f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        matrix->invert(&fExternalInverse);
1173f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    }
1174f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com}
11758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1176e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.comSkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config,
1177e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com                                      int width, int height,
1178e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com                                      bool isOpaque) {
117988edf1e50794e6d8cd7cc671ffce4f5e329ef888bungeman@google.com    SkDevice* device = this->getTopDevice();
1180cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com    if (device) {
1181cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com        return device->createCompatibleDeviceForSaveLayer(config, width, height,
1182cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com                                                          isOpaque);
1183e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    } else {
1184cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com        return NULL;
1185e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    }
11868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1188e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.comSkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config,
1189e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com                                           int width, int height,
1190e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com                                           bool isOpaque) {
1191e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    SkDevice* device = this->getDevice();
1192e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    if (device) {
1193cde92111d50a96b6d0f3e166fbac7c9bc6eca349reed@google.com        return device->createCompatibleDevice(config, width, height, isOpaque);
1194e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    } else {
1195e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com        return NULL;
1196e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    }
1197e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com}
1198e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com
1199e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com
12008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
12018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//  These are the virtual drawing methods
12028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
12038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12042a98181f048c11f21f52fbd99f803f5fd6118261reed@google.comvoid SkCanvas::clear(SkColor color) {
12052a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com    SkDrawIter  iter(this);
12062a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com
12072a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com    while (iter.next()) {
12082a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com        iter.fDevice->clear(color);
12092a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com    }
12102a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com}
12112a98181f048c11f21f52fbd99f803f5fd6118261reed@google.com
12128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPaint(const SkPaint& paint) {
1213fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com    this->internalDrawPaint(paint);
1214fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com}
1215fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com
1216fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.comvoid SkCanvas::internalDrawPaint(const SkPaint& paint) {
12174e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type)
12188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
12204e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        iter.fDevice->drawPaint(iter, looper.paint());
12218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12234e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
12248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
12278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                          const SkPaint& paint) {
12288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((long)count <= 0) {
12298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
12308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(pts != NULL);
12338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12344e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type)
12354b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
12368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
12374e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
12388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12394b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
12404e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
12418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
12448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (paint.canComputeFastBounds()) {
12458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRect storage;
12468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (this->quickReject(paint.computeFastBounds(r, &storage),
12478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              paint2EdgeType(&paint))) {
12488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
12498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
12508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12514b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
12524e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type)
12538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
12554e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        iter.fDevice->drawRect(iter, r, looper.paint());
12568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12584e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
12598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1262fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com    if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
1263d252db03d9650013b545ef9781fe993c07f8f314reed@android.com        SkRect storage;
1264d252db03d9650013b545ef9781fe993c07f8f314reed@android.com        const SkRect& bounds = path.getBounds();
1265d252db03d9650013b545ef9781fe993c07f8f314reed@android.com        if (this->quickReject(paint.computeFastBounds(bounds, &storage),
12668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              paint2EdgeType(&paint))) {
12678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
12688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
12698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1270fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com    if (path.isEmpty()) {
1271fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com        if (path.isInverseFillType()) {
1272fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com            this->internalDrawPaint(paint);
1273fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com        }
1274fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com        return;
1275fa6ac938e64fe11b442d05fe8a90ddac2d1951f9bsalomon@google.com    }
12768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12774e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
12788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
12804e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        iter.fDevice->drawPath(iter, path, looper.paint());
12818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12834e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
12848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
12878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                          const SkPaint* paint) {
12888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(bitmap.validate();)
12898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL == paint || (paint->getMaskFilter() == NULL)) {
12918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRect fastBounds;
12928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fastBounds.set(x, y,
12938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                       x + SkIntToScalar(bitmap.width()),
12948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                       y + SkIntToScalar(bitmap.height()));
12958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (this->quickReject(fastBounds, paint2EdgeType(paint))) {
12968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
12978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
12988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12994b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
13008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix matrix;
13018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    matrix.setTranslate(x, y);
1302f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    this->internalDrawBitmap(bitmap, NULL, matrix, paint);
13038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
13048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13059987ec3791336bad6af5cbe513564786b2df55aareed@google.com// this one is non-virtual, so it can be called safely by other canvas apis
13069987ec3791336bad6af5cbe513564786b2df55aareed@google.comvoid SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
13079987ec3791336bad6af5cbe513564786b2df55aareed@google.com                                      const SkRect& dst, const SkPaint* paint) {
13088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) {
13098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
13108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
13119987ec3791336bad6af5cbe513564786b2df55aareed@google.com
13128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // do this now, to avoid the cost of calling extract for RLE bitmaps
13138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (this->quickReject(dst, paint2EdgeType(paint))) {
13148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
13158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
13169987ec3791336bad6af5cbe513564786b2df55aareed@google.com
13178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkBitmap* bitmapPtr = &bitmap;
13189987ec3791336bad6af5cbe513564786b2df55aareed@google.com
13198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix matrix;
1320878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com    SkRect tmpSrc;
1321878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com    if (src) {
1322878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        tmpSrc.set(*src);
1323878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        // if the extract process clipped off the top or left of the
1324878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        // original, we adjust for that here to get the position right.
1325878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        if (tmpSrc.fLeft > 0) {
1326878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com            tmpSrc.fRight -= tmpSrc.fLeft;
1327878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com            tmpSrc.fLeft = 0;
1328fead49e3c43e67cf9648ec1999b34da959e1e36breed@android.com        }
1329878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        if (tmpSrc.fTop > 0) {
1330878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com            tmpSrc.fBottom -= tmpSrc.fTop;
1331878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com            tmpSrc.fTop = 0;
1332878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        }
1333878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com    } else {
1334878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com        tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()),
1335878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com                   SkIntToScalar(bitmap.height()));
13368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1337878999965b977c4ed771c3d655f9e23ef9b5adb1reed@android.com    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
13389987ec3791336bad6af5cbe513564786b2df55aareed@google.com
1339f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    // ensure that src is "valid" before we pass it to our internal routines
1340f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    // and to SkDevice. i.e. sure it is contained inside the original bitmap.
1341f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    SkIRect tmpISrc;
1342f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    if (src) {
1343f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        tmpISrc.set(0, 0, bitmap.width(), bitmap.height());
13442ade0863c3af14d274561cc7cb6e628bb9862761reed@google.com        if (!tmpISrc.intersect(*src)) {
13452ade0863c3af14d274561cc7cb6e628bb9862761reed@google.com            return;
13462ade0863c3af14d274561cc7cb6e628bb9862761reed@google.com        }
1347f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        src = &tmpISrc;
1348f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    }
1349f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    this->internalDrawBitmap(*bitmapPtr, src, matrix, paint);
13508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
13518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13529987ec3791336bad6af5cbe513564786b2df55aareed@google.comvoid SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
13539987ec3791336bad6af5cbe513564786b2df55aareed@google.com                              const SkRect& dst, const SkPaint* paint) {
13549987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkDEBUGCODE(bitmap.validate();)
13559987ec3791336bad6af5cbe513564786b2df55aareed@google.com    this->internalDrawBitmapRect(bitmap, src, dst, paint);
13569987ec3791336bad6af5cbe513564786b2df55aareed@google.com}
13579987ec3791336bad6af5cbe513564786b2df55aareed@google.com
13588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
13598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                const SkPaint* paint) {
13608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(bitmap.validate();)
1361f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    this->internalDrawBitmap(bitmap, NULL, matrix, paint);
13628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
13638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1364f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comvoid SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
1365f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com                                const SkMatrix& matrix, const SkPaint& paint) {
13668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(bitmap.validate();)
13679b0390626f73cc88c05c90de64bfe0481e808f14reed@android.com
13684e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type)
13699b0390626f73cc88c05c90de64bfe0481e808f14reed@android.com
13708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
13714e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint());
13728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
13739b0390626f73cc88c05c90de64bfe0481e808f14reed@android.com
13744e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
13758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
13768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13779987ec3791336bad6af5cbe513564786b2df55aareed@google.comvoid SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
13789987ec3791336bad6af5cbe513564786b2df55aareed@google.com                                      const SkIRect& center, const SkRect& dst,
13799987ec3791336bad6af5cbe513564786b2df55aareed@google.com                                      const SkPaint* paint) {
13809987ec3791336bad6af5cbe513564786b2df55aareed@google.com    const int32_t w = bitmap.width();
13819987ec3791336bad6af5cbe513564786b2df55aareed@google.com    const int32_t h = bitmap.height();
13829987ec3791336bad6af5cbe513564786b2df55aareed@google.com
13839987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkIRect c = center;
13849987ec3791336bad6af5cbe513564786b2df55aareed@google.com    // pin center to the bounds of the bitmap
13859987ec3791336bad6af5cbe513564786b2df55aareed@google.com    c.fLeft = SkMax32(0, center.fLeft);
13869987ec3791336bad6af5cbe513564786b2df55aareed@google.com    c.fTop = SkMax32(0, center.fTop);
13879987ec3791336bad6af5cbe513564786b2df55aareed@google.com    c.fRight = SkPin32(center.fRight, c.fLeft, w);
13889987ec3791336bad6af5cbe513564786b2df55aareed@google.com    c.fBottom = SkPin32(center.fBottom, c.fTop, h);
13899987ec3791336bad6af5cbe513564786b2df55aareed@google.com
13909987ec3791336bad6af5cbe513564786b2df55aareed@google.com    const int32_t srcX[4] = { 0, c.fLeft, c.fRight, w };
13919987ec3791336bad6af5cbe513564786b2df55aareed@google.com    const int32_t srcY[4] = { 0, c.fTop, c.fBottom, h };
13929987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkScalar dstX[4] = {
13939987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
13949987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
13959987ec3791336bad6af5cbe513564786b2df55aareed@google.com    };
13969987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkScalar dstY[4] = {
13979987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
13989987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
13999987ec3791336bad6af5cbe513564786b2df55aareed@google.com    };
14009987ec3791336bad6af5cbe513564786b2df55aareed@google.com
14019987ec3791336bad6af5cbe513564786b2df55aareed@google.com    if (dstX[1] > dstX[2]) {
14029987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
14039987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dstX[2] = dstX[1];
14049987ec3791336bad6af5cbe513564786b2df55aareed@google.com    }
14059987ec3791336bad6af5cbe513564786b2df55aareed@google.com
14069987ec3791336bad6af5cbe513564786b2df55aareed@google.com    if (dstY[1] > dstY[2]) {
14079987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
14089987ec3791336bad6af5cbe513564786b2df55aareed@google.com        dstY[2] = dstY[1];
14099987ec3791336bad6af5cbe513564786b2df55aareed@google.com    }
14109987ec3791336bad6af5cbe513564786b2df55aareed@google.com
14119987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkIRect s;
14129987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkRect  d;
14139987ec3791336bad6af5cbe513564786b2df55aareed@google.com    for (int y = 0; y < 3; y++) {
14149987ec3791336bad6af5cbe513564786b2df55aareed@google.com        s.fTop = srcY[y];
14159987ec3791336bad6af5cbe513564786b2df55aareed@google.com        s.fBottom = srcY[y+1];
14169987ec3791336bad6af5cbe513564786b2df55aareed@google.com        d.fTop = dstY[y];
14179987ec3791336bad6af5cbe513564786b2df55aareed@google.com        d.fBottom = dstY[y+1];
14189987ec3791336bad6af5cbe513564786b2df55aareed@google.com        for (int x = 0; x < 3; x++) {
14199987ec3791336bad6af5cbe513564786b2df55aareed@google.com            s.fLeft = srcX[x];
14209987ec3791336bad6af5cbe513564786b2df55aareed@google.com            s.fRight = srcX[x+1];
14219987ec3791336bad6af5cbe513564786b2df55aareed@google.com            d.fLeft = dstX[x];
14229987ec3791336bad6af5cbe513564786b2df55aareed@google.com            d.fRight = dstX[x+1];
14239987ec3791336bad6af5cbe513564786b2df55aareed@google.com            this->internalDrawBitmapRect(bitmap, &s, d, paint);
14249987ec3791336bad6af5cbe513564786b2df55aareed@google.com        }
14259987ec3791336bad6af5cbe513564786b2df55aareed@google.com    }
14269987ec3791336bad6af5cbe513564786b2df55aareed@google.com}
14279987ec3791336bad6af5cbe513564786b2df55aareed@google.com
14289987ec3791336bad6af5cbe513564786b2df55aareed@google.comvoid SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
14299987ec3791336bad6af5cbe513564786b2df55aareed@google.com                              const SkRect& dst, const SkPaint* paint) {
14309987ec3791336bad6af5cbe513564786b2df55aareed@google.com    SkDEBUGCODE(bitmap.validate();)
14319987ec3791336bad6af5cbe513564786b2df55aareed@google.com
14329987ec3791336bad6af5cbe513564786b2df55aareed@google.com    // Need a device entry-point, so gpu can use a mesh
14339987ec3791336bad6af5cbe513564786b2df55aareed@google.com    this->internalDrawBitmapNine(bitmap, center, dst, paint);
14349987ec3791336bad6af5cbe513564786b2df55aareed@google.com}
14359987ec3791336bad6af5cbe513564786b2df55aareed@google.com
14368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
14378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                          const SkPaint* paint) {
14388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(bitmap.validate();)
14394b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
14408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (reject_bitmap(bitmap)) {
14418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
14428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14434b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
14448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPaint tmp;
14458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL == paint) {
14468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        paint = &tmp;
14478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14484b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
14494e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
14504b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
14518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
14528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(),
14534e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                                 looper.paint());
14548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14554e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
14568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
14578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1458f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.comclass SkDeviceFilteredPaint {
1459f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.compublic:
1460f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com    SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) {
1461f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com        SkDevice::TextFlags flags;
1462f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com        if (device->filterTextFlags(paint, &flags)) {
1463a076e9be17654a60310e72c4f70fcd5337f56dbfreed@google.com            SkPaint* newPaint = fLazy.set(paint);
1464f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com            newPaint->setFlags(flags.fFlags);
1465f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com            newPaint->setHinting(flags.fHinting);
1466f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com            fPaint = newPaint;
1467f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com        } else {
1468f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com            fPaint = &paint;
1469f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com        }
1470f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com    }
1471f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com
1472f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com    const SkPaint& paint() const { return *fPaint; }
1473f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com
1474f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.comprivate:
14752c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    const SkPaint*  fPaint;
14762c8fc5a7038cdfbb28a8364fd0057f3c21f90bfdmike@reedtribe.org    SkLazyPaint     fLazy;
1477f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com};
1478f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com
147952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.comvoid SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
148052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                        const SkRect& r, SkScalar textSize) {
148117b78946096265d80215a6c946286ecaa35ea7edepoger@google.com    if (paint.getStyle() == SkPaint::kFill_Style) {
148252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        draw.fDevice->drawRect(draw, r, paint);
148352c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    } else {
148452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        SkPaint p(paint);
148517b78946096265d80215a6c946286ecaa35ea7edepoger@google.com        p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
148652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        draw.fDevice->drawRect(draw, r, p);
148752c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    }
148852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com}
148952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
149052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.comvoid SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
149152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                                   const char text[], size_t byteLength,
149252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                                   SkScalar x, SkScalar y) {
149352c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    SkASSERT(byteLength == 0 || text != NULL);
149452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
149552c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    // nothing to draw
149652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    if (text == NULL || byteLength == 0 ||
149752c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        draw.fClip->isEmpty() ||
149852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
149952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        return;
150052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    }
150152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
150252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    SkScalar    width = 0;
150352c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    SkPoint     start;
150452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
150552c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    start.set(0, 0);    // to avoid warning
150652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
150752c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                            SkPaint::kStrikeThruText_Flag)) {
150852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        width = paint.measureText(text, byteLength);
150952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
151052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        SkScalar offsetX = 0;
151152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
151252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            offsetX = SkScalarHalf(width);
151352c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
151452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            offsetX = width;
151552c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        }
151652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        start.set(x - offsetX, y);
151752c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    }
151852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
151952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    if (0 == width) {
152052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        return;
152152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    }
152252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
152352c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    uint32_t flags = paint.getFlags();
152452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
152552c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    if (flags & (SkPaint::kUnderlineText_Flag |
152652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                 SkPaint::kStrikeThruText_Flag)) {
152752c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        SkScalar textSize = paint.getTextSize();
152852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
152952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        SkRect   r;
153052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
153152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        r.fLeft = start.fX;
153252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        r.fRight = start.fX + width;
153352c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
153452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        if (flags & SkPaint::kUnderlineText_Flag) {
153552c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
153652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                                             start.fY);
153752c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            r.fTop = offset;
153852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            r.fBottom = offset + height;
153952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            DrawRect(draw, paint, r, textSize);
154052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        }
154152c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        if (flags & SkPaint::kStrikeThruText_Flag) {
154252c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
154352c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                                             start.fY);
154452c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            r.fTop = offset;
154552c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            r.fBottom = offset + height;
154652c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com            DrawRect(draw, paint, r, textSize);
154752c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        }
154852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com    }
154952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com}
155052c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com
15518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawText(const void* text, size_t byteLength,
15528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SkScalar x, SkScalar y, const SkPaint& paint) {
15534e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
15548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
15564e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1557f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com        iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
155852c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com        DrawTextDecorations(iter, dfp.paint(),
155952c748b1691f02f90b27c35bc05074fcef709e66bungeman@google.com                            static_cast<const char*>(text), byteLength, x, y);
15608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
15618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15624e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
15638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
15648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPosText(const void* text, size_t byteLength,
15668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                           const SkPoint pos[], const SkPaint& paint) {
15674e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
15684b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
15698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
15704e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
15718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
1572f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com                                  dfp.paint());
15738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
15744b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
15754e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
15768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
15778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPosTextH(const void* text, size_t byteLength,
15798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const SkScalar xpos[], SkScalar constY,
15808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const SkPaint& paint) {
15814e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
15824b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
15838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
15844e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
15858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
1586f67e4cf4c18cd228738a11372859ee0280bce1d7reed@google.com                                  dfp.paint());
15878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
15884b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
15894e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
15908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
15918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
15938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              const SkPath& path, const SkMatrix* matrix,
15948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              const SkPaint& paint) {
15954e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
15968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
15988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
15994e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                                     matrix, looper.paint());
16008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
16018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16024e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
16038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
16048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1605cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com#ifdef ANDROID
1606cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.comvoid SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength,
1607cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com                                 const SkPoint pos[], const SkPaint& paint,
1608cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com                                 const SkPath& path, const SkMatrix* matrix) {
16094e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1610cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com
1611cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com    while (iter.next()) {
1612cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com        iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos,
16134e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                                        looper.paint(), path, matrix);
1614cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com    }
1615cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com
16164e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
1617cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com}
1618cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com#endif
1619cd9d69b9ce7eb301a9fd8d91b9f95fd99b07bae5djsollen@google.com
16208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
16218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const SkPoint verts[], const SkPoint texs[],
16228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const SkColor colors[], SkXfermode* xmode,
16238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const uint16_t indices[], int indexCount,
16248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const SkPaint& paint) {
16254e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
16264b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
16278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (iter.next()) {
16288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
16294e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                                   colors, xmode, indices, indexCount,
16304e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                                   looper.paint());
16318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
16324b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
16334e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    LOOPER_END
16348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
16358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1636cb60844b34766aad4151df5e87c144d4a57e9abereed@android.comvoid SkCanvas::drawData(const void* data, size_t length) {
1637cb60844b34766aad4151df5e87c144d4a57e9abereed@android.com    // do nothing. Subclasses may do something with the data
1638cb60844b34766aad4151df5e87c144d4a57e9abereed@android.com}
1639cb60844b34766aad4151df5e87c144d4a57e9abereed@android.com
16408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
16418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// These methods are NOT virtual, and therefore must call back into virtual
16428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// methods, rather than actually drawing themselves.
16438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
16448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
1646845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com                        SkXfermode::Mode mode) {
16478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPaint paint;
16488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    paint.setARGB(a, r, g, b);
1650845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com    if (SkXfermode::kSrcOver_Mode != mode) {
16510baf19375466cfc24c96532df406e7c5b1d1aae8reed@android.com        paint.setXfermodeMode(mode);
16528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
16538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPaint(paint);
16548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
16558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1656845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.comvoid SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
16578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPaint paint;
16588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    paint.setColor(c);
1660845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com    if (SkXfermode::kSrcOver_Mode != mode) {
16610baf19375466cfc24c96532df406e7c5b1d1aae8reed@android.com        paint.setXfermodeMode(mode);
16628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
16638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPaint(paint);
16648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
16658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
16678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint pt;
16684b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
16698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pt.set(x, y);
16708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
16718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
16728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
16748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint pt;
16758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPaint paint;
16764b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
16778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pt.set(x, y);
16788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    paint.setColor(color);
16798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
16808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
16818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
16838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        const SkPaint& paint) {
16848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint pts[2];
16854b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
16868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pts[0].set(x0, y0);
16878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pts[1].set(x1, y1);
16888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPoints(kLines_PointMode, 2, pts, paint);
16898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
16908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
16928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              SkScalar right, SkScalar bottom,
16938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              const SkPaint& paint) {
16948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRect  r;
16958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    r.set(left, top, right, bottom);
16978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawRect(r, paint);
16988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
16998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
17018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                          const SkPaint& paint) {
17028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (radius < 0) {
17038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        radius = 0;
17048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
17058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRect  r;
17078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    r.set(cx - radius, cy - radius, cx + radius, cy + radius);
17084b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
17098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (paint.canComputeFastBounds()) {
17108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRect storage;
17118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (this->quickReject(paint.computeFastBounds(r, &storage),
17128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              paint2EdgeType(&paint))) {
17138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
17148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
17158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
17164b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
17178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath  path;
17188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path.addOval(r);
17198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPath(path, paint);
17208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
17218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
17238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                             const SkPaint& paint) {
17248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (rx > 0 && ry > 0) {
17258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (paint.canComputeFastBounds()) {
17268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkRect storage;
17278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (this->quickReject(paint.computeFastBounds(r, &storage),
17288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                  paint2EdgeType(&paint))) {
17298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return;
17308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
17318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
17328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPath  path;
17348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
17358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->drawPath(path, paint);
17368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
17378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->drawRect(r, paint);
17388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
17398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
17408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
17428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (paint.canComputeFastBounds()) {
17438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRect storage;
17448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (this->quickReject(paint.computeFastBounds(oval, &storage),
17458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              paint2EdgeType(&paint))) {
17468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
17478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
17488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
17498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath  path;
17518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path.addOval(oval);
17528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawPath(path, paint);
17538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
17548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
17568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                       SkScalar sweepAngle, bool useCenter,
17578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                       const SkPaint& paint) {
17588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
17598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->drawOval(oval, paint);
17608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
17618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPath  path;
17628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (useCenter) {
17638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            path.moveTo(oval.centerX(), oval.centerY());
17648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
17658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        path.arcTo(oval, startAngle, sweepAngle, !useCenter);
17668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (useCenter) {
17678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            path.close();
17688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
17698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->drawPath(path, paint);
17708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
17718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
17728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
17748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                const SkPath& path, SkScalar hOffset,
17758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                SkScalar vOffset, const SkPaint& paint) {
17768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix    matrix;
17774b226023832011bc3bcdd1e5092ff0645ad0bdeereed@google.com
17788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    matrix.setTranslate(hOffset, vOffset);
17798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->drawTextOnPath(text, byteLength, path, &matrix, paint);
17808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
17818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1782f76bacff7f66724072c67edb185abf9e3add11a0reed@android.com///////////////////////////////////////////////////////////////////////////////
1783f76bacff7f66724072c67edb185abf9e3add11a0reed@android.com
17848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::drawPicture(SkPicture& picture) {
17858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int saveCount = save();
17868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    picture.draw(this);
17878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    restoreToCount(saveCount);
17888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
17898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
17918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
17928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
1794d642329293cce602ac24df8f585c14a98795da87reed@google.com    SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
17958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(canvas);
17978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
17998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDone = !fImpl->next();
18008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
18018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCanvas::LayerIter::~LayerIter() {
18038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fImpl->~SkDrawIter();
18048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
18058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCanvas::LayerIter::next() {
18078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDone = !fImpl->next();
18088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
18098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkDevice* SkCanvas::LayerIter::device() const {
18118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fImpl->getDevice();
18128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
18138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkMatrix& SkCanvas::LayerIter::matrix() const {
18158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fImpl->getMatrix();
18168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
18178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkPaint& SkCanvas::LayerIter::paint() const {
18198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkPaint* paint = fImpl->getPaint();
18208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL == paint) {
18218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        paint = &fDefaultPaint;
18228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
18238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return *paint;
18248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
18258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
18268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
18278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCanvas::LayerIter::x() const { return fImpl->getX(); }
18288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkCanvas::LayerIter::y() const { return fImpl->getY(); }
1829