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" 118b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h" 128b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h" 13c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org#include "SkValidationUtils.h" 1482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 1582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com//////////////////////////////////////////////////////////////////////////////// 1603245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com#if SK_SUPPORT_GPU 17eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "GrInvariantOutput.h" 1882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include "effects/GrSingleTextureEffect.h" 19b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "gl/GrGLProcessor.h" 2082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include "gl/GrGLSL.h" 2182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com#include "gl/GrGLTexture.h" 22eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "gl/builders/GrGLProgramBuilder.h" 2382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 2482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comclass GrMagnifierEffect : public GrSingleTextureEffect { 2582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 2682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.compublic: 27b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt static GrFragmentProcessor* Create(GrTexture* texture, 28d0d37cace08f12abf8d316e6949e947551d418e6senorblanco const SkRect& bounds, 29b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt float xOffset, 30b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt float yOffset, 31b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt float xInvZoom, 32b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt float yInvZoom, 33b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt float xInvInset, 34b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt float yInvInset) { 3555fad7af61c21d502acb9891d631e8aa29e3628cbsalomon return SkNEW_ARGS(GrMagnifierEffect, (texture, 36d0d37cace08f12abf8d316e6949e947551d418e6senorblanco bounds, 3755fad7af61c21d502acb9891d631e8aa29e3628cbsalomon xOffset, 3855fad7af61c21d502acb9891d631e8aa29e3628cbsalomon yOffset, 3955fad7af61c21d502acb9891d631e8aa29e3628cbsalomon xInvZoom, 4055fad7af61c21d502acb9891d631e8aa29e3628cbsalomon yInvZoom, 4155fad7af61c21d502acb9891d631e8aa29e3628cbsalomon xInvInset, 4255fad7af61c21d502acb9891d631e8aa29e3628cbsalomon yInvInset)); 430ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com } 4482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 4582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com virtual ~GrMagnifierEffect() {}; 4682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 4736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein const char* name() const override { return "Magnifier"; } 48eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt 49cfc18867d982119d9dc2888bf09f1093012daaddjvanverth void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; 50eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt 5136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein GrGLFragmentProcessor* createGLInstance() const override; 5282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 53d0d37cace08f12abf8d316e6949e947551d418e6senorblanco const SkRect& bounds() const { return fBounds; } // Bounds of source image. 54d0d37cace08f12abf8d316e6949e947551d418e6senorblanco // Offset to apply to zoomed pixels, (srcRect position / texture size). 5582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com float x_offset() const { return fXOffset; } 5682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com float y_offset() const { return fYOffset; } 57d0d37cace08f12abf8d316e6949e947551d418e6senorblanco 58d0d37cace08f12abf8d316e6949e947551d418e6senorblanco // Scale to apply to zoomed pixels (srcRect size / bounds size). 59f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org float x_inv_zoom() const { return fXInvZoom; } 60f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org float y_inv_zoom() const { return fYInvZoom; } 61d0d37cace08f12abf8d316e6949e947551d418e6senorblanco 62d0d37cace08f12abf8d316e6949e947551d418e6senorblanco // 1/radius over which to transition from unzoomed to zoomed pixels (bounds size / inset). 63f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org float x_inv_inset() const { return fXInvInset; } 64f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org float y_inv_inset() const { return fYInvInset; } 6582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 6682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comprivate: 670ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com GrMagnifierEffect(GrTexture* texture, 68d0d37cace08f12abf8d316e6949e947551d418e6senorblanco const SkRect& bounds, 690ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com float xOffset, 700ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com float yOffset, 71f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org float xInvZoom, 72f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org float yInvZoom, 73f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org float xInvInset, 74f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org float yInvInset) 756267f81f3d60ce144ab2b09ea369420984d5c9d9bsalomon : GrSingleTextureEffect(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture)) 76d0d37cace08f12abf8d316e6949e947551d418e6senorblanco , fBounds(bounds) 770ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com , fXOffset(xOffset) 780ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com , fYOffset(yOffset) 79f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org , fXInvZoom(xInvZoom) 80f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org , fYInvZoom(yInvZoom) 81f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org , fXInvInset(xInvInset) 82eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt , fYInvInset(yInvInset) { 83eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt this->initClassID<GrMagnifierEffect>(); 84eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt } 850ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com 8636352bf5e38f45a70ee4f4fc132a38048d38206dmtklein bool onIsEqual(const GrFragmentProcessor&) const override; 8768b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com 8836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein void onComputeInvariantOutput(GrInvariantOutput* inout) const override; 891a8ecdfb73a15de600d5779b75d7c4b61863c50begdaniel 90b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GR_DECLARE_FRAGMENT_PROCESSOR_TEST; 9182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 92d0d37cace08f12abf8d316e6949e947551d418e6senorblanco SkRect fBounds; 9382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com float fXOffset; 9482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com float fYOffset; 95f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org float fXInvZoom; 96f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org float fYInvZoom; 97f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org float fXInvInset; 98f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org float fYInvInset; 9982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 10082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com typedef GrSingleTextureEffect INHERITED; 10182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}; 10282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 10382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com// For brevity 1047510b224e52b9518a8ddf7418db0e9c258f79539kkinnunentypedef GrGLProgramDataManager::UniformHandle UniformHandle; 10582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 106b0a8a377f832c59cee939ad721e1f87d378b7142joshualittclass GrGLMagnifierEffect : public GrGLFragmentProcessor { 10782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.compublic: 108eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt GrGLMagnifierEffect(const GrProcessor&); 10982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 1101598899975ecc85b003a59740b588d1ddbcedb09joshualitt virtual void emitCode(GrGLFPBuilder*, 111b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt const GrFragmentProcessor&, 11247d7a8885b02478fa41069f14bba7ffbe5475d87bsalomon@google.com const char* outputColor, 11347d7a8885b02478fa41069f14bba7ffbe5475d87bsalomon@google.com const char* inputColor, 11477af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com const TransformedCoordsArray&, 11536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein const TextureSamplerArray&) override; 11682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 11736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein void setData(const GrGLProgramDataManager&, const GrProcessor&) override; 11882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 11982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.comprivate: 12017fc651dbe2e0624f6c85fb6e081d28a87d5a08bbsalomon@google.com UniformHandle fOffsetVar; 121f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org UniformHandle fInvZoomVar; 122f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org UniformHandle fInvInsetVar; 123d0d37cace08f12abf8d316e6949e947551d418e6senorblanco UniformHandle fBoundsVar; 12417fc651dbe2e0624f6c85fb6e081d28a87d5a08bbsalomon@google.com 125b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt typedef GrGLFragmentProcessor INHERITED; 12682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com}; 12782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 128eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualittGrGLMagnifierEffect::GrGLMagnifierEffect(const GrProcessor&) { 12982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com} 13082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 1311598899975ecc85b003a59740b588d1ddbcedb09joshualittvoid GrGLMagnifierEffect::emitCode(GrGLFPBuilder* builder, 132b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt const GrFragmentProcessor&, 13347d7a8885b02478fa41069f14bba7ffbe5475d87bsalomon@google.com const char* outputColor, 13447d7a8885b02478fa41069f14bba7ffbe5475d87bsalomon@google.com const char* inputColor, 13577af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com const TransformedCoordsArray& coords, 13647d7a8885b02478fa41069f14bba7ffbe5475d87bsalomon@google.com const TextureSamplerArray& samplers) { 13747d7a8885b02478fa41069f14bba7ffbe5475d87bsalomon@google.com fOffsetVar = builder->addUniform( 13830ba436f04e61d4505fb854d5fc56079636e0788joshualitt GrGLProgramBuilder::kFragment_Visibility | 13930ba436f04e61d4505fb854d5fc56079636e0788joshualitt GrGLProgramBuilder::kVertex_Visibility, 140422f56f6e51c2f6a6ab425573b4d790f0157f883bsalomon kVec2f_GrSLType, kDefault_GrSLPrecision, "Offset"); 141f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org fInvZoomVar = builder->addUniform( 14230ba436f04e61d4505fb854d5fc56079636e0788joshualitt GrGLProgramBuilder::kFragment_Visibility | 14330ba436f04e61d4505fb854d5fc56079636e0788joshualitt GrGLProgramBuilder::kVertex_Visibility, 144422f56f6e51c2f6a6ab425573b4d790f0157f883bsalomon kVec2f_GrSLType, kDefault_GrSLPrecision, "InvZoom"); 145f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org fInvInsetVar = builder->addUniform( 14630ba436f04e61d4505fb854d5fc56079636e0788joshualitt GrGLProgramBuilder::kFragment_Visibility | 14730ba436f04e61d4505fb854d5fc56079636e0788joshualitt GrGLProgramBuilder::kVertex_Visibility, 148422f56f6e51c2f6a6ab425573b4d790f0157f883bsalomon kVec2f_GrSLType, kDefault_GrSLPrecision, "InvInset"); 149d0d37cace08f12abf8d316e6949e947551d418e6senorblanco fBoundsVar = builder->addUniform( 150d0d37cace08f12abf8d316e6949e947551d418e6senorblanco GrGLProgramBuilder::kFragment_Visibility | 151d0d37cace08f12abf8d316e6949e947551d418e6senorblanco GrGLProgramBuilder::kVertex_Visibility, 152d0d37cace08f12abf8d316e6949e947551d418e6senorblanco kVec4f_GrSLType, kDefault_GrSLPrecision, "Bounds"); 15382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 15429bee0fe657fabf7c396502b69c9167fba13eaaaegdaniel GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); 15530ba436f04e61d4505fb854d5fc56079636e0788joshualitt SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0); 15630ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str()); 15730ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppendf("\t\tvec2 zoom_coord = %s + %s * %s;\n", 158f910d3b23bcf590ee937628dbab8e39a98ee5860bsalomon@google.com builder->getUniformCStr(fOffsetVar), 15977af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com coords2D.c_str(), 160f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org builder->getUniformCStr(fInvZoomVar)); 161d0d37cace08f12abf8d316e6949e947551d418e6senorblanco const char* bounds = builder->getUniformCStr(fBoundsVar); 162d0d37cace08f12abf8d316e6949e947551d418e6senorblanco fsBuilder->codeAppendf("\t\tvec2 delta = (coord - %s.xy) * %s.zw;\n", bounds, bounds); 163d0d37cace08f12abf8d316e6949e947551d418e6senorblanco fsBuilder->codeAppendf("\t\tdelta = min(delta, vec2(1.0, 1.0) - delta);\n"); 16430ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppendf("\t\tdelta = delta * %s;\n", builder->getUniformCStr(fInvInsetVar)); 165f910d3b23bcf590ee937628dbab8e39a98ee5860bsalomon@google.com 16630ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend("\t\tfloat weight = 0.0;\n"); 16730ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend("\t\tif (delta.s < 2.0 && delta.t < 2.0) {\n"); 16830ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend("\t\t\tdelta = vec2(2.0, 2.0) - delta;\n"); 16930ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend("\t\t\tfloat dist = length(delta);\n"); 17030ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend("\t\t\tdist = max(2.0 - dist, 0.0);\n"); 17130ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend("\t\t\tweight = min(dist * dist, 1.0);\n"); 17230ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend("\t\t} else {\n"); 17330ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend("\t\t\tvec2 delta_squared = delta * delta;\n"); 17430ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend("\t\t\tweight = min(min(delta_squared.x, delta_squared.y), 1.0);\n"); 17530ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend("\t\t}\n"); 176f910d3b23bcf590ee937628dbab8e39a98ee5860bsalomon@google.com 17730ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend("\t\tvec2 mix_coord = mix(coord, zoom_coord, weight);\n"); 17830ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend("\t\tvec4 output_color = "); 17930ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->appendTextureLookup(samplers[0], "mix_coord"); 18030ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend(";\n"); 181f910d3b23bcf590ee937628dbab8e39a98ee5860bsalomon@google.com 18230ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppendf("\t\t%s = output_color;", outputColor); 183f910d3b23bcf590ee937628dbab8e39a98ee5860bsalomon@google.com SkString modulate; 184089f8de82d6c342faa9170d8c19d8504177bf5fbegdaniel GrGLSLMulVarBy4f(&modulate, outputColor, inputColor); 18530ba436f04e61d4505fb854d5fc56079636e0788joshualitt fsBuilder->codeAppend(modulate.c_str()); 18682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com} 18782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 1887510b224e52b9518a8ddf7418db0e9c258f79539kkinnunenvoid GrGLMagnifierEffect::setData(const GrGLProgramDataManager& pdman, 189b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt const GrProcessor& effect) { 19049586bec7383d4ccb81f85f8e2dc4162e2d4f6a8joshualitt const GrMagnifierEffect& zoom = effect.cast<GrMagnifierEffect>(); 1917510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen pdman.set2f(fOffsetVar, zoom.x_offset(), zoom.y_offset()); 1927510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen pdman.set2f(fInvZoomVar, zoom.x_inv_zoom(), zoom.y_inv_zoom()); 1937510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen pdman.set2f(fInvInsetVar, zoom.x_inv_inset(), zoom.y_inv_inset()); 194d0d37cace08f12abf8d316e6949e947551d418e6senorblanco pdman.set4f(fBoundsVar, zoom.bounds().x(), zoom.bounds().y(), 195d0d37cace08f12abf8d316e6949e947551d418e6senorblanco zoom.bounds().width(), zoom.bounds().height()); 19682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com} 19782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 19882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com///////////////////////////////////////////////////////////////////// 19982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 200cfc18867d982119d9dc2888bf09f1093012daaddjvanverthvoid GrMagnifierEffect::getGLProcessorKey(const GrGLSLCaps& caps, 201eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt GrProcessorKeyBuilder* b) const { 202eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt GrGLMagnifierEffect::GenKey(*this, caps, b); 203eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt} 204eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt 205eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualittGrGLFragmentProcessor* GrMagnifierEffect::createGLInstance() const { 206eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt return SkNEW_ARGS(GrGLMagnifierEffect, (*this)); 207eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt} 208eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt 209b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMagnifierEffect); 21082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 211b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrFragmentProcessor* GrMagnifierEffect::TestCreate(SkRandom* random, 212b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GrContext* context, 213b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt const GrDrawTargetCaps&, 214b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GrTexture** textures) { 2151aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org GrTexture* texture = textures[0]; 21682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com const int kMaxWidth = 200; 21782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com const int kMaxHeight = 200; 21882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com const int kMaxInset = 20; 2195d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com uint32_t width = random->nextULessThan(kMaxWidth); 2205d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com uint32_t height = random->nextULessThan(kMaxHeight); 2215d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com uint32_t x = random->nextULessThan(kMaxWidth - width); 2225d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com uint32_t y = random->nextULessThan(kMaxHeight - height); 2231aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org uint32_t inset = random->nextULessThan(kMaxInset); 2241aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org 225b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GrFragmentProcessor* effect = GrMagnifierEffect::Create( 2261aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org texture, 227d0d37cace08f12abf8d316e6949e947551d418e6senorblanco SkRect::MakeWH(SkIntToScalar(kMaxWidth), SkIntToScalar(kMaxHeight)), 2281aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org (float) width / texture->width(), 2291aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org (float) height / texture->height(), 2301aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org texture->width() / (float) x, 2311aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org texture->height() / (float) y, 2321aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org (float) inset / texture->width(), 2331aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org (float) inset / texture->height()); 23449f085dddff10473b6ebf832a974288300224e60bsalomon SkASSERT(effect); 235021fc736f89fddac4f26b3f32f50263ff8fe3279bsalomon@google.com return effect; 23682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com} 23782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 23882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com/////////////////////////////////////////////////////////////////////////////// 23982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 2400e08fc17e4718f7ce4e38f793695896473e96948bsalomonbool GrMagnifierEffect::onIsEqual(const GrFragmentProcessor& sBase) const { 24149586bec7383d4ccb81f85f8e2dc4162e2d4f6a8joshualitt const GrMagnifierEffect& s = sBase.cast<GrMagnifierEffect>(); 242d0d37cace08f12abf8d316e6949e947551d418e6senorblanco return (this->fBounds == s.fBounds && 243d0d37cace08f12abf8d316e6949e947551d418e6senorblanco this->fXOffset == s.fXOffset && 24482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com this->fYOffset == s.fYOffset && 245f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org this->fXInvZoom == s.fXInvZoom && 246f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org this->fYInvZoom == s.fYInvZoom && 247f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org this->fXInvInset == s.fXInvInset && 248f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org this->fYInvInset == s.fYInvInset); 24982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com} 25082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 251605dd0fbce9dbb2a0d3313e13e161f2bd54870d7egdanielvoid GrMagnifierEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { 2521a8ecdfb73a15de600d5779b75d7c4b61863c50begdaniel this->updateInvariantOutputForModulation(inout); 25368b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com} 25468b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com 25503245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com#endif 25603245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com 25782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com//////////////////////////////////////////////////////////////////////////////// 2589fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed 2599fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkImageFilter* SkMagnifierImageFilter::Create(const SkRect& srcRect, SkScalar inset, 2609fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkImageFilter* input) { 2613f3b3d003527861dc0bd89733857576408906431mtklein 2629fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed if (!SkScalarIsFinite(inset) || !SkIsValidRect(srcRect)) { 2639fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed return NULL; 2649fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed } 2659fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed // Negative numbers in src rect are not supported 2669fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed if (srcRect.fLeft < 0 || srcRect.fTop < 0) { 2679fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed return NULL; 2689fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed } 2699fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed return SkNEW_ARGS(SkMagnifierImageFilter, (srcRect, inset, input)); 2709fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed} 2719fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed 2729fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed 2739ea3d57fde28a5fe4487a111dc3dd49418235e5esenorblancoSkMagnifierImageFilter::SkMagnifierImageFilter(const SkRect& srcRect, SkScalar inset, 2749ea3d57fde28a5fe4487a111dc3dd49418235e5esenorblanco SkImageFilter* input) 2759ea3d57fde28a5fe4487a111dc3dd49418235e5esenorblanco : INHERITED(1, &input), fSrcRect(srcRect), fInset(inset) { 27682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com SkASSERT(srcRect.x() >= 0 && srcRect.y() >= 0 && inset >= 0); 27782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com} 27882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 27903245700d6f1c5db903a2b9ea34e6cc0ce34a185bsalomon@google.com#if SK_SUPPORT_GPU 280b0a8a377f832c59cee939ad721e1f87d378b7142joshualittbool SkMagnifierImageFilter::asFragmentProcessor(GrFragmentProcessor** fp, GrTexture* texture, 281d0d37cace08f12abf8d316e6949e947551d418e6senorblanco const SkMatrix&, const SkIRect&bounds) const { 282b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt if (fp) { 283d0d37cace08f12abf8d316e6949e947551d418e6senorblanco SkScalar yOffset = texture->origin() == kTopLeft_GrSurfaceOrigin ? fSrcRect.y() : 284d0d37cace08f12abf8d316e6949e947551d418e6senorblanco texture->height() - fSrcRect.height() * texture->height() / bounds.height() 285d0d37cace08f12abf8d316e6949e947551d418e6senorblanco - fSrcRect.y(); 286d0d37cace08f12abf8d316e6949e947551d418e6senorblanco int boundsY = (texture->origin() == kTopLeft_GrSurfaceOrigin) ? bounds.y() : 287d0d37cace08f12abf8d316e6949e947551d418e6senorblanco (texture->height() - bounds.height()); 288d0d37cace08f12abf8d316e6949e947551d418e6senorblanco SkRect effectBounds = SkRect::MakeXYWH( 289d0d37cace08f12abf8d316e6949e947551d418e6senorblanco SkIntToScalar(bounds.x()) / texture->width(), 290d0d37cace08f12abf8d316e6949e947551d418e6senorblanco SkIntToScalar(boundsY) / texture->height(), 291d0d37cace08f12abf8d316e6949e947551d418e6senorblanco SkIntToScalar(texture->width()) / bounds.width(), 292d0d37cace08f12abf8d316e6949e947551d418e6senorblanco SkIntToScalar(texture->height()) / bounds.height()); 293f642f8cf90c8fd4111094026a1a9e9fdc92be9c3commit-bot@chromium.org SkScalar invInset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1; 294b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt *fp = GrMagnifierEffect::Create(texture, 295d0d37cace08f12abf8d316e6949e947551d418e6senorblanco effectBounds, 296b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt fSrcRect.x() / texture->width(), 297b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt yOffset / texture->height(), 298d0d37cace08f12abf8d316e6949e947551d418e6senorblanco fSrcRect.width() / bounds.width(), 299d0d37cace08f12abf8d316e6949e947551d418e6senorblanco fSrcRect.height() / bounds.height(), 300d0d37cace08f12abf8d316e6949e947551d418e6senorblanco bounds.width() * invInset, 301d0d37cace08f12abf8d316e6949e947551d418e6senorblanco bounds.height() * invInset); 30282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com } 30382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com return true; 30482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com} 305d043ccee3788ea4192806bd8c94484ed003fa828senorblanco@chromium.org#endif 30682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 3079fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkMagnifierImageFilter::CreateProc(SkReadBuffer& buffer) { 3089fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); 3099fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkRect src; 3109fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed buffer.readRect(&src); 3119fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed return Create(src, buffer.readScalar(), common.getInput(0)); 3129fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed} 3139fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed 3148b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkMagnifierImageFilter::flatten(SkWriteBuffer& buffer) const { 31582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com this->INHERITED::flatten(buffer); 3169fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed buffer.writeRect(fSrcRect); 31782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com buffer.writeScalar(fInset); 31882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com} 31982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 32082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.combool SkMagnifierImageFilter::onFilterImage(Proxy*, const SkBitmap& src, 3214cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org const Context&, SkBitmap* dst, 322ae761f7545d8ebf181d220169afac2056b057b8ccommit-bot@chromium.org SkIPoint* offset) const { 32328fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org if ((src.colorType() != kN32_SkColorType) || 324cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org (fSrcRect.width() >= src.width()) || 325cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org (fSrcRect.height() >= src.height())) { 32682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com return false; 32782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com } 32882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 32982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com SkAutoLockPixels alp(src); 33082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com SkASSERT(src.getPixels()); 33182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com if (!src.getPixels() || src.width() <= 0 || src.height() <= 0) { 33282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com return false; 33382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com } 33482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 335848250415eddc54075f7eb8795e8db79e749c6abreed if (!dst->tryAllocPixels(src.info())) { 336cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org return false; 337cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org } 338cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org 3395d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com SkScalar inv_inset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1; 34082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 3415d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com SkScalar inv_x_zoom = fSrcRect.width() / src.width(); 3425d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com SkScalar inv_y_zoom = fSrcRect.height() / src.height(); 34382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 34482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com SkColor* sptr = src.getAddr32(0, 0); 34582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com SkColor* dptr = dst->getAddr32(0, 0); 34682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com int width = src.width(), height = src.height(); 34782aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com for (int y = 0; y < height; ++y) { 34882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com for (int x = 0; x < width; ++x) { 3495d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com SkScalar x_dist = SkMin32(x, width - x - 1) * inv_inset; 3505d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com SkScalar y_dist = SkMin32(y, height - y - 1) * inv_inset; 3515d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com SkScalar weight = 0; 3525d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com 3535d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com static const SkScalar kScalar2 = SkScalar(2); 35482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 35582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com // To create a smooth curve at the corners, we need to work on 35682aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com // a square twice the size of the inset. 3575d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com if (x_dist < kScalar2 && y_dist < kScalar2) { 3585d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com x_dist = kScalar2 - x_dist; 3595d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com y_dist = kScalar2 - y_dist; 3605d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com 3615d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com SkScalar dist = SkScalarSqrt(SkScalarSquare(x_dist) + 3625d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com SkScalarSquare(y_dist)); 3635d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com dist = SkMaxScalar(kScalar2 - dist, 0); 3645d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com weight = SkMinScalar(SkScalarSquare(dist), SK_Scalar1); 36582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com } else { 3665d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com SkScalar sqDist = SkMinScalar(SkScalarSquare(x_dist), 3675d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com SkScalarSquare(y_dist)); 3685d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com weight = SkMinScalar(sqDist, SK_Scalar1); 36982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com } 37082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 3715d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com SkScalar x_interp = SkScalarMul(weight, (fSrcRect.x() + x * inv_x_zoom)) + 3725d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com (SK_Scalar1 - weight) * x; 3735d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com SkScalar y_interp = SkScalarMul(weight, (fSrcRect.y() + y * inv_y_zoom)) + 3745d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com (SK_Scalar1 - weight) * y; 37582aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 376cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org int x_val = SkPin32(SkScalarFloorToInt(x_interp), 0, width - 1); 377cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org int y_val = SkPin32(SkScalarFloorToInt(y_interp), 0, height - 1); 37882aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 37982aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com *dptr = sptr[y_val * width + x_val]; 38082aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com dptr++; 38182aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com } 38282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com } 38382aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com return true; 38482aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com} 385f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips 386f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#ifndef SK_IGNORE_TO_STRING 387f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillipsvoid SkMagnifierImageFilter::toString(SkString* str) const { 388f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips str->appendf("SkMagnifierImageFilter: ("); 389f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips str->appendf("src: (%f,%f,%f,%f) ", 390f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom); 391f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips str->appendf("inset: %f", fInset); 392f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips str->append(")"); 393f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips} 394f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#endif 395