2012-02-12 18:05:59 -08:00
/** \file color.cpp Color class implementation
*/
# include "color.h"
2012-02-19 11:07:02 -08:00
# include "fallback.h"
2012-02-12 18:05:59 -08:00
bool rgb_color_t : : try_parse_special ( const wcstring & special ) {
bzero ( & data , sizeof data ) ;
const wchar_t * name = special . c_str ( ) ;
if ( ! wcscasecmp ( name , L " normal " ) ) {
this - > type = type_normal ;
} else if ( ! wcscasecmp ( name , L " reset " ) ) {
this - > type = type_reset ;
} else if ( ! wcscasecmp ( name , L " ignore " ) ) {
this - > type = type_ignore ;
} else {
this - > type = type_none ;
}
return this - > type ! = type_none ;
}
static int parse_hex_digit ( wchar_t x ) {
switch ( x ) {
case L ' 0 ' : return 0x0 ;
case L ' 1 ' : return 0x1 ;
case L ' 2 ' : return 0x2 ;
case L ' 3 ' : return 0x3 ;
case L ' 4 ' : return 0x4 ;
case L ' 5 ' : return 0x5 ;
case L ' 6 ' : return 0x6 ;
case L ' 7 ' : return 0x7 ;
case L ' 8 ' : return 0x8 ;
case L ' 9 ' : return 0x9 ;
case L ' a ' : case L ' A ' : return 0xA ;
case L ' b ' : case L ' B ' : return 0xB ;
case L ' c ' : case L ' C ' : return 0xC ;
case L ' d ' : case L ' D ' : return 0xD ;
case L ' e ' : case L ' E ' : return 0xE ;
case L ' f ' : case L ' F ' : return 0xF ;
default : return - 1 ;
}
}
static unsigned char convert_color ( const unsigned char rgb [ 3 ] , const uint32_t * colors , size_t color_count ) {
long r = rgb [ 0 ] , g = rgb [ 1 ] , b = rgb [ 2 ] ;
unsigned long best_distance = ( unsigned long ) ( - 1 ) ;
unsigned char best_index = ( unsigned char ) ( - 1 ) ;
for ( unsigned char idx = 0 ; idx < color_count ; idx + + ) {
uint32_t color = colors [ idx ] ;
long test_r = ( color > > 16 ) & 0xFF , test_g = ( color > > 8 ) & 0xFF , test_b = ( color > > 0 ) & 0xFF ;
unsigned long distance = 0 ;
distance + = ( r - test_r ) * ( r - test_r ) ;
distance + = ( g - test_g ) * ( g - test_g ) ;
distance + = ( b - test_b ) * ( b - test_b ) ;
if ( distance < = best_distance ) {
best_index = idx ;
best_distance = distance ;
}
}
return best_index ;
}
bool rgb_color_t : : try_parse_rgb ( const wcstring & name ) {
bzero ( & data , sizeof data ) ;
/* We support the following style of rgb formats (case insensitive):
# FA3
# F3A035
FA3
F3A035
*/
size_t digit_idx = 0 , len = name . size ( ) ;
/* Skip any leading # */
if ( len > 0 & & name . at ( 0 ) = = L ' # ' )
digit_idx + + ;
bool success = false ;
size_t i ;
if ( len - digit_idx = = 3 ) {
// type FA3
for ( i = 0 ; i < 3 ; i + + ) {
int val = parse_hex_digit ( name . at ( digit_idx + + ) ) ;
if ( val < 0 ) break ;
data . rgb [ i ] = val * 16 + val ;
}
success = ( i = = 3 ) ;
} else if ( len - digit_idx = = 6 ) {
// type F3A035
for ( i = 0 ; i < 3 ; i + + ) {
int hi = parse_hex_digit ( name . at ( digit_idx + + ) ) ;
int lo = parse_hex_digit ( name . at ( digit_idx + + ) ) ;
if ( lo < 0 | | hi < 0 ) break ;
data . rgb [ i ] = hi * 16 + lo ;
}
success = ( i = = 3 ) ;
}
if ( success ) {
this - > type = type_rgb ;
}
return success ;
}
struct named_color_t {
const wchar_t * name ;
unsigned char idx ;
unsigned char rgb [ 3 ] ;
} ;
static const named_color_t named_colors [ 11 ] = {
{ L " black " , 0 , { 0 , 0 , 0 } } ,
{ L " red " , 1 , { 0xFF , 0 , 0 } } ,
{ L " green " , 2 , { 0 , 0xFF , 0 } } ,
{ L " brown " , 3 , { 0x72 , 0x50 , 0 } } ,
{ L " yellow " , 3 , { 0xFF , 0xFF , 0 } } ,
{ L " blue " , 4 , { 0 , 0 , 0xFF } } ,
{ L " magenta " , 5 , { 0xFF , 0 , 0xFF } } ,
{ L " purple " , 5 , { 0xFF , 0 , 0xFF } } ,
{ L " cyan " , 6 , { 0 , 0xFF , 0xFF } } ,
{ L " white " , 7 , { 0xFF , 0xFF , 0xFF } } ,
{ L " normal " , 8 , { 0xFF , 0xFF , 0XFF } }
} ;
bool rgb_color_t : : try_parse_named ( const wcstring & str ) {
bzero ( & data , sizeof data ) ;
size_t max = sizeof named_colors / sizeof * named_colors ;
for ( size_t idx = 0 ; idx < max ; idx + + ) {
if ( 0 = = wcscasecmp ( str . c_str ( ) , named_colors [ idx ] . name ) ) {
data . name_idx = named_colors [ idx ] . idx ;
this - > type = type_named ;
return true ;
}
}
return false ;
}
rgb_color_t : : rgb_color_t ( unsigned char t , unsigned char i ) : type ( t ) , data ( ) , flags ( ) {
data . name_idx = i ;
}
rgb_color_t rgb_color_t : : normal ( ) { return rgb_color_t ( type_normal ) ; }
rgb_color_t rgb_color_t : : reset ( ) { return rgb_color_t ( type_reset ) ; }
rgb_color_t rgb_color_t : : ignore ( ) { return rgb_color_t ( type_ignore ) ; }
rgb_color_t rgb_color_t : : none ( ) { return rgb_color_t ( type_none ) ; }
rgb_color_t rgb_color_t : : white ( ) { return rgb_color_t ( type_named , 7 ) ; }
rgb_color_t rgb_color_t : : black ( ) { return rgb_color_t ( type_named , 0 ) ; }
static unsigned char term8_color_for_rgb ( const unsigned char rgb [ 3 ] ) {
const uint32_t kColors [ ] = {
0x000000 , //Black
0xFF0000 , //Red
0x00FF00 , //Green
0x725000 , //Brown
0xFFFF00 , //Yellow
0x0000FF , //Blue
0xFF00FF , //Magenta
0xFF00FF , //Purple
0x00FFFF , //Cyan
0xFFFFFF , //White
} ;
return convert_color ( rgb , kColors , sizeof kColors / sizeof * kColors ) ;
}
static unsigned char term256_color_for_rgb ( const unsigned char rgb [ 3 ] ) {
const uint32_t kColors [ 240 ] = {
0x000000 , 0x00005f , 0x000087 , 0x0000af , 0x0000d7 , 0x0000ff , 0x005f00 , 0x005f5f ,
0x005f87 , 0x005faf , 0x005fd7 , 0x005fff , 0x008700 , 0x00875f , 0x008787 , 0x0087af ,
0x0087d7 , 0x0087ff , 0x00af00 , 0x00af5f , 0x00af87 , 0x00afaf , 0x00afd7 , 0x00afff ,
0x00d700 , 0x00d75f , 0x00d787 , 0x00d7af , 0x00d7d7 , 0x00d7ff , 0x00ff00 , 0x00ff5f ,
0x00ff87 , 0x00ffaf , 0x00ffd7 , 0x00ffff , 0x5f0000 , 0x5f005f , 0x5f0087 , 0x5f00af ,
0x5f00d7 , 0x5f00ff , 0x5f5f00 , 0x5f5f5f , 0x5f5f87 , 0x5f5faf , 0x5f5fd7 , 0x5f5fff ,
0x5f8700 , 0x5f875f , 0x5f8787 , 0x5f87af , 0x5f87d7 , 0x5f87ff , 0x5faf00 , 0x5faf5f ,
0x5faf87 , 0x5fafaf , 0x5fafd7 , 0x5fafff , 0x5fd700 , 0x5fd75f , 0x5fd787 , 0x5fd7af ,
0x5fd7d7 , 0x5fd7ff , 0x5fff00 , 0x5fff5f , 0x5fff87 , 0x5fffaf , 0x5fffd7 , 0x5fffff ,
0x870000 , 0x87005f , 0x870087 , 0x8700af , 0x8700d7 , 0x8700ff , 0x875f00 , 0x875f5f ,
0x875f87 , 0x875faf , 0x875fd7 , 0x875fff , 0x878700 , 0x87875f , 0x878787 , 0x8787af ,
0x8787d7 , 0x8787ff , 0x87af00 , 0x87af5f , 0x87af87 , 0x87afaf , 0x87afd7 , 0x87afff ,
0x87d700 , 0x87d75f , 0x87d787 , 0x87d7af , 0x87d7d7 , 0x87d7ff , 0x87ff00 , 0x87ff5f ,
0x87ff87 , 0x87ffaf , 0x87ffd7 , 0x87ffff , 0xaf0000 , 0xaf005f , 0xaf0087 , 0xaf00af ,
0xaf00d7 , 0xaf00ff , 0xaf5f00 , 0xaf5f5f , 0xaf5f87 , 0xaf5faf , 0xaf5fd7 , 0xaf5fff ,
0xaf8700 , 0xaf875f , 0xaf8787 , 0xaf87af , 0xaf87d7 , 0xaf87ff , 0xafaf00 , 0xafaf5f ,
0xafaf87 , 0xafafaf , 0xafafd7 , 0xafafff , 0xafd700 , 0xafd75f , 0xafd787 , 0xafd7af ,
0xafd7d7 , 0xafd7ff , 0xafff00 , 0xafff5f , 0xafff87 , 0xafffaf , 0xafffd7 , 0xafffff ,
0xd70000 , 0xd7005f , 0xd70087 , 0xd700af , 0xd700d7 , 0xd700ff , 0xd75f00 , 0xd75f5f ,
0xd75f87 , 0xd75faf , 0xd75fd7 , 0xd75fff , 0xd78700 , 0xd7875f , 0xd78787 , 0xd787af ,
0xd787d7 , 0xd787ff , 0xd7af00 , 0xd7af5f , 0xd7af87 , 0xd7afaf , 0xd7afd7 , 0xd7afff ,
0xd7d700 , 0xd7d75f , 0xd7d787 , 0xd7d7af , 0xd7d7d7 , 0xd7d7ff , 0xd7ff00 , 0xd7ff5f ,
0xd7ff87 , 0xd7ffaf , 0xd7ffd7 , 0xd7ffff , 0xff0000 , 0xff005f , 0xff0087 , 0xff00af ,
0xff00d7 , 0xff00ff , 0xff5f00 , 0xff5f5f , 0xff5f87 , 0xff5faf , 0xff5fd7 , 0xff5fff ,
0xff8700 , 0xff875f , 0xff8787 , 0xff87af , 0xff87d7 , 0xff87ff , 0xffaf00 , 0xffaf5f ,
0xffaf87 , 0xffafaf , 0xffafd7 , 0xffafff , 0xffd700 , 0xffd75f , 0xffd787 , 0xffd7af ,
0xffd7d7 , 0xffd7ff , 0xffff00 , 0xffff5f , 0xffff87 , 0xffffaf , 0xffffd7 , 0xffffff ,
0x080808 , 0x121212 , 0x1c1c1c , 0x262626 , 0x303030 , 0x3a3a3a , 0x444444 , 0x4e4e4e ,
0x585858 , 0x626262 , 0x6c6c6c , 0x767676 , 0x808080 , 0x8a8a8a , 0x949494 , 0x9e9e9e ,
0xa8a8a8 , 0xb2b2b2 , 0xbcbcbc , 0xc6c6c6 , 0xd0d0d0 , 0xdadada , 0xe4e4e4 , 0xeeeeee
} ;
return 16 + convert_color ( rgb , kColors , sizeof kColors / sizeof * kColors ) ;
}
unsigned char rgb_color_t : : to_term256_index ( ) const {
assert ( type = = type_rgb ) ;
return term256_color_for_rgb ( data . rgb ) ;
}
unsigned char rgb_color_t : : to_name_index ( ) const {
if ( type = = type_named ) {
return data . name_idx ;
} else if ( type = = type_rgb ) {
return term8_color_for_rgb ( data . rgb ) ;
} else {
throw " Bad type for to_name_index " ;
}
}
rgb_color_t : : rgb_color_t ( const wcstring & str ) {
bool success = false ;
if ( ! success ) success = try_parse_special ( str ) ;
if ( ! success ) success = try_parse_named ( str ) ;
if ( ! success ) success = try_parse_rgb ( str ) ;
if ( ! success ) {
bzero ( this - > data . rgb , sizeof this - > data . rgb ) ;
this - > type = type_none ;
}
if ( ! success ) success = try_parse_special ( str ) ;
if ( this - > try_parse_special ( str ) ) {
/* Nothing */
} else if ( this - > try_parse_named ( str ) ) {
} else if ( this - > try_parse_rgb ( str ) ) {
this - > type = type_rgb ;
} else {
bzero ( this - > data . rgb , sizeof this - > data . rgb ) ;
this - > type = type_none ;
}
}
wcstring rgb_color_t : : description ( ) const {
switch ( type ) {
case type_none :
return L " none " ;
case type_named :
return format_string ( L " named(%d) " , (int)data.name_idx) ;
case type_rgb :
return format_string ( L " rgb(0x%02x%02x%02x) " , data.rgb[0], data.rgb[1], data.rgb[2]) ;
case type_reset :
return L " reset " ;
case type_ignore :
return L " ignore " ;
default :
abort ( ) ;
return L " " ;
}
}