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