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