///|
/// An 8-bit coverage mask the size of the canvas framebuffer.
/// Each byte `data[y * width + x]` is the clip opacity at that pixel:
/// 0 = fully clipped out, 255 = fully visible.
///
/// Stored on `DrawState.clip` lazily: canvases without clip keep
/// `clip = None` and incur zero memory overhead.
pub struct ClipMask {
  width : Int
  height : Int
  data : FixedArray[Byte]
} derive(Eq)

///|
pub impl Show for ClipMask with fn output(self, logger) {
  logger.write_string("ClipMask { width: ")
  logger.write_object(self.width)
  logger.write_string(", height: ")
  logger.write_object(self.height)
  logger.write_string(", data: <")
  logger.write_object(self.data.length())
  logger.write_string(" bytes> }")
}

///|
/// Create a fully-visible mask (every byte == 255) at the given size.
pub fn ClipMask::new(width : Int, height : Int) -> ClipMask {
  let n = width * height
  { width, height, data: FixedArray::make(n, b'\xFF') }
}

///|
/// Return an independent deep copy of the mask data.
pub fn ClipMask::clone(self : ClipMask) -> ClipMask {
  let n = self.data.length()
  let data = FixedArray::make(n, b'\x00')
  for i in 0..