Update to groff 1.19.2.
[dragonfly.git] / contrib / groff-1.19 / src / libs / libgroff / color.cpp
1 // -*- C++ -*-
2
3 /* <groff_src_dir>/src/libs/libgroff/color.cpp
4
5 Last update: 26 May 2004
6
7 Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
8     Written by Gaius Mulley <gaius@glam.ac.uk>
9
10 This file is part of groff.
11
12 groff is free software; you can redistribute it and/or modify it under
13 the terms of the GNU General Public License as published by the Free
14 Software Foundation; either version 2, or (at your option) any later
15 version.
16
17 groff is distributed in the hope that it will be useful, but WITHOUT ANY
18 WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 for more details.
21
22 You should have received a copy of the GNU General Public License along
23 with groff; see the file COPYING.  If not, write to the Free Software
24 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
25
26 #include "lib.h"
27 #include "color.h"
28 #include "cset.h"
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32
33 #include <assert.h>
34 #include <stdio.h>
35 #include <fcntl.h>
36 #include <stdlib.h>
37 #include "errarg.h"
38 #include "error.h"
39
40 static inline unsigned int
41 min(const unsigned int a, const unsigned int b)
42 {
43   if (a < b)
44     return a;
45   else
46     return b;
47 }
48
49 color *color::free_list = 0;
50
51 void *color::operator new(size_t n)
52 {
53   assert(n == sizeof(color));
54   if (!free_list) {
55     const int BLOCK = 128;
56     free_list = (color *)new char[sizeof(color)*BLOCK];
57     for (int i = 0; i < BLOCK - 1; i++)
58       free_list[i].next = free_list + i + 1;
59     free_list[BLOCK-1].next = 0;
60   }
61   color *p = free_list;
62   free_list = (color *)(free_list->next);
63   p->next = 0;
64   return p;
65 }
66
67 void color::operator delete(void *p)
68 {
69   if (p) {
70     ((color *)p)->next = free_list;
71     free_list = (color *)p;
72   }
73 }
74
75 color::color(const color * const c)
76 {
77   nm = c->nm;
78   scheme = c->scheme;
79   components[0] = c->components[0];
80   components[1] = c->components[1];
81   components[2] = c->components[2];
82   components[3] = c->components[3];
83 }
84
85 color::~color()
86 {
87 }
88
89 int color::operator==(const color & c) const
90 {
91   if (scheme != c.scheme)
92     return 0;
93   switch (scheme) {
94   case DEFAULT:
95     break;
96   case RGB:
97     if (Red != c.Red || Green != c.Green || Blue != c.Blue)
98       return 0;
99     break;
100   case CMYK:
101     if (Cyan != c.Cyan || Magenta != c.Magenta
102         || Yellow != c.Yellow || Black != c.Black)
103       return 0;
104     break;
105   case GRAY:
106     if (Gray != c.Gray)
107       return 0;
108     break;
109   case CMY:
110     if (Cyan != c.Cyan || Magenta != c.Magenta || Yellow != c.Yellow)
111       return 0;
112     break;
113   }
114   return 1;
115 }
116
117 int color::operator!=(const color & c) const
118 {
119   return !(*this == c);
120 }
121
122 color_scheme color::get_components(unsigned int *c) const
123 {
124 #if 0
125   if (sizeof (c) < sizeof (unsigned int) * 4)
126     fatal("argument is not big enough to store 4 color components");
127 #endif
128   c[0] = components[0];
129   c[1] = components[1];
130   c[2] = components[2];
131   c[3] = components[3];
132   return scheme;
133 }
134
135 void color::set_default()
136 {
137   scheme = DEFAULT;
138 }
139
140 // (0, 0, 0) is black
141
142 void color::set_rgb(const unsigned int r, const unsigned int g,
143                     const unsigned int b)
144 {
145   scheme = RGB;
146   Red = min(MAX_COLOR_VAL, r);
147   Green = min(MAX_COLOR_VAL, g);
148   Blue = min(MAX_COLOR_VAL, b);
149 }
150
151 // (0, 0, 0) is white
152
153 void color::set_cmy(const unsigned int c, const unsigned int m,
154                     const unsigned int y)
155 {
156   scheme = CMY;
157   Cyan = min(MAX_COLOR_VAL, c);
158   Magenta = min(MAX_COLOR_VAL, m);
159   Yellow = min(MAX_COLOR_VAL, y);
160 }
161
162 // (0, 0, 0, 0) is white
163
164 void color::set_cmyk(const unsigned int c, const unsigned int m,
165                      const unsigned int y, const unsigned int k)
166 {
167   scheme = CMYK;
168   Cyan = min(MAX_COLOR_VAL, c);
169   Magenta = min(MAX_COLOR_VAL, m);
170   Yellow = min(MAX_COLOR_VAL, y);
171   Black = min(MAX_COLOR_VAL, k);
172 }
173
174 // (0) is black
175
176 void color::set_gray(const unsigned int g)
177 {
178   scheme = GRAY;
179   Gray = min(MAX_COLOR_VAL, g);
180 }
181
182 /*
183  *  atoh - computes the decimal value of a hexadecimal number string.
184  *         `length' characters of `s' are read.  Returns 1 if successful.
185  */
186
187 static int atoh(unsigned int *result,
188                 const char * const s, const size_t length)
189 {
190   size_t i = 0;
191   unsigned int val = 0;
192   while ((i < length) && csxdigit(s[i])) {
193     if (csdigit(s[i]))
194       val = val*0x10 + (s[i]-'0');
195     else if (csupper(s[i]))
196       val = val*0x10 + (s[i]-'A') + 10;
197     else
198       val = val*0x10 + (s[i]-'a') + 10;
199     i++;
200   }
201   if (i != length)
202     return 0;
203   *result = val;
204   return 1;
205 }
206
207 /*
208  *  read_encoding - set color from a hexadecimal color string.
209  *
210  *  Use color scheme `cs' to parse `n' color components from string `s'.
211  *  Returns 1 if successful.
212  */
213
214 int color::read_encoding(const color_scheme cs, const char * const s,
215                          const size_t n)
216 {
217   size_t hex_length = 2;
218   scheme = cs;
219   char *p = (char *) s;
220   p++;
221   if (*p == '#') {
222     hex_length = 4;
223     p++;
224   }
225   for (size_t i = 0; i < n; i++) {
226     if (!atoh(&(components[i]), p, hex_length))
227       return 0;
228     if (hex_length == 2)
229       components[i] *= 0x101;   // scale up -- 0xff should become 0xffff
230     p += hex_length;
231   }
232   return 1;
233 }
234
235 int color::read_rgb(const char * const s)
236 {
237   return read_encoding(RGB, s, 3);
238 }
239
240 int color::read_cmy(const char * const s)
241 {
242   return read_encoding(CMY, s, 3);
243 }
244
245 int color::read_cmyk(const char * const s)
246 {
247   return read_encoding(CMYK, s, 4);
248 }
249
250 int color::read_gray(const char * const s)
251 {
252   return read_encoding(GRAY, s, 1);
253 }
254
255 void
256 color::get_rgb(unsigned int *r, unsigned int *g, unsigned int *b) const
257 {
258   switch (scheme) {
259   case RGB:
260     *r = Red;
261     *g = Green;
262     *b = Blue;
263     break;
264   case CMY:
265     *r = MAX_COLOR_VAL - Cyan;
266     *g = MAX_COLOR_VAL - Magenta;
267     *b = MAX_COLOR_VAL - Yellow;
268     break;
269   case CMYK:
270     *r = MAX_COLOR_VAL
271          - min(MAX_COLOR_VAL,
272                Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
273     *g = MAX_COLOR_VAL
274          - min(MAX_COLOR_VAL,
275                Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
276     *b = MAX_COLOR_VAL
277          - min(MAX_COLOR_VAL,
278                Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
279     break;
280   case GRAY:
281     *r = *g = *b = Gray;
282     break;
283   default:
284     assert(0);
285     break;
286   }
287 }
288
289 void
290 color::get_cmy(unsigned int *c, unsigned int *m, unsigned int *y) const
291 {
292   switch (scheme) {
293   case RGB:
294     *c = MAX_COLOR_VAL - Red;
295     *m = MAX_COLOR_VAL - Green;
296     *y = MAX_COLOR_VAL - Blue;
297     break;
298   case CMY:
299     *c = Cyan;
300     *m = Magenta;
301     *y = Yellow;
302     break;
303   case CMYK:
304     *c = min(MAX_COLOR_VAL,
305              Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
306     *m = min(MAX_COLOR_VAL,
307              Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
308     *y = min(MAX_COLOR_VAL,
309              Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
310     break;
311   case GRAY:
312     *c = *m = *y = MAX_COLOR_VAL - Gray;
313     break;
314   default:
315     assert(0);
316     break;
317   }
318 }
319
320 void color::get_cmyk(unsigned int *c, unsigned int *m,
321                      unsigned int *y, unsigned int *k) const
322 {
323   switch (scheme) {
324   case RGB:
325     *k = min(MAX_COLOR_VAL - Red,
326              min(MAX_COLOR_VAL - Green, MAX_COLOR_VAL - Blue));
327     if (MAX_COLOR_VAL == *k) {
328       *c = MAX_COLOR_VAL;
329       *m = MAX_COLOR_VAL;
330       *y = MAX_COLOR_VAL;
331     }
332     else {
333       *c = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Red - *k))
334            / (MAX_COLOR_VAL - *k);
335       *m = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Green - *k))
336            / (MAX_COLOR_VAL - *k);
337       *y = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Blue - *k))
338            / (MAX_COLOR_VAL - *k);
339     }
340     break;
341   case CMY:
342     *k = min(Cyan, min(Magenta, Yellow));
343     if (MAX_COLOR_VAL == *k) {
344       *c = MAX_COLOR_VAL;
345       *m = MAX_COLOR_VAL;
346       *y = MAX_COLOR_VAL;
347     }
348     else {
349       *c = (MAX_COLOR_VAL * (Cyan - *k)) / (MAX_COLOR_VAL - *k);
350       *m = (MAX_COLOR_VAL * (Magenta - *k)) / (MAX_COLOR_VAL - *k);
351       *y = (MAX_COLOR_VAL * (Yellow - *k)) / (MAX_COLOR_VAL - *k);
352     }
353     break;
354   case CMYK:
355     *c = Cyan;
356     *m = Magenta;
357     *y = Yellow;
358     *k = Black;
359     break;
360   case GRAY:
361     *c = *m = *y = 0;
362     *k = MAX_COLOR_VAL - Gray;
363     break;
364   default:
365     assert(0);
366     break;
367   }
368 }
369
370 // we use `0.222r + 0.707g + 0.071b' (this is the ITU standard)
371 // as an approximation for gray
372
373 void color::get_gray(unsigned int *g) const
374 {
375   switch (scheme) {
376   case RGB:
377     *g = (222*Red + 707*Green + 71*Blue) / 1000;
378     break;
379   case CMY:
380     *g = MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000;
381     break;
382   case CMYK:
383     *g = (MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000)
384          * (MAX_COLOR_VAL - Black);
385     break;
386   case GRAY:
387     *g = Gray;
388     break;
389   default:
390     assert(0);
391     break;
392   }
393 }
394
395 char *color::print_color()
396 {
397   char *s = new char[30];
398   switch (scheme) {
399   case DEFAULT:
400     sprintf(s, "default");
401     break;
402   case RGB:
403     sprintf(s, "rgb %.2ff %.2ff %.2ff",
404             double(Red) / MAX_COLOR_VAL,
405             double(Green) / MAX_COLOR_VAL,
406             double(Blue) / MAX_COLOR_VAL);
407     break;
408   case CMY:
409     sprintf(s, "cmy %.2ff %.2ff %.2ff",
410             double(Cyan) / MAX_COLOR_VAL,
411             double(Magenta) / MAX_COLOR_VAL,
412             double(Yellow) / MAX_COLOR_VAL);
413     break;
414   case CMYK:
415     sprintf(s, "cmyk %.2ff %.2ff %.2ff %.2ff",
416             double(Cyan) / MAX_COLOR_VAL,
417             double(Magenta) / MAX_COLOR_VAL,
418             double(Yellow) / MAX_COLOR_VAL,
419             double(Black) / MAX_COLOR_VAL);
420     break;
421   case GRAY:
422     sprintf(s, "gray %.2ff",
423             double(Gray) / MAX_COLOR_VAL);
424     break;
425   }
426   return s;
427 }
428
429 color default_color;