1 /*
2 * Copyright 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 androidx.compose.ui.graphics
18
19 import androidx.compose.runtime.Immutable
20
21 /**
22 * Algorithms to use when painting on the canvas.
23 *
24 * When drawing a shape or image onto a canvas, different algorithms can be used to blend the
25 * pixels. The different values of [BlendMode] specify different such algorithms.
26 *
27 * Each algorithm has two inputs, the _source_, which is the image being drawn, and the
28 * _destination_, which is the image into which the source image is being composited. The
29 * destination is often thought of as the _background_. The source and destination both have four
30 * color channels, the red, green, blue, and alpha channels. These are typically represented as
31 * numbers in the range 0.0 to 1.0. The output of the algorithm also has these same four channels,
32 * with values computed from the source and destination.
33 *
34 * ## Application to the [Canvas] API
35 *
36 * When using [Canvas.saveLayer] and [Canvas.restore], the blend mode of the [Paint] given to the
37 * [Canvas.saveLayer] will be applied when [Canvas.restore] is called. Each call to
38 * [Canvas.saveLayer] introduces a new layer onto which shapes and images are painted; when
39 * [Canvas.restore] is called, that layer is then composited onto the parent layer, with the source
40 * being the most-recently-drawn shapes and images, and the destination being the parent layer. (For
41 * the first [Canvas.saveLayer] call, the parent layer is the canvas itself.)
42 *
43 * See also:
44 * * [Paint.blendMode], which uses [BlendMode] to define the compositing strategy.
45 */
46 @Immutable
47 @kotlin.jvm.JvmInline
48 value class BlendMode internal constructor(@Suppress("unused") private val value: Int) {
49
50 companion object {
51
52 /** Drop both the source and destination images, leaving nothing. */
53 val Clear = BlendMode(0)
54
55 /**
56 * Drop the destination image, only paint the source image.
57 *
58 * Conceptually, the destination is first cleared, then the source image is painted.
59 */
60 val Src = BlendMode(1)
61
62 /**
63 * Drop the source image, only paint the destination image.
64 *
65 * Conceptually, the source image is discarded, leaving the destination untouched.
66 */
67 val Dst = BlendMode(2)
68
69 /**
70 * Composite the source image over the destination image.
71 *
72 * This is the default value. It represents the most intuitive case, where shapes are
73 * painted on top of what is below, with transparent areas showing the destination layer.
74 */
75 val SrcOver = BlendMode(3)
76
77 /**
78 * Composite the source image under the destination image.
79 *
80 * This is the opposite of [SrcOver].
81 *
82 * This is useful when the source image should have been painted before the destination
83 * image, but could not be.
84 */
85 val DstOver = BlendMode(4)
86
87 /**
88 * Show the source image, but only where the two images overlap. The destination image is
89 * not rendered, it is treated merely as a mask. The color channels of the destination are
90 * ignored, only the opacity has an effect.
91 *
92 * To show the destination image instead, consider [DstIn].
93 *
94 * To reverse the semantic of the mask (only showing the source where the destination is
95 * absent, rather than where it is present), consider [SrcOut].
96 */
97 val SrcIn = BlendMode(5)
98
99 /**
100 * Show the destination image, but only where the two images overlap. The source image is
101 * not rendered, it is treated merely as a mask. The color channels of the source are
102 * ignored, only the opacity has an effect.
103 *
104 * To show the source image instead, consider [SrcIn].
105 *
106 * To reverse the semantic of the mask (only showing the source where the destination is
107 * present, rather than where it is absent), consider [DstOut].
108 */
109 val DstIn = BlendMode(6)
110
111 /**
112 * Show the source image, but only where the two images do not overlap. The destination
113 * image is not rendered, it is treated merely as a mask. The color channels of the
114 * destination are ignored, only the opacity has an effect.
115 *
116 * To show the destination image instead, consider [DstOut].
117 *
118 * To reverse the semantic of the mask (only showing the source where the destination is
119 * present, rather than where it is absent), consider [SrcIn].
120 *
121 * This corresponds to the "Source out Destination" Porter-Duff operator.
122 */
123 val SrcOut = BlendMode(7)
124
125 /**
126 * Show the destination image, but only where the two images do not overlap. The source
127 * image is not rendered, it is treated merely as a mask. The color channels of the source
128 * are ignored, only the opacity has an effect.
129 *
130 * To show the source image instead, consider [SrcOut].
131 *
132 * To reverse the semantic of the mask (only showing the destination where the source is
133 * present, rather than where it is absent), consider [DstIn].
134 *
135 * This corresponds to the "Destination out Source" Porter-Duff operator.
136 */
137 val DstOut = BlendMode(8)
138
139 /**
140 * Composite the source image over the destination image, but only where it overlaps the
141 * destination.
142 *
143 * This is essentially the [SrcOver] operator, but with the output's opacity channel being
144 * set to that of the destination image instead of being a combination of both image's
145 * opacity channels.
146 *
147 * For a variant with the destination on top instead of the source, see [DstAtop].
148 */
149 val SrcAtop = BlendMode(9)
150
151 /**
152 * Composite the destination image over the source image, but only where it overlaps the
153 * source.
154 *
155 * This is essentially the [DstOver] operator, but with the output's opacity channel being
156 * set to that of the source image instead of being a combination of both image's opacity
157 * channels.
158 *
159 * For a variant with the source on top instead of the destination, see [SrcAtop].
160 */
161 val DstAtop = BlendMode(10)
162
163 /**
164 * Apply a bitwise `xor` operator to the source and destination images. This leaves
165 * transparency where they would overlap.
166 */
167 val Xor = BlendMode(11)
168
169 /**
170 * Sum the components of the source and destination images.
171 *
172 * Transparency in a pixel of one of the images reduces the contribution of that image to
173 * the corresponding output pixel, as if the color of that pixel in that image was darker.
174 */
175 val Plus = BlendMode(12)
176
177 /**
178 * Multiply the color components of the source and destination images.
179 *
180 * This can only result in the same or darker colors (multiplying by white, 1.0, results in
181 * no change; multiplying by black, 0.0, results in black).
182 *
183 * When compositing two opaque images, this has similar effect to overlapping two
184 * transparencies on a projector.
185 *
186 * For a variant that also multiplies the alpha channel, consider [Multiply].
187 *
188 * See also:
189 * * [Screen], which does a similar computation but inverted.
190 * * [Overlay], which combines [Modulate] and [Screen] to favor the destination image.
191 * * [Hardlight], which combines [Modulate] and [Screen] to favor the source image.
192 */
193 val Modulate = BlendMode(13)
194
195 /**
196 * Multiply the inverse of the components of the source and destination images, and inverse
197 * the result.
198 *
199 * Inverting the components means that a fully saturated channel (opaque white) is treated
200 * as the value 0.0, and values normally treated as 0.0 (black, transparent) are treated as
201 * 1.0.
202 *
203 * This is essentially the same as [Modulate] blend mode, but with the values of the colors
204 * inverted before the multiplication and the result being inverted back before rendering.
205 *
206 * This can only result in the same or lighter colors (multiplying by black, 1.0, results in
207 * no change; multiplying by white, 0.0, results in white). Similarly, in the alpha channel,
208 * it can only result in more opaque colors.
209 *
210 * This has similar effect to two projectors displaying their images on the same screen
211 * simultaneously.
212 *
213 * See also:
214 * * [Modulate], which does a similar computation but without inverting the values.
215 * * [Overlay], which combines [Modulate] and [Screen] to favor the destination image.
216 * * [Hardlight], which combines [Modulate] and [Screen] to favor the source image.
217 */
218 val Screen = BlendMode(14) // The last coeff mode.
219
220 /**
221 * Multiply the components of the source and destination images after adjusting them to
222 * favor the destination.
223 *
224 * Specifically, if the destination value is smaller, this multiplies it with the source
225 * value, whereas is the source value is smaller, it multiplies the inverse of the source
226 * value with the inverse of the destination value, then inverts the result.
227 *
228 * Inverting the components means that a fully saturated channel (opaque white) is treated
229 * as the value 0.0, and values normally treated as 0.0 (black, transparent) are treated as
230 * 1.0.
231 *
232 * See also:
233 * * [Modulate], which always multiplies the values.
234 * * [Screen], which always multiplies the inverses of the values.
235 * * [Hardlight], which is similar to [Overlay] but favors the source image instead of the
236 * destination image.
237 */
238 val Overlay = BlendMode(15)
239
240 /**
241 * Composite the source and destination image by choosing the lowest value from each color
242 * channel.
243 *
244 * The opacity of the output image is computed in the same way as for [SrcOver].
245 */
246 val Darken = BlendMode(16)
247
248 /**
249 * Composite the source and destination image by choosing the highest value from each color
250 * channel.
251 *
252 * The opacity of the output image is computed in the same way as for [SrcOver].
253 */
254 val Lighten = BlendMode(17)
255
256 /**
257 * Divide the destination by the inverse of the source.
258 *
259 * Inverting the components means that a fully saturated channel (opaque white) is treated
260 * as the value 0.0, and values normally treated as 0.0 (black, transparent) are treated as
261 * 1.0.
262 *
263 * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
264 */
265 val ColorDodge = BlendMode(18)
266
267 /**
268 * Divide the inverse of the destination by the source, and inverse the result.
269 *
270 * Inverting the components means that a fully saturated channel (opaque white) is treated
271 * as the value 0.0, and values normally treated as 0.0 (black, transparent) are treated as
272 * 1.0.
273 *
274 * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
275 */
276 val ColorBurn = BlendMode(19)
277
278 /**
279 * Multiply the components of the source and destination images after adjusting them to
280 * favor the source.
281 *
282 * Specifically, if the source value is smaller, this multiplies it with the destination
283 * value, whereas is the destination value is smaller, it multiplies the inverse of the
284 * destination value with the inverse of the source value, then inverts the result.
285 *
286 * Inverting the components means that a fully saturated channel (opaque white) is treated
287 * as the value 0.0, and values normally treated as 0.0 (black, transparent) are treated as
288 * 1.0.
289 *
290 * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
291 *
292 * See also:
293 * * [Modulate], which always multiplies the values.
294 * * [Screen], which always multiplies the inverses of the values.
295 * * [Overlay], which is similar to [Hardlight] but favors the destination image instead of
296 * the source image.
297 */
298 val Hardlight = BlendMode(20)
299
300 /**
301 * Use [ColorDodge] for source values below 0.5 and [ColorBurn] for source values above 0.5.
302 *
303 * This results in a similar but softer effect than [Overlay].
304 *
305 * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
306 *
307 * See also:
308 * * [BlendMode.Color], which is a more subtle tinting effect.
309 */
310 val Softlight = BlendMode(21)
311
312 /**
313 * Subtract the smaller value from the bigger value for each channel.
314 *
315 * Compositing black has no effect; compositing white inverts the colors of the other image.
316 *
317 * The opacity of the output image is computed in the same way as for [SrcOver].
318 *
319 * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
320 *
321 * The effect is similar to [Exclusion] but harsher.
322 */
323 val Difference = BlendMode(22)
324
325 /**
326 * Subtract double the product of the two images from the sum of the two images.
327 *
328 * Compositing black has no effect; compositing white inverts the colors of the other image.
329 *
330 * The opacity of the output image is computed in the same way as for [SrcOver].
331 *
332 * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
333 *
334 * The effect is similar to [Difference] but softer.
335 */
336 val Exclusion = BlendMode(23)
337
338 /**
339 * Multiply the components of the source and destination images, including the alpha
340 * channel.
341 *
342 * This can only result in the same or darker colors (multiplying by white, 1.0, results in
343 * no change; multiplying by black, 0.0, results in black).
344 *
345 * Since the alpha channel is also multiplied, a fully-transparent pixel (opacity 0.0) in
346 * one image results in a fully transparent pixel in the output. This is similar to [DstIn],
347 * but with the colors combined.
348 *
349 * For a variant that multiplies the colors but does not multiply the alpha channel,
350 * consider [Modulate].
351 *
352 * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
353 */
354 val Multiply = BlendMode(24) // The last separable mode.
355
356 /**
357 * Take the hue of the source image, and the saturation and luminosity of the destination
358 * image.
359 *
360 * The effect is to tint the destination image with the source image.
361 *
362 * The opacity of the output image is computed in the same way as for [SrcOver]. Regions
363 * that are entirely transparent in the source image take their hue from the destination.
364 *
365 * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
366 */
367 val Hue = BlendMode(25)
368
369 /**
370 * Take the saturation of the source image, and the hue and luminosity of the destination
371 * image.
372 *
373 * The opacity of the output image is computed in the same way as for [SrcOver]. Regions
374 * that are entirely transparent in the source image take their saturation from the
375 * destination.
376 *
377 * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
378 *
379 * See also:
380 * * [BlendMode.Color], which also applies the hue of the source image.
381 * * [Luminosity], which applies the luminosity of the source image to the destination.
382 */
383 val Saturation = BlendMode(26)
384
385 /**
386 * Take the hue and saturation of the source image, and the luminosity of the destination
387 * image.
388 *
389 * The effect is to tint the destination image with the source image.
390 *
391 * The opacity of the output image is computed in the same way as for [SrcOver]. Regions
392 * that are entirely transparent in the source image take their hue and saturation from the
393 * destination.
394 *
395 * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
396 *
397 * See also:
398 * * [Hue], which is a similar but weaker effect.
399 * * [Softlight], which is a similar tinting effect but also tints white.
400 * * [Saturation], which only applies the saturation of the source image.
401 */
402 val Color = BlendMode(27)
403
404 /**
405 * Take the luminosity of the source image, and the hue and saturation of the destination
406 * image.
407 *
408 * The opacity of the output image is computed in the same way as for [SrcOver]. Regions
409 * that are entirely transparent in the source image take their luminosity from the
410 * destination.
411 *
412 * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
413 *
414 * See also:
415 * * [Saturation], which applies the saturation of the source image to the destination.
416 */
417 val Luminosity = BlendMode(28)
418 }
419
toStringnull420 override fun toString() =
421 when (this) {
422 Clear -> "Clear"
423 Src -> "Src"
424 Dst -> "Dst"
425 SrcOver -> "SrcOver"
426 DstOver -> "DstOver"
427 SrcIn -> "SrcIn"
428 DstIn -> "DstIn"
429 SrcOut -> "SrcOut"
430 DstOut -> "DstOut"
431 SrcAtop -> "SrcAtop"
432 DstAtop -> "DstAtop"
433 Xor -> "Xor"
434 Plus -> "Plus"
435 Modulate -> "Modulate"
436 Screen -> "Screen"
437 Overlay -> "Overlay"
438 Darken -> "Darken"
439 Lighten -> "Lighten"
440 ColorDodge -> "ColorDodge"
441 ColorBurn -> "ColorBurn"
442 Hardlight -> "HardLight"
443 Softlight -> "Softlight"
444 Difference -> "Difference"
445 Exclusion -> "Exclusion"
446 Multiply -> "Multiply"
447 Hue -> "Hue"
448 Saturation -> "Saturation"
449 Color -> "Color"
450 Luminosity -> "Luminosity"
451 else -> "Unknown" // Should not get here since we have an internal constructor
452 }
453 }
454
455 /**
456 * Capability query to determine if the particular platform supports the [BlendMode]. Not all
457 * platforms support all blend mode algorithms, however, [BlendMode.SrcOver] is guaranteed to be
458 * supported as it is the default drawing algorithm. If a [BlendMode] that is not supported is used,
459 * the default of SrcOver is consumed instead.
460 */
isSupportednull461 expect fun BlendMode.isSupported(): Boolean
462