// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System;
using System.Collections.Generic;
using System.Numerics;
namespace SixLabors.ImageSharp.Drawing.Processing.Backends {
///
/// Identifies the flush-time role carried by a .
///
public enum CompositionCommandKind : byte
{
///
/// A fill-path command.
///
FillLayer = 0,
///
/// Starts an isolated compositing layer.
///
BeginLayer = 1,
///
/// Ends the most recently opened layer.
///
EndLayer = 2
}
///
/// One normalized fill-path or layer-based composition command queued for backend execution.
///
///
/// This type carries fill-path commands plus inline layer boundaries.
///
public readonly struct CompositionCommand
{
private readonly IPath? sourcePath;
private readonly Brush? brush;
private readonly DrawingOptions? drawingOptions;
private readonly GraphicsOptions? layerGraphicsOptions;
private readonly IReadOnlyList? clipPaths;
private CompositionCommand(
CompositionCommandKind kind,
IPath? sourcePath,
Brush? brush,
DrawingOptions? drawingOptions,
GraphicsOptions? layerGraphicsOptions,
in RasterizerOptions rasterizerOptions,
Rectangle targetBounds,
Rectangle layerBounds,
Point destinationOffset,
IReadOnlyList? clipPaths,
bool isInsideLayer)
{
this.Kind = kind;
this.sourcePath = sourcePath;
this.brush = brush;
this.drawingOptions = drawingOptions;
this.layerGraphicsOptions = layerGraphicsOptions;
this.RasterizerOptions = rasterizerOptions;
this.TargetBounds = targetBounds;
this.LayerBounds = layerBounds;
this.DestinationOffset = destinationOffset;
this.clipPaths = clipPaths;
this.IsInsideLayer = isInsideLayer;
}
///
/// Gets the command kind.
///
public CompositionCommandKind Kind { get; }
///
/// Gets the absolute bounds of the logical target for this command.
///
public Rectangle TargetBounds { get; }
///
/// Gets the absolute bounds of the layer opened by this command.
///
///
/// Only meaningful for and
/// .
///
public Rectangle LayerBounds { get; }
///
/// Gets the brush used during composition.
///
public Brush Brush => this.brush ?? throw new InvalidOperationException("Layer commands do not carry a brush.");
///
/// Gets the drawing options carried by the command.
///
public DrawingOptions DrawingOptions => this.drawingOptions ?? throw new InvalidOperationException("Layer commands do not carry drawing options.");
///
/// Gets graphics options used for composition or layer compositing.
///
public GraphicsOptions GraphicsOptions => this.drawingOptions?.GraphicsOptions ?? this.layerGraphicsOptions!;
///
/// Gets rasterizer options used to generate coverage.
///
public RasterizerOptions RasterizerOptions { get; }
///
/// Gets the absolute destination offset where the local coverage should be composited.
///
public Point DestinationOffset { get; }
///
/// Gets the source path carried by the command.
///
public IPath SourcePath => this.sourcePath ?? throw new InvalidOperationException("Layer commands do not carry path geometry.");
///
/// Gets the command transform.
///
public Matrix4x4 Transform => this.drawingOptions?.Transform ?? Matrix4x4.Identity;
///
/// Gets the clip paths carried by the command.
///
public IReadOnlyList? ClipPaths => this.clipPaths;
///
/// Gets the shape options carried by the command.
///
public ShapeOptions ShapeOptions => this.drawingOptions?.ShapeOptions ?? throw new InvalidOperationException("Layer commands do not carry shape options.");
///
/// Gets a value indicating whether the command was recorded inside a layer.
///
public bool IsInsideLayer { get; }
///
/// Creates a fill-path composition command.
///
/// Path in target-local coordinates.
/// Brush used during composition.
/// Drawing options (graphics, shape, transform) used during composition.
/// Rasterizer options used to generate coverage.
/// The absolute bounds of the logical target for this command.
/// Absolute destination offset where coverage is composited.
/// Optional clip paths supplied with the command.
/// True if the command was recorded inside a layer.
/// The composition command.
public static CompositionCommand Create(
IPath path,
Brush brush,
DrawingOptions drawingOptions,
in RasterizerOptions rasterizerOptions,
Rectangle targetBounds,
Point destinationOffset,
IReadOnlyList? clipPaths,
bool isInsideLayer)
=> new(
CompositionCommandKind.FillLayer,
path,
brush,
drawingOptions,
null,
in rasterizerOptions,
targetBounds,
default,
destinationOffset,
clipPaths,
isInsideLayer);
///
/// Creates a begin-layer composition command. is false on the
/// BeginLayer marker itself; the flag is only meaningful for fills/strokes that follow it.
///
/// The absolute bounds of the layer.
/// The compositing options used when the layer closes.
/// The begin-layer command.
public static CompositionCommand CreateBeginLayer(Rectangle layerBounds, GraphicsOptions graphicsOptions)
=> new(
CompositionCommandKind.BeginLayer,
null,
null,
null,
graphicsOptions,
default,
layerBounds,
layerBounds,
default,
null,
false);
///
/// Creates an end-layer composition command. is false on the
/// EndLayer marker itself; the flag is only meaningful for fills/strokes that preceded it.
///
/// The absolute bounds of the layer being closed.
/// The compositing options used by the layer.
/// The end-layer command.
public static CompositionCommand CreateEndLayer(Rectangle layerBounds, GraphicsOptions graphicsOptions)
=> new(
CompositionCommandKind.EndLayer,
null,
null,
null,
graphicsOptions,
default,
layerBounds,
layerBounds,
default,
null,
false);
}
}