Blob Blame Raw
using System;
using System.Collections.Generic;

namespace Assistance {
	public class Canvas {
		public static readonly int initialSize = 100;
		public static readonly double incrementScale = 1.2;
	
		private int offsetX = -initialSize/2;
		private int offsetY = -initialSize/2;
		private Cairo.ImageSurface surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, initialSize, initialSize);

		public void draw(Cairo.Context context) {
			context.Save();
			context.Translate(offsetX, offsetY);
			context.SetSource(surface);
			context.Paint();
			context.Restore();
		}

		public void expand(Rectangle rect) {
			int l = offsetX;
			int t = offsetY;
			int r = l + surface.Width;
			int b = t + surface.Height;
			
			int rl = (int)Math.Floor(rect.x0);
			int rt = (int)Math.Floor(rect.y0);
			int rr = Math.Max(rl, (int)Math.Ceiling(rect.x1));
			int rb = Math.Max(rt, (int)Math.Ceiling(rect.y1));
		    
		    int incX = (int)Math.Ceiling(surface.Width*incrementScale);
		    int incY = (int)Math.Ceiling(surface.Height*incrementScale);

		    if (rl < l) l = rl - incX;
		    if (rt < t) t = rt - incY;
		    if (rr > r) r = rr + incX;
		    if (rb > b) b = rb + incY;
		    
		    int w = r - l;
		    int h = b - t;
		    if (l != offsetX || t != offsetY || w != surface.Width || h != surface.Height) {
				Cairo.ImageSurface newSurface = new Cairo.ImageSurface(Cairo.Format.ARGB32, w, h);
		    	Cairo.Context context = new Cairo.Context(newSurface);
		    	context.Translate(offsetX - l, offsetY - t);
		    	context.SetSource(surface);
		    	context.Paint();
				context.GetTarget().Flush();
				context.Dispose();
				surface.Dispose();
				
				offsetX = l;
				offsetY = t;
				surface = newSurface;
			}
		}

		private Cairo.Context getContext() {
			Cairo.Context context = new Cairo.Context(surface);
			context.Antialias = Cairo.Antialias.Gray;
			context.Translate(-offsetX, -offsetY);
			return context;
		}

		public void paintTrack(Track track) {
			expand(track.getBounds());
			Cairo.Context context = getContext();
			track.draw(context);
			context.GetTarget().Flush();
			context.Dispose();
		}
	}
}