1 /*
2  * Copyright (C) 2000, Matias Atria
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include <config.h>
20 #include "mdvi.h"
21 #include "color.h"
22 
mdvi_set_color(DviContext * dvi,Ulong fg,Ulong bg)23 void	mdvi_set_color(DviContext *dvi, Ulong fg, Ulong bg)
24 {
25 	if(dvi->curr_fg != fg || dvi->curr_bg != bg) {
26 		DEBUG((DBG_DEVICE, "setting color to (%lu,%lu)\n", fg, bg));
27 		if(dvi->device.set_color)
28 			dvi->device.set_color(dvi->device.device_data, fg, bg);
29 		dvi->curr_fg = fg;
30 		dvi->curr_bg = bg;
31 	}
32 }
33 
mdvi_push_color(DviContext * dvi,Ulong fg,Ulong bg)34 void	mdvi_push_color(DviContext *dvi, Ulong fg, Ulong bg)
35 {
36 	if(dvi->color_top == dvi->color_size) {
37 		dvi->color_size += 32;
38 		dvi->color_stack = mdvi_realloc(dvi->color_stack,
39 			dvi->color_size * sizeof(DviColorPair));
40 	}
41 	dvi->color_stack[dvi->color_top].fg = dvi->curr_fg;
42 	dvi->color_stack[dvi->color_top].bg = dvi->curr_bg;
43 	dvi->color_top++;
44 	mdvi_set_color(dvi, fg, bg);
45 }
46 
mdvi_pop_color(DviContext * dvi)47 void	mdvi_pop_color(DviContext *dvi)
48 {
49 	Ulong	fg, bg;
50 
51 	if(dvi->color_top == 0)
52 		return;
53 	dvi->color_top--;
54 	fg = dvi->color_stack[dvi->color_top].fg;
55 	bg = dvi->color_stack[dvi->color_top].bg;
56 	mdvi_set_color(dvi, fg, bg);
57 }
58 
mdvi_reset_color(DviContext * dvi)59 void	mdvi_reset_color(DviContext *dvi)
60 {
61 	dvi->color_top = 0;
62 	mdvi_set_color(dvi, dvi->params.fg, dvi->params.bg);
63 }
64 
65 /* cache for color tables, to avoid creating them for every glyph */
66 typedef struct {
67 	Ulong	fg;
68 	Ulong	bg;
69 	Uint	nlevels;
70 	Ulong	*pixels;
71 	int	density;
72 	double	gamma;
73 	Uint	hits;
74 } ColorCache;
75 
76 #define CCSIZE		256
77 static ColorCache	color_cache[CCSIZE];
78 static int		cc_entries;
79 
80 #define GAMMA_DIFF	0.005
81 
82 
83 /* create a color table */
get_color_table(DviDevice * dev,int nlevels,Ulong fg,Ulong bg,double gamma,int density)84 Ulong	*get_color_table(DviDevice *dev,
85 			 int nlevels, Ulong fg, Ulong bg, double gamma, int density)
86 {
87 	ColorCache	*cc, *tofree;
88 	int		lohits;
89 	Ulong		*pixels;
90 	int		status;
91 
92 	lohits = color_cache[0].hits;
93 	tofree = &color_cache[0];
94 	/* look in the cache and see if we have one that matches this request */
95 	for(cc = &color_cache[0]; cc < &color_cache[cc_entries]; cc++) {
96 		if(cc->hits < lohits) {
97 			lohits = cc->hits;
98 			tofree = cc;
99 		}
100 		if(cc->fg == fg && cc->bg == bg && cc->density == density &&
101 		   cc->nlevels == nlevels && fabs(cc->gamma - gamma) <= GAMMA_DIFF)
102 		   	break;
103 	}
104 
105 	if(cc < &color_cache[cc_entries]) {
106 		cc->hits++;
107 		return cc->pixels;
108 	}
109 
110 	DEBUG((DBG_DEVICE, "Adding color table to cache (fg=%lu, bg=%lu, n=%d)\n",
111 		fg, bg, nlevels));
112 
113 	/* no entry was found in the cache, create a new one */
114 	if(cc_entries < CCSIZE) {
115 		cc = &color_cache[cc_entries++];
116 		cc->pixels = NULL;
117 	} else {
118 		cc = tofree;
119 		mdvi_free(cc->pixels);
120 	}
121 	pixels = xnalloc(Ulong, nlevels);
122 	status = dev->alloc_colors(dev->device_data,
123 		pixels, nlevels, fg, bg, gamma, density);
124 	if(status < 0) {
125 		mdvi_free(pixels);
126 		return NULL;
127 	}
128 	cc->fg = fg;
129 	cc->bg = bg;
130 	cc->gamma = gamma;
131 	cc->density = density;
132 	cc->nlevels = nlevels;
133 	cc->pixels = pixels;
134 	cc->hits = 1;
135 	return pixels;
136 }
137