xref: /haiku/src/libs/icon/flat_icon/FlatIconImporter.cpp (revision 36830615ddf125c44964bc21a8c2040058f97841)
1fb07ece0SStephan Aßmus /*
2c6c2c042SZardshard  * Copyright 2006, 2023, 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>
7c6c2c042SZardshard  *		Zardshard
8fb07ece0SStephan Aßmus  */
9fb07ece0SStephan Aßmus 
10fb07ece0SStephan Aßmus #include "FlatIconImporter.h"
11fb07ece0SStephan Aßmus 
12fb07ece0SStephan Aßmus #include <new>
13fb07ece0SStephan Aßmus #include <stdio.h>
14fb07ece0SStephan Aßmus 
15fb07ece0SStephan Aßmus #include <Archivable.h>
16fb07ece0SStephan Aßmus #include <DataIO.h>
17fb07ece0SStephan Aßmus #include <Message.h>
18fb07ece0SStephan Aßmus 
19fb07ece0SStephan Aßmus #include "AffineTransformer.h"
20fb07ece0SStephan Aßmus #include "AutoDeleter.h"
21fb07ece0SStephan Aßmus #include "ContourTransformer.h"
22fb07ece0SStephan Aßmus #include "FlatIconFormat.h"
23991547efSStephan Aßmus #include "GradientTransformable.h"
24fb07ece0SStephan Aßmus #include "Icon.h"
25fb07ece0SStephan Aßmus #include "LittleEndianBuffer.h"
26fb07ece0SStephan Aßmus #include "PathCommandQueue.h"
27098eaec6SZardshard #include "PathSourceShape.h"
28fb07ece0SStephan Aßmus #include "PerspectiveTransformer.h"
29fb07ece0SStephan Aßmus #include "Shape.h"
30fb07ece0SStephan Aßmus #include "StrokeTransformer.h"
31fb07ece0SStephan Aßmus #include "Style.h"
32fb07ece0SStephan Aßmus #include "VectorPath.h"
33fb07ece0SStephan Aßmus 
34fb07ece0SStephan Aßmus using std::nothrow;
35fb07ece0SStephan Aßmus 
36*36830615SZardshard _USING_ICON_NAMESPACE
37*36830615SZardshard 
38*36830615SZardshard 
39fb07ece0SStephan Aßmus // constructor
FlatIconImporter()40fb07ece0SStephan Aßmus FlatIconImporter::FlatIconImporter()
41014c7e94SStephan Aßmus #ifdef ICON_O_MATIC
42014c7e94SStephan Aßmus 	: Importer()
43014c7e94SStephan Aßmus #endif
44fb07ece0SStephan Aßmus {
45fb07ece0SStephan Aßmus }
46fb07ece0SStephan Aßmus 
47fb07ece0SStephan Aßmus // destructor
~FlatIconImporter()48fb07ece0SStephan Aßmus FlatIconImporter::~FlatIconImporter()
49fb07ece0SStephan Aßmus {
50fb07ece0SStephan Aßmus }
51fb07ece0SStephan Aßmus 
52fb07ece0SStephan Aßmus // Import
53fb07ece0SStephan Aßmus status_t
Import(Icon * icon,BPositionIO * stream)54fb07ece0SStephan Aßmus FlatIconImporter::Import(Icon* icon, BPositionIO* stream)
55fb07ece0SStephan Aßmus {
56014c7e94SStephan Aßmus #ifdef ICON_O_MATIC
57014c7e94SStephan Aßmus 	status_t ret = Init(icon);
58014c7e94SStephan Aßmus 	if (ret < B_OK)
59014c7e94SStephan Aßmus 		return ret;
60014c7e94SStephan Aßmus #else
61014c7e94SStephan Aßmus 	status_t ret;
62014c7e94SStephan Aßmus #endif
63014c7e94SStephan Aßmus 
64fb07ece0SStephan Aßmus 	// seek around in the stream to figure out the size
65fb07ece0SStephan Aßmus 	off_t size = stream->Seek(0, SEEK_END);
66fb07ece0SStephan Aßmus 	if (stream->Seek(0, SEEK_SET) != 0)
67fb07ece0SStephan Aßmus 		return B_ERROR;
68fb07ece0SStephan Aßmus 
69fb07ece0SStephan Aßmus 	// we chicken out on anything larger than 256k
70fb07ece0SStephan Aßmus 	if (size <= 0 || size > 256 * 1024)
71fb07ece0SStephan Aßmus 		return B_BAD_VALUE;
72fb07ece0SStephan Aßmus 
73fb07ece0SStephan Aßmus 	// read the entire stream into a buffer
74fb07ece0SStephan Aßmus 	LittleEndianBuffer buffer(size);
75fb07ece0SStephan Aßmus 	if (!buffer.Buffer())
76fb07ece0SStephan Aßmus 		return B_NO_MEMORY;
77fb07ece0SStephan Aßmus 
78fb07ece0SStephan Aßmus 	if (stream->Read(buffer.Buffer(), size) != size)
79fb07ece0SStephan Aßmus 		return B_ERROR;
80fb07ece0SStephan Aßmus 
81014c7e94SStephan Aßmus 	ret = _ParseSections(buffer, icon);
82fb07ece0SStephan Aßmus 
83fb07ece0SStephan Aßmus 	return ret;
84fb07ece0SStephan Aßmus }
85fb07ece0SStephan Aßmus 
86fb07ece0SStephan Aßmus // Import
87fb07ece0SStephan Aßmus status_t
Import(Icon * icon,uint8 * _buffer,size_t size)88fb07ece0SStephan Aßmus FlatIconImporter::Import(Icon* icon, uint8* _buffer, size_t size)
89fb07ece0SStephan Aßmus {
90014c7e94SStephan Aßmus #ifdef ICON_O_MATIC
91014c7e94SStephan Aßmus 	status_t ret = Init(icon);
92014c7e94SStephan Aßmus 	if (ret < B_OK)
93014c7e94SStephan Aßmus 		return ret;
94014c7e94SStephan Aßmus #endif
95014c7e94SStephan Aßmus 
96fb07ece0SStephan Aßmus 	if (!_buffer)
97fb07ece0SStephan Aßmus 		return B_BAD_VALUE;
98fb07ece0SStephan Aßmus 
99fb07ece0SStephan Aßmus 	// attach LittleEndianBuffer to buffer
100fb07ece0SStephan Aßmus 	LittleEndianBuffer buffer(_buffer, size);
101fb07ece0SStephan Aßmus 
102fb07ece0SStephan Aßmus 	return _ParseSections(buffer, icon);
103fb07ece0SStephan Aßmus }
104fb07ece0SStephan Aßmus 
105fb07ece0SStephan Aßmus // #pragma mark -
106fb07ece0SStephan Aßmus 
107fb07ece0SStephan Aßmus // _ParseSections
108fb07ece0SStephan Aßmus status_t
_ParseSections(LittleEndianBuffer & buffer,Icon * icon)109fb07ece0SStephan Aßmus FlatIconImporter::_ParseSections(LittleEndianBuffer& buffer, Icon* icon)
110fb07ece0SStephan Aßmus {
111fb07ece0SStephan Aßmus 	// test if this is an icon at all
112fb07ece0SStephan Aßmus 	uint32 magic;
113fb07ece0SStephan Aßmus 	if (!buffer.Read(magic) || magic != FLAT_ICON_MAGIC)
1141a948d74SAxel Dörfler 		return B_BAD_TYPE;
115fb07ece0SStephan Aßmus 
116fb07ece0SStephan Aßmus 	// styles
11764279352SZardshard 	Container<Style>* styles = icon->Styles();
118fb07ece0SStephan Aßmus 	status_t ret = _ParseStyles(buffer, styles);
119fb07ece0SStephan Aßmus 	if (ret < B_OK) {
120fb07ece0SStephan Aßmus 		printf("FlatIconImporter::_ParseSections() - "
121fb07ece0SStephan Aßmus 			   "error parsing styles: %s\n", strerror(ret));
122fb07ece0SStephan Aßmus 		return ret;
123fb07ece0SStephan Aßmus 	}
124fb07ece0SStephan Aßmus 
125fb07ece0SStephan Aßmus 	// paths
12664279352SZardshard 	Container<VectorPath>* paths = icon->Paths();
127fb07ece0SStephan Aßmus 	ret = _ParsePaths(buffer, paths);
128fb07ece0SStephan Aßmus 	if (ret < B_OK) {
129fb07ece0SStephan Aßmus 		printf("FlatIconImporter::_ParseSections() - "
130fb07ece0SStephan Aßmus 			   "error parsing paths: %s\n", strerror(ret));
131fb07ece0SStephan Aßmus 		return ret;
132fb07ece0SStephan Aßmus 	}
133fb07ece0SStephan Aßmus 
134fb07ece0SStephan Aßmus 	// shapes
135fb07ece0SStephan Aßmus 	ret = _ParseShapes(buffer, styles, paths, icon->Shapes());
136fb07ece0SStephan Aßmus 	if (ret < B_OK) {
137fb07ece0SStephan Aßmus 		printf("FlatIconImporter::_ParseSections() - "
138fb07ece0SStephan Aßmus 			   "error parsing shapes: %s\n", strerror(ret));
139fb07ece0SStephan Aßmus 		return ret;
140fb07ece0SStephan Aßmus 	}
141fb07ece0SStephan Aßmus 
142fb07ece0SStephan Aßmus 	return B_OK;
143fb07ece0SStephan Aßmus }
144fb07ece0SStephan Aßmus 
145fb07ece0SStephan Aßmus // _ReadTransformable
146fb07ece0SStephan Aßmus static bool
_ReadTransformable(LittleEndianBuffer & buffer,Transformable * transformable)147fb07ece0SStephan Aßmus _ReadTransformable(LittleEndianBuffer& buffer, Transformable* transformable)
148fb07ece0SStephan Aßmus {
149fb07ece0SStephan Aßmus 	int32 matrixSize = Transformable::matrix_size;
150fb07ece0SStephan Aßmus 	double matrix[matrixSize];
151fb07ece0SStephan Aßmus 	for (int32 i = 0; i < matrixSize; i++) {
152fb07ece0SStephan Aßmus 		float value;
153fb07ece0SStephan Aßmus 		if (!read_float_24(buffer, value))
154fb07ece0SStephan Aßmus 			return false;
155fb07ece0SStephan Aßmus 		matrix[i] = value;
156fb07ece0SStephan Aßmus 	}
157fb07ece0SStephan Aßmus 	transformable->LoadFrom(matrix);
158fb07ece0SStephan Aßmus 	return true;
159fb07ece0SStephan Aßmus }
160fb07ece0SStephan Aßmus 
161fb07ece0SStephan Aßmus // _ReadTranslation
162fb07ece0SStephan Aßmus static bool
_ReadTranslation(LittleEndianBuffer & buffer,Transformable * transformable)163fb07ece0SStephan Aßmus _ReadTranslation(LittleEndianBuffer& buffer, Transformable* transformable)
164fb07ece0SStephan Aßmus {
165fb07ece0SStephan Aßmus 	BPoint t;
166fb07ece0SStephan Aßmus 	if (read_coord(buffer, t.x) && read_coord(buffer, t.y)) {
167fb07ece0SStephan Aßmus 		transformable->TranslateBy(t);
168fb07ece0SStephan Aßmus 		return true;
169fb07ece0SStephan Aßmus 	}
170fb07ece0SStephan Aßmus 
171fb07ece0SStephan Aßmus 	return false;
172fb07ece0SStephan Aßmus }
173fb07ece0SStephan Aßmus 
174fb07ece0SStephan Aßmus // _ReadColorStyle
175fb07ece0SStephan Aßmus static Style*
_ReadColorStyle(LittleEndianBuffer & buffer,bool alpha,bool gray)1762f953b71SStephan Aßmus _ReadColorStyle(LittleEndianBuffer& buffer, bool alpha, bool gray)
177fb07ece0SStephan Aßmus {
178fb07ece0SStephan Aßmus 	rgb_color color;
179fb07ece0SStephan Aßmus 	if (alpha) {
1802f953b71SStephan Aßmus 		if (gray) {
1812f953b71SStephan Aßmus 			if (!buffer.Read(color.red)
1822f953b71SStephan Aßmus 				|| !buffer.Read(color.alpha))
1832f953b71SStephan Aßmus 				return NULL;
1842f953b71SStephan Aßmus 			color.green = color.blue = color.red;
1852f953b71SStephan Aßmus 		} else {
186fb07ece0SStephan Aßmus 			if (!buffer.Read((uint32&)color))
187fb07ece0SStephan Aßmus 				return NULL;
1882f953b71SStephan Aßmus 		}
189fb07ece0SStephan Aßmus 	} else {
190fb07ece0SStephan Aßmus 		color.alpha = 255;
1912f953b71SStephan Aßmus 		if (gray) {
1922f953b71SStephan Aßmus 			if (!buffer.Read(color.red))
1932f953b71SStephan Aßmus 				return NULL;
1942f953b71SStephan Aßmus 			color.green = color.blue = color.red;
1952f953b71SStephan Aßmus 		} else {
196fb07ece0SStephan Aßmus 			if (!buffer.Read(color.red)
197fb07ece0SStephan Aßmus 				|| !buffer.Read(color.green)
198fb07ece0SStephan Aßmus 				|| !buffer.Read(color.blue))
199fb07ece0SStephan Aßmus 				return NULL;
200fb07ece0SStephan Aßmus 		}
2012f953b71SStephan Aßmus 	}
202fb07ece0SStephan Aßmus 	return new (nothrow) Style(color);
203fb07ece0SStephan Aßmus }
204fb07ece0SStephan Aßmus 
205fb07ece0SStephan Aßmus // _ReadGradientStyle
206fb07ece0SStephan Aßmus static Style*
_ReadGradientStyle(LittleEndianBuffer & buffer)207fb07ece0SStephan Aßmus _ReadGradientStyle(LittleEndianBuffer& buffer)
208fb07ece0SStephan Aßmus {
209fb07ece0SStephan Aßmus 	Style* style = new (nothrow) Style();
210fb07ece0SStephan Aßmus 	if (!style)
211fb07ece0SStephan Aßmus 		return NULL;
212fb07ece0SStephan Aßmus 
213fb07ece0SStephan Aßmus 	ObjectDeleter<Style> styleDeleter(style);
214fb07ece0SStephan Aßmus 
215fb07ece0SStephan Aßmus 	uint8 gradientType;
216fb07ece0SStephan Aßmus 	uint8 gradientFlags;
217fb07ece0SStephan Aßmus 	uint8 gradientStopCount;
218fb07ece0SStephan Aßmus 	if (!buffer.Read(gradientType)
219fb07ece0SStephan Aßmus 		|| !buffer.Read(gradientFlags)
220fb07ece0SStephan Aßmus 		|| !buffer.Read(gradientStopCount)) {
221fb07ece0SStephan Aßmus 		return NULL;
222fb07ece0SStephan Aßmus 	}
223fb07ece0SStephan Aßmus 
224fb07ece0SStephan Aßmus 	Gradient gradient(true);
225fb07ece0SStephan Aßmus 		// empty gradient
226fb07ece0SStephan Aßmus 
227991547efSStephan Aßmus 	gradient.SetType((gradients_type)gradientType);
228fb07ece0SStephan Aßmus 	// TODO: support more stuff with flags
229fb07ece0SStephan Aßmus 	// ("inherits transformation" and so on)
230fb07ece0SStephan Aßmus 	if (gradientFlags & GRADIENT_FLAG_TRANSFORM) {
231fb07ece0SStephan Aßmus 		if (!_ReadTransformable(buffer, &gradient))
232fb07ece0SStephan Aßmus 			return NULL;
233fb07ece0SStephan Aßmus 	}
234fb07ece0SStephan Aßmus 
235fb07ece0SStephan Aßmus 	bool alpha = !(gradientFlags & GRADIENT_FLAG_NO_ALPHA);
2362f953b71SStephan Aßmus 	bool gray = gradientFlags & GRADIENT_FLAG_GRAYS;
237fb07ece0SStephan Aßmus 
238fb07ece0SStephan Aßmus 	for (int32 i = 0; i < gradientStopCount; i++) {
239fb07ece0SStephan Aßmus 		uint8 stopOffset;
240fb07ece0SStephan Aßmus 		rgb_color color;
241fb07ece0SStephan Aßmus 
242fb07ece0SStephan Aßmus 		if (!buffer.Read(stopOffset))
243fb07ece0SStephan Aßmus 			return NULL;
244fb07ece0SStephan Aßmus 
245fb07ece0SStephan Aßmus 		if (alpha) {
2462f953b71SStephan Aßmus 			if (gray) {
2472f953b71SStephan Aßmus 				if (!buffer.Read(color.red)
2482f953b71SStephan Aßmus 					|| !buffer.Read(color.alpha))
2492f953b71SStephan Aßmus 					return NULL;
2502f953b71SStephan Aßmus 				color.green = color.blue = color.red;
2512f953b71SStephan Aßmus 			} else {
252fb07ece0SStephan Aßmus 				if (!buffer.Read((uint32&)color))
253fb07ece0SStephan Aßmus 					return NULL;
2542f953b71SStephan Aßmus 			}
255fb07ece0SStephan Aßmus 		} else {
256fb07ece0SStephan Aßmus 			color.alpha = 255;
2572f953b71SStephan Aßmus 			if (gray) {
2582f953b71SStephan Aßmus 				if (!buffer.Read(color.red))
2592f953b71SStephan Aßmus 					return NULL;
2602f953b71SStephan Aßmus 				color.green = color.blue = color.red;
2612f953b71SStephan Aßmus 			} else {
262fb07ece0SStephan Aßmus 				if (!buffer.Read(color.red)
263fb07ece0SStephan Aßmus 					|| !buffer.Read(color.green)
264fb07ece0SStephan Aßmus 					|| !buffer.Read(color.blue)) {
265fb07ece0SStephan Aßmus 					return NULL;
266fb07ece0SStephan Aßmus 				}
267fb07ece0SStephan Aßmus 			}
2682f953b71SStephan Aßmus 		}
269fb07ece0SStephan Aßmus 
270fb07ece0SStephan Aßmus 		gradient.AddColor(color, stopOffset / 255.0);
271fb07ece0SStephan Aßmus 	}
272fb07ece0SStephan Aßmus 
273fb07ece0SStephan Aßmus 	style->SetGradient(&gradient);
274fb07ece0SStephan Aßmus 
275fb07ece0SStephan Aßmus 	styleDeleter.Detach();
276fb07ece0SStephan Aßmus 	return style;
277fb07ece0SStephan Aßmus }
278fb07ece0SStephan Aßmus 
279fb07ece0SStephan Aßmus // _ParseStyles
280fb07ece0SStephan Aßmus status_t
_ParseStyles(LittleEndianBuffer & buffer,Container<Style> * styles)281fb07ece0SStephan Aßmus FlatIconImporter::_ParseStyles(LittleEndianBuffer& buffer,
28264279352SZardshard 							   Container<Style>* styles)
283fb07ece0SStephan Aßmus {
284fb07ece0SStephan Aßmus 	uint8 styleCount;
285fb07ece0SStephan Aßmus 	if (!buffer.Read(styleCount))
286fb07ece0SStephan Aßmus 		return B_ERROR;
287fb07ece0SStephan Aßmus 
288fb07ece0SStephan Aßmus 	for (int32 i = 0; i < styleCount; i++) {
289fb07ece0SStephan Aßmus 		uint8 styleType;
290fb07ece0SStephan Aßmus 		if (!buffer.Read(styleType))
291fb07ece0SStephan Aßmus 			return B_ERROR;
292fb07ece0SStephan Aßmus 		Style* style = NULL;
29370f4b8c0SStephan Aßmus 		if (styleType == STYLE_TYPE_SOLID_COLOR) {
294fb07ece0SStephan Aßmus 			// solid color
2952f953b71SStephan Aßmus 			style = _ReadColorStyle(buffer, true, false);
296fb07ece0SStephan Aßmus 			if (!style)
297fb07ece0SStephan Aßmus 				return B_NO_MEMORY;
29870f4b8c0SStephan Aßmus 		} else if (styleType == STYLE_TYPE_SOLID_COLOR_NO_ALPHA) {
299fb07ece0SStephan Aßmus 			// solid color without alpha
3002f953b71SStephan Aßmus 			style = _ReadColorStyle(buffer, false, false);
3012f953b71SStephan Aßmus 			if (!style)
3022f953b71SStephan Aßmus 				return B_NO_MEMORY;
3032f953b71SStephan Aßmus 		} else if (styleType == STYLE_TYPE_SOLID_GRAY) {
3042f953b71SStephan Aßmus 			// solid gray plus alpha
3052f953b71SStephan Aßmus 			style = _ReadColorStyle(buffer, true, true);
3062f953b71SStephan Aßmus 			if (!style)
3072f953b71SStephan Aßmus 				return B_NO_MEMORY;
3082f953b71SStephan Aßmus 		} else if (styleType == STYLE_TYPE_SOLID_GRAY_NO_ALPHA) {
3092f953b71SStephan Aßmus 			// solid gray without alpha
3102f953b71SStephan Aßmus 			style = _ReadColorStyle(buffer, false, true);
311fb07ece0SStephan Aßmus 			if (!style)
312fb07ece0SStephan Aßmus 				return B_NO_MEMORY;
31370f4b8c0SStephan Aßmus 		} else if (styleType == STYLE_TYPE_GRADIENT) {
314fb07ece0SStephan Aßmus 			// gradient
315fb07ece0SStephan Aßmus 			style = _ReadGradientStyle(buffer);
316fb07ece0SStephan Aßmus 			if (!style)
317fb07ece0SStephan Aßmus 				return B_NO_MEMORY;
318fb07ece0SStephan Aßmus 		} else {
319fb07ece0SStephan Aßmus 			// unkown style type, skip tag
320fb07ece0SStephan Aßmus 			uint16 tagLength;
321fb07ece0SStephan Aßmus 			if (!buffer.Read(tagLength))
322fb07ece0SStephan Aßmus 				return B_ERROR;
323fb07ece0SStephan Aßmus 			buffer.Skip(tagLength);
324fb07ece0SStephan Aßmus 			continue;
325fb07ece0SStephan Aßmus 		}
326fb07ece0SStephan Aßmus 		// add style if we were able to read one
32764279352SZardshard 		if (style && !styles->AddItem(style)) {
328fb07ece0SStephan Aßmus 			delete style;
329fb07ece0SStephan Aßmus 			return B_NO_MEMORY;
330fb07ece0SStephan Aßmus 		}
331fb07ece0SStephan Aßmus 	}
332fb07ece0SStephan Aßmus 
333fb07ece0SStephan Aßmus 	return B_OK;
334fb07ece0SStephan Aßmus }
335fb07ece0SStephan Aßmus 
336fb07ece0SStephan Aßmus // read_path_no_curves
337fb07ece0SStephan Aßmus static bool
read_path_no_curves(LittleEndianBuffer & buffer,VectorPath * path,uint8 pointCount)338fb07ece0SStephan Aßmus read_path_no_curves(LittleEndianBuffer& buffer, VectorPath* path,
339fb07ece0SStephan Aßmus 					uint8 pointCount)
340fb07ece0SStephan Aßmus {
341fb07ece0SStephan Aßmus 	for (uint32 p = 0; p < pointCount; p++) {
342fb07ece0SStephan Aßmus 		BPoint point;
343fb07ece0SStephan Aßmus 		if (!read_coord(buffer, point.x)
344fb07ece0SStephan Aßmus 			|| !read_coord(buffer, point.y))
345fb07ece0SStephan Aßmus 			return false;
346fb07ece0SStephan Aßmus 
347fb07ece0SStephan Aßmus 		if (!path->AddPoint(point))
348fb07ece0SStephan Aßmus 			return false;
349fb07ece0SStephan Aßmus 	}
350fb07ece0SStephan Aßmus 	return true;
351fb07ece0SStephan Aßmus }
352fb07ece0SStephan Aßmus 
353fb07ece0SStephan Aßmus // read_path_curves
354fb07ece0SStephan Aßmus static bool
read_path_curves(LittleEndianBuffer & buffer,VectorPath * path,uint8 pointCount)355fb07ece0SStephan Aßmus read_path_curves(LittleEndianBuffer& buffer, VectorPath* path,
356fb07ece0SStephan Aßmus 				 uint8 pointCount)
357fb07ece0SStephan Aßmus {
358fb07ece0SStephan Aßmus 	for (uint32 p = 0; p < pointCount; p++) {
359fb07ece0SStephan Aßmus 		BPoint point;
360fb07ece0SStephan Aßmus 		if (!read_coord(buffer, point.x)
361fb07ece0SStephan Aßmus 			|| !read_coord(buffer, point.y))
362fb07ece0SStephan Aßmus 			return false;
363fb07ece0SStephan Aßmus 
364fb07ece0SStephan Aßmus 		BPoint pointIn;
365fb07ece0SStephan Aßmus 		if (!read_coord(buffer, pointIn.x)
366fb07ece0SStephan Aßmus 			|| !read_coord(buffer, pointIn.y))
367fb07ece0SStephan Aßmus 			return false;
368fb07ece0SStephan Aßmus 
369fb07ece0SStephan Aßmus 		BPoint pointOut;
370fb07ece0SStephan Aßmus 		if (!read_coord(buffer, pointOut.x)
371fb07ece0SStephan Aßmus 			|| !read_coord(buffer, pointOut.y))
372fb07ece0SStephan Aßmus 			return false;
373fb07ece0SStephan Aßmus 
374fb07ece0SStephan Aßmus 		if (!path->AddPoint(point, pointIn, pointOut, false))
375fb07ece0SStephan Aßmus 			return false;
376fb07ece0SStephan Aßmus 	}
377fb07ece0SStephan Aßmus 	return true;
378fb07ece0SStephan Aßmus }
379fb07ece0SStephan Aßmus 
380fb07ece0SStephan Aßmus // read_path_with_commands
381fb07ece0SStephan Aßmus static bool
read_path_with_commands(LittleEndianBuffer & buffer,VectorPath * path,uint8 pointCount)382fb07ece0SStephan Aßmus read_path_with_commands(LittleEndianBuffer& buffer, VectorPath* path,
383fb07ece0SStephan Aßmus 						uint8 pointCount)
384fb07ece0SStephan Aßmus {
385fb07ece0SStephan Aßmus 	PathCommandQueue queue;
386fb07ece0SStephan Aßmus 	return queue.Read(buffer, path, pointCount);
387fb07ece0SStephan Aßmus }
388fb07ece0SStephan Aßmus 
389fb07ece0SStephan Aßmus 
390fb07ece0SStephan Aßmus // _ParsePaths
391fb07ece0SStephan Aßmus status_t
_ParsePaths(LittleEndianBuffer & buffer,Container<VectorPath> * paths)392fb07ece0SStephan Aßmus FlatIconImporter::_ParsePaths(LittleEndianBuffer& buffer,
39364279352SZardshard 							  Container<VectorPath>* paths)
394fb07ece0SStephan Aßmus {
395fb07ece0SStephan Aßmus 	uint8 pathCount;
396fb07ece0SStephan Aßmus 	if (!buffer.Read(pathCount))
397fb07ece0SStephan Aßmus 		return B_ERROR;
398fb07ece0SStephan Aßmus 
399fb07ece0SStephan Aßmus 	for (int32 i = 0; i < pathCount; i++) {
400fb07ece0SStephan Aßmus 		uint8 pathFlags;
401fb07ece0SStephan Aßmus 		uint8 pointCount;
402fb07ece0SStephan Aßmus 		if (!buffer.Read(pathFlags) || !buffer.Read(pointCount))
403fb07ece0SStephan Aßmus 			return B_ERROR;
404fb07ece0SStephan Aßmus 
405fb07ece0SStephan Aßmus 		VectorPath* path = new (nothrow) VectorPath();
406fb07ece0SStephan Aßmus 		if (!path)
407fb07ece0SStephan Aßmus 			return B_NO_MEMORY;
408fb07ece0SStephan Aßmus 
409fb07ece0SStephan Aßmus 		// chose path reading strategy depending on path flags
410fb07ece0SStephan Aßmus 		bool error = false;
41170f4b8c0SStephan Aßmus 		if (pathFlags & PATH_FLAG_NO_CURVES) {
412fb07ece0SStephan Aßmus 			if (!read_path_no_curves(buffer, path, pointCount))
413fb07ece0SStephan Aßmus 				error = true;
41470f4b8c0SStephan Aßmus 		} else if (pathFlags & PATH_FLAG_USES_COMMANDS) {
415fb07ece0SStephan Aßmus 			if (!read_path_with_commands(buffer, path, pointCount))
416fb07ece0SStephan Aßmus 				error = true;
417fb07ece0SStephan Aßmus 		} else {
418fb07ece0SStephan Aßmus 			if (!read_path_curves(buffer, path, pointCount))
419fb07ece0SStephan Aßmus 				error = true;
420fb07ece0SStephan Aßmus 		}
421fb07ece0SStephan Aßmus 
422fb07ece0SStephan Aßmus 		if (error) {
423fb07ece0SStephan Aßmus 			delete path;
424fb07ece0SStephan Aßmus 			return B_ERROR;
425fb07ece0SStephan Aßmus 		}
426fb07ece0SStephan Aßmus 		// post process path to clean it up
427fb07ece0SStephan Aßmus 		path->CleanUp();
42870f4b8c0SStephan Aßmus 		if (pathFlags & PATH_FLAG_CLOSED)
429fb07ece0SStephan Aßmus 			path->SetClosed(true);
430fb07ece0SStephan Aßmus 		// add path to container
43164279352SZardshard 		if (!paths->AddItem(path)) {
432fb07ece0SStephan Aßmus 			delete path;
433fb07ece0SStephan Aßmus 			return B_NO_MEMORY;
434fb07ece0SStephan Aßmus 		}
435fb07ece0SStephan Aßmus 	}
436fb07ece0SStephan Aßmus 
437fb07ece0SStephan Aßmus 	return B_OK;
438fb07ece0SStephan Aßmus }
439fb07ece0SStephan Aßmus 
440fb07ece0SStephan Aßmus // _ReadTransformer
441fb07ece0SStephan Aßmus static Transformer*
_ReadTransformer(LittleEndianBuffer & buffer,VertexSource & source,Shape * shape)442c6c2c042SZardshard _ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source, Shape* shape)
443fb07ece0SStephan Aßmus {
444fb07ece0SStephan Aßmus 	uint8 transformerType;
445fb07ece0SStephan Aßmus 	if (!buffer.Read(transformerType))
446fb07ece0SStephan Aßmus 		return NULL;
447fb07ece0SStephan Aßmus 
448fb07ece0SStephan Aßmus 	switch (transformerType) {
44970f4b8c0SStephan Aßmus 		case TRANSFORMER_TYPE_AFFINE: {
450fb07ece0SStephan Aßmus 			AffineTransformer* affine
451fb07ece0SStephan Aßmus 				= new (nothrow) AffineTransformer(source);
452fb07ece0SStephan Aßmus 			if (!affine)
453fb07ece0SStephan Aßmus 				return NULL;
454fb07ece0SStephan Aßmus 			double matrix[6];
455fb07ece0SStephan Aßmus 			for (int32 i = 0; i < 6; i++) {
456fb07ece0SStephan Aßmus 				float value;
457fb07ece0SStephan Aßmus 				if (!buffer.Read(value)) {
458fb07ece0SStephan Aßmus 					delete affine;
459fb07ece0SStephan Aßmus 					return NULL;
460fb07ece0SStephan Aßmus 				}
461fb07ece0SStephan Aßmus 				matrix[i] = value;
462fb07ece0SStephan Aßmus 			}
463fb07ece0SStephan Aßmus 			affine->load_from(matrix);
464fb07ece0SStephan Aßmus 			return affine;
465fb07ece0SStephan Aßmus 		}
46670f4b8c0SStephan Aßmus 		case TRANSFORMER_TYPE_CONTOUR: {
467fb07ece0SStephan Aßmus 			ContourTransformer* contour
468fb07ece0SStephan Aßmus 				= new (nothrow) ContourTransformer(source);
469fb07ece0SStephan Aßmus 			uint8 width;
470fb07ece0SStephan Aßmus 			uint8 lineJoin;
471fb07ece0SStephan Aßmus 			uint8 miterLimit;
472fb07ece0SStephan Aßmus 			if (!contour
473fb07ece0SStephan Aßmus 				|| !buffer.Read(width)
474fb07ece0SStephan Aßmus 				|| !buffer.Read(lineJoin)
475fb07ece0SStephan Aßmus 				|| !buffer.Read(miterLimit)) {
476fb07ece0SStephan Aßmus 				delete contour;
477fb07ece0SStephan Aßmus 				return NULL;
478fb07ece0SStephan Aßmus 			}
479fb07ece0SStephan Aßmus 			contour->width(width - 128.0);
480fb07ece0SStephan Aßmus 			contour->line_join((agg::line_join_e)lineJoin);
481fb07ece0SStephan Aßmus 			contour->miter_limit(miterLimit);
482fb07ece0SStephan Aßmus 			return contour;
483fb07ece0SStephan Aßmus 		}
48470f4b8c0SStephan Aßmus 		case TRANSFORMER_TYPE_PERSPECTIVE: {
485fb07ece0SStephan Aßmus 			PerspectiveTransformer* perspective
486c6c2c042SZardshard 				= new (nothrow) PerspectiveTransformer(source, shape);
487c6c2c042SZardshard 			if (!perspective)
488c6c2c042SZardshard 				return NULL;
489c6c2c042SZardshard 			double matrix[9];
490c6c2c042SZardshard 			for (int32 i = 0; i < 9; i++) {
491c6c2c042SZardshard 				float value;
492c6c2c042SZardshard 				if (!read_float_24(buffer, value)) {
493c6c2c042SZardshard 					delete perspective;
494c6c2c042SZardshard 					return NULL;
495c6c2c042SZardshard 				}
496c6c2c042SZardshard 				matrix[i] = value;
497c6c2c042SZardshard 			}
498c6c2c042SZardshard 			perspective->load_from(matrix);
499fb07ece0SStephan Aßmus 			return perspective;
500fb07ece0SStephan Aßmus 		}
50170f4b8c0SStephan Aßmus 		case TRANSFORMER_TYPE_STROKE: {
502fb07ece0SStephan Aßmus 			StrokeTransformer* stroke
503fb07ece0SStephan Aßmus 				= new (nothrow) StrokeTransformer(source);
504fb07ece0SStephan Aßmus 			uint8 width;
5052f953b71SStephan Aßmus 			uint8 lineOptions;
506fb07ece0SStephan Aßmus 			uint8 miterLimit;
507fb07ece0SStephan Aßmus //			uint8 shorten;
508fb07ece0SStephan Aßmus 			if (!stroke
509fb07ece0SStephan Aßmus 				|| !buffer.Read(width)
5102f953b71SStephan Aßmus 				|| !buffer.Read(lineOptions)
511fb07ece0SStephan Aßmus 				|| !buffer.Read(miterLimit)) {
512fb07ece0SStephan Aßmus 				delete stroke;
513fb07ece0SStephan Aßmus 				return NULL;
514fb07ece0SStephan Aßmus 			}
515fb07ece0SStephan Aßmus 			stroke->width(width - 128.0);
5162f953b71SStephan Aßmus 			uint8 lineJoin = lineOptions & 15;
517fb07ece0SStephan Aßmus 			stroke->line_join((agg::line_join_e)lineJoin);
5182f953b71SStephan Aßmus 			uint8 lineCap = lineOptions >> 4;
519fb07ece0SStephan Aßmus 			stroke->line_cap((agg::line_cap_e)lineCap);
520fb07ece0SStephan Aßmus 			stroke->miter_limit(miterLimit);
521fb07ece0SStephan Aßmus 			return stroke;
522fb07ece0SStephan Aßmus 		}
523fb07ece0SStephan Aßmus 		default: {
524fb07ece0SStephan Aßmus 			// unkown transformer, skip tag
525fb07ece0SStephan Aßmus 			uint16 tagLength;
526fb07ece0SStephan Aßmus 			if (!buffer.Read(tagLength))
527fb07ece0SStephan Aßmus 				return NULL;
528fb07ece0SStephan Aßmus 			buffer.Skip(tagLength);
529fb07ece0SStephan Aßmus 			return NULL;
530fb07ece0SStephan Aßmus 		}
531fb07ece0SStephan Aßmus 	}
532fb07ece0SStephan Aßmus }
533fb07ece0SStephan Aßmus 
534fb07ece0SStephan Aßmus // _ReadPathSourceShape
535014c7e94SStephan Aßmus Shape*
_ReadPathSourceShape(LittleEndianBuffer & buffer,Container<Style> * styles,Container<VectorPath> * paths)536014c7e94SStephan Aßmus FlatIconImporter::_ReadPathSourceShape(LittleEndianBuffer& buffer,
53764279352SZardshard 									   Container<Style>* styles,
53864279352SZardshard 									   Container<VectorPath>* paths)
539fb07ece0SStephan Aßmus {
540fb07ece0SStephan Aßmus 	// find out which style this shape uses
541fb07ece0SStephan Aßmus 	uint8 styleIndex;
542fb07ece0SStephan Aßmus 	uint8 pathCount;
543fb07ece0SStephan Aßmus 	if (!buffer.Read(styleIndex) || !buffer.Read(pathCount))
544fb07ece0SStephan Aßmus 		return NULL;
545fb07ece0SStephan Aßmus 
546014c7e94SStephan Aßmus #ifdef ICON_O_MATIC
54764279352SZardshard 	Style* style = styles->ItemAt(StyleIndexFor(styleIndex));
548014c7e94SStephan Aßmus #else
54964279352SZardshard 	Style* style = styles->ItemAt(styleIndex);
550014c7e94SStephan Aßmus #endif
551014c7e94SStephan Aßmus 
552fb07ece0SStephan Aßmus 	if (!style) {
553fb07ece0SStephan Aßmus 		printf("_ReadPathSourceShape() - "
554fb07ece0SStephan Aßmus 			   "shape references non-existing style %d\n", styleIndex);
555fb07ece0SStephan Aßmus 		return NULL;
556fb07ece0SStephan Aßmus 	}
557fb07ece0SStephan Aßmus 
558fb07ece0SStephan Aßmus 	// create the shape
559098eaec6SZardshard 	PathSourceShape* shape = new (nothrow) PathSourceShape(style);
560fb07ece0SStephan Aßmus 	ObjectDeleter<Shape> shapeDeleter(shape);
561fb07ece0SStephan Aßmus 
562fb07ece0SStephan Aßmus 	if (!shape || shape->InitCheck() < B_OK)
563fb07ece0SStephan Aßmus 		return NULL;
564fb07ece0SStephan Aßmus 
565fb07ece0SStephan Aßmus 	// find out which paths this shape uses
566fb07ece0SStephan Aßmus 	for (uint32 i = 0; i < pathCount; i++) {
567fb07ece0SStephan Aßmus 		uint8 pathIndex;
568fb07ece0SStephan Aßmus 		if (!buffer.Read(pathIndex))
569fb07ece0SStephan Aßmus 			return NULL;
570fb07ece0SStephan Aßmus 
571014c7e94SStephan Aßmus #ifdef ICON_O_MATIC
57264279352SZardshard 		VectorPath* path = paths->ItemAt(PathIndexFor(pathIndex));
573014c7e94SStephan Aßmus #else
57464279352SZardshard 		VectorPath* path = paths->ItemAt(pathIndex);
575014c7e94SStephan Aßmus #endif
576fb07ece0SStephan Aßmus 		if (!path) {
577fb07ece0SStephan Aßmus 			printf("_ReadPathSourceShape() - "
578fb07ece0SStephan Aßmus 				   "shape references non-existing path %d\n", pathIndex);
579fb07ece0SStephan Aßmus 			continue;
580fb07ece0SStephan Aßmus 		}
58164279352SZardshard 		shape->Paths()->AddItem(path);
582fb07ece0SStephan Aßmus 	}
583fb07ece0SStephan Aßmus 
584fb07ece0SStephan Aßmus 	// shape flags
585fb07ece0SStephan Aßmus 	uint8 shapeFlags;
586fb07ece0SStephan Aßmus 	if (!buffer.Read(shapeFlags))
587fb07ece0SStephan Aßmus 		return NULL;
588fb07ece0SStephan Aßmus 
589fb07ece0SStephan Aßmus 	shape->SetHinting(shapeFlags & SHAPE_FLAG_HINTING);
590fb07ece0SStephan Aßmus 
591fb07ece0SStephan Aßmus 	if (shapeFlags & SHAPE_FLAG_TRANSFORM) {
592fb07ece0SStephan Aßmus 		// transformation
593fb07ece0SStephan Aßmus 		if (!_ReadTransformable(buffer, shape))
594fb07ece0SStephan Aßmus 			return NULL;
595fb07ece0SStephan Aßmus 	} else if (shapeFlags & SHAPE_FLAG_TRANSLATION) {
596fb07ece0SStephan Aßmus 		// translation
597fb07ece0SStephan Aßmus 		if (!_ReadTranslation(buffer, shape))
598fb07ece0SStephan Aßmus 			return NULL;
599fb07ece0SStephan Aßmus 	}
600fb07ece0SStephan Aßmus 
601fb07ece0SStephan Aßmus 	if (shapeFlags & SHAPE_FLAG_LOD_SCALE) {
602fb07ece0SStephan Aßmus 		// min max visibility scale
603fb07ece0SStephan Aßmus 		uint8 minScale;
604fb07ece0SStephan Aßmus 		uint8 maxScale;
605fb07ece0SStephan Aßmus 		if (!buffer.Read(minScale) || !buffer.Read(maxScale))
606fb07ece0SStephan Aßmus 			return NULL;
6072f953b71SStephan Aßmus 		shape->SetMinVisibilityScale(minScale / 63.75);
6082f953b71SStephan Aßmus 		shape->SetMaxVisibilityScale(maxScale / 63.75);
609fb07ece0SStephan Aßmus 	}
610fb07ece0SStephan Aßmus 
611fb07ece0SStephan Aßmus 	// transformers
612fb07ece0SStephan Aßmus 	if (shapeFlags & SHAPE_FLAG_HAS_TRANSFORMERS) {
613fb07ece0SStephan Aßmus 		uint8 transformerCount;
614fb07ece0SStephan Aßmus 		if (!buffer.Read(transformerCount))
615fb07ece0SStephan Aßmus 			return NULL;
616fb07ece0SStephan Aßmus 		for (uint32 i = 0; i < transformerCount; i++) {
617fb07ece0SStephan Aßmus 			Transformer* transformer
618c6c2c042SZardshard 				= _ReadTransformer(buffer, shape->VertexSource(), shape);
61964279352SZardshard 			if (transformer && !shape->Transformers()->AddItem(transformer)) {
620fb07ece0SStephan Aßmus 				delete transformer;
621fb07ece0SStephan Aßmus 				return NULL;
622fb07ece0SStephan Aßmus 			}
623fb07ece0SStephan Aßmus 		}
624fb07ece0SStephan Aßmus 	}
625fb07ece0SStephan Aßmus 
626fb07ece0SStephan Aßmus 	shapeDeleter.Detach();
627fb07ece0SStephan Aßmus 	return shape;
628fb07ece0SStephan Aßmus }
629fb07ece0SStephan Aßmus 
630fb07ece0SStephan Aßmus // _ParseShapes
631fb07ece0SStephan Aßmus status_t
_ParseShapes(LittleEndianBuffer & buffer,Container<Style> * styles,Container<VectorPath> * paths,Container<Shape> * shapes)632fb07ece0SStephan Aßmus FlatIconImporter::_ParseShapes(LittleEndianBuffer& buffer,
63364279352SZardshard 							   Container<Style>* styles,
63464279352SZardshard 							   Container<VectorPath>* paths,
63564279352SZardshard 							   Container<Shape>* shapes)
636fb07ece0SStephan Aßmus {
637fb07ece0SStephan Aßmus 	uint8 shapeCount;
638fb07ece0SStephan Aßmus 	if (!buffer.Read(shapeCount))
639fb07ece0SStephan Aßmus 		return B_ERROR;
640fb07ece0SStephan Aßmus 
641fb07ece0SStephan Aßmus 	for (uint32 i = 0; i < shapeCount; i++) {
642fb07ece0SStephan Aßmus 		uint8 shapeType;
643fb07ece0SStephan Aßmus 		if (!buffer.Read(shapeType))
644fb07ece0SStephan Aßmus 			return B_ERROR;
645fb07ece0SStephan Aßmus 		Shape* shape = NULL;
64670f4b8c0SStephan Aßmus 		if (shapeType == SHAPE_TYPE_PATH_SOURCE) {
647fb07ece0SStephan Aßmus 			// path source shape
648fb07ece0SStephan Aßmus 			shape = _ReadPathSourceShape(buffer, styles, paths);
649fb07ece0SStephan Aßmus 			if (!shape)
650fb07ece0SStephan Aßmus 				return B_NO_MEMORY;
651fb07ece0SStephan Aßmus 		} else {
652fb07ece0SStephan Aßmus 			// unkown shape type, skip tag
653fb07ece0SStephan Aßmus 			uint16 tagLength;
654fb07ece0SStephan Aßmus 			if (!buffer.Read(tagLength))
655fb07ece0SStephan Aßmus 				return B_ERROR;
656fb07ece0SStephan Aßmus 			buffer.Skip(tagLength);
657fb07ece0SStephan Aßmus 			continue;
658fb07ece0SStephan Aßmus 		}
659fb07ece0SStephan Aßmus 		// add shape if we were able to read one
66064279352SZardshard 		if (shape && !shapes->AddItem(shape)) {
661fb07ece0SStephan Aßmus 			delete shape;
662fb07ece0SStephan Aßmus 			return B_NO_MEMORY;
663fb07ece0SStephan Aßmus 		}
664fb07ece0SStephan Aßmus 	}
665fb07ece0SStephan Aßmus 
666fb07ece0SStephan Aßmus 	return B_OK;
667fb07ece0SStephan Aßmus }
668