xref: /haiku/src/libs/icon/flat_icon/PathCommandQueue.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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
22 PathCommandQueue::PathCommandQueue()
23 	: fCommandBuffer(),
24 	  fPointBuffer(),
25 
26 	  fCommandByte(0),
27 	  fCommandPos(0),
28 
29 	  fCommandCount(0)
30 {
31 }
32 
33 // destructor
34 PathCommandQueue::~PathCommandQueue()
35 {
36 }
37 
38 // Write
39 bool
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
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
170 PathCommandQueue::_AppendHLine(float x)
171 {
172 	return _AppendCommand(PATH_COMMAND_H_LINE)
173 		&& write_coord(fPointBuffer, x);
174 }
175 
176 // _AppendVLine
177 bool
178 PathCommandQueue::_AppendVLine(float y)
179 {
180 	return _AppendCommand(PATH_COMMAND_V_LINE)
181 		&& write_coord(fPointBuffer, y);
182 }
183 
184 // _AppendLine
185 bool
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
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
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
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