11a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org/*
21a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org * Copyright 2013 Google Inc.
31a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org *
41a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org * Use of this source code is governed by a BSD-style license that can be
51a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org * found in the LICENSE file.
61a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org */
71a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
81a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org#include "SkTileImageFilter.h"
91a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org#include "SkBitmap.h"
101a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org#include "SkCanvas.h"
111a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org#include "SkDevice.h"
1205dcb4c7a9fe350af495e4cc53f8ad0cc9b79052senorblanco#include "SkOffsetImageFilter.h"
138b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
148b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
151a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org#include "SkMatrix.h"
161a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org#include "SkPaint.h"
171a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org#include "SkShader.h"
18c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org#include "SkValidationUtils.h"
191a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
205ea95df02de9cd774d0b84d1341599bbd9c0d8dbreedSkImageFilter* SkTileImageFilter::Create(const SkRect& srcRect, const SkRect& dstRect,
215ea95df02de9cd774d0b84d1341599bbd9c0d8dbreed                                         SkImageFilter* input) {
229fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    if (!SkIsValidRect(srcRect) || !SkIsValidRect(dstRect)) {
2396fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
249fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
2505dcb4c7a9fe350af495e4cc53f8ad0cc9b79052senorblanco    if (srcRect.width() == dstRect.width() && srcRect.height() == dstRect.height()) {
2605dcb4c7a9fe350af495e4cc53f8ad0cc9b79052senorblanco        SkRect ir = dstRect;
2705dcb4c7a9fe350af495e4cc53f8ad0cc9b79052senorblanco        if (!ir.intersect(srcRect)) {
2805dcb4c7a9fe350af495e4cc53f8ad0cc9b79052senorblanco            return SkSafeRef(input);
2905dcb4c7a9fe350af495e4cc53f8ad0cc9b79052senorblanco        }
3005dcb4c7a9fe350af495e4cc53f8ad0cc9b79052senorblanco        CropRect cropRect(ir);
3105dcb4c7a9fe350af495e4cc53f8ad0cc9b79052senorblanco        return SkOffsetImageFilter::Create(dstRect.x() - srcRect.x(),
3205dcb4c7a9fe350af495e4cc53f8ad0cc9b79052senorblanco                                           dstRect.y() - srcRect.y(),
3305dcb4c7a9fe350af495e4cc53f8ad0cc9b79052senorblanco                                           input, &cropRect);
3405dcb4c7a9fe350af495e4cc53f8ad0cc9b79052senorblanco    }
35385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary    return new SkTileImageFilter(srcRect, dstRect, input);
369fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
379fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
3848e78468f5f6b900d476e616bdb1ba457c8f0b2arobertphillipsbool SkTileImageFilter::onFilterImageDeprecated(Proxy* proxy, const SkBitmap& src,
3948e78468f5f6b900d476e616bdb1ba457c8f0b2arobertphillips                                                const Context& ctx,
4048e78468f5f6b900d476e616bdb1ba457c8f0b2arobertphillips                                                SkBitmap* dst, SkIPoint* offset) const {
41d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    SkBitmap source = src;
42d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    SkIPoint srcOffset = SkIPoint::Make(0, 0);
4348e78468f5f6b900d476e616bdb1ba457c8f0b2arobertphillips    if (!this->filterInputDeprecated(0, proxy, src, ctx, &source, &srcOffset)) {
44d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips        return false;
45d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    }
461a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
47e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org    SkRect dstRect;
484cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    ctx.ctm().mapRect(&dstRect, fDstRect);
49b50b97d70a62d90f5266113c9a5ba6cd1b912eddsenorblanco    if (!dstRect.intersect(SkRect::Make(ctx.clipBounds()))) {
50b50b97d70a62d90f5266113c9a5ba6cd1b912eddsenorblanco        offset->fX = offset->fY = 0;
51b50b97d70a62d90f5266113c9a5ba6cd1b912eddsenorblanco        return true;
52b50b97d70a62d90f5266113c9a5ba6cd1b912eddsenorblanco    }
53b07a94f1cba3976596ae1a7f23d8c2043ba353f3reed    const SkIRect dstIRect = dstRect.roundOut();
54d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    int w = dstIRect.width();
55d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    int h = dstIRect.height();
56d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    if (!fSrcRect.width() || !fSrcRect.height() || !w || !h) {
571a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org        return false;
581a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    }
591a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
60e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org    SkRect srcRect;
614cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    ctx.ctm().mapRect(&srcRect, fSrcRect);
62e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org    SkIRect srcIRect;
63e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org    srcRect.roundOut(&srcIRect);
646776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    srcIRect.offset(-srcOffset);
651a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    SkBitmap subset;
66a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco    SkIRect srcBounds;
67a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco    source.getBounds(&srcBounds);
686776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org
69a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco    if (!SkIRect::Intersects(srcIRect, srcBounds)) {
706776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org        offset->fX = offset->fY = 0;
71e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org        return true;
721a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    }
73a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco    if (srcBounds.contains(srcIRect)) {
74a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco        if (!source.extractSubset(&subset, srcIRect)) {
75a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco            return false;
76a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco        }
77a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco    } else {
78a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco        SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(srcIRect.width(),
79a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco                                                              srcIRect.height(),
80a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco                                                              kPossible_TileUsage));
81a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco        if (!device) {
82a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco            return false;
83a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco        }
84a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco        SkCanvas canvas(device);
85a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco        canvas.drawBitmap(src, SkIntToScalar(srcOffset.x()),
86a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco                               SkIntToScalar(srcOffset.y()));
87a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco        subset = device->accessBitmap(false);
88a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco    }
89a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco    SkASSERT(subset.width() == srcIRect.width());
90a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco    SkASSERT(subset.height() == srcIRect.height());
911a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
92d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(w, h));
9396fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (nullptr == device.get()) {
94cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org        return false;
95cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org    }
961a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    SkCanvas canvas(device);
971a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    SkPaint paint;
981a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
991a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
1009c9005a347e9996f357bd79591bd34f74f8bbc66commit-bot@chromium.org    SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(subset,
101a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco                                  SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
1021a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    paint.setShader(shader);
1036776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    canvas.translate(-dstRect.fLeft, -dstRect.fTop);
1041a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    canvas.drawRect(dstRect, paint);
1051a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    *dst = device->accessBitmap(false);
1066776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    offset->fX = dstIRect.fLeft;
1076776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    offset->fY = dstIRect.fTop;
1081a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    return true;
1091a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org}
1101a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
111db64af3b178a19ecb47d2b9a373113687d8921fdsenorblancovoid SkTileImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
112db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco                                          SkIRect* dst, MapDirection direction) const {
113db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco    SkRect rect = kReverse_MapDirection == direction ? fSrcRect : fDstRect;
114db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco    ctm.mapRect(&rect);
115db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco    rect.roundOut(dst);
116db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco}
117db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco
1180a5c233e3b911232c0d6f9a88ded99ecf88b8a97senorblanco@chromium.orgbool SkTileImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
119d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco                                       SkIRect* dst, MapDirection direction) const {
120d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco    // Don't recurse into inputs.
121d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco    *dst = src;
1220a5c233e3b911232c0d6f9a88ded99ecf88b8a97senorblanco@chromium.org    return true;
1230a5c233e3b911232c0d6f9a88ded99ecf88b8a97senorblanco@chromium.org}
1240a5c233e3b911232c0d6f9a88ded99ecf88b8a97senorblanco@chromium.org
125c3176aa5e578cc64a2534a9ddac2fec5ab6d8d77robertphillipsvoid SkTileImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
126db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco    *dst = fDstRect;
127c3176aa5e578cc64a2534a9ddac2fec5ab6d8d77robertphillips}
128c3176aa5e578cc64a2534a9ddac2fec5ab6d8d77robertphillips
1299fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkTileImageFilter::CreateProc(SkReadBuffer& buffer) {
1309fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1319fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkRect src, dst;
1329fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    buffer.readRect(&src);
1339fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    buffer.readRect(&dst);
13424e06d5244ae96e440410e1d76e039983b2efac9senorblanco    return Create(src, dst, common.getInput(0));
1359fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
1361a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
1378b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkTileImageFilter::flatten(SkWriteBuffer& buffer) const {
1381a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    this->INHERITED::flatten(buffer);
1391a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    buffer.writeRect(fSrcRect);
1401a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    buffer.writeRect(fDstRect);
1411a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org}
142f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips
143f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#ifndef SK_IGNORE_TO_STRING
144f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillipsvoid SkTileImageFilter::toString(SkString* str) const {
145f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("SkTileImageFilter: (");
14663195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips    str->appendf("src: %.2f %.2f %.2f %.2f",
14763195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips                 fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom);
14863195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips    str->appendf(" dst: %.2f %.2f %.2f %.2f",
14963195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips                 fDstRect.fLeft, fDstRect.fTop, fDstRect.fRight, fDstRect.fBottom);
15063195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips    if (this->getInput(0)) {
151d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips        str->appendf("input: (");
15263195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips        this->getInput(0)->toString(str);
15363195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips        str->appendf(")");
15463195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips    }
155f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->append(")");
156f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips}
157f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#endif
158