153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com/*
253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com * Copyright 2013 Google Inc.
353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com *
453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com * Use of this source code is governed by a BSD-style license that can be
553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com * found in the LICENSE file.
653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com */
753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com#include "SkBitmapDevice.h"
953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com#include "SkConfig8888.h"
10b2db898573e3cdcc8234eebf51961bfc4977ebbcreed#include "SkDeviceProperties.h"
1153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com#include "SkDraw.h"
1253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com#include "SkRasterClip.h"
1353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com#include "SkShader.h"
1476f10a3bd936af7dbe2b5873d5a7eedd73cdc5dareed@google.com#include "SkSurface.h"
1553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
164469938e92d779dff05e745559e67907bbf21e78reed@google.com#define CHECK_FOR_ANNOTATION(paint) \
174469938e92d779dff05e745559e67907bbf21e78reed@google.com    do { if (paint.getAnnotation()) { return; } } while (0)
1853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
1915a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.orgstatic bool valid_for_bitmap_device(const SkImageInfo& info,
2015a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org                                    SkAlphaType* newAlphaType) {
2115a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    if (info.width() < 0 || info.height() < 0) {
2215a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        return false;
2315a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    }
2415a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org
2515a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    // TODO: can we stop supporting kUnknown in SkBitmkapDevice?
2615a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    if (kUnknown_SkColorType == info.colorType()) {
2715a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        if (newAlphaType) {
2844977485bdac75c055c3fa638f118874ccd2d22freed            *newAlphaType = kUnknown_SkAlphaType;
2915a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        }
3015a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        return true;
3115a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    }
32969588f0c9030d5a4942085a4b5a5ea7e8d2bc25skia.committer@gmail.com
3315a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    switch (info.alphaType()) {
3415a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        case kPremul_SkAlphaType:
3515a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        case kOpaque_SkAlphaType:
3615a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org            break;
3715a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        default:
3815a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org            return false;
3915a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    }
4015a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org
4115a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    SkAlphaType canonicalAlphaType = info.alphaType();
4215a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org
4315a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    switch (info.colorType()) {
4415a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        case kAlpha_8_SkColorType:
4515a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org            break;
4615a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        case kRGB_565_SkColorType:
4715a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org            canonicalAlphaType = kOpaque_SkAlphaType;
4815a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org            break;
4928fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org        case kN32_SkColorType:
5015a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org            break;
5115a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        default:
5215a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org            return false;
5315a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    }
5415a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org
5515a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    if (newAlphaType) {
5615a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        *newAlphaType = canonicalAlphaType;
5715a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    }
5815a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    return true;
5915a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org}
6015a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org
6115a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.orgSkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
6215a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
6353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
6453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
6553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comSkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties)
6653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    : SkBaseDevice(deviceProperties)
6715a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    , fBitmap(bitmap)
6815a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org{
6915a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
7053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
7153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
7215a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.orgSkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
7315a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org                                       const SkDeviceProperties* props) {
74e5ea500d4714a7d84de2bf913e81be3b65d2de68reed    SkAlphaType newAT = origInfo.alphaType();
75e5ea500d4714a7d84de2bf913e81be3b65d2de68reed    if (!valid_for_bitmap_device(origInfo, &newAT)) {
7615a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        return NULL;
7715a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    }
7815a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org
79e5ea500d4714a7d84de2bf913e81be3b65d2de68reed    const SkImageInfo info = origInfo.makeAlphaType(newAT);
8015a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    SkBitmap bitmap;
8115a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org
8215a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    if (kUnknown_SkColorType == info.colorType()) {
83a3264e53ee3f3c5d6a2c813df7e44b5b96d207f2commit-bot@chromium.org        if (!bitmap.setInfo(info)) {
8415a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org            return NULL;
8515a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        }
8615a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    } else {
87848250415eddc54075f7eb8795e8db79e749c6abreed        if (!bitmap.tryAllocPixels(info)) {
8815a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org            return NULL;
8915a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        }
9015a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        if (!bitmap.info().isOpaque()) {
9115a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org            bitmap.eraseColor(SK_ColorTRANSPARENT);
9215a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        }
9315a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    }
9453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
95b2db898573e3cdcc8234eebf51961bfc4977ebbcreed    if (props) {
96b2db898573e3cdcc8234eebf51961bfc4977ebbcreed        return SkNEW_ARGS(SkBitmapDevice, (bitmap, *props));
9715a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    } else {
9815a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org        return SkNEW_ARGS(SkBitmapDevice, (bitmap));
9915a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    }
10053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
10153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
102c3bd8af6d5722e854feca70c40d92f4954c5b67bcommit-bot@chromium.orgSkImageInfo SkBitmapDevice::imageInfo() const {
103c3bd8af6d5722e854feca70c40d92f4954c5b67bcommit-bot@chromium.org    return fBitmap.info();
104c3bd8af6d5722e854feca70c40d92f4954c5b67bcommit-bot@chromium.org}
105c3bd8af6d5722e854feca70c40d92f4954c5b67bcommit-bot@chromium.org
106feaadee1c38e1d4e1ec0069a3509ef6fbc5fbeffmtkleinvoid SkBitmapDevice::setNewSize(const SkISize& size) {
107feaadee1c38e1d4e1ec0069a3509ef6fbc5fbeffmtklein    SkASSERT(!fBitmap.pixelRef());
108feaadee1c38e1d4e1ec0069a3509ef6fbc5fbeffmtklein    fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight));
109feaadee1c38e1d4e1ec0069a3509ef6fbc5fbeffmtklein}
110feaadee1c38e1d4e1ec0069a3509ef6fbc5fbeffmtklein
11153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
11253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    SkASSERT(bm.width() == fBitmap.width());
11353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    SkASSERT(bm.height() == fBitmap.height());
11453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    fBitmap = bm;   // intent is to use bm's pixelRef (and rowbytes/config)
11553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    fBitmap.lockPixels();
11653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
11753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
11876033be81b82c44fd5d4fdf2672eb22e505da1f0reedSkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
119b2db898573e3cdcc8234eebf51961bfc4977ebbcreed    SkDeviceProperties leaky(cinfo.fPixelGeometry);
120b2db898573e3cdcc8234eebf51961bfc4977ebbcreed    return SkBitmapDevice::Create(cinfo.fInfo, &leaky);
12153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
12253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
12353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::lockPixels() {
12453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    if (fBitmap.lockPixelsAreWritable()) {
12553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        fBitmap.lockPixels();
12653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    }
12753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
12853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
12953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::unlockPixels() {
13053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    if (fBitmap.lockPixelsAreWritable()) {
13153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        fBitmap.unlockPixels();
13253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    }
13353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
13453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
13553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comconst SkBitmap& SkBitmapDevice::onAccessBitmap() {
13653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    return fBitmap;
13753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
13853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
1399c135db83d198e7d8200027c7d2cf60f38517ee3reed@google.comvoid* SkBitmapDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) {
1409c135db83d198e7d8200027c7d2cf60f38517ee3reed@google.com    if (fBitmap.getPixels()) {
1419c135db83d198e7d8200027c7d2cf60f38517ee3reed@google.com        *info = fBitmap.info();
1429c135db83d198e7d8200027c7d2cf60f38517ee3reed@google.com        *rowBytes = fBitmap.rowBytes();
1439c135db83d198e7d8200027c7d2cf60f38517ee3reed@google.com        return fBitmap.getPixels();
1449c135db83d198e7d8200027c7d2cf60f38517ee3reed@google.com    }
1459c135db83d198e7d8200027c7d2cf60f38517ee3reed@google.com    return NULL;
1469c135db83d198e7d8200027c7d2cf60f38517ee3reed@google.com}
1479c135db83d198e7d8200027c7d2cf60f38517ee3reed@google.com
148231f6b81c22001cac4ea87ea412c4d6fd10ffb8acommit-bot@chromium.org#include "SkConfig8888.h"
1490e9770515cab45decb56a5926d1741b71854fb4cpiotaixr#include "SkPixelRef.h"
1507111d463cee893a479280c7af41757e709e33ef5reed@google.com
1514cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.orgbool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
1524cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org                                   size_t srcRowBytes, int x, int y) {
1530d30c51c6cf45b3a08a3000b6d348c16bdec7f05reed@google.com    // since we don't stop creating un-pixeled devices yet, check for no pixels here
1540d30c51c6cf45b3a08a3000b6d348c16bdec7f05reed@google.com    if (NULL == fBitmap.getPixels()) {
1550d30c51c6cf45b3a08a3000b6d348c16bdec7f05reed@google.com        return false;
1560d30c51c6cf45b3a08a3000b6d348c16bdec7f05reed@google.com    }
1570d30c51c6cf45b3a08a3000b6d348c16bdec7f05reed@google.com
158e5ea500d4714a7d84de2bf913e81be3b65d2de68reed    const SkImageInfo dstInfo = fBitmap.info().makeWH(srcInfo.width(), srcInfo.height());
1594cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org
1604cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org    void* dstPixels = fBitmap.getAddr(x, y);
1614cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org    size_t dstRowBytes = fBitmap.rowBytes();
1624cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org
163b184f7f52b2a94e95aee326a3ca37110d2e43336reed    if (SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
1644cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org        fBitmap.notifyPixelsChanged();
1654cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org        return true;
1664cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org    }
1674cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org    return false;
1684cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org}
16953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
170a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.orgbool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
171a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org                                  int x, int y) {
172b184f7f52b2a94e95aee326a3ca37110d2e43336reed    return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y);
173a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org}
174a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org
17553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com///////////////////////////////////////////////////////////////////////////////
17653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
17753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
17853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    draw.drawPaint(paint);
17953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
18053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
18153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
18253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                                const SkPoint pts[], const SkPaint& paint) {
1834469938e92d779dff05e745559e67907bbf21e78reed@google.com    CHECK_FOR_ANNOTATION(paint);
18453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    draw.drawPoints(mode, count, pts, paint);
18553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
18653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
18753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
1884469938e92d779dff05e745559e67907bbf21e78reed@google.com    CHECK_FOR_ANNOTATION(paint);
18953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    draw.drawRect(r, paint);
19053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
19153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
19253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
1934469938e92d779dff05e745559e67907bbf21e78reed@google.com    CHECK_FOR_ANNOTATION(paint);
19453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
19553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    SkPath path;
19653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    path.addOval(oval);
19753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
19853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    // required to override drawOval.
19953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    this->drawPath(draw, path, paint, NULL, true);
20053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
20153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
20253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
2034469938e92d779dff05e745559e67907bbf21e78reed@google.com    CHECK_FOR_ANNOTATION(paint);
20453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
20550a7600d05d427c64f77d39c8c18d2bf6cabd25brobertphillips@google.com#ifdef SK_IGNORE_BLURRED_RRECT_OPT
20650a7600d05d427c64f77d39c8c18d2bf6cabd25brobertphillips@google.com    SkPath  path;
20750a7600d05d427c64f77d39c8c18d2bf6cabd25brobertphillips@google.com
20850a7600d05d427c64f77d39c8c18d2bf6cabd25brobertphillips@google.com    path.addRRect(rrect);
20950a7600d05d427c64f77d39c8c18d2bf6cabd25brobertphillips@google.com    // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
21050a7600d05d427c64f77d39c8c18d2bf6cabd25brobertphillips@google.com    // required to override drawRRect.
21150a7600d05d427c64f77d39c8c18d2bf6cabd25brobertphillips@google.com    this->drawPath(draw, path, paint, NULL, true);
21250a7600d05d427c64f77d39c8c18d2bf6cabd25brobertphillips@google.com#else
213a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    draw.drawRRect(rrect, paint);
21450a7600d05d427c64f77d39c8c18d2bf6cabd25brobertphillips@google.com#endif
21553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
21653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
21753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
21853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                              const SkPaint& paint, const SkMatrix* prePathMatrix,
21953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                              bool pathIsMutable) {
2204469938e92d779dff05e745559e67907bbf21e78reed@google.com    CHECK_FOR_ANNOTATION(paint);
22153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
22253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
22353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
22453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
22553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                                const SkMatrix& matrix, const SkPaint& paint) {
2260393912de72bc3d8b3640c122c53470dd0da1e6dreed    draw.drawBitmap(bitmap, matrix, NULL, paint);
22753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
22853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
22953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
23053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                                    const SkRect* src, const SkRect& dst,
23153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                                    const SkPaint& paint,
23253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                                    SkCanvas::DrawBitmapRectFlags flags) {
23353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    SkMatrix    matrix;
23453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    SkRect      bitmapBounds, tmpSrc, tmpDst;
23553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    SkBitmap    tmpBitmap;
23653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
23753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    bitmapBounds.isetWH(bitmap.width(), bitmap.height());
23853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
23953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    // Compute matrix from the two rectangles
24053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    if (src) {
24153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        tmpSrc = *src;
24253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    } else {
24353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        tmpSrc = bitmapBounds;
24453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    }
24553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
24653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
24753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    const SkRect* dstPtr = &dst;
24853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    const SkBitmap* bitmapPtr = &bitmap;
24953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
25053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
25153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    // needed (if the src was clipped). No check needed if src==null.
25253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    if (src) {
25353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        if (!bitmapBounds.contains(*src)) {
25453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com            if (!tmpSrc.intersect(bitmapBounds)) {
25553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                return; // nothing to draw
25653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com            }
25753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com            // recompute dst, based on the smaller tmpSrc
25853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com            matrix.mapRect(&tmpDst, tmpSrc);
25953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com            dstPtr = &tmpDst;
26053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        }
26153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
26253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        // since we may need to clamp to the borders of the src rect within
26353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        // the bitmap, we extract a subset.
264b07a94f1cba3976596ae1a7f23d8c2043ba353f3reed        const SkIRect srcIR = tmpSrc.roundOut();
2650e9770515cab45decb56a5926d1741b71854fb4cpiotaixr        if(bitmap.pixelRef()->getTexture()) {
2660e9770515cab45decb56a5926d1741b71854fb4cpiotaixr            // Accelerated source canvas, don't use extractSubset but readPixels to get the subset.
2670e9770515cab45decb56a5926d1741b71854fb4cpiotaixr            // This way, the pixels are copied in CPU memory instead of GPU memory.
2680e9770515cab45decb56a5926d1741b71854fb4cpiotaixr            bitmap.pixelRef()->readPixels(&tmpBitmap, &srcIR);
2690e9770515cab45decb56a5926d1741b71854fb4cpiotaixr        } else {
2700e9770515cab45decb56a5926d1741b71854fb4cpiotaixr            if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
2710e9770515cab45decb56a5926d1741b71854fb4cpiotaixr                return;
2720e9770515cab45decb56a5926d1741b71854fb4cpiotaixr            }
27353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        }
27453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        bitmapPtr = &tmpBitmap;
27553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
27653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        // Since we did an extract, we need to adjust the matrix accordingly
27753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        SkScalar dx = 0, dy = 0;
27853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        if (srcIR.fLeft > 0) {
27953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com            dx = SkIntToScalar(srcIR.fLeft);
28053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        }
28153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        if (srcIR.fTop > 0) {
28253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com            dy = SkIntToScalar(srcIR.fTop);
28353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        }
28453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        if (dx || dy) {
28553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com            matrix.preTranslate(dx, dy);
28653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        }
28753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
28853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        SkRect extractedBitmapBounds;
28953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
29053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        if (extractedBitmapBounds == tmpSrc) {
29153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com            // no fractional part in src, we can just call drawBitmap
29253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com            goto USE_DRAWBITMAP;
29353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        }
29453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    } else {
29553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        USE_DRAWBITMAP:
29653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        // We can go faster by just calling drawBitmap, which will concat the
29753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        // matrix with the CTM, and try to call drawSprite if it can. If not,
29853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        // it will make a shader and call drawRect, as we do below.
2990393912de72bc3d8b3640c122c53470dd0da1e6dreed        draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
30053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        return;
30153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    }
30253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
30353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    // construct a shader, so we can call drawRect with the dst
30453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
30553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                                               SkShader::kClamp_TileMode,
3069c9005a347e9996f357bd79591bd34f74f8bbc66commit-bot@chromium.org                                               SkShader::kClamp_TileMode,
3079c9005a347e9996f357bd79591bd34f74f8bbc66commit-bot@chromium.org                                               &matrix);
30853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    if (NULL == s) {
30953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        return;
31053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    }
31153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
31253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    SkPaint paintWithShader(paint);
31353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    paintWithShader.setStyle(SkPaint::kFill_Style);
31453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    paintWithShader.setShader(s)->unref();
31553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
31653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    // Call ourself, in case the subclass wanted to share this setup code
31753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    // but handle the drawRect code themselves.
31853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    this->drawRect(draw, *dstPtr, paintWithShader);
31953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
32053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
32153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
32253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                                int x, int y, const SkPaint& paint) {
32353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    draw.drawSprite(bitmap, x, y, paint);
32453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
32553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
32653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
32753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                              SkScalar x, SkScalar y, const SkPaint& paint) {
32853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    draw.drawText((const char*)text, len, x, y, paint);
32953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
33053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
33153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
33205c4a4322e7d4f3417b7df33825bab8603d52051fmalita                                 const SkScalar xpos[], int scalarsPerPos,
33305c4a4322e7d4f3417b7df33825bab8603d52051fmalita                                 const SkPoint& offset, const SkPaint& paint) {
33405c4a4322e7d4f3417b7df33825bab8603d52051fmalita    draw.drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint);
33553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
33653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
33753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
33853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                                  int vertexCount,
33953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                                  const SkPoint verts[], const SkPoint textures[],
34053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                                  const SkColor colors[], SkXfermode* xmode,
34153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                                  const uint16_t indices[], int indexCount,
34253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                                  const SkPaint& paint) {
34353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
34453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                      indices, indexCount, paint);
34553238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
34653238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
34753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.comvoid SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
34853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com                                int x, int y, const SkPaint& paint) {
34953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    const SkBitmap& src = device->accessBitmap(false);
35053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    draw.drawSprite(src, x, y, paint);
35153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
35253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
3534a8126e7f81384526629b1e21bf89b632ea13cd9reedSkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
3544a8126e7f81384526629b1e21bf89b632ea13cd9reed    return SkSurface::NewRaster(info, &props);
35576f10a3bd936af7dbe2b5873d5a7eedd73cdc5dareed@google.com}
35676f10a3bd936af7dbe2b5873d5a7eedd73cdc5dareed@google.com
357c3bd8af6d5722e854feca70c40d92f4954c5b67bcommit-bot@chromium.orgconst void* SkBitmapDevice::peekPixels(SkImageInfo* info, size_t* rowBytes) {
358466f5f3e44e703ca58b43ac1c4ac3bfa0e1ff024commit-bot@chromium.org    const SkImageInfo bmInfo = fBitmap.info();
359466f5f3e44e703ca58b43ac1c4ac3bfa0e1ff024commit-bot@chromium.org    if (fBitmap.getPixels() && (kUnknown_SkColorType != bmInfo.colorType())) {
360466f5f3e44e703ca58b43ac1c4ac3bfa0e1ff024commit-bot@chromium.org        if (info) {
361466f5f3e44e703ca58b43ac1c4ac3bfa0e1ff024commit-bot@chromium.org            *info = bmInfo;
362466f5f3e44e703ca58b43ac1c4ac3bfa0e1ff024commit-bot@chromium.org        }
363c3bd8af6d5722e854feca70c40d92f4954c5b67bcommit-bot@chromium.org        if (rowBytes) {
364c3bd8af6d5722e854feca70c40d92f4954c5b67bcommit-bot@chromium.org            *rowBytes = fBitmap.rowBytes();
365c3bd8af6d5722e854feca70c40d92f4954c5b67bcommit-bot@chromium.org        }
366c3bd8af6d5722e854feca70c40d92f4954c5b67bcommit-bot@chromium.org        return fBitmap.getPixels();
367c3bd8af6d5722e854feca70c40d92f4954c5b67bcommit-bot@chromium.org    }
368c3bd8af6d5722e854feca70c40d92f4954c5b67bcommit-bot@chromium.org    return NULL;
369c3bd8af6d5722e854feca70c40d92f4954c5b67bcommit-bot@chromium.org}
370c3bd8af6d5722e854feca70c40d92f4954c5b67bcommit-bot@chromium.org
371be129b26f13d575fd6b396c6ae759838ecc9bd1asenorblancoSkImageFilter::Cache* SkBitmapDevice::getImageFilterCache() {
372be129b26f13d575fd6b396c6ae759838ecc9bd1asenorblanco    SkImageFilter::Cache* cache = SkImageFilter::Cache::Get();
37355b6d8be997a447ef9ce0f029697677a940bfc24senorblanco    cache->ref();
37455b6d8be997a447ef9ce0f029697677a940bfc24senorblanco    return cache;
37555b6d8be997a447ef9ce0f029697677a940bfc24senorblanco}
37655b6d8be997a447ef9ce0f029697677a940bfc24senorblanco
37753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com///////////////////////////////////////////////////////////////////////////////
37853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com
379b2db898573e3cdcc8234eebf51961bfc4977ebbcreedbool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const {
380cba73780bbd12fd254229517aec04fcbf0b64b52commit-bot@chromium.org    if (kN32_SkColorType != fBitmap.colorType() ||
38153238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        paint.getRasterizer() ||
38253238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        paint.getPathEffect() ||
38353238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        paint.isFakeBoldText() ||
38453238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        paint.getStyle() != SkPaint::kFill_Style ||
385b2db898573e3cdcc8234eebf51961bfc4977ebbcreed        !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode))
386b2db898573e3cdcc8234eebf51961bfc4977ebbcreed    {
38753238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com        return true;
38853238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    }
38953238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com    return false;
39053238bc96051d1774b7f72d3ebfd35a7dd4c04dfrobertphillips@google.com}
391