/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef MOZILLA_GFX_FILTERS_H_
#define MOZILLA_GFX_FILTERS_H_

#include "Types.h"
#include "mozilla/RefCounted.h"

#include "Point.h"
#include "Matrix.h"

namespace mozilla {
namespace gfx {

class SourceSurface;

enum FilterBackend {
  FILTER_BACKEND_SOFTWARE = 0,
  FILTER_BACKEND_WEBGL,
  FILTER_BACKEND_RECORDING,
  FILTER_BACKEND_CAPTURE
};

enum TransformFilterAtts {
  ATT_TRANSFORM_MATRIX = 0,  // Matrix
  ATT_TRANSFORM_FILTER       // Filter
};

enum TransformFilterInputs { IN_TRANSFORM_IN = 0 };

enum BlendFilterAtts {
  ATT_BLEND_BLENDMODE = 0  // uint32_t
};

enum BlendMode {
  BLEND_MODE_MULTIPLY = 0,
  BLEND_MODE_SCREEN,
  BLEND_MODE_DARKEN,
  BLEND_MODE_LIGHTEN,
  BLEND_MODE_OVERLAY,
  BLEND_MODE_COLOR_DODGE,
  BLEND_MODE_COLOR_BURN,
  BLEND_MODE_HARD_LIGHT,
  BLEND_MODE_SOFT_LIGHT,
  BLEND_MODE_DIFFERENCE,
  BLEND_MODE_EXCLUSION,
  BLEND_MODE_HUE,
  BLEND_MODE_SATURATION,
  BLEND_MODE_COLOR,
  BLEND_MODE_LUMINOSITY
};

enum BlendFilterInputs { IN_BLEND_IN = 0, IN_BLEND_IN2 };

enum MorphologyFilterAtts {
  ATT_MORPHOLOGY_RADII = 0,  // IntSize
  ATT_MORPHOLOGY_OPERATOR    // MorphologyOperator
};

enum MorphologyOperator {
  MORPHOLOGY_OPERATOR_ERODE = 0,
  MORPHOLOGY_OPERATOR_DILATE
};

enum MorphologyFilterInputs { IN_MORPHOLOGY_IN = 0 };

enum AlphaMode { ALPHA_MODE_PREMULTIPLIED = 0, ALPHA_MODE_STRAIGHT };

enum ColorMatrixFilterAtts {
  ATT_COLOR_MATRIX_MATRIX = 0,  // Matrix5x4
  ATT_COLOR_MATRIX_ALPHA_MODE   // AlphaMode
};

enum ColorMatrixFilterInputs { IN_COLOR_MATRIX_IN = 0 };

enum FloodFilterAtts {
  ATT_FLOOD_COLOR = 0  // Color
};

enum FloodFilterInputs { IN_FLOOD_IN = 0 };

enum TileFilterAtts {
  ATT_TILE_SOURCE_RECT = 0  // IntRect
};

enum TileFilterInputs { IN_TILE_IN = 0 };

enum TransferAtts {
  ATT_TRANSFER_DISABLE_R = 0,  // bool
  ATT_TRANSFER_DISABLE_G,      // bool
  ATT_TRANSFER_DISABLE_B,      // bool
  ATT_TRANSFER_DISABLE_A       // bool
};

enum TransferInputs { IN_TRANSFER_IN = 0 };

enum TableTransferAtts {
  ATT_TABLE_TRANSFER_DISABLE_R = ATT_TRANSFER_DISABLE_R,
  ATT_TABLE_TRANSFER_DISABLE_G = ATT_TRANSFER_DISABLE_G,
  ATT_TABLE_TRANSFER_DISABLE_B = ATT_TRANSFER_DISABLE_B,
  ATT_TABLE_TRANSFER_DISABLE_A = ATT_TRANSFER_DISABLE_A,
  ATT_TABLE_TRANSFER_TABLE_R,  // Float[]
  ATT_TABLE_TRANSFER_TABLE_G,  // Float[]
  ATT_TABLE_TRANSFER_TABLE_B,  // Float[]
  ATT_TABLE_TRANSFER_TABLE_A   // Float[]
};

enum TableTransferInputs { IN_TABLE_TRANSFER_IN = IN_TRANSFER_IN };

enum DiscreteTransferAtts {
  ATT_DISCRETE_TRANSFER_DISABLE_R = ATT_TRANSFER_DISABLE_R,
  ATT_DISCRETE_TRANSFER_DISABLE_G = ATT_TRANSFER_DISABLE_G,
  ATT_DISCRETE_TRANSFER_DISABLE_B = ATT_TRANSFER_DISABLE_B,
  ATT_DISCRETE_TRANSFER_DISABLE_A = ATT_TRANSFER_DISABLE_A,
  ATT_DISCRETE_TRANSFER_TABLE_R,  // Float[]
  ATT_DISCRETE_TRANSFER_TABLE_G,  // Float[]
  ATT_DISCRETE_TRANSFER_TABLE_B,  // Float[]
  ATT_DISCRETE_TRANSFER_TABLE_A   // Float[]
};

enum DiscreteTransferInputs { IN_DISCRETE_TRANSFER_IN = IN_TRANSFER_IN };

enum LinearTransferAtts {
  ATT_LINEAR_TRANSFER_DISABLE_R = ATT_TRANSFER_DISABLE_R,
  ATT_LINEAR_TRANSFER_DISABLE_G = ATT_TRANSFER_DISABLE_G,
  ATT_LINEAR_TRANSFER_DISABLE_B = ATT_TRANSFER_DISABLE_B,
  ATT_LINEAR_TRANSFER_DISABLE_A = ATT_TRANSFER_DISABLE_A,
  ATT_LINEAR_TRANSFER_SLOPE_R,      // Float
  ATT_LINEAR_TRANSFER_SLOPE_G,      // Float
  ATT_LINEAR_TRANSFER_SLOPE_B,      // Float
  ATT_LINEAR_TRANSFER_SLOPE_A,      // Float
  ATT_LINEAR_TRANSFER_INTERCEPT_R,  // Float
  ATT_LINEAR_TRANSFER_INTERCEPT_G,  // Float
  ATT_LINEAR_TRANSFER_INTERCEPT_B,  // Float
  ATT_LINEAR_TRANSFER_INTERCEPT_A   // Float
};

enum LinearTransferInputs { IN_LINEAR_TRANSFER_IN = IN_TRANSFER_IN };

enum GammaTransferAtts {
  ATT_GAMMA_TRANSFER_DISABLE_R = ATT_TRANSFER_DISABLE_R,
  ATT_GAMMA_TRANSFER_DISABLE_G = ATT_TRANSFER_DISABLE_G,
  ATT_GAMMA_TRANSFER_DISABLE_B = ATT_TRANSFER_DISABLE_B,
  ATT_GAMMA_TRANSFER_DISABLE_A = ATT_TRANSFER_DISABLE_A,
  ATT_GAMMA_TRANSFER_AMPLITUDE_R,  // Float
  ATT_GAMMA_TRANSFER_AMPLITUDE_G,  // Float
  ATT_GAMMA_TRANSFER_AMPLITUDE_B,  // Float
  ATT_GAMMA_TRANSFER_AMPLITUDE_A,  // Float
  ATT_GAMMA_TRANSFER_EXPONENT_R,   // Float
  ATT_GAMMA_TRANSFER_EXPONENT_G,   // Float
  ATT_GAMMA_TRANSFER_EXPONENT_B,   // Float
  ATT_GAMMA_TRANSFER_EXPONENT_A,   // Float
  ATT_GAMMA_TRANSFER_OFFSET_R,     // Float
  ATT_GAMMA_TRANSFER_OFFSET_G,     // Float
  ATT_GAMMA_TRANSFER_OFFSET_B,     // Float
  ATT_GAMMA_TRANSFER_OFFSET_A      // Float
};

enum GammaTransferInputs { IN_GAMMA_TRANSFER_IN = IN_TRANSFER_IN };

enum ConvolveMatrixAtts {
  ATT_CONVOLVE_MATRIX_KERNEL_SIZE = 0,     // IntSize
  ATT_CONVOLVE_MATRIX_KERNEL_MATRIX,       // Float[]
  ATT_CONVOLVE_MATRIX_DIVISOR,             // Float
  ATT_CONVOLVE_MATRIX_BIAS,                // Float
  ATT_CONVOLVE_MATRIX_TARGET,              // IntPoint
  ATT_CONVOLVE_MATRIX_RENDER_RECT,         // IntRect
  ATT_CONVOLVE_MATRIX_EDGE_MODE,           // ConvolveMatrixEdgeMode
  ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH,  // Size
  ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA,      // bool
};

enum ConvolveMatrixEdgeMode {
  EDGE_MODE_DUPLICATE = 0,
  EDGE_MODE_WRAP,
  EDGE_MODE_NONE
};

enum ConvolveMatrixInputs { IN_CONVOLVE_MATRIX_IN = 0 };

enum DisplacementMapAtts {
  ATT_DISPLACEMENT_MAP_SCALE = 0,  // Float
  ATT_DISPLACEMENT_MAP_X_CHANNEL,  // ColorChannel
  ATT_DISPLACEMENT_MAP_Y_CHANNEL   // ColorChannel
};

enum ColorChannel {
  COLOR_CHANNEL_R = 0,
  COLOR_CHANNEL_G,
  COLOR_CHANNEL_B,
  COLOR_CHANNEL_A,
  COLOR_CHANNEL_MAX = COLOR_CHANNEL_A
};

enum DisplacementMapInputs {
  IN_DISPLACEMENT_MAP_IN = 0,
  IN_DISPLACEMENT_MAP_IN2
};

enum TurbulenceAtts {
  ATT_TURBULENCE_BASE_FREQUENCY = 0,  // Size
  ATT_TURBULENCE_NUM_OCTAVES,         // uint32_t
  ATT_TURBULENCE_SEED,                // uint32_t
  ATT_TURBULENCE_STITCHABLE,          // bool
  ATT_TURBULENCE_TYPE,                // TurbulenceType
  ATT_TURBULENCE_RECT                 // IntRect
};

enum TurbulenceType {
  TURBULENCE_TYPE_TURBULENCE = 0,
  TURBULENCE_TYPE_FRACTAL_NOISE
};

enum ArithmeticCombineAtts {
  ATT_ARITHMETIC_COMBINE_COEFFICIENTS = 0  // Float[4]
};

enum ArithmeticCombineInputs {
  IN_ARITHMETIC_COMBINE_IN = 0,
  IN_ARITHMETIC_COMBINE_IN2
};

enum CompositeAtts {
  ATT_COMPOSITE_OPERATOR = 0  // CompositeOperator
};

enum CompositeOperator {
  COMPOSITE_OPERATOR_OVER = 0,
  COMPOSITE_OPERATOR_IN,
  COMPOSITE_OPERATOR_OUT,
  COMPOSITE_OPERATOR_ATOP,
  COMPOSITE_OPERATOR_XOR,
  COMPOSITE_OPERATOR_LIGHTER
};

enum CompositeInputs {
  // arbitrary number of inputs
  IN_COMPOSITE_IN_START = 0
};

enum GaussianBlurAtts {
  ATT_GAUSSIAN_BLUR_STD_DEVIATION = 0  // Float
};

enum GaussianBlurInputs { IN_GAUSSIAN_BLUR_IN = 0 };

enum DirectionalBlurAtts {
  ATT_DIRECTIONAL_BLUR_STD_DEVIATION = 0,  // Float
  ATT_DIRECTIONAL_BLUR_DIRECTION           // BlurDirection
};

enum BlurDirection { BLUR_DIRECTION_X = 0, BLUR_DIRECTION_Y };

enum DirectionalBlurInputs { IN_DIRECTIONAL_BLUR_IN = 0 };

enum LightingAtts {
  ATT_POINT_LIGHT_POSITION = 0,  // Point3D

  ATT_SPOT_LIGHT_POSITION,             // Point3D
  ATT_SPOT_LIGHT_POINTS_AT,            // Point3D
  ATT_SPOT_LIGHT_FOCUS,                // Float
  ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE,  // Float

  ATT_DISTANT_LIGHT_AZIMUTH,    // Float
  ATT_DISTANT_LIGHT_ELEVATION,  // Float

  ATT_LIGHTING_COLOR,               // Color
  ATT_LIGHTING_SURFACE_SCALE,       // Float
  ATT_LIGHTING_KERNEL_UNIT_LENGTH,  // Size
  ATT_LIGHTING_RENDER_RECT,         // IntRect

  ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT,  // Float

  ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT,  // Float
  ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT   // Float
};

enum LightingInputs { IN_LIGHTING_IN = 0 };

enum PointDiffuseAtts {
  ATT_POINT_DIFFUSE_POSITION = ATT_POINT_LIGHT_POSITION,
  ATT_POINT_DIFFUSE_COLOR = ATT_LIGHTING_COLOR,
  ATT_POINT_DIFFUSE_SURFACE_SCALE = ATT_LIGHTING_SURFACE_SCALE,
  ATT_POINT_DIFFUSE_KERNEL_UNIT_LENGTH = ATT_LIGHTING_KERNEL_UNIT_LENGTH,
  ATT_POINT_DIFFUSE_DIFFUSE_CONSTANT = ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT
};

enum PointDiffuseInputs { IN_POINT_DIFFUSE_IN = IN_LIGHTING_IN };

enum SpotDiffuseAtts {
  ATT_SPOT_DIFFUSE_POSITION = ATT_SPOT_LIGHT_POSITION,
  ATT_SPOT_DIFFUSE_POINTS_AT = ATT_SPOT_LIGHT_POINTS_AT,
  ATT_SPOT_DIFFUSE_FOCUS = ATT_SPOT_LIGHT_FOCUS,
  ATT_SPOT_DIFFUSE_LIMITING_CONE_ANGLE = ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE,
  ATT_SPOT_DIFFUSE_COLOR = ATT_LIGHTING_COLOR,
  ATT_SPOT_DIFFUSE_SURFACE_SCALE = ATT_LIGHTING_SURFACE_SCALE,
  ATT_SPOT_DIFFUSE_KERNEL_UNIT_LENGTH = ATT_LIGHTING_KERNEL_UNIT_LENGTH,
  ATT_SPOT_DIFFUSE_DIFFUSE_CONSTANT = ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT
};

enum SpotDiffuseInputs { IN_SPOT_DIFFUSE_IN = IN_LIGHTING_IN };

enum DistantDiffuseAtts {
  ATT_DISTANT_DIFFUSE_AZIMUTH = ATT_DISTANT_LIGHT_AZIMUTH,
  ATT_DISTANT_DIFFUSE_ELEVATION = ATT_DISTANT_LIGHT_ELEVATION,
  ATT_DISTANT_DIFFUSE_COLOR = ATT_LIGHTING_COLOR,
  ATT_DISTANT_DIFFUSE_SURFACE_SCALE = ATT_LIGHTING_SURFACE_SCALE,
  ATT_DISTANT_DIFFUSE_KERNEL_UNIT_LENGTH = ATT_LIGHTING_KERNEL_UNIT_LENGTH,
  ATT_DISTANT_DIFFUSE_DIFFUSE_CONSTANT = ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT
};

enum DistantDiffuseInputs { IN_DISTANT_DIFFUSE_IN = IN_LIGHTING_IN };

enum PointSpecularAtts {
  ATT_POINT_SPECULAR_POSITION = ATT_POINT_LIGHT_POSITION,
  ATT_POINT_SPECULAR_COLOR = ATT_LIGHTING_COLOR,
  ATT_POINT_SPECULAR_SURFACE_SCALE = ATT_LIGHTING_SURFACE_SCALE,
  ATT_POINT_SPECULAR_KERNEL_UNIT_LENGTH = ATT_LIGHTING_KERNEL_UNIT_LENGTH,
  ATT_POINT_SPECULAR_SPECULAR_CONSTANT =
      ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT,
  ATT_POINT_SPECULAR_SPECULAR_EXPONENT = ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT
};

enum PointSpecularInputs { IN_POINT_SPECULAR_IN = IN_LIGHTING_IN };

enum SpotSpecularAtts {
  ATT_SPOT_SPECULAR_POSITION = ATT_SPOT_LIGHT_POSITION,
  ATT_SPOT_SPECULAR_POINTS_AT = ATT_SPOT_LIGHT_POINTS_AT,
  ATT_SPOT_SPECULAR_FOCUS = ATT_SPOT_LIGHT_FOCUS,
  ATT_SPOT_SPECULAR_LIMITING_CONE_ANGLE = ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE,
  ATT_SPOT_SPECULAR_COLOR = ATT_LIGHTING_COLOR,
  ATT_SPOT_SPECULAR_SURFACE_SCALE = ATT_LIGHTING_SURFACE_SCALE,
  ATT_SPOT_SPECULAR_KERNEL_UNIT_LENGTH = ATT_LIGHTING_KERNEL_UNIT_LENGTH,
  ATT_SPOT_SPECULAR_SPECULAR_CONSTANT = ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT,
  ATT_SPOT_SPECULAR_SPECULAR_EXPONENT = ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT
};

enum SpotSpecularInputs { IN_SPOT_SPECULAR_IN = IN_LIGHTING_IN };

enum DistantSpecularAtts {
  ATT_DISTANT_SPECULAR_AZIMUTH = ATT_DISTANT_LIGHT_AZIMUTH,
  ATT_DISTANT_SPECULAR_ELEVATION = ATT_DISTANT_LIGHT_ELEVATION,
  ATT_DISTANT_SPECULAR_COLOR = ATT_LIGHTING_COLOR,
  ATT_DISTANT_SPECULAR_SURFACE_SCALE = ATT_LIGHTING_SURFACE_SCALE,
  ATT_DISTANT_SPECULAR_KERNEL_UNIT_LENGTH = ATT_LIGHTING_KERNEL_UNIT_LENGTH,
  ATT_DISTANT_SPECULAR_SPECULAR_CONSTANT =
      ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT,
  ATT_DISTANT_SPECULAR_SPECULAR_EXPONENT =
      ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT
};

enum DistantSpecularInputs { IN_DISTANT_SPECULAR_IN = IN_LIGHTING_IN };

enum CropAtts {
  ATT_CROP_RECT = 0  // Rect
};

enum CropInputs { IN_CROP_IN = 0 };

enum PremultiplyInputs { IN_PREMULTIPLY_IN = 0 };

enum UnpremultiplyInputs { IN_UNPREMULTIPLY_IN = 0 };

enum OpacityAtts { ATT_OPACITY_VALUE = 0 };

enum OpacityInputs { IN_OPACITY_IN = 0 };

class FilterNode : public external::AtomicRefCounted<FilterNode> {
 public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNode)
  virtual ~FilterNode() = default;

  virtual FilterBackend GetBackendType() = 0;

  virtual void SetInput(uint32_t aIndex, SourceSurface* aSurface) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetInput(uint32_t aIndex, FilterNode* aFilter) {
    MOZ_CRASH("GFX: FilterNode");
  }

  virtual void SetAttribute(uint32_t aIndex, bool) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetAttribute(uint32_t aIndex, uint32_t) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetAttribute(uint32_t aIndex, Float) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetAttribute(uint32_t aIndex, const Size&) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetAttribute(uint32_t aIndex, const IntSize&) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetAttribute(uint32_t aIndex, const IntPoint&) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetAttribute(uint32_t aIndex, const Rect&) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetAttribute(uint32_t aIndex, const IntRect&) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetAttribute(uint32_t aIndex, const Point&) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetAttribute(uint32_t aIndex, const Matrix&) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetAttribute(uint32_t aIndex, const Matrix5x4&) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetAttribute(uint32_t aIndex, const Point3D&) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetAttribute(uint32_t aIndex, const DeviceColor&) {
    MOZ_CRASH("GFX: FilterNode");
  }
  virtual void SetAttribute(uint32_t aIndex, const Float* aFloat,
                            uint32_t aSize) {
    MOZ_CRASH("GFX: FilterNode");
  }

  /** Maps a rectangle in filter space back to a rectangle in the space of
   * aSourceNode's first input. aSourceNode should not have an input
   * assigned when calling this function. */
  virtual IntRect MapRectToSource(const IntRect& aRect, const IntRect& aMax,
                                  FilterNode* aSourceNode) {
    return aMax;
  }

 protected:
  friend class Factory;

  FilterNode() = default;
};

}  // namespace gfx
}  // namespace mozilla

#endif
