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