blob: 262ad65672227d80c678f43222fc248ef886e14b [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"
robertphillipsc14b9782016-04-11 13:26:14 -07009
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000010#include "SkCanvas.h"
robertphillipsc14b9782016-04-11 13:26:14 -070011#include "SkImage.h"
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000012#include "SkMatrix.h"
robertphillipsc14b9782016-04-11 13:26:14 -070013#include "SkOffsetImageFilter.h"
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000014#include "SkPaint.h"
robertphillipsc14b9782016-04-11 13:26:14 -070015#include "SkReadBuffer.h"
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000016#include "SkShader.h"
robertphillipsc14b9782016-04-11 13:26:14 -070017#include "SkSpecialImage.h"
18#include "SkSpecialSurface.h"
19#include "SkSurface.h"
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +000020#include "SkValidationUtils.h"
robertphillipsc14b9782016-04-11 13:26:14 -070021#include "SkWriteBuffer.h"
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000022
robertphillips534c2702016-04-15 07:57:40 -070023sk_sp<SkImageFilter> SkTileImageFilter::Make(const SkRect& srcRect, const SkRect& dstRect,
24 sk_sp<SkImageFilter> input) {
reed9fa60da2014-08-21 07:59:51 -070025 if (!SkIsValidRect(srcRect) || !SkIsValidRect(dstRect)) {
halcanary96fcdcc2015-08-27 07:41:13 -070026 return nullptr;
reed9fa60da2014-08-21 07:59:51 -070027 }
senorblanco05dcb4c2016-01-12 07:49:15 -080028 if (srcRect.width() == dstRect.width() && srcRect.height() == dstRect.height()) {
29 SkRect ir = dstRect;
30 if (!ir.intersect(srcRect)) {
robertphillips534c2702016-04-15 07:57:40 -070031 return input;
senorblanco05dcb4c2016-01-12 07:49:15 -080032 }
33 CropRect cropRect(ir);
robertphillips51a315e2016-03-31 09:05:49 -070034 return SkOffsetImageFilter::Make(dstRect.x() - srcRect.x(),
35 dstRect.y() - srcRect.y(),
robertphillips534c2702016-04-15 07:57:40 -070036 std::move(input),
37 &cropRect);
senorblanco05dcb4c2016-01-12 07:49:15 -080038 }
robertphillips534c2702016-04-15 07:57:40 -070039 return sk_sp<SkImageFilter>(new SkTileImageFilter(srcRect, dstRect, std::move(input)));
reed9fa60da2014-08-21 07:59:51 -070040}
41
robertphillipsc14b9782016-04-11 13:26:14 -070042sk_sp<SkSpecialImage> SkTileImageFilter::onFilterImage(SkSpecialImage* source,
43 const Context& ctx,
44 SkIPoint* offset) const {
45 SkIPoint inputOffset = SkIPoint::Make(0, 0);
46 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
47 if (!input) {
48 return nullptr;
robertphillipsd312dca2015-07-06 07:59:09 -070049 }
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000050
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +000051 SkRect dstRect;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000052 ctx.ctm().mapRect(&dstRect, fDstRect);
senorblancob50b97d2016-01-06 09:46:24 -080053 if (!dstRect.intersect(SkRect::Make(ctx.clipBounds()))) {
robertphillipsc14b9782016-04-11 13:26:14 -070054 return nullptr;
senorblancob50b97d2016-01-06 09:46:24 -080055 }
robertphillipsc14b9782016-04-11 13:26:14 -070056
reedb07a94f2014-11-19 05:03:18 -080057 const SkIRect dstIRect = dstRect.roundOut();
brianosmaneed6b0e2016-09-23 13:04:05 -070058 if (!fSrcRect.width() || !fSrcRect.height() || !dstIRect.width() || !dstIRect.height()) {
robertphillipsc14b9782016-04-11 13:26:14 -070059 return nullptr;
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000060 }
61
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +000062 SkRect srcRect;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000063 ctx.ctm().mapRect(&srcRect, fSrcRect);
senorblanco@chromium.orge93e1db2013-12-09 18:31:42 +000064 SkIRect srcIRect;
65 srcRect.roundOut(&srcIRect);
robertphillipsc14b9782016-04-11 13:26:14 -070066 srcIRect.offset(-inputOffset);
67 const SkIRect inputBounds = SkIRect::MakeWH(input->width(), input->height());
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000068
robertphillipsc14b9782016-04-11 13:26:14 -070069 if (!SkIRect::Intersects(srcIRect, inputBounds)) {
70 return nullptr;
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000071 }
robertphillipsc14b9782016-04-11 13:26:14 -070072
73 // We create an SkImage here b.c. it needs to be a tight fit for the tiling
74 sk_sp<SkImage> subset;
75 if (inputBounds.contains(srcIRect)) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -050076 subset = input->asImage(&srcIRect);
robertphillipsc14b9782016-04-11 13:26:14 -070077 if (!subset) {
78 return nullptr;
senorblancoa9fbd162016-01-11 14:09:09 -080079 }
80 } else {
brianosmaneed6b0e2016-09-23 13:04:05 -070081 sk_sp<SkSurface> surf(input->makeTightSurface(ctx.outputProperties(), srcIRect.size()));
robertphillipsc14b9782016-04-11 13:26:14 -070082 if (!surf) {
83 return nullptr;
senorblancoa9fbd162016-01-11 14:09:09 -080084 }
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +000085
robertphillipsc14b9782016-04-11 13:26:14 -070086 SkCanvas* canvas = surf->getCanvas();
87 SkASSERT(canvas);
88
89 SkPaint paint;
reed374772b2016-10-05 17:33:02 -070090 paint.setBlendMode(SkBlendMode::kSrc);
robertphillipsc14b9782016-04-11 13:26:14 -070091
92 input->draw(canvas,
93 SkIntToScalar(inputOffset.x()), SkIntToScalar(inputOffset.y()),
94 &paint);
95
96 subset = surf->makeImageSnapshot();
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000097 }
robertphillipsc14b9782016-04-11 13:26:14 -070098 SkASSERT(subset->width() == srcIRect.width());
99 SkASSERT(subset->height() == srcIRect.height());
100
brianosmaneed6b0e2016-09-23 13:04:05 -0700101 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), dstIRect.size()));
robertphillipsc14b9782016-04-11 13:26:14 -0700102 if (!surf) {
103 return nullptr;
104 }
105
106 SkCanvas* canvas = surf->getCanvas();
107 SkASSERT(canvas);
108
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000109 SkPaint paint;
reed374772b2016-10-05 17:33:02 -0700110 paint.setBlendMode(SkBlendMode::kSrc);
robertphillipsc14b9782016-04-11 13:26:14 -0700111 paint.setShader(subset->makeShader(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
112 canvas->translate(-dstRect.fLeft, -dstRect.fTop);
113 canvas->drawRect(dstRect, paint);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000114 offset->fX = dstIRect.fLeft;
115 offset->fY = dstIRect.fTop;
robertphillipsc14b9782016-04-11 13:26:14 -0700116 return surf->makeImageSnapshot();
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000117}
118
Matt Sarett6d72ed92017-04-10 16:35:33 -0400119sk_sp<SkImageFilter> SkTileImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
120 SkASSERT(1 == this->countInputs());
121 if (!this->getInput(0)) {
122 return sk_ref_sp(const_cast<SkTileImageFilter*>(this));
123 }
124
125 sk_sp<SkImageFilter> input = this->getInput(0)->makeColorSpace(xformer);
126 return SkTileImageFilter::Make(fSrcRect, fDstRect, std::move(input));
127}
128
senorblancoe5e79842016-03-21 14:51:59 -0700129SkIRect SkTileImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
130 MapDirection direction) const {
senorblancodb64af32015-12-09 10:11:43 -0800131 SkRect rect = kReverse_MapDirection == direction ? fSrcRect : fDstRect;
132 ctm.mapRect(&rect);
senorblancoe5e79842016-03-21 14:51:59 -0700133 return rect.roundOut();
senorblancodb64af32015-12-09 10:11:43 -0800134}
135
senorblancoe5e79842016-03-21 14:51:59 -0700136SkIRect SkTileImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix&, MapDirection) const {
senorblancod8ff5b32016-01-28 08:23:02 -0800137 // Don't recurse into inputs.
senorblancoe5e79842016-03-21 14:51:59 -0700138 return src;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000139}
140
senorblancoe5e79842016-03-21 14:51:59 -0700141SkRect SkTileImageFilter::computeFastBounds(const SkRect& src) const {
142 return fDstRect;
robertphillipsc3176aa2015-06-16 09:44:56 -0700143}
144
reed60c9b582016-04-03 09:11:13 -0700145sk_sp<SkFlattenable> SkTileImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -0700146 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
147 SkRect src, dst;
148 buffer.readRect(&src);
149 buffer.readRect(&dst);
robertphillips534c2702016-04-15 07:57:40 -0700150 return Make(src, dst, common.getInput(0));
reed9fa60da2014-08-21 07:59:51 -0700151}
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000152
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000153void SkTileImageFilter::flatten(SkWriteBuffer& buffer) const {
commit-bot@chromium.org1a4fb702013-09-26 16:09:28 +0000154 this->INHERITED::flatten(buffer);
155 buffer.writeRect(fSrcRect);
156 buffer.writeRect(fDstRect);
157}
robertphillipsf3f5bad2014-12-19 13:49:15 -0800158
159#ifndef SK_IGNORE_TO_STRING
160void SkTileImageFilter::toString(SkString* str) const {
161 str->appendf("SkTileImageFilter: (");
robertphillips63195182015-06-08 06:21:14 -0700162 str->appendf("src: %.2f %.2f %.2f %.2f",
163 fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom);
164 str->appendf(" dst: %.2f %.2f %.2f %.2f",
165 fDstRect.fLeft, fDstRect.fTop, fDstRect.fRight, fDstRect.fBottom);
166 if (this->getInput(0)) {
robertphillipsd312dca2015-07-06 07:59:09 -0700167 str->appendf("input: (");
robertphillips63195182015-06-08 06:21:14 -0700168 this->getInput(0)->toString(str);
169 str->appendf(")");
170 }
robertphillipsf3f5bad2014-12-19 13:49:15 -0800171 str->append(")");
172}
173#endif