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