]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/XPM.cxx
e693736a21c3e50831cf2d876b91d523d43f4037
[wxWidgets.git] / src / stc / scintilla / src / XPM.cxx
1 // Scintilla source code edit control
2 /** @file XPM.cxx
3 ** Define a class that holds data in the X Pixmap (XPM) format.
4 **/
5 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
7
8 #include <string.h>
9 #include <stdlib.h>
10
11 #include "Platform.h"
12
13 #include "XPM.h"
14
15 static const char *NextField(const char *s) {
16 while (*s && *s != ' ') {
17 s++;
18 }
19 while (*s && *s == ' ') {
20 s++;
21 }
22 return s;
23 }
24
25 // Data lines in XPM can be terminated either with NUL or "
26 static size_t MeasureLength(const char *s) {
27 size_t i = 0;
28 while (s[i] && (s[i] != '\"'))
29 i++;
30 return i;
31 }
32
33 ColourAllocated XPM::ColourFromCode(int ch) {
34 return colourCodeTable[ch]->allocated;
35 #ifdef SLOW
36 for (int i=0; i<nColours; i++) {
37 if (codes[i] == ch) {
38 return colours[i].allocated;
39 }
40 }
41 return colours[0].allocated;
42 #endif
43 }
44
45 void XPM::FillRun(Surface *surface, int code, int startX, int y, int x) {
46 if ((code != codeTransparent) && (startX != x)) {
47 PRectangle rc(startX, y, x, y+1);
48 surface->FillRectangle(rc, ColourFromCode(code));
49 }
50 }
51
52 XPM::XPM(const char *textForm) :
53 data(0), codes(0), colours(0), lines(0) {
54 Init(textForm);
55 }
56
57 XPM::XPM(const char * const *linesForm) :
58 data(0), codes(0), colours(0), lines(0) {
59 Init(linesForm);
60 }
61
62 XPM::~XPM() {
63 Clear();
64 }
65
66 void XPM::Init(const char *textForm) {
67 Clear();
68 // Test done is two parts to avoid possibility of overstepping the memory
69 // if memcmp implemented strangely. Must be 4 bytes at least at destination.
70 if ((0 == memcmp(textForm, "/* X", 4)) && (0 == memcmp(textForm, "/* XPM */", 9))) {
71 // Build the lines form out of the text form
72 const char **linesForm = LinesFormFromTextForm(textForm);
73 Init(linesForm);
74 delete []linesForm;
75 } else {
76 // It is really in line form
77 Init(reinterpret_cast<const char * const *>(textForm));
78 }
79 }
80
81 void XPM::Init(const char * const *linesForm) {
82 Clear();
83 height = 1;
84 width = 1;
85 nColours = 1;
86 data = NULL;
87 codeTransparent = ' ';
88 codes = NULL;
89 colours = NULL;
90 lines = NULL;
91 if (!linesForm)
92 return;
93
94 const char *line0 = linesForm[0];
95 width = atoi(line0);
96 line0 = NextField(line0);
97 height = atoi(line0);
98 line0 = NextField(line0);
99 nColours = atoi(line0);
100 codes = new char[nColours];
101 colours = new ColourPair[nColours];
102
103 int strings = 1+height+nColours;
104 lines = new char *[strings];
105 size_t allocation = 0;
106 for (int i=0; i<strings; i++) {
107 allocation += MeasureLength(linesForm[i]) + 1;
108 }
109 data = new char[allocation];
110 char *nextBit = data;
111 for (int j=0; j<strings; j++) {
112 lines[j] = nextBit;
113 size_t len = MeasureLength(linesForm[j]);
114 memcpy(nextBit, linesForm[j], len);
115 nextBit += len;
116 *nextBit++ = '\0';
117 }
118
119 for (int code=0; code<256; code++) {
120 colourCodeTable[code] = 0;
121 }
122
123 for (int c=0; c<nColours; c++) {
124 const char *colourDef = linesForm[c+1];
125 codes[c] = colourDef[0];
126 colourDef += 4;
127 if (*colourDef == '#') {
128 colours[c].desired.Set(colourDef);
129 } else {
130 colours[c].desired = ColourDesired(0xff, 0xff, 0xff);
131 codeTransparent = codes[c];
132 }
133 colourCodeTable[static_cast<unsigned char>(codes[c])] = &(colours[c]);
134 }
135 }
136
137 void XPM::Clear() {
138 delete []data;
139 data = 0;
140 delete []codes;
141 codes = 0;
142 delete []colours;
143 colours = 0;
144 delete []lines;
145 lines = 0;
146 }
147
148 void XPM::RefreshColourPalette(Palette &pal, bool want) {
149 if (!data || !codes || !colours || !lines) {
150 return;
151 }
152 for (int i=0; i<nColours; i++) {
153 pal.WantFind(colours[i], want);
154 }
155 }
156
157 void XPM::CopyDesiredColours() {
158 if (!data || !codes || !colours || !lines) {
159 return;
160 }
161 for (int i=0; i<nColours; i++) {
162 colours[i].Copy();
163 }
164 }
165
166 void XPM::Draw(Surface *surface, PRectangle &rc) {
167 if (!data || !codes || !colours || !lines) {
168 return;
169 }
170 // Centre the pixmap
171 int startY = rc.top + (rc.Height() - height) / 2;
172 int startX = rc.left + (rc.Width() - width) / 2;
173 for (int y=0;y<height;y++) {
174 int prevCode = 0;
175 int xStartRun = 0;
176 for (int x=0; x<width; x++) {
177 int code = lines[y+nColours+1][x];
178 if (code != prevCode) {
179 FillRun(surface, prevCode, startX + xStartRun, startY + y, startX + x);
180 xStartRun = x;
181 prevCode = code;
182 }
183 }
184 FillRun(surface, prevCode, startX + xStartRun, startY + y, startX + width);
185 }
186 }
187
188 const char **XPM::LinesFormFromTextForm(const char *textForm) {
189 // Build the lines form out of the text form
190 const char **linesForm = 0;
191 int countQuotes = 0;
192 int strings=1;
193 for (int j=0; countQuotes < (2*strings); j++) {
194 if (textForm[j] == '\"') {
195 if (countQuotes == 0) {
196 const char *line0 = textForm + j + 1;
197 // Skip width
198 line0 = NextField(line0);
199 // Add 1 line for each pixel of height
200 strings += atoi(line0);
201 line0 = NextField(line0);
202 // Add 1 line for each colour
203 strings += atoi(line0);
204 linesForm = new const char *[strings];
205 }
206 if (linesForm && ((countQuotes & 1) == 0)) {
207 linesForm[countQuotes / 2] = textForm + j + 1;
208 }
209 countQuotes++;
210 }
211 }
212 return linesForm;
213 }
214
215 // In future, may want to minimize search time by sorting and using a binary search.
216
217 XPMSet::XPMSet() : set(0), len(0), maximum(0), height(-1), width(-1) {
218 }
219
220 XPMSet::~XPMSet() {
221 Clear();
222 }
223
224 void XPMSet::Clear() {
225 for (int i = 0; i < len; i++) {
226 delete set[i];
227 }
228 delete []set;
229 set = 0;
230 len = 0;
231 maximum = 0;
232 height = -1;
233 width = -1;
234 }
235
236 void XPMSet::Add(int id, const char *textForm) {
237 // Invalidate cached dimensions
238 height = -1;
239 width = -1;
240
241 // Replace if this id already present
242 for (int i = 0; i < len; i++) {
243 if (set[i]->GetId() == id) {
244 set[i]->Init(textForm);
245 return;
246 }
247 }
248
249 // Not present, so add to end
250 XPM *pxpm = new XPM(textForm);
251 if (pxpm) {
252 pxpm->SetId(id);
253 pxpm->CopyDesiredColours();
254 if (len == maximum) {
255 maximum += 64;
256 XPM **setNew = new XPM *[maximum];
257 for (int i = 0; i < len; i++) {
258 setNew[i] = set[i];
259 }
260 delete []set;
261 set = setNew;
262 }
263 set[len] = pxpm;
264 len++;
265 }
266 }
267
268 XPM *XPMSet::Get(int id) {
269 for (int i = 0; i < len; i++) {
270 if (set[i]->GetId() == id) {
271 return set[i];
272 }
273 }
274 return 0;
275 }
276
277 int XPMSet::GetHeight() {
278 if (height < 0) {
279 for (int i = 0; i < len; i++) {
280 if (height < set[i]->GetHeight()) {
281 height = set[i]->GetHeight();
282 }
283 }
284 }
285 return (height > 0) ? height : 0;
286 }
287
288 int XPMSet::GetWidth() {
289 if (width < 0) {
290 for (int i = 0; i < len; i++) {
291 if (width < set[i]->GetWidth()) {
292 width = set[i]->GetWidth();
293 }
294 }
295 }
296 return (width > 0) ? width : 0;
297 }