BlendMode.kt

/*
 * Copyright 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 androidx.compose.ui.graphics

/**
 * Algorithms to use when painting on the canvas.
 *
 * When drawing a shape or image onto a canvas, different algorithms can be
 * used to blend the pixels. The different values of [BlendMode] specify
 * different such algorithms.
 *
 * Each algorithm has two inputs, the _source_, which is the image being drawn,
 * and the _destination_, which is the image into which the source image is
 * being composited. The destination is often thought of as the _background_.
 * The source and destination both have four color channels, the red, green,
 * blue, and alpha channels. These are typically represented as numbers in the
 * range 0.0 to 1.0. The output of the algorithm also has these same four
 * channels, with values computed from the source and destination.
 *
 * The horizontal and vertical bars in these images show the red, green, and
 * blue channels with varying opacity levels, then all three color channels
 * together with those same varying opacity levels, then all three color
 * channels set to zero with those varying opacity levels, then two bars showing
 * a red/green/blue repeating gradient, the first with full opacity and the
 * second with partial opacity, and finally a bar with the three color channels
 * set to zero but the opacity varying in a repeating gradient.
 *
 * ## Application to the [Canvas] API
 *
 * When using [Canvas.saveLayer] and [Canvas.restore], the blend mode of the
 * [Paint] given to the [Canvas.saveLayer] will be applied when
 * [Canvas.restore] is called. Each call to [Canvas.saveLayer] introduces a new
 * layer onto which shapes and images are painted; when [Canvas.restore] is
 * called, that layer is then composited onto the parent layer, with the source
 * being the most-recently-drawn shapes and images, and the destination being
 * the parent layer. (For the first [Canvas.saveLayer] call, the parent layer
 * is the canvas itself.)
 *
 * See also:
 *
 *  * [Paint.blendMode], which uses [BlendMode] to define the compositing
 *    strategy.
 */
enum class BlendMode {

    /**
     * Drop both the source and destination images, leaving nothing.
     */
    Clear,

    /**
     * Drop the destination image, only paint the source image.
     *
     * Conceptually, the destination is first cleared, then the source image is
     * painted.
     */
    Src,

    /**
     * Drop the source image, only paint the destination image.
     *
     * Conceptually, the source image is discarded, leaving the destination
     * untouched.
     */
    Dst,

    /**
     * Composite the source image over the destination image.
     *
     * This is the default value. It represents the most intuitive case, where
     * shapes are painted on top of what is below, with transparent areas showing
     * the destination layer.
     */
    SrcOver,

    /**
     * Composite the source image under the destination image.
     *
     * This is the opposite of [SrcOver].
     *
     * This is useful when the source image should have been painted before the
     * destination image, but could not be.
     */
    DstOver,

    /**
     * Show the source image, but only where the two images overlap. The
     * destination image is not rendered, it is treated merely as a mask. The
     * color channels of the destination are ignored, only the opacity has an
     * effect.
     *
     * To show the destination image instead, consider [DstIn].
     *
     * To reverse the semantic of the mask (only showing the source where the
     * destination is absent, rather than where it is present), consider
     * [SrcOut].
     */
    SrcIn,

    /**
     * Show the destination image, but only where the two images overlap. The
     * source image is not rendered, it is treated merely as a mask. The color
     * channels of the source are ignored, only the opacity has an effect.
     *
     * To show the source image instead, consider [SrcIn].
     *
     * To reverse the semantic of the mask (only showing the source where the
     * destination is present, rather than where it is absent), consider [DstOut].
     */
    DstIn,

    /**
     * Show the source image, but only where the two images do not overlap. The
     * destination image is not rendered, it is treated merely as a mask. The color
     * channels of the destination are ignored, only the opacity has an effect.
     *
     * To show the destination image instead, consider [DstOut].
     *
     * To reverse the semantic of the mask (only showing the source where the
     * destination is present, rather than where it is absent), consider [SrcIn].
     *
     * This corresponds to the "Source out Destination" Porter-Duff operator.
     */
    SrcOut,

    /**
     * Show the destination image, but only where the two images do not overlap. The
     * source image is not rendered, it is treated merely as a mask. The color
     * channels of the source are ignored, only the opacity has an effect.
     *
     * To show the source image instead, consider [SrcOut].
     *
     * To reverse the semantic of the mask (only showing the destination where the
     * source is present, rather than where it is absent), consider [DstIn].
     *
     * This corresponds to the "Destination out Source" Porter-Duff operator.
     */
    DstOut,

    /**
     * Composite the source image over the destination image, but only where it
     * overlaps the destination.
     *
     * This is essentially the [SrcOver] operator, but with the output's opacity
     * channel being set to that of the destination image instead of being a
     * combination of both image's opacity channels.
     *
     * For a variant with the destination on top instead of the source, see
     * [DstAtop].
     */
    SrcAtop,

    /**
     * Composite the destination image over the source image, but only where it
     * overlaps the source.
     *
     * This is essentially the [DstOver] operator, but with the output's opacity
     * channel being set to that of the source image instead of being a
     * combination of both image's opacity channels.
     *
     * For a variant with the source on top instead of the destination, see
     * [SrcAtop].
     */
    DstAtop,

    /**
     * Apply a bitwise `xor` operator to the source and destination images. This
     * leaves transparency where they would overlap.
     */
    Xor,

    /**
     * Sum the components of the source and destination images.
     *
     * Transparency in a pixel of one of the images reduces the contribution of
     * that image to the corresponding output pixel, as if the color of that
     * pixel in that image was darker.
     *
     */
    Plus,

    /**
     * Multiply the color components of the source and destination images.
     *
     * This can only result in the same or darker colors (multiplying by white,
     * 1.0, results in no change; multiplying by black, 0.0, results in black).
     *
     * When compositing two opaque images, this has similar effect to overlapping
     * two transparencies on a projector.
     *
     * For a variant that also multiplies the alpha channel, consider [Multiply].
     *
     * See also:
     *
     *  * [Screen], which does a similar computation but inverted.
     *  * [Overlay], which combines [Modulate] and [Screen] to favor the
     *    destination image.
     *  * [Hardlight], which combines [Modulate] and [Screen] to favor the
     *    source image.
     */
    Modulate,

    /**
     * Multiply the inverse of the components of the source and destination
     * images, and inverse the result.
     *
     * Inverting the components means that a fully saturated channel (opaque
     * white) is treated as the value 0.0, and values normally treated as 0.0
     * (black, transparent) are treated as 1.0.
     *
     * This is essentially the same as [Modulate] blend mode, but with the values
     * of the colors inverted before the multiplication and the result being
     * inverted back before rendering.
     *
     * This can only result in the same or lighter colors (multiplying by black,
     * 1.0, results in no change; multiplying by white, 0.0, results in white).
     * Similarly, in the alpha channel, it can only result in more opaque colors.
     *
     * This has similar effect to two projectors displaying their images on the
     * same screen simultaneously.
     *
     * See also:
     *
     *  * [Modulate], which does a similar computation but without inverting the
     *    values.
     *  * [Overlay], which combines [Modulate] and [Screen] to favor the
     *    destination image.
     *  * [Hardlight], which combines [Modulate] and [Screen] to favor the
     *    source image.
     */
    Screen, // The last coeff mode.

    /**
     * Multiply the components of the source and destination images after
     * adjusting them to favor the destination.
     *
     * Specifically, if the destination value is smaller, this multiplies it with
     * the source value, whereas is the source value is smaller, it multiplies
     * the inverse of the source value with the inverse of the destination value,
     * then inverts the result.
     *
     * Inverting the components means that a fully saturated channel (opaque
     * white) is treated as the value 0.0, and values normally treated as 0.0
     * (black, transparent) are treated as 1.0.
     *
     * See also:
     *
     *  * [Modulate], which always multiplies the values.
     *  * [Screen], which always multiplies the inverses of the values.
     *  * [Hardlight], which is similar to [Overlay] but favors the source image
     *    instead of the destination image.
     */
    Overlay,

    /**
     * Composite the source and destination image by choosing the lowest value
     * from each color channel.
     *
     * The opacity of the output image is computed in the same way as for
     * [SrcOver].
     */
    Darken,

    /**
     * Composite the source and destination image by choosing the highest value
     * from each color channel.
     *
     * The opacity of the output image is computed in the same way as for
     * [SrcOver].
     */
    Lighten,

    /**
     * Divide the destination by the inverse of the source.
     *
     * Inverting the components means that a fully saturated channel (opaque
     * white) is treated as the value 0.0, and values normally treated as 0.0
     * (black, transparent) are treated as 1.0.
     *
     * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
     */
    ColorDodge,

    /**
     * Divide the inverse of the destination by the the source, and inverse the result.
     *
     * Inverting the components means that a fully saturated channel (opaque
     * white) is treated as the value 0.0, and values normally treated as 0.0
     * (black, transparent) are treated as 1.0.
     *
     * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
     */
    ColorBurn,

    /**
     * Multiply the components of the source and destination images after
     * adjusting them to favor the source.
     *
     * Specifically, if the source value is smaller, this multiplies it with the
     * destination value, whereas is the destination value is smaller, it
     * multiplies the inverse of the destination value with the inverse of the
     * source value, then inverts the result.
     *
     * Inverting the components means that a fully saturated channel (opaque
     * white) is treated as the value 0.0, and values normally treated as 0.0
     * (black, transparent) are treated as 1.0.
     *
     * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
     *
     * See also:
     *
     *  * [Modulate], which always multiplies the values.
     *  * [Screen], which always multiplies the inverses of the values.
     *  * [Overlay], which is similar to [Hardlight] but favors the destination
     *    image instead of the source image.
     */
    Hardlight,

    /**
     * Use [ColorDodge] for source values below 0.5 and [ColorBurn] for source
     * values above 0.5.
     *
     * This results in a similar but softer effect than [Overlay].
     *
     * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
     *
     * See also:
     *
     *  * [Color], which is a more subtle tinting effect.
     */
    Softlight,

    /**
     * Subtract the smaller value from the bigger value for each channel.
     *
     * Compositing black has no effect; compositing white inverts the colors of
     * the other image.
     *
     * The opacity of the output image is computed in the same way as for
     * [SrcOver].
     *
     * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
     *
     * The effect is similar to [Exclusion] but harsher.
     */
    Difference,

    /**
     * Subtract double the product of the two images from the sum of the two
     * images.
     *
     * Compositing black has no effect; compositing white inverts the colors of
     * the other image.
     *
     * The opacity of the output image is computed in the same way as for
     * [SrcOver].
     *
     * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
     *
     * The effect is similar to [Difference] but softer.
     */
    Exclusion,

    /**
     * Multiply the components of the source and destination images, including
     * the alpha channel.
     *
     * This can only result in the same or darker colors (multiplying by white,
     * 1.0, results in no change; multiplying by black, 0.0, results in black).
     *
     * Since the alpha channel is also multiplied, a fully-transparent pixel
     * (opacity 0.0) in one image results in a fully transparent pixel in the
     * output. This is similar to [DstIn], but with the colors combined.
     *
     * For a variant that multiplies the colors but does not multiply the alpha
     * channel, consider [Modulate].
     *
     * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
     */
    Multiply, // The last separable mode.

    /**
     * Take the hue of the source image, and the saturation and luminosity of the
     * destination image.
     *
     * The effect is to tint the destination image with the source image.
     *
     * The opacity of the output image is computed in the same way as for
     * [SrcOver]. Regions that are entirely transparent in the source image take
     * their hue from the destination.
     *
     * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
     */
    Hue,

    /**
     * Take the saturation of the source image, and the hue and luminosity of the
     * destination image.
     *
     * The opacity of the output image is computed in the same way as for
     * [SrcOver]. Regions that are entirely transparent in the source image take
     * their saturation from the destination.
     *
     * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
     *
     * See also:
     *
     *  * [Color], which also applies the hue of the source image.
     *  * [Luminosity], which applies the luminosity of the source image to the
     *    destination.
     */
    Saturation,

    /**
     * Take the hue and saturation of the source image, and the luminosity of the
     * destination image.
     *
     * The effect is to tint the destination image with the source image.
     *
     * The opacity of the output image is computed in the same way as for
     * [SrcOver]. Regions that are entirely transparent in the source image take
     * their hue and saturation from the destination.
     *
     * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
     *
     * See also:
     *
     *  * [Hue], which is a similar but weaker effect.
     *  * [Softlight], which is a similar tinting effect but also tints white.
     *  * [Saturation], which only applies the saturation of the source image.
     */
    Color,

    /**
     * Take the luminosity of the source image, and the hue and saturation of the
     * destination image.
     *
     * The opacity of the output image is computed in the same way as for
     * [SrcOver]. Regions that are entirely transparent in the source image take
     * their luminosity from the destination.
     *
     * **NOTE** This [BlendMode] can only be used on Android API level 29 and above
     *
     * See also:
     *
     *  * [Saturation], which applies the saturation of the source image to the
     *    destination.
     */
    Luminosity;
}

/**
 * Capability query to determine if the particular platform supports the [BlendMode]. Not
 * all platforms support all blend mode algorithms, however, [BlendMode.SrcOver] is guaranteed
 * to be supported as it is the default drawing algorithm. If a [BlendMode] that is not supported
 * is used, the default of SrcOver is consumed instead.
 */
expect fun BlendMode.isSupported(): Boolean