1/*
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"
12#include "SkReadBuffer.h"
13#include "SkWriteBuffer.h"
14#include "SkMatrix.h"
15#include "SkPaint.h"
16#include "SkShader.h"
17#include "SkValidationUtils.h"
18
19bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
20                                      const Context& ctx,
21                                      SkBitmap* dst, SkIPoint* offset) const {
22    SkBitmap source = src;
23    SkImageFilter* input = getInput(0);
24    SkIPoint srcOffset = SkIPoint::Make(0, 0);
25    if (input && !input->filterImage(proxy, src, ctx, &source, &srcOffset)) {
26        return false;
27    }
28
29    SkRect dstRect;
30    ctx.ctm().mapRect(&dstRect, fDstRect);
31    SkIRect dstIRect;
32    dstRect.roundOut(&dstIRect);
33    int w = dstIRect.width();
34    int h = dstIRect.height();
35    if (!fSrcRect.width() || !fSrcRect.height() || !w || !h) {
36        return false;
37    }
38
39    SkRect srcRect;
40    ctx.ctm().mapRect(&srcRect, fSrcRect);
41    SkIRect srcIRect;
42    srcRect.roundOut(&srcIRect);
43    srcIRect.offset(-srcOffset);
44    SkBitmap subset;
45    SkIRect bounds;
46    source.getBounds(&bounds);
47
48    if (!srcIRect.intersect(bounds)) {
49        offset->fX = offset->fY = 0;
50        return true;
51    } else if (!source.extractSubset(&subset, srcIRect)) {
52        return false;
53    }
54
55    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(w, h));
56    if (NULL == device.get()) {
57        return false;
58    }
59    SkCanvas canvas(device);
60    SkPaint paint;
61    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
62
63    SkMatrix shaderMatrix;
64    shaderMatrix.setTranslate(SkIntToScalar(srcOffset.fX),
65                              SkIntToScalar(srcOffset.fY));
66    SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(subset,
67                                  SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode,
68                                  &shaderMatrix));
69    paint.setShader(shader);
70    canvas.translate(-dstRect.fLeft, -dstRect.fTop);
71    canvas.drawRect(dstRect, paint);
72    *dst = device->accessBitmap(false);
73    offset->fX = dstIRect.fLeft;
74    offset->fY = dstIRect.fTop;
75    return true;
76}
77
78bool SkTileImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
79                                       SkIRect* dst) const {
80    SkRect srcRect;
81    ctm.mapRect(&srcRect, fSrcRect);
82    SkIRect srcIRect;
83    srcRect.roundOut(&srcIRect);
84    srcIRect.join(src);
85    *dst = srcIRect;
86    return true;
87}
88
89SkTileImageFilter::SkTileImageFilter(SkReadBuffer& buffer)
90  : INHERITED(1, buffer) {
91    buffer.readRect(&fSrcRect);
92    buffer.readRect(&fDstRect);
93    buffer.validate(buffer.isValid() && SkIsValidRect(fSrcRect) && SkIsValidRect(fDstRect));
94}
95
96void SkTileImageFilter::flatten(SkWriteBuffer& buffer) const {
97    this->INHERITED::flatten(buffer);
98    buffer.writeRect(fSrcRect);
99    buffer.writeRect(fDstRect);
100}
101