Fantom

 

//
// Copyright (c) 2008, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   16 Jun 2008  Brian Frank  Creation
//   12 May 2016  Brian Frank  SVG/CSS changes
//

**
** ColorTest
**
@Js
class ColorTest : Test
{

  Void testMake()
  {
    c := Color(0xaabbcc)
    verifyEq(c.a,  1.0f)
    verifyEq(c.rgb,  0xaabbcc)
    verifyEq(c.toHexStr, "#abc")
    verifyColor(c, 0xaa, 0xbb, 0xcc, 1.0f, "#abc")

    c = Color(0x123456)
    verifyEq(c.a,  1.0f)
    verifyEq(c.rgb,  0x123456)
    verifyEq(c.toHexStr, "#123456")
    verifyColor(c, 0x12, 0x34, 0x56, 1.0f, "#123456")

    c = Color(0xbbccdd, 0.5f)
    verifyEq(c.rgb,  0xbbccdd)
    verifyEq(c.a, 0.5f)
    verifyEq(c.toHexStr, "#bbccdd7f")
    verifyColor(c, 0xbb, 0xcc, 0xdd, 0.5f, "rgba(187,204,221,0.5)")

    c = Color.makeRgb(1, 2, 3, 0.4f)
    verifyEq(c.rgb, 0x010203)
    verifyEq(c.a, 0.4f)
    verifyEq(c.toHexStr, "#01020366")
    verifyColor(c, 1, 2, 3, 0.4f, "rgba(1,2,3,0.4)")

    c = Color.makeRgb(0x33, 0x22, 0x11)
    verifyEq(c.rgb, 0x332211)
    verifyEq(c.a,  1.0f)
    verifyColor(c, 0x33, 0x22, 0x11, 1.0f, "#321")
  }

  Void verifyColor(Color c, Int r, Int g, Int b, Float a, Str s)
  {
    verifyEq(c.r, r)
    verifyEq(c.g, g)
    verifyEq(c.b, b)
    verifyEq(c.a, a)
    verifyEq(c.toStr, s)
    verifyEq(c, Color.fromStr(c.toStr))
    verifyEq(c, Buf().writeObj(c).flip.readObj)
    verifyEq(c, Color.makeRgb(r, g, b, a))
  }

  Void testFromStr()
  {
    // named colors
    verifyFromStr("red", Color(0xff0000))
    verifyFromStr("DeepPink", Color(0xff1493))
    verifyFromStr("LIME", Color(0x00ff00))

    // #RGB
    verifyFromStr("#abc", Color(0xaabbcc))
    verifyFromStr("#023", Color(0x002233))
    verifyFromStr("#345", Color(0x334455))

    // #RGBA
    verifyFromStr("#a7b3", Color(0xaa77bb, 0.2f))
    verifyFromStr("#30CF", Color(0x3300cc))

    // #RRGGBB
    verifyFromStr("#a4b5c6", Color(0xa4b5c6))

    // #RRGGBBAA
    verifyFromStr("#dea4b540", Color(0xdea4b5, 0.251f))
    verifyFromStr("#12345678", Color(0x123456, GeomUtil.formatFloat(120f/255f).toFloat))

    // rgb() - CSS4 allows comma or space
    verifyFromStr("rgb(10, 20, 30)", Color(0x0a141e, 1.0f))
    verifyFromStr("rgb(10 20 30)", Color(0x0a141e, 1.0f))
    verifyFromStr("rgb(10%, 20%, 30%)", Color(0x19334c, 1.0f))
    verifyFromStr("rgb(10%  20%  30%)", Color(0x19334c, 1.0f))

    // rgba() - CSS4 allows alpha in rgb and uses rgba as deprecated
    verifyFromStr("rgb(10 , 20 , 30 , 0.5)", Color(0x0a141e, 0.5f))
    verifyFromStr("rgb(10  20  30  50%)", Color(0x0a141e, 0.5f))
    verifyFromStr("rgb(50% 0% 100% 25%)", Color(0x7f00ff, 0.25f))
    verifyFromStr("rgb(50%, 0%, 100%, 0.25)", Color(0x7f00ff, 0.25f))
    verifyFromStr("rgba(10 , 20 , 30 , 0.5)", Color(0x0a141e, 0.5f))
    verifyFromStr("rgba(10  20  30  50%)", Color(0x0a141e, 0.5f))
    verifyFromStr("rgba(50% 0% 100% 25%)", Color(0x7f00ff, 0.25f))
    verifyFromStr("rgba(50%, 0%, 100%, 0.25)", Color(0x7f00ff, 0.25f))

    // hsl()
    verifyFromStr("hsl(120deg 50% 0.75)", Color.makeHsl(120f, 0.5f, 0.75f, 1.0f))
    verifyFromStr("hsl(700, 0.2, 0.3, 0.4)", Color.makeHsl(340f, 0.2f, 0.3f, 0.4f))
    verifyFromStr("hsl(0deg  0.8  70%)", Color.makeHsl(0f, 0.8f, 0.7f, 1f))
    verifyFromStr("hsl(0deg  0.8  70%  50%)", Color.makeHsl(0f, 0.8f, 0.7f, 0.5f))

    // hsla()
    verifyFromStr("hsla(120deg 50% 0.75)", Color.makeHsl(120f, 0.5f, 0.75f, 1.0f))
    verifyFromStr("hsla(700, 0.2, 0.3, 0.4)", Color.makeHsl(340f, 0.2f, 0.3f, 0.4f))
    verifyFromStr("hsla(0deg  0.8  70%  50%)", Color.makeHsl(0f, 0.8f, 0.7f, 0.5f))

    // errors
    verifyEq(Color.fromStr("#bc", false), null)
    verifyErr(ParseErr#) { x := Color.fromStr("abc") }
    verifyErr(ParseErr#) { x := Color.fromStr("#xyz", true) }
  }

  Void verifyFromStr(Str s, Color e)
  {
    a := Color.fromStr(s)
    // echo("-- $s\n   $a\n   $e")
    verifyEq(a, e)

    list := Color.listFromStr("$s,$s , $s")
    verifyEq(list.size, 3)
    verifyEq(list[0], e)
    verifyEq(list[1], e)
    verifyEq(list[2], e)
  }

  Void testListFromStr()
  {
    verifyEq(Color.listFromStr("#abc, red, rgb(128, 0, 0)"),
             Color[Color("#abc"), Color("red"), Color("rgb(128, 0, 0)")])
    verifyEq(Color.listFromStr("rgba(128, 0, 0, 50%), #abc, rgb(128, 0, 0)"),
             Color[Color("rgba(128, 0, 0, 50%)"), Color("#abc"), Color("rgb(128, 0, 0)")])
  }

  Void testEquals()
  {
    verifyEq(Color(0xaabbcc), Color(0xaabbcc))
    verifyEq(Color(0xaabbcc, 0.5f), Color(0xaabbcc, 0.5f))
    verifyNotEq(Color(0xaa0bcc), Color(0xaabbcc))
    verifyNotEq(Color(0xaabbcc, 1.0f), Color(0xaabbcc, 0.9f))
  }

  Void testHsl()
  {
    verifyHsl(0x000000, 0f,   0f, 0f)
    verifyHsl(0xffffff, 0f,   0f, 1f)
    verifyHsl(0xff0000, 0f,   1f, 1f)
    verifyHsl(0x00ff00, 120f, 1f, 1f)
    verifyHsl(0x0000ff, 240f, 1f, 1f)
    verifyHsl(0xffff00, 60f,  1f, 1f)
    verifyHsl(0x00ffff, 180f, 1f, 1f)
    verifyHsl(0xff00ff, 300f, 1f, 1f)
    verifyHsl(0x6496c8, 210f, 0.5f,  0.78f)
    verifyHsl(0x32c850, 132f, 0.75f, 0.78f)
    verifyHsl(Color("hsl(240 0.4 1)"), 240f, 0.4f, 1f)
  }

  Void verifyHsl(Obj obj, Float h, Float s, Float l)
  {
    c := obj as Color ?: Color.make(obj)
    verify(c.h.approx(h, 0.1f))
    verify(c.s.approx(s, 0.01f))
    verify(c.l.approx(l, 0.01f))
    verifyEq(c, Color.makeHsl(c.h, c.s, c.l))
  }

//////////////////////////////////////////////////////////////////////////
// Interpolate RGB
//////////////////////////////////////////////////////////////////////////

  Void testInterpolateRgb()
  {
    a := Color("#123")
    b := Color("#cba")
    verifyInterpolateRgb(a, b, -1f,   "rgb(0 0 0)")
    verifyInterpolateRgb(a, b, -0.2f, "rgb(0 3 27)")
    verifyInterpolateRgb(a, b, 0f,    "rgb(17 34 51)")
    verifyInterpolateRgb(a, b, 0.25f, "rgb(63 72 80)")
    verifyInterpolateRgb(a, b, 0.5f,  "rgb(110 110 110)")
    verifyInterpolateRgb(a, b, 0.75f, "rgb(157 148 140)")
    verifyInterpolateRgb(a, b, 1.0f,  "rgb(204 187 170)")
    verifyInterpolateRgb(a, b, 1.2f,  "rgb(241 217 193)")
    verifyInterpolateRgb(a, b, 2f,    "rgb(255 255 255)")

    a = Color("rgba(200 70 30 0.9)")
    b = Color("rgba(250 20 90 0.1)")
    verifyInterpolateRgb(a, b, -1f,   "rgba(150 120 0 1.0)")
    verifyInterpolateRgb(a, b, -0.2f, "rgba(190 80 18 1.0)")
    verifyInterpolateRgb(a, b, 0f,    "rgba(200 70 30 0.9)")
    verifyInterpolateRgb(a, b, 0.25f, "rgba(212 57 45 0.7)")
    verifyInterpolateRgb(a, b, 0.5f,  "rgba(225 45 60 0.5)")
    verifyInterpolateRgb(a, b, 0.75f, "rgba(237 32 75 0.3)")
    verifyInterpolateRgb(a, b, 1.0f,  "rgba(250 20 90 0.1)")
    verifyInterpolateRgb(a, b, 1.2f,  "rgba(255 10 102 0.0)")
    verifyInterpolateRgb(a, b, 2f,    "rgba(255 0 150 0.0)")
  }

  Void verifyInterpolateRgb(Color a, Color b, Float t, Str expected)
  {
    x := Color.interpolateRgb(a, b, t)
    //echo("-- $a, $b  $t => $x ?= $expected => " + (x == Color(expected)))
    verifyRbgEq(x, Color(expected))
  }

//////////////////////////////////////////////////////////////////////////
// Interpolote HSL
//////////////////////////////////////////////////////////////////////////

  Void testInterpolateHsl()
  {
    a := Color("hsl(200 0.5 0.9)")
    b := Color("hsl(20 1 0.1)")
    verifyInterpolateHsl(a, b, -1f,   "hsl(360 0 1)")
    verifyInterpolateHsl(a, b, -0.2f, "hsl(236 0.4 1)")
    verifyInterpolateHsl(a, b, 0f,    "hsl(200 0.5 0.9)")
    verifyInterpolateHsl(a, b, 0.25f, "hsl(155 0.625 0.7)")
    verifyInterpolateHsl(a, b, 0.5f,  "hsl(110 0.75 0.5)")
    verifyInterpolateHsl(a, b, 0.75f, "hsl(65 0.875 0.3)")
    verifyInterpolateHsl(a, b, 1.0f,  "hsl(20 1 0.1)")
    verifyInterpolateHsl(a, b, 1.2f,  "hsl(0 1 0)")
    verifyInterpolateHsl(a, b, 2f,    "hsl(0 1 0)")
  }

  Void verifyInterpolateHsl(Color a, Color b, Float t, Str expected)
  {
    r := Color.interpolateHsl(a, b, t)
    e := Color(expected)
    //echo("-- $t")
    //echo("   ${hslStr(r)} // result")
    //echo("   ${hslStr(e)} // expected")
    verifyHslEq(r, e)
  }

//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////

  static Str hslStr(Color c)
  {
    "hsl(" + GeomUtil.formatFloat(c.h) + " " +
             GeomUtil.formatFloat(c.s) + " " +
             GeomUtil.formatFloat(c.l) + " " +
             GeomUtil.formatFloat(c.a) + ")"
  }

  Void verifyRbgEq(Color a, Color b)
  {
    verifyEq(a.r, b.r)
    verifyEq(a.g, b.g)
    verifyEq(a.b, b.b)
    verify(a.a.approx(b.a))
  }

  Void verifyHslEq(Color a, Color b)
  {
    verify(a.h.approx(b.h, 2f))
    verify(a.s.approx(b.s, 0.05f))
    verify(a.l.approx(b.l, 0.05f))
    verify(a.a.approx(b.a))
  }

}