xref: /haiku/src/libs/icon/flat_icon/FlatIconImporter.cpp (revision fb07ece069b8b7ca52eda06449ce2f0460b294ab)
1*fb07ece0SStephan Aßmus /*
2*fb07ece0SStephan Aßmus  * Copyright 2006, Haiku. All rights reserved.
3*fb07ece0SStephan Aßmus  * Distributed under the terms of the MIT License.
4*fb07ece0SStephan Aßmus  *
5*fb07ece0SStephan Aßmus  * Authors:
6*fb07ece0SStephan Aßmus  *		Stephan Aßmus <superstippi@gmx.de>
7*fb07ece0SStephan Aßmus  */
8*fb07ece0SStephan Aßmus 
9*fb07ece0SStephan Aßmus #include "FlatIconImporter.h"
10*fb07ece0SStephan Aßmus 
11*fb07ece0SStephan Aßmus #include <new>
12*fb07ece0SStephan Aßmus #include <stdio.h>
13*fb07ece0SStephan Aßmus 
14*fb07ece0SStephan Aßmus #include <Archivable.h>
15*fb07ece0SStephan Aßmus #include <DataIO.h>
16*fb07ece0SStephan Aßmus #include <Message.h>
17*fb07ece0SStephan Aßmus 
18*fb07ece0SStephan Aßmus #include "AffineTransformer.h"
19*fb07ece0SStephan Aßmus #include "AutoDeleter.h"
20*fb07ece0SStephan Aßmus #include "ContourTransformer.h"
21*fb07ece0SStephan Aßmus #include "FlatIconFormat.h"
22*fb07ece0SStephan Aßmus #include "Gradient.h"
23*fb07ece0SStephan Aßmus #include "Icon.h"
24*fb07ece0SStephan Aßmus #include "LittleEndianBuffer.h"
25*fb07ece0SStephan Aßmus #include "PathCommandQueue.h"
26*fb07ece0SStephan Aßmus #include "PathContainer.h"
27*fb07ece0SStephan Aßmus #include "PerspectiveTransformer.h"
28*fb07ece0SStephan Aßmus #include "Shape.h"
29*fb07ece0SStephan Aßmus #include "StrokeTransformer.h"
30*fb07ece0SStephan Aßmus #include "Style.h"
31*fb07ece0SStephan Aßmus #include "StyleContainer.h"
32*fb07ece0SStephan Aßmus #include "VectorPath.h"
33*fb07ece0SStephan Aßmus 
34*fb07ece0SStephan Aßmus using std::nothrow;
35*fb07ece0SStephan Aßmus 
36*fb07ece0SStephan Aßmus // constructor
37*fb07ece0SStephan Aßmus FlatIconImporter::FlatIconImporter()
38*fb07ece0SStephan Aßmus {
39*fb07ece0SStephan Aßmus }
40*fb07ece0SStephan Aßmus 
41*fb07ece0SStephan Aßmus // destructor
42*fb07ece0SStephan Aßmus FlatIconImporter::~FlatIconImporter()
43*fb07ece0SStephan Aßmus {
44*fb07ece0SStephan Aßmus }
45*fb07ece0SStephan Aßmus 
46*fb07ece0SStephan Aßmus // Import
47*fb07ece0SStephan Aßmus status_t
48*fb07ece0SStephan Aßmus FlatIconImporter::Import(Icon* icon, BPositionIO* stream)
49*fb07ece0SStephan Aßmus {
50*fb07ece0SStephan Aßmus 	// seek around in the stream to figure out the size
51*fb07ece0SStephan Aßmus 	off_t size = stream->Seek(0, SEEK_END);
52*fb07ece0SStephan Aßmus 	if (stream->Seek(0, SEEK_SET) != 0)
53*fb07ece0SStephan Aßmus 		return B_ERROR;
54*fb07ece0SStephan Aßmus 
55*fb07ece0SStephan Aßmus 	// we chicken out on anything larger than 256k
56*fb07ece0SStephan Aßmus 	if (size <= 0 || size > 256 * 1024)
57*fb07ece0SStephan Aßmus 		return B_BAD_VALUE;
58*fb07ece0SStephan Aßmus 
59*fb07ece0SStephan Aßmus 	// read the entire stream into a buffer
60*fb07ece0SStephan Aßmus 	LittleEndianBuffer buffer(size);
61*fb07ece0SStephan Aßmus 	if (!buffer.Buffer())
62*fb07ece0SStephan Aßmus 		return B_NO_MEMORY;
63*fb07ece0SStephan Aßmus 
64*fb07ece0SStephan Aßmus 	if (stream->Read(buffer.Buffer(), size) != size)
65*fb07ece0SStephan Aßmus 		return B_ERROR;
66*fb07ece0SStephan Aßmus 
67*fb07ece0SStephan Aßmus 	status_t ret = _ParseSections(buffer, icon);
68*fb07ece0SStephan Aßmus 
69*fb07ece0SStephan Aßmus 	return ret;
70*fb07ece0SStephan Aßmus }
71*fb07ece0SStephan Aßmus 
72*fb07ece0SStephan Aßmus // Import
73*fb07ece0SStephan Aßmus status_t
74*fb07ece0SStephan Aßmus FlatIconImporter::Import(Icon* icon, uint8* _buffer, size_t size)
75*fb07ece0SStephan Aßmus {
76*fb07ece0SStephan Aßmus 	if (!_buffer)
77*fb07ece0SStephan Aßmus 		return B_BAD_VALUE;
78*fb07ece0SStephan Aßmus 
79*fb07ece0SStephan Aßmus 	// attach LittleEndianBuffer to buffer
80*fb07ece0SStephan Aßmus 	LittleEndianBuffer buffer(_buffer, size);
81*fb07ece0SStephan Aßmus 
82*fb07ece0SStephan Aßmus 	return _ParseSections(buffer, icon);
83*fb07ece0SStephan Aßmus }
84*fb07ece0SStephan Aßmus 
85*fb07ece0SStephan Aßmus // #pragma mark -
86*fb07ece0SStephan Aßmus 
87*fb07ece0SStephan Aßmus // _ParseSections
88*fb07ece0SStephan Aßmus status_t
89*fb07ece0SStephan Aßmus FlatIconImporter::_ParseSections(LittleEndianBuffer& buffer, Icon* icon)
90*fb07ece0SStephan Aßmus {
91*fb07ece0SStephan Aßmus 	// test if this is an icon at all
92*fb07ece0SStephan Aßmus 	uint32 magic;
93*fb07ece0SStephan Aßmus 	if (!buffer.Read(magic) || magic != FLAT_ICON_MAGIC)
94*fb07ece0SStephan Aßmus 		return B_ERROR;
95*fb07ece0SStephan Aßmus 
96*fb07ece0SStephan Aßmus 	// styles
97*fb07ece0SStephan Aßmus 	StyleContainer* styles = icon->Styles();
98*fb07ece0SStephan Aßmus 	status_t ret = _ParseStyles(buffer, styles);
99*fb07ece0SStephan Aßmus 	if (ret < B_OK) {
100*fb07ece0SStephan Aßmus 		printf("FlatIconImporter::_ParseSections() - "
101*fb07ece0SStephan Aßmus 			   "error parsing styles: %s\n", strerror(ret));
102*fb07ece0SStephan Aßmus 		return ret;
103*fb07ece0SStephan Aßmus 	}
104*fb07ece0SStephan Aßmus 
105*fb07ece0SStephan Aßmus 	// paths
106*fb07ece0SStephan Aßmus 	PathContainer* paths = icon->Paths();
107*fb07ece0SStephan Aßmus 	ret = _ParsePaths(buffer, paths);
108*fb07ece0SStephan Aßmus 	if (ret < B_OK) {
109*fb07ece0SStephan Aßmus 		printf("FlatIconImporter::_ParseSections() - "
110*fb07ece0SStephan Aßmus 			   "error parsing paths: %s\n", strerror(ret));
111*fb07ece0SStephan Aßmus 		return ret;
112*fb07ece0SStephan Aßmus 	}
113*fb07ece0SStephan Aßmus 
114*fb07ece0SStephan Aßmus 	// shapes
115*fb07ece0SStephan Aßmus 	ret = _ParseShapes(buffer, styles, paths, icon->Shapes());
116*fb07ece0SStephan Aßmus 	if (ret < B_OK) {
117*fb07ece0SStephan Aßmus 		printf("FlatIconImporter::_ParseSections() - "
118*fb07ece0SStephan Aßmus 			   "error parsing shapes: %s\n", strerror(ret));
119*fb07ece0SStephan Aßmus 		return ret;
120*fb07ece0SStephan Aßmus 	}
121*fb07ece0SStephan Aßmus 
122*fb07ece0SStephan Aßmus 	return B_OK;
123*fb07ece0SStephan Aßmus }
124*fb07ece0SStephan Aßmus 
125*fb07ece0SStephan Aßmus // _ReadTransformable
126*fb07ece0SStephan Aßmus static bool
127*fb07ece0SStephan Aßmus _ReadTransformable(LittleEndianBuffer& buffer, Transformable* transformable)
128*fb07ece0SStephan Aßmus {
129*fb07ece0SStephan Aßmus 	int32 matrixSize = Transformable::matrix_size;
130*fb07ece0SStephan Aßmus 	double matrix[matrixSize];
131*fb07ece0SStephan Aßmus 	for (int32 i = 0; i < matrixSize; i++) {
132*fb07ece0SStephan Aßmus 		float value;
133*fb07ece0SStephan Aßmus 		if (!read_float_24(buffer, value))
134*fb07ece0SStephan Aßmus 			return false;
135*fb07ece0SStephan Aßmus 		matrix[i] = value;
136*fb07ece0SStephan Aßmus 	}
137*fb07ece0SStephan Aßmus 	transformable->LoadFrom(matrix);
138*fb07ece0SStephan Aßmus 	return true;
139*fb07ece0SStephan Aßmus }
140*fb07ece0SStephan Aßmus 
141*fb07ece0SStephan Aßmus // _ReadTranslation
142*fb07ece0SStephan Aßmus static bool
143*fb07ece0SStephan Aßmus _ReadTranslation(LittleEndianBuffer& buffer, Transformable* transformable)
144*fb07ece0SStephan Aßmus {
145*fb07ece0SStephan Aßmus 	BPoint t;
146*fb07ece0SStephan Aßmus 	if (read_coord(buffer, t.x) && read_coord(buffer, t.y)) {
147*fb07ece0SStephan Aßmus 		transformable->TranslateBy(t);
148*fb07ece0SStephan Aßmus 		return true;
149*fb07ece0SStephan Aßmus 	}
150*fb07ece0SStephan Aßmus 
151*fb07ece0SStephan Aßmus 	return false;
152*fb07ece0SStephan Aßmus }
153*fb07ece0SStephan Aßmus 
154*fb07ece0SStephan Aßmus // _ReadColorStyle
155*fb07ece0SStephan Aßmus static Style*
156*fb07ece0SStephan Aßmus _ReadColorStyle(LittleEndianBuffer& buffer, bool alpha)
157*fb07ece0SStephan Aßmus {
158*fb07ece0SStephan Aßmus 	rgb_color color;
159*fb07ece0SStephan Aßmus 	if (alpha) {
160*fb07ece0SStephan Aßmus 		if (!buffer.Read((uint32&)color))
161*fb07ece0SStephan Aßmus 			return NULL;
162*fb07ece0SStephan Aßmus 	} else {
163*fb07ece0SStephan Aßmus 		color.alpha = 255;
164*fb07ece0SStephan Aßmus 		if (!buffer.Read(color.red)
165*fb07ece0SStephan Aßmus 			|| !buffer.Read(color.green)
166*fb07ece0SStephan Aßmus 			|| !buffer.Read(color.blue))
167*fb07ece0SStephan Aßmus 			return NULL;
168*fb07ece0SStephan Aßmus 	}
169*fb07ece0SStephan Aßmus 	return new (nothrow) Style(color);
170*fb07ece0SStephan Aßmus }
171*fb07ece0SStephan Aßmus 
172*fb07ece0SStephan Aßmus // _ReadGradientStyle
173*fb07ece0SStephan Aßmus static Style*
174*fb07ece0SStephan Aßmus _ReadGradientStyle(LittleEndianBuffer& buffer)
175*fb07ece0SStephan Aßmus {
176*fb07ece0SStephan Aßmus 	Style* style = new (nothrow) Style();
177*fb07ece0SStephan Aßmus 	if (!style)
178*fb07ece0SStephan Aßmus 		return NULL;
179*fb07ece0SStephan Aßmus 
180*fb07ece0SStephan Aßmus 	ObjectDeleter<Style> styleDeleter(style);
181*fb07ece0SStephan Aßmus 
182*fb07ece0SStephan Aßmus 	uint8 gradientType;
183*fb07ece0SStephan Aßmus 	uint8 gradientFlags;
184*fb07ece0SStephan Aßmus 	uint8 gradientStopCount;
185*fb07ece0SStephan Aßmus 	if (!buffer.Read(gradientType)
186*fb07ece0SStephan Aßmus 		|| !buffer.Read(gradientFlags)
187*fb07ece0SStephan Aßmus 		|| !buffer.Read(gradientStopCount)) {
188*fb07ece0SStephan Aßmus 		return NULL;
189*fb07ece0SStephan Aßmus 	}
190*fb07ece0SStephan Aßmus 
191*fb07ece0SStephan Aßmus 	Gradient gradient(true);
192*fb07ece0SStephan Aßmus 		// empty gradient
193*fb07ece0SStephan Aßmus 
194*fb07ece0SStephan Aßmus 	gradient.SetType((gradient_type)gradientType);
195*fb07ece0SStephan Aßmus 	// TODO: support more stuff with flags
196*fb07ece0SStephan Aßmus 	// ("inherits transformation" and so on)
197*fb07ece0SStephan Aßmus 	if (gradientFlags & GRADIENT_FLAG_TRANSFORM) {
198*fb07ece0SStephan Aßmus 		if (!_ReadTransformable(buffer, &gradient))
199*fb07ece0SStephan Aßmus 			return NULL;
200*fb07ece0SStephan Aßmus 	}
201*fb07ece0SStephan Aßmus 
202*fb07ece0SStephan Aßmus 	bool alpha = !(gradientFlags & GRADIENT_FLAG_NO_ALPHA);
203*fb07ece0SStephan Aßmus 
204*fb07ece0SStephan Aßmus 	for (int32 i = 0; i < gradientStopCount; i++) {
205*fb07ece0SStephan Aßmus 		uint8 stopOffset;
206*fb07ece0SStephan Aßmus 		rgb_color color;
207*fb07ece0SStephan Aßmus 
208*fb07ece0SStephan Aßmus 		if (!buffer.Read(stopOffset))
209*fb07ece0SStephan Aßmus 			return NULL;
210*fb07ece0SStephan Aßmus 
211*fb07ece0SStephan Aßmus 		if (alpha) {
212*fb07ece0SStephan Aßmus 			if (!buffer.Read((uint32&)color))
213*fb07ece0SStephan Aßmus 				return NULL;
214*fb07ece0SStephan Aßmus 		} else {
215*fb07ece0SStephan Aßmus 			color.alpha = 255;
216*fb07ece0SStephan Aßmus 			if (!buffer.Read(color.red)
217*fb07ece0SStephan Aßmus 				|| !buffer.Read(color.green)
218*fb07ece0SStephan Aßmus 				|| !buffer.Read(color.blue)) {
219*fb07ece0SStephan Aßmus 				return NULL;
220*fb07ece0SStephan Aßmus 			}
221*fb07ece0SStephan Aßmus 		}
222*fb07ece0SStephan Aßmus 
223*fb07ece0SStephan Aßmus 		gradient.AddColor(color, stopOffset / 255.0);
224*fb07ece0SStephan Aßmus 	}
225*fb07ece0SStephan Aßmus 
226*fb07ece0SStephan Aßmus 	style->SetGradient(&gradient);
227*fb07ece0SStephan Aßmus 
228*fb07ece0SStephan Aßmus 	styleDeleter.Detach();
229*fb07ece0SStephan Aßmus 	return style;
230*fb07ece0SStephan Aßmus }
231*fb07ece0SStephan Aßmus 
232*fb07ece0SStephan Aßmus // _ParseStyles
233*fb07ece0SStephan Aßmus status_t
234*fb07ece0SStephan Aßmus FlatIconImporter::_ParseStyles(LittleEndianBuffer& buffer,
235*fb07ece0SStephan Aßmus 							   StyleContainer* styles)
236*fb07ece0SStephan Aßmus {
237*fb07ece0SStephan Aßmus 	uint8 styleCount;
238*fb07ece0SStephan Aßmus 	if (!buffer.Read(styleCount))
239*fb07ece0SStephan Aßmus 		return B_ERROR;
240*fb07ece0SStephan Aßmus 
241*fb07ece0SStephan Aßmus 	for (int32 i = 0; i < styleCount; i++) {
242*fb07ece0SStephan Aßmus 		uint8 styleType;
243*fb07ece0SStephan Aßmus 		if (!buffer.Read(styleType))
244*fb07ece0SStephan Aßmus 			return B_ERROR;
245*fb07ece0SStephan Aßmus 		Style* style = NULL;
246*fb07ece0SStephan Aßmus 		if (styleType == TAG_STYLE_SOLID_COLOR) {
247*fb07ece0SStephan Aßmus 			// solid color
248*fb07ece0SStephan Aßmus 			style = _ReadColorStyle(buffer, true);
249*fb07ece0SStephan Aßmus 			if (!style)
250*fb07ece0SStephan Aßmus 				return B_NO_MEMORY;
251*fb07ece0SStephan Aßmus 		} else if (styleType == TAG_STYLE_SOLID_COLOR_NO_ALPHA) {
252*fb07ece0SStephan Aßmus 			// solid color without alpha
253*fb07ece0SStephan Aßmus 			style = _ReadColorStyle(buffer, false);
254*fb07ece0SStephan Aßmus 			if (!style)
255*fb07ece0SStephan Aßmus 				return B_NO_MEMORY;
256*fb07ece0SStephan Aßmus 		} else if (styleType == TAG_STYLE_GRADIENT) {
257*fb07ece0SStephan Aßmus 			// gradient
258*fb07ece0SStephan Aßmus 			style = _ReadGradientStyle(buffer);
259*fb07ece0SStephan Aßmus 			if (!style)
260*fb07ece0SStephan Aßmus 				return B_NO_MEMORY;
261*fb07ece0SStephan Aßmus 		} else {
262*fb07ece0SStephan Aßmus 			// unkown style type, skip tag
263*fb07ece0SStephan Aßmus 			uint16 tagLength;
264*fb07ece0SStephan Aßmus 			if (!buffer.Read(tagLength))
265*fb07ece0SStephan Aßmus 				return B_ERROR;
266*fb07ece0SStephan Aßmus 			buffer.Skip(tagLength);
267*fb07ece0SStephan Aßmus 			continue;
268*fb07ece0SStephan Aßmus 		}
269*fb07ece0SStephan Aßmus 		// add style if we were able to read one
270*fb07ece0SStephan Aßmus 		if (style && !styles->AddStyle(style)) {
271*fb07ece0SStephan Aßmus 			delete style;
272*fb07ece0SStephan Aßmus 			return B_NO_MEMORY;
273*fb07ece0SStephan Aßmus 		}
274*fb07ece0SStephan Aßmus 	}
275*fb07ece0SStephan Aßmus 
276*fb07ece0SStephan Aßmus 	return B_OK;
277*fb07ece0SStephan Aßmus }
278*fb07ece0SStephan Aßmus 
279*fb07ece0SStephan Aßmus // read_path_no_curves
280*fb07ece0SStephan Aßmus static bool
281*fb07ece0SStephan Aßmus read_path_no_curves(LittleEndianBuffer& buffer, VectorPath* path,
282*fb07ece0SStephan Aßmus 					uint8 pointCount)
283*fb07ece0SStephan Aßmus {
284*fb07ece0SStephan Aßmus 	for (uint32 p = 0; p < pointCount; p++) {
285*fb07ece0SStephan Aßmus 		BPoint point;
286*fb07ece0SStephan Aßmus 		if (!read_coord(buffer, point.x)
287*fb07ece0SStephan Aßmus 			|| !read_coord(buffer, point.y))
288*fb07ece0SStephan Aßmus 			return false;
289*fb07ece0SStephan Aßmus 
290*fb07ece0SStephan Aßmus 		if (!path->AddPoint(point))
291*fb07ece0SStephan Aßmus 			return false;
292*fb07ece0SStephan Aßmus 	}
293*fb07ece0SStephan Aßmus 	return true;
294*fb07ece0SStephan Aßmus }
295*fb07ece0SStephan Aßmus 
296*fb07ece0SStephan Aßmus // read_path_curves
297*fb07ece0SStephan Aßmus static bool
298*fb07ece0SStephan Aßmus read_path_curves(LittleEndianBuffer& buffer, VectorPath* path,
299*fb07ece0SStephan Aßmus 				 uint8 pointCount)
300*fb07ece0SStephan Aßmus {
301*fb07ece0SStephan Aßmus 	for (uint32 p = 0; p < pointCount; p++) {
302*fb07ece0SStephan Aßmus 		BPoint point;
303*fb07ece0SStephan Aßmus 		if (!read_coord(buffer, point.x)
304*fb07ece0SStephan Aßmus 			|| !read_coord(buffer, point.y))
305*fb07ece0SStephan Aßmus 			return false;
306*fb07ece0SStephan Aßmus 
307*fb07ece0SStephan Aßmus 		BPoint pointIn;
308*fb07ece0SStephan Aßmus 		if (!read_coord(buffer, pointIn.x)
309*fb07ece0SStephan Aßmus 			|| !read_coord(buffer, pointIn.y))
310*fb07ece0SStephan Aßmus 			return false;
311*fb07ece0SStephan Aßmus 
312*fb07ece0SStephan Aßmus 		BPoint pointOut;
313*fb07ece0SStephan Aßmus 		if (!read_coord(buffer, pointOut.x)
314*fb07ece0SStephan Aßmus 			|| !read_coord(buffer, pointOut.y))
315*fb07ece0SStephan Aßmus 			return false;
316*fb07ece0SStephan Aßmus 
317*fb07ece0SStephan Aßmus 		if (!path->AddPoint(point, pointIn, pointOut, false))
318*fb07ece0SStephan Aßmus 			return false;
319*fb07ece0SStephan Aßmus 	}
320*fb07ece0SStephan Aßmus 	return true;
321*fb07ece0SStephan Aßmus }
322*fb07ece0SStephan Aßmus 
323*fb07ece0SStephan Aßmus // read_path_with_commands
324*fb07ece0SStephan Aßmus static bool
325*fb07ece0SStephan Aßmus read_path_with_commands(LittleEndianBuffer& buffer, VectorPath* path,
326*fb07ece0SStephan Aßmus 						uint8 pointCount)
327*fb07ece0SStephan Aßmus {
328*fb07ece0SStephan Aßmus 	PathCommandQueue queue;
329*fb07ece0SStephan Aßmus 	return queue.Read(buffer, path, pointCount);
330*fb07ece0SStephan Aßmus }
331*fb07ece0SStephan Aßmus 
332*fb07ece0SStephan Aßmus 
333*fb07ece0SStephan Aßmus // _ParsePaths
334*fb07ece0SStephan Aßmus status_t
335*fb07ece0SStephan Aßmus FlatIconImporter::_ParsePaths(LittleEndianBuffer& buffer,
336*fb07ece0SStephan Aßmus 							  PathContainer* paths)
337*fb07ece0SStephan Aßmus {
338*fb07ece0SStephan Aßmus 	uint8 pathCount;
339*fb07ece0SStephan Aßmus 	if (!buffer.Read(pathCount))
340*fb07ece0SStephan Aßmus 		return B_ERROR;
341*fb07ece0SStephan Aßmus 
342*fb07ece0SStephan Aßmus 	for (int32 i = 0; i < pathCount; i++) {
343*fb07ece0SStephan Aßmus 		uint8 pathFlags;
344*fb07ece0SStephan Aßmus 		uint8 pointCount;
345*fb07ece0SStephan Aßmus 		if (!buffer.Read(pathFlags) || !buffer.Read(pointCount))
346*fb07ece0SStephan Aßmus 			return B_ERROR;
347*fb07ece0SStephan Aßmus 
348*fb07ece0SStephan Aßmus 		VectorPath* path = new (nothrow) VectorPath();
349*fb07ece0SStephan Aßmus 		if (!path)
350*fb07ece0SStephan Aßmus 			return B_NO_MEMORY;
351*fb07ece0SStephan Aßmus 
352*fb07ece0SStephan Aßmus 		// chose path reading strategy depending on path flags
353*fb07ece0SStephan Aßmus 		bool error = false;
354*fb07ece0SStephan Aßmus 		if (pathFlags & PATH_FLAGS_NO_CURVES) {
355*fb07ece0SStephan Aßmus 			if (!read_path_no_curves(buffer, path, pointCount))
356*fb07ece0SStephan Aßmus 				error = true;
357*fb07ece0SStephan Aßmus 		} else if (pathFlags & PATH_FLAGS_USES_COMMANDS) {
358*fb07ece0SStephan Aßmus 			if (!read_path_with_commands(buffer, path, pointCount))
359*fb07ece0SStephan Aßmus 				error = true;
360*fb07ece0SStephan Aßmus 		} else {
361*fb07ece0SStephan Aßmus 			if (!read_path_curves(buffer, path, pointCount))
362*fb07ece0SStephan Aßmus 				error = true;
363*fb07ece0SStephan Aßmus 		}
364*fb07ece0SStephan Aßmus 
365*fb07ece0SStephan Aßmus 		if (error) {
366*fb07ece0SStephan Aßmus 			delete path;
367*fb07ece0SStephan Aßmus 			return B_ERROR;
368*fb07ece0SStephan Aßmus 		}
369*fb07ece0SStephan Aßmus 		// post process path to clean it up
370*fb07ece0SStephan Aßmus 		path->CleanUp();
371*fb07ece0SStephan Aßmus 		if (pathFlags & PATH_FLAGS_CLOSED)
372*fb07ece0SStephan Aßmus 			path->SetClosed(true);
373*fb07ece0SStephan Aßmus 		// add path to container
374*fb07ece0SStephan Aßmus 		if (!paths->AddPath(path)) {
375*fb07ece0SStephan Aßmus 			delete path;
376*fb07ece0SStephan Aßmus 			return B_NO_MEMORY;
377*fb07ece0SStephan Aßmus 		}
378*fb07ece0SStephan Aßmus 	}
379*fb07ece0SStephan Aßmus 
380*fb07ece0SStephan Aßmus 	return B_OK;
381*fb07ece0SStephan Aßmus }
382*fb07ece0SStephan Aßmus 
383*fb07ece0SStephan Aßmus // _ReadTransformer
384*fb07ece0SStephan Aßmus static Transformer*
385*fb07ece0SStephan Aßmus _ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source)
386*fb07ece0SStephan Aßmus {
387*fb07ece0SStephan Aßmus 	uint8 transformerType;
388*fb07ece0SStephan Aßmus 	if (!buffer.Read(transformerType))
389*fb07ece0SStephan Aßmus 		return NULL;
390*fb07ece0SStephan Aßmus 
391*fb07ece0SStephan Aßmus 	switch (transformerType) {
392*fb07ece0SStephan Aßmus 		case TAG_TRANSFORMER_AFFINE: {
393*fb07ece0SStephan Aßmus 			AffineTransformer* affine
394*fb07ece0SStephan Aßmus 				= new (nothrow) AffineTransformer(source);
395*fb07ece0SStephan Aßmus 			if (!affine)
396*fb07ece0SStephan Aßmus 				return NULL;
397*fb07ece0SStephan Aßmus 			double matrix[6];
398*fb07ece0SStephan Aßmus 			for (int32 i = 0; i < 6; i++) {
399*fb07ece0SStephan Aßmus 				float value;
400*fb07ece0SStephan Aßmus 				if (!buffer.Read(value)) {
401*fb07ece0SStephan Aßmus 					delete affine;
402*fb07ece0SStephan Aßmus 					return NULL;
403*fb07ece0SStephan Aßmus 				}
404*fb07ece0SStephan Aßmus 				matrix[i] = value;
405*fb07ece0SStephan Aßmus 			}
406*fb07ece0SStephan Aßmus 			affine->load_from(matrix);
407*fb07ece0SStephan Aßmus 			return affine;
408*fb07ece0SStephan Aßmus 		}
409*fb07ece0SStephan Aßmus 		case TAG_TRANSFORMER_CONTOUR: {
410*fb07ece0SStephan Aßmus 			ContourTransformer* contour
411*fb07ece0SStephan Aßmus 				= new (nothrow) ContourTransformer(source);
412*fb07ece0SStephan Aßmus 			uint8 width;
413*fb07ece0SStephan Aßmus 			uint8 lineJoin;
414*fb07ece0SStephan Aßmus 			uint8 miterLimit;
415*fb07ece0SStephan Aßmus 			if (!contour
416*fb07ece0SStephan Aßmus 				|| !buffer.Read(width)
417*fb07ece0SStephan Aßmus 				|| !buffer.Read(lineJoin)
418*fb07ece0SStephan Aßmus 				|| !buffer.Read(miterLimit)) {
419*fb07ece0SStephan Aßmus 				delete contour;
420*fb07ece0SStephan Aßmus 				return NULL;
421*fb07ece0SStephan Aßmus 			}
422*fb07ece0SStephan Aßmus 			contour->width(width - 128.0);
423*fb07ece0SStephan Aßmus 			contour->line_join((agg::line_join_e)lineJoin);
424*fb07ece0SStephan Aßmus 			contour->miter_limit(miterLimit);
425*fb07ece0SStephan Aßmus 			return contour;
426*fb07ece0SStephan Aßmus 		}
427*fb07ece0SStephan Aßmus 		case TAG_TRANSFORMER_PERSPECTIVE: {
428*fb07ece0SStephan Aßmus 			PerspectiveTransformer* perspective
429*fb07ece0SStephan Aßmus 				= new (nothrow) PerspectiveTransformer(source);
430*fb07ece0SStephan Aßmus 			// TODO: upgrade AGG to be able to support storage of
431*fb07ece0SStephan Aßmus 			// trans_perspective
432*fb07ece0SStephan Aßmus 			return perspective;
433*fb07ece0SStephan Aßmus 		}
434*fb07ece0SStephan Aßmus 		case TAG_TRANSFORMER_STROKE: {
435*fb07ece0SStephan Aßmus 			StrokeTransformer* stroke
436*fb07ece0SStephan Aßmus 				= new (nothrow) StrokeTransformer(source);
437*fb07ece0SStephan Aßmus 			uint8 width;
438*fb07ece0SStephan Aßmus 			uint8 lineJoin;
439*fb07ece0SStephan Aßmus 			uint8 lineCap;
440*fb07ece0SStephan Aßmus 			uint8 miterLimit;
441*fb07ece0SStephan Aßmus //			uint8 shorten;
442*fb07ece0SStephan Aßmus 			if (!stroke
443*fb07ece0SStephan Aßmus 				|| !buffer.Read(width)
444*fb07ece0SStephan Aßmus 				|| !buffer.Read(lineJoin)
445*fb07ece0SStephan Aßmus 				|| !buffer.Read(lineCap)
446*fb07ece0SStephan Aßmus 				|| !buffer.Read(miterLimit)) {
447*fb07ece0SStephan Aßmus 				delete stroke;
448*fb07ece0SStephan Aßmus 				return NULL;
449*fb07ece0SStephan Aßmus 			}
450*fb07ece0SStephan Aßmus 			stroke->width(width - 128.0);
451*fb07ece0SStephan Aßmus 			stroke->line_join((agg::line_join_e)lineJoin);
452*fb07ece0SStephan Aßmus 			stroke->line_cap((agg::line_cap_e)lineCap);
453*fb07ece0SStephan Aßmus 			stroke->miter_limit(miterLimit);
454*fb07ece0SStephan Aßmus 			return stroke;
455*fb07ece0SStephan Aßmus 		}
456*fb07ece0SStephan Aßmus 		default: {
457*fb07ece0SStephan Aßmus 			// unkown transformer, skip tag
458*fb07ece0SStephan Aßmus 			uint16 tagLength;
459*fb07ece0SStephan Aßmus 			if (!buffer.Read(tagLength))
460*fb07ece0SStephan Aßmus 				return NULL;
461*fb07ece0SStephan Aßmus 			buffer.Skip(tagLength);
462*fb07ece0SStephan Aßmus 			return NULL;
463*fb07ece0SStephan Aßmus 		}
464*fb07ece0SStephan Aßmus 	}
465*fb07ece0SStephan Aßmus }
466*fb07ece0SStephan Aßmus 
467*fb07ece0SStephan Aßmus // _ReadPathSourceShape
468*fb07ece0SStephan Aßmus static Shape*
469*fb07ece0SStephan Aßmus _ReadPathSourceShape(LittleEndianBuffer& buffer,
470*fb07ece0SStephan Aßmus 					 StyleContainer* styles, PathContainer* paths)
471*fb07ece0SStephan Aßmus {
472*fb07ece0SStephan Aßmus 	// find out which style this shape uses
473*fb07ece0SStephan Aßmus 	uint8 styleIndex;
474*fb07ece0SStephan Aßmus 	uint8 pathCount;
475*fb07ece0SStephan Aßmus 	if (!buffer.Read(styleIndex) || !buffer.Read(pathCount))
476*fb07ece0SStephan Aßmus 		return NULL;
477*fb07ece0SStephan Aßmus 
478*fb07ece0SStephan Aßmus 	Style* style = styles->StyleAt(styleIndex);
479*fb07ece0SStephan Aßmus 	if (!style) {
480*fb07ece0SStephan Aßmus 		printf("_ReadPathSourceShape() - "
481*fb07ece0SStephan Aßmus 			   "shape references non-existing style %d\n", styleIndex);
482*fb07ece0SStephan Aßmus 		return NULL;
483*fb07ece0SStephan Aßmus 	}
484*fb07ece0SStephan Aßmus 
485*fb07ece0SStephan Aßmus 	// create the shape
486*fb07ece0SStephan Aßmus 	Shape* shape = new (nothrow) Shape(style);
487*fb07ece0SStephan Aßmus 	ObjectDeleter<Shape> shapeDeleter(shape);
488*fb07ece0SStephan Aßmus 
489*fb07ece0SStephan Aßmus 	if (!shape || shape->InitCheck() < B_OK)
490*fb07ece0SStephan Aßmus 		return NULL;
491*fb07ece0SStephan Aßmus 
492*fb07ece0SStephan Aßmus 	// find out which paths this shape uses
493*fb07ece0SStephan Aßmus 	for (uint32 i = 0; i < pathCount; i++) {
494*fb07ece0SStephan Aßmus 		uint8 pathIndex;
495*fb07ece0SStephan Aßmus 		if (!buffer.Read(pathIndex))
496*fb07ece0SStephan Aßmus 			return NULL;
497*fb07ece0SStephan Aßmus 
498*fb07ece0SStephan Aßmus 		VectorPath* path = paths->PathAt(pathIndex);
499*fb07ece0SStephan Aßmus 		if (!path) {
500*fb07ece0SStephan Aßmus 			printf("_ReadPathSourceShape() - "
501*fb07ece0SStephan Aßmus 				   "shape references non-existing path %d\n", pathIndex);
502*fb07ece0SStephan Aßmus 			continue;
503*fb07ece0SStephan Aßmus 		}
504*fb07ece0SStephan Aßmus 		shape->Paths()->AddPath(path);
505*fb07ece0SStephan Aßmus 	}
506*fb07ece0SStephan Aßmus 
507*fb07ece0SStephan Aßmus 	// shape flags
508*fb07ece0SStephan Aßmus 	uint8 shapeFlags;
509*fb07ece0SStephan Aßmus 	if (!buffer.Read(shapeFlags))
510*fb07ece0SStephan Aßmus 		return NULL;
511*fb07ece0SStephan Aßmus 
512*fb07ece0SStephan Aßmus 	shape->SetHinting(shapeFlags & SHAPE_FLAG_HINTING);
513*fb07ece0SStephan Aßmus 
514*fb07ece0SStephan Aßmus 	if (shapeFlags & SHAPE_FLAG_TRANSFORM) {
515*fb07ece0SStephan Aßmus 		// transformation
516*fb07ece0SStephan Aßmus 		if (!_ReadTransformable(buffer, shape))
517*fb07ece0SStephan Aßmus 			return NULL;
518*fb07ece0SStephan Aßmus 	} else if (shapeFlags & SHAPE_FLAG_TRANSLATION) {
519*fb07ece0SStephan Aßmus 		// translation
520*fb07ece0SStephan Aßmus 		if (!_ReadTranslation(buffer, shape))
521*fb07ece0SStephan Aßmus 			return NULL;
522*fb07ece0SStephan Aßmus 	}
523*fb07ece0SStephan Aßmus 
524*fb07ece0SStephan Aßmus 	if (shapeFlags & SHAPE_FLAG_LOD_SCALE) {
525*fb07ece0SStephan Aßmus 		// min max visibility scale
526*fb07ece0SStephan Aßmus 		uint8 minScale;
527*fb07ece0SStephan Aßmus 		uint8 maxScale;
528*fb07ece0SStephan Aßmus 		if (!buffer.Read(minScale) || !buffer.Read(maxScale))
529*fb07ece0SStephan Aßmus 			return NULL;
530*fb07ece0SStephan Aßmus 		shape->SetMinVisibilityScale((float)minScale);
531*fb07ece0SStephan Aßmus 		shape->SetMaxVisibilityScale((float)maxScale);
532*fb07ece0SStephan Aßmus 	}
533*fb07ece0SStephan Aßmus 
534*fb07ece0SStephan Aßmus 	// transformers
535*fb07ece0SStephan Aßmus 	if (shapeFlags & SHAPE_FLAG_HAS_TRANSFORMERS) {
536*fb07ece0SStephan Aßmus 		uint8 transformerCount;
537*fb07ece0SStephan Aßmus 		if (!buffer.Read(transformerCount))
538*fb07ece0SStephan Aßmus 			return NULL;
539*fb07ece0SStephan Aßmus 		for (uint32 i = 0; i < transformerCount; i++) {
540*fb07ece0SStephan Aßmus 			Transformer* transformer
541*fb07ece0SStephan Aßmus 				= _ReadTransformer(buffer, shape->VertexSource());
542*fb07ece0SStephan Aßmus 			if (transformer && !shape->AddTransformer(transformer)) {
543*fb07ece0SStephan Aßmus 				delete transformer;
544*fb07ece0SStephan Aßmus 				return NULL;
545*fb07ece0SStephan Aßmus 			}
546*fb07ece0SStephan Aßmus 		}
547*fb07ece0SStephan Aßmus 	}
548*fb07ece0SStephan Aßmus 
549*fb07ece0SStephan Aßmus 	shapeDeleter.Detach();
550*fb07ece0SStephan Aßmus 	return shape;
551*fb07ece0SStephan Aßmus }
552*fb07ece0SStephan Aßmus 
553*fb07ece0SStephan Aßmus // _ParseShapes
554*fb07ece0SStephan Aßmus status_t
555*fb07ece0SStephan Aßmus FlatIconImporter::_ParseShapes(LittleEndianBuffer& buffer,
556*fb07ece0SStephan Aßmus 							   StyleContainer* styles,
557*fb07ece0SStephan Aßmus 							   PathContainer* paths,
558*fb07ece0SStephan Aßmus 							   ShapeContainer* shapes)
559*fb07ece0SStephan Aßmus {
560*fb07ece0SStephan Aßmus 	uint8 shapeCount;
561*fb07ece0SStephan Aßmus 	if (!buffer.Read(shapeCount))
562*fb07ece0SStephan Aßmus 		return B_ERROR;
563*fb07ece0SStephan Aßmus 
564*fb07ece0SStephan Aßmus 	for (uint32 i = 0; i < shapeCount; i++) {
565*fb07ece0SStephan Aßmus 		uint8 shapeType;
566*fb07ece0SStephan Aßmus 		if (!buffer.Read(shapeType))
567*fb07ece0SStephan Aßmus 			return B_ERROR;
568*fb07ece0SStephan Aßmus 		Shape* shape = NULL;
569*fb07ece0SStephan Aßmus 		if (shapeType == TAG_SHAPE_PATH_SOURCE) {
570*fb07ece0SStephan Aßmus 			// path source shape
571*fb07ece0SStephan Aßmus 			shape = _ReadPathSourceShape(buffer, styles, paths);
572*fb07ece0SStephan Aßmus 			if (!shape)
573*fb07ece0SStephan Aßmus 				return B_NO_MEMORY;
574*fb07ece0SStephan Aßmus 		} else {
575*fb07ece0SStephan Aßmus 			// unkown shape type, skip tag
576*fb07ece0SStephan Aßmus 			uint16 tagLength;
577*fb07ece0SStephan Aßmus 			if (!buffer.Read(tagLength))
578*fb07ece0SStephan Aßmus 				return B_ERROR;
579*fb07ece0SStephan Aßmus 			buffer.Skip(tagLength);
580*fb07ece0SStephan Aßmus 			continue;
581*fb07ece0SStephan Aßmus 		}
582*fb07ece0SStephan Aßmus 		// add shape if we were able to read one
583*fb07ece0SStephan Aßmus 		if (shape && !shapes->AddShape(shape)) {
584*fb07ece0SStephan Aßmus 			delete shape;
585*fb07ece0SStephan Aßmus 			return B_NO_MEMORY;
586*fb07ece0SStephan Aßmus 		}
587*fb07ece0SStephan Aßmus 	}
588*fb07ece0SStephan Aßmus 
589*fb07ece0SStephan Aßmus 	return B_OK;
590*fb07ece0SStephan Aßmus }
591*fb07ece0SStephan Aßmus 
592*fb07ece0SStephan Aßmus 
593*fb07ece0SStephan Aßmus 
594*fb07ece0SStephan Aßmus 
595