blob: 66cad47ad031dda661e88d0ef5df09bb55cc2409 [file] [log] [blame]
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkTileImageFilter.h"
9#include "SkBitmap.h"
10#include "SkCanvas.h"
11#include "SkDevice.h"
senorblanco05dcb4c2016-01-12 07:49:15 -080012#include "SkOffsetImageFilter.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000013#include "SkReadBuffer.h"
14#include "SkWriteBuffer.h"
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000015#include "SkMatrix.h"
16#include "SkPaint.h"
17#include "SkShader.h"
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +000018#include "SkValidationUtils.h"
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000019
reed5ea95df2015-10-06 14:05:32 -070020SkImageFilter* SkTileImageFilter::Create(const SkRect& srcRect, const SkRect& dstRect,
21 SkImageFilter* input) {
reed9fa60da2014-08-21 07:59:51 -070022 if (!SkIsValidRect(srcRect) || !SkIsValidRect(dstRect)) {
halcanary96fcdcc2015-08-27 07:41:13 -070023 return nullptr;
reed9fa60da2014-08-21 07:59:51 -070024 }
senorblanco05dcb4c2016-01-12 07:49:15 -080025 if (srcRect.width() == dstRect.width() && srcRect.height() == dstRect.height()) {
26 SkRect ir = dstRect;
27 if (!ir.intersect(srcRect)) {
28 return SkSafeRef(input);
29 }
30 CropRect cropRect(ir);
31 return SkOffsetImageFilter::Create(dstRect.x() - srcRect.x(),
32 dstRect.y() - srcRect.y(),
33 input, &cropRect);
34 }
halcanary385fe4d2015-08-26 13:07:48 -070035 return new SkTileImageFilter(srcRect, dstRect, input);
reed9fa60da2014-08-21 07:59:51 -070036}
37
robertphillips48e78462016-02-17 13:57:16 -080038bool SkTileImageFilter::onFilterImageDeprecated(Proxy* proxy, const SkBitmap& src,
39 const Context& ctx,
40 SkBitmap* dst, SkIPoint* offset) const {
robertphillipsd312dca2015-07-06 07:59:09 -070041 SkBitmap source = src;
robertphillipsd312dca2015-07-06 07:59:09 -070042 SkIPoint srcOffset = SkIPoint::Make(0, 0);
robertphillips48e78462016-02-17 13:57:16 -080043 if (!this->filterInputDeprecated(0, proxy, src, ctx, &source, &srcOffset)) {
robertphillipsd312dca2015-07-06 07:59:09 -070044 return false;
45 }
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000046
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +000047 SkRect dstRect;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000048 ctx.ctm().mapRect(&dstRect, fDstRect);
senorblancob50b97d2016-01-06 09:46:24 -080049 if (!dstRect.intersect(SkRect::Make(ctx.clipBounds()))) {
50 offset->fX = offset->fY = 0;
51 return true;
52 }
reedb07a94f2014-11-19 05:03:18 -080053 const SkIRect dstIRect = dstRect.roundOut();
robertphillipsd312dca2015-07-06 07:59:09 -070054 int w = dstIRect.width();
55 int h = dstIRect.height();
56 if (!fSrcRect.width() || !fSrcRect.height() || !w || !h) {
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000057 return false;
58 }
59
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +000060 SkRect srcRect;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000061 ctx.ctm().mapRect(&srcRect, fSrcRect);
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +000062 SkIRect srcIRect;
63 srcRect.roundOut(&srcIRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000064 srcIRect.offset(-srcOffset);
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000065 SkBitmap subset;
senorblancoa9fbd162016-01-11 14:09:09 -080066 SkIRect srcBounds;
67 source.getBounds(&srcBounds);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000068
senorblancoa9fbd162016-01-11 14:09:09 -080069 if (!SkIRect::Intersects(srcIRect, srcBounds)) {
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000070 offset->fX = offset->fY = 0;
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +000071 return true;
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000072 }
senorblancoa9fbd162016-01-11 14:09:09 -080073 if (srcBounds.contains(srcIRect)) {
74 if (!source.extractSubset(&subset, srcIRect)) {
75 return false;
76 }
77 } else {
78 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(srcIRect.width(),
79 srcIRect.height(),
80 kPossible_TileUsage));
81 if (!device) {
82 return false;
83 }
84 SkCanvas canvas(device);
85 canvas.drawBitmap(src, SkIntToScalar(srcOffset.x()),
86 SkIntToScalar(srcOffset.y()));
87 subset = device->accessBitmap(false);
88 }
89 SkASSERT(subset.width() == srcIRect.width());
90 SkASSERT(subset.height() == srcIRect.height());
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000091
robertphillipsd312dca2015-07-06 07:59:09 -070092 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(w, h));
halcanary96fcdcc2015-08-27 07:41:13 -070093 if (nullptr == device.get()) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000094 return false;
95 }
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000096 SkCanvas canvas(device);
97 SkPaint paint;
98 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
99
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000100 SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(subset,
senorblancoa9fbd162016-01-11 14:09:09 -0800101 SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000102 paint.setShader(shader);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000103 canvas.translate(-dstRect.fLeft, -dstRect.fTop);
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000104 canvas.drawRect(dstRect, paint);
105 *dst = device->accessBitmap(false);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000106 offset->fX = dstIRect.fLeft;
107 offset->fY = dstIRect.fTop;
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000108 return true;
109}
110
senorblancodb64af32015-12-09 10:11:43 -0800111void SkTileImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
112 SkIRect* dst, MapDirection direction) const {
113 SkRect rect = kReverse_MapDirection == direction ? fSrcRect : fDstRect;
114 ctm.mapRect(&rect);
115 rect.roundOut(dst);
senorblancodb64af32015-12-09 10:11:43 -0800116}
117
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000118bool SkTileImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
senorblancod8ff5b32016-01-28 08:23:02 -0800119 SkIRect* dst, MapDirection direction) const {
120 // Don't recurse into inputs.
121 *dst = src;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000122 return true;
123}
124
robertphillipsc3176aa2015-06-16 09:44:56 -0700125void SkTileImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
senorblancodb64af32015-12-09 10:11:43 -0800126 *dst = fDstRect;
robertphillipsc3176aa2015-06-16 09:44:56 -0700127}
128
reed9fa60da2014-08-21 07:59:51 -0700129SkFlattenable* SkTileImageFilter::CreateProc(SkReadBuffer& buffer) {
130 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
131 SkRect src, dst;
132 buffer.readRect(&src);
133 buffer.readRect(&dst);
senorblanco24e06d52015-03-18 12:11:33 -0700134 return Create(src, dst, common.getInput(0));
reed9fa60da2014-08-21 07:59:51 -0700135}
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000136
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000137void SkTileImageFilter::flatten(SkWriteBuffer& buffer) const {
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000138 this->INHERITED::flatten(buffer);
139 buffer.writeRect(fSrcRect);
140 buffer.writeRect(fDstRect);
141}
robertphillipsf3f5bad2014-12-19 13:49:15 -0800142
143#ifndef SK_IGNORE_TO_STRING
144void SkTileImageFilter::toString(SkString* str) const {
145 str->appendf("SkTileImageFilter: (");
robertphillips63195182015-06-08 06:21:14 -0700146 str->appendf("src: %.2f %.2f %.2f %.2f",
147 fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom);
148 str->appendf(" dst: %.2f %.2f %.2f %.2f",
149 fDstRect.fLeft, fDstRect.fTop, fDstRect.fRight, fDstRect.fBottom);
150 if (this->getInput(0)) {
robertphillipsd312dca2015-07-06 07:59:09 -0700151 str->appendf("input: (");
robertphillips63195182015-06-08 06:21:14 -0700152 this->getInput(0)->toString(str);
153 str->appendf(")");
154 }
robertphillipsf3f5bad2014-12-19 13:49:15 -0800155 str->append(")");
156}
157#endif