diff options
author | Nader Jawad <njawad@google.com> | 2018-11-16 11:22:32 -0800 |
---|---|---|
committer | Nader Jawad <njawad@google.com> | 2018-12-10 15:38:59 -0800 |
commit | 55e49d8816d7a6fad20df604839a4d2bfe6b9957 (patch) | |
tree | 702af16273fc7f932524de5b1a3d1bea676d1b13 | |
parent | f66699ae165ce30f1cda1cfd704027a75bf457d2 (diff) |
Added support for additional Blend Modes
Created new BlendMode enum that maps to XferModes with additional
supported native values that map to SkBlendMode constants
Created new BlendModeColorFilter
Deprecated PorterDuffColorMode and PorterDuffColorFilter in
favor of BlendMode and BlendModeColorFilter.
Updated Paint API to use setBlendMode and deprecated setXfermode
Bug: 119671925
Bug: 112166079
Bug: 73224934
Test: Added CTS tests for BlendMode and BlendModeColorFilter
Change-Id: Idd50e2f0b81975c5ecf6f1c0edd4eb68198d9131
40 files changed, 714 insertions, 15 deletions
diff --git a/api/current.txt b/api/current.txt index ff78d481f4de..ebec9e385c31 100755 --- a/api/current.txt +++ b/api/current.txt @@ -13417,6 +13417,46 @@ package android.graphics { ctor public BitmapShader(android.graphics.Bitmap, android.graphics.Shader.TileMode, android.graphics.Shader.TileMode); } + public final class BlendMode extends java.lang.Enum { + method public static android.graphics.BlendMode valueOf(java.lang.String); + method public static final android.graphics.BlendMode[] values(); + enum_constant public static final android.graphics.BlendMode CLEAR; + enum_constant public static final android.graphics.BlendMode COLOR; + enum_constant public static final android.graphics.BlendMode COLOR_BURN; + enum_constant public static final android.graphics.BlendMode COLOR_DODGE; + enum_constant public static final android.graphics.BlendMode DARKEN; + enum_constant public static final android.graphics.BlendMode DIFFERENCE; + enum_constant public static final android.graphics.BlendMode DST; + enum_constant public static final android.graphics.BlendMode DST_ATOP; + enum_constant public static final android.graphics.BlendMode DST_IN; + enum_constant public static final android.graphics.BlendMode DST_OUT; + enum_constant public static final android.graphics.BlendMode DST_OVER; + enum_constant public static final android.graphics.BlendMode EXCLUSION; + enum_constant public static final android.graphics.BlendMode HARD_LIGHT; + enum_constant public static final android.graphics.BlendMode HUE; + enum_constant public static final android.graphics.BlendMode LIGHTEN; + enum_constant public static final android.graphics.BlendMode LUMINOSITY; + enum_constant public static final android.graphics.BlendMode MODULATE; + enum_constant public static final android.graphics.BlendMode MULTIPLY; + enum_constant public static final android.graphics.BlendMode OVERLAY; + enum_constant public static final android.graphics.BlendMode PLUS; + enum_constant public static final android.graphics.BlendMode SATURATION; + enum_constant public static final android.graphics.BlendMode SCREEN; + enum_constant public static final android.graphics.BlendMode SOFT_LIGHT; + enum_constant public static final android.graphics.BlendMode SRC; + enum_constant public static final android.graphics.BlendMode SRC_ATOP; + enum_constant public static final android.graphics.BlendMode SRC_IN; + enum_constant public static final android.graphics.BlendMode SRC_OUT; + enum_constant public static final android.graphics.BlendMode SRC_OVER; + enum_constant public static final android.graphics.BlendMode XOR; + } + + public final class BlendModeColorFilter extends android.graphics.ColorFilter { + ctor public BlendModeColorFilter(int, android.graphics.BlendMode); + method public int getColor(); + method public android.graphics.BlendMode getMode(); + } + public class BlurMaskFilter extends android.graphics.MaskFilter { ctor public BlurMaskFilter(float, android.graphics.BlurMaskFilter.Blur); } @@ -13479,7 +13519,8 @@ package android.graphics { method public void drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint); method public void drawCircle(float, float, float, android.graphics.Paint); method public void drawColor(int); - method public void drawColor(int, android.graphics.PorterDuff.Mode); + method public deprecated void drawColor(int, android.graphics.PorterDuff.Mode); + method public void drawColor(int, android.graphics.BlendMode); method public void drawDoubleRoundRect(android.graphics.RectF, float, float, android.graphics.RectF, float, float, android.graphics.Paint); method public void drawDoubleRoundRect(android.graphics.RectF, float[], android.graphics.RectF, float[], android.graphics.Paint); method public void drawLine(float, float, float, float, android.graphics.Paint); @@ -14098,6 +14139,7 @@ package android.graphics { method public float descent(); method public boolean equalsForTextMeasurement(android.graphics.Paint); method public int getAlpha(); + method public android.graphics.BlendMode getBlendMode(); method public int getColor(); method public android.graphics.ColorFilter getColorFilter(); method public boolean getFillPath(android.graphics.Path, android.graphics.Path); @@ -14152,7 +14194,7 @@ package android.graphics { method public float getUnderlinePosition(); method public float getUnderlineThickness(); method public float getWordSpacing(); - method public android.graphics.Xfermode getXfermode(); + method public deprecated android.graphics.Xfermode getXfermode(); method public boolean hasGlyph(java.lang.String); method public final boolean isAntiAlias(); method public final boolean isDither(); @@ -14172,6 +14214,7 @@ package android.graphics { method public void setARGB(int, int, int, int); method public void setAlpha(int); method public void setAntiAlias(boolean); + method public void setBlendMode(android.graphics.BlendMode); method public void setColor(int); method public android.graphics.ColorFilter setColorFilter(android.graphics.ColorFilter); method public void setDither(boolean); @@ -14205,7 +14248,7 @@ package android.graphics { method public android.graphics.Typeface setTypeface(android.graphics.Typeface); method public void setUnderlineText(boolean); method public void setWordSpacing(float); - method public android.graphics.Xfermode setXfermode(android.graphics.Xfermode); + method public deprecated android.graphics.Xfermode setXfermode(android.graphics.Xfermode); field public static final int ANTI_ALIAS_FLAG = 1; // 0x1 field public static final int CURSOR_AFTER = 0; // 0x0 field public static final int CURSOR_AT = 4; // 0x4 @@ -14487,7 +14530,7 @@ package android.graphics { enum_constant public static final android.graphics.PorterDuff.Mode XOR; } - public class PorterDuffColorFilter extends android.graphics.ColorFilter { + public deprecated class PorterDuffColorFilter extends android.graphics.ColorFilter { ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode); } @@ -15040,7 +15083,7 @@ package android.graphics.drawable { method public final void setCallback(android.graphics.drawable.Drawable.Callback); method public void setChangingConfigurations(int); method public abstract void setColorFilter(android.graphics.ColorFilter); - method public void setColorFilter(int, android.graphics.PorterDuff.Mode); + method public deprecated void setColorFilter(int, android.graphics.PorterDuff.Mode); method public deprecated void setDither(boolean); method public void setFilterBitmap(boolean); method public void setHotspot(float, float); diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp index 6ebf35c8e1dc..a54571b539da 100644 --- a/core/jni/android/graphics/ColorFilter.cpp +++ b/core/jni/android/graphics/ColorFilter.cpp @@ -36,7 +36,7 @@ public: return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SafeUnref)); } - static jlong CreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor, jint modeHandle) { + static jlong CreateBlendModeFilter(JNIEnv* env, jobject, jint srcColor, jint modeHandle) { SkBlendMode mode = static_cast<SkBlendMode>(modeHandle); return reinterpret_cast<jlong>(SkColorFilter::MakeModeFilter(srcColor, mode).release()); } @@ -61,8 +61,8 @@ static const JNINativeMethod colorfilter_methods[] = { {"nativeGetFinalizer", "()J", (void*) SkColorFilterGlue::GetNativeFinalizer } }; -static const JNINativeMethod porterduff_methods[] = { - { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter }, +static const JNINativeMethod blendmode_methods[] = { + { "native_CreateBlendModeFilter", "(II)J", (void*) SkColorFilterGlue::CreateBlendModeFilter }, }; static const JNINativeMethod lighting_methods[] = { @@ -76,8 +76,10 @@ static const JNINativeMethod colormatrix_methods[] = { int register_android_graphics_ColorFilter(JNIEnv* env) { android::RegisterMethodsOrDie(env, "android/graphics/ColorFilter", colorfilter_methods, NELEM(colorfilter_methods)); - android::RegisterMethodsOrDie(env, "android/graphics/PorterDuffColorFilter", porterduff_methods, - NELEM(porterduff_methods)); + android::RegisterMethodsOrDie(env, "android/graphics/PorterDuffColorFilter", blendmode_methods, + NELEM(blendmode_methods)); + android::RegisterMethodsOrDie(env, "android/graphics/BlendModeColorFilter", blendmode_methods, + NELEM(blendmode_methods)); android::RegisterMethodsOrDie(env, "android/graphics/LightingColorFilter", lighting_methods, NELEM(lighting_methods)); android::RegisterMethodsOrDie(env, "android/graphics/ColorMatrixColorFilter", diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index a8b0640c3a73..cd54268e2fab 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -845,12 +845,23 @@ namespace PaintGlue { static_assert(9 == static_cast<int>(SkBlendMode::kSrcATop), "xfermode_mismatch"); static_assert(10 == static_cast<int>(SkBlendMode::kDstATop), "xfermode_mismatch"); static_assert(11 == static_cast<int>(SkBlendMode::kXor), "xfermode_mismatch"); - static_assert(16 == static_cast<int>(SkBlendMode::kDarken), "xfermode_mismatch"); - static_assert(17 == static_cast<int>(SkBlendMode::kLighten), "xfermode_mismatch"); + static_assert(12 == static_cast<int>(SkBlendMode::kPlus), "xfermode_mismatch"); static_assert(13 == static_cast<int>(SkBlendMode::kModulate), "xfermode_mismatch"); static_assert(14 == static_cast<int>(SkBlendMode::kScreen), "xfermode_mismatch"); - static_assert(12 == static_cast<int>(SkBlendMode::kPlus), "xfermode_mismatch"); static_assert(15 == static_cast<int>(SkBlendMode::kOverlay), "xfermode_mismatch"); + static_assert(16 == static_cast<int>(SkBlendMode::kDarken), "xfermode_mismatch"); + static_assert(17 == static_cast<int>(SkBlendMode::kLighten), "xfermode_mismatch"); + static_assert(18 == static_cast<int>(SkBlendMode::kColorDodge), "xfermode mismatch"); + static_assert(19 == static_cast<int>(SkBlendMode::kColorBurn), "xfermode mismatch"); + static_assert(20 == static_cast<int>(SkBlendMode::kHardLight), "xfermode mismatch"); + static_assert(21 == static_cast<int>(SkBlendMode::kSoftLight), "xfermode mismatch"); + static_assert(22 == static_cast<int>(SkBlendMode::kDifference), "xfermode mismatch"); + static_assert(23 == static_cast<int>(SkBlendMode::kExclusion), "xfermode mismatch"); + static_assert(24 == static_cast<int>(SkBlendMode::kMultiply), "xfermode mismatch"); + static_assert(25 == static_cast<int>(SkBlendMode::kHue), "xfermode mismatch"); + static_assert(26 == static_cast<int>(SkBlendMode::kSaturation), "xfermode mismatch"); + static_assert(27 == static_cast<int>(SkBlendMode::kColor), "xfermode mismatch"); + static_assert(28 == static_cast<int>(SkBlendMode::kLuminosity), "xfermode mismatch"); SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle); Paint* paint = reinterpret_cast<Paint*>(paintHandle); diff --git a/docs/html/reference/images/graphics/blendmode_CLEAR.png b/docs/html/reference/images/graphics/blendmode_CLEAR.png Binary files differnew file mode 100644 index 000000000000..979782adef58 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_CLEAR.png diff --git a/docs/html/reference/images/graphics/blendmode_COLOR.png b/docs/html/reference/images/graphics/blendmode_COLOR.png Binary files differnew file mode 100644 index 000000000000..2f41bfb03cfb --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_COLOR.png diff --git a/docs/html/reference/images/graphics/blendmode_COLOR_BURN.png b/docs/html/reference/images/graphics/blendmode_COLOR_BURN.png Binary files differnew file mode 100644 index 000000000000..26059ce858ee --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_COLOR_BURN.png diff --git a/docs/html/reference/images/graphics/blendmode_COLOR_DODGE.png b/docs/html/reference/images/graphics/blendmode_COLOR_DODGE.png Binary files differnew file mode 100644 index 000000000000..922f1d9e474d --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_COLOR_DODGE.png diff --git a/docs/html/reference/images/graphics/blendmode_DARKEN.png b/docs/html/reference/images/graphics/blendmode_DARKEN.png Binary files differnew file mode 100644 index 000000000000..6c04aa3a129f --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DARKEN.png diff --git a/docs/html/reference/images/graphics/blendmode_DIFFERENCE.png b/docs/html/reference/images/graphics/blendmode_DIFFERENCE.png Binary files differnew file mode 100644 index 000000000000..aab2bcb8833a --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DIFFERENCE.png diff --git a/docs/html/reference/images/graphics/blendmode_DST.png b/docs/html/reference/images/graphics/blendmode_DST.png Binary files differnew file mode 100644 index 000000000000..16f96b4752b8 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DST.png diff --git a/docs/html/reference/images/graphics/blendmode_DST_ATOP.png b/docs/html/reference/images/graphics/blendmode_DST_ATOP.png Binary files differnew file mode 100644 index 000000000000..d0ae2cde7b0f --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DST_ATOP.png diff --git a/docs/html/reference/images/graphics/blendmode_DST_IN.png b/docs/html/reference/images/graphics/blendmode_DST_IN.png Binary files differnew file mode 100644 index 000000000000..9befe279af73 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DST_IN.png diff --git a/docs/html/reference/images/graphics/blendmode_DST_OUT.png b/docs/html/reference/images/graphics/blendmode_DST_OUT.png Binary files differnew file mode 100644 index 000000000000..e9227e9f06d3 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DST_OUT.png diff --git a/docs/html/reference/images/graphics/blendmode_DST_OVER.png b/docs/html/reference/images/graphics/blendmode_DST_OVER.png Binary files differnew file mode 100644 index 000000000000..015be0a4a730 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DST_OVER.png diff --git a/docs/html/reference/images/graphics/blendmode_EXCLUSION.png b/docs/html/reference/images/graphics/blendmode_EXCLUSION.png Binary files differnew file mode 100644 index 000000000000..307dec90ec33 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_EXCLUSION.png diff --git a/docs/html/reference/images/graphics/blendmode_HARD_LIGHT.png b/docs/html/reference/images/graphics/blendmode_HARD_LIGHT.png Binary files differnew file mode 100644 index 000000000000..3b62b9855bf4 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_HARD_LIGHT.png diff --git a/docs/html/reference/images/graphics/blendmode_HUE.png b/docs/html/reference/images/graphics/blendmode_HUE.png Binary files differnew file mode 100644 index 000000000000..012bd3332358 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_HUE.png diff --git a/docs/html/reference/images/graphics/blendmode_LIGHTEN.png b/docs/html/reference/images/graphics/blendmode_LIGHTEN.png Binary files differnew file mode 100644 index 000000000000..1c3be656e40a --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_LIGHTEN.png diff --git a/docs/html/reference/images/graphics/blendmode_LUMINOSITY.png b/docs/html/reference/images/graphics/blendmode_LUMINOSITY.png Binary files differnew file mode 100644 index 000000000000..3549082e4c62 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_LUMINOSITY.png diff --git a/docs/html/reference/images/graphics/blendmode_MODULATE.png b/docs/html/reference/images/graphics/blendmode_MODULATE.png Binary files differnew file mode 100644 index 000000000000..ed1b59d140e8 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_MODULATE.png diff --git a/docs/html/reference/images/graphics/blendmode_MULTIPLY.png b/docs/html/reference/images/graphics/blendmode_MULTIPLY.png Binary files differnew file mode 100644 index 000000000000..c8c7ccb1e21a --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_MULTIPLY.png diff --git a/docs/html/reference/images/graphics/blendmode_OVERLAY.png b/docs/html/reference/images/graphics/blendmode_OVERLAY.png Binary files differnew file mode 100644 index 000000000000..6962f928dc7e --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_OVERLAY.png diff --git a/docs/html/reference/images/graphics/blendmode_PLUS.png b/docs/html/reference/images/graphics/blendmode_PLUS.png Binary files differnew file mode 100644 index 000000000000..015fa2b5d0e4 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_PLUS.png diff --git a/docs/html/reference/images/graphics/blendmode_SATURATION.png b/docs/html/reference/images/graphics/blendmode_SATURATION.png Binary files differnew file mode 100644 index 000000000000..5ac96c32f648 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SATURATION.png diff --git a/docs/html/reference/images/graphics/blendmode_SCREEN.png b/docs/html/reference/images/graphics/blendmode_SCREEN.png Binary files differnew file mode 100644 index 000000000000..d2d70d25850d --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SCREEN.png diff --git a/docs/html/reference/images/graphics/blendmode_SOFT_LIGHT.png b/docs/html/reference/images/graphics/blendmode_SOFT_LIGHT.png Binary files differnew file mode 100644 index 000000000000..89fbacd24dcc --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SOFT_LIGHT.png diff --git a/docs/html/reference/images/graphics/blendmode_SRC.png b/docs/html/reference/images/graphics/blendmode_SRC.png Binary files differnew file mode 100644 index 000000000000..990ec94301b3 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SRC.png diff --git a/docs/html/reference/images/graphics/blendmode_SRC_ATOP.png b/docs/html/reference/images/graphics/blendmode_SRC_ATOP.png Binary files differnew file mode 100644 index 000000000000..d574dfd923f2 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SRC_ATOP.png diff --git a/docs/html/reference/images/graphics/blendmode_SRC_IN.png b/docs/html/reference/images/graphics/blendmode_SRC_IN.png Binary files differnew file mode 100644 index 000000000000..dda45d7319a4 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SRC_IN.png diff --git a/docs/html/reference/images/graphics/blendmode_SRC_OUT.png b/docs/html/reference/images/graphics/blendmode_SRC_OUT.png Binary files differnew file mode 100644 index 000000000000..f5d43c103dc2 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SRC_OUT.png diff --git a/docs/html/reference/images/graphics/blendmode_SRC_OVER.png b/docs/html/reference/images/graphics/blendmode_SRC_OVER.png Binary files differnew file mode 100644 index 000000000000..b1a405bc878d --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SRC_OVER.png diff --git a/docs/html/reference/images/graphics/blendmode_XOR.png b/docs/html/reference/images/graphics/blendmode_XOR.png Binary files differnew file mode 100644 index 000000000000..31c110d98d27 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_XOR.png diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java index 3db240b54299..ca9dc475f7a1 100644 --- a/graphics/java/android/graphics/BaseCanvas.java +++ b/graphics/java/android/graphics/BaseCanvas.java @@ -241,10 +241,22 @@ public abstract class BaseCanvas { nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt); } + /** + * @deprecated use {@link Canvas#drawColor(int, BlendMode)} + */ + @Deprecated public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) { nDrawColor(mNativeCanvasWrapper, color, mode.nativeInt); } + /** + * Make lint happy. + * See {@link Canvas#drawColor(int, BlendMode)} + */ + public void drawColor(@ColorInt int color, @NonNull BlendMode mode) { + nDrawColor(mNativeCanvasWrapper, color, mode.getXfermode().porterDuffMode); + } + public void drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint) { throwIfHasHwBitmapInSwMode(paint); diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java index 4de7ca708eb6..901c2116884b 100644 --- a/graphics/java/android/graphics/BaseRecordingCanvas.java +++ b/graphics/java/android/graphics/BaseRecordingCanvas.java @@ -201,12 +201,21 @@ public class BaseRecordingCanvas extends Canvas { nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt); } + /** + * @deprecated use {@link #drawColor(int, BlendMode)} instead + */ + @Deprecated @Override public final void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) { nDrawColor(mNativeCanvasWrapper, color, mode.nativeInt); } @Override + public final void drawColor(@ColorInt int color, @NonNull BlendMode mode) { + nDrawColor(mNativeCanvasWrapper, color, mode.getXfermode().porterDuffMode); + } + + @Override public final void drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint) { nDrawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance()); diff --git a/graphics/java/android/graphics/BlendMode.java b/graphics/java/android/graphics/BlendMode.java new file mode 100644 index 000000000000..39392c89d170 --- /dev/null +++ b/graphics/java/android/graphics/BlendMode.java @@ -0,0 +1,472 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +public enum BlendMode { + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_CLEAR.png" /> + * <figcaption>Destination pixels covered by the source are cleared to 0.</figcaption> + * </p> + * <p>\(\alpha_{out} = 0\)</p> + * <p>\(C_{out} = 0\)</p> + */ + CLEAR(0), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC.png" /> + * <figcaption>The source pixels replace the destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src}\)</p> + * <p>\(C_{out} = C_{src}\)</p> + */ + SRC(1), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST.png" /> + * <figcaption>The source pixels are discarded, leaving the destination intact.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{dst}\)</p> + * <p>\(C_{out} = C_{dst}\)</p> + */ + DST(2), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_OVER.png" /> + * <figcaption>The source pixels are drawn over the destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)</p> + * <p>\(C_{out} = C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p> + */ + SRC_OVER(3), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_OVER.png" /> + * <figcaption>The source pixels are drawn behind the destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{dst} + (1 - \alpha_{dst}) * \alpha_{src}\)</p> + * <p>\(C_{out} = C_{dst} + (1 - \alpha_{dst}) * C_{src}\)</p> + */ + DST_OVER(4), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_IN.png" /> + * <figcaption>Keeps the source pixels that cover the destination pixels, + * discards the remaining source and destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p> + * <p>\(C_{out} = C_{src} * \alpha_{dst}\)</p> + */ + SRC_IN(5), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_IN.png" /> + * <figcaption>Keeps the destination pixels that cover source pixels, + * discards the remaining source and destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p> + * <p>\(C_{out} = C_{dst} * \alpha_{src}\)</p> + */ + DST_IN(6), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_OUT.png" /> + * <figcaption>Keeps the source pixels that do not cover destination pixels. + * Discards source pixels that cover destination pixels. Discards all + * destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src}\)</p> + * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src}\)</p> + */ + SRC_OUT(7), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_OUT.png" /> + * <figcaption>Keeps the destination pixels that are not covered by source pixels. + * Discards destination pixels that are covered by source pixels. Discards all + * source pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = (1 - \alpha_{src}) * \alpha_{dst}\)</p> + * <p>\(C_{out} = (1 - \alpha_{src}) * C_{dst}\)</p> + */ + DST_OUT(8), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_ATOP.png" /> + * <figcaption>Discards the source pixels that do not cover destination pixels. + * Draws remaining source pixels over destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{dst}\)</p> + * <p>\(C_{out} = \alpha_{dst} * C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p> + */ + SRC_ATOP(9), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_ATOP.png" /> + * <figcaption>Discards the destination pixels that are not covered by source pixels. + * Draws remaining destination pixels over source pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src}\)</p> + * <p>\(C_{out} = \alpha_{src} * C_{dst} + (1 - \alpha_{dst}) * C_{src}\)</p> + */ + DST_ATOP(10), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_XOR.png" /> + * <figcaption>Discards the source and destination pixels where source pixels + * cover destination pixels. Draws remaining source pixels.</figcaption> + * </p> + * <p> + * \(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\) + * </p> + * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p> + */ + XOR(11), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_PLUS.png" /> + * <figcaption>Adds the source pixels to the destination pixels and saturates + * the result.</figcaption> + * </p> + * <p>\(\alpha_{out} = max(0, min(\alpha_{src} + \alpha_{dst}, 1))\)</p> + * <p>\(C_{out} = max(0, min(C_{src} + C_{dst}, 1))\)</p> + */ + PLUS(12), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_MODULATE.png" /> + * <figcaption>Multiplies the source and destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p> + * <p>\(C_{out} = C_{src} * C_{dst}\)</p> + * + */ + MODULATE(13), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SCREEN.png" /> + * <figcaption> + * Adds the source and destination pixels, then subtracts the + * source pixels multiplied by the destination. + * </figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> + * <p>\(C_{out} = C_{src} + C_{dst} - C_{src} * C_{dst}\)</p> + */ + SCREEN(14), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_OVERLAY.png" /> + * <figcaption> + * Multiplies or screens the source and destination depending on the + * destination color. + * </figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> + * <p>\(\begin{equation} + * C_{out} = \begin{cases} 2 * C_{src} * C_{dst} & 2 * C_{dst} \lt \alpha_{dst} \\ + * \alpha_{src} * \alpha_{dst} - 2 (\alpha_{dst} - C_{src}) (\alpha_{src} - C_{dst}) & + * otherwise \end{cases} + * \end{equation}\)</p> + */ + OVERLAY(15), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DARKEN.png" /> + * <figcaption> + * Retains the smallest component of the source and + * destination pixels. + * </figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> + * <p> + * \(C_{out} = + * (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + min(C_{src}, C_{dst})\) + * </p> + */ + DARKEN(16), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_LIGHTEN.png" /> + * <figcaption>Retains the largest component of the source and + * destination pixel.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> + * <p> + * \(C_{out} = + * (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + max(C_{src}, C_{dst})\) + * </p> + */ + LIGHTEN(17), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR_DODGE.png" /> + * <figcaption>Makes destination brighter to reflect source.</figcaption> + * </p> + * <p> + * \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\) + * </p> + * <p> + * \begin{equation} + * C_{out} = + * \begin{cases} + * C_{src} * (1 - \alpha_{dst}) & C_{dst} = 0 \\ + * C_{src} + \alpha_{dst}*(1 - \alpha_{src}) & C_{src} = \alpha_{src} \\ + * \alpha_{src} * min(\alpha_{dst}, C_{dst} * \alpha_{src}/(\alpha_{src} - C_{src})) + * + C_{src} *(1 - \alpha_{dst} + \alpha_{dst}*(1 - \alpha_{src}) & otherwise + * \end{cases} + * \end{equation} + * </p> + */ + COLOR_DODGE(18), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR_BURN.png" /> + * <figcaption>Makes destination darker to reflect source.</figcaption> + * </p> + * <p> + * \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\) + * </p> + * <p> + * \begin{equation} + * C_{out} = + * \begin{cases} + * C_{dst} + C_{src}*(1 - \alpha_{dst}) & C_{dst} = \alpha_{dst} \\ + * \alpha_{dst}*(1 - \alpha_{src}) & C_{src} = 0 \\ + * \alpha_{src}*(\alpha_{dst} - min(\alpha_{dst}, (\alpha_{dst} + * - C_{dst})*\alpha_{src}/C_{src})) + * + C_{src} * (1 - \alpha_{dst}) + \alpha_{dst}*(1-\alpha_{src}) & otherwise + * \end{cases} + * \end{equation} + * </p> + */ + COLOR_BURN(19), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_HARD_LIGHT.png" /> + * <figcaption>Makes destination lighter or darker, depending on source.</figcaption> + * </p> + * <p> + * \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\) + * </p> + * <p> + * \begin{equation} + * C_{out} = + * \begin{cases} + * 2*C_{src}*C_{dst} & C_{src}*(1-\alpha_{dst}) + C_{dst}*(1-\alpha_{src}) + 2*C_{src} + * \leq \alpha_{src} \\ + * \alpha_{src}*\alpha_{dst}- 2*(\alpha_{dst} - C_{dst})*(\alpha_{src} - C_{src}) + * & otherwise + * \end{cases} + * \end{equation} + * </p> + */ + HARD_LIGHT(20), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SOFT_LIGHT.png" /> + * <figcaption>Makes destination lighter or darker, depending on source.</figcaption> + * </p> + * <p> + * Where + * \begin{equation} + * m = + * \begin{cases} + * C_{dst} / \alpha_{dst} & \alpha_{dst} \gt 0 \\ + * 0 & otherwise + * \end{cases} + * \end{equation} + * </p> + * <p> + * \begin{equation} + * g = + * \begin{cases} + * (16 * m * m + 4 * m) * (m - 1) + 7 * m & 4 * C_{dst} \leq \alpha_{dst} \\ + * \sqrt m - m & otherwise + * \end{cases} + * \end{equation} + * </p> + * <p> + * \begin{equation} + * f = + * \begin{cases} + * C_{dst} * (\alpha_{src} + (2 * C_{src} - \alpha_{src}) * (1 - m)) + * & 2 * C_{src} \leq \alpha_{src} \\ + * C_{dst} * \alpha_{src} + \alpha_{dst} * (2 * C_{src} - \alpha_{src}) * g + * & otherwise + * \end{cases} + * \end{equation} + * </p> + * <p> + * \begin{equation} + * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst} + * \end{equation} + * \begin{equation} + * C_{out} = C_{src} / \alpha_{dst} + C_{dst} / \alpha_{src} + f + * \end{equation} + * </p> + */ + SOFT_LIGHT(21), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DIFFERENCE.png" /> + * <figcaption>Subtracts darker from lighter with higher contrast.</figcaption> + * </p> + * <p> + * \begin{equation} + * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst} + * \end{equation} + * </p> + * <p> + * \begin{equation} + * C_{out} = C_{src} + C_{dst} - 2 * min(C_{src} + * * \alpha_{dst}, C_{dst} * \alpha_{src}) + * \end{equation} + * </p> + */ + DIFFERENCE(22), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DIFFERENCE.png" /> + * <figcaption>Subtracts darker from lighter with lower contrast.</figcaption> + * </p> + * <p> + * \begin{equation} + * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst} + * \end{equation} + * </p> + * <p> + * \begin{equation} + * C_{out} = C_{src} + C_{dst} - 2 * C_{src} * C_{dst} + * \end{equation} + * </p> + */ + EXCLUSION(23), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_MODULATE.png" /> + * <figcaption>Multiplies the source and destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> + * <p>\(C_{out} = + * C_{src} * (1 - \alpha_{dst}) + C_{dst} * (1 - \alpha_{src}) + (C_{src} * C_{dst})\) + * </p> + */ + MULTIPLY(24), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_HUE.png" /> + * <figcaption> + * Replaces hue of destination with hue of source, leaving saturation + * and luminosity unchanged. + * </figcaption> + * </p> + */ + HUE(25), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SATURATION.png" /> + * <figcaption> + * Replaces saturation of destination saturation hue of source, leaving hue and + * luminosity unchanged. + * </figcaption> + * </p> + */ + SATURATION(26), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR.png" /> + * <figcaption> + * Replaces hue and saturation of destination with hue and saturation of source, + * leaving luminosity unchanged. + * </figcaption> + * </p> + */ + COLOR(27), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_LUMINOSITY.png" /> + * <figcaption> + * Replaces luminosity of destination with luminosity of source, leaving hue and + * saturation unchanged. + * </figcaption> + * </p> + */ + LUMINOSITY(28); + + private static final BlendMode[] BLEND_MODES = values(); + + /** + * @hide + */ + public static @Nullable BlendMode fromValue(int value) { + for (BlendMode mode : BLEND_MODES) { + if (mode.mXfermode.porterDuffMode == value) { + return mode; + } + } + return null; + } + + @NonNull + private final Xfermode mXfermode; + + BlendMode(int mode) { + mXfermode = new Xfermode(); + mXfermode.porterDuffMode = mode; + } + + /** + * @hide + */ + @NonNull + public Xfermode getXfermode() { + return mXfermode; + } +} diff --git a/graphics/java/android/graphics/BlendModeColorFilter.java b/graphics/java/android/graphics/BlendModeColorFilter.java new file mode 100644 index 000000000000..7caeb4267ad2 --- /dev/null +++ b/graphics/java/android/graphics/BlendModeColorFilter.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics; + +import android.annotation.ColorInt; +import android.annotation.NonNull; + +/** + * A color filter that can be used to tint the source pixels using a single + * color and a specific {@link BlendMode}. + */ +public final class BlendModeColorFilter extends ColorFilter { + + @ColorInt final int mColor; + private final BlendMode mMode; + + public BlendModeColorFilter(@ColorInt int color, @NonNull BlendMode mode) { + mColor = color; + mMode = mode; + } + + + /** + * Returns the ARGB color used to tint the source pixels when this filter + * is applied. + * + * @see Color + * + */ + @ColorInt + public int getColor() { + return mColor; + } + + /** + * Returns the Porter-Duff mode used to composite this color filter's + * color with the source pixel when this filter is applied. + * + * @see BlendMode + * + */ + public BlendMode getMode() { + return mMode; + } + + @Override + long createNativeInstance() { + return native_CreateBlendModeFilter(mColor, mMode.getXfermode().porterDuffMode); + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + final BlendModeColorFilter other = (BlendModeColorFilter) object; + return other.mMode == mMode; + } + + @Override + public int hashCode() { + return 31 * mMode.hashCode() + mColor; + } + + private static native long native_CreateBlendModeFilter(int srcColor, int blendmode); + +} diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 3b0dc9d9f125..f61890c18a14 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -1684,12 +1684,26 @@ public class Canvas extends BaseCanvas { * * @param color the color to draw with * @param mode the porter-duff mode to apply to the color + * + * @deprecated use {@link #drawColor(int, BlendMode)} instead */ + @Deprecated public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) { super.drawColor(color, mode); } /** + * Fill the entire canvas' bitmap (restricted to the current clip) with the specified color and + * blendmode. + * + * @param color the color to draw with + * @param mode the blendmode to apply to the color + */ + public void drawColor(@ColorInt int color, @NonNull BlendMode mode) { + super.drawColor(color, mode); + } + + /** * Draw a line segment with the specified start and stop x,y coordinates, using the specified * paint. * <p> diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 69ff3bca6528..6821282bd0a7 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -1168,12 +1168,29 @@ public class Paint { * Get the paint's transfer mode object. * * @return the paint's transfer mode (or null) + * + * @deprecated use {@link #getBlendMode()} instead */ + @Deprecated public Xfermode getXfermode() { return mXfermode; } /** + * Get the paint's blend mode object. + * + * @return the paint's blend mode (or null) + */ + @Nullable + public BlendMode getBlendMode() { + if (mXfermode == null) { + return null; + } else { + return BlendMode.fromValue(mXfermode.porterDuffMode); + } + } + + /** * Set or clear the transfer mode object. A transfer mode defines how * source pixels (generate by a drawing command) are composited with * the destination pixels (content of the render target). @@ -1185,8 +1202,17 @@ public class Paint { * * @param xfermode May be null. The xfermode to be installed in the paint * @return xfermode + * + * @deprecated Use {@link #setBlendMode} to apply a Xfermode directly + * through usage of {@link BlendMode} */ + @Deprecated public Xfermode setXfermode(Xfermode xfermode) { + return installXfermode(xfermode); + } + + @Nullable + private Xfermode installXfermode(Xfermode xfermode) { int newMode = xfermode != null ? xfermode.porterDuffMode : Xfermode.DEFAULT; int curMode = mXfermode != null ? mXfermode.porterDuffMode : Xfermode.DEFAULT; if (newMode != curMode) { @@ -1197,6 +1223,23 @@ public class Paint { } /** + * Set or clear the blend mode. A blend mode defines how source pixels + * (generated by a drawing command) are composited with the destination pixels + * (content of the render target). + * <p /> + * Pass null to clear any previous blend mode. + * As a convenience, the parameter passed is also returned. + * <p /> + * + * @see BlendMode + * + * @param blendmode May be null. The blend mode to be installed in the paint + */ + public void setBlendMode(@Nullable BlendMode blendmode) { + installXfermode(blendmode != null ? blendmode.getXfermode() : null); + } + + /** * Get the paint's patheffect object. * * @return the paint's patheffect (or null) diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java index 6665220c293c..c2a8eb7dbab1 100644 --- a/graphics/java/android/graphics/PorterDuffColorFilter.java +++ b/graphics/java/android/graphics/PorterDuffColorFilter.java @@ -23,7 +23,11 @@ import android.annotation.UnsupportedAppUsage; /** * A color filter that can be used to tint the source pixels using a single * color and a specific {@link PorterDuff Porter-Duff composite mode}. + * + * @deprecated Consider using {@link BlendModeColorFilter} instead as it supports a wider + * set of blend modes than those defined in {@link PorterDuff.Mode} */ +@Deprecated public class PorterDuffColorFilter extends ColorFilter { @ColorInt private int mColor; @@ -71,7 +75,7 @@ public class PorterDuffColorFilter extends ColorFilter { @Override long createNativeInstance() { - return native_CreatePorterDuffFilter(mColor, mMode.nativeInt); + return native_CreateBlendModeFilter(mColor, mMode.nativeInt); } @Override @@ -91,5 +95,5 @@ public class PorterDuffColorFilter extends ColorFilter { return 31 * mMode.hashCode() + mColor; } - private static native long native_CreatePorterDuffFilter(int srcColor, int porterDuffMode); + private static native long native_CreateBlendModeFilter(int srcColor, int blendmode); } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index caf610b8c236..a5482650c0e7 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -595,7 +595,12 @@ public abstract class Drawable { * <p class="note"><strong>Note:</strong> Setting a color filter disables * {@link #setTintList(ColorStateList) tint}. * </p> + * + * @see {@link #setColorFilter(ColorFilter)} } + * @deprecated use {@link #setColorFilter(ColorFilter)} with an instance + * of {@link android.graphics.BlendModeColorFilter} */ + @Deprecated public void setColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) { if (getColorFilter() instanceof PorterDuffColorFilter) { PorterDuffColorFilter existing = (PorterDuffColorFilter) getColorFilter(); |