From fb07ece069b8b7ca52eda06449ce2f0460b294ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Fri, 4 Aug 2006 23:57:01 +0000 Subject: [PATCH] * moved all the classes actually needed for reading a vector icon to this place, #ifdef'd out all the editing features (listening, referencing, converting to PropertyObject... etc) * TODO: put into BPrivate namespace... git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18396 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/libs/Jamfile | 1 + src/libs/icon/Icon.cpp | 206 +++ src/libs/icon/Icon.h | 83 ++ src/libs/icon/IconRenderer.cpp | 428 +++++++ src/libs/icon/IconRenderer.h | 94 ++ src/libs/icon/Jamfile | 58 + src/libs/icon/flat_icon/FlatIconFormat.cpp | 121 ++ src/libs/icon/flat_icon/FlatIconFormat.h | 68 + src/libs/icon/flat_icon/FlatIconImporter.cpp | 594 +++++++++ src/libs/icon/flat_icon/FlatIconImporter.h | 49 + .../icon/flat_icon/LittleEndianBuffer.cpp | 289 +++++ src/libs/icon/flat_icon/LittleEndianBuffer.h | 57 + src/libs/icon/flat_icon/PathCommandQueue.cpp | 264 ++++ src/libs/icon/flat_icon/PathCommandQueue.h | 53 + src/libs/icon/shape/PathContainer.cpp | 213 ++++ src/libs/icon/shape/PathContainer.h | 64 + src/libs/icon/shape/Shape.cpp | 676 ++++++++++ src/libs/icon/shape/Shape.h | 162 +++ src/libs/icon/shape/ShapeContainer.cpp | 228 ++++ src/libs/icon/shape/ShapeContainer.h | 66 + src/libs/icon/shape/VectorPath.cpp | 1119 +++++++++++++++++ src/libs/icon/shape/VectorPath.h | 208 +++ src/libs/icon/style/Gradient.cpp | 638 ++++++++++ src/libs/icon/style/Gradient.h | 124 ++ src/libs/icon/style/Style.cpp | 220 ++++ src/libs/icon/style/Style.h | 78 ++ src/libs/icon/style/StyleContainer.cpp | 215 ++++ src/libs/icon/style/StyleContainer.h | 63 + src/libs/icon/transformable/Transformable.cpp | 315 +++++ src/libs/icon/transformable/Transformable.h | 70 ++ .../icon/transformer/AffineTransformer.cpp | 194 +++ src/libs/icon/transformer/AffineTransformer.h | 57 + .../icon/transformer/ContourTransformer.cpp | 218 ++++ .../icon/transformer/ContourTransformer.h | 54 + src/libs/icon/transformer/PathSource.cpp | 73 ++ src/libs/icon/transformer/PathSource.h | 44 + .../transformer/PerspectiveTransformer.cpp | 106 ++ .../icon/transformer/PerspectiveTransformer.h | 55 + .../icon/transformer/StrokeTransformer.cpp | 251 ++++ src/libs/icon/transformer/StrokeTransformer.h | 56 + src/libs/icon/transformer/Transformer.cpp | 85 ++ src/libs/icon/transformer/Transformer.h | 61 + .../icon/transformer/TransformerFactory.cpp | 82 ++ .../icon/transformer/TransformerFactory.h | 35 + 44 files changed, 8195 insertions(+) create mode 100644 src/libs/icon/Icon.cpp create mode 100644 src/libs/icon/Icon.h create mode 100644 src/libs/icon/IconRenderer.cpp create mode 100644 src/libs/icon/IconRenderer.h create mode 100644 src/libs/icon/Jamfile create mode 100644 src/libs/icon/flat_icon/FlatIconFormat.cpp create mode 100644 src/libs/icon/flat_icon/FlatIconFormat.h create mode 100644 src/libs/icon/flat_icon/FlatIconImporter.cpp create mode 100644 src/libs/icon/flat_icon/FlatIconImporter.h create mode 100644 src/libs/icon/flat_icon/LittleEndianBuffer.cpp create mode 100644 src/libs/icon/flat_icon/LittleEndianBuffer.h create mode 100644 src/libs/icon/flat_icon/PathCommandQueue.cpp create mode 100644 src/libs/icon/flat_icon/PathCommandQueue.h create mode 100644 src/libs/icon/shape/PathContainer.cpp create mode 100644 src/libs/icon/shape/PathContainer.h create mode 100644 src/libs/icon/shape/Shape.cpp create mode 100644 src/libs/icon/shape/Shape.h create mode 100644 src/libs/icon/shape/ShapeContainer.cpp create mode 100644 src/libs/icon/shape/ShapeContainer.h create mode 100644 src/libs/icon/shape/VectorPath.cpp create mode 100644 src/libs/icon/shape/VectorPath.h create mode 100644 src/libs/icon/style/Gradient.cpp create mode 100644 src/libs/icon/style/Gradient.h create mode 100644 src/libs/icon/style/Style.cpp create mode 100644 src/libs/icon/style/Style.h create mode 100644 src/libs/icon/style/StyleContainer.cpp create mode 100644 src/libs/icon/style/StyleContainer.h create mode 100644 src/libs/icon/transformable/Transformable.cpp create mode 100644 src/libs/icon/transformable/Transformable.h create mode 100644 src/libs/icon/transformer/AffineTransformer.cpp create mode 100644 src/libs/icon/transformer/AffineTransformer.h create mode 100644 src/libs/icon/transformer/ContourTransformer.cpp create mode 100644 src/libs/icon/transformer/ContourTransformer.h create mode 100644 src/libs/icon/transformer/PathSource.cpp create mode 100644 src/libs/icon/transformer/PathSource.h create mode 100644 src/libs/icon/transformer/PerspectiveTransformer.cpp create mode 100644 src/libs/icon/transformer/PerspectiveTransformer.h create mode 100644 src/libs/icon/transformer/StrokeTransformer.cpp create mode 100644 src/libs/icon/transformer/StrokeTransformer.h create mode 100644 src/libs/icon/transformer/Transformer.cpp create mode 100644 src/libs/icon/transformer/Transformer.h create mode 100644 src/libs/icon/transformer/TransformerFactory.cpp create mode 100644 src/libs/icon/transformer/TransformerFactory.h diff --git a/src/libs/Jamfile b/src/libs/Jamfile index 6ff84f8608..8202cfeb4b 100644 --- a/src/libs/Jamfile +++ b/src/libs/Jamfile @@ -5,6 +5,7 @@ SubInclude HAIKU_TOP src libs bsd ; #SubInclude HAIKU_TOP src libs edit ; SubInclude HAIKU_TOP src libs fluidsynth ; SubInclude HAIKU_TOP src libs freetype2 ; +SubInclude HAIKU_TOP src libs icon ; #SubInclude HAIKU_TOP src libs ncurses ; SubInclude HAIKU_TOP src libs pdflib ; SubInclude HAIKU_TOP src libs png ; diff --git a/src/libs/icon/Icon.cpp b/src/libs/icon/Icon.cpp new file mode 100644 index 0000000000..5f17272ae8 --- /dev/null +++ b/src/libs/icon/Icon.cpp @@ -0,0 +1,206 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "Icon.h" + +#include +#include + +#include "PathContainer.h" +#include "Shape.h" +#include "Style.h" +#include "StyleContainer.h" + +using std::nothrow; + +#ifdef ICON_O_MATIC +IconListener::IconListener() {} +IconListener::~IconListener() {} +#endif + +// #pragma mark - + +// constructor +Icon::Icon() + : fStyles(new (nothrow) StyleContainer()), + fPaths(new (nothrow) PathContainer(true)), + fShapes(new (nothrow) ShapeContainer()) +#ifdef ICON_O_MATIC + , fListeners(2) +#endif +{ +#ifdef ICON_O_MATIC + if (fShapes) + fShapes->AddListener(this); +#endif +} + +// constructor +Icon::Icon(const Icon& other) + : fStyles(new (nothrow) StyleContainer()), + fPaths(new (nothrow) PathContainer(true)), + fShapes(new (nothrow) ShapeContainer()) +#ifdef ICON_O_MATIC + , fListeners(2) +#endif +{ + if (!fStyles || !fPaths || !fShapes) + return; + +#ifdef ICON_O_MATIC + fShapes->AddListener(this); +#endif + + int32 styleCount = other.fStyles->CountStyles(); + for (int32 i = 0; i < styleCount; i++) { + Style* style = other.fStyles->StyleAtFast(i); + Style* clone = new (nothrow) Style(*style); + if (!clone || !fStyles->AddStyle(clone)) { + delete clone; + return; + } + } + + int32 pathCount = other.fPaths->CountPaths(); + for (int32 i = 0; i < pathCount; i++) { + VectorPath* path = other.fPaths->PathAtFast(i); + VectorPath* clone = new (nothrow) VectorPath(*path); + if (!clone || !fPaths->AddPath(clone)) { + delete clone; + return; + } + } + + int32 shapeCount = other.fShapes->CountShapes(); + for (int32 i = 0; i < shapeCount; i++) { + Shape* shape = other.fShapes->ShapeAtFast(i); + Shape* clone = new (nothrow) Shape(*shape); + if (!clone || !fShapes->AddShape(clone)) { + delete clone; + return; + } + // the cloned shape references styles and paths in + // the "other" icon, replace them with "local" styles + // and paths + int32 styleIndex = other.fStyles->IndexOf(shape->Style()); + clone->SetStyle(fStyles->StyleAt(styleIndex)); + + clone->Paths()->MakeEmpty(); + pathCount = shape->Paths()->CountPaths(); + for (int32 j = 0; j < pathCount; j++) { + VectorPath* remote = shape->Paths()->PathAtFast(j); + int32 index = other.fPaths->IndexOf(remote); + VectorPath* local = fPaths->PathAt(index); + if (!local) { + printf("failed to match remote and " + "local paths while cloning icon\n"); + continue; + } + if (!clone->Paths()->AddPath(local)) { + return; + } + } + } +} + +// destructor +Icon::~Icon() +{ + if (fShapes) { + fShapes->MakeEmpty(); +#ifdef ICON_O_MATIC + fShapes->RemoveListener(this); +#endif + delete fShapes; + } + delete fPaths; + delete fStyles; +} + +#ifdef ICON_O_MATIC +// ShapeAdded +void +Icon::ShapeAdded(Shape* shape, int32 index) +{ + shape->AddObserver(this); + _NotifyAreaInvalidated(shape->Bounds(true)); +} + +// ShapeRemoved +void +Icon::ShapeRemoved(Shape* shape) +{ + shape->RemoveObserver(this); + _NotifyAreaInvalidated(shape->Bounds(true)); +} + +// ObjectChanged +void +Icon::ObjectChanged(const Observable* object) +{ + const Shape* shape = dynamic_cast(object); + if (shape) { + BRect area = shape->LastBounds(); + area = area | shape->Bounds(true); + area.InsetBy(-1, -1); + _NotifyAreaInvalidated(area); + } +} + +// AddListener +bool +Icon::AddListener(IconListener* listener) +{ + if (listener && !fListeners.HasItem((void*)listener)) + return fListeners.AddItem((void*)listener); + return false; +} + +// RemoveListener +bool +Icon::RemoveListener(IconListener* listener) +{ + return fListeners.RemoveItem((void*)listener); +} +#endif // ICON_O_MATIC + + +// Clone +Icon* +Icon::Clone() const +{ + return new (nothrow) Icon(*this); +} + +// MakeEmpty +void +Icon::MakeEmpty() +{ + fShapes->MakeEmpty(); + fPaths->MakeEmpty(); + fStyles->MakeEmpty(); +} + +// #pragma mark - + +#ifdef ICON_O_MATIC +// _NotifyAreaInvalidated +void +Icon::_NotifyAreaInvalidated(const BRect& area) const +{ + BList listeners(fListeners); + int32 count = listeners.CountItems(); + for (int32 i = 0; i < count; i++) { + IconListener* listener + = (IconListener*)listeners.ItemAtFast(i); + listener->AreaInvalidated(area); + } +} +#endif // ICON_O_MATIC + + diff --git a/src/libs/icon/Icon.h b/src/libs/icon/Icon.h new file mode 100644 index 0000000000..6f02de5398 --- /dev/null +++ b/src/libs/icon/Icon.h @@ -0,0 +1,83 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef ICON_H +#define ICON_H + +#ifdef ICON_O_MATIC +#include + +# include "Observer.h" +#else +# include +#endif +#include "ShapeContainer.h" + +class BRect; +class PathContainer; +class StyleContainer; + +#ifdef ICON_O_MATIC +class IconListener { + public: + IconListener(); + virtual ~IconListener(); + + virtual void AreaInvalidated(const BRect& area) = 0; +}; +#endif + +#ifdef ICON_O_MATIC +class Icon : public ShapeContainerListener, + public Observer { +#else +class Icon { +#endif + + public: + Icon(); + Icon(const Icon& other); + virtual ~Icon(); + + StyleContainer* Styles() const + { return fStyles; } + PathContainer* Paths() const + { return fPaths; } + ShapeContainer* Shapes() const + { return fShapes; } + + Icon* Clone() const; + void MakeEmpty(); + + private: + + StyleContainer* fStyles; + PathContainer* fPaths; + ShapeContainer* fShapes; + +#ifdef ICON_O_MATIC + public: + // ShapeContainerListener interface + virtual void ShapeAdded(Shape* shape, int32 index); + virtual void ShapeRemoved(Shape* shape); + + // Observer interface + virtual void ObjectChanged(const Observable* object); + + // Icon + bool AddListener(IconListener* listener); + bool RemoveListener(IconListener* listener); + + private: + void _NotifyAreaInvalidated( + const BRect& area) const; + BList fListeners; +#endif +}; + +#endif // ICON_H diff --git a/src/libs/icon/IconRenderer.cpp b/src/libs/icon/IconRenderer.cpp new file mode 100644 index 0000000000..d2e2549b4d --- /dev/null +++ b/src/libs/icon/IconRenderer.cpp @@ -0,0 +1,428 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "IconRenderer.h" + +#include +#include + +#include +#include + +#include +#include + +#include "Gradient.h" +#include "Icon.h" +#include "Shape.h" +#include "ShapeContainer.h" +#include "Style.h" +#include "VectorPath.h" + +using std::nothrow; + +class StyleHandler { + struct StyleItem { + Style* style; + Transformation transformation; + }; + + public: + StyleHandler(::GammaTable& gammaTable) + : fStyles(20), + fGammaTable(gammaTable), + fTransparent(0, 0, 0, 0), + fColor(0, 0, 0, 0) + {} + + ~StyleHandler() + { + int32 count = fStyles.CountItems(); + for (int32 i = 0; i < count; i++) + delete (StyleItem*)fStyles.ItemAtFast(i); + } + + bool is_solid(unsigned styleIndex) const + { + StyleItem* styleItem = (StyleItem*)fStyles.ItemAt(styleIndex); + if (!styleItem) + return true; + + return styleItem->style->Gradient() == NULL; + } + + const agg::rgba8& color(unsigned styleIndex); + + void generate_span(agg::rgba8* span, int x, int y, + unsigned len, unsigned styleIndex); + + bool AddStyle(Style* style, const Transformation& transformation) + { + if (!style) + return false; + StyleItem* item = new (nothrow) StyleItem; + if (!item) + return false; + item->style = style; + // if the style uses a gradient, the transformation + // is based on the gradient transformation + if (Gradient* gradient = style->Gradient()) { + item->transformation = *gradient; + item->transformation.multiply(transformation); + } else { + item->transformation = transformation; + } + item->transformation.invert(); + return fStyles.AddItem((void*)item); + } + +private: + template + void _GenerateGradient(agg::rgba8* span, int x, int y, unsigned len, + GradientFunction function, int32 start, int32 end, + const agg::rgba8* gradientColors, + Transformation& gradientTransform); + + BList fStyles; + ::GammaTable& fGammaTable; + agg::rgba8 fTransparent; + agg::rgba8 fColor; +}; + +// color +const agg::rgba8& +StyleHandler::color(unsigned styleIndex) +{ + StyleItem* styleItem = (StyleItem*)fStyles.ItemAt(styleIndex); + if (!styleItem) { + printf("no style at index: %d!\n", styleIndex); + return fTransparent; + } + + const rgb_color& c = styleItem->style->Color(); + fColor = agg::rgba8(fGammaTable.dir(c.red), + fGammaTable.dir(c.green), + fGammaTable.dir(c.blue), + c.alpha); + fColor.premultiply(); + return fColor; +} + +// generate_span +void +StyleHandler::generate_span(agg::rgba8* span, int x, int y, + unsigned len, unsigned styleIndex) +{ + StyleItem* styleItem = (StyleItem*)fStyles.ItemAt(styleIndex); + if (!styleItem || !styleItem->style->Gradient()) { + printf("no style/gradient at index: %d!\n", styleIndex); + // TODO: memset() span? + return; + } + + Style* style = styleItem->style; + Gradient* gradient = style->Gradient(); + const agg::rgba8* colors = style->GammaCorrectedColors(fGammaTable); + + switch (gradient->Type()) { + case GRADIENT_LINEAR: { + agg::gradient_x function; + _GenerateGradient(span, x, y, len, function, -64, 64, colors, + styleItem->transformation); + break; + } + case GRADIENT_CIRCULAR: { + agg::gradient_radial function; + _GenerateGradient(span, x, y, len, function, 0, 64, colors, + styleItem->transformation); + break; + } + case GRADIENT_DIAMONT: { + agg::gradient_diamond function; + _GenerateGradient(span, x, y, len, function, 0, 64, colors, + styleItem->transformation); + break; + } + case GRADIENT_CONIC: { + agg::gradient_conic function; + _GenerateGradient(span, x, y, len, function, 0, 64, colors, + styleItem->transformation); + break; + } + case GRADIENT_XY: { + agg::gradient_xy function; + _GenerateGradient(span, x, y, len, function, 0, 64, colors, + styleItem->transformation); + break; + } + case GRADIENT_SQRT_XY: { + agg::gradient_sqrt_xy function; + _GenerateGradient(span, x, y, len, function, 0, 64, colors, + styleItem->transformation); + break; + } + } +} + +// _GenerateGradient +template +void +StyleHandler::_GenerateGradient(agg::rgba8* span, int x, int y, unsigned len, + GradientFunction function, + int32 start, int32 end, + const agg::rgba8* gradientColors, + Transformation& gradientTransform) + +{ + typedef agg::pod_auto_array ColorArray; + typedef agg::span_interpolator_linear<> Interpolator; + typedef agg::span_gradient GradientGenerator; + + Interpolator interpolator(gradientTransform); + + ColorArray array(gradientColors); + GradientGenerator gradientGenerator(interpolator, + function, + array, + start, end); + + gradientGenerator.generate(span, x, y, len); +} + +// #pragma mark - + +class HintingTransformer { + public: + + void transform(double* x, double* y) const + { + *x = floor(*x + 0.5); + *y = floor(*y + 0.5); + } +}; + + +// #pragma mark - + +// constructor +IconRenderer::IconRenderer(BBitmap* bitmap) + : fBitmap(bitmap), + fBackground(NULL), + fBackgroundColor(0, 0, 0, 0), + fIcon(NULL), + + fGammaTable(2.2), + + fRenderingBuffer(), + fPixelFormat(fRenderingBuffer), + fPixelFormatPre(fRenderingBuffer), + fBaseRenderer(fPixelFormat), + fBaseRendererPre(fPixelFormatPre), + + fScanline(), + fBinaryScanline(), + fSpanAllocator(), + + fRasterizer(), + + fGlobalTransform() +{ + // attach rendering buffer to bitmap + fRenderingBuffer.attach((uint8*)bitmap->Bits(), + bitmap->Bounds().IntegerWidth() + 1, + bitmap->Bounds().IntegerHeight() + 1, + bitmap->BytesPerRow()); + + fBaseRendererPre.clip_box(0, + 0, + fBitmap->Bounds().IntegerWidth(), + fBitmap->Bounds().IntegerHeight()); +} + +// destructor +IconRenderer::~IconRenderer() +{ +} + +// SetIcon +void +IconRenderer::SetIcon(const Icon* icon) +{ + if (fIcon == icon) + return; + + fIcon = icon; + // TODO: ... ? +} + +// Render +void +IconRenderer::Render() +{ + _Render(fBitmap->Bounds()); +} + +// Render +void +IconRenderer::Render(const BRect& area) +{ + _Render(fBitmap->Bounds() & area); +} + +//SetScale +void +IconRenderer::SetScale(double scale) +{ + fGlobalTransform.reset(); + fGlobalTransform.multiply(agg::trans_affine_scaling(scale)); +} + +//SetBackground +void +IconRenderer::SetBackground(const BBitmap* background) +{ + fBackground = background; +} + +//SetBackground +void +IconRenderer::SetBackground(const agg::rgba8& background) +{ + fBackgroundColor.r = fGammaTable.dir(background.r); + fBackgroundColor.g = fGammaTable.dir(background.g); + fBackgroundColor.b = fGammaTable.dir(background.b); + fBackgroundColor.a = background.a; +} + +// Demultiply +void +IconRenderer::Demultiply() +{ + uint8* bits = (uint8*)fBitmap->Bits(); + uint32 bpr = fBitmap->BytesPerRow(); + uint32 width = fBitmap->Bounds().IntegerWidth() + 1; + uint32 height = fBitmap->Bounds().IntegerHeight() + 1; + + for (uint32 y = 0; y < height; y++) { + uint8* b = bits; + for (uint32 x = 0; x < width; x++) { + if (b[3] < 255 && b[3] > 0) { + b[0] = (uint8)((int)b[0] * 255 / b[3]); + b[1] = (uint8)((int)b[1] * 255 / b[3]); + b[2] = (uint8)((int)b[2] * 255 / b[3]); + } + b += 4; + } + bits += bpr; + } +} + +// #pragma mark - + +typedef agg::conv_transform ScaledPath; +typedef agg::conv_transform HintedPath; + +// _Render +void +IconRenderer::_Render(const BRect& r) +{ + if (!fIcon) + return; + +// TODO: fix clip box for "clear" and "apply_gamma_inv" +// fBaseRendererPre.clip_box((int)floorf(r.left), +// (int)floorf(r.top), +// (int)ceilf(r.right), +// (int)ceilf(r.bottom)); + + if (fBackground) + memcpy(fBitmap->Bits(), fBackground->Bits(), fBitmap->BitsLength()); + else + fBaseRendererPre.clear(fBackgroundColor); + +//bigtime_t start = system_time(); + StyleHandler styleHandler(fGammaTable); + + fRasterizer.reset(); + // iterate over the shapes in the icon, + // add the vector paths to the rasterizer + // and associate each shapes style + int32 shapeCount = fIcon->Shapes()->CountShapes(); + int32 styleIndex = 0; + for (int32 i = 0; i < shapeCount; i++) { + Shape* shape = fIcon->Shapes()->ShapeAtFast(i); + + Transformation transform(*shape); + transform.multiply(fGlobalTransform); + // NOTE: this works only because "agg::trans_affine", + // "Transformable" and "Transformation" are all the + // same thing + + // don't render shape if the Level Of Detail falls + // out of range + if (transform.scale() <= shape->MinVisibilityScale() + || transform.scale() > shape->MaxVisibilityScale()) + continue; + + Style* style = shape->Style(); + if (!style) + continue; + + // add the style either with global transformation or with + // the shapes transformation, depending on wether there + // is a gradient and its settings + Gradient* gradient = style->Gradient(); + bool styleAdded = false; + if (gradient && !gradient->InheritTransformation()) { + styleAdded = styleHandler.AddStyle(shape->Style(), + fGlobalTransform); + } else { + styleAdded = styleHandler.AddStyle(shape->Style(), + transform); + } + + if (!styleAdded) { + printf("IconRenderer::_Render() - out of memory\n"); + break; + } + fRasterizer.styles(styleIndex, -1); + styleIndex++; + + // global scale + ScaledPath scaledPath(shape->VertexSource(), transform); + if (shape->Hinting()) { + // additional hinting + HintingTransformer hinter; + HintedPath hintedPath(scaledPath, hinter); + fRasterizer.add_path(hintedPath); + } else { + fRasterizer.add_path(scaledPath); + } + } + + agg::render_scanlines_compound(fRasterizer, + fScanline, + fBinaryScanline, + fBaseRendererPre, + fSpanAllocator, + styleHandler); + + if (fGammaTable.gamma() != 1.0) + fPixelFormat.apply_gamma_inv(fGammaTable); + +//if (fRenderingBuffer.width() == 64) +//printf("rendering 64x64: %lld\n", system_time() - start); +} + + + + + diff --git a/src/libs/icon/IconRenderer.h b/src/libs/icon/IconRenderer.h new file mode 100644 index 0000000000..f22d49a3ba --- /dev/null +++ b/src/libs/icon/IconRenderer.h @@ -0,0 +1,94 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef ICON_RENDERER_H +#define ICON_RENDERER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class BBitmap; +class BRect; +class Icon; + +typedef agg::gamma_lut + GammaTable; + +typedef agg::rendering_buffer RenderingBuffer; +typedef agg::pixfmt_bgra32 PixelFormat; +typedef agg::pixfmt_bgra32_pre PixelFormatPre; +typedef agg::renderer_base BaseRenderer; +typedef agg::renderer_base BaseRendererPre; + +typedef agg::scanline_u8 Scanline; +typedef agg::scanline_bin BinaryScanline; +typedef agg::span_allocator SpanAllocator; +typedef agg::rasterizer_compound_aa + CompoundRasterizer; + +typedef agg::trans_affine Transformation; + +class IconRenderer { + public: + IconRenderer(BBitmap* bitmap); + virtual ~IconRenderer(); + + void SetIcon(const Icon* icon); + + void Render(); + void Render(const BRect& area); + + void SetScale(double scale); + void SetBackground(const BBitmap* background); + // background is not copied, + // ownership stays with the caller + // colorspace and size need to + // be the same as bitmap passed + // to constructor + void SetBackground(const agg::rgba8& color); + // used when no background bitmap + // is set + + const ::GammaTable& GammaTable() const + { return fGammaTable; } + + void Demultiply(); + + private: + void _Render(const BRect& area); + + BBitmap* fBitmap; + const BBitmap* fBackground; + agg::rgba8 fBackgroundColor; + const Icon* fIcon; + + ::GammaTable fGammaTable; + + RenderingBuffer fRenderingBuffer; + PixelFormat fPixelFormat; + PixelFormatPre fPixelFormatPre; + BaseRenderer fBaseRenderer; + BaseRendererPre fBaseRendererPre; + + Scanline fScanline; + BinaryScanline fBinaryScanline; + SpanAllocator fSpanAllocator; + + CompoundRasterizer fRasterizer; + + Transformation fGlobalTransform; +}; + +#endif // ICON_RENDERER_H diff --git a/src/libs/icon/Jamfile b/src/libs/icon/Jamfile new file mode 100644 index 0000000000..fda395335f --- /dev/null +++ b/src/libs/icon/Jamfile @@ -0,0 +1,58 @@ +SubDir HAIKU_TOP src libs icon ; + +SetSubDirSupportedPlatformsBeOSCompatible ; +AddSubDirSupportedPlatforms libbe_test ; + +# source directories +local sourceDirs = + flat_icon + shape + style + transformable + transformer +; + +local sourceDir ; +for sourceDir in $(sourceDirs) { + SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src libs icon $(sourceDir) ] ; +} + +# system headers +UseLibraryHeaders agg ; + +UsePrivateHeaders shared ; + +StaticLibrary libicon.a : + # flat_icon + FlatIconFormat.cpp + FlatIconImporter.cpp + LittleEndianBuffer.cpp + PathCommandQueue.cpp + + # shape + PathContainer.cpp + Shape.cpp + ShapeContainer.cpp + VectorPath.cpp + + # style + Gradient.cpp + Style.cpp + StyleContainer.cpp + + # transformable + Transformable.cpp + + # transformer + AffineTransformer.cpp + ContourTransformer.cpp + PathSource.cpp + PerspectiveTransformer.cpp + StrokeTransformer.cpp + Transformer.cpp + TransformerFactory.cpp + + Icon.cpp + IconRenderer.cpp +; + diff --git a/src/libs/icon/flat_icon/FlatIconFormat.cpp b/src/libs/icon/flat_icon/FlatIconFormat.cpp new file mode 100644 index 0000000000..86f5be0afe --- /dev/null +++ b/src/libs/icon/flat_icon/FlatIconFormat.cpp @@ -0,0 +1,121 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "FlatIconFormat.h" + +#include "LittleEndianBuffer.h" + +const uint32 FLAT_ICON_MAGIC = 'ficn'; + +const char* kVectorAttrNodeName = "BEOS:I:STD_ICON"; +const char* kVectorAttrMimeName = "META:I:STD_ICON"; + +// read_coord +bool +read_coord(LittleEndianBuffer& buffer, float& coord) +{ + uint8 value; + if (!buffer.Read(value)) + return false; + + if (value & 128) { + // high bit set, the next byte is part of the coord + uint8 lowValue; + if (!buffer.Read(lowValue)) + return false; + value &= 127; + uint16 coordValue = (value << 8) | lowValue; + coord = (float)coordValue / 102.0 - 128.0; + } else { + // simple coord + coord = (float)value - 32.0; + } + return true; +} + +// write_coord +bool +write_coord(LittleEndianBuffer& buffer, float coord) +{ + // clamp coord + if (coord < -128.0) + coord = -128.0; + if (coord > 192.0) + coord = 192.0; + + if (int(coord * 100.0) == (int)coord * 100 + && coord >= - 32.0 && coord <= 96.0) { + // saving coord in 7 bit is sufficient + uint8 value = (uint8)(coord + 32.0); + return buffer.Write(value); + } else { + // needing to save coord in 15 bits + uint16 value = (uint16)((coord + 128.0) * 102.0); + // set high bit to indicate there is only one byte + value |= 32768; + uint8 highValue = value >> 8; + uint8 lowValue = value & 255; + return buffer.Write(highValue) && buffer.Write(lowValue); + } +} + +// read_float_24 +bool +read_float_24(LittleEndianBuffer& buffer, float& _value) +{ + uint8 bufferValue[3]; + if (!buffer.Read(bufferValue[0]) || !buffer.Read(bufferValue[1]) + || !buffer.Read(bufferValue[2])) + return false; + + int shortValue = (bufferValue[0] << 16) + | (bufferValue[1] << 8) | bufferValue[2]; + + int sign = (shortValue & 0x800000) >> 23; + int exponent = ((shortValue & 0x7e0000) >> 17) - 32; + int mantissa = (shortValue & 0x01ffff) << 6; + + if (shortValue == 0) + _value = 0.0; + else { + uint32 value = (sign << 31) | ((exponent + 127) << 23) | mantissa; + + _value = (float&)value; + } + + return true; +} + +// write_float_24 +bool +write_float_24(LittleEndianBuffer& buffer, float _value) +{ + // 1 bit sign + // 6 bit exponent + // 17 bit mantissa + // TODO: fixme for non-IEEE 754 architectures + uint32 value = (uint32&)_value; + + int sign = (value & 0x80000000) >> 31; + int exponent = ((value & 0x7f800000) >> 23) - 127; + int mantissa = value & 0x007fffff; + + if (exponent >= 32 || exponent < -32) { + uint8 zero = 0; + return buffer.Write(zero) && buffer.Write(zero) + && buffer.Write(zero); + } + + int shortValue = (sign << 23) + | ((exponent + 32) << 17) + | (mantissa >> 6); + + return buffer.Write((uint8)(shortValue >> 16)) + && buffer.Write((uint8)((shortValue >> 8) & 0xff)) + && buffer.Write((uint8)(shortValue & 0xff)); +} diff --git a/src/libs/icon/flat_icon/FlatIconFormat.h b/src/libs/icon/flat_icon/FlatIconFormat.h new file mode 100644 index 0000000000..9fef486b73 --- /dev/null +++ b/src/libs/icon/flat_icon/FlatIconFormat.h @@ -0,0 +1,68 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef FLAT_ICON_FORMAT_H +#define FLAT_ICON_FORMAT_H + +#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, + + TAG_SHAPE_PATH_SOURCE = 10, + + TAG_TRANSFORMER_AFFINE = 20, + TAG_TRANSFORMER_CONTOUR = 21, + TAG_TRANSFORMER_PERSPECTIVE = 22, + TAG_TRANSFORMER_STROKE = 23, +}; + +enum { + GRADIENT_FLAG_TRANSFORM = 1 << 1, + GRADIENT_FLAG_NO_ALPHA = 1 << 2, + GRADIENT_FLAG_16_BIT_COLORS = 1 << 3, // not yet used +}; + +enum { + PATH_FLAGS_CLOSED = 1 << 1, + PATH_FLAGS_USES_COMMANDS = 1 << 2, + PATH_FLAGS_NO_CURVES = 1 << 3, +}; + +enum { + PATH_COMMAND_H_LINE = 0, + PATH_COMMAND_V_LINE = 1, + PATH_COMMAND_LINE = 2, + PATH_COMMAND_CURVE = 3, +}; + +enum { + SHAPE_FLAG_TRANSFORM = 1 << 1, + SHAPE_FLAG_HINTING = 1 << 2, + SHAPE_FLAG_LOD_SCALE = 1 << 3, + SHAPE_FLAG_HAS_TRANSFORMERS = 1 << 4, + SHAPE_FLAG_TRANSLATION = 1 << 5, +}; + +// utility functions + +class LittleEndianBuffer; + +bool read_coord(LittleEndianBuffer& buffer, float& coord); +bool write_coord(LittleEndianBuffer& buffer, float coord); + +bool read_float_24(LittleEndianBuffer& buffer, float& value); +bool write_float_24(LittleEndianBuffer& buffer, float value); + +#endif // FLAT_ICON_FORMAT_H diff --git a/src/libs/icon/flat_icon/FlatIconImporter.cpp b/src/libs/icon/flat_icon/FlatIconImporter.cpp new file mode 100644 index 0000000000..abd40388cf --- /dev/null +++ b/src/libs/icon/flat_icon/FlatIconImporter.cpp @@ -0,0 +1,594 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "FlatIconImporter.h" + +#include +#include + +#include +#include +#include + +#include "AffineTransformer.h" +#include "AutoDeleter.h" +#include "ContourTransformer.h" +#include "FlatIconFormat.h" +#include "Gradient.h" +#include "Icon.h" +#include "LittleEndianBuffer.h" +#include "PathCommandQueue.h" +#include "PathContainer.h" +#include "PerspectiveTransformer.h" +#include "Shape.h" +#include "StrokeTransformer.h" +#include "Style.h" +#include "StyleContainer.h" +#include "VectorPath.h" + +using std::nothrow; + +// constructor +FlatIconImporter::FlatIconImporter() +{ +} + +// destructor +FlatIconImporter::~FlatIconImporter() +{ +} + +// Import +status_t +FlatIconImporter::Import(Icon* icon, BPositionIO* stream) +{ + // seek around in the stream to figure out the size + off_t size = stream->Seek(0, SEEK_END); + if (stream->Seek(0, SEEK_SET) != 0) + return B_ERROR; + + // we chicken out on anything larger than 256k + if (size <= 0 || size > 256 * 1024) + return B_BAD_VALUE; + + // read the entire stream into a buffer + LittleEndianBuffer buffer(size); + if (!buffer.Buffer()) + return B_NO_MEMORY; + + if (stream->Read(buffer.Buffer(), size) != size) + return B_ERROR; + + status_t ret = _ParseSections(buffer, icon); + + return ret; +} + +// Import +status_t +FlatIconImporter::Import(Icon* icon, uint8* _buffer, size_t size) +{ + if (!_buffer) + return B_BAD_VALUE; + + // attach LittleEndianBuffer to buffer + LittleEndianBuffer buffer(_buffer, size); + + return _ParseSections(buffer, icon); +} + +// #pragma mark - + +// _ParseSections +status_t +FlatIconImporter::_ParseSections(LittleEndianBuffer& buffer, Icon* icon) +{ + // test if this is an icon at all + uint32 magic; + if (!buffer.Read(magic) || magic != FLAT_ICON_MAGIC) + return B_ERROR; + + // styles + StyleContainer* styles = icon->Styles(); + status_t ret = _ParseStyles(buffer, styles); + if (ret < B_OK) { + printf("FlatIconImporter::_ParseSections() - " + "error parsing styles: %s\n", strerror(ret)); + return ret; + } + + // paths + PathContainer* paths = icon->Paths(); + ret = _ParsePaths(buffer, paths); + if (ret < B_OK) { + printf("FlatIconImporter::_ParseSections() - " + "error parsing paths: %s\n", strerror(ret)); + return ret; + } + + // shapes + ret = _ParseShapes(buffer, styles, paths, icon->Shapes()); + if (ret < B_OK) { + printf("FlatIconImporter::_ParseSections() - " + "error parsing shapes: %s\n", strerror(ret)); + return ret; + } + + return B_OK; +} + +// _ReadTransformable +static bool +_ReadTransformable(LittleEndianBuffer& buffer, Transformable* transformable) +{ + int32 matrixSize = Transformable::matrix_size; + double matrix[matrixSize]; + for (int32 i = 0; i < matrixSize; i++) { + float value; + if (!read_float_24(buffer, value)) + return false; + matrix[i] = value; + } + transformable->LoadFrom(matrix); + return true; +} + +// _ReadTranslation +static bool +_ReadTranslation(LittleEndianBuffer& buffer, Transformable* transformable) +{ + BPoint t; + if (read_coord(buffer, t.x) && read_coord(buffer, t.y)) { + transformable->TranslateBy(t); + return true; + } + + return false; +} + +// _ReadColorStyle +static Style* +_ReadColorStyle(LittleEndianBuffer& buffer, bool alpha) +{ + rgb_color color; + if (alpha) { + if (!buffer.Read((uint32&)color)) + return NULL; + } else { + color.alpha = 255; + if (!buffer.Read(color.red) + || !buffer.Read(color.green) + || !buffer.Read(color.blue)) + return NULL; + } + return new (nothrow) Style(color); +} + +// _ReadGradientStyle +static Style* +_ReadGradientStyle(LittleEndianBuffer& buffer) +{ + Style* style = new (nothrow) Style(); + if (!style) + return NULL; + + ObjectDeleter