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 "FlatIconImporter.h" 10 11 #include <new> 12 #include <stdio.h> 13 14 #include <Archivable.h> 15 #include <DataIO.h> 16 #include <Message.h> 17 18 #include "AffineTransformer.h" 19 #include "AutoDeleter.h" 20 #include "ContourTransformer.h" 21 #include "FlatIconFormat.h" 22 #include "GradientTransformable.h" 23 #include "Icon.h" 24 #include "LittleEndianBuffer.h" 25 #include "PathCommandQueue.h" 26 #include "PathSourceShape.h" 27 #include "PerspectiveTransformer.h" 28 #include "Shape.h" 29 #include "StrokeTransformer.h" 30 #include "Style.h" 31 #include "VectorPath.h" 32 33 using std::nothrow; 34 35 // constructor 36 FlatIconImporter::FlatIconImporter() 37 #ifdef ICON_O_MATIC 38 : Importer() 39 #endif 40 { 41 } 42 43 // destructor 44 FlatIconImporter::~FlatIconImporter() 45 { 46 } 47 48 // Import 49 status_t 50 FlatIconImporter::Import(Icon* icon, BPositionIO* stream) 51 { 52 #ifdef ICON_O_MATIC 53 status_t ret = Init(icon); 54 if (ret < B_OK) 55 return ret; 56 #else 57 status_t ret; 58 #endif 59 60 // seek around in the stream to figure out the size 61 off_t size = stream->Seek(0, SEEK_END); 62 if (stream->Seek(0, SEEK_SET) != 0) 63 return B_ERROR; 64 65 // we chicken out on anything larger than 256k 66 if (size <= 0 || size > 256 * 1024) 67 return B_BAD_VALUE; 68 69 // read the entire stream into a buffer 70 LittleEndianBuffer buffer(size); 71 if (!buffer.Buffer()) 72 return B_NO_MEMORY; 73 74 if (stream->Read(buffer.Buffer(), size) != size) 75 return B_ERROR; 76 77 ret = _ParseSections(buffer, icon); 78 79 return ret; 80 } 81 82 // Import 83 status_t 84 FlatIconImporter::Import(Icon* icon, uint8* _buffer, size_t size) 85 { 86 #ifdef ICON_O_MATIC 87 status_t ret = Init(icon); 88 if (ret < B_OK) 89 return ret; 90 #endif 91 92 if (!_buffer) 93 return B_BAD_VALUE; 94 95 // attach LittleEndianBuffer to buffer 96 LittleEndianBuffer buffer(_buffer, size); 97 98 return _ParseSections(buffer, icon); 99 } 100 101 // #pragma mark - 102 103 // _ParseSections 104 status_t 105 FlatIconImporter::_ParseSections(LittleEndianBuffer& buffer, Icon* icon) 106 { 107 // test if this is an icon at all 108 uint32 magic; 109 if (!buffer.Read(magic) || magic != FLAT_ICON_MAGIC) 110 return B_BAD_TYPE; 111 112 // styles 113 Container<Style>* styles = icon->Styles(); 114 status_t ret = _ParseStyles(buffer, styles); 115 if (ret < B_OK) { 116 printf("FlatIconImporter::_ParseSections() - " 117 "error parsing styles: %s\n", strerror(ret)); 118 return ret; 119 } 120 121 // paths 122 Container<VectorPath>* paths = icon->Paths(); 123 ret = _ParsePaths(buffer, paths); 124 if (ret < B_OK) { 125 printf("FlatIconImporter::_ParseSections() - " 126 "error parsing paths: %s\n", strerror(ret)); 127 return ret; 128 } 129 130 // shapes 131 ret = _ParseShapes(buffer, styles, paths, icon->Shapes()); 132 if (ret < B_OK) { 133 printf("FlatIconImporter::_ParseSections() - " 134 "error parsing shapes: %s\n", strerror(ret)); 135 return ret; 136 } 137 138 return B_OK; 139 } 140 141 // _ReadTransformable 142 static bool 143 _ReadTransformable(LittleEndianBuffer& buffer, Transformable* transformable) 144 { 145 int32 matrixSize = Transformable::matrix_size; 146 double matrix[matrixSize]; 147 for (int32 i = 0; i < matrixSize; i++) { 148 float value; 149 if (!read_float_24(buffer, value)) 150 return false; 151 matrix[i] = value; 152 } 153 transformable->LoadFrom(matrix); 154 return true; 155 } 156 157 // _ReadTranslation 158 static bool 159 _ReadTranslation(LittleEndianBuffer& buffer, Transformable* transformable) 160 { 161 BPoint t; 162 if (read_coord(buffer, t.x) && read_coord(buffer, t.y)) { 163 transformable->TranslateBy(t); 164 return true; 165 } 166 167 return false; 168 } 169 170 // _ReadColorStyle 171 static Style* 172 _ReadColorStyle(LittleEndianBuffer& buffer, bool alpha, bool gray) 173 { 174 rgb_color color; 175 if (alpha) { 176 if (gray) { 177 if (!buffer.Read(color.red) 178 || !buffer.Read(color.alpha)) 179 return NULL; 180 color.green = color.blue = color.red; 181 } else { 182 if (!buffer.Read((uint32&)color)) 183 return NULL; 184 } 185 } else { 186 color.alpha = 255; 187 if (gray) { 188 if (!buffer.Read(color.red)) 189 return NULL; 190 color.green = color.blue = color.red; 191 } else { 192 if (!buffer.Read(color.red) 193 || !buffer.Read(color.green) 194 || !buffer.Read(color.blue)) 195 return NULL; 196 } 197 } 198 return new (nothrow) Style(color); 199 } 200 201 // _ReadGradientStyle 202 static Style* 203 _ReadGradientStyle(LittleEndianBuffer& buffer) 204 { 205 Style* style = new (nothrow) Style(); 206 if (!style) 207 return NULL; 208 209 ObjectDeleter<Style> styleDeleter(style); 210 211 uint8 gradientType; 212 uint8 gradientFlags; 213 uint8 gradientStopCount; 214 if (!buffer.Read(gradientType) 215 || !buffer.Read(gradientFlags) 216 || !buffer.Read(gradientStopCount)) { 217 return NULL; 218 } 219 220 Gradient gradient(true); 221 // empty gradient 222 223 gradient.SetType((gradients_type)gradientType); 224 // TODO: support more stuff with flags 225 // ("inherits transformation" and so on) 226 if (gradientFlags & GRADIENT_FLAG_TRANSFORM) { 227 if (!_ReadTransformable(buffer, &gradient)) 228 return NULL; 229 } 230 231 bool alpha = !(gradientFlags & GRADIENT_FLAG_NO_ALPHA); 232 bool gray = gradientFlags & GRADIENT_FLAG_GRAYS; 233 234 for (int32 i = 0; i < gradientStopCount; i++) { 235 uint8 stopOffset; 236 rgb_color color; 237 238 if (!buffer.Read(stopOffset)) 239 return NULL; 240 241 if (alpha) { 242 if (gray) { 243 if (!buffer.Read(color.red) 244 || !buffer.Read(color.alpha)) 245 return NULL; 246 color.green = color.blue = color.red; 247 } else { 248 if (!buffer.Read((uint32&)color)) 249 return NULL; 250 } 251 } else { 252 color.alpha = 255; 253 if (gray) { 254 if (!buffer.Read(color.red)) 255 return NULL; 256 color.green = color.blue = color.red; 257 } else { 258 if (!buffer.Read(color.red) 259 || !buffer.Read(color.green) 260 || !buffer.Read(color.blue)) { 261 return NULL; 262 } 263 } 264 } 265 266 gradient.AddColor(color, stopOffset / 255.0); 267 } 268 269 style->SetGradient(&gradient); 270 271 styleDeleter.Detach(); 272 return style; 273 } 274 275 // _ParseStyles 276 status_t 277 FlatIconImporter::_ParseStyles(LittleEndianBuffer& buffer, 278 Container<Style>* styles) 279 { 280 uint8 styleCount; 281 if (!buffer.Read(styleCount)) 282 return B_ERROR; 283 284 for (int32 i = 0; i < styleCount; i++) { 285 uint8 styleType; 286 if (!buffer.Read(styleType)) 287 return B_ERROR; 288 Style* style = NULL; 289 if (styleType == STYLE_TYPE_SOLID_COLOR) { 290 // solid color 291 style = _ReadColorStyle(buffer, true, false); 292 if (!style) 293 return B_NO_MEMORY; 294 } else if (styleType == STYLE_TYPE_SOLID_COLOR_NO_ALPHA) { 295 // solid color without alpha 296 style = _ReadColorStyle(buffer, false, false); 297 if (!style) 298 return B_NO_MEMORY; 299 } else if (styleType == STYLE_TYPE_SOLID_GRAY) { 300 // solid gray plus alpha 301 style = _ReadColorStyle(buffer, true, true); 302 if (!style) 303 return B_NO_MEMORY; 304 } else if (styleType == STYLE_TYPE_SOLID_GRAY_NO_ALPHA) { 305 // solid gray without alpha 306 style = _ReadColorStyle(buffer, false, true); 307 if (!style) 308 return B_NO_MEMORY; 309 } else if (styleType == STYLE_TYPE_GRADIENT) { 310 // gradient 311 style = _ReadGradientStyle(buffer); 312 if (!style) 313 return B_NO_MEMORY; 314 } else { 315 // unkown style type, skip tag 316 uint16 tagLength; 317 if (!buffer.Read(tagLength)) 318 return B_ERROR; 319 buffer.Skip(tagLength); 320 continue; 321 } 322 // add style if we were able to read one 323 if (style && !styles->AddItem(style)) { 324 delete style; 325 return B_NO_MEMORY; 326 } 327 } 328 329 return B_OK; 330 } 331 332 // read_path_no_curves 333 static bool 334 read_path_no_curves(LittleEndianBuffer& buffer, VectorPath* path, 335 uint8 pointCount) 336 { 337 for (uint32 p = 0; p < pointCount; p++) { 338 BPoint point; 339 if (!read_coord(buffer, point.x) 340 || !read_coord(buffer, point.y)) 341 return false; 342 343 if (!path->AddPoint(point)) 344 return false; 345 } 346 return true; 347 } 348 349 // read_path_curves 350 static bool 351 read_path_curves(LittleEndianBuffer& buffer, VectorPath* path, 352 uint8 pointCount) 353 { 354 for (uint32 p = 0; p < pointCount; p++) { 355 BPoint point; 356 if (!read_coord(buffer, point.x) 357 || !read_coord(buffer, point.y)) 358 return false; 359 360 BPoint pointIn; 361 if (!read_coord(buffer, pointIn.x) 362 || !read_coord(buffer, pointIn.y)) 363 return false; 364 365 BPoint pointOut; 366 if (!read_coord(buffer, pointOut.x) 367 || !read_coord(buffer, pointOut.y)) 368 return false; 369 370 if (!path->AddPoint(point, pointIn, pointOut, false)) 371 return false; 372 } 373 return true; 374 } 375 376 // read_path_with_commands 377 static bool 378 read_path_with_commands(LittleEndianBuffer& buffer, VectorPath* path, 379 uint8 pointCount) 380 { 381 PathCommandQueue queue; 382 return queue.Read(buffer, path, pointCount); 383 } 384 385 386 // _ParsePaths 387 status_t 388 FlatIconImporter::_ParsePaths(LittleEndianBuffer& buffer, 389 Container<VectorPath>* paths) 390 { 391 uint8 pathCount; 392 if (!buffer.Read(pathCount)) 393 return B_ERROR; 394 395 for (int32 i = 0; i < pathCount; i++) { 396 uint8 pathFlags; 397 uint8 pointCount; 398 if (!buffer.Read(pathFlags) || !buffer.Read(pointCount)) 399 return B_ERROR; 400 401 VectorPath* path = new (nothrow) VectorPath(); 402 if (!path) 403 return B_NO_MEMORY; 404 405 // chose path reading strategy depending on path flags 406 bool error = false; 407 if (pathFlags & PATH_FLAG_NO_CURVES) { 408 if (!read_path_no_curves(buffer, path, pointCount)) 409 error = true; 410 } else if (pathFlags & PATH_FLAG_USES_COMMANDS) { 411 if (!read_path_with_commands(buffer, path, pointCount)) 412 error = true; 413 } else { 414 if (!read_path_curves(buffer, path, pointCount)) 415 error = true; 416 } 417 418 if (error) { 419 delete path; 420 return B_ERROR; 421 } 422 // post process path to clean it up 423 path->CleanUp(); 424 if (pathFlags & PATH_FLAG_CLOSED) 425 path->SetClosed(true); 426 // add path to container 427 if (!paths->AddItem(path)) { 428 delete path; 429 return B_NO_MEMORY; 430 } 431 } 432 433 return B_OK; 434 } 435 436 // _ReadTransformer 437 static Transformer* 438 _ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source) 439 { 440 uint8 transformerType; 441 if (!buffer.Read(transformerType)) 442 return NULL; 443 444 switch (transformerType) { 445 case TRANSFORMER_TYPE_AFFINE: { 446 AffineTransformer* affine 447 = new (nothrow) AffineTransformer(source); 448 if (!affine) 449 return NULL; 450 double matrix[6]; 451 for (int32 i = 0; i < 6; i++) { 452 float value; 453 if (!buffer.Read(value)) { 454 delete affine; 455 return NULL; 456 } 457 matrix[i] = value; 458 } 459 affine->load_from(matrix); 460 return affine; 461 } 462 case TRANSFORMER_TYPE_CONTOUR: { 463 ContourTransformer* contour 464 = new (nothrow) ContourTransformer(source); 465 uint8 width; 466 uint8 lineJoin; 467 uint8 miterLimit; 468 if (!contour 469 || !buffer.Read(width) 470 || !buffer.Read(lineJoin) 471 || !buffer.Read(miterLimit)) { 472 delete contour; 473 return NULL; 474 } 475 contour->width(width - 128.0); 476 contour->line_join((agg::line_join_e)lineJoin); 477 contour->miter_limit(miterLimit); 478 return contour; 479 } 480 case TRANSFORMER_TYPE_PERSPECTIVE: { 481 PerspectiveTransformer* perspective 482 = new (nothrow) PerspectiveTransformer(source); 483 // TODO: upgrade AGG to be able to support storage of 484 // trans_perspective 485 return perspective; 486 } 487 case TRANSFORMER_TYPE_STROKE: { 488 StrokeTransformer* stroke 489 = new (nothrow) StrokeTransformer(source); 490 uint8 width; 491 uint8 lineOptions; 492 uint8 miterLimit; 493 // uint8 shorten; 494 if (!stroke 495 || !buffer.Read(width) 496 || !buffer.Read(lineOptions) 497 || !buffer.Read(miterLimit)) { 498 delete stroke; 499 return NULL; 500 } 501 stroke->width(width - 128.0); 502 uint8 lineJoin = lineOptions & 15; 503 stroke->line_join((agg::line_join_e)lineJoin); 504 uint8 lineCap = lineOptions >> 4; 505 stroke->line_cap((agg::line_cap_e)lineCap); 506 stroke->miter_limit(miterLimit); 507 return stroke; 508 } 509 default: { 510 // unkown transformer, skip tag 511 uint16 tagLength; 512 if (!buffer.Read(tagLength)) 513 return NULL; 514 buffer.Skip(tagLength); 515 return NULL; 516 } 517 } 518 } 519 520 // _ReadPathSourceShape 521 Shape* 522 FlatIconImporter::_ReadPathSourceShape(LittleEndianBuffer& buffer, 523 Container<Style>* styles, 524 Container<VectorPath>* paths) 525 { 526 // find out which style this shape uses 527 uint8 styleIndex; 528 uint8 pathCount; 529 if (!buffer.Read(styleIndex) || !buffer.Read(pathCount)) 530 return NULL; 531 532 #ifdef ICON_O_MATIC 533 Style* style = styles->ItemAt(StyleIndexFor(styleIndex)); 534 #else 535 Style* style = styles->ItemAt(styleIndex); 536 #endif 537 538 if (!style) { 539 printf("_ReadPathSourceShape() - " 540 "shape references non-existing style %d\n", styleIndex); 541 return NULL; 542 } 543 544 // create the shape 545 PathSourceShape* shape = new (nothrow) PathSourceShape(style); 546 ObjectDeleter<Shape> shapeDeleter(shape); 547 548 if (!shape || shape->InitCheck() < B_OK) 549 return NULL; 550 551 // find out which paths this shape uses 552 for (uint32 i = 0; i < pathCount; i++) { 553 uint8 pathIndex; 554 if (!buffer.Read(pathIndex)) 555 return NULL; 556 557 #ifdef ICON_O_MATIC 558 VectorPath* path = paths->ItemAt(PathIndexFor(pathIndex)); 559 #else 560 VectorPath* path = paths->ItemAt(pathIndex); 561 #endif 562 if (!path) { 563 printf("_ReadPathSourceShape() - " 564 "shape references non-existing path %d\n", pathIndex); 565 continue; 566 } 567 shape->Paths()->AddItem(path); 568 } 569 570 // shape flags 571 uint8 shapeFlags; 572 if (!buffer.Read(shapeFlags)) 573 return NULL; 574 575 shape->SetHinting(shapeFlags & SHAPE_FLAG_HINTING); 576 577 if (shapeFlags & SHAPE_FLAG_TRANSFORM) { 578 // transformation 579 if (!_ReadTransformable(buffer, shape)) 580 return NULL; 581 } else if (shapeFlags & SHAPE_FLAG_TRANSLATION) { 582 // translation 583 if (!_ReadTranslation(buffer, shape)) 584 return NULL; 585 } 586 587 if (shapeFlags & SHAPE_FLAG_LOD_SCALE) { 588 // min max visibility scale 589 uint8 minScale; 590 uint8 maxScale; 591 if (!buffer.Read(minScale) || !buffer.Read(maxScale)) 592 return NULL; 593 shape->SetMinVisibilityScale(minScale / 63.75); 594 shape->SetMaxVisibilityScale(maxScale / 63.75); 595 } 596 597 // transformers 598 if (shapeFlags & SHAPE_FLAG_HAS_TRANSFORMERS) { 599 uint8 transformerCount; 600 if (!buffer.Read(transformerCount)) 601 return NULL; 602 for (uint32 i = 0; i < transformerCount; i++) { 603 Transformer* transformer 604 = _ReadTransformer(buffer, shape->VertexSource()); 605 if (transformer && !shape->Transformers()->AddItem(transformer)) { 606 delete transformer; 607 return NULL; 608 } 609 } 610 } 611 612 shapeDeleter.Detach(); 613 return shape; 614 } 615 616 // _ParseShapes 617 status_t 618 FlatIconImporter::_ParseShapes(LittleEndianBuffer& buffer, 619 Container<Style>* styles, 620 Container<VectorPath>* paths, 621 Container<Shape>* shapes) 622 { 623 uint8 shapeCount; 624 if (!buffer.Read(shapeCount)) 625 return B_ERROR; 626 627 for (uint32 i = 0; i < shapeCount; i++) { 628 uint8 shapeType; 629 if (!buffer.Read(shapeType)) 630 return B_ERROR; 631 Shape* shape = NULL; 632 if (shapeType == SHAPE_TYPE_PATH_SOURCE) { 633 // path source shape 634 shape = _ReadPathSourceShape(buffer, styles, paths); 635 if (!shape) 636 return B_NO_MEMORY; 637 } else { 638 // unkown shape type, skip tag 639 uint16 tagLength; 640 if (!buffer.Read(tagLength)) 641 return B_ERROR; 642 buffer.Skip(tagLength); 643 continue; 644 } 645 // add shape if we were able to read one 646 if (shape && !shapes->AddItem(shape)) { 647 delete shape; 648 return B_NO_MEMORY; 649 } 650 } 651 652 return B_OK; 653 } 654 655 656 657 658