1 /* 2 * Copyright 2010-2013, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stefano Ceccherini, stefano.ceccherini@gmail.com 7 * Siarzhuk Zharski, zharik@gmx.li 8 */ 9 10 11 #include "Colors.h" 12 13 #include <ctype.h> 14 #include <stdio.h> 15 #include <strings.h> 16 17 #include <Application.h> 18 #include <Catalog.h> 19 #include <Resources.h> 20 21 22 #undef B_TRANSLATION_CONTEXT 23 #define B_TRANSLATION_CONTEXT "Terminal colors scheme" 24 25 26 struct color_scheme gCustomColorScheme = { 27 B_TRANSLATE("Custom") 28 }; 29 30 31 BObjectList<const color_scheme>* gColorSchemes = NULL; 32 33 34 bool 35 ansi_color_scheme::operator==(const ansi_color_scheme& scheme) 36 { 37 return black == scheme.black 38 && red == scheme.red 39 && green == scheme.green 40 && yellow == scheme.yellow 41 && blue == scheme.blue 42 && magenta == scheme.magenta 43 && cyan == scheme.cyan 44 && white == scheme.white; 45 } 46 47 48 bool 49 color_scheme::operator==(const color_scheme& scheme) 50 { 51 return text_fore_color == scheme.text_fore_color 52 && text_back_color == scheme.text_back_color 53 && cursor_fore_color == scheme.cursor_fore_color 54 && cursor_back_color == scheme.cursor_back_color 55 && select_fore_color == scheme.select_fore_color 56 && select_back_color == scheme.select_back_color 57 && ansi_colors == scheme.ansi_colors 58 && ansi_colors_h == scheme.ansi_colors_h; 59 } 60 61 // #pragma mark XColorsTable implementation 62 63 XColorsTable gXColorsTable; 64 65 66 XColorsTable::XColorsTable() 67 : 68 fTable(NULL), 69 fCount(0) 70 { 71 } 72 73 74 XColorsTable::~XColorsTable() 75 { 76 // fTable as result of LoadResource call and owned 77 // by BApplication so no need to free it explicitly 78 fTable = NULL; 79 fCount = 0; 80 } 81 82 83 status_t 84 XColorsTable::LookUpColor(const char* name, rgb_color* color) 85 { 86 if (name == NULL || color == NULL) 87 return B_BAD_DATA; 88 89 size_t length = strlen(name); 90 91 // first check for 'rgb:xx/xx/xx' or '#xxxxxx'-encoded color names 92 u_int r = 0, g = 0, b = 0; 93 float c = 0, m = 0, y = 0, k = 0; 94 if ((length == 12 && sscanf(name, "rgb:%02x/%02x/%02x", &r, &g, &b) == 3) 95 || (length == 7 && sscanf(name, "#%02x%02x%02x", &r, &g, &b) == 3)) { 96 color->set_to(r, g, b); 97 return B_OK; 98 // then check for 'rgb:xxxx/xxxx/xxxx' or '#xxxxxxxxxxxx'-encoded color names 99 } else if ((length == 18 && sscanf(name, "rgb:%04x/%04x/%04x", &r, &g, &b) == 3) 100 || (length == 13 && sscanf(name, "#%04x%04x%04x", &r, &g, &b) == 3)) { 101 color->set_to(r >> 8, g >> 8, b >> 8); 102 return B_OK; 103 // then check for 'cmyk:c.c/m.m/y.y/k.k' or 'cmy:c.c/m.m/y.y'-encoded color names 104 } else if (sscanf(name, "cmyk:%f/%f/%f/%f", &c, &m, &y, &k) == 4 105 || sscanf(name, "cmy:%f/%f/%f", &c, &m, &y) == 3) { 106 if (c >= 0 && m >= 0 && y >= 0 && k >= 0 107 && c <= 1 && m <= 1 && y <= 1 && k <= 1) { 108 color->set_to((1 - c) * (1 - k) * 255, 109 (1 - m) * (1 - k) * 255, 110 (1 - y) * (1 - k) * 255); 111 return B_OK; 112 } 113 } 114 115 // then search the X11 rgb table 116 if (fTable == NULL) { 117 status_t result = _LoadXColorsTable(); 118 if (result != B_OK) 119 return result; 120 } 121 122 // use binary search to lookup color name hash in table 123 int left = -1; 124 int right = fCount; 125 uint32 hash = _HashName(name); 126 while ((right - left) > 1) { 127 int i = (left + right) / 2; 128 ((fTable[i].hash < hash) ? left : right) = i; 129 } 130 131 if (fTable[right].hash == hash) { 132 *color = fTable[right].color; 133 return B_OK; 134 } 135 136 return B_NAME_NOT_FOUND; 137 } 138 139 140 status_t 141 XColorsTable::_LoadXColorsTable() 142 { 143 BResources* res = BApplication::AppResources(); 144 if (res == NULL) 145 return B_ERROR; 146 147 size_t size = 0; 148 fTable = (_XColorEntry*)res->LoadResource(B_RAW_TYPE, "XColorsTable", &size); 149 if (fTable == NULL || size < sizeof(_XColorEntry)) { 150 fTable = NULL; 151 return B_ENTRY_NOT_FOUND; 152 } 153 154 fCount = size / sizeof(_XColorEntry); 155 return B_OK; 156 } 157 158 159 uint32 160 XColorsTable::_HashName(const char* name) 161 { 162 uint32 hash = 0; 163 uint32 g = 0; 164 165 // Using modified P.J.Weinberger hash algorithm 166 // Spaces are purged out, characters are upper-cased 167 // 'E' replaced with 'A' (to join 'grey' and 'gray' variations) 168 for (const char* p = name; *p; p++) { 169 int ch = toupper(*p); 170 switch (ch) { 171 case ' ': 172 break; 173 case 'E': 174 ch = 'A'; 175 default: 176 hash = (hash << 4) + (ch & 0xFF); 177 g = hash & 0xf0000000; 178 if (g != 0) { 179 hash ^= g >> 24; 180 hash ^= g; 181 } 182 break; 183 } 184 } 185 186 return hash; 187 } 188