diff options
-rw-r--r-- | core/java/android/view/GLES20Canvas.java | 15 | ||||
-rw-r--r-- | core/java/android/widget/TextView.java | 5 | ||||
-rw-r--r-- | core/jni/android/graphics/Paint.cpp | 18 | ||||
-rw-r--r-- | core/jni/android_view_GLES20Canvas.cpp | 9 | ||||
-rw-r--r-- | graphics/java/android/graphics/Paint.java | 59 | ||||
-rw-r--r-- | graphics/java/android/graphics/drawable/ShapeDrawable.java | 2 | ||||
-rw-r--r-- | libs/hwui/DeferredDisplayList.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/DisplayListOp.h | 51 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 10 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.h | 3 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 40 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 36 | ||||
-rw-r--r-- | libs/hwui/Renderer.h | 3 | ||||
-rw-r--r-- | libs/hwui/utils/Blur.cpp | 33 | ||||
-rw-r--r-- | libs/hwui/utils/Blur.h | 6 |
15 files changed, 118 insertions, 174 deletions
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index f234baa..6c451eb 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -43,7 +43,6 @@ import android.text.TextUtils; class GLES20Canvas extends HardwareCanvas { // Must match modifiers used in the JNI layer private static final int MODIFIER_NONE = 0; - private static final int MODIFIER_SHADOW = 1; private static final int MODIFIER_SHADER = 2; private final boolean mOpaque; @@ -1297,12 +1296,6 @@ class GLES20Canvas extends HardwareCanvas { private int setupModifiers(Paint paint) { int modifiers = MODIFIER_NONE; - if (paint.hasShadow) { - nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy, - paint.shadowColor); - modifiers |= MODIFIER_SHADOW; - } - final Shader shader = paint.getShader(); if (shader != null) { nSetupShader(mRenderer, shader.native_shader); @@ -1315,12 +1308,6 @@ class GLES20Canvas extends HardwareCanvas { private int setupModifiers(Paint paint, int flags) { int modifiers = MODIFIER_NONE; - if (paint.hasShadow && (flags & MODIFIER_SHADOW) != 0) { - nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy, - paint.shadowColor); - modifiers |= MODIFIER_SHADOW; - } - final Shader shader = paint.getShader(); if (shader != null && (flags & MODIFIER_SHADER) != 0) { nSetupShader(mRenderer, shader.native_shader); @@ -1331,8 +1318,6 @@ class GLES20Canvas extends HardwareCanvas { } private static native void nSetupShader(long renderer, long shader); - private static native void nSetupShadow(long renderer, float radius, - float dx, float dy, int color); private static native void nResetModifiers(long renderer, int modifiers); } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index b91111d..8f073de 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -289,6 +289,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance(); private float mShadowRadius, mShadowDx, mShadowDy; + private int mShadowColor; + private boolean mPreDrawRegistered; @@ -2755,6 +2757,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mShadowRadius = radius; mShadowDx = dx; mShadowDy = dy; + mShadowColor = color; // Will change text clip region if (mEditor != null) mEditor.invalidateTextDisplayList(); @@ -2804,7 +2807,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @attr ref android.R.styleable#TextView_shadowColor */ public int getShadowColor() { - return mTextPaint.shadowColor; + return mShadowColor; } /** diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 08a88d1..22c17dd 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -33,6 +33,7 @@ #include "SkXfermode.h" #include "unicode/uloc.h" #include "unicode/ushape.h" +#include "utils/Blur.h" #include "TextLayout.h" // temporary for debugging @@ -776,19 +777,23 @@ public: env->ReleaseStringChars(text, textArray); } - static void setShadowLayer(JNIEnv* env, jobject jpaint, jfloat radius, + static void setShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius, jfloat dx, jfloat dy, jint color) { - NPE_CHECK_RETURN_VOID(env, jpaint); - - SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint); + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); if (radius <= 0) { paint->setLooper(NULL); } else { - paint->setLooper(new SkBlurDrawLooper(radius, dx, dy, (SkColor)color))->unref(); + SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius); + paint->setLooper(new SkBlurDrawLooper((SkColor)color, sigma, dx, dy))->unref(); } } + static jboolean hasShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle) { + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL); + } + static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[], int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured, SkPaint::TextBufferDirection tbd) { @@ -968,7 +973,8 @@ static JNINativeMethod methods[] = { (void*) SkPaintGlue::getStringBounds }, {"nativeGetCharArrayBounds", "(J[CIIILandroid/graphics/Rect;)V", (void*) SkPaintGlue::getCharArrayBounds }, - {"nSetShadowLayer", "(FFFI)V", (void*)SkPaintGlue::setShadowLayer} + {"native_setShadowLayer", "(JFFFI)V", (void*)SkPaintGlue::setShadowLayer}, + {"native_hasShadowLayer", "(J)Z", (void*)SkPaintGlue::hasShadowLayer} }; static jfieldID req_fieldID(jfieldID id) { diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 7b2f829..fae6698 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -79,7 +79,6 @@ using namespace uirenderer; #define RENDERER_LOGD(...) #endif -#define MODIFIER_SHADOW 1 #define MODIFIER_SHADER 2 // ---------------------------------------------------------------------------- @@ -617,7 +616,6 @@ static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz, static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject clazz, jlong rendererPtr, jint modifiers) { OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - if (modifiers & MODIFIER_SHADOW) renderer->resetShadow(); if (modifiers & MODIFIER_SHADER) renderer->resetShader(); } @@ -629,12 +627,6 @@ static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject clazz, } -static void android_view_GLES20Canvas_setupShadow(JNIEnv* env, jobject clazz, - jlong rendererPtr, jfloat radius, jfloat dx, jfloat dy, jint color) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - renderer->setupShadow(radius, dx, dy, color); -} - // ---------------------------------------------------------------------------- // Draw filters // ---------------------------------------------------------------------------- @@ -1032,7 +1024,6 @@ static JNINativeMethod gMethods[] = { { "nResetModifiers", "(JI)V", (void*) android_view_GLES20Canvas_resetModifiers }, { "nSetupShader", "(JJ)V", (void*) android_view_GLES20Canvas_setupShader }, - { "nSetupShadow", "(JFFFI)V", (void*) android_view_GLES20Canvas_setupShadow }, { "nSetupPaintFilter", "(JII)V", (void*) android_view_GLES20Canvas_setupPaintFilter }, { "nResetPaintFilter", "(J)V", (void*) android_view_GLES20Canvas_resetPaintFilter }, diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 1e1128e..457b3ea 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -55,27 +55,6 @@ public class Paint { /** * @hide */ - public boolean hasShadow; - /** - * @hide - */ - public float shadowDx; - /** - * @hide - */ - public float shadowDy; - /** - * @hide - */ - public float shadowRadius; - /** - * @hide - */ - public int shadowColor; - - /** - * @hide - */ public int mBidiFlags = BIDI_DEFAULT_LTR; static final Style[] sStyleArray = { @@ -492,12 +471,6 @@ public class Paint { mCompatScaling = 1; mInvCompatScaling = 1; - hasShadow = false; - shadowDx = 0; - shadowDy = 0; - shadowRadius = 0; - shadowColor = 0; - mBidiFlags = BIDI_DEFAULT_LTR; setTextLocale(Locale.getDefault()); setElegantTextHeight(false); @@ -538,12 +511,6 @@ public class Paint { mCompatScaling = paint.mCompatScaling; mInvCompatScaling = paint.mInvCompatScaling; - hasShadow = paint.hasShadow; - shadowDx = paint.shadowDx; - shadowDy = paint.shadowDy; - shadowRadius = paint.shadowRadius; - shadowColor = paint.shadowColor; - mBidiFlags = paint.mBidiFlags; mLocale = paint.mLocale; } @@ -1135,22 +1102,24 @@ public class Paint { * layer is removed. */ public void setShadowLayer(float radius, float dx, float dy, int color) { - hasShadow = radius > 0.0f; - shadowRadius = radius; - shadowDx = dx; - shadowDy = dy; - shadowColor = color; - nSetShadowLayer(radius, dx, dy, color); + native_setShadowLayer(mNativePaint, radius, dx, dy, color); } - - private native void nSetShadowLayer(float radius, float dx, float dy, int color); /** * Clear the shadow layer. */ public void clearShadowLayer() { - hasShadow = false; - nSetShadowLayer(0, 0, 0, 0); + setShadowLayer(0, 0, 0, 0); + } + + /** + * Checks if the paint has a shadow layer attached + * + * @return true if the paint has a shadow layer attached and false otherwise + * @hide + */ + public boolean hasShadowLayer() { + return native_hasShadowLayer(mNativePaint); } /** @@ -2295,4 +2264,8 @@ public class Paint { private static native void nativeGetCharArrayBounds(long nativePaint, char[] text, int index, int count, int bidiFlags, Rect bounds); private static native void finalizer(long nativePaint); + + private static native void native_setShadowLayer(long native_object, + float radius, float dx, float dy, int color); + private static native boolean native_hasShadowLayer(long native_object); } diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java index 61b1b85..99ab4dd 100644 --- a/graphics/java/android/graphics/drawable/ShapeDrawable.java +++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java @@ -237,7 +237,7 @@ public class ShapeDrawable extends Drawable { paint.setAlpha(modulateAlpha(prevAlpha, state.mAlpha)); // only draw shape if it may affect output - if (paint.getAlpha() != 0 || paint.getXfermode() != null || paint.hasShadow) { + if (paint.getAlpha() != 0 || paint.getXfermode() != null || paint.hasShadowLayer()) { final boolean clearColorFilter; if (mTintFilter != null && paint.getColorFilter() == null) { paint.setColorFilter(mTintFilter); diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp index 3d58964..45b6624 100644 --- a/libs/hwui/DeferredDisplayList.cpp +++ b/libs/hwui/DeferredDisplayList.cpp @@ -190,7 +190,7 @@ public: // Overlapping other operations is only allowed for text without shadow. For other ops, // multiDraw isn't guaranteed to overdraw correctly - if (!isTextBatch || state->mDrawModifiers.mHasShadow) { + if (!isTextBatch || op->hasTextShadow()) { if (intersects(state->mBounds)) return false; } const DeferredDisplayState* lhs = state; diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index ce92beb..f1d70eb 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -183,6 +183,10 @@ public: return OpenGLRenderer::getAlphaDirect(mPaint); } + virtual bool hasTextShadow() const { + return false; + } + inline float strokeWidthOutset() { // since anything AA stroke with less than 1.0 pixel width is drawn with an alpha-reduced // 1.0 stroke, treat 1.0 as minimum. @@ -244,11 +248,11 @@ public: bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) { localBounds.set(mLocalBounds); - if (drawModifiers.mHasShadow) { - // TODO: inspect paint's looper directly + OpenGLRenderer::TextShadow textShadow; + if (OpenGLRenderer::getTextShadow(mPaint, &textShadow)) { Rect shadow(mLocalBounds); - shadow.translate(drawModifiers.mShadowDx, drawModifiers.mShadowDy); - shadow.outset(drawModifiers.mShadowRadius); + shadow.translate(textShadow.dx, textShadow.dx); + shadow.outset(textShadow.radius); localBounds.unionWith(shadow); } return true; @@ -619,41 +623,6 @@ private: SkiaShader* mShader; }; -class ResetShadowOp : public StateOp { -public: - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { - renderer.resetShadow(); - } - - virtual void output(int level, uint32_t logFlags) const { - OP_LOGS("ResetShadow"); - } - - virtual const char* name() { return "ResetShadow"; } -}; - -class SetupShadowOp : public StateOp { -public: - SetupShadowOp(float radius, float dx, float dy, int color) - : mRadius(radius), mDx(dx), mDy(dy), mColor(color) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { - renderer.setupShadow(mRadius, mDx, mDy, mColor); - } - - virtual void output(int level, uint32_t logFlags) const { - OP_LOG("SetupShadow, radius %f, %f, %f, color %#x", mRadius, mDx, mDy, mColor); - } - - virtual const char* name() { return "SetupShadow"; } - -private: - float mRadius; - float mDx; - float mDy; - int mColor; -}; - class ResetPaintFilterOp : public StateOp { public: virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { @@ -1351,6 +1320,10 @@ public: OP_LOG("Draw some text, %d bytes", mBytesCount); } + virtual bool hasTextShadow() const { + return OpenGLRenderer::hasTextShadow(mPaint); + } + virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, const DeferredDisplayState& state) { const SkPaint* paint = getPaint(renderer); diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 8afd106..c2ce6ed 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -410,16 +410,6 @@ void DisplayListRenderer::setupShader(SkiaShader* shader) { addStateOp(new (alloc()) SetupShaderOp(shader)); } -void DisplayListRenderer::resetShadow() { - addStateOp(new (alloc()) ResetShadowOp()); - OpenGLRenderer::resetShadow(); -} - -void DisplayListRenderer::setupShadow(float radius, float dx, float dy, int color) { - addStateOp(new (alloc()) SetupShadowOp(radius, dx, dy, color)); - OpenGLRenderer::setupShadow(radius, dx, dy, color); -} - void DisplayListRenderer::resetPaintFilter() { addStateOp(new (alloc()) ResetPaintFilterOp()); } diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 25e78c1..185179a 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -102,9 +102,6 @@ public: virtual void resetShader(); virtual void setupShader(SkiaShader* shader); - virtual void resetShadow(); - virtual void setupShadow(float radius, float dx, float dy, int color); - virtual void resetPaintFilter(); virtual void setupPaintFilter(int clearBits, int setBits); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 6de369c..87b07b3 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -2654,28 +2654,32 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text, FontRenderer& fontRenderer, int alpha, float x, float y) { mCaches.activeTexture(0); + TextShadow textShadow; + if (!getTextShadow(paint, &textShadow)) { + LOG_ALWAYS_FATAL("failed to query shadow attributes"); + } + // NOTE: The drop shadow will not perform gamma correction // if shader-based correction is enabled mCaches.dropShadowCache.setFontRenderer(fontRenderer); const ShadowTexture* shadow = mCaches.dropShadowCache.get( - paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions); + paint, text, bytesCount, count, textShadow.radius, positions); // If the drop shadow exceeds the max texture size or couldn't be // allocated, skip drawing if (!shadow) return; const AutoTexture autoCleanup(shadow); - const float sx = x - shadow->left + mDrawModifiers.mShadowDx; - const float sy = y - shadow->top + mDrawModifiers.mShadowDy; + const float sx = x - shadow->left + textShadow.dx; + const float sy = y - shadow->top + textShadow.dy; - const int shadowAlpha = ((mDrawModifiers.mShadowColor >> 24) & 0xFF) * mSnapshot->alpha; - int shadowColor = mDrawModifiers.mShadowColor; + const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha; if (mDrawModifiers.mShader) { - shadowColor = 0xffffffff; + textShadow.color = SK_ColorWHITE; } setupDraw(); setupDrawWithTexture(true); - setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha); + setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha); setupDrawColorFilter(getColorFilter(paint)); setupDrawShader(); setupDrawBlending(paint, true); @@ -2692,7 +2696,7 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text, } bool OpenGLRenderer::canSkipText(const SkPaint* paint) const { - float alpha = (mDrawModifiers.mHasShadow ? 1.0f : paint->getAlpha()) * mSnapshot->alpha; + float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * mSnapshot->alpha; return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode; } @@ -2724,7 +2728,7 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); - if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) { + if (CC_UNLIKELY(hasTextShadow(paint))) { drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, 0.0f, 0.0f); } @@ -2801,7 +2805,7 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, f FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); - if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) { + if (CC_UNLIKELY(hasTextShadow(paint))) { fontRenderer.setFont(paint, mat4::identity()); drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, oldX, oldY); @@ -3022,22 +3026,6 @@ void OpenGLRenderer::setupShader(SkiaShader* shader) { } /////////////////////////////////////////////////////////////////////////////// -// Drop shadow -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::resetShadow() { - mDrawModifiers.mHasShadow = false; -} - -void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) { - mDrawModifiers.mHasShadow = true; - mDrawModifiers.mShadowRadius = radius; - mDrawModifiers.mShadowDx = dx; - mDrawModifiers.mShadowDy = dy; - mDrawModifiers.mShadowColor = color; -} - -/////////////////////////////////////////////////////////////////////////////// // Draw filters /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 4de52ac..1d46945 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -29,6 +29,7 @@ #include <SkShader.h> #include <SkXfermode.h> +#include <utils/Blur.h> #include <utils/Functor.h> #include <utils/RefBase.h> #include <utils/SortedVector.h> @@ -72,13 +73,6 @@ struct DrawModifiers { SkiaShader* mShader; float mOverrideLayerAlpha; - // Drop shadow - bool mHasShadow; - float mShadowRadius; - float mShadowDx; - float mShadowDy; - int mShadowColor; - // Draw filters bool mHasDrawFilter; int mPaintFilterClearBits; @@ -226,9 +220,6 @@ public: virtual void resetShader(); virtual void setupShader(SkiaShader* shader); - virtual void resetShadow(); - virtual void setupShadow(float radius, float dx, float dy, int color); - virtual void resetPaintFilter(); virtual void setupPaintFilter(int clearBits, int setBits); @@ -316,6 +307,31 @@ public: return paint->getAlpha(); } + struct TextShadow { + SkScalar radius; + float dx; + float dy; + SkColor color; + }; + + static inline bool getTextShadow(const SkPaint* paint, TextShadow* textShadow) { + SkDrawLooper::BlurShadowRec blur; + if (paint && paint->getLooper() && paint->getLooper()->asABlurShadow(&blur)) { + if (textShadow) { + textShadow->radius = Blur::convertSigmaToRadius(blur.fSigma); + textShadow->dx = blur.fOffset.fX; + textShadow->dy = blur.fOffset.fY; + textShadow->color = blur.fColor; + } + return true; + } + return false; + } + + static inline bool hasTextShadow(const SkPaint* paint) { + return getTextShadow(paint, NULL); + } + /** * Return the best transform to use to rasterize text given a full * transform matrix. diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h index 3209a53..57db816 100644 --- a/libs/hwui/Renderer.h +++ b/libs/hwui/Renderer.h @@ -178,9 +178,6 @@ public: virtual void resetShader() = 0; virtual void setupShader(SkiaShader* shader) = 0; - virtual void resetShadow() = 0; - virtual void setupShadow(float radius, float dx, float dy, int color) = 0; - virtual void resetPaintFilter() = 0; virtual void setupPaintFilter(int clearBits, int setBits) = 0; diff --git a/libs/hwui/utils/Blur.cpp b/libs/hwui/utils/Blur.cpp index 85d90d0..c020b40 100644 --- a/libs/hwui/utils/Blur.cpp +++ b/libs/hwui/utils/Blur.cpp @@ -23,6 +23,31 @@ namespace android { namespace uirenderer { +// This constant approximates the scaling done in the software path's +// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). +static const float BLUR_SIGMA_SCALE = 0.57735f; + +float Blur::convertRadiusToSigma(float radius) { + return radius > 0 ? BLUR_SIGMA_SCALE * radius + 0.5f : 0.0f; +} + +float Blur::convertSigmaToRadius(float sigma) { + return sigma > 0.5f ? (sigma - 0.5f) / BLUR_SIGMA_SCALE : 0.0f; +} + +/** + * HWUI has used a slightly different equation than Skia to generate the value + * for sigma and to preserve compatibility we have kept that logic. + * + * Based on some experimental radius and sigma values we approximate the + * equation sigma = f(radius) as sigma = radius * 0.3 + 0.6. The larger the + * radius gets, the more our gaussian blur will resemble a box blur since with + * large sigma the gaussian curve begins to lose its shape. + */ +static float legacyConvertRadiusToSigma(float radius) { + return radius > 0 ? 0.3f * radius + 0.6f : 0.0f; +} + void Blur::generateGaussianWeights(float* weights, int32_t radius) { // Compute gaussian weights for the blur // e is the euler's number @@ -31,13 +56,7 @@ void Blur::generateGaussianWeights(float* weights, int32_t radius) { // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) // x is of the form [-radius .. 0 .. radius] // and sigma varies with radius. - // Based on some experimental radius values and sigma's - // we approximately fit sigma = f(radius) as - // sigma = radius * 0.3 + 0.6 - // The larger the radius gets, the more our gaussian blur - // will resemble a box blur since with large sigma - // the gaussian curve begins to lose its shape - float sigma = 0.3f * (float) radius + 0.6f; + float sigma = legacyConvertRadiusToSigma((float) radius); // Now compute the coefficints // We will store some redundant values to save some math during diff --git a/libs/hwui/utils/Blur.h b/libs/hwui/utils/Blur.h index 6c176e9..79aff65 100644 --- a/libs/hwui/utils/Blur.h +++ b/libs/hwui/utils/Blur.h @@ -18,12 +18,18 @@ #define ANDROID_HWUI_BLUR_H #include <stdint.h> +#include <cutils/compiler.h> namespace android { namespace uirenderer { class Blur { public: + // If radius > 0, return the corresponding sigma, else return 0 + ANDROID_API static float convertRadiusToSigma(float radius); + // If sigma > 0.6, return the corresponding radius, else return 0 + ANDROID_API static float convertSigmaToRadius(float sigma); + static void generateGaussianWeights(float* weights, int32_t radius); static void horizontal(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest, int32_t width, int32_t height); |