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