2 * Copyright 2006, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Stephan Aßmus <superstippi@gmx.de>
9 #include "FlatIconExporter.h"
14 #include <Archivable.h>
19 #include "AffineTransformer.h"
20 #include "ContourTransformer.h"
21 #include "FlatIconFormat.h"
22 #include "GradientTransformable.h"
24 #include "LittleEndianBuffer.h"
25 #include "PathCommandQueue.h"
26 #include "PathContainer.h"
27 #include "PerspectiveTransformer.h"
29 #include "StrokeTransformer.h"
31 #include "StyleContainer.h"
32 #include "VectorPath.h"
37 FlatIconExporter::FlatIconExporter()
39 : fStyleSectionSize(0)
41 , fGradientTransformSize(0)
43 , fShapeSectionSize(0)
45 #endif // PRINT_STATISTICS
50 FlatIconExporter::~FlatIconExporter()
54 "--style section size: %" B_PRId32
"\n"
55 " gradients: %" B_PRId32
"\n"
56 " gradient transforms: %" B_PRId32
"\n"
57 "---path section size: %" B_PRId32
"\n"
58 "--shape section size: %" B_PRId32
"\n"
59 "---total/different points: %" B_PRId32
"/%" B_PRIdSSIZE
"\n",
62 fGradientTransformSize
,
67 #endif // PRINT_STATISTICS
72 FlatIconExporter::Export(const Icon
* icon
, BPositionIO
* stream
)
74 LittleEndianBuffer buffer
;
77 status_t ret
= _Export(buffer
, icon
);
81 // write buffer to stream
82 ssize_t written
= stream
->Write(buffer
.Buffer(), buffer
.SizeUsed());
83 if (written
!= (ssize_t
)buffer
.SizeUsed()) {
85 return (status_t
)written
;
94 FlatIconExporter::MIMEType()
101 FlatIconExporter::Export(const Icon
* icon
, BNode
* node
,
102 const char* attrName
)
104 LittleEndianBuffer buffer
;
107 status_t ret
= _Export(buffer
, icon
);
109 printf("failed to export to buffer: %s\n", strerror(ret
));
114 // work arround a BFS bug, attributes with the same name but different
115 // type fail to be written
116 node
->RemoveAttr(attrName
);
119 // write buffer to attribute
120 ssize_t written
= node
->WriteAttr(attrName
, B_VECTOR_ICON_TYPE
, 0,
121 buffer
.Buffer(), buffer
.SizeUsed());
122 if (written
!= (ssize_t
)buffer
.SizeUsed()) {
124 printf("failed to write attribute: %s\n",
125 strerror((status_t
)written
));
126 return (status_t
)written
;
128 printf("failed to write attribute\n");
139 FlatIconExporter::_Export(LittleEndianBuffer
& buffer
, const Icon
* icon
)
141 if (!buffer
.Write(FLAT_ICON_MAGIC
))
146 fGradientTransformSize
= 0;
151 StyleContainer
* styles
= icon
->Styles();
152 status_t ret
= _WriteStyles(buffer
, styles
);
157 fStyleSectionSize
= buffer
.SizeUsed();
161 PathContainer
* paths
= icon
->Paths();
162 ret
= _WritePaths(buffer
, paths
);
167 fPathSectionSize
= buffer
.SizeUsed() - fStyleSectionSize
;
171 ret
= _WriteShapes(buffer
, styles
, paths
, icon
->Shapes());
176 fShapeSectionSize
= buffer
.SizeUsed()
177 - (fStyleSectionSize
+ fPathSectionSize
);
183 // _WriteTransformable
185 _WriteTransformable(LittleEndianBuffer
& buffer
,
186 const Transformable
* transformable
)
188 int32 matrixSize
= Transformable::matrix_size
;
189 double matrix
[matrixSize
];
190 transformable
->StoreTo(matrix
);
191 for (int32 i
= 0; i
< matrixSize
; i
++) {
192 // if (!buffer.Write((float)matrix[i]))
194 if (!write_float_24(buffer
, (float)matrix
[i
]))
202 _WriteTranslation(LittleEndianBuffer
& buffer
,
203 const Transformable
* transformable
)
206 transformable
->Transform(&t
);
207 return write_coord(buffer
, t
.x
) && write_coord(buffer
, t
.y
);
212 FlatIconExporter::_WriteStyles(LittleEndianBuffer
& buffer
,
213 StyleContainer
* styles
)
215 uint8 styleCount
= min_c(255, styles
->CountStyles());
216 if (!buffer
.Write(styleCount
))
219 for (int32 i
= 0; i
< styleCount
; i
++) {
220 Style
* style
= styles
->StyleAtFast(i
);
225 const Gradient
* gradient
= style
->Gradient();
227 styleType
= STYLE_TYPE_GRADIENT
;
229 rgb_color color
= style
->Color();
230 if (color
.red
== color
.green
&& color
.red
== color
.blue
) {
232 if (style
->Color().alpha
== 255)
233 styleType
= STYLE_TYPE_SOLID_GRAY_NO_ALPHA
;
235 styleType
= STYLE_TYPE_SOLID_GRAY
;
238 if (style
->Color().alpha
== 255)
239 styleType
= STYLE_TYPE_SOLID_COLOR_NO_ALPHA
;
241 styleType
= STYLE_TYPE_SOLID_COLOR
;
245 if (!buffer
.Write(styleType
))
248 if (styleType
== STYLE_TYPE_SOLID_COLOR
) {
250 rgb_color color
= style
->Color();
251 if (!buffer
.Write(*(uint32
*)&color
))
253 } else if (styleType
== STYLE_TYPE_SOLID_COLOR_NO_ALPHA
) {
254 // solid color without alpha
255 rgb_color color
= style
->Color();
256 if (!buffer
.Write(color
.red
)
257 || !buffer
.Write(color
.green
)
258 || !buffer
.Write(color
.blue
))
260 } else if (styleType
== STYLE_TYPE_SOLID_GRAY
) {
262 rgb_color color
= style
->Color();
263 if (!buffer
.Write(color
.red
)
264 || !buffer
.Write(color
.alpha
))
266 } else if (styleType
== STYLE_TYPE_SOLID_GRAY_NO_ALPHA
) {
267 // solid gray without alpha
268 if (!buffer
.Write(style
->Color().red
))
270 } else if (styleType
== STYLE_TYPE_GRADIENT
) {
272 if (!_WriteGradient(buffer
, gradient
))
282 FlatIconExporter::_AnalysePath(VectorPath
* path
, uint8 pointCount
,
283 int32
& straightCount
, int32
& lineCount
, int32
& curveCount
)
289 BPoint
lastPoint(B_ORIGIN
);
290 for (uint32 p
= 0; p
< pointCount
; p
++) {
294 if (!path
->GetPointsAt(p
, point
, pointIn
, pointOut
))
296 if (point
== pointIn
&& point
== pointOut
) {
297 if (point
.x
== lastPoint
.x
|| point
.y
== lastPoint
.y
)
306 fUsedPoints
.insert(point
);
307 fUsedPoints
.insert(pointIn
);
308 fUsedPoints
.insert(pointOut
);
317 // write_path_no_curves
319 write_path_no_curves(LittleEndianBuffer
& buffer
, VectorPath
* path
,
322 //printf("write_path_no_curves()\n");
323 for (uint32 p
= 0; p
< pointCount
; p
++) {
325 if (!path
->GetPointAt(p
, point
))
327 if (!write_coord(buffer
, point
.x
) || !write_coord(buffer
, point
.y
))
335 write_path_curves(LittleEndianBuffer
& buffer
, VectorPath
* path
,
338 //printf("write_path_curves()\n");
339 for (uint32 p
= 0; p
< pointCount
; p
++) {
343 if (!path
->GetPointsAt(p
, point
, pointIn
, pointOut
))
345 if (!write_coord(buffer
, point
.x
)
346 || !write_coord(buffer
, point
.y
))
348 if (!write_coord(buffer
, pointIn
.x
)
349 || !write_coord(buffer
, pointIn
.y
))
351 if (!write_coord(buffer
, pointOut
.x
)
352 || !write_coord(buffer
, pointOut
.y
))
358 // write_path_with_commands
360 write_path_with_commands(LittleEndianBuffer
& buffer
, VectorPath
* path
,
363 PathCommandQueue queue
;
364 return queue
.Write(buffer
, path
, pointCount
);
370 FlatIconExporter::_WritePaths(LittleEndianBuffer
& buffer
, PathContainer
* paths
)
372 uint8 pathCount
= min_c(255, paths
->CountPaths());
373 if (!buffer
.Write(pathCount
))
376 for (uint32 i
= 0; i
< pathCount
; i
++) {
377 VectorPath
* path
= paths
->PathAtFast(i
);
379 if (path
->IsClosed())
380 pathFlags
|= PATH_FLAG_CLOSED
;
382 uint8 pointCount
= min_c(255, path
->CountPoints());
384 // see if writing segments with commands is more efficient
385 // than writing all segments as curves with no commands
389 if (!_AnalysePath(path
, pointCount
,
390 straightCount
, lineCount
, curveCount
))
393 int32 commandPathLength
394 = pointCount
+ straightCount
* 2 + lineCount
* 4 + curveCount
* 12;
395 int32 plainPathLength
397 //printf("segments: %d, command length: %ld, plain length: %ld\n",
398 // pointCount, commandPathLength, plainPathLength);
400 if (commandPathLength
< plainPathLength
) {
402 pathFlags
|= PATH_FLAG_NO_CURVES
;
404 pathFlags
|= PATH_FLAG_USES_COMMANDS
;
407 if (!buffer
.Write(pathFlags
) || !buffer
.Write(pointCount
))
410 if (pathFlags
& PATH_FLAG_NO_CURVES
) {
411 if (!write_path_no_curves(buffer
, path
, pointCount
))
413 } else if (pathFlags
& PATH_FLAG_USES_COMMANDS
) {
414 if (!write_path_with_commands(buffer
, path
, pointCount
))
417 if (!write_path_curves(buffer
, path
, pointCount
))
427 _WriteTransformer(LittleEndianBuffer
& buffer
, Transformer
* t
)
429 if (AffineTransformer
* affine
430 = dynamic_cast<AffineTransformer
*>(t
)) {
432 if (!buffer
.Write((uint8
)TRANSFORMER_TYPE_AFFINE
))
435 affine
->store_to(matrix
);
436 for (int32 i
= 0; i
< 6; i
++) {
437 if (!write_float_24(buffer
, (float)matrix
[i
]))
441 } else if (ContourTransformer
* contour
442 = dynamic_cast<ContourTransformer
*>(t
)) {
444 if (!buffer
.Write((uint8
)TRANSFORMER_TYPE_CONTOUR
))
446 uint8 width
= (uint8
)((int8
)contour
->width() + 128);
447 uint8 lineJoin
= (uint8
)contour
->line_join();
448 uint8 miterLimit
= (uint8
)contour
->miter_limit();
449 if (!buffer
.Write(width
)
450 || !buffer
.Write(lineJoin
)
451 || !buffer
.Write(miterLimit
))
454 } else if (dynamic_cast<PerspectiveTransformer
*>(t
)) {
456 if (!buffer
.Write((uint8
)TRANSFORMER_TYPE_PERSPECTIVE
))
458 // TODO: ... (upgrade AGG for storage support of trans_perspective)
460 } else if (StrokeTransformer
* stroke
461 = dynamic_cast<StrokeTransformer
*>(t
)) {
463 if (!buffer
.Write((uint8
)TRANSFORMER_TYPE_STROKE
))
465 uint8 width
= (uint8
)((int8
)stroke
->width() + 128);
466 uint8 lineOptions
= (uint8
)stroke
->line_join();
467 lineOptions
|= ((uint8
)stroke
->line_cap()) << 4;
468 uint8 miterLimit
= (uint8
)stroke
->miter_limit();
470 if (!buffer
.Write(width
)
471 || !buffer
.Write(lineOptions
)
472 || !buffer
.Write(miterLimit
))
479 // _WritePathSourceShape
481 _WritePathSourceShape(LittleEndianBuffer
& buffer
, Shape
* shape
,
482 StyleContainer
* styles
, PathContainer
* paths
)
484 // find out which style this shape uses
485 Style
* style
= shape
->Style();
489 int32 styleIndex
= styles
->IndexOf(style
);
490 if (styleIndex
< 0 || styleIndex
> 255)
493 uint8 pathCount
= min_c(255, shape
->Paths()->CountPaths());
495 // write shape type and style index
496 if (!buffer
.Write((uint8
)SHAPE_TYPE_PATH_SOURCE
)
497 || !buffer
.Write((uint8
)styleIndex
)
498 || !buffer
.Write(pathCount
))
501 // find out which paths this shape uses
502 for (uint32 i
= 0; i
< pathCount
; i
++) {
503 VectorPath
* path
= shape
->Paths()->PathAtFast(i
);
504 int32 pathIndex
= paths
->IndexOf(path
);
505 if (pathIndex
< 0 || pathIndex
> 255)
508 if (!buffer
.Write((uint8
)pathIndex
))
512 uint8 transformerCount
= min_c(255, shape
->CountTransformers());
515 uint8 shapeFlags
= 0;
516 if (!shape
->IsIdentity()) {
517 if (shape
->IsTranslationOnly())
518 shapeFlags
|= SHAPE_FLAG_TRANSLATION
;
520 shapeFlags
|= SHAPE_FLAG_TRANSFORM
;
522 if (shape
->Hinting())
523 shapeFlags
|= SHAPE_FLAG_HINTING
;
524 if (shape
->MinVisibilityScale() != 0.0
525 || shape
->MaxVisibilityScale() != 4.0)
526 shapeFlags
|= SHAPE_FLAG_LOD_SCALE
;
527 if (transformerCount
> 0)
528 shapeFlags
|= SHAPE_FLAG_HAS_TRANSFORMERS
;
530 if (!buffer
.Write((uint8
)shapeFlags
))
533 if (shapeFlags
& SHAPE_FLAG_TRANSFORM
) {
535 if (!_WriteTransformable(buffer
, shape
))
537 } else if (shapeFlags
& SHAPE_FLAG_TRANSLATION
) {
539 if (!_WriteTranslation(buffer
, shape
))
543 if (shapeFlags
& SHAPE_FLAG_LOD_SCALE
) {
544 // min max visibility scale
546 (uint8
)(shape
->MinVisibilityScale() * 63.75 + 0.5))
548 (uint8
)(shape
->MaxVisibilityScale() * 63.75 + 0.5))) {
553 if (shapeFlags
& SHAPE_FLAG_HAS_TRANSFORMERS
) {
555 if (!buffer
.Write(transformerCount
))
558 for (uint32 i
= 0; i
< transformerCount
; i
++) {
559 Transformer
* transformer
= shape
->TransformerAtFast(i
);
560 if (!_WriteTransformer(buffer
, transformer
))
570 FlatIconExporter::_WriteShapes(LittleEndianBuffer
& buffer
,
571 StyleContainer
* styles
,
572 PathContainer
* paths
,
573 ShapeContainer
* shapes
)
575 uint8 shapeCount
= min_c(255, shapes
->CountShapes());
576 if (!buffer
.Write(shapeCount
))
579 for (uint32 i
= 0; i
< shapeCount
; i
++) {
580 Shape
* shape
= shapes
->ShapeAtFast(i
);
581 if (!_WritePathSourceShape(buffer
, shape
, styles
, paths
))
590 FlatIconExporter::_WriteGradient(LittleEndianBuffer
& buffer
,
591 const Gradient
* gradient
)
594 size_t currentSize
= buffer
.SizeUsed();
597 uint8 gradientType
= (uint8
)gradient
->Type();
598 uint8 gradientFlags
= 0;
599 uint8 gradientStopCount
= (uint8
)gradient
->CountColors();
602 if (!gradient
->IsIdentity())
603 gradientFlags
|= GRADIENT_FLAG_TRANSFORM
;
607 for (int32 i
= 0; i
< gradientStopCount
; i
++) {
608 BGradient::ColorStop
* step
= gradient
->ColorAtFast(i
);
609 if (step
->color
.alpha
< 255)
611 if (step
->color
.red
!= step
->color
.green
612 || step
->color
.red
!= step
->color
.blue
)
616 gradientFlags
|= GRADIENT_FLAG_NO_ALPHA
;
618 gradientFlags
|= GRADIENT_FLAG_GRAYS
;
620 if (!buffer
.Write(gradientType
)
621 || !buffer
.Write(gradientFlags
)
622 || !buffer
.Write(gradientStopCount
))
625 if (gradientFlags
& GRADIENT_FLAG_TRANSFORM
) {
626 if (!_WriteTransformable(buffer
, gradient
))
629 fGradientTransformSize
+= Transformable::matrix_size
* sizeof(float);
633 for (int32 i
= 0; i
< gradientStopCount
; i
++) {
634 BGradient::ColorStop
* step
= gradient
->ColorAtFast(i
);
635 uint8 stopOffset
= (uint8
)(step
->offset
* 255.0);
636 uint32 color
= (uint32
&)step
->color
;
637 if (!buffer
.Write(stopOffset
))
641 if (!buffer
.Write(step
->color
.red
)
642 || !buffer
.Write(step
->color
.alpha
))
645 if (!buffer
.Write(color
))
650 if (!buffer
.Write(step
->color
.red
))
653 if (!buffer
.Write(step
->color
.red
)
654 || !buffer
.Write(step
->color
.green
)
655 || !buffer
.Write(step
->color
.blue
))
662 fGradientSize
+= buffer
.SizeUsed() - currentSize
;