SkTileImageFilter.cpp revision b50b97d70a62d90f5266113c9a5ba6cd1b912edd
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"
128b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
138b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
141a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org#include "SkMatrix.h"
151a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org#include "SkPaint.h"
161a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org#include "SkShader.h"
17c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org#include "SkValidationUtils.h"
181a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
195ea95df02de9cd774d0b84d1341599bbd9c0d8dbreedSkImageFilter* SkTileImageFilter::Create(const SkRect& srcRect, const SkRect& dstRect,
205ea95df02de9cd774d0b84d1341599bbd9c0d8dbreed                                         SkImageFilter* input) {
219fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    if (!SkIsValidRect(srcRect) || !SkIsValidRect(dstRect)) {
2296fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
239fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
24385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary    return new SkTileImageFilter(srcRect, dstRect, input);
259fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
269fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
27f7efa502d62af80bd15b03e1131603fb6577c3dfcommit-bot@chromium.orgbool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
28f7efa502d62af80bd15b03e1131603fb6577c3dfcommit-bot@chromium.org                                      const Context& ctx,
29ae761f7545d8ebf181d220169afac2056b057b8ccommit-bot@chromium.org                                      SkBitmap* dst, SkIPoint* offset) const {
30d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    SkBitmap source = src;
31d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    SkIPoint srcOffset = SkIPoint::Make(0, 0);
32b9519f86bbce946e505980a4fa950fdc4bcf74absenorblanco    if (!this->filterInput(0, proxy, src, ctx, &source, &srcOffset)) {
33d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips        return false;
34d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    }
351a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
36e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org    SkRect dstRect;
374cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    ctx.ctm().mapRect(&dstRect, fDstRect);
38b50b97d70a62d90f5266113c9a5ba6cd1b912eddsenorblanco#ifndef SK_DISABLE_TILE_IMAGE_FILTER_DEST_OPTIMIZATION
39b50b97d70a62d90f5266113c9a5ba6cd1b912eddsenorblanco    if (!dstRect.intersect(SkRect::Make(ctx.clipBounds()))) {
40b50b97d70a62d90f5266113c9a5ba6cd1b912eddsenorblanco        offset->fX = offset->fY = 0;
41b50b97d70a62d90f5266113c9a5ba6cd1b912eddsenorblanco        return true;
42b50b97d70a62d90f5266113c9a5ba6cd1b912eddsenorblanco    }
43b50b97d70a62d90f5266113c9a5ba6cd1b912eddsenorblanco#endif
44b07a94f1cba3976596ae1a7f23d8c2043ba353f3reed    const SkIRect dstIRect = dstRect.roundOut();
45d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    int w = dstIRect.width();
46d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    int h = dstIRect.height();
47d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    if (!fSrcRect.width() || !fSrcRect.height() || !w || !h) {
481a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org        return false;
491a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    }
501a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
51e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org    SkRect srcRect;
524cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    ctx.ctm().mapRect(&srcRect, fSrcRect);
53e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org    SkIRect srcIRect;
54e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org    srcRect.roundOut(&srcIRect);
556776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    srcIRect.offset(-srcOffset);
561a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    SkBitmap subset;
57e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org    SkIRect bounds;
58e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org    source.getBounds(&bounds);
596776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org
60e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org    if (!srcIRect.intersect(bounds)) {
616776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org        offset->fX = offset->fY = 0;
62e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org        return true;
63e93e1dbf0eced1e1b9aeed7c0c170961e2d61e32senorblanco@chromium.org    } else if (!source.extractSubset(&subset, srcIRect)) {
641a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org        return false;
651a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    }
661a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
67d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(w, h));
6896fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (nullptr == device.get()) {
69cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org        return false;
70cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org    }
711a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    SkCanvas canvas(device);
721a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    SkPaint paint;
731a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
741a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
756776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    SkMatrix shaderMatrix;
766776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    shaderMatrix.setTranslate(SkIntToScalar(srcOffset.fX),
776776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org                              SkIntToScalar(srcOffset.fY));
789c9005a347e9996f357bd79591bd34f74f8bbc66commit-bot@chromium.org    SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(subset,
799c9005a347e9996f357bd79591bd34f74f8bbc66commit-bot@chromium.org                                  SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode,
809c9005a347e9996f357bd79591bd34f74f8bbc66commit-bot@chromium.org                                  &shaderMatrix));
811a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    paint.setShader(shader);
826776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    canvas.translate(-dstRect.fLeft, -dstRect.fTop);
831a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    canvas.drawRect(dstRect, paint);
841a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    *dst = device->accessBitmap(false);
856776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    offset->fX = dstIRect.fLeft;
866776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    offset->fY = dstIRect.fTop;
871a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    return true;
881a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org}
891a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
90db64af3b178a19ecb47d2b9a373113687d8921fdsenorblancovoid SkTileImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
91db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco                                          SkIRect* dst, MapDirection direction) const {
92db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco    SkRect rect = kReverse_MapDirection == direction ? fSrcRect : fDstRect;
93db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco    ctm.mapRect(&rect);
94db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco    rect.roundOut(dst);
95db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
96db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco    dst->join(src);
97db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco#endif
98db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco}
99db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco
1000a5c233e3b911232c0d6f9a88ded99ecf88b8a97senorblanco@chromium.orgbool SkTileImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
1010a5c233e3b911232c0d6f9a88ded99ecf88b8a97senorblanco@chromium.org                                       SkIRect* dst) const {
102db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco    this->onFilterNodeBounds(src, ctm, dst, kReverse_MapDirection);
1030a5c233e3b911232c0d6f9a88ded99ecf88b8a97senorblanco@chromium.org    return true;
1040a5c233e3b911232c0d6f9a88ded99ecf88b8a97senorblanco@chromium.org}
1050a5c233e3b911232c0d6f9a88ded99ecf88b8a97senorblanco@chromium.org
106c3176aa5e578cc64a2534a9ddac2fec5ab6d8d77robertphillipsvoid SkTileImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
107db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
108c3176aa5e578cc64a2534a9ddac2fec5ab6d8d77robertphillips    // This is a workaround for skia:3194.
109c3176aa5e578cc64a2534a9ddac2fec5ab6d8d77robertphillips    *dst = src;
110c3176aa5e578cc64a2534a9ddac2fec5ab6d8d77robertphillips    dst->join(fDstRect);
111db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco#else
112db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco    *dst = fDstRect;
113db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco#endif
114c3176aa5e578cc64a2534a9ddac2fec5ab6d8d77robertphillips}
115c3176aa5e578cc64a2534a9ddac2fec5ab6d8d77robertphillips
1169fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkTileImageFilter::CreateProc(SkReadBuffer& buffer) {
1179fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1189fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkRect src, dst;
1199fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    buffer.readRect(&src);
1209fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    buffer.readRect(&dst);
12124e06d5244ae96e440410e1d76e039983b2efac9senorblanco    return Create(src, dst, common.getInput(0));
1229fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
1231a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
1248b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkTileImageFilter::flatten(SkWriteBuffer& buffer) const {
1251a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    this->INHERITED::flatten(buffer);
1261a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    buffer.writeRect(fSrcRect);
1271a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    buffer.writeRect(fDstRect);
1281a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org}
129f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips
130f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#ifndef SK_IGNORE_TO_STRING
131f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillipsvoid SkTileImageFilter::toString(SkString* str) const {
132f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("SkTileImageFilter: (");
13363195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips    str->appendf("src: %.2f %.2f %.2f %.2f",
13463195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips                 fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom);
13563195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips    str->appendf(" dst: %.2f %.2f %.2f %.2f",
13663195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips                 fDstRect.fLeft, fDstRect.fTop, fDstRect.fRight, fDstRect.fBottom);
13763195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips    if (this->getInput(0)) {
138d312dcade1e54a687b18755b5b8efbc0d01ec69erobertphillips        str->appendf("input: (");
13963195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips        this->getInput(0)->toString(str);
14063195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips        str->appendf(")");
14163195181d12751bed2fae6e167c7bed7f4a2de2arobertphillips    }
142f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->append(")");
143f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips}
144f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#endif
145