diff --git a/src/libs/icon/Icon.cpp b/src/libs/icon/Icon.cpp index 5f17272ae8..7b5d82066d 100644 --- a/src/libs/icon/Icon.cpp +++ b/src/libs/icon/Icon.cpp @@ -122,6 +122,13 @@ Icon::~Icon() delete fStyles; } +// InitCheck +status_t +Icon::InitCheck() const +{ + return fStyles && fPaths && fShapes ? B_OK : B_NO_MEMORY; +} + #ifdef ICON_O_MATIC // ShapeAdded void diff --git a/src/libs/icon/Icon.h b/src/libs/icon/Icon.h index 6f02de5398..f312efdda6 100644 --- a/src/libs/icon/Icon.h +++ b/src/libs/icon/Icon.h @@ -44,6 +44,8 @@ class Icon { Icon(const Icon& other); virtual ~Icon(); + status_t InitCheck() const; + StyleContainer* Styles() const { return fStyles; } PathContainer* Paths() const diff --git a/src/libs/icon/IconUtils.cpp b/src/libs/icon/IconUtils.cpp new file mode 100644 index 0000000000..9382551593 --- /dev/null +++ b/src/libs/icon/IconUtils.cpp @@ -0,0 +1,195 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "IconUtils.h" + +#include + +#include +#include +#include + +#include "Icon.h" +#include "IconRenderer.h" +#include "FlatIconImporter.h" + +// GetVectorIcon +status_t +BIconUtils::GetVectorIcon(BNode* node, const char* attrName, + BBitmap* result) +{ + if (!node || !attrName) + return B_BAD_VALUE; + +#if TIME_VECTOR_ICONS +bigtime_t startTime = system_time(); +#endif + + // get the attribute info and check type and size of the attr contents + attr_info attrInfo; + status_t ret = node->GetAttrInfo(attrName, &attrInfo); + if (ret < B_OK) + return ret; + + type_code attrType = B_RAW_TYPE; + // TODO: introduce special type? + + if (attrInfo.type != attrType) + return B_BAD_TYPE; + + // chicken out on unrealisticly large attributes + if (attrInfo.size > 16 * 1024) + return B_BAD_VALUE; + + uint8 buffer[attrInfo.size]; + node->ReadAttr(attrName, attrType, 0, buffer, attrInfo.size); + +#if TIME_VECTOR_ICONS +bigtime_t importTime = system_time(); +#endif + + ret = GetVectorIcon(buffer, attrInfo.size, result); + if (ret < B_OK) + return ret; + +#if TIME_VECTOR_ICONS +bigtime_t finishTime = system_time(); +printf("read: %lld, import: %lld\n", importTime - startTime, finishTime - importTime); +#endif + + return B_OK; +} + +// GetVectorIcon +status_t +BIconUtils::GetVectorIcon(const uint8* buffer, size_t size, + BBitmap* result) +{ + if (!result) + return B_BAD_VALUE; + + status_t ret = result->InitCheck(); + if (ret < B_OK) + return ret; + + if (result->ColorSpace() != B_RGBA32 && result->ColorSpace() != B_RGB32) + return B_BAD_VALUE; + + Icon icon; + ret = icon.InitCheck(); + if (ret < B_OK) + return ret; + + FlatIconImporter importer; + ret = importer.Import(&icon, const_cast(buffer), size); + if (ret < B_OK) + return ret; + + IconRenderer renderer(result); + renderer.SetIcon(&icon); + renderer.SetScale((result->Bounds().Width() + 1.0) / 64.0); + renderer.Render(); + + // TODO: would be nice to get rid of this + // (B_RGBA32_PREMULTIPLIED or better yes, new blending_mode) + // NOTE: probably not necessary only because + // transparent colors are "black" in all existing icons + // lighter transparent colors should be too dark if + // app_server uses correct blending +// renderer.Demultiply(); + + return B_OK; +} + +// ConvertFromCMAP8 +status_t +BIconUtils::ConvertFromCMAP8(BBitmap* source, BBitmap* result) +{ + if (!source) + return B_BAD_VALUE; + + status_t ret = source->InitCheck(); + if (ret < B_OK) + return ret; + + uint8* src = (uint8*)source->Bits(); + uint32 srcBPR = source->BytesPerRow(); + uint32 width = source->Bounds().IntegerWidth() + 1; + uint32 height = source->Bounds().IntegerHeight() + 1; + + return ConvertFromCMAP8(src, width, height, srcBPR, result); +} + +// ConvertFromCMAP8 +status_t +BIconUtils::ConvertFromCMAP8(const uint8* src, + uint32 width, uint32 height, uint32 srcBPR, + BBitmap* result) +{ + if (!src || !result || srcBPR == 0) + return B_BAD_VALUE; + + status_t ret = result->InitCheck(); + if (ret < B_OK) + return ret; + + uint32 dstWidth = result->Bounds().IntegerWidth() + 1; + uint32 dstHeight = result->Bounds().IntegerHeight() + 1; + + if (dstWidth < width || dstHeight < height) { + // TODO: down scaling + return B_ERROR; + } else if (dstWidth > width || dstHeight > height) { + // TODO: up scaling + // (currently copies bitmap into result at left-top) + } + +#if __HAIKU__ + + return result->ImportBits(src, height * srcBPR, srcBPR, 0, B_CMAP8); + +#else + + if (result->ColorSpace() != B_RGBA32 && result->ColorSpace() != B_RGB32) { + // TODO: support other color spaces + return B_BAD_VALUE; + } + + uint8* dst = (uint8*)result->Bits(); + uint32 dstBPR = result->BytesPerRow(); + + const rgb_color* colorMap = system_colors()->color_list; + + for (uint32 y = 0; y < dstHeight; y++) { + uint32* d = (uint32*)dst; + const uint8* s = src; + for (uint32 x = 0; x < dstWidth; x++) { + const rgb_color c = colorMap[*s]; + uint8 alpha = 255; + if (*s == B_TRANSPARENT_MAGIC_CMAP8) + alpha = 0; + *d = (alpha << 24) | (c.red << 16) | (c.green << 8) | (c.blue); + s++; + d++; + } + src += srcBPR; + dst += dstBPR; + } + + return B_OK; + +#endif // __HAIKU__ +} + +// #pragma mark - forbidden + +BIconUtils::BIconUtils() {} +BIconUtils::~BIconUtils() {} +BIconUtils::BIconUtils(const BIconUtils&) {} +BIconUtils& BIconUtils::operator=(const BIconUtils&) { return *this; } + diff --git a/src/libs/icon/IconUtils.h b/src/libs/icon/IconUtils.h new file mode 100644 index 0000000000..d6981dd35c --- /dev/null +++ b/src/libs/icon/IconUtils.h @@ -0,0 +1,44 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + */ + +#ifndef ICON_UTILS_H +#define ICON_UTILS_H + +#include + +class BBitmap; +class BNode; + +// This class is a little different from many other classes. +// You don't create an instance of it; you just call its various +// static member functions for utility-like operations. +class BIconUtils { + BIconUtils(); + ~BIconUtils(); + BIconUtils(const BIconUtils&); + BIconUtils& operator=(const BIconUtils&); + + public: + + static status_t GetVectorIcon(BNode* node, + const char* attrName, + BBitmap* result); + + static status_t GetVectorIcon(const uint8* buffer, + size_t size, + BBitmap* result); + + + static status_t ConvertFromCMAP8(BBitmap* source, + BBitmap* result); + + static status_t ConvertFromCMAP8(const uint8* data, + uint32 width, uint32 height, + uint32 bytesPerRow, + BBitmap* result); +}; + +#endif // ICON_UTILS_H diff --git a/src/libs/icon/Jamfile b/src/libs/icon/Jamfile index fda395335f..1c24f725c5 100644 --- a/src/libs/icon/Jamfile +++ b/src/libs/icon/Jamfile @@ -54,5 +54,6 @@ StaticLibrary libicon.a : Icon.cpp IconRenderer.cpp + IconUtils.cpp ; diff --git a/src/libs/icon/flat_icon/FlatIconFormat.cpp b/src/libs/icon/flat_icon/FlatIconFormat.cpp index 86f5be0afe..9b4fe77c7e 100644 --- a/src/libs/icon/flat_icon/FlatIconFormat.cpp +++ b/src/libs/icon/flat_icon/FlatIconFormat.cpp @@ -12,8 +12,8 @@ const uint32 FLAT_ICON_MAGIC = 'ficn'; -const char* kVectorAttrNodeName = "BEOS:I:STD_ICON"; -const char* kVectorAttrMimeName = "META:I:STD_ICON"; +const char* kVectorAttrNodeName = "BEOS:ICON"; +const char* kVectorAttrMimeName = "META:ICON"; // read_coord bool diff --git a/src/libs/icon/flat_icon/FlatIconFormat.h b/src/libs/icon/flat_icon/FlatIconFormat.h index 9fef486b73..6fe725b952 100644 --- a/src/libs/icon/flat_icon/FlatIconFormat.h +++ b/src/libs/icon/flat_icon/FlatIconFormat.h @@ -12,20 +12,21 @@ #include extern const uint32 FLAT_ICON_MAGIC; + extern const char* kVectorAttrNodeName; extern const char* kVectorAttrMimeName; enum { - TAG_STYLE_SOLID_COLOR = 1, - TAG_STYLE_GRADIENT = 2, - TAG_STYLE_SOLID_COLOR_NO_ALPHA = 3, + STYLE_TYPE_SOLID_COLOR = 1, + STYLE_TYPE_GRADIENT = 2, + STYLE_TYPE_SOLID_COLOR_NO_ALPHA = 3, - TAG_SHAPE_PATH_SOURCE = 10, + SHAPE_TYPE_PATH_SOURCE = 10, - TAG_TRANSFORMER_AFFINE = 20, - TAG_TRANSFORMER_CONTOUR = 21, - TAG_TRANSFORMER_PERSPECTIVE = 22, - TAG_TRANSFORMER_STROKE = 23, + TRANSFORMER_TYPE_AFFINE = 20, + TRANSFORMER_TYPE_CONTOUR = 21, + TRANSFORMER_TYPE_PERSPECTIVE = 22, + TRANSFORMER_TYPE_STROKE = 23, }; enum { @@ -35,9 +36,9 @@ enum { }; enum { - PATH_FLAGS_CLOSED = 1 << 1, - PATH_FLAGS_USES_COMMANDS = 1 << 2, - PATH_FLAGS_NO_CURVES = 1 << 3, + PATH_FLAG_CLOSED = 1 << 1, + PATH_FLAG_USES_COMMANDS = 1 << 2, + PATH_FLAG_NO_CURVES = 1 << 3, }; enum { diff --git a/src/libs/icon/flat_icon/FlatIconImporter.cpp b/src/libs/icon/flat_icon/FlatIconImporter.cpp index abd40388cf..652fccee58 100644 --- a/src/libs/icon/flat_icon/FlatIconImporter.cpp +++ b/src/libs/icon/flat_icon/FlatIconImporter.cpp @@ -243,17 +243,17 @@ FlatIconImporter::_ParseStyles(LittleEndianBuffer& buffer, if (!buffer.Read(styleType)) return B_ERROR; Style* style = NULL; - if (styleType == TAG_STYLE_SOLID_COLOR) { + if (styleType == STYLE_TYPE_SOLID_COLOR) { // solid color style = _ReadColorStyle(buffer, true); if (!style) return B_NO_MEMORY; - } else if (styleType == TAG_STYLE_SOLID_COLOR_NO_ALPHA) { + } else if (styleType == STYLE_TYPE_SOLID_COLOR_NO_ALPHA) { // solid color without alpha style = _ReadColorStyle(buffer, false); if (!style) return B_NO_MEMORY; - } else if (styleType == TAG_STYLE_GRADIENT) { + } else if (styleType == STYLE_TYPE_GRADIENT) { // gradient style = _ReadGradientStyle(buffer); if (!style) @@ -351,10 +351,10 @@ FlatIconImporter::_ParsePaths(LittleEndianBuffer& buffer, // chose path reading strategy depending on path flags bool error = false; - if (pathFlags & PATH_FLAGS_NO_CURVES) { + if (pathFlags & PATH_FLAG_NO_CURVES) { if (!read_path_no_curves(buffer, path, pointCount)) error = true; - } else if (pathFlags & PATH_FLAGS_USES_COMMANDS) { + } else if (pathFlags & PATH_FLAG_USES_COMMANDS) { if (!read_path_with_commands(buffer, path, pointCount)) error = true; } else { @@ -368,7 +368,7 @@ FlatIconImporter::_ParsePaths(LittleEndianBuffer& buffer, } // post process path to clean it up path->CleanUp(); - if (pathFlags & PATH_FLAGS_CLOSED) + if (pathFlags & PATH_FLAG_CLOSED) path->SetClosed(true); // add path to container if (!paths->AddPath(path)) { @@ -389,7 +389,7 @@ _ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source) return NULL; switch (transformerType) { - case TAG_TRANSFORMER_AFFINE: { + case TRANSFORMER_TYPE_AFFINE: { AffineTransformer* affine = new (nothrow) AffineTransformer(source); if (!affine) @@ -406,7 +406,7 @@ _ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source) affine->load_from(matrix); return affine; } - case TAG_TRANSFORMER_CONTOUR: { + case TRANSFORMER_TYPE_CONTOUR: { ContourTransformer* contour = new (nothrow) ContourTransformer(source); uint8 width; @@ -424,14 +424,14 @@ _ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source) contour->miter_limit(miterLimit); return contour; } - case TAG_TRANSFORMER_PERSPECTIVE: { + case TRANSFORMER_TYPE_PERSPECTIVE: { PerspectiveTransformer* perspective = new (nothrow) PerspectiveTransformer(source); // TODO: upgrade AGG to be able to support storage of // trans_perspective return perspective; } - case TAG_TRANSFORMER_STROKE: { + case TRANSFORMER_TYPE_STROKE: { StrokeTransformer* stroke = new (nothrow) StrokeTransformer(source); uint8 width; @@ -566,7 +566,7 @@ FlatIconImporter::_ParseShapes(LittleEndianBuffer& buffer, if (!buffer.Read(shapeType)) return B_ERROR; Shape* shape = NULL; - if (shapeType == TAG_SHAPE_PATH_SOURCE) { + if (shapeType == SHAPE_TYPE_PATH_SOURCE) { // path source shape shape = _ReadPathSourceShape(buffer, styles, paths); if (!shape)