1 /*
2 * Copyright 2006, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Stephan Aßmus <superstippi@gmx.de>
7 */
8
9 #include "PathCommandQueue.h"
10
11 #include <stdio.h>
12
13 #include <Point.h>
14
15 #include "FlatIconFormat.h"
16 #include "VectorPath.h"
17
18 _USING_ICON_NAMESPACE;
19
20
21 // constructor
PathCommandQueue()22 PathCommandQueue::PathCommandQueue()
23 : fCommandBuffer(),
24 fPointBuffer(),
25
26 fCommandByte(0),
27 fCommandPos(0),
28
29 fCommandCount(0)
30 {
31 }
32
33 // destructor
~PathCommandQueue()34 PathCommandQueue::~PathCommandQueue()
35 {
36 }
37
38 // Write
39 bool
Write(LittleEndianBuffer & buffer,const VectorPath * path,uint8 pointCount)40 PathCommandQueue::Write(LittleEndianBuffer& buffer,
41 const VectorPath* path, uint8 pointCount)
42 {
43 // reset
44 fCommandCount = 0;
45 fCommandByte = 0;
46 fCommandPos = 0;
47 fCommandBuffer.Reset();
48 fPointBuffer.Reset();
49
50 BPoint last(B_ORIGIN);
51
52 for (uint32 p = 0; p < pointCount; p++) {
53 BPoint point;
54 BPoint pointIn;
55 BPoint pointOut;
56 if (!path->GetPointsAt(p, point, pointIn, pointOut))
57 return false;
58
59 if (point == pointIn && point == pointOut) {
60 // single point is sufficient
61 if (point.x == last.x) {
62 // vertical line
63 if (!_AppendVLine(point.y))
64 return false;
65 } else if (point.y == last.y) {
66 // horizontal line
67 if (!_AppendHLine(point.x))
68 return false;
69 } else {
70 // line
71 if (!_AppendLine(point))
72 return false;
73 }
74 } else {
75 // needing to write all three points
76 if (!_AppendCurve(point, pointIn, pointOut))
77 return false;
78 }
79
80 last = point;
81 }
82
83 if (fCommandPos > 0) {
84 // the last couple commands have not been written
85 if (!fCommandBuffer.Write(fCommandByte))
86 return false;
87 }
88
89 return buffer.Write(fCommandBuffer) && buffer.Write(fPointBuffer);
90 }
91
92 // Read
93 bool
Read(LittleEndianBuffer & buffer,VectorPath * path,uint8 pointCount)94 PathCommandQueue::Read(LittleEndianBuffer& buffer,
95 VectorPath* path, uint8 pointCount)
96 {
97 // reset
98 fCommandCount = 0;
99 fCommandByte = 0;
100 fCommandPos = 0;
101
102 fCommandBuffer.Reset();
103
104 // NOTE: fPointBuffer is not used for reading
105 // we read the command buffer and then use the
106 // buffer directly for the coords
107
108 // read command buffer
109 uint8 commandBufferSize = (pointCount + 3) / 4;
110 if (!buffer.Read(fCommandBuffer, commandBufferSize))
111 return false;
112
113 BPoint last(B_ORIGIN);
114 for (uint32 p = 0; p < pointCount; p++) {
115
116 uint8 command;
117 if (!_ReadCommand(command))
118 return false;
119
120 BPoint point;
121 BPoint pointIn;
122 BPoint pointOut;
123
124 switch (command) {
125 case PATH_COMMAND_H_LINE:
126 if (!read_coord(buffer, point.x))
127 return false;
128 point.y = last.y;
129 pointIn = point;
130 pointOut = point;
131 break;
132 case PATH_COMMAND_V_LINE:
133 if (!read_coord(buffer, point.y))
134 return false;
135 point.x = last.x;
136 pointIn = point;
137 pointOut = point;
138 break;
139 case PATH_COMMAND_LINE:
140 if (!read_coord(buffer, point.x)
141 || !read_coord(buffer, point.y))
142 return false;
143 pointIn = point;
144 pointOut = point;
145 break;
146 case PATH_COMMAND_CURVE:
147 if (!read_coord(buffer, point.x)
148 || !read_coord(buffer, point.y)
149 || !read_coord(buffer, pointIn.x)
150 || !read_coord(buffer, pointIn.y)
151 || !read_coord(buffer, pointOut.x)
152 || !read_coord(buffer, pointOut.y))
153 return false;
154 break;
155 }
156
157 if (!path->AddPoint(point, pointIn, pointOut, false))
158 return false;
159
160 last = point;
161 }
162
163 return true;
164 }
165
166 // #pragma mark -
167
168 // _AppendHLine
169 bool
_AppendHLine(float x)170 PathCommandQueue::_AppendHLine(float x)
171 {
172 return _AppendCommand(PATH_COMMAND_H_LINE)
173 && write_coord(fPointBuffer, x);
174 }
175
176 // _AppendVLine
177 bool
_AppendVLine(float y)178 PathCommandQueue::_AppendVLine(float y)
179 {
180 return _AppendCommand(PATH_COMMAND_V_LINE)
181 && write_coord(fPointBuffer, y);
182 }
183
184 // _AppendLine
185 bool
_AppendLine(const BPoint & point)186 PathCommandQueue::_AppendLine(const BPoint& point)
187 {
188 return _AppendCommand(PATH_COMMAND_LINE)
189 && write_coord(fPointBuffer, point.x)
190 && write_coord(fPointBuffer, point.y);
191 }
192
193 // _AppendCurve
194 bool
_AppendCurve(const BPoint & point,const BPoint & pointIn,const BPoint & pointOut)195 PathCommandQueue::_AppendCurve(const BPoint& point,
196 const BPoint& pointIn,
197 const BPoint& pointOut)
198 {
199 return _AppendCommand(PATH_COMMAND_CURVE)
200 && write_coord(fPointBuffer, point.x)
201 && write_coord(fPointBuffer, point.y)
202 && write_coord(fPointBuffer, pointIn.x)
203 && write_coord(fPointBuffer, pointIn.y)
204 && write_coord(fPointBuffer, pointOut.x)
205 && write_coord(fPointBuffer, pointOut.y);
206 }
207
208 // #pragma mark -
209
210 // _AppendCommand
211 bool
_AppendCommand(uint8 command)212 PathCommandQueue::_AppendCommand(uint8 command)
213 {
214 // NOTE: a path command uses 2 bits, so 4 of
215 // them fit into a single byte
216 // after we have appended the fourth command,
217 // the byte is written to fCommandBuffer and
218 // the cycle repeats
219
220 if (fCommandCount == 255) {
221 printf("PathCommandQueue::_AppendCommand() - "
222 "maximum path section count reached\n");
223 return false;
224 }
225
226 fCommandByte |= command << fCommandPos;
227 fCommandPos += 2;
228 fCommandCount++;
229
230 if (fCommandPos == 8) {
231 uint8 commandByte = fCommandByte;
232 fCommandByte = 0;
233 fCommandPos = 0;
234 return fCommandBuffer.Write(commandByte);
235 }
236
237 return true;
238 }
239
240
241 // _ReadCommand
242 bool
_ReadCommand(uint8 & command)243 PathCommandQueue::_ReadCommand(uint8& command)
244 {
245 if (fCommandCount == 255) {
246 printf("PathCommandQueue::_NextCommand() - "
247 "maximum path section count reached\n");
248 return false;
249 }
250
251 if (fCommandPos == 0) {
252 // fetch the next four commands from the buffer
253 if (!fCommandBuffer.Read(fCommandByte))
254 return false;
255 }
256
257 command = (fCommandByte >> fCommandPos) & 0x03;
258 fCommandPos += 2;
259 fCommandCount++;
260
261 if (fCommandPos == 8)
262 fCommandPos = 0;
263
264 return true;
265 }
266
267
268