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