182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com/*
282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com * Copyright 2012 The Android Open Source Project
382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com *
482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com * Use of this source code is governed by a BSD-style license that can be
582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com * found in the LICENSE file.
682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com */
782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include "SkMagnifierImageFilter.h"
9b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
10b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips#include "SkBitmap.h"
1182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include "SkColorPriv.h"
128b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
13b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips#include "SkSpecialImage.h"
148b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
15c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org#include "SkValidationUtils.h"
1682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
1782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com////////////////////////////////////////////////////////////////////////////////
1803245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com#if SK_SUPPORT_GPU
19b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips#include "GrContext.h"
208e1c4e672553ecae2745168514240705f3516773Robert Phillips#include "effects/GrProxyMove.h"
2182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include "effects/GrSingleTextureEffect.h"
22b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman#include "glsl/GrGLSLColorSpaceXformHelper.h"
2364c4728c70001ed074fecf5c4e083781987b12e9egdaniel#include "glsl/GrGLSLFragmentProcessor.h"
242d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel#include "glsl/GrGLSLFragmentShaderBuilder.h"
25018fb62d12d1febf121fe265da5b6117b86a6541egdaniel#include "glsl/GrGLSLProgramDataManager.h"
267ea439b2203855db97330b25945b87dd4b170b8begdaniel#include "glsl/GrGLSLUniformHandler.h"
2794efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon#include "../private/GrGLSL.h"
288e1c4e672553ecae2745168514240705f3516773Robert Phillips#endif
298e1c4e672553ecae2745168514240705f3516773Robert Phillips
308e1c4e672553ecae2745168514240705f3516773Robert Phillipssk_sp<SkImageFilter> SkMagnifierImageFilter::Make(const SkRect& srcRect, SkScalar inset,
318e1c4e672553ecae2745168514240705f3516773Robert Phillips                                                  sk_sp<SkImageFilter> input,
328e1c4e672553ecae2745168514240705f3516773Robert Phillips                                                  const CropRect* cropRect) {
338e1c4e672553ecae2745168514240705f3516773Robert Phillips    if (!SkScalarIsFinite(inset) || !SkIsValidRect(srcRect)) {
348e1c4e672553ecae2745168514240705f3516773Robert Phillips        return nullptr;
358e1c4e672553ecae2745168514240705f3516773Robert Phillips    }
368e1c4e672553ecae2745168514240705f3516773Robert Phillips    if (inset < 0) {
378e1c4e672553ecae2745168514240705f3516773Robert Phillips        return nullptr;
388e1c4e672553ecae2745168514240705f3516773Robert Phillips    }
398e1c4e672553ecae2745168514240705f3516773Robert Phillips    // Negative numbers in src rect are not supported
408e1c4e672553ecae2745168514240705f3516773Robert Phillips    if (srcRect.fLeft < 0 || srcRect.fTop < 0) {
418e1c4e672553ecae2745168514240705f3516773Robert Phillips        return nullptr;
428e1c4e672553ecae2745168514240705f3516773Robert Phillips    }
438e1c4e672553ecae2745168514240705f3516773Robert Phillips    return sk_sp<SkImageFilter>(new SkMagnifierImageFilter(srcRect, inset,
448e1c4e672553ecae2745168514240705f3516773Robert Phillips                                                           std::move(input),
458e1c4e672553ecae2745168514240705f3516773Robert Phillips                                                           cropRect));
468e1c4e672553ecae2745168514240705f3516773Robert Phillips}
4782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
488e1c4e672553ecae2745168514240705f3516773Robert Phillips#if SK_SUPPORT_GPU
4982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comclass GrMagnifierEffect : public GrSingleTextureEffect {
5082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.compublic:
51296b1ccf9b8e9c8b945645efcbaa9c71c7135f58Robert Phillips    static sk_sp<GrFragmentProcessor> Make(GrResourceProvider* resourceProvider,
528e1c4e672553ecae2745168514240705f3516773Robert Phillips                                           sk_sp<GrTextureProxy> proxy,
538e1c4e672553ecae2745168514240705f3516773Robert Phillips                                           sk_sp<GrColorSpaceXform> colorSpaceXform,
548e1c4e672553ecae2745168514240705f3516773Robert Phillips                                           const SkIRect& bounds,
558e1c4e672553ecae2745168514240705f3516773Robert Phillips                                           const SkRect& srcRect,
568e1c4e672553ecae2745168514240705f3516773Robert Phillips                                           float xInvZoom,
578e1c4e672553ecae2745168514240705f3516773Robert Phillips                                           float yInvZoom,
588e1c4e672553ecae2745168514240705f3516773Robert Phillips                                           float xInvInset,
598e1c4e672553ecae2745168514240705f3516773Robert Phillips                                           float yInvInset) {
60296b1ccf9b8e9c8b945645efcbaa9c71c7135f58Robert Phillips        return sk_sp<GrFragmentProcessor>(new GrMagnifierEffect(resourceProvider,
618e1c4e672553ecae2745168514240705f3516773Robert Phillips                                                                std::move(proxy),
628e1c4e672553ecae2745168514240705f3516773Robert Phillips                                                                std::move(colorSpaceXform),
638e1c4e672553ecae2745168514240705f3516773Robert Phillips                                                                bounds, srcRect,
6406ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman                                                                xInvZoom, yInvZoom,
6506ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman                                                                xInvInset, yInvInset));
660ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com    }
6782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
68fc6c37b981daeece7474ce61070c707c37eefa62Mike Klein    ~GrMagnifierEffect() override {}
6982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
7036352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* name() const override { return "Magnifier"; }
71eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
728e1c4e672553ecae2745168514240705f3516773Robert Phillips    const SkIRect& bounds() const { return fBounds; }    // Bounds of source image.
738e1c4e672553ecae2745168514240705f3516773Robert Phillips    const SkRect& srcRect() const { return fSrcRect; }
74d0d37cace08f12abf8d316e6949e947551d418e6senorblanco
75d0d37cace08f12abf8d316e6949e947551d418e6senorblanco    // Scale to apply to zoomed pixels (srcRect size / bounds size).
76b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    float xInvZoom() const { return fXInvZoom; }
77b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    float yInvZoom() const { return fYInvZoom; }
78d0d37cace08f12abf8d316e6949e947551d418e6senorblanco
79d0d37cace08f12abf8d316e6949e947551d418e6senorblanco    // 1/radius over which to transition from unzoomed to zoomed pixels (bounds size / inset).
80b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    float xInvInset() const { return fXInvInset; }
81b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    float yInvInset() const { return fYInvInset; }
8282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
8382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comprivate:
84296b1ccf9b8e9c8b945645efcbaa9c71c7135f58Robert Phillips    GrMagnifierEffect(GrResourceProvider* resourceProvider,
858e1c4e672553ecae2745168514240705f3516773Robert Phillips                      sk_sp<GrTextureProxy> proxy,
868e1c4e672553ecae2745168514240705f3516773Robert Phillips                      sk_sp<GrColorSpaceXform> colorSpaceXform,
878e1c4e672553ecae2745168514240705f3516773Robert Phillips                      const SkIRect& bounds,
888e1c4e672553ecae2745168514240705f3516773Robert Phillips                      const SkRect& srcRect,
898e1c4e672553ecae2745168514240705f3516773Robert Phillips                      float xInvZoom,
908e1c4e672553ecae2745168514240705f3516773Robert Phillips                      float yInvZoom,
918e1c4e672553ecae2745168514240705f3516773Robert Phillips                      float xInvInset,
928e1c4e672553ecae2745168514240705f3516773Robert Phillips                      float yInvInset)
93296b1ccf9b8e9c8b945645efcbaa9c71c7135f58Robert Phillips            : INHERITED{resourceProvider,
948e1c4e672553ecae2745168514240705f3516773Robert Phillips                        ModulationFlags(proxy->config()),
958e1c4e672553ecae2745168514240705f3516773Robert Phillips                        GR_PROXY_MOVE(proxy),
968e1c4e672553ecae2745168514240705f3516773Robert Phillips                        std::move(colorSpaceXform),
978e1c4e672553ecae2745168514240705f3516773Robert Phillips                        SkMatrix::I()} // TODO: no GrSamplerParams::kBilerp_FilterMode?
988e1c4e672553ecae2745168514240705f3516773Robert Phillips            , fBounds(bounds)
998e1c4e672553ecae2745168514240705f3516773Robert Phillips            , fSrcRect(srcRect)
100587e08f361ee3e775a6bbc6dca761dbba82e422cBrian Salomon            , fXInvZoom(xInvZoom)
101587e08f361ee3e775a6bbc6dca761dbba82e422cBrian Salomon            , fYInvZoom(yInvZoom)
102587e08f361ee3e775a6bbc6dca761dbba82e422cBrian Salomon            , fXInvInset(xInvInset)
103587e08f361ee3e775a6bbc6dca761dbba82e422cBrian Salomon            , fYInvInset(yInvInset) {
104eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt        this->initClassID<GrMagnifierEffect>();
105eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    }
1060ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com
10757d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
108b1daa86732fe70aa4630c89d75ff0fd619d77c77wangyix
10994efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomon    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
1104b3050b410254d0cb38df9a30ae2e209124fa1a2wangyix
11136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onIsEqual(const GrFragmentProcessor&) const override;
11268b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com
113b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
11482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
1158e1c4e672553ecae2745168514240705f3516773Robert Phillips    SkIRect fBounds;
1168e1c4e672553ecae2745168514240705f3516773Robert Phillips    SkRect  fSrcRect;
117f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org    float fXInvZoom;
118f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org    float fYInvZoom;
119f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org    float fXInvInset;
120f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org    float fYInvInset;
12182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
12282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    typedef GrSingleTextureEffect INHERITED;
12382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com};
12482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
12582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com// For brevity
126018fb62d12d1febf121fe265da5b6117b86a6541egdanieltypedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
12782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
12864c4728c70001ed074fecf5c4e083781987b12e9egdanielclass GrGLMagnifierEffect : public GrGLSLFragmentProcessor {
12982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.compublic:
1309cdb9920fcad286ecf7875ea19902022b644fbdcrobertphillips    void emitCode(EmitArgs&) override;
13182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
132b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman    static inline void GenKey(const GrProcessor& effect, const GrShaderCaps&,
133b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman                              GrProcessorKeyBuilder* b) {
134b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman        const GrMagnifierEffect& zoom = effect.cast<GrMagnifierEffect>();
135b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman        b->add32(GrColorSpaceXform::XformKey(zoom.colorSpaceXform()));
136b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman    }
137b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman
138b1daa86732fe70aa4630c89d75ff0fd619d77c77wangyixprotected:
139018fb62d12d1febf121fe265da5b6117b86a6541egdaniel    void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
14082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
14182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comprivate:
14217fc651dbe2e0624f6c85fb6e081d28a87d5a08bbsalomon@google.com    UniformHandle       fOffsetVar;
143f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org    UniformHandle       fInvZoomVar;
144f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org    UniformHandle       fInvInsetVar;
145d0d37cace08f12abf8d316e6949e947551d418e6senorblanco    UniformHandle       fBoundsVar;
146c624d9d212c4168fc6c202a8535ddff8a3bfb16aBrian Osman    GrGLSLColorSpaceXformHelper fColorSpaceHelper;
14717fc651dbe2e0624f6c85fb6e081d28a87d5a08bbsalomon@google.com
14864c4728c70001ed074fecf5c4e083781987b12e9egdaniel    typedef GrGLSLFragmentProcessor INHERITED;
14982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com};
15082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
1517c157a988845fb00f9024d6db6dda142c3458033wangyixvoid GrGLMagnifierEffect::emitCode(EmitArgs& args) {
1527ea439b2203855db97330b25945b87dd4b170b8begdaniel    GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1535e58ceea8569f0d90ff7e3daf5de2def50407212cdalton    fOffsetVar = uniformHandler->addUniform(kFragment_GrShaderFlag,
1547ea439b2203855db97330b25945b87dd4b170b8begdaniel                                            kVec2f_GrSLType, kDefault_GrSLPrecision,
1557ea439b2203855db97330b25945b87dd4b170b8begdaniel                                            "Offset");
1565e58ceea8569f0d90ff7e3daf5de2def50407212cdalton    fInvZoomVar = uniformHandler->addUniform(kFragment_GrShaderFlag,
1577ea439b2203855db97330b25945b87dd4b170b8begdaniel                                             kVec2f_GrSLType, kDefault_GrSLPrecision,
1587ea439b2203855db97330b25945b87dd4b170b8begdaniel                                             "InvZoom");
1595e58ceea8569f0d90ff7e3daf5de2def50407212cdalton    fInvInsetVar = uniformHandler->addUniform(kFragment_GrShaderFlag,
1607ea439b2203855db97330b25945b87dd4b170b8begdaniel                                              kVec2f_GrSLType, kDefault_GrSLPrecision,
1617ea439b2203855db97330b25945b87dd4b170b8begdaniel                                              "InvInset");
1625e58ceea8569f0d90ff7e3daf5de2def50407212cdalton    fBoundsVar = uniformHandler->addUniform(kFragment_GrShaderFlag,
1637ea439b2203855db97330b25945b87dd4b170b8begdaniel                                            kVec4f_GrSLType, kDefault_GrSLPrecision,
1647ea439b2203855db97330b25945b87dd4b170b8begdaniel                                            "Bounds");
16582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
166b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman    const GrMagnifierEffect& zoom = args.fFp.cast<GrMagnifierEffect>();
167c624d9d212c4168fc6c202a8535ddff8a3bfb16aBrian Osman    fColorSpaceHelper.emitCode(uniformHandler, zoom.colorSpaceXform());
168b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman
1698528541dd7f09f5bd76f3f1ce5f45d08ac7347c7cdalton    GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
1701a1aa9303484106a955e5549bf8ae24950f54e7absalomon    SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
1714ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1724ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("\t\tvec2 zoom_coord = %s + %s * %s;\n",
1737ea439b2203855db97330b25945b87dd4b170b8begdaniel                             uniformHandler->getUniformCStr(fOffsetVar),
1744ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             coords2D.c_str(),
1757ea439b2203855db97330b25945b87dd4b170b8begdaniel                             uniformHandler->getUniformCStr(fInvZoomVar));
1767ea439b2203855db97330b25945b87dd4b170b8begdaniel    const char* bounds = uniformHandler->getUniformCStr(fBoundsVar);
1774ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("\t\tvec2 delta = (coord - %s.xy) * %s.zw;\n", bounds, bounds);
1784ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("\t\tdelta = min(delta, vec2(1.0, 1.0) - delta);\n");
1794ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("\t\tdelta = delta * %s;\n",
1807ea439b2203855db97330b25945b87dd4b170b8begdaniel                             uniformHandler->getUniformCStr(fInvInsetVar));
1814ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
1824ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend("\t\tfloat weight = 0.0;\n");
1834ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend("\t\tif (delta.s < 2.0 && delta.t < 2.0) {\n");
1844ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend("\t\t\tdelta = vec2(2.0, 2.0) - delta;\n");
1854ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend("\t\t\tfloat dist = length(delta);\n");
1864ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend("\t\t\tdist = max(2.0 - dist, 0.0);\n");
1874ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend("\t\t\tweight = min(dist * dist, 1.0);\n");
1884ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend("\t\t} else {\n");
1894ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend("\t\t\tvec2 delta_squared = delta * delta;\n");
1904ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend("\t\t\tweight = min(min(delta_squared.x, delta_squared.y), 1.0);\n");
1914ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend("\t\t}\n");
1924ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
1934ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend("\t\tvec2 mix_coord = mix(coord, zoom_coord, weight);\n");
1944ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend("\t\tvec4 output_color = ");
195b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman    fragBuilder->appendTextureLookup(args.fTexSamplers[0], "mix_coord", kVec2f_GrSLType,
196c624d9d212c4168fc6c202a8535ddff8a3bfb16aBrian Osman                                     &fColorSpaceHelper);
1974ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend(";\n");
1984ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
1994ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppendf("\t\t%s = output_color;", args.fOutputColor);
200f910d3b23bcf590ee937628dbab8e39a98ee5860bsalomon@google.com    SkString modulate;
2017c157a988845fb00f9024d6db6dda142c3458033wangyix    GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
2024ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel    fragBuilder->codeAppend(modulate.c_str());
20382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
20482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
205018fb62d12d1febf121fe265da5b6117b86a6541egdanielvoid GrGLMagnifierEffect::onSetData(const GrGLSLProgramDataManager& pdman,
206018fb62d12d1febf121fe265da5b6117b86a6541egdaniel                                    const GrProcessor& effect) {
20749586bec7383d4ccb81f85f8e2dc4162e2d4f6a8joshualitt    const GrMagnifierEffect& zoom = effect.cast<GrMagnifierEffect>();
2088e1c4e672553ecae2745168514240705f3516773Robert Phillips
2098e1c4e672553ecae2745168514240705f3516773Robert Phillips    GrTexture* tex = zoom.textureSampler(0).texture();
2108e1c4e672553ecae2745168514240705f3516773Robert Phillips    SkASSERT(tex);
2118e1c4e672553ecae2745168514240705f3516773Robert Phillips
2128e1c4e672553ecae2745168514240705f3516773Robert Phillips    SkScalar invW = 1.0f / tex->width();
2138e1c4e672553ecae2745168514240705f3516773Robert Phillips    SkScalar invH = 1.0f / tex->height();
2148e1c4e672553ecae2745168514240705f3516773Robert Phillips
2158e1c4e672553ecae2745168514240705f3516773Robert Phillips    {
2168e1c4e672553ecae2745168514240705f3516773Robert Phillips        SkScalar y = zoom.srcRect().y() * invH;
2178e1c4e672553ecae2745168514240705f3516773Robert Phillips        if (tex->origin() != kTopLeft_GrSurfaceOrigin) {
2188e1c4e672553ecae2745168514240705f3516773Robert Phillips            y = 1.0f - (zoom.srcRect().height() / zoom.bounds().height()) - y;
2198e1c4e672553ecae2745168514240705f3516773Robert Phillips        }
2208e1c4e672553ecae2745168514240705f3516773Robert Phillips
2218e1c4e672553ecae2745168514240705f3516773Robert Phillips        pdman.set2f(fOffsetVar, zoom.srcRect().x() * invW, y);
2228e1c4e672553ecae2745168514240705f3516773Robert Phillips    }
2238e1c4e672553ecae2745168514240705f3516773Robert Phillips
224b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    pdman.set2f(fInvZoomVar, zoom.xInvZoom(), zoom.yInvZoom());
225b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    pdman.set2f(fInvInsetVar, zoom.xInvInset(), zoom.yInvInset());
2268e1c4e672553ecae2745168514240705f3516773Robert Phillips
2278e1c4e672553ecae2745168514240705f3516773Robert Phillips    {
2288e1c4e672553ecae2745168514240705f3516773Robert Phillips        SkScalar y = zoom.bounds().y() * invH;
2298e1c4e672553ecae2745168514240705f3516773Robert Phillips        if (tex->origin() != kTopLeft_GrSurfaceOrigin) {
2308e1c4e672553ecae2745168514240705f3516773Robert Phillips            y = 1.0f - zoom.bounds().height() * invH;
2318e1c4e672553ecae2745168514240705f3516773Robert Phillips        }
2328e1c4e672553ecae2745168514240705f3516773Robert Phillips
2338e1c4e672553ecae2745168514240705f3516773Robert Phillips        pdman.set4f(fBoundsVar,
2348e1c4e672553ecae2745168514240705f3516773Robert Phillips                    zoom.bounds().x() * invW,
2358e1c4e672553ecae2745168514240705f3516773Robert Phillips                    y,
2368e1c4e672553ecae2745168514240705f3516773Robert Phillips                    SkIntToScalar(tex->width()) / zoom.bounds().width(),
2378e1c4e672553ecae2745168514240705f3516773Robert Phillips                    SkIntToScalar(tex->height()) / zoom.bounds().height());
2388e1c4e672553ecae2745168514240705f3516773Robert Phillips    }
2398e1c4e672553ecae2745168514240705f3516773Robert Phillips
240b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman    if (SkToBool(zoom.colorSpaceXform())) {
241c624d9d212c4168fc6c202a8535ddff8a3bfb16aBrian Osman        fColorSpaceHelper.setData(pdman, zoom.colorSpaceXform());
242b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman    }
24382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
24482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
24582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com/////////////////////////////////////////////////////////////////////
24682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
24794efbf51f5a88d9e8aa961d3fbe38c5e335d6108Brian Salomonvoid GrMagnifierEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
24857d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel                                              GrProcessorKeyBuilder* b) const {
249eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt    GrGLMagnifierEffect::GenKey(*this, caps, b);
250eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt}
251eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
25257d3b039c635945e1dc2fcbac3462ed8bfedb068egdanielGrGLSLFragmentProcessor* GrMagnifierEffect::onCreateGLSLInstance() const {
2539cdb9920fcad286ecf7875ea19902022b644fbdcrobertphillips    return new GrGLMagnifierEffect;
254eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt}
255eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
256b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMagnifierEffect);
25782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
2586f6961ebad65c582318564b3688e78e5c99f3935Hal Canary#if GR_TEST_UTILS
25906ca8ec87cf6fab57cadd043a5ac18c4154a4129bungemansk_sp<GrFragmentProcessor> GrMagnifierEffect::TestCreate(GrProcessorTestData* d) {
2608e1c4e672553ecae2745168514240705f3516773Robert Phillips    sk_sp<GrTextureProxy> proxy = d->textureProxy(0);
26182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    const int kMaxWidth = 200;
26282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    const int kMaxHeight = 200;
2638e1c4e672553ecae2745168514240705f3516773Robert Phillips    const SkScalar kMaxInset = 20.0f;
2640067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    uint32_t width = d->fRandom->nextULessThan(kMaxWidth);
2650067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    uint32_t height = d->fRandom->nextULessThan(kMaxHeight);
2668e1c4e672553ecae2745168514240705f3516773Robert Phillips    SkScalar inset = d->fRandom->nextRangeScalar(1.0f, kMaxInset);
2678e1c4e672553ecae2745168514240705f3516773Robert Phillips    sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(d->fRandom);
2688e1c4e672553ecae2745168514240705f3516773Robert Phillips
2698e1c4e672553ecae2745168514240705f3516773Robert Phillips    SkIRect bounds = SkIRect::MakeWH(SkIntToScalar(kMaxWidth), SkIntToScalar(kMaxHeight));
2708e1c4e672553ecae2745168514240705f3516773Robert Phillips    SkRect srcRect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
2711aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org
27206ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman    sk_sp<GrFragmentProcessor> effect(GrMagnifierEffect::Make(
273296b1ccf9b8e9c8b945645efcbaa9c71c7135f58Robert Phillips        d->resourceProvider(),
2748e1c4e672553ecae2745168514240705f3516773Robert Phillips        std::move(proxy),
275b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman        std::move(colorSpaceXform),
2768e1c4e672553ecae2745168514240705f3516773Robert Phillips        bounds,
2778e1c4e672553ecae2745168514240705f3516773Robert Phillips        srcRect,
2788e1c4e672553ecae2745168514240705f3516773Robert Phillips        srcRect.width() / bounds.width(),
2798e1c4e672553ecae2745168514240705f3516773Robert Phillips        srcRect.height() / bounds.height(),
2808e1c4e672553ecae2745168514240705f3516773Robert Phillips        bounds.width() / inset,
2818e1c4e672553ecae2745168514240705f3516773Robert Phillips        bounds.height() / inset));
28249f085dddff10473b6ebf832a974288300224e60bsalomon    SkASSERT(effect);
283021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com    return effect;
28482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
2856f6961ebad65c582318564b3688e78e5c99f3935Hal Canary#endif
28682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
28782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com///////////////////////////////////////////////////////////////////////////////
28882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
2890e08fc17e4718f7ce4e38f793695896473e96948bsalomonbool GrMagnifierEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
29049586bec7383d4ccb81f85f8e2dc4162e2d4f6a8joshualitt    const GrMagnifierEffect& s = sBase.cast<GrMagnifierEffect>();
291d0d37cace08f12abf8d316e6949e947551d418e6senorblanco    return (this->fBounds == s.fBounds &&
2928e1c4e672553ecae2745168514240705f3516773Robert Phillips            this->fSrcRect == s.fSrcRect &&
293f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org            this->fXInvZoom == s.fXInvZoom &&
294f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org            this->fYInvZoom == s.fYInvZoom &&
295f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org            this->fXInvInset == s.fXInvInset &&
296f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org            this->fYInvInset == s.fYInvInset);
29782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
29882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
29903245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com#endif
30003245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com
30182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com////////////////////////////////////////////////////////////////////////////////
3029fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
303b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillipsSkMagnifierImageFilter::SkMagnifierImageFilter(const SkRect& srcRect,
304b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips                                               SkScalar inset,
305b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips                                               sk_sp<SkImageFilter> input,
306b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips                                               const CropRect* cropRect)
307b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    : INHERITED(&input, 1, cropRect)
30811171f3b66ba6aba561fcaafbc51eaa354b73353robertphillips    , fSrcRect(srcRect)
30911171f3b66ba6aba561fcaafbc51eaa354b73353robertphillips    , fInset(inset) {
3108e1c4e672553ecae2745168514240705f3516773Robert Phillips    SkASSERT(srcRect.left() >= 0 && srcRect.top() >= 0 && inset >= 0);
31182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
31282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
31360c9b58b3214b0154c931656e91e39b230e987d8reedsk_sp<SkFlattenable> SkMagnifierImageFilter::CreateProc(SkReadBuffer& buffer) {
3149fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
3159fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkRect src;
3169fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    buffer.readRect(&src);
317b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    return Make(src, buffer.readScalar(), common.getInput(0), &common.cropRect());
3189fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
3199fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
3208b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkMagnifierImageFilter::flatten(SkWriteBuffer& buffer) const {
32182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    this->INHERITED::flatten(buffer);
3229fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    buffer.writeRect(fSrcRect);
32382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    buffer.writeScalar(fInset);
32482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
32582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
326b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillipssk_sp<SkSpecialImage> SkMagnifierImageFilter::onFilterImage(SkSpecialImage* source,
327b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips                                                            const Context& ctx,
328b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips                                                            SkIPoint* offset) const {
329b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    SkIPoint inputOffset = SkIPoint::Make(0, 0);
330b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
331b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    if (!input) {
332b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        return nullptr;
333b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    }
334b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
335b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
336b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips                                                  input->width(), input->height());
337b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
338b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    SkIRect bounds;
339b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
340b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        return nullptr;
341b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    }
342b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
343b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    SkScalar invInset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1;
344b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
345b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    SkScalar invXZoom = fSrcRect.width() / bounds.width();
346b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    SkScalar invYZoom = fSrcRect.height() / bounds.height();
347b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
348b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
349b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips#if SK_SUPPORT_GPU
350b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    if (source->isTextureBacked()) {
351b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        GrContext* context = source->getContext();
352b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
3538e1c4e672553ecae2745168514240705f3516773Robert Phillips        sk_sp<GrTextureProxy> inputProxy(input->asTextureProxyRef(context));
3548e1c4e672553ecae2745168514240705f3516773Robert Phillips        SkASSERT(inputProxy);
355b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
356b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        offset->fX = bounds.left();
357b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        offset->fY = bounds.top();
358b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        bounds.offset(-inputOffset);
359b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
360b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman        SkColorSpace* dstColorSpace = ctx.outputProperties().colorSpace();
361b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman        sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(input->getColorSpace(),
362b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman                                                                           dstColorSpace);
36306ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman        sk_sp<GrFragmentProcessor> fp(GrMagnifierEffect::Make(
364296b1ccf9b8e9c8b945645efcbaa9c71c7135f58Robert Phillips                                                        context->resourceProvider(),
3658e1c4e672553ecae2745168514240705f3516773Robert Phillips                                                        std::move(inputProxy),
366b44bb31137787b9dcc530d9061e3a08cf261da23Brian Osman                                                        std::move(colorSpaceXform),
3678e1c4e672553ecae2745168514240705f3516773Robert Phillips                                                        bounds,
3688e1c4e672553ecae2745168514240705f3516773Robert Phillips                                                        fSrcRect,
369b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips                                                        invXZoom,
370b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips                                                        invYZoom,
371b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips                                                        bounds.width() * invInset,
372b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips                                                        bounds.height() * invInset));
373b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        if (!fp) {
374b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips            return nullptr;
375b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        }
376b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
3772a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman        return DrawWithFP(context, std::move(fp), bounds, ctx.outputProperties());
37882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    }
379b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips#endif
38082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
381b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    SkBitmap inputBM;
382b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
383b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    if (!input->getROPixels(&inputBM)) {
384b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        return nullptr;
38582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    }
38682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
387b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    if ((inputBM.colorType() != kN32_SkColorType) ||
388b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        (fSrcRect.width() >= inputBM.width()) || (fSrcRect.height() >= inputBM.height())) {
389b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        return nullptr;
390b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    }
391b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
392b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    SkAutoLockPixels alp(inputBM);
393b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    SkASSERT(inputBM.getPixels());
394b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    if (!inputBM.getPixels() || inputBM.width() <= 0 || inputBM.height() <= 0) {
395b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        return nullptr;
396cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org    }
397cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org
398b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height());
39982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
400b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    SkBitmap dst;
401b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    if (!dst.tryAllocPixels(info)) {
402b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        return nullptr;
403b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    }
40482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
405b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    SkAutoLockPixels dstLock(dst);
406b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
407b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    SkColor* dptr = dst.getAddr32(0, 0);
408b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    int dstWidth = dst.width(), dstHeight = dst.height();
409b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    for (int y = 0; y < dstHeight; ++y) {
410b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips        for (int x = 0; x < dstWidth; ++x) {
411b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips            SkScalar x_dist = SkMin32(x, dstWidth - x - 1) * invInset;
412b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips            SkScalar y_dist = SkMin32(y, dstHeight - y - 1) * invInset;
4135d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com            SkScalar weight = 0;
4145d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com
4155d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com            static const SkScalar kScalar2 = SkScalar(2);
41682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
41782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            // To create a smooth curve at the corners, we need to work on
41882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            // a square twice the size of the inset.
4195d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com            if (x_dist < kScalar2 && y_dist < kScalar2) {
4205d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                x_dist = kScalar2 - x_dist;
4215d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                y_dist = kScalar2 - y_dist;
4225d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com
4235d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                SkScalar dist = SkScalarSqrt(SkScalarSquare(x_dist) +
4245d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                                             SkScalarSquare(y_dist));
4255d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                dist = SkMaxScalar(kScalar2 - dist, 0);
4265d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                weight = SkMinScalar(SkScalarSquare(dist), SK_Scalar1);
42782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            } else {
4285d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                SkScalar sqDist = SkMinScalar(SkScalarSquare(x_dist),
4295d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                                              SkScalarSquare(y_dist));
4305d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                weight = SkMinScalar(sqDist, SK_Scalar1);
43182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            }
43282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
4338be952ad8c9deefe19cff36f9ad217563400f817Mike Reed            SkScalar x_interp = weight * (fSrcRect.x() + x * invXZoom) + (1 - weight) * x;
4348be952ad8c9deefe19cff36f9ad217563400f817Mike Reed            SkScalar y_interp = weight * (fSrcRect.y() + y * invYZoom) + (1 - weight) * y;
43582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
436b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips            int x_val = SkTPin(bounds.x() + SkScalarFloorToInt(x_interp), 0, inputBM.width() - 1);
437b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips            int y_val = SkTPin(bounds.y() + SkScalarFloorToInt(y_interp), 0, inputBM.height() - 1);
43882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
439b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips            *dptr = *inputBM.getAddr32(x_val, y_val);
44082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            dptr++;
44182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        }
44282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    }
443b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips
444b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    offset->fX = bounds.left();
445b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips    offset->fY = bounds.top();
4463e302275b324172c845627cbd00cee8a06571bafrobertphillips    return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()),
447b2a4dc6a350abe3b18ecac719e499600f739a6e2robertphillips                                          dst);
44882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
449f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips
450f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#ifndef SK_IGNORE_TO_STRING
451f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillipsvoid SkMagnifierImageFilter::toString(SkString* str) const {
452f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("SkMagnifierImageFilter: (");
453f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("src: (%f,%f,%f,%f) ",
454f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                 fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom);
455f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("inset: %f", fInset);
456f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->append(")");
457f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips}
458f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#endif
459