Fix catalan translation
[geany-mirror.git] / scintilla / src / XPM.cxx
blobc2b308acb725b9c641746c46721d97969be0e6ef
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.
8 #include <stdlib.h>
9 #include <string.h>
11 #include <vector>
12 #include <map>
14 #include "Platform.h"
16 #include "XPM.h"
18 #ifdef SCI_NAMESPACE
19 using namespace Scintilla;
20 #endif
22 static const char *NextField(const char *s) {
23 // In case there are leading spaces in the string
24 while (*s && *s == ' ') {
25 s++;
27 while (*s && *s != ' ') {
28 s++;
30 while (*s && *s == ' ') {
31 s++;
33 return s;
36 // Data lines in XPM can be terminated either with NUL or "
37 static size_t MeasureLength(const char *s) {
38 size_t i = 0;
39 while (s[i] && (s[i] != '\"'))
40 i++;
41 return i;
44 ColourDesired XPM::ColourFromCode(int ch) const {
45 return colourCodeTable[ch];
48 void XPM::FillRun(Surface *surface, int code, int startX, int y, int x) {
49 if ((code != codeTransparent) && (startX != x)) {
50 PRectangle rc = PRectangle::FromInts(startX, y, x, y + 1);
51 surface->FillRectangle(rc, ColourFromCode(code));
55 XPM::XPM(const char *textForm) {
56 Init(textForm);
59 XPM::XPM(const char *const *linesForm) {
60 Init(linesForm);
63 XPM::~XPM() {
66 void XPM::Init(const char *textForm) {
67 // Test done is two parts to avoid possibility of overstepping the memory
68 // if memcmp implemented strangely. Must be 4 bytes at least at destination.
69 if ((0 == memcmp(textForm, "/* X", 4)) && (0 == memcmp(textForm, "/* XPM */", 9))) {
70 // Build the lines form out of the text form
71 std::vector<const char *> linesForm = LinesFormFromTextForm(textForm);
72 if (!linesForm.empty()) {
73 Init(&linesForm[0]);
75 } else {
76 // It is really in line form
77 Init(reinterpret_cast<const char * const *>(textForm));
81 void XPM::Init(const char *const *linesForm) {
82 height = 1;
83 width = 1;
84 nColours = 1;
85 pixels.clear();
86 codeTransparent = ' ';
87 if (!linesForm)
88 return;
90 std::fill(colourCodeTable, colourCodeTable+256, 0);
91 const char *line0 = linesForm[0];
92 width = atoi(line0);
93 line0 = NextField(line0);
94 height = atoi(line0);
95 pixels.resize(width*height);
96 line0 = NextField(line0);
97 nColours = atoi(line0);
98 line0 = NextField(line0);
99 if (atoi(line0) != 1) {
100 // Only one char per pixel is supported
101 return;
104 for (int c=0; c<nColours; c++) {
105 const char *colourDef = linesForm[c+1];
106 int code = static_cast<unsigned char>(colourDef[0]);
107 colourDef += 4;
108 ColourDesired colour(0xff, 0xff, 0xff);
109 if (*colourDef == '#') {
110 colour.Set(colourDef);
111 } else {
112 codeTransparent = static_cast<char>(code);
114 colourCodeTable[code] = colour;
117 for (int y=0; y<height; y++) {
118 const char *lform = linesForm[y+nColours+1];
119 size_t len = MeasureLength(lform);
120 for (size_t x = 0; x<len; x++)
121 pixels[y * width + x] = static_cast<unsigned char>(lform[x]);
125 void XPM::Draw(Surface *surface, PRectangle &rc) {
126 if (pixels.empty()) {
127 return;
129 // Centre the pixmap
130 int startY = static_cast<int>(rc.top + (rc.Height() - height) / 2);
131 int startX = static_cast<int>(rc.left + (rc.Width() - width) / 2);
132 for (int y=0; y<height; y++) {
133 int prevCode = 0;
134 int xStartRun = 0;
135 for (int x=0; x<width; x++) {
136 int code = pixels[y * width + x];
137 if (code != prevCode) {
138 FillRun(surface, prevCode, startX + xStartRun, startY + y, startX + x);
139 xStartRun = x;
140 prevCode = code;
143 FillRun(surface, prevCode, startX + xStartRun, startY + y, startX + width);
147 void XPM::PixelAt(int x, int y, ColourDesired &colour, bool &transparent) const {
148 if (pixels.empty() || (x<0) || (x >= width) || (y<0) || (y >= height)) {
149 colour = 0;
150 transparent = true;
151 return;
153 int code = pixels[y * width + x];
154 transparent = code == codeTransparent;
155 if (transparent) {
156 colour = 0;
157 } else {
158 colour = ColourFromCode(code).AsLong();
162 std::vector<const char *> XPM::LinesFormFromTextForm(const char *textForm) {
163 // Build the lines form out of the text form
164 std::vector<const char *> linesForm;
165 int countQuotes = 0;
166 int strings=1;
167 int j=0;
168 for (; countQuotes < (2*strings) && textForm[j] != '\0'; j++) {
169 if (textForm[j] == '\"') {
170 if (countQuotes == 0) {
171 // First field: width, height, number of colors, chars per pixel
172 const char *line0 = textForm + j + 1;
173 // Skip width
174 line0 = NextField(line0);
175 // Add 1 line for each pixel of height
176 strings += atoi(line0);
177 line0 = NextField(line0);
178 // Add 1 line for each colour
179 strings += atoi(line0);
181 if (countQuotes / 2 >= strings) {
182 break; // Bad height or number of colors!
184 if ((countQuotes & 1) == 0) {
185 linesForm.push_back(textForm + j + 1);
187 countQuotes++;
190 if (textForm[j] == '\0' || countQuotes / 2 > strings) {
191 // Malformed XPM! Height + number of colors too high or too low
192 linesForm.clear();
194 return linesForm;
197 RGBAImage::RGBAImage(int width_, int height_, float scale_, const unsigned char *pixels_) :
198 height(height_), width(width_), scale(scale_) {
199 if (pixels_) {
200 pixelBytes.assign(pixels_, pixels_ + CountBytes());
201 } else {
202 pixelBytes.resize(CountBytes());
206 RGBAImage::RGBAImage(const XPM &xpm) {
207 height = xpm.GetHeight();
208 width = xpm.GetWidth();
209 scale = 1;
210 pixelBytes.resize(CountBytes());
211 for (int y=0; y<height; y++) {
212 for (int x=0; x<width; x++) {
213 ColourDesired colour;
214 bool transparent = false;
215 xpm.PixelAt(x, y, colour, transparent);
216 SetPixel(x, y, colour, transparent ? 0 : 255);
221 RGBAImage::~RGBAImage() {
224 int RGBAImage::CountBytes() const {
225 return width * height * 4;
228 const unsigned char *RGBAImage::Pixels() const {
229 return &pixelBytes[0];
232 void RGBAImage::SetPixel(int x, int y, ColourDesired colour, int alpha) {
233 unsigned char *pixel = &pixelBytes[0] + (y*width+x) * 4;
234 // RGBA
235 pixel[0] = static_cast<unsigned char>(colour.GetRed());
236 pixel[1] = static_cast<unsigned char>(colour.GetGreen());
237 pixel[2] = static_cast<unsigned char>(colour.GetBlue());
238 pixel[3] = static_cast<unsigned char>(alpha);
241 RGBAImageSet::RGBAImageSet() : height(-1), width(-1) {
244 RGBAImageSet::~RGBAImageSet() {
245 Clear();
248 /// Remove all images.
249 void RGBAImageSet::Clear() {
250 for (ImageMap::iterator it=images.begin(); it != images.end(); ++it) {
251 delete it->second;
252 it->second = 0;
254 images.clear();
255 height = -1;
256 width = -1;
259 /// Add an image.
260 void RGBAImageSet::Add(int ident, RGBAImage *image) {
261 ImageMap::iterator it=images.find(ident);
262 if (it == images.end()) {
263 images[ident] = image;
264 } else {
265 delete it->second;
266 it->second = image;
268 height = -1;
269 width = -1;
272 /// Get image by id.
273 RGBAImage *RGBAImageSet::Get(int ident) {
274 ImageMap::iterator it = images.find(ident);
275 if (it != images.end()) {
276 return it->second;
278 return NULL;
281 /// Give the largest height of the set.
282 int RGBAImageSet::GetHeight() const {
283 if (height < 0) {
284 for (ImageMap::const_iterator it=images.begin(); it != images.end(); ++it) {
285 if (height < it->second->GetHeight()) {
286 height = it->second->GetHeight();
290 return (height > 0) ? height : 0;
293 /// Give the largest width of the set.
294 int RGBAImageSet::GetWidth() const {
295 if (width < 0) {
296 for (ImageMap::const_iterator it=images.begin(); it != images.end(); ++it) {
297 if (width < it->second->GetWidth()) {
298 width = it->second->GetWidth();
302 return (width > 0) ? width : 0;