• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.graphics;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 
22 @android.ravenwood.annotation.RavenwoodKeepWholeClass
23 public enum BlendMode {
24 
25     /**
26      * {@usesMathJax}
27      *
28      * <p>
29      *  <img src="{@docRoot}reference/android/images/graphics/blendmode_CLEAR.png" />
30      *  <figcaption>Destination pixels covered by the source are cleared to 0.</figcaption>
31      * </p>
32      * <p>\(\alpha_{out} = 0\)</p>
33      * <p>\(C_{out} = 0\)</p>
34      */
35     CLEAR(0),
36 
37     /**
38      * {@usesMathJax}
39      *
40      * <p>
41      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC.png" />
42      *     <figcaption>The source pixels replace the destination pixels.</figcaption>
43      * </p>
44      * <p>\(\alpha_{out} = \alpha_{src}\)</p>
45      * <p>\(C_{out} = C_{src}\)</p>
46      */
47     SRC(1),
48 
49     /**
50      * {@usesMathJax}
51      *
52      * <p>
53      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_DST.png" />
54      *     <figcaption>The source pixels are discarded, leaving the destination intact.</figcaption>
55      * </p>
56      * <p>\(\alpha_{out} = \alpha_{dst}\)</p>
57      * <p>\(C_{out} = C_{dst}\)</p>
58      */
59     DST(2),
60 
61     /**
62      * {@usesMathJax}
63      *
64      * <p>
65      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_OVER.png" />
66      *     <figcaption>The source pixels are drawn over the destination pixels.</figcaption>
67      * </p>
68      * <p>\(\alpha_{out} = \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)</p>
69      * <p>\(C_{out} = C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p>
70      */
71     SRC_OVER(3),
72 
73     /**
74      * {@usesMathJax}
75      *
76      * <p>
77      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_OVER.png" />
78      *     <figcaption>The source pixels are drawn behind the destination pixels.</figcaption>
79      * </p>
80      * <p>\(\alpha_{out} = \alpha_{dst} + (1 - \alpha_{dst}) * \alpha_{src}\)</p>
81      * <p>\(C_{out} = C_{dst} + (1 - \alpha_{dst}) * C_{src}\)</p>
82      */
83     DST_OVER(4),
84 
85     /**
86      * {@usesMathJax}
87      *
88      * <p>
89      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_IN.png" />
90      *     <figcaption>Keeps the source pixels that cover the destination pixels,
91      *     discards the remaining source and destination pixels.</figcaption>
92      * </p>
93      * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p>
94      * <p>\(C_{out} = C_{src} * \alpha_{dst}\)</p>
95      */
96     SRC_IN(5),
97 
98     /**
99      * {@usesMathJax}
100      *
101      * <p>
102      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_IN.png" />
103      *     <figcaption>Keeps the destination pixels that cover source pixels,
104      *     discards the remaining source and destination pixels.</figcaption>
105      * </p>
106      * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p>
107      * <p>\(C_{out} = C_{dst} * \alpha_{src}\)</p>
108      */
109     DST_IN(6),
110 
111     /**
112      * {@usesMathJax}
113      *
114      * <p>
115      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_OUT.png" />
116      *     <figcaption>Keeps the source pixels that do not cover destination pixels.
117      *     Discards source pixels that cover destination pixels. Discards all
118      *     destination pixels.</figcaption>
119      * </p>
120      * <p>\(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src}\)</p>
121      * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src}\)</p>
122      */
123     SRC_OUT(7),
124 
125     /**
126      * {@usesMathJax}
127      *
128      * <p>
129      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_OUT.png" />
130      *     <figcaption>Keeps the destination pixels that are not covered by source pixels.
131      *     Discards destination pixels that are covered by source pixels. Discards all
132      *     source pixels.</figcaption>
133      * </p>
134      * <p>\(\alpha_{out} = (1 - \alpha_{src}) * \alpha_{dst}\)</p>
135      * <p>\(C_{out} = (1 - \alpha_{src}) * C_{dst}\)</p>
136      */
137     DST_OUT(8),
138 
139     /**
140      * {@usesMathJax}
141      *
142      * <p>
143      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_ATOP.png" />
144      *     <figcaption>Discards the source pixels that do not cover destination pixels.
145      *     Draws remaining source pixels over destination pixels.</figcaption>
146      * </p>
147      * <p>\(\alpha_{out} = \alpha_{dst}\)</p>
148      * <p>\(C_{out} = \alpha_{dst} * C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p>
149      */
150     SRC_ATOP(9),
151 
152     /**
153      * {@usesMathJax}
154      *
155      * <p>
156      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_ATOP.png" />
157      *     <figcaption>Discards the destination pixels that are not covered by source pixels.
158      *     Draws remaining destination pixels over source pixels.</figcaption>
159      * </p>
160      * <p>\(\alpha_{out} = \alpha_{src}\)</p>
161      * <p>\(C_{out} = \alpha_{src} * C_{dst} + (1 - \alpha_{dst}) * C_{src}\)</p>
162      */
163     DST_ATOP(10),
164 
165     /**
166      * {@usesMathJax}
167      *
168      * <p>
169      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_XOR.png" />
170      *     <figcaption>Discards the source and destination pixels where source pixels
171      *     cover destination pixels. Draws remaining source pixels.</figcaption>
172      * </p>
173      * <p>
174      *     \(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)
175      * </p>
176      * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p>
177      */
178     XOR(11),
179 
180     /**
181      * {@usesMathJax}
182      *
183      * <p>
184      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_PLUS.png" />
185      *     <figcaption>Adds the source pixels to the destination pixels and saturates
186      *     the result.</figcaption>
187      * </p>
188      * <p>\(\alpha_{out} = max(0, min(\alpha_{src} + \alpha_{dst}, 1))\)</p>
189      * <p>\(C_{out} = max(0, min(C_{src} + C_{dst}, 1))\)</p>
190      */
191     PLUS(12),
192 
193     /**
194      * {@usesMathJax}
195      *
196      * <p>
197      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_MODULATE.png" />
198      *     <figcaption>Multiplies the source and destination pixels.</figcaption>
199      * </p>
200      * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p>
201      * <p>\(C_{out} = C_{src} * C_{dst}\)</p>
202      *
203      */
204     MODULATE(13),
205 
206     /**
207      * {@usesMathJax}
208      *
209      * <p>
210      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_SCREEN.png" />
211      *     <figcaption>
212      *         Adds the source and destination pixels, then subtracts the
213      *         source pixels multiplied by the destination.
214      *     </figcaption>
215      * </p>
216      * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
217      * <p>\(C_{out} = C_{src} + C_{dst} - C_{src} * C_{dst}\)</p>
218      */
219     SCREEN(14),
220 
221     /**
222      * {@usesMathJax}
223      *
224      * <p>
225      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_OVERLAY.png" />
226      *     <figcaption>
227      *         Multiplies or screens the source and destination depending on the
228      *         destination color.
229      *     </figcaption>
230      * </p>
231      * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
232      * <p>\(\begin{equation}
233      * C_{out} = \begin{cases} 2 * C_{src} * C_{dst} & 2 * C_{dst} \lt \alpha_{dst} \\
234      * \alpha_{src} * \alpha_{dst} - 2 (\alpha_{dst} - C_{src}) (\alpha_{src} - C_{dst}) &
235      * otherwise \end{cases}
236      * \end{equation}\)</p>
237      */
238     OVERLAY(15),
239 
240     /**
241      * {@usesMathJax}
242      *
243      * <p>
244      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_DARKEN.png" />
245      *     <figcaption>
246      *         Retains the smallest component of the source and
247      *         destination pixels.
248      *     </figcaption>
249      * </p>
250      * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
251      * <p>
252      *     \(C_{out} =
253      *     (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + min(C_{src}, C_{dst})\)
254      * </p>
255      */
256     DARKEN(16),
257 
258     /**
259      * {@usesMathJax}
260      *
261      * <p>
262      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_LIGHTEN.png" />
263      *     <figcaption>Retains the largest component of the source and
264      *     destination pixel.</figcaption>
265      * </p>
266      * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
267      * <p>
268      *     \(C_{out} =
269      *      (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + max(C_{src}, C_{dst})\)
270      * </p>
271      */
272     LIGHTEN(17),
273 
274     /**
275      * {@usesMathJax}
276      *
277      * <p>
278      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR_DODGE.png" />
279      *     <figcaption>Makes destination brighter to reflect source.</figcaption>
280      * </p>
281      * <p>
282      *     \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)
283      * </p>
284      * <p>
285      *      \begin{equation}
286      *      C_{out} =
287      *      \begin{cases}
288      *          C_{src} * (1 - \alpha_{dst}) & C_{dst} = 0 \\
289      *          C_{src} + \alpha_{dst}*(1 - \alpha_{src}) & C_{src} = \alpha_{src} \\
290      *          \alpha_{src} * min(\alpha_{dst}, C_{dst} * \alpha_{src}/(\alpha_{src} - C_{src}))
291      *              + C_{src} *(1 - \alpha_{dst} + \alpha_{dst}*(1 - \alpha_{src}) & otherwise
292      *      \end{cases}
293      *      \end{equation}
294      * </p>
295      */
296     COLOR_DODGE(18),
297 
298     /**
299      * {@usesMathJax}
300      *
301      * <p>
302      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR_BURN.png" />
303      *     <figcaption>Makes destination darker to reflect source.</figcaption>
304      * </p>
305      * <p>
306      *     \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)
307      * </p>
308      * <p>
309      *     \begin{equation}
310      *     C_{out} =
311      *     \begin{cases}
312      *         C_{dst} + C_{src}*(1 - \alpha_{dst}) & C_{dst} = \alpha_{dst} \\
313      *         \alpha_{dst}*(1 - \alpha_{src}) & C_{src} = 0 \\
314      *         \alpha_{src}*(\alpha_{dst} - min(\alpha_{dst}, (\alpha_{dst}
315      *         - C_{dst})*\alpha_{src}/C_{src}))
316      *         + C_{src} * (1 - \alpha_{dst}) + \alpha_{dst}*(1-\alpha_{src}) & otherwise
317      *     \end{cases}
318      *     \end{equation}
319      * </p>
320      */
321     COLOR_BURN(19),
322 
323     /**
324      * {@usesMathJax}
325      *
326      * <p>
327      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_HARD_LIGHT.png" />
328      *     <figcaption>Makes destination lighter or darker, depending on source.</figcaption>
329      * </p>
330      * <p>
331      *     \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)
332      * </p>
333      * <p>
334      *     \begin{equation}
335      *      C_{out} =
336      *      \begin{cases}
337      *           2*C_{src}*C_{dst} & C_{src}*(1-\alpha_{dst}) + C_{dst}*(1-\alpha_{src}) + 2*C_{src}
338      *              \leq \alpha_{src} \\
339      *           \alpha_{src}*\alpha_{dst}- 2*(\alpha_{dst} - C_{dst})*(\alpha_{src} - C_{src})
340      *              & otherwise
341      *      \end{cases}
342      *      \end{equation}
343      * </p>
344      */
345     HARD_LIGHT(20),
346 
347     /**
348      * {@usesMathJax}
349      *
350      * <p>
351      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_SOFT_LIGHT.png" />
352      *     <figcaption>Makes destination lighter or darker, depending on source.</figcaption>
353      * </p>
354      * <p>
355      *     Where
356      *       \begin{equation}
357      *       m =
358      *          \begin{cases}
359      *              C_{dst} / \alpha_{dst} & \alpha_{dst} \gt 0 \\
360      *              0 & otherwise
361      *          \end{cases}
362      *       \end{equation}
363      * </p>
364      * <p>
365      *       \begin{equation}
366      *       g =
367      *          \begin{cases}
368      *              (16 * m * m + 4 * m) * (m - 1) + 7 * m & 4 * C_{dst} \leq \alpha_{dst} \\
369      *              \sqrt m - m & otherwise
370      *          \end{cases}
371      *       \end{equation}
372      * </p>
373      * <p>
374      *       \begin{equation}
375      *       f =
376      *          \begin{cases}
377      *              C_{dst} * (\alpha_{src} + (2 * C_{src} - \alpha_{src}) * (1 - m))
378      *                  & 2 * C_{src} \leq \alpha_{src} \\
379      *              C_{dst} * \alpha_{src} + \alpha_{dst} * (2 * C_{src} - \alpha_{src}) * g
380      *                  & otherwise
381      *          \end{cases}
382      *       \end{equation}
383      * </p>
384      * <p>
385      *       \begin{equation}
386      *          \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}
387      *       \end{equation}
388      *       \begin{equation}
389      *          C_{out} = C_{src} / \alpha_{dst} + C_{dst} / \alpha_{src} + f
390      *       \end{equation}
391      * </p>
392      */
393     SOFT_LIGHT(21),
394 
395     /**
396      * {@usesMathJax}
397      *
398      * <p>
399      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_DIFFERENCE.png" />
400      *     <figcaption>Subtracts darker from lighter with higher contrast.</figcaption>
401      * </p>
402      * <p>
403      *     \begin{equation}
404      *          \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}
405      *     \end{equation}
406      * </p>
407      * <p>
408      *     \begin{equation}
409      *           C_{out} = C_{src} + C_{dst} - 2 * min(C_{src}
410      *                       * \alpha_{dst}, C_{dst} * \alpha_{src})
411      *     \end{equation}
412      * </p>
413      */
414     DIFFERENCE(22),
415 
416     /**
417      * {@usesMathJax}
418      *
419      * <p>
420      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_DIFFERENCE.png" />
421      *     <figcaption>Subtracts darker from lighter with lower contrast.</figcaption>
422      * </p>
423      * <p>
424      *     \begin{equation}
425      *          \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}
426      *     \end{equation}
427      * </p>
428      * <p>
429      *     \begin{equation}
430      *          C_{out} = C_{src} + C_{dst} - 2 * C_{src} * C_{dst}
431      *     \end{equation}
432      * </p>
433      */
434     EXCLUSION(23),
435 
436     /**
437      * {@usesMathJax}
438      *
439      * <p>
440      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_MODULATE.png" />
441      *     <figcaption>Multiplies the source and destination pixels.</figcaption>
442      * </p>
443      * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
444      * <p>\(C_{out} =
445      *      C_{src} * (1 - \alpha_{dst}) + C_{dst} * (1 - \alpha_{src}) + (C_{src} * C_{dst})\)
446      * </p>
447      */
448     MULTIPLY(24),
449 
450     /**
451      * {@usesMathJax}
452      *
453      * <p>
454      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_HUE.png" />
455      *     <figcaption>
456      *         Replaces hue of destination with hue of source, leaving saturation
457      *         and luminosity unchanged.
458      *     </figcaption>
459      * </p>
460      */
461     HUE(25),
462 
463     /**
464      * {@usesMathJax}
465      *
466      * <p>
467      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_SATURATION.png" />
468      *     <figcaption>
469      *          Replaces saturation of destination saturation hue of source, leaving hue and
470      *          luminosity unchanged.
471      *     </figcaption>
472      * </p>
473      */
474     SATURATION(26),
475 
476     /**
477      * {@usesMathJax}
478      *
479      * <p>
480      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR.png" />
481      *     <figcaption>
482      *          Replaces hue and saturation of destination with hue and saturation of source,
483      *          leaving luminosity unchanged.
484      *     </figcaption>
485      * </p>
486      */
487     COLOR(27),
488 
489     /**
490      * {@usesMathJax}
491      *
492      * <p>
493      *     <img src="{@docRoot}reference/android/images/graphics/blendmode_LUMINOSITY.png" />
494      *     <figcaption>
495      *          Replaces luminosity of destination with luminosity of source, leaving hue and
496      *          saturation unchanged.
497      *     </figcaption>
498      * </p>
499      */
500     LUMINOSITY(28);
501 
502     private static final BlendMode[] BLEND_MODES = values();
503 
504     /**
505      * @hide
506      */
fromValue(int value)507     public static @Nullable BlendMode fromValue(int value) {
508         for (BlendMode mode : BLEND_MODES) {
509             if (mode.mXfermode.porterDuffMode == value) {
510                 return mode;
511             }
512         }
513         return null;
514     }
515 
516     /**
517      * @hide
518      */
toValue(BlendMode mode)519     public static int toValue(BlendMode mode) {
520         return mode.getXfermode().porterDuffMode;
521     }
522 
523     /**
524      * @hide
525      */
blendModeToPorterDuffMode(@ullable BlendMode mode)526     public static @Nullable PorterDuff.Mode blendModeToPorterDuffMode(@Nullable BlendMode mode) {
527         if (mode != null) {
528             switch (mode) {
529                 case CLEAR:
530                     return PorterDuff.Mode.CLEAR;
531                 case SRC:
532                     return PorterDuff.Mode.SRC;
533                 case DST:
534                     return PorterDuff.Mode.DST;
535                 case SRC_OVER:
536                     return PorterDuff.Mode.SRC_OVER;
537                 case DST_OVER:
538                     return PorterDuff.Mode.DST_OVER;
539                 case SRC_IN:
540                     return PorterDuff.Mode.SRC_IN;
541                 case DST_IN:
542                     return PorterDuff.Mode.DST_IN;
543                 case SRC_OUT:
544                     return PorterDuff.Mode.SRC_OUT;
545                 case DST_OUT:
546                     return PorterDuff.Mode.DST_OUT;
547                 case SRC_ATOP:
548                     return PorterDuff.Mode.SRC_ATOP;
549                 case DST_ATOP:
550                     return PorterDuff.Mode.DST_ATOP;
551                 case XOR:
552                     return PorterDuff.Mode.XOR;
553                 case DARKEN:
554                     return PorterDuff.Mode.DARKEN;
555                 case LIGHTEN:
556                     return PorterDuff.Mode.LIGHTEN;
557                 // b/73224934 PorterDuff Multiply maps to Skia Modulate
558                 case MODULATE:
559                     return PorterDuff.Mode.MULTIPLY;
560                 case SCREEN:
561                     return PorterDuff.Mode.SCREEN;
562                 case PLUS:
563                     return PorterDuff.Mode.ADD;
564                 case OVERLAY:
565                     return PorterDuff.Mode.OVERLAY;
566                 default:
567                     return null;
568             }
569         } else {
570             return null;
571         }
572     }
573 
574     @NonNull
575     private final PorterDuffXfermode mXfermode;
576 
BlendMode(int mode)577     BlendMode(int mode) {
578         mXfermode = new PorterDuffXfermode();
579         mXfermode.porterDuffMode = mode;
580     }
581 
582     /**
583      * @hide
584      */
585     @NonNull
getXfermode()586     public PorterDuffXfermode getXfermode() {
587         return mXfermode;
588     }
589 }
590