#!/usr/bin/perl

use strict;
use warnings;
use Cairo;

use constant
{
	LINE_WIDTH => 13,
};

sub spline_path
{
	my ($cr) = @_;

	$cr->save;
	{
		$cr->translate (-106.0988385, -235.84433);
		$cr->move_to (49.517857, 235.84433);
		$cr->curve_to (86.544809, 175.18401,
		               130.19603, 301.40165,
		               162.67982, 240.42946);
	}
	$cr->restore;
}

sub source_path
{
	my ($cr) = @_;
	spline_path ($cr);
	$cr->set_line_width (1);
	$cr->stroke;
}

sub stroke
{
	my ($cr) = @_;
	spline_path ($cr);
	$cr->set_line_width (LINE_WIDTH);
	$cr->stroke;
}

sub scale_both_set_line_width_stroke
{
	my ($cr) = @_;
	$cr->scale (0.5, 0.5);
	spline_path ($cr);
	$cr->set_line_width (LINE_WIDTH);
	$cr->stroke;
}

sub scale_both_set_line_width_double_stroke
{
	my ($cr) = @_;
	$cr->scale (0.5, 0.5);
	spline_path ($cr);
	$cr->set_line_width (2 * LINE_WIDTH);
	$cr->stroke;
}

sub save_scale_path_restore_set_line_width_stroke
{
	my ($cr) = @_;
	$cr->save;
	{
		$cr->scale (0.5, 1.0);
		spline_path ($cr);
	}
	$cr->restore;

	$cr->set_line_width (LINE_WIDTH);
	$cr->stroke;
}

# XXX: Ouch. It looks like there's an API bug in the implemented semantics for
# cairo_set_line_width. I believe the following function
# (set_line_width_scale_path_stroke_BUGGY) should result in a figure identical
# to the version above it (save_scale_path_restore_set_line_width_stroke), but
# it's currently giving the same result as the one beloe
# (scale_path_set_line_width_stroke).
sub set_line_width_scale_path_stroke_BUGGY
{
	my ($cr) = @_;
	$cr->set_line_width (LINE_WIDTH);
	$cr->scale (0.5, 1.0);
	spline_path ($cr);
	$cr->stroke;
}

sub scale_path_set_line_width_stroke
{
	my ($cr) = @_;
	$cr->scale (0.5, 1.0);
	$cr->set_line_width (LINE_WIDTH);
	spline_path ($cr);
	$cr->stroke;
}

{
	my @pipelines = (
		\&source_path,
		\&stroke,
		\&scale_both_set_line_width_stroke,
		\&scale_both_set_line_width_double_stroke,
		\&save_scale_path_restore_set_line_width_stroke,
		\&scale_path_set_line_width_stroke,
	);
	my $width = 140;
	my $height = 68.833 * scalar @pipelines;

	my $surface = Cairo::ImageSurface->create ('argb32', $width, $height);
	my $cr = Cairo::Context->create ($surface);

	foreach (0 .. $#pipelines) {
		$cr->save;
		{
			$cr->translate ($width/2, ($_+0.5)*($height/scalar @pipelines));
			$pipelines[$_]->($cr);
		}
		$cr->restore;
		if ($cr->status ne 'success') {
			warn "Cairo is unhappy after pipeline #$_: " . $cr->status . "\n";
			exit 1;
		}
	}

	$surface->write_to_png ('spline-pipeline.png');
}