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