xref: /haiku/src/apps/terminal/Colors.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
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