OSDN Git Service

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