/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * pika-layer-modes.c * Copyright (C) 2017 Michael Natterer * Øyvind Kolås * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include "../operations-types.h" #include "gegl/pika-babl.h" #include "pikaoperationlayermode.h" #include "pikaoperationlayermode-blend.h" #include "pika-layer-modes.h" typedef struct _PikaLayerModeInfo PikaLayerModeInfo; struct _PikaLayerModeInfo { PikaLayerMode layer_mode; const gchar *op_name; PikaLayerModeBlendFunc blend_function; PikaLayerModeFlags flags; PikaLayerModeContext context; PikaLayerCompositeMode paint_composite_mode; PikaLayerCompositeMode composite_mode; PikaLayerColorSpace composite_space; PikaLayerColorSpace blend_space; }; /* static variables */ static const PikaLayerModeInfo layer_mode_infos[] = { { PIKA_LAYER_MODE_NORMAL_LEGACY, .op_name = "pika:normal", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_TRIVIAL, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_DISSOLVE, .op_name = "pika:dissolve", .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_TRIVIAL, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_UNION }, { PIKA_LAYER_MODE_BEHIND_LEGACY, .op_name = "pika:behind", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_PAINT | PIKA_LAYER_MODE_CONTEXT_FILTER, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_MULTIPLY_LEGACY, .op_name = "pika:multiply-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_SCREEN_LEGACY, .op_name = "pika:screen-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_OVERLAY_LEGACY, .op_name = "pika:softlight-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_DIFFERENCE_LEGACY, .op_name = "pika:difference-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_ADDITION_LEGACY, .op_name = "pika:addition-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_SUBTRACT_LEGACY, .op_name = "pika:subtract-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_DARKEN_ONLY_LEGACY, .op_name = "pika:darken-only-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_LIGHTEN_ONLY_LEGACY, .op_name = "pika:lighten-only-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_HSV_HUE_LEGACY, .op_name = "pika:hsv-hue-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_HSV_SATURATION_LEGACY, .op_name = "pika:hsv-saturation-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_HSL_COLOR_LEGACY, .op_name = "pika:hsl-color-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_HSV_VALUE_LEGACY, .op_name = "pika:hsv-value-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_DIVIDE_LEGACY, .op_name = "pika:divide-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_DODGE_LEGACY, .op_name = "pika:dodge-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_BURN_LEGACY, .op_name = "pika:burn-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_HARDLIGHT_LEGACY, .op_name = "pika:hardlight-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_SOFTLIGHT_LEGACY, .op_name = "pika:softlight-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_GRAIN_EXTRACT_LEGACY, .op_name = "pika:grain-extract-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_GRAIN_MERGE_LEGACY, .op_name = "pika:grain-merge-legacy", .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_COLOR_ERASE_LEGACY, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_color_erase, .flags = PIKA_LAYER_MODE_FLAG_LEGACY | PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_SUBTRACTIVE, .context = PIKA_LAYER_MODE_CONTEXT_PAINT | PIKA_LAYER_MODE_CONTEXT_FILTER, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_OVERLAY, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_overlay, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_LCH_HUE, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_lch_hue, .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_LAB }, { PIKA_LAYER_MODE_LCH_CHROMA, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_lch_chroma, .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_LAB }, { PIKA_LAYER_MODE_LCH_COLOR, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_lch_color, .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_LAB }, { PIKA_LAYER_MODE_LCH_LIGHTNESS, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_lch_lightness, .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_LAB }, { PIKA_LAYER_MODE_NORMAL, .op_name = "pika:normal", .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_TRIVIAL, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR }, { PIKA_LAYER_MODE_BEHIND, .op_name = "pika:behind", .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_PAINT | PIKA_LAYER_MODE_CONTEXT_FILTER, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR }, { PIKA_LAYER_MODE_MULTIPLY, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_multiply, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR }, { PIKA_LAYER_MODE_SCREEN, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_screen, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_DIFFERENCE, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_difference, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_ADDITION, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_addition, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR }, { PIKA_LAYER_MODE_SUBTRACT, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_subtract, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR }, { PIKA_LAYER_MODE_DARKEN_ONLY, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_darken_only, .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR /* no blend_space: reuse composite space, no conversion thus fewer copies */ }, { PIKA_LAYER_MODE_LIGHTEN_ONLY, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_lighten_only, .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR /* no blend_space: reuse composite space, no conversion thus fewer copies */ }, { PIKA_LAYER_MODE_HSV_HUE, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_hsv_hue, .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_HSV_SATURATION, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_hsv_saturation, .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_HSL_COLOR, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_hsl_color, .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_HSV_VALUE, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_hsv_value, .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_DIVIDE, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_divide, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR }, { PIKA_LAYER_MODE_DODGE, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_dodge, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_BURN, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_burn, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_HARDLIGHT, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_hardlight, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_SOFTLIGHT, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_softlight, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_GRAIN_EXTRACT, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_grain_extract, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_GRAIN_MERGE, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_grain_merge, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_VIVID_LIGHT, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_vivid_light, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_PIN_LIGHT, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_pin_light, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_LINEAR_LIGHT, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_linear_light, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_HARD_MIX, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_hard_mix, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_EXCLUSION, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_exclusion, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_LINEAR_BURN, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_linear_burn, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_LUMA_DARKEN_ONLY, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_luma_darken_only, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_LUMA_LIGHTEN_ONLY, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_luma_lighten_only, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL }, { PIKA_LAYER_MODE_LUMINANCE, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_luminance, .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR }, { PIKA_LAYER_MODE_COLOR_ERASE, .op_name = "pika:layer-mode", .blend_function = pika_operation_layer_mode_blend_color_erase, .flags = PIKA_LAYER_MODE_FLAG_SUBTRACTIVE, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR, .blend_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR }, { PIKA_LAYER_MODE_ERASE, .op_name = "pika:erase", .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_SUBTRACTIVE | PIKA_LAYER_MODE_FLAG_ALPHA_ONLY | PIKA_LAYER_MODE_FLAG_TRIVIAL, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR }, { PIKA_LAYER_MODE_MERGE, .op_name = "pika:merge", .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_TRIVIAL, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR }, { PIKA_LAYER_MODE_SPLIT, .op_name = "pika:split", .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_SUBTRACTIVE | PIKA_LAYER_MODE_FLAG_ALPHA_ONLY | PIKA_LAYER_MODE_FLAG_TRIVIAL, .context = PIKA_LAYER_MODE_CONTEXT_ALL, .paint_composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP, .composite_mode = PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP }, { PIKA_LAYER_MODE_PASS_THROUGH, .op_name = "pika:pass-through", .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_TRIVIAL, .context = PIKA_LAYER_MODE_CONTEXT_GROUP, .composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR }, { PIKA_LAYER_MODE_REPLACE, .op_name = "pika:replace", .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_TRIVIAL, .context = PIKA_LAYER_MODE_CONTEXT_FILTER, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_space = PIKA_LAYER_COLOR_SPACE_RGB_LINEAR }, { PIKA_LAYER_MODE_ANTI_ERASE, .op_name = "pika:anti-erase", .flags = PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | PIKA_LAYER_MODE_FLAG_ALPHA_ONLY, .paint_composite_mode = PIKA_LAYER_COMPOSITE_UNION, .composite_mode = PIKA_LAYER_COMPOSITE_UNION } }; static const PikaLayerMode layer_mode_group_default[] = { PIKA_LAYER_MODE_PASS_THROUGH, PIKA_LAYER_MODE_SEPARATOR, PIKA_LAYER_MODE_REPLACE, PIKA_LAYER_MODE_SEPARATOR, PIKA_LAYER_MODE_NORMAL, PIKA_LAYER_MODE_DISSOLVE, PIKA_LAYER_MODE_BEHIND, PIKA_LAYER_MODE_COLOR_ERASE, PIKA_LAYER_MODE_ERASE, PIKA_LAYER_MODE_ANTI_ERASE, PIKA_LAYER_MODE_MERGE, PIKA_LAYER_MODE_SPLIT, PIKA_LAYER_MODE_SEPARATOR, PIKA_LAYER_MODE_LIGHTEN_ONLY, PIKA_LAYER_MODE_LUMA_LIGHTEN_ONLY, PIKA_LAYER_MODE_SCREEN, PIKA_LAYER_MODE_DODGE, PIKA_LAYER_MODE_ADDITION, PIKA_LAYER_MODE_SEPARATOR, PIKA_LAYER_MODE_DARKEN_ONLY, PIKA_LAYER_MODE_LUMA_DARKEN_ONLY, PIKA_LAYER_MODE_MULTIPLY, PIKA_LAYER_MODE_BURN, PIKA_LAYER_MODE_LINEAR_BURN, PIKA_LAYER_MODE_SEPARATOR, PIKA_LAYER_MODE_OVERLAY, PIKA_LAYER_MODE_SOFTLIGHT, PIKA_LAYER_MODE_HARDLIGHT, PIKA_LAYER_MODE_VIVID_LIGHT, PIKA_LAYER_MODE_PIN_LIGHT, PIKA_LAYER_MODE_LINEAR_LIGHT, PIKA_LAYER_MODE_HARD_MIX, PIKA_LAYER_MODE_SEPARATOR, PIKA_LAYER_MODE_DIFFERENCE, PIKA_LAYER_MODE_EXCLUSION, PIKA_LAYER_MODE_SUBTRACT, PIKA_LAYER_MODE_GRAIN_EXTRACT, PIKA_LAYER_MODE_GRAIN_MERGE, PIKA_LAYER_MODE_DIVIDE, PIKA_LAYER_MODE_SEPARATOR, PIKA_LAYER_MODE_HSV_HUE, PIKA_LAYER_MODE_HSV_SATURATION, PIKA_LAYER_MODE_HSL_COLOR, PIKA_LAYER_MODE_HSV_VALUE, PIKA_LAYER_MODE_SEPARATOR, PIKA_LAYER_MODE_LCH_HUE, PIKA_LAYER_MODE_LCH_CHROMA, PIKA_LAYER_MODE_LCH_COLOR, PIKA_LAYER_MODE_LCH_LIGHTNESS, PIKA_LAYER_MODE_LUMINANCE }; static const PikaLayerMode layer_mode_group_legacy[] = { PIKA_LAYER_MODE_NORMAL_LEGACY, PIKA_LAYER_MODE_DISSOLVE, PIKA_LAYER_MODE_BEHIND_LEGACY, PIKA_LAYER_MODE_COLOR_ERASE_LEGACY, PIKA_LAYER_MODE_SEPARATOR, PIKA_LAYER_MODE_LIGHTEN_ONLY_LEGACY, PIKA_LAYER_MODE_SCREEN_LEGACY, PIKA_LAYER_MODE_DODGE_LEGACY, PIKA_LAYER_MODE_ADDITION_LEGACY, PIKA_LAYER_MODE_SEPARATOR, PIKA_LAYER_MODE_DARKEN_ONLY_LEGACY, PIKA_LAYER_MODE_MULTIPLY_LEGACY, PIKA_LAYER_MODE_BURN_LEGACY, PIKA_LAYER_MODE_SEPARATOR, PIKA_LAYER_MODE_OVERLAY, PIKA_LAYER_MODE_SOFTLIGHT_LEGACY, PIKA_LAYER_MODE_HARDLIGHT_LEGACY, PIKA_LAYER_MODE_SEPARATOR, PIKA_LAYER_MODE_DIFFERENCE_LEGACY, PIKA_LAYER_MODE_SUBTRACT_LEGACY, PIKA_LAYER_MODE_GRAIN_EXTRACT_LEGACY, PIKA_LAYER_MODE_GRAIN_MERGE_LEGACY, PIKA_LAYER_MODE_DIVIDE_LEGACY, PIKA_LAYER_MODE_SEPARATOR, PIKA_LAYER_MODE_HSV_HUE_LEGACY, PIKA_LAYER_MODE_HSV_SATURATION_LEGACY, PIKA_LAYER_MODE_HSL_COLOR_LEGACY, PIKA_LAYER_MODE_HSV_VALUE_LEGACY }; static const PikaLayerMode layer_mode_groups[][2] = { { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_NORMAL, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_NORMAL_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_DISSOLVE, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_DISSOLVE }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_BEHIND, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_BEHIND_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_MULTIPLY, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_MULTIPLY_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_SCREEN, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_SCREEN_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_OVERLAY, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_DIFFERENCE, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_DIFFERENCE_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_ADDITION, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_ADDITION_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_SUBTRACT, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_SUBTRACT_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_DARKEN_ONLY, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_DARKEN_ONLY_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_LIGHTEN_ONLY, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_LIGHTEN_ONLY_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_HSV_HUE, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_HSV_HUE_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_HSV_SATURATION, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_HSV_SATURATION_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_HSL_COLOR, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_HSL_COLOR_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_HSV_VALUE, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_HSV_VALUE_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_DIVIDE, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_DIVIDE_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_DODGE, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_DODGE_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_BURN, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_BURN_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_HARDLIGHT, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_HARDLIGHT_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_SOFTLIGHT, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_SOFTLIGHT_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_GRAIN_EXTRACT, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_GRAIN_EXTRACT_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_GRAIN_MERGE, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_GRAIN_MERGE_LEGACY }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_COLOR_ERASE, [PIKA_LAYER_MODE_GROUP_LEGACY ] = PIKA_LAYER_MODE_COLOR_ERASE_LEGACY, }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_VIVID_LIGHT, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_PIN_LIGHT, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_LINEAR_LIGHT, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_HARD_MIX, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_EXCLUSION, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_LINEAR_BURN, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_LUMA_DARKEN_ONLY, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_LUMA_LIGHTEN_ONLY, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_LUMINANCE, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_ERASE, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_MERGE, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_SPLIT, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_PASS_THROUGH, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1, }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_REPLACE, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 }, { [PIKA_LAYER_MODE_GROUP_DEFAULT] = PIKA_LAYER_MODE_ANTI_ERASE, [PIKA_LAYER_MODE_GROUP_LEGACY ] = -1 } }; static GeglOperation *ops[G_N_ELEMENTS (layer_mode_infos)] = { 0 }; /* public functions */ void pika_layer_modes_init (void) { gint i; for (i = 0; i < G_N_ELEMENTS (layer_mode_infos); i++) { pika_assert ((PikaLayerMode) i == layer_mode_infos[i].layer_mode); } } void pika_layer_modes_exit (void) { gint i; for (i = 0; i < G_N_ELEMENTS (layer_mode_infos); i++) { if (ops[i]) { GeglNode *node; node = ops[i]->node; g_object_unref (node); ops[i] = NULL; } } } static const PikaLayerModeInfo * pika_layer_mode_info (PikaLayerMode mode) { g_return_val_if_fail (mode >= 0 && mode < G_N_ELEMENTS (layer_mode_infos), &layer_mode_infos[0]); return &layer_mode_infos[mode]; } gboolean pika_layer_mode_is_legacy (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return FALSE; return (info->flags & PIKA_LAYER_MODE_FLAG_LEGACY) != 0; } gboolean pika_layer_mode_is_blend_space_mutable (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return FALSE; return (info->flags & PIKA_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE) == 0; } gboolean pika_layer_mode_is_composite_space_mutable (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return FALSE; return (info->flags & PIKA_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE) == 0; } gboolean pika_layer_mode_is_composite_mode_mutable (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return FALSE; return (info->flags & PIKA_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE) == 0; } gboolean pika_layer_mode_is_subtractive (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return FALSE; return (info->flags & PIKA_LAYER_MODE_FLAG_SUBTRACTIVE) != 0; } gboolean pika_layer_mode_is_alpha_only (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return FALSE; return (info->flags & PIKA_LAYER_MODE_FLAG_ALPHA_ONLY) != 0; } gboolean pika_layer_mode_is_trivial (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return FALSE; return (info->flags & PIKA_LAYER_MODE_FLAG_TRIVIAL) != 0; } PikaLayerColorSpace pika_layer_mode_get_blend_space (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return PIKA_LAYER_COLOR_SPACE_RGB_LINEAR; return info->blend_space; } PikaLayerColorSpace pika_layer_mode_get_composite_space (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return PIKA_LAYER_COLOR_SPACE_RGB_LINEAR; return info->composite_space; } PikaLayerCompositeMode pika_layer_mode_get_composite_mode (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return PIKA_LAYER_COMPOSITE_UNION; return info->composite_mode; } PikaLayerCompositeMode pika_layer_mode_get_paint_composite_mode (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return PIKA_LAYER_COMPOSITE_UNION; return info->paint_composite_mode; } const gchar * pika_layer_mode_get_operation_name (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return "pika:layer-mode"; return info->op_name; } /** * pika_layer_mode_get_operation: * @mode: * * Returns: a #GeglOperation for @mode which may be reused and must not * be freed. */ GeglOperation * pika_layer_mode_get_operation (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); const gchar *op_name; op_name = pika_layer_mode_get_operation_name (mode); if (! info) info = layer_mode_infos; mode = info - layer_mode_infos; if (! ops[mode]) { GeglNode *node; GeglOperation *operation; node = gegl_node_new_child (NULL, "operation", op_name, NULL); operation = gegl_node_get_gegl_operation (node); ops[mode] = operation; if (PIKA_IS_OPERATION_LAYER_MODE (operation)) { PikaOperationLayerMode *layer_mode = PIKA_OPERATION_LAYER_MODE (operation); layer_mode->layer_mode = mode; layer_mode->function = PIKA_OPERATION_LAYER_MODE_GET_CLASS (operation)->process; layer_mode->blend_function = pika_layer_mode_get_blend_function (mode); layer_mode->blend_space = pika_layer_mode_get_blend_space (mode); layer_mode->composite_space = pika_layer_mode_get_composite_space (mode); layer_mode->composite_mode = pika_layer_mode_get_paint_composite_mode (mode); } } return ops[mode]; } PikaLayerModeFunc pika_layer_mode_get_function (PikaLayerMode mode) { GeglOperation *operation; operation = pika_layer_mode_get_operation (mode); return PIKA_OPERATION_LAYER_MODE_GET_CLASS (operation)->process; } PikaLayerModeBlendFunc pika_layer_mode_get_blend_function (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return NULL; return info->blend_function; } PikaLayerModeContext pika_layer_mode_get_context (PikaLayerMode mode) { const PikaLayerModeInfo *info = pika_layer_mode_info (mode); if (! info) return 0; return info->context; } PikaLayerMode * pika_layer_mode_get_context_array (PikaLayerMode mode, PikaLayerModeContext context, gint *n_modes) { PikaLayerModeGroup group; const PikaLayerMode *group_modes; gint n_group_modes; PikaLayerMode *array; gint i; group = pika_layer_mode_get_group (mode); group_modes = pika_layer_mode_get_group_array (group, &n_group_modes); array = g_new0 (PikaLayerMode, n_group_modes); *n_modes = 0; for (i = 0; i < n_group_modes; i++) { if (group_modes[i] != PIKA_LAYER_MODE_SEPARATOR && (pika_layer_mode_get_context (group_modes[i]) & context)) { array[*n_modes] = group_modes[i]; (*n_modes)++; } } return array; } static gboolean is_mode_in_array (const PikaLayerMode *modes, gint n_modes, PikaLayerMode mode) { gint i; for (i = 0; i < n_modes; i++) { if (modes[i] == mode) return TRUE; } return FALSE; } PikaLayerModeGroup pika_layer_mode_get_group (PikaLayerMode mode) { if (is_mode_in_array (layer_mode_group_default, G_N_ELEMENTS (layer_mode_group_default), mode)) { return PIKA_LAYER_MODE_GROUP_DEFAULT; } else if (is_mode_in_array (layer_mode_group_legacy, G_N_ELEMENTS (layer_mode_group_legacy), mode)) { return PIKA_LAYER_MODE_GROUP_LEGACY; } return PIKA_LAYER_MODE_GROUP_DEFAULT; } const PikaLayerMode * pika_layer_mode_get_group_array (PikaLayerModeGroup group, gint *n_modes) { g_return_val_if_fail (n_modes != NULL, NULL); switch (group) { case PIKA_LAYER_MODE_GROUP_DEFAULT: *n_modes = G_N_ELEMENTS (layer_mode_group_default); return layer_mode_group_default; case PIKA_LAYER_MODE_GROUP_LEGACY: *n_modes = G_N_ELEMENTS (layer_mode_group_legacy); return layer_mode_group_legacy; default: g_return_val_if_reached (NULL); } } gboolean pika_layer_mode_get_for_group (PikaLayerMode old_mode, PikaLayerModeGroup new_group, PikaLayerMode *new_mode) { gint i; g_return_val_if_fail (new_mode != NULL, FALSE); for (i = 0; i < G_N_ELEMENTS (layer_mode_groups); i++) { if (is_mode_in_array (layer_mode_groups[i], 2, old_mode)) { *new_mode = layer_mode_groups[i][new_group]; if (*new_mode != -1) return TRUE; return FALSE; } } *new_mode = -1; return FALSE; } const Babl * pika_layer_mode_get_format (PikaLayerMode mode, PikaLayerColorSpace blend_space, PikaLayerColorSpace composite_space, PikaLayerCompositeMode composite_mode, const Babl *preferred_format) { PikaLayerCompositeRegion composite_region; /* for now, all modes perform i/o in the composite space. */ (void) mode; (void) blend_space; if (composite_space == PIKA_LAYER_COLOR_SPACE_AUTO) composite_space = pika_layer_mode_get_composite_space (mode); if (composite_mode == PIKA_LAYER_COMPOSITE_AUTO) composite_mode = pika_layer_mode_get_composite_mode (mode); composite_region = pika_layer_mode_get_included_region (mode, composite_mode); if (pika_layer_mode_is_alpha_only (mode)) { if (composite_region != PIKA_LAYER_COMPOSITE_REGION_UNION) { /* alpha-only layer modes don't combine colors in non-union composite * modes, hence we can disregard the composite space. */ composite_space = PIKA_LAYER_COLOR_SPACE_AUTO; } } else if (pika_layer_mode_is_trivial (mode)) { if (! (composite_region & PIKA_LAYER_COMPOSITE_REGION_DESTINATION)) { /* trivial layer modes don't combine colors when only the source * region is included, hence we can disregard the composite space. */ composite_space = PIKA_LAYER_COLOR_SPACE_AUTO; } } switch (composite_space) { case PIKA_LAYER_COLOR_SPACE_AUTO: /* compositing is color-space agnostic. return a format that has a fast * conversion path to/from the preferred format. */ if (! preferred_format || pika_babl_format_get_trc (preferred_format) == PIKA_TRC_LINEAR) return babl_format_with_space ("RGBA float", preferred_format); else return babl_format_with_space ("R'G'B'A float", preferred_format); case PIKA_LAYER_COLOR_SPACE_RGB_LINEAR: return babl_format_with_space ("RGBA float", preferred_format); case PIKA_LAYER_COLOR_SPACE_RGB_PERCEPTUAL: return babl_format_with_space ("R'G'B'A float", preferred_format); case PIKA_LAYER_COLOR_SPACE_LAB: return babl_format_with_space ("CIE Lab alpha float", preferred_format); } g_return_val_if_reached (babl_format_with_space ("RGBA float", preferred_format)); } PikaLayerCompositeRegion pika_layer_mode_get_included_region (PikaLayerMode mode, PikaLayerCompositeMode composite_mode) { if (composite_mode == PIKA_LAYER_COMPOSITE_AUTO) composite_mode = pika_layer_mode_get_composite_mode (mode); switch (composite_mode) { case PIKA_LAYER_COMPOSITE_UNION: return PIKA_LAYER_COMPOSITE_REGION_UNION; case PIKA_LAYER_COMPOSITE_CLIP_TO_BACKDROP: return PIKA_LAYER_COMPOSITE_REGION_DESTINATION; case PIKA_LAYER_COMPOSITE_CLIP_TO_LAYER: return PIKA_LAYER_COMPOSITE_REGION_SOURCE; case PIKA_LAYER_COMPOSITE_INTERSECTION: return PIKA_LAYER_COMPOSITE_REGION_INTERSECTION; default: g_return_val_if_reached (PIKA_LAYER_COMPOSITE_REGION_INTERSECTION); } }