SkMagnifierImageFilter.cpp revision d698f77c13d97c61109b861eac4d25b14a5de935
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 "SkBitmap.h"
982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include "SkMagnifierImageFilter.h"
1082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include "SkColorPriv.h"
1182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include "SkFlattenableBuffers.h"
1282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
1382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include <algorithm>
1482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
1582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com////////////////////////////////////////////////////////////////////////////////
1603245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com#if SK_SUPPORT_GPU
1782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include "effects/GrSingleTextureEffect.h"
18d698f77c13d97c61109b861eac4d25b14a5de935bsalomon@google.com#include "gl/GrGLEffect.h"
1982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include "gl/GrGLSL.h"
2082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include "gl/GrGLTexture.h"
2182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include "GrProgramStageFactory.h"
2282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
2382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comclass GrGLMagnifierEffect;
2482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
2582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comclass GrMagnifierEffect : public GrSingleTextureEffect {
2682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
2782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.compublic:
2882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    GrMagnifierEffect(GrTexture* texture,
2982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                      float xOffset,
3082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                      float yOffset,
3182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                      float xZoom,
3282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                      float yZoom,
3382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                      float xInset,
3482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                      float yInset)
3582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        : GrSingleTextureEffect(texture)
3682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        , fXOffset(xOffset)
3782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        , fYOffset(yOffset)
3882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        , fXZoom(xZoom)
3982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        , fYZoom(yZoom)
4082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        , fXInset(xInset)
4182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        , fYInset(yInset) {}
4282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
4382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    virtual ~GrMagnifierEffect() {};
4482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
4582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    static const char* Name() { return "Magnifier"; }
4682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
4782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
48a469c28c3c16214733a25201a286970f57b3d944bsalomon@google.com    virtual bool isEqual(const GrEffect&) const SK_OVERRIDE;
4982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
5082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float x_offset() const { return fXOffset; }
5182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float y_offset() const { return fYOffset; }
5282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float x_zoom() const { return fXZoom; }
5382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float y_zoom() const { return fYZoom; }
5482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float x_inset() const { return fXInset; }
5582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float y_inset() const { return fYInset; }
5682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
5782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    typedef GrGLMagnifierEffect GLProgramStage;
5882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
5982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comprivate:
60f271cc7183fe48ac64d2d9a454eb013c91b42d53bsalomon@google.com    GR_DECLARE_EFFECT_TEST;
6182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
6282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float fXOffset;
6382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float fYOffset;
6482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float fXZoom;
6582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float fYZoom;
6682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float fXInset;
6782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float fYInset;
6882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
6982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    typedef GrSingleTextureEffect INHERITED;
7082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com};
7182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
7282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com// For brevity
7382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comtypedef GrGLUniformManager::UniformHandle UniformHandle;
7482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
75374e75956e7a56bbbd2da5509f9c4117512515d2bsalomon@google.comclass GrGLMagnifierEffect : public GrGLLegacyProgramStage {
7682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.compublic:
7782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    GrGLMagnifierEffect(const GrProgramStageFactory& factory,
78021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com                        const GrEffect& effect);
7982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
8082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    virtual void setupVariables(GrGLShaderBuilder* state) SK_OVERRIDE;
8182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    virtual void emitVS(GrGLShaderBuilder* state,
8282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                        const char* vertexCoords) SK_OVERRIDE;
8382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    virtual void emitFS(GrGLShaderBuilder* state,
8482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                        const char* outputColor,
8582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                        const char* inputColor,
86f06df1bb9ab201a78bfc906a9e95326c6e15a119bsalomon@google.com                        const TextureSamplerArray&) SK_OVERRIDE;
8782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
8882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    virtual void setData(const GrGLUniformManager& uman,
89a469c28c3c16214733a25201a286970f57b3d944bsalomon@google.com                         const GrEffect& data) SK_OVERRIDE;
9082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
91a469c28c3c16214733a25201a286970f57b3d944bsalomon@google.com    static inline StageKey GenKey(const GrEffect&, const GrGLCaps&);
9282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
9382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comprivate:
9482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
9582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    UniformHandle  fOffsetVar;
9682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    UniformHandle  fZoomVar;
9782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    UniformHandle  fInsetVar;
9882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
99374e75956e7a56bbbd2da5509f9c4117512515d2bsalomon@google.com    typedef GrGLLegacyProgramStage INHERITED;
10082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com};
10182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
10282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comGrGLMagnifierEffect::GrGLMagnifierEffect(const GrProgramStageFactory& factory,
103021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com                                         const GrEffect& effect)
104374e75956e7a56bbbd2da5509f9c4117512515d2bsalomon@google.com    : INHERITED(factory)
10582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    , fOffsetVar(GrGLUniformManager::kInvalidUniformHandle)
10682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    , fZoomVar(GrGLUniformManager::kInvalidUniformHandle)
10782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    , fInsetVar(GrGLUniformManager::kInvalidUniformHandle) {
10882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
10982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
11082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comvoid GrGLMagnifierEffect::setupVariables(GrGLShaderBuilder* state) {
11182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    fOffsetVar = state->addUniform(
11282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        GrGLShaderBuilder::kFragment_ShaderType |
11382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        GrGLShaderBuilder::kVertex_ShaderType,
11482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        kVec2f_GrSLType, "uOffset");
11582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    fZoomVar = state->addUniform(
11682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        GrGLShaderBuilder::kFragment_ShaderType |
11782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        GrGLShaderBuilder::kVertex_ShaderType,
11882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        kVec2f_GrSLType, "uZoom");
11982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    fInsetVar = state->addUniform(
12082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        GrGLShaderBuilder::kFragment_ShaderType |
12182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        GrGLShaderBuilder::kVertex_ShaderType,
12282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        kVec2f_GrSLType, "uInset");
12382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
12482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
12582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comvoid GrGLMagnifierEffect::emitVS(GrGLShaderBuilder* state,
12682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                                 const char* vertexCoords) {
12782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
12882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
12982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comvoid GrGLMagnifierEffect::emitFS(GrGLShaderBuilder* state,
13082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                                 const char* outputColor,
13182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                                 const char* inputColor,
132f06df1bb9ab201a78bfc906a9e95326c6e15a119bsalomon@google.com                                 const TextureSamplerArray& samplers) {
13382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    SkString* code = &state->fFSCode;
13482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
13534bcb9f80336fe0dc56ad5f67aeb0859bf84d92ebsalomon@google.com    code->appendf("\t\tvec2 coord = %s;\n", state->defaultTexCoordsName());
13682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\tvec2 zoom_coord = %s + %s / %s;\n",
13782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                  state->getUniformCStr(fOffsetVar),
13834bcb9f80336fe0dc56ad5f67aeb0859bf84d92ebsalomon@google.com                  state->defaultTexCoordsName(),
13982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                  state->getUniformCStr(fZoomVar));
14082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
14182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\tvec2 delta = min(coord, vec2(1.0, 1.0) - coord);\n");
14282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
14382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf(
14482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        "\t\tdelta = delta / %s;\n", state->getUniformCStr(fInsetVar));
14582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
14682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\tfloat weight = 0.0;\n");
14782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\tif (delta.s < 2.0 && delta.t < 2.0) {\n");
14882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\t\tdelta = vec2(2.0, 2.0) - delta;\n");
14982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\t\tfloat dist = length(delta);\n");
15082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\t\tdist = max(2.0 - dist, 0.0);\n");
15182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\t\tweight = min(dist * dist, 1.0);\n");
15282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\t} else {\n");
15382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\t\tvec2 delta_squared = delta * delta;\n");
15482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf(
15582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        "\t\t\tweight = min(min(delta_squared.s, delta_squared.y), 1.0);\n");
15682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\t}\n");
15782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
15882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\tvec2 mix_coord = mix(coord, zoom_coord, weight);\n");
15982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\tvec4 output_color = ");
160f06df1bb9ab201a78bfc906a9e95326c6e15a119bsalomon@google.com    state->appendTextureLookup(code, samplers[0], "mix_coord");
161868a8e7fc83e9ac6ee1418e75b84a0595605626cbsalomon@google.com    code->append(";\n");
16282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
16382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    code->appendf("\t\t%s = output_color;", outputColor);
164868a8e7fc83e9ac6ee1418e75b84a0595605626cbsalomon@google.com    GrGLSLMulVarBy4f(code, 2, outputColor, inputColor);
16582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
16682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
16782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comvoid GrGLMagnifierEffect::setData(const GrGLUniformManager& uman,
168a469c28c3c16214733a25201a286970f57b3d944bsalomon@google.com                                  const GrEffect& data) {
16982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    const GrMagnifierEffect& zoom =
17082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        static_cast<const GrMagnifierEffect&>(data);
17182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
17282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    uman.set2f(fOffsetVar, zoom.x_offset(), zoom.y_offset());
17382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    uman.set2f(fZoomVar, zoom.x_zoom(), zoom.y_zoom());
17482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    uman.set2f(fInsetVar, zoom.x_inset(), zoom.y_inset());
17582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
17682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
177d698f77c13d97c61109b861eac4d25b14a5de935bsalomon@google.comGrGLEffect::StageKey GrGLMagnifierEffect::GenKey(const GrEffect& s,
17882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                                                       const GrGLCaps& caps) {
17982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    return 0;
18082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
18182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
18282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com/////////////////////////////////////////////////////////////////////
18382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
184f271cc7183fe48ac64d2d9a454eb013c91b42d53bsalomon@google.comGR_DEFINE_EFFECT_TEST(GrMagnifierEffect);
18582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
186a469c28c3c16214733a25201a286970f57b3d944bsalomon@google.comGrEffect* GrMagnifierEffect::TestCreate(SkRandom* random,
187a469c28c3c16214733a25201a286970f57b3d944bsalomon@google.com                                        GrContext* context,
188a469c28c3c16214733a25201a286970f57b3d944bsalomon@google.com                                        GrTexture** textures) {
18982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    const int kMaxWidth = 200;
19082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    const int kMaxHeight = 200;
19182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    const int kMaxInset = 20;
1925d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com    uint32_t width = random->nextULessThan(kMaxWidth);
1935d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com    uint32_t height = random->nextULessThan(kMaxHeight);
1945d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com    uint32_t x = random->nextULessThan(kMaxWidth - width);
1955d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com    uint32_t y = random->nextULessThan(kMaxHeight - height);
1965d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com    SkScalar inset = SkIntToScalar(random->nextULessThan(kMaxInset));
19782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
19882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    SkAutoTUnref<SkImageFilter> filter(
19982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            new SkMagnifierImageFilter(
2005d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
2015d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                                 SkIntToScalar(width), SkIntToScalar(height)),
20282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                inset));
20382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    GrSamplerState sampler;
204021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com    GrEffect* effect;
205021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com    filter->asNewEffect(&effect, textures[0]);
206021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com    GrAssert(NULL != effect);
207021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com    return effect;
20882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
20982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
21082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com///////////////////////////////////////////////////////////////////////////////
21182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
21282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comconst GrProgramStageFactory& GrMagnifierEffect::getFactory() const {
21382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    return GrTProgramStageFactory<GrMagnifierEffect>::getInstance();
21482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
21582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
216a469c28c3c16214733a25201a286970f57b3d944bsalomon@google.combool GrMagnifierEffect::isEqual(const GrEffect& sBase) const {
21782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com     const GrMagnifierEffect& s =
21882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        static_cast<const GrMagnifierEffect&>(sBase);
21982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    return (this->fXOffset == s.fXOffset &&
22082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            this->fYOffset == s.fYOffset &&
22182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            this->fXZoom == s.fXZoom &&
22282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            this->fYZoom == s.fYZoom &&
22382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            this->fXInset == s.fXInset &&
22482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            this->fYInset == s.fYInset);
22582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
22682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
22703245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com#endif
22803245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com
22982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com////////////////////////////////////////////////////////////////////////////////
23082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comSkMagnifierImageFilter::SkMagnifierImageFilter(SkFlattenableReadBuffer& buffer)
23182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com  : INHERITED(buffer) {
23282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float x = buffer.readScalar();
23382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float y = buffer.readScalar();
23482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float width = buffer.readScalar();
23582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    float height = buffer.readScalar();
23682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    fSrcRect = SkRect::MakeXYWH(x, y, width, height);
23782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    fInset = buffer.readScalar();
23882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
23982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
2409f25de79009ce721aa13abe71c38179d5a6710e2senorblanco@chromium.org// FIXME:  implement single-input semantics
24182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comSkMagnifierImageFilter::SkMagnifierImageFilter(SkRect srcRect, SkScalar inset)
2429f25de79009ce721aa13abe71c38179d5a6710e2senorblanco@chromium.org    : INHERITED(0), fSrcRect(srcRect), fInset(inset) {
24382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    SkASSERT(srcRect.x() >= 0 && srcRect.y() >= 0 && inset >= 0);
24482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
24582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
246021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.combool SkMagnifierImageFilter::asNewEffect(GrEffect** effect,
2478ea78d83dc4e8243c16eedf8100a3987c54123fabsalomon@google.com                                         GrTexture* texture) const {
24803245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com#if SK_SUPPORT_GPU
249021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com    if (effect) {
250021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com      *effect = SkNEW_ARGS(GrMagnifierEffect, (texture,
251021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com                                               fSrcRect.x() / texture->width(),
252021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com                                               fSrcRect.y() / texture->height(),
253021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com                                               texture->width() / fSrcRect.width(),
254021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com                                               texture->height() / fSrcRect.height(),
255021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com                                               fInset / texture->width(),
256021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com                                               fInset / texture->height()));
25782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    }
25882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    return true;
25903245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com#else
26003245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com    return false;
26103245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com#endif
26282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
26382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
26482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comvoid SkMagnifierImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
26582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    this->INHERITED::flatten(buffer);
26682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    buffer.writeScalar(fSrcRect.x());
26782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    buffer.writeScalar(fSrcRect.y());
26882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    buffer.writeScalar(fSrcRect.width());
26982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    buffer.writeScalar(fSrcRect.height());
27082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    buffer.writeScalar(fInset);
27182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
27282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
27382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.combool SkMagnifierImageFilter::onFilterImage(Proxy*, const SkBitmap& src,
27482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                                           const SkMatrix&, SkBitmap* dst,
27582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com                                           SkIPoint* offset) {
27682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    SkASSERT(src.config() == SkBitmap::kARGB_8888_Config);
27782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    SkASSERT(fSrcRect.width() < src.width());
27882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    SkASSERT(fSrcRect.height() < src.height());
27982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
28082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    if (src.config() != SkBitmap::kARGB_8888_Config) {
28182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com      return false;
28282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    }
28382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
28482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    SkAutoLockPixels alp(src);
28582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    SkASSERT(src.getPixels());
28682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    if (!src.getPixels() || src.width() <= 0 || src.height() <= 0) {
28782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com      return false;
28882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    }
28982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
2905d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com    SkScalar inv_inset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1;
29182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
2925d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com    SkScalar inv_x_zoom = fSrcRect.width() / src.width();
2935d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com    SkScalar inv_y_zoom = fSrcRect.height() / src.height();
29482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
29582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    dst->setConfig(src.config(), src.width(), src.height());
29682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    dst->allocPixels();
29782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    SkColor* sptr = src.getAddr32(0, 0);
29882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    SkColor* dptr = dst->getAddr32(0, 0);
29982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    int width = src.width(), height = src.height();
30082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    for (int y = 0; y < height; ++y) {
30182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        for (int x = 0; x < width; ++x) {
3025d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com            SkScalar x_dist = SkMin32(x, width - x - 1) * inv_inset;
3035d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com            SkScalar y_dist = SkMin32(y, height - y - 1) * inv_inset;
3045d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com            SkScalar weight = 0;
3055d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com
3065d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com            static const SkScalar kScalar2 = SkScalar(2);
30782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
30882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            // To create a smooth curve at the corners, we need to work on
30982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            // a square twice the size of the inset.
3105d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com            if (x_dist < kScalar2 && y_dist < kScalar2) {
3115d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                x_dist = kScalar2 - x_dist;
3125d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                y_dist = kScalar2 - y_dist;
3135d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com
3145d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                SkScalar dist = SkScalarSqrt(SkScalarSquare(x_dist) +
3155d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                                             SkScalarSquare(y_dist));
3165d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                dist = SkMaxScalar(kScalar2 - dist, 0);
3175d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                weight = SkMinScalar(SkScalarSquare(dist), SK_Scalar1);
31882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            } else {
3195d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                SkScalar sqDist = SkMinScalar(SkScalarSquare(x_dist),
3205d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                                              SkScalarSquare(y_dist));
3215d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                weight = SkMinScalar(sqDist, SK_Scalar1);
32282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            }
32382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
3245d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com            SkScalar x_interp = SkScalarMul(weight, (fSrcRect.x() + x * inv_x_zoom)) +
3255d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                           (SK_Scalar1 - weight) * x;
3265d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com            SkScalar y_interp = SkScalarMul(weight, (fSrcRect.y() + y * inv_y_zoom)) +
3275d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com                           (SK_Scalar1 - weight) * y;
32882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
3295d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com            int x_val = SkMin32(SkScalarFloorToInt(x_interp), width - 1);
3305d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com            int y_val = SkMin32(SkScalarFloorToInt(y_interp), height - 1);
33182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com
33282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            *dptr = sptr[y_val * width + x_val];
33382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com            dptr++;
33482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com        }
33582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    }
33682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com    return true;
33782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}
338