xref: /haiku/src/libs/icon/flat_icon/FlatIconImporter.cpp (revision 1a948d749b39e70000afb011e02a59ee595aee1f)
1fb07ece0SStephan Aßmus /*
2fb07ece0SStephan Aßmus  * Copyright 2006, Haiku. All rights reserved.
3fb07ece0SStephan Aßmus  * Distributed under the terms of the MIT License.
4fb07ece0SStephan Aßmus  *
5fb07ece0SStephan Aßmus  * Authors:
6fb07ece0SStephan Aßmus  *		Stephan Aßmus <superstippi@gmx.de>
7fb07ece0SStephan Aßmus  */
8fb07ece0SStephan Aßmus 
9fb07ece0SStephan Aßmus #include "FlatIconImporter.h"
10fb07ece0SStephan Aßmus 
11fb07ece0SStephan Aßmus #include <new>
12fb07ece0SStephan Aßmus #include <stdio.h>
13fb07ece0SStephan Aßmus 
14fb07ece0SStephan Aßmus #include <Archivable.h>
15fb07ece0SStephan Aßmus #include <DataIO.h>
16fb07ece0SStephan Aßmus #include <Message.h>
17fb07ece0SStephan Aßmus 
18fb07ece0SStephan Aßmus #include "AffineTransformer.h"
19fb07ece0SStephan Aßmus #include "AutoDeleter.h"
20fb07ece0SStephan Aßmus #include "ContourTransformer.h"
21fb07ece0SStephan Aßmus #include "FlatIconFormat.h"
22fb07ece0SStephan Aßmus #include "Gradient.h"
23fb07ece0SStephan Aßmus #include "Icon.h"
24fb07ece0SStephan Aßmus #include "LittleEndianBuffer.h"
25fb07ece0SStephan Aßmus #include "PathCommandQueue.h"
26fb07ece0SStephan Aßmus #include "PathContainer.h"
27fb07ece0SStephan Aßmus #include "PerspectiveTransformer.h"
28fb07ece0SStephan Aßmus #include "Shape.h"
29fb07ece0SStephan Aßmus #include "StrokeTransformer.h"
30fb07ece0SStephan Aßmus #include "Style.h"
31fb07ece0SStephan Aßmus #include "StyleContainer.h"
32fb07ece0SStephan Aßmus #include "VectorPath.h"
33fb07ece0SStephan Aßmus 
34fb07ece0SStephan Aßmus using std::nothrow;
35fb07ece0SStephan Aßmus 
36fb07ece0SStephan Aßmus // constructor
37fb07ece0SStephan Aßmus FlatIconImporter::FlatIconImporter()
38014c7e94SStephan Aßmus #ifdef ICON_O_MATIC
39014c7e94SStephan Aßmus 	: Importer()
40014c7e94SStephan Aßmus #endif
41fb07ece0SStephan Aßmus {
42fb07ece0SStephan Aßmus }
43fb07ece0SStephan Aßmus 
44fb07ece0SStephan Aßmus // destructor
45fb07ece0SStephan Aßmus FlatIconImporter::~FlatIconImporter()
46fb07ece0SStephan Aßmus {
47fb07ece0SStephan Aßmus }
48fb07ece0SStephan Aßmus 
49fb07ece0SStephan Aßmus // Import
50fb07ece0SStephan Aßmus status_t
51fb07ece0SStephan Aßmus FlatIconImporter::Import(Icon* icon, BPositionIO* stream)
52fb07ece0SStephan Aßmus {
53014c7e94SStephan Aßmus #ifdef ICON_O_MATIC
54014c7e94SStephan Aßmus 	status_t ret = Init(icon);
55014c7e94SStephan Aßmus 	if (ret < B_OK)
56014c7e94SStephan Aßmus 		return ret;
57014c7e94SStephan Aßmus #else
58014c7e94SStephan Aßmus 	status_t ret;
59014c7e94SStephan Aßmus #endif
60014c7e94SStephan Aßmus 
61fb07ece0SStephan Aßmus 	// seek around in the stream to figure out the size
62fb07ece0SStephan Aßmus 	off_t size = stream->Seek(0, SEEK_END);
63fb07ece0SStephan Aßmus 	if (stream->Seek(0, SEEK_SET) != 0)
64fb07ece0SStephan Aßmus 		return B_ERROR;
65fb07ece0SStephan Aßmus 
66fb07ece0SStephan Aßmus 	// we chicken out on anything larger than 256k
67fb07ece0SStephan Aßmus 	if (size <= 0 || size > 256 * 1024)
68fb07ece0SStephan Aßmus 		return B_BAD_VALUE;
69fb07ece0SStephan Aßmus 
70fb07ece0SStephan Aßmus 	// read the entire stream into a buffer
71fb07ece0SStephan Aßmus 	LittleEndianBuffer buffer(size);
72fb07ece0SStephan Aßmus 	if (!buffer.Buffer())
73fb07ece0SStephan Aßmus 		return B_NO_MEMORY;
74fb07ece0SStephan Aßmus 
75fb07ece0SStephan Aßmus 	if (stream->Read(buffer.Buffer(), size) != size)
76fb07ece0SStephan Aßmus 		return B_ERROR;
77fb07ece0SStephan Aßmus 
78014c7e94SStephan Aßmus 	ret = _ParseSections(buffer, icon);
79fb07ece0SStephan Aßmus 
80fb07ece0SStephan Aßmus 	return ret;
81fb07ece0SStephan Aßmus }
82fb07ece0SStephan Aßmus 
83fb07ece0SStephan Aßmus // Import
84fb07ece0SStephan Aßmus status_t
85fb07ece0SStephan Aßmus FlatIconImporter::Import(Icon* icon, uint8* _buffer, size_t size)
86fb07ece0SStephan Aßmus {
87014c7e94SStephan Aßmus #ifdef ICON_O_MATIC
88014c7e94SStephan Aßmus 	status_t ret = Init(icon);
89014c7e94SStephan Aßmus 	if (ret < B_OK)
90014c7e94SStephan Aßmus 		return ret;
91014c7e94SStephan Aßmus #endif
92014c7e94SStephan Aßmus 
93fb07ece0SStephan Aßmus 	if (!_buffer)
94fb07ece0SStephan Aßmus 		return B_BAD_VALUE;
95fb07ece0SStephan Aßmus 
96fb07ece0SStephan Aßmus 	// attach LittleEndianBuffer to buffer
97fb07ece0SStephan Aßmus 	LittleEndianBuffer buffer(_buffer, size);
98fb07ece0SStephan Aßmus 
99fb07ece0SStephan Aßmus 	return _ParseSections(buffer, icon);
100fb07ece0SStephan Aßmus }
101fb07ece0SStephan Aßmus 
102fb07ece0SStephan Aßmus // #pragma mark -
103fb07ece0SStephan Aßmus 
104fb07ece0SStephan Aßmus // _ParseSections
105fb07ece0SStephan Aßmus status_t
106fb07ece0SStephan Aßmus FlatIconImporter::_ParseSections(LittleEndianBuffer& buffer, Icon* icon)
107fb07ece0SStephan Aßmus {
108fb07ece0SStephan Aßmus 	// test if this is an icon at all
109fb07ece0SStephan Aßmus 	uint32 magic;
110fb07ece0SStephan Aßmus 	if (!buffer.Read(magic) || magic != FLAT_ICON_MAGIC)
111*1a948d74SAxel Dörfler 		return B_BAD_TYPE;
112fb07ece0SStephan Aßmus 
113fb07ece0SStephan Aßmus 	// styles
114fb07ece0SStephan Aßmus 	StyleContainer* styles = icon->Styles();
115fb07ece0SStephan Aßmus 	status_t ret = _ParseStyles(buffer, styles);
116fb07ece0SStephan Aßmus 	if (ret < B_OK) {
117fb07ece0SStephan Aßmus 		printf("FlatIconImporter::_ParseSections() - "
118fb07ece0SStephan Aßmus 			   "error parsing styles: %s\n", strerror(ret));
119fb07ece0SStephan Aßmus 		return ret;
120fb07ece0SStephan Aßmus 	}
121fb07ece0SStephan Aßmus 
122fb07ece0SStephan Aßmus 	// paths
123fb07ece0SStephan Aßmus 	PathContainer* paths = icon->Paths();
124fb07ece0SStephan Aßmus 	ret = _ParsePaths(buffer, paths);
125fb07ece0SStephan Aßmus 	if (ret < B_OK) {
126fb07ece0SStephan Aßmus 		printf("FlatIconImporter::_ParseSections() - "
127fb07ece0SStephan Aßmus 			   "error parsing paths: %s\n", strerror(ret));
128fb07ece0SStephan Aßmus 		return ret;
129fb07ece0SStephan Aßmus 	}
130fb07ece0SStephan Aßmus 
131fb07ece0SStephan Aßmus 	// shapes
132fb07ece0SStephan Aßmus 	ret = _ParseShapes(buffer, styles, paths, icon->Shapes());
133fb07ece0SStephan Aßmus 	if (ret < B_OK) {
134fb07ece0SStephan Aßmus 		printf("FlatIconImporter::_ParseSections() - "
135fb07ece0SStephan Aßmus 			   "error parsing shapes: %s\n", strerror(ret));
136fb07ece0SStephan Aßmus 		return ret;
137fb07ece0SStephan Aßmus 	}
138fb07ece0SStephan Aßmus 
139fb07ece0SStephan Aßmus 	return B_OK;
140fb07ece0SStephan Aßmus }
141fb07ece0SStephan Aßmus 
142fb07ece0SStephan Aßmus // _ReadTransformable
143fb07ece0SStephan Aßmus static bool
144fb07ece0SStephan Aßmus _ReadTransformable(LittleEndianBuffer& buffer, Transformable* transformable)
145fb07ece0SStephan Aßmus {
146fb07ece0SStephan Aßmus 	int32 matrixSize = Transformable::matrix_size;
147fb07ece0SStephan Aßmus 	double matrix[matrixSize];
148fb07ece0SStephan Aßmus 	for (int32 i = 0; i < matrixSize; i++) {
149fb07ece0SStephan Aßmus 		float value;
150fb07ece0SStephan Aßmus 		if (!read_float_24(buffer, value))
151fb07ece0SStephan Aßmus 			return false;
152fb07ece0SStephan Aßmus 		matrix[i] = value;
153fb07ece0SStephan Aßmus 	}
154fb07ece0SStephan Aßmus 	transformable->LoadFrom(matrix);
155fb07ece0SStephan Aßmus 	return true;
156fb07ece0SStephan Aßmus }
157fb07ece0SStephan Aßmus 
158fb07ece0SStephan Aßmus // _ReadTranslation
159fb07ece0SStephan Aßmus static bool
160fb07ece0SStephan Aßmus _ReadTranslation(LittleEndianBuffer& buffer, Transformable* transformable)
161fb07ece0SStephan Aßmus {
162fb07ece0SStephan Aßmus 	BPoint t;
163fb07ece0SStephan Aßmus 	if (read_coord(buffer, t.x) && read_coord(buffer, t.y)) {
164fb07ece0SStephan Aßmus 		transformable->TranslateBy(t);
165fb07ece0SStephan Aßmus 		return true;
166fb07ece0SStephan Aßmus 	}
167fb07ece0SStephan Aßmus 
168fb07ece0SStephan Aßmus 	return false;
169fb07ece0SStephan Aßmus }
170fb07ece0SStephan Aßmus 
171fb07ece0SStephan Aßmus // _ReadColorStyle
172fb07ece0SStephan Aßmus static Style*
1732f953b71SStephan Aßmus _ReadColorStyle(LittleEndianBuffer& buffer, bool alpha, bool gray)
174fb07ece0SStephan Aßmus {
175fb07ece0SStephan Aßmus 	rgb_color color;
176fb07ece0SStephan Aßmus 	if (alpha) {
1772f953b71SStephan Aßmus 		if (gray) {
1782f953b71SStephan Aßmus 			if (!buffer.Read(color.red)
1792f953b71SStephan Aßmus 				|| !buffer.Read(color.alpha))
1802f953b71SStephan Aßmus 				return NULL;
1812f953b71SStephan Aßmus 			color.green = color.blue = color.red;
1822f953b71SStephan Aßmus 		} else {
183fb07ece0SStephan Aßmus 			if (!buffer.Read((uint32&)color))
184fb07ece0SStephan Aßmus 				return NULL;
1852f953b71SStephan Aßmus 		}
186fb07ece0SStephan Aßmus 	} else {
187fb07ece0SStephan Aßmus 		color.alpha = 255;
1882f953b71SStephan Aßmus 		if (gray) {
1892f953b71SStephan Aßmus 			if (!buffer.Read(color.red))
1902f953b71SStephan Aßmus 				return NULL;
1912f953b71SStephan Aßmus 			color.green = color.blue = color.red;
1922f953b71SStephan Aßmus 		} else {
193fb07ece0SStephan Aßmus 			if (!buffer.Read(color.red)
194fb07ece0SStephan Aßmus 				|| !buffer.Read(color.green)
195fb07ece0SStephan Aßmus 				|| !buffer.Read(color.blue))
196fb07ece0SStephan Aßmus 				return NULL;
197fb07ece0SStephan Aßmus 		}
1982f953b71SStephan Aßmus 	}
199fb07ece0SStephan Aßmus 	return new (nothrow) Style(color);
200fb07ece0SStephan Aßmus }
201fb07ece0SStephan Aßmus 
202fb07ece0SStephan Aßmus // _ReadGradientStyle
203fb07ece0SStephan Aßmus static Style*
204fb07ece0SStephan Aßmus _ReadGradientStyle(LittleEndianBuffer& buffer)
205fb07ece0SStephan Aßmus {
206fb07ece0SStephan Aßmus 	Style* style = new (nothrow) Style();
207fb07ece0SStephan Aßmus 	if (!style)
208fb07ece0SStephan Aßmus 		return NULL;
209fb07ece0SStephan Aßmus 
210fb07ece0SStephan Aßmus 	ObjectDeleter<Style> styleDeleter(style);
211fb07ece0SStephan Aßmus 
212fb07ece0SStephan Aßmus 	uint8 gradientType;
213fb07ece0SStephan Aßmus 	uint8 gradientFlags;
214fb07ece0SStephan Aßmus 	uint8 gradientStopCount;
215fb07ece0SStephan Aßmus 	if (!buffer.Read(gradientType)
216fb07ece0SStephan Aßmus 		|| !buffer.Read(gradientFlags)
217fb07ece0SStephan Aßmus 		|| !buffer.Read(gradientStopCount)) {
218fb07ece0SStephan Aßmus 		return NULL;
219fb07ece0SStephan Aßmus 	}
220fb07ece0SStephan Aßmus 
221fb07ece0SStephan Aßmus 	Gradient gradient(true);
222fb07ece0SStephan Aßmus 		// empty gradient
223fb07ece0SStephan Aßmus 
224fb07ece0SStephan Aßmus 	gradient.SetType((gradient_type)gradientType);
225fb07ece0SStephan Aßmus 	// TODO: support more stuff with flags
226fb07ece0SStephan Aßmus 	// ("inherits transformation" and so on)
227fb07ece0SStephan Aßmus 	if (gradientFlags & GRADIENT_FLAG_TRANSFORM) {
228fb07ece0SStephan Aßmus 		if (!_ReadTransformable(buffer, &gradient))
229fb07ece0SStephan Aßmus 			return NULL;
230fb07ece0SStephan Aßmus 	}
231fb07ece0SStephan Aßmus 
232fb07ece0SStephan Aßmus 	bool alpha = !(gradientFlags & GRADIENT_FLAG_NO_ALPHA);
2332f953b71SStephan Aßmus 	bool gray = gradientFlags & GRADIENT_FLAG_GRAYS;
234fb07ece0SStephan Aßmus 
235fb07ece0SStephan Aßmus 	for (int32 i = 0; i < gradientStopCount; i++) {
236fb07ece0SStephan Aßmus 		uint8 stopOffset;
237fb07ece0SStephan Aßmus 		rgb_color color;
238fb07ece0SStephan Aßmus 
239fb07ece0SStephan Aßmus 		if (!buffer.Read(stopOffset))
240fb07ece0SStephan Aßmus 			return NULL;
241fb07ece0SStephan Aßmus 
242fb07ece0SStephan Aßmus 		if (alpha) {
2432f953b71SStephan Aßmus 			if (gray) {
2442f953b71SStephan Aßmus 				if (!buffer.Read(color.red)
2452f953b71SStephan Aßmus 					|| !buffer.Read(color.alpha))
2462f953b71SStephan Aßmus 					return NULL;
2472f953b71SStephan Aßmus 				color.green = color.blue = color.red;
2482f953b71SStephan Aßmus 			} else {
249fb07ece0SStephan Aßmus 				if (!buffer.Read((uint32&)color))
250fb07ece0SStephan Aßmus 					return NULL;
2512f953b71SStephan Aßmus 			}
252fb07ece0SStephan Aßmus 		} else {
253fb07ece0SStephan Aßmus 			color.alpha = 255;
2542f953b71SStephan Aßmus 			if (gray) {
2552f953b71SStephan Aßmus 				if (!buffer.Read(color.red))
2562f953b71SStephan Aßmus 					return NULL;
2572f953b71SStephan Aßmus 				color.green = color.blue = color.red;
2582f953b71SStephan Aßmus 			} else {
259fb07ece0SStephan Aßmus 				if (!buffer.Read(color.red)
260fb07ece0SStephan Aßmus 					|| !buffer.Read(color.green)
261fb07ece0SStephan Aßmus 					|| !buffer.Read(color.blue)) {
262fb07ece0SStephan Aßmus 					return NULL;
263fb07ece0SStephan Aßmus 				}
264fb07ece0SStephan Aßmus 			}
2652f953b71SStephan Aßmus 		}
266fb07ece0SStephan Aßmus 
267fb07ece0SStephan Aßmus 		gradient.AddColor(color, stopOffset / 255.0);
268fb07ece0SStephan Aßmus 	}
269fb07ece0SStephan Aßmus 
270fb07ece0SStephan Aßmus 	style->SetGradient(&gradient);
271fb07ece0SStephan Aßmus 
272fb07ece0SStephan Aßmus 	styleDeleter.Detach();
273fb07ece0SStephan Aßmus 	return style;
274fb07ece0SStephan Aßmus }
275fb07ece0SStephan Aßmus 
276fb07ece0SStephan Aßmus // _ParseStyles
277fb07ece0SStephan Aßmus status_t
278fb07ece0SStephan Aßmus FlatIconImporter::_ParseStyles(LittleEndianBuffer& buffer,
279fb07ece0SStephan Aßmus 							   StyleContainer* styles)
280fb07ece0SStephan Aßmus {
281fb07ece0SStephan Aßmus 	uint8 styleCount;
282fb07ece0SStephan Aßmus 	if (!buffer.Read(styleCount))
283fb07ece0SStephan Aßmus 		return B_ERROR;
284fb07ece0SStephan Aßmus 
285fb07ece0SStephan Aßmus 	for (int32 i = 0; i < styleCount; i++) {
286fb07ece0SStephan Aßmus 		uint8 styleType;
287fb07ece0SStephan Aßmus 		if (!buffer.Read(styleType))
288fb07ece0SStephan Aßmus 			return B_ERROR;
289fb07ece0SStephan Aßmus 		Style* style = NULL;
29070f4b8c0SStephan Aßmus 		if (styleType == STYLE_TYPE_SOLID_COLOR) {
291fb07ece0SStephan Aßmus 			// solid color
2922f953b71SStephan Aßmus 			style = _ReadColorStyle(buffer, true, false);
293fb07ece0SStephan Aßmus 			if (!style)
294fb07ece0SStephan Aßmus 				return B_NO_MEMORY;
29570f4b8c0SStephan Aßmus 		} else if (styleType == STYLE_TYPE_SOLID_COLOR_NO_ALPHA) {
296fb07ece0SStephan Aßmus 			// solid color without alpha
2972f953b71SStephan Aßmus 			style = _ReadColorStyle(buffer, false, false);
2982f953b71SStephan Aßmus 			if (!style)
2992f953b71SStephan Aßmus 				return B_NO_MEMORY;
3002f953b71SStephan Aßmus 		} else if (styleType == STYLE_TYPE_SOLID_GRAY) {
3012f953b71SStephan Aßmus 			// solid gray plus alpha
3022f953b71SStephan Aßmus 			style = _ReadColorStyle(buffer, true, true);
3032f953b71SStephan Aßmus 			if (!style)
3042f953b71SStephan Aßmus 				return B_NO_MEMORY;
3052f953b71SStephan Aßmus 		} else if (styleType == STYLE_TYPE_SOLID_GRAY_NO_ALPHA) {
3062f953b71SStephan Aßmus 			// solid gray without alpha
3072f953b71SStephan Aßmus 			style = _ReadColorStyle(buffer, false, true);
308fb07ece0SStephan Aßmus 			if (!style)
309fb07ece0SStephan Aßmus 				return B_NO_MEMORY;
31070f4b8c0SStephan Aßmus 		} else if (styleType == STYLE_TYPE_GRADIENT) {
311fb07ece0SStephan Aßmus 			// gradient
312fb07ece0SStephan Aßmus 			style = _ReadGradientStyle(buffer);
313fb07ece0SStephan Aßmus 			if (!style)
314fb07ece0SStephan Aßmus 				return B_NO_MEMORY;
315fb07ece0SStephan Aßmus 		} else {
316fb07ece0SStephan Aßmus 			// unkown style type, skip tag
317fb07ece0SStephan Aßmus 			uint16 tagLength;
318fb07ece0SStephan Aßmus 			if (!buffer.Read(tagLength))
319fb07ece0SStephan Aßmus 				return B_ERROR;
320fb07ece0SStephan Aßmus 			buffer.Skip(tagLength);
321fb07ece0SStephan Aßmus 			continue;
322fb07ece0SStephan Aßmus 		}
323fb07ece0SStephan Aßmus 		// add style if we were able to read one
324fb07ece0SStephan Aßmus 		if (style && !styles->AddStyle(style)) {
325fb07ece0SStephan Aßmus 			delete style;
326fb07ece0SStephan Aßmus 			return B_NO_MEMORY;
327fb07ece0SStephan Aßmus 		}
328fb07ece0SStephan Aßmus 	}
329fb07ece0SStephan Aßmus 
330fb07ece0SStephan Aßmus 	return B_OK;
331fb07ece0SStephan Aßmus }
332fb07ece0SStephan Aßmus 
333fb07ece0SStephan Aßmus // read_path_no_curves
334fb07ece0SStephan Aßmus static bool
335fb07ece0SStephan Aßmus read_path_no_curves(LittleEndianBuffer& buffer, VectorPath* path,
336fb07ece0SStephan Aßmus 					uint8 pointCount)
337fb07ece0SStephan Aßmus {
338fb07ece0SStephan Aßmus 	for (uint32 p = 0; p < pointCount; p++) {
339fb07ece0SStephan Aßmus 		BPoint point;
340fb07ece0SStephan Aßmus 		if (!read_coord(buffer, point.x)
341fb07ece0SStephan Aßmus 			|| !read_coord(buffer, point.y))
342fb07ece0SStephan Aßmus 			return false;
343fb07ece0SStephan Aßmus 
344fb07ece0SStephan Aßmus 		if (!path->AddPoint(point))
345fb07ece0SStephan Aßmus 			return false;
346fb07ece0SStephan Aßmus 	}
347fb07ece0SStephan Aßmus 	return true;
348fb07ece0SStephan Aßmus }
349fb07ece0SStephan Aßmus 
350fb07ece0SStephan Aßmus // read_path_curves
351fb07ece0SStephan Aßmus static bool
352fb07ece0SStephan Aßmus read_path_curves(LittleEndianBuffer& buffer, VectorPath* path,
353fb07ece0SStephan Aßmus 				 uint8 pointCount)
354fb07ece0SStephan Aßmus {
355fb07ece0SStephan Aßmus 	for (uint32 p = 0; p < pointCount; p++) {
356fb07ece0SStephan Aßmus 		BPoint point;
357fb07ece0SStephan Aßmus 		if (!read_coord(buffer, point.x)
358fb07ece0SStephan Aßmus 			|| !read_coord(buffer, point.y))
359fb07ece0SStephan Aßmus 			return false;
360fb07ece0SStephan Aßmus 
361fb07ece0SStephan Aßmus 		BPoint pointIn;
362fb07ece0SStephan Aßmus 		if (!read_coord(buffer, pointIn.x)
363fb07ece0SStephan Aßmus 			|| !read_coord(buffer, pointIn.y))
364fb07ece0SStephan Aßmus 			return false;
365fb07ece0SStephan Aßmus 
366fb07ece0SStephan Aßmus 		BPoint pointOut;
367fb07ece0SStephan Aßmus 		if (!read_coord(buffer, pointOut.x)
368fb07ece0SStephan Aßmus 			|| !read_coord(buffer, pointOut.y))
369fb07ece0SStephan Aßmus 			return false;
370fb07ece0SStephan Aßmus 
371fb07ece0SStephan Aßmus 		if (!path->AddPoint(point, pointIn, pointOut, false))
372fb07ece0SStephan Aßmus 			return false;
373fb07ece0SStephan Aßmus 	}
374fb07ece0SStephan Aßmus 	return true;
375fb07ece0SStephan Aßmus }
376fb07ece0SStephan Aßmus 
377fb07ece0SStephan Aßmus // read_path_with_commands
378fb07ece0SStephan Aßmus static bool
379fb07ece0SStephan Aßmus read_path_with_commands(LittleEndianBuffer& buffer, VectorPath* path,
380fb07ece0SStephan Aßmus 						uint8 pointCount)
381fb07ece0SStephan Aßmus {
382fb07ece0SStephan Aßmus 	PathCommandQueue queue;
383fb07ece0SStephan Aßmus 	return queue.Read(buffer, path, pointCount);
384fb07ece0SStephan Aßmus }
385fb07ece0SStephan Aßmus 
386fb07ece0SStephan Aßmus 
387fb07ece0SStephan Aßmus // _ParsePaths
388fb07ece0SStephan Aßmus status_t
389fb07ece0SStephan Aßmus FlatIconImporter::_ParsePaths(LittleEndianBuffer& buffer,
390fb07ece0SStephan Aßmus 							  PathContainer* paths)
391fb07ece0SStephan Aßmus {
392fb07ece0SStephan Aßmus 	uint8 pathCount;
393fb07ece0SStephan Aßmus 	if (!buffer.Read(pathCount))
394fb07ece0SStephan Aßmus 		return B_ERROR;
395fb07ece0SStephan Aßmus 
396fb07ece0SStephan Aßmus 	for (int32 i = 0; i < pathCount; i++) {
397fb07ece0SStephan Aßmus 		uint8 pathFlags;
398fb07ece0SStephan Aßmus 		uint8 pointCount;
399fb07ece0SStephan Aßmus 		if (!buffer.Read(pathFlags) || !buffer.Read(pointCount))
400fb07ece0SStephan Aßmus 			return B_ERROR;
401fb07ece0SStephan Aßmus 
402fb07ece0SStephan Aßmus 		VectorPath* path = new (nothrow) VectorPath();
403fb07ece0SStephan Aßmus 		if (!path)
404fb07ece0SStephan Aßmus 			return B_NO_MEMORY;
405fb07ece0SStephan Aßmus 
406fb07ece0SStephan Aßmus 		// chose path reading strategy depending on path flags
407fb07ece0SStephan Aßmus 		bool error = false;
40870f4b8c0SStephan Aßmus 		if (pathFlags & PATH_FLAG_NO_CURVES) {
409fb07ece0SStephan Aßmus 			if (!read_path_no_curves(buffer, path, pointCount))
410fb07ece0SStephan Aßmus 				error = true;
41170f4b8c0SStephan Aßmus 		} else if (pathFlags & PATH_FLAG_USES_COMMANDS) {
412fb07ece0SStephan Aßmus 			if (!read_path_with_commands(buffer, path, pointCount))
413fb07ece0SStephan Aßmus 				error = true;
414fb07ece0SStephan Aßmus 		} else {
415fb07ece0SStephan Aßmus 			if (!read_path_curves(buffer, path, pointCount))
416fb07ece0SStephan Aßmus 				error = true;
417fb07ece0SStephan Aßmus 		}
418fb07ece0SStephan Aßmus 
419fb07ece0SStephan Aßmus 		if (error) {
420fb07ece0SStephan Aßmus 			delete path;
421fb07ece0SStephan Aßmus 			return B_ERROR;
422fb07ece0SStephan Aßmus 		}
423fb07ece0SStephan Aßmus 		// post process path to clean it up
424fb07ece0SStephan Aßmus 		path->CleanUp();
42570f4b8c0SStephan Aßmus 		if (pathFlags & PATH_FLAG_CLOSED)
426fb07ece0SStephan Aßmus 			path->SetClosed(true);
427fb07ece0SStephan Aßmus 		// add path to container
428fb07ece0SStephan Aßmus 		if (!paths->AddPath(path)) {
429fb07ece0SStephan Aßmus 			delete path;
430fb07ece0SStephan Aßmus 			return B_NO_MEMORY;
431fb07ece0SStephan Aßmus 		}
432fb07ece0SStephan Aßmus 	}
433fb07ece0SStephan Aßmus 
434fb07ece0SStephan Aßmus 	return B_OK;
435fb07ece0SStephan Aßmus }
436fb07ece0SStephan Aßmus 
437fb07ece0SStephan Aßmus // _ReadTransformer
438fb07ece0SStephan Aßmus static Transformer*
439fb07ece0SStephan Aßmus _ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source)
440fb07ece0SStephan Aßmus {
441fb07ece0SStephan Aßmus 	uint8 transformerType;
442fb07ece0SStephan Aßmus 	if (!buffer.Read(transformerType))
443fb07ece0SStephan Aßmus 		return NULL;
444fb07ece0SStephan Aßmus 
445fb07ece0SStephan Aßmus 	switch (transformerType) {
44670f4b8c0SStephan Aßmus 		case TRANSFORMER_TYPE_AFFINE: {
447fb07ece0SStephan Aßmus 			AffineTransformer* affine
448fb07ece0SStephan Aßmus 				= new (nothrow) AffineTransformer(source);
449fb07ece0SStephan Aßmus 			if (!affine)
450fb07ece0SStephan Aßmus 				return NULL;
451fb07ece0SStephan Aßmus 			double matrix[6];
452fb07ece0SStephan Aßmus 			for (int32 i = 0; i < 6; i++) {
453fb07ece0SStephan Aßmus 				float value;
454fb07ece0SStephan Aßmus 				if (!buffer.Read(value)) {
455fb07ece0SStephan Aßmus 					delete affine;
456fb07ece0SStephan Aßmus 					return NULL;
457fb07ece0SStephan Aßmus 				}
458fb07ece0SStephan Aßmus 				matrix[i] = value;
459fb07ece0SStephan Aßmus 			}
460fb07ece0SStephan Aßmus 			affine->load_from(matrix);
461fb07ece0SStephan Aßmus 			return affine;
462fb07ece0SStephan Aßmus 		}
46370f4b8c0SStephan Aßmus 		case TRANSFORMER_TYPE_CONTOUR: {
464fb07ece0SStephan Aßmus 			ContourTransformer* contour
465fb07ece0SStephan Aßmus 				= new (nothrow) ContourTransformer(source);
466fb07ece0SStephan Aßmus 			uint8 width;
467fb07ece0SStephan Aßmus 			uint8 lineJoin;
468fb07ece0SStephan Aßmus 			uint8 miterLimit;
469fb07ece0SStephan Aßmus 			if (!contour
470fb07ece0SStephan Aßmus 				|| !buffer.Read(width)
471fb07ece0SStephan Aßmus 				|| !buffer.Read(lineJoin)
472fb07ece0SStephan Aßmus 				|| !buffer.Read(miterLimit)) {
473fb07ece0SStephan Aßmus 				delete contour;
474fb07ece0SStephan Aßmus 				return NULL;
475fb07ece0SStephan Aßmus 			}
476fb07ece0SStephan Aßmus 			contour->width(width - 128.0);
477fb07ece0SStephan Aßmus 			contour->line_join((agg::line_join_e)lineJoin);
478fb07ece0SStephan Aßmus 			contour->miter_limit(miterLimit);
479fb07ece0SStephan Aßmus 			return contour;
480fb07ece0SStephan Aßmus 		}
48170f4b8c0SStephan Aßmus 		case TRANSFORMER_TYPE_PERSPECTIVE: {
482fb07ece0SStephan Aßmus 			PerspectiveTransformer* perspective
483fb07ece0SStephan Aßmus 				= new (nothrow) PerspectiveTransformer(source);
484fb07ece0SStephan Aßmus 			// TODO: upgrade AGG to be able to support storage of
485fb07ece0SStephan Aßmus 			// trans_perspective
486fb07ece0SStephan Aßmus 			return perspective;
487fb07ece0SStephan Aßmus 		}
48870f4b8c0SStephan Aßmus 		case TRANSFORMER_TYPE_STROKE: {
489fb07ece0SStephan Aßmus 			StrokeTransformer* stroke
490fb07ece0SStephan Aßmus 				= new (nothrow) StrokeTransformer(source);
491fb07ece0SStephan Aßmus 			uint8 width;
4922f953b71SStephan Aßmus 			uint8 lineOptions;
493fb07ece0SStephan Aßmus 			uint8 miterLimit;
494fb07ece0SStephan Aßmus //			uint8 shorten;
495fb07ece0SStephan Aßmus 			if (!stroke
496fb07ece0SStephan Aßmus 				|| !buffer.Read(width)
4972f953b71SStephan Aßmus 				|| !buffer.Read(lineOptions)
498fb07ece0SStephan Aßmus 				|| !buffer.Read(miterLimit)) {
499fb07ece0SStephan Aßmus 				delete stroke;
500fb07ece0SStephan Aßmus 				return NULL;
501fb07ece0SStephan Aßmus 			}
502fb07ece0SStephan Aßmus 			stroke->width(width - 128.0);
5032f953b71SStephan Aßmus 			uint8 lineJoin = lineOptions & 15;
504fb07ece0SStephan Aßmus 			stroke->line_join((agg::line_join_e)lineJoin);
5052f953b71SStephan Aßmus 			uint8 lineCap = lineOptions >> 4;
506fb07ece0SStephan Aßmus 			stroke->line_cap((agg::line_cap_e)lineCap);
507fb07ece0SStephan Aßmus 			stroke->miter_limit(miterLimit);
508fb07ece0SStephan Aßmus 			return stroke;
509fb07ece0SStephan Aßmus 		}
510fb07ece0SStephan Aßmus 		default: {
511fb07ece0SStephan Aßmus 			// unkown transformer, skip tag
512fb07ece0SStephan Aßmus 			uint16 tagLength;
513fb07ece0SStephan Aßmus 			if (!buffer.Read(tagLength))
514fb07ece0SStephan Aßmus 				return NULL;
515fb07ece0SStephan Aßmus 			buffer.Skip(tagLength);
516fb07ece0SStephan Aßmus 			return NULL;
517fb07ece0SStephan Aßmus 		}
518fb07ece0SStephan Aßmus 	}
519fb07ece0SStephan Aßmus }
520fb07ece0SStephan Aßmus 
521fb07ece0SStephan Aßmus // _ReadPathSourceShape
522014c7e94SStephan Aßmus Shape*
523014c7e94SStephan Aßmus FlatIconImporter::_ReadPathSourceShape(LittleEndianBuffer& buffer,
524014c7e94SStephan Aßmus 									   StyleContainer* styles,
525014c7e94SStephan Aßmus 									   PathContainer* paths)
526fb07ece0SStephan Aßmus {
527fb07ece0SStephan Aßmus 	// find out which style this shape uses
528fb07ece0SStephan Aßmus 	uint8 styleIndex;
529fb07ece0SStephan Aßmus 	uint8 pathCount;
530fb07ece0SStephan Aßmus 	if (!buffer.Read(styleIndex) || !buffer.Read(pathCount))
531fb07ece0SStephan Aßmus 		return NULL;
532fb07ece0SStephan Aßmus 
533014c7e94SStephan Aßmus #ifdef ICON_O_MATIC
534014c7e94SStephan Aßmus 	Style* style = styles->StyleAt(StyleIndexFor(styleIndex));
535014c7e94SStephan Aßmus #else
536fb07ece0SStephan Aßmus 	Style* style = styles->StyleAt(styleIndex);
537014c7e94SStephan Aßmus #endif
538014c7e94SStephan Aßmus 
539fb07ece0SStephan Aßmus 	if (!style) {
540fb07ece0SStephan Aßmus 		printf("_ReadPathSourceShape() - "
541fb07ece0SStephan Aßmus 			   "shape references non-existing style %d\n", styleIndex);
542fb07ece0SStephan Aßmus 		return NULL;
543fb07ece0SStephan Aßmus 	}
544fb07ece0SStephan Aßmus 
545fb07ece0SStephan Aßmus 	// create the shape
546fb07ece0SStephan Aßmus 	Shape* shape = new (nothrow) Shape(style);
547fb07ece0SStephan Aßmus 	ObjectDeleter<Shape> shapeDeleter(shape);
548fb07ece0SStephan Aßmus 
549fb07ece0SStephan Aßmus 	if (!shape || shape->InitCheck() < B_OK)
550fb07ece0SStephan Aßmus 		return NULL;
551fb07ece0SStephan Aßmus 
552fb07ece0SStephan Aßmus 	// find out which paths this shape uses
553fb07ece0SStephan Aßmus 	for (uint32 i = 0; i < pathCount; i++) {
554fb07ece0SStephan Aßmus 		uint8 pathIndex;
555fb07ece0SStephan Aßmus 		if (!buffer.Read(pathIndex))
556fb07ece0SStephan Aßmus 			return NULL;
557fb07ece0SStephan Aßmus 
558014c7e94SStephan Aßmus #ifdef ICON_O_MATIC
559014c7e94SStephan Aßmus 		VectorPath* path = paths->PathAt(PathIndexFor(pathIndex));
560014c7e94SStephan Aßmus #else
561fb07ece0SStephan Aßmus 		VectorPath* path = paths->PathAt(pathIndex);
562014c7e94SStephan Aßmus #endif
563fb07ece0SStephan Aßmus 		if (!path) {
564fb07ece0SStephan Aßmus 			printf("_ReadPathSourceShape() - "
565fb07ece0SStephan Aßmus 				   "shape references non-existing path %d\n", pathIndex);
566fb07ece0SStephan Aßmus 			continue;
567fb07ece0SStephan Aßmus 		}
568fb07ece0SStephan Aßmus 		shape->Paths()->AddPath(path);
569fb07ece0SStephan Aßmus 	}
570fb07ece0SStephan Aßmus 
571fb07ece0SStephan Aßmus 	// shape flags
572fb07ece0SStephan Aßmus 	uint8 shapeFlags;
573fb07ece0SStephan Aßmus 	if (!buffer.Read(shapeFlags))
574fb07ece0SStephan Aßmus 		return NULL;
575fb07ece0SStephan Aßmus 
576fb07ece0SStephan Aßmus 	shape->SetHinting(shapeFlags & SHAPE_FLAG_HINTING);
577fb07ece0SStephan Aßmus 
578fb07ece0SStephan Aßmus 	if (shapeFlags & SHAPE_FLAG_TRANSFORM) {
579fb07ece0SStephan Aßmus 		// transformation
580fb07ece0SStephan Aßmus 		if (!_ReadTransformable(buffer, shape))
581fb07ece0SStephan Aßmus 			return NULL;
582fb07ece0SStephan Aßmus 	} else if (shapeFlags & SHAPE_FLAG_TRANSLATION) {
583fb07ece0SStephan Aßmus 		// translation
584fb07ece0SStephan Aßmus 		if (!_ReadTranslation(buffer, shape))
585fb07ece0SStephan Aßmus 			return NULL;
586fb07ece0SStephan Aßmus 	}
587fb07ece0SStephan Aßmus 
588fb07ece0SStephan Aßmus 	if (shapeFlags & SHAPE_FLAG_LOD_SCALE) {
589fb07ece0SStephan Aßmus 		// min max visibility scale
590fb07ece0SStephan Aßmus 		uint8 minScale;
591fb07ece0SStephan Aßmus 		uint8 maxScale;
592fb07ece0SStephan Aßmus 		if (!buffer.Read(minScale) || !buffer.Read(maxScale))
593fb07ece0SStephan Aßmus 			return NULL;
5942f953b71SStephan Aßmus 		shape->SetMinVisibilityScale(minScale / 63.75);
5952f953b71SStephan Aßmus 		shape->SetMaxVisibilityScale(maxScale / 63.75);
596fb07ece0SStephan Aßmus 	}
597fb07ece0SStephan Aßmus 
598fb07ece0SStephan Aßmus 	// transformers
599fb07ece0SStephan Aßmus 	if (shapeFlags & SHAPE_FLAG_HAS_TRANSFORMERS) {
600fb07ece0SStephan Aßmus 		uint8 transformerCount;
601fb07ece0SStephan Aßmus 		if (!buffer.Read(transformerCount))
602fb07ece0SStephan Aßmus 			return NULL;
603fb07ece0SStephan Aßmus 		for (uint32 i = 0; i < transformerCount; i++) {
604fb07ece0SStephan Aßmus 			Transformer* transformer
605fb07ece0SStephan Aßmus 				= _ReadTransformer(buffer, shape->VertexSource());
606fb07ece0SStephan Aßmus 			if (transformer && !shape->AddTransformer(transformer)) {
607fb07ece0SStephan Aßmus 				delete transformer;
608fb07ece0SStephan Aßmus 				return NULL;
609fb07ece0SStephan Aßmus 			}
610fb07ece0SStephan Aßmus 		}
611fb07ece0SStephan Aßmus 	}
612fb07ece0SStephan Aßmus 
613fb07ece0SStephan Aßmus 	shapeDeleter.Detach();
614fb07ece0SStephan Aßmus 	return shape;
615fb07ece0SStephan Aßmus }
616fb07ece0SStephan Aßmus 
617fb07ece0SStephan Aßmus // _ParseShapes
618fb07ece0SStephan Aßmus status_t
619fb07ece0SStephan Aßmus FlatIconImporter::_ParseShapes(LittleEndianBuffer& buffer,
620fb07ece0SStephan Aßmus 							   StyleContainer* styles,
621fb07ece0SStephan Aßmus 							   PathContainer* paths,
622fb07ece0SStephan Aßmus 							   ShapeContainer* shapes)
623fb07ece0SStephan Aßmus {
624fb07ece0SStephan Aßmus 	uint8 shapeCount;
625fb07ece0SStephan Aßmus 	if (!buffer.Read(shapeCount))
626fb07ece0SStephan Aßmus 		return B_ERROR;
627fb07ece0SStephan Aßmus 
628fb07ece0SStephan Aßmus 	for (uint32 i = 0; i < shapeCount; i++) {
629fb07ece0SStephan Aßmus 		uint8 shapeType;
630fb07ece0SStephan Aßmus 		if (!buffer.Read(shapeType))
631fb07ece0SStephan Aßmus 			return B_ERROR;
632fb07ece0SStephan Aßmus 		Shape* shape = NULL;
63370f4b8c0SStephan Aßmus 		if (shapeType == SHAPE_TYPE_PATH_SOURCE) {
634fb07ece0SStephan Aßmus 			// path source shape
635fb07ece0SStephan Aßmus 			shape = _ReadPathSourceShape(buffer, styles, paths);
636fb07ece0SStephan Aßmus 			if (!shape)
637fb07ece0SStephan Aßmus 				return B_NO_MEMORY;
638fb07ece0SStephan Aßmus 		} else {
639fb07ece0SStephan Aßmus 			// unkown shape type, skip tag
640fb07ece0SStephan Aßmus 			uint16 tagLength;
641fb07ece0SStephan Aßmus 			if (!buffer.Read(tagLength))
642fb07ece0SStephan Aßmus 				return B_ERROR;
643fb07ece0SStephan Aßmus 			buffer.Skip(tagLength);
644fb07ece0SStephan Aßmus 			continue;
645fb07ece0SStephan Aßmus 		}
646fb07ece0SStephan Aßmus 		// add shape if we were able to read one
647fb07ece0SStephan Aßmus 		if (shape && !shapes->AddShape(shape)) {
648fb07ece0SStephan Aßmus 			delete shape;
649fb07ece0SStephan Aßmus 			return B_NO_MEMORY;
650fb07ece0SStephan Aßmus 		}
651fb07ece0SStephan Aßmus 	}
652fb07ece0SStephan Aßmus 
653fb07ece0SStephan Aßmus 	return B_OK;
654fb07ece0SStephan Aßmus }
655fb07ece0SStephan Aßmus 
656fb07ece0SStephan Aßmus 
657fb07ece0SStephan Aßmus 
658fb07ece0SStephan Aßmus 
659