* 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
This commit is contained in:
Stephan Aßmus
2006-08-04 23:57:01 +00:00
parent fd493c239f
commit fb07ece069
44 changed files with 8195 additions and 0 deletions
+1
View File
@@ -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 ;
+206
View File
@@ -0,0 +1,206 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "Icon.h"
#include <new>
#include <stdio.h>
#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<const Shape*>(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
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef ICON_H
#define ICON_H
#ifdef ICON_O_MATIC
#include <List.h>
# include "Observer.h"
#else
# include <SupportDefs.h>
#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
+428
View File
@@ -0,0 +1,428 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "IconRenderer.h"
#include <new>
#include <stdio.h>
#include <Bitmap.h>
#include <List.h>
#include <agg_span_gradient.h>
#include <agg_span_interpolator_linear.h>
#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<class GradientFunction>
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<class GradientFunction>
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<agg::rgba8, 256> ColorArray;
typedef agg::span_interpolator_linear<> Interpolator;
typedef agg::span_gradient<agg::rgba8,
Interpolator,
GradientFunction,
ColorArray> 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<VertexSource, Transformation> ScaledPath;
typedef agg::conv_transform<ScaledPath, HintingTransformer> 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);
}
+94
View File
@@ -0,0 +1,94 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef ICON_RENDERER_H
#define ICON_RENDERER_H
#include <agg_gamma_lut.h>
#include <agg_pixfmt_rgba.h>
#include <agg_rasterizer_compound_aa.h>
#include <agg_rendering_buffer.h>
#include <agg_renderer_scanline.h>
#include <agg_scanline_bin.h>
#include <agg_scanline_u.h>
#include <agg_span_allocator.h>
#include <agg_trans_affine.h>
class BBitmap;
class BRect;
class Icon;
typedef agg::gamma_lut
<agg::int8u, agg::int8u> GammaTable;
typedef agg::rendering_buffer RenderingBuffer;
typedef agg::pixfmt_bgra32 PixelFormat;
typedef agg::pixfmt_bgra32_pre PixelFormatPre;
typedef agg::renderer_base<PixelFormat> BaseRenderer;
typedef agg::renderer_base<PixelFormatPre> BaseRendererPre;
typedef agg::scanline_u8 Scanline;
typedef agg::scanline_bin BinaryScanline;
typedef agg::span_allocator<agg::rgba8> SpanAllocator;
typedef agg::rasterizer_compound_aa
<agg::rasterizer_sl_clip_dbl> 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
+58
View File
@@ -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
;
+121
View File
@@ -0,0 +1,121 @@
/*
* Copyright 2006, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#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));
}
+68
View File
@@ -0,0 +1,68 @@
/*
* Copyright 2006, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef FLAT_ICON_FORMAT_H
#define FLAT_ICON_FORMAT_H
#include <SupportDefs.h>
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
@@ -0,0 +1,594 @@
/*
* Copyright 2006, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "FlatIconImporter.h"
#include <new>
#include <stdio.h>
#include <Archivable.h>
#include <DataIO.h>
#include <Message.h>
#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<Style> styleDeleter(style);
uint8 gradientType;
uint8 gradientFlags;
uint8 gradientStopCount;
if (!buffer.Read(gradientType)
|| !buffer.Read(gradientFlags)
|| !buffer.Read(gradientStopCount)) {
return NULL;
}
Gradient gradient(true);
// empty gradient
gradient.SetType((gradient_type)gradientType);
// TODO: support more stuff with flags
// ("inherits transformation" and so on)
if (gradientFlags & GRADIENT_FLAG_TRANSFORM) {
if (!_ReadTransformable(buffer, &gradient))
return NULL;
}
bool alpha = !(gradientFlags & GRADIENT_FLAG_NO_ALPHA);
for (int32 i = 0; i < gradientStopCount; i++) {
uint8 stopOffset;
rgb_color color;
if (!buffer.Read(stopOffset))
return NULL;
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;
}
}
gradient.AddColor(color, stopOffset / 255.0);
}
style->SetGradient(&gradient);
styleDeleter.Detach();
return style;
}
// _ParseStyles
status_t
FlatIconImporter::_ParseStyles(LittleEndianBuffer& buffer,
StyleContainer* styles)
{
uint8 styleCount;
if (!buffer.Read(styleCount))
return B_ERROR;
for (int32 i = 0; i < styleCount; i++) {
uint8 styleType;
if (!buffer.Read(styleType))
return B_ERROR;
Style* style = NULL;
if (styleType == TAG_STYLE_SOLID_COLOR) {
// solid color
style = _ReadColorStyle(buffer, true);
if (!style)
return B_NO_MEMORY;
} else if (styleType == TAG_STYLE_SOLID_COLOR_NO_ALPHA) {
// solid color without alpha
style = _ReadColorStyle(buffer, false);
if (!style)
return B_NO_MEMORY;
} else if (styleType == TAG_STYLE_GRADIENT) {
// gradient
style = _ReadGradientStyle(buffer);
if (!style)
return B_NO_MEMORY;
} else {
// unkown style type, skip tag
uint16 tagLength;
if (!buffer.Read(tagLength))
return B_ERROR;
buffer.Skip(tagLength);
continue;
}
// add style if we were able to read one
if (style && !styles->AddStyle(style)) {
delete style;
return B_NO_MEMORY;
}
}
return B_OK;
}
// read_path_no_curves
static bool
read_path_no_curves(LittleEndianBuffer& buffer, VectorPath* path,
uint8 pointCount)
{
for (uint32 p = 0; p < pointCount; p++) {
BPoint point;
if (!read_coord(buffer, point.x)
|| !read_coord(buffer, point.y))
return false;
if (!path->AddPoint(point))
return false;
}
return true;
}
// read_path_curves
static bool
read_path_curves(LittleEndianBuffer& buffer, VectorPath* path,
uint8 pointCount)
{
for (uint32 p = 0; p < pointCount; p++) {
BPoint point;
if (!read_coord(buffer, point.x)
|| !read_coord(buffer, point.y))
return false;
BPoint pointIn;
if (!read_coord(buffer, pointIn.x)
|| !read_coord(buffer, pointIn.y))
return false;
BPoint pointOut;
if (!read_coord(buffer, pointOut.x)
|| !read_coord(buffer, pointOut.y))
return false;
if (!path->AddPoint(point, pointIn, pointOut, false))
return false;
}
return true;
}
// read_path_with_commands
static bool
read_path_with_commands(LittleEndianBuffer& buffer, VectorPath* path,
uint8 pointCount)
{
PathCommandQueue queue;
return queue.Read(buffer, path, pointCount);
}
// _ParsePaths
status_t
FlatIconImporter::_ParsePaths(LittleEndianBuffer& buffer,
PathContainer* paths)
{
uint8 pathCount;
if (!buffer.Read(pathCount))
return B_ERROR;
for (int32 i = 0; i < pathCount; i++) {
uint8 pathFlags;
uint8 pointCount;
if (!buffer.Read(pathFlags) || !buffer.Read(pointCount))
return B_ERROR;
VectorPath* path = new (nothrow) VectorPath();
if (!path)
return B_NO_MEMORY;
// chose path reading strategy depending on path flags
bool error = false;
if (pathFlags & PATH_FLAGS_NO_CURVES) {
if (!read_path_no_curves(buffer, path, pointCount))
error = true;
} else if (pathFlags & PATH_FLAGS_USES_COMMANDS) {
if (!read_path_with_commands(buffer, path, pointCount))
error = true;
} else {
if (!read_path_curves(buffer, path, pointCount))
error = true;
}
if (error) {
delete path;
return B_ERROR;
}
// post process path to clean it up
path->CleanUp();
if (pathFlags & PATH_FLAGS_CLOSED)
path->SetClosed(true);
// add path to container
if (!paths->AddPath(path)) {
delete path;
return B_NO_MEMORY;
}
}
return B_OK;
}
// _ReadTransformer
static Transformer*
_ReadTransformer(LittleEndianBuffer& buffer, VertexSource& source)
{
uint8 transformerType;
if (!buffer.Read(transformerType))
return NULL;
switch (transformerType) {
case TAG_TRANSFORMER_AFFINE: {
AffineTransformer* affine
= new (nothrow) AffineTransformer(source);
if (!affine)
return NULL;
double matrix[6];
for (int32 i = 0; i < 6; i++) {
float value;
if (!buffer.Read(value)) {
delete affine;
return NULL;
}
matrix[i] = value;
}
affine->load_from(matrix);
return affine;
}
case TAG_TRANSFORMER_CONTOUR: {
ContourTransformer* contour
= new (nothrow) ContourTransformer(source);
uint8 width;
uint8 lineJoin;
uint8 miterLimit;
if (!contour
|| !buffer.Read(width)
|| !buffer.Read(lineJoin)
|| !buffer.Read(miterLimit)) {
delete contour;
return NULL;
}
contour->width(width - 128.0);
contour->line_join((agg::line_join_e)lineJoin);
contour->miter_limit(miterLimit);
return contour;
}
case TAG_TRANSFORMER_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: {
StrokeTransformer* stroke
= new (nothrow) StrokeTransformer(source);
uint8 width;
uint8 lineJoin;
uint8 lineCap;
uint8 miterLimit;
// uint8 shorten;
if (!stroke
|| !buffer.Read(width)
|| !buffer.Read(lineJoin)
|| !buffer.Read(lineCap)
|| !buffer.Read(miterLimit)) {
delete stroke;
return NULL;
}
stroke->width(width - 128.0);
stroke->line_join((agg::line_join_e)lineJoin);
stroke->line_cap((agg::line_cap_e)lineCap);
stroke->miter_limit(miterLimit);
return stroke;
}
default: {
// unkown transformer, skip tag
uint16 tagLength;
if (!buffer.Read(tagLength))
return NULL;
buffer.Skip(tagLength);
return NULL;
}
}
}
// _ReadPathSourceShape
static Shape*
_ReadPathSourceShape(LittleEndianBuffer& buffer,
StyleContainer* styles, PathContainer* paths)
{
// find out which style this shape uses
uint8 styleIndex;
uint8 pathCount;
if (!buffer.Read(styleIndex) || !buffer.Read(pathCount))
return NULL;
Style* style = styles->StyleAt(styleIndex);
if (!style) {
printf("_ReadPathSourceShape() - "
"shape references non-existing style %d\n", styleIndex);
return NULL;
}
// create the shape
Shape* shape = new (nothrow) Shape(style);
ObjectDeleter<Shape> shapeDeleter(shape);
if (!shape || shape->InitCheck() < B_OK)
return NULL;
// find out which paths this shape uses
for (uint32 i = 0; i < pathCount; i++) {
uint8 pathIndex;
if (!buffer.Read(pathIndex))
return NULL;
VectorPath* path = paths->PathAt(pathIndex);
if (!path) {
printf("_ReadPathSourceShape() - "
"shape references non-existing path %d\n", pathIndex);
continue;
}
shape->Paths()->AddPath(path);
}
// shape flags
uint8 shapeFlags;
if (!buffer.Read(shapeFlags))
return NULL;
shape->SetHinting(shapeFlags & SHAPE_FLAG_HINTING);
if (shapeFlags & SHAPE_FLAG_TRANSFORM) {
// transformation
if (!_ReadTransformable(buffer, shape))
return NULL;
} else if (shapeFlags & SHAPE_FLAG_TRANSLATION) {
// translation
if (!_ReadTranslation(buffer, shape))
return NULL;
}
if (shapeFlags & SHAPE_FLAG_LOD_SCALE) {
// min max visibility scale
uint8 minScale;
uint8 maxScale;
if (!buffer.Read(minScale) || !buffer.Read(maxScale))
return NULL;
shape->SetMinVisibilityScale((float)minScale);
shape->SetMaxVisibilityScale((float)maxScale);
}
// transformers
if (shapeFlags & SHAPE_FLAG_HAS_TRANSFORMERS) {
uint8 transformerCount;
if (!buffer.Read(transformerCount))
return NULL;
for (uint32 i = 0; i < transformerCount; i++) {
Transformer* transformer
= _ReadTransformer(buffer, shape->VertexSource());
if (transformer && !shape->AddTransformer(transformer)) {
delete transformer;
return NULL;
}
}
}
shapeDeleter.Detach();
return shape;
}
// _ParseShapes
status_t
FlatIconImporter::_ParseShapes(LittleEndianBuffer& buffer,
StyleContainer* styles,
PathContainer* paths,
ShapeContainer* shapes)
{
uint8 shapeCount;
if (!buffer.Read(shapeCount))
return B_ERROR;
for (uint32 i = 0; i < shapeCount; i++) {
uint8 shapeType;
if (!buffer.Read(shapeType))
return B_ERROR;
Shape* shape = NULL;
if (shapeType == TAG_SHAPE_PATH_SOURCE) {
// path source shape
shape = _ReadPathSourceShape(buffer, styles, paths);
if (!shape)
return B_NO_MEMORY;
} else {
// unkown shape type, skip tag
uint16 tagLength;
if (!buffer.Read(tagLength))
return B_ERROR;
buffer.Skip(tagLength);
continue;
}
// add shape if we were able to read one
if (shape && !shapes->AddShape(shape)) {
delete shape;
return B_NO_MEMORY;
}
}
return B_OK;
}
@@ -0,0 +1,49 @@
/*
* Copyright 2006, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef FLAT_ICON_IMPORTER_H
#define FLAT_ICON_IMPORTER_H
#include <SupportDefs.h>
class BMessage;
class BPositionIO;
class Icon;
class LittleEndianBuffer;
class PathContainer;
class ShapeContainer;
class StyleContainer;
class FlatIconImporter {
public:
FlatIconImporter();
virtual ~FlatIconImporter();
// Importer interface (Importer base not yet written)
virtual status_t Import(Icon* icon,
BPositionIO* stream);
// FlatIconImporter
status_t Import(Icon* icon,
uint8* buffer, size_t size);
private:
status_t _ParseSections(LittleEndianBuffer& buffer,
Icon* icon);
status_t _ParseStyles(LittleEndianBuffer& buffer,
StyleContainer* styles);
status_t _ParsePaths(LittleEndianBuffer& buffer,
PathContainer* paths);
status_t _ParseShapes(LittleEndianBuffer& buffer,
StyleContainer* styles,
PathContainer* paths,
ShapeContainer* shapes);
};
#endif // FLAT_ICON_IMPORTER_H
@@ -0,0 +1,289 @@
/*
* Copyright 2006, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "LittleEndianBuffer.h"
#include <malloc.h>
#include <stdio.h>
#include <ByteOrder.h>
#define CHUNK_SIZE 256
// constructor
LittleEndianBuffer::LittleEndianBuffer()
: fBuffer((uint8*)malloc(CHUNK_SIZE)),
fHandle(fBuffer),
fBufferEnd(fBuffer + CHUNK_SIZE),
fSize(CHUNK_SIZE),
fOwnsBuffer(true)
{
}
// constructor
LittleEndianBuffer::LittleEndianBuffer(size_t size)
: fBuffer((uint8*)malloc(size)),
fHandle(fBuffer),
fBufferEnd(fBuffer + size),
fSize(size),
fOwnsBuffer(true)
{
}
// constructor
LittleEndianBuffer::LittleEndianBuffer(uint8* buffer, size_t size)
: fBuffer(buffer),
fHandle(fBuffer),
fBufferEnd(fBuffer + size),
fSize(size),
fOwnsBuffer(false)
{
}
// destructor
LittleEndianBuffer::~LittleEndianBuffer()
{
if (fOwnsBuffer)
free(fBuffer);
}
// Write 8
bool
LittleEndianBuffer::Write(uint8 value)
{
if (fHandle == fBufferEnd)
_SetSize(fSize + CHUNK_SIZE);
if (!fBuffer)
return false;
*fHandle = value;
fHandle++;
return true;
}
// Write 16
bool
LittleEndianBuffer::Write(uint16 value)
{
if ((fHandle + 1) >= fBufferEnd)
_SetSize(fSize + CHUNK_SIZE);
if (!fBuffer)
return false;
*(uint16*)fHandle = B_HOST_TO_LENDIAN_INT16(value);
fHandle += 2;
return true;
}
// Write 32
bool
LittleEndianBuffer::Write(uint32 value)
{
if ((fHandle + 3) >= fBufferEnd)
_SetSize(fSize + CHUNK_SIZE);
if (!fBuffer)
return false;
*(uint32*)fHandle = B_HOST_TO_LENDIAN_INT32(value);
fHandle += 4;
return true;
}
// Write double
bool
LittleEndianBuffer::Write(float value)
{
if ((fHandle + sizeof(float) - 1) >= fBufferEnd)
_SetSize(fSize + CHUNK_SIZE);
if (!fBuffer)
return false;
*(float*)fHandle = B_HOST_TO_LENDIAN_FLOAT(value);
fHandle += sizeof(float);
return true;
}
// Write double
bool
LittleEndianBuffer::Write(double value)
{
if ((fHandle + sizeof(double) - 1) >= fBufferEnd)
_SetSize(fSize + CHUNK_SIZE);
if (!fBuffer)
return false;
*(double*)fHandle = B_HOST_TO_LENDIAN_DOUBLE(value);
fHandle += sizeof(double);
return true;
}
// Write LittleEndianBuffer
bool
LittleEndianBuffer::Write(const LittleEndianBuffer& other)
{
return Write(other.Buffer(), other.SizeUsed());
}
// Write buffer
bool
LittleEndianBuffer::Write(const uint8* buffer, size_t bytes)
{
if (bytes == 0)
return true;
// figure out needed size and suitable new size
size_t neededSize = SizeUsed() + bytes;
size_t newSize = fSize;
while (newSize < neededSize)
newSize += CHUNK_SIZE;
// resize if necessary
if (newSize > fSize)
_SetSize(newSize);
if (!fBuffer)
return false;
// paste buffer
memcpy(fHandle, buffer, bytes);
fHandle += bytes;
return true;
}
// #pragma mark -
// Read 8
bool
LittleEndianBuffer::Read(uint8& value)
{
if (fHandle >= fBufferEnd)
return false;
value = *fHandle++;
return true;
}
// Read 16
bool
LittleEndianBuffer::Read(uint16& value)
{
if ((fHandle + 1) >= fBufferEnd)
return false;
value = B_LENDIAN_TO_HOST_INT16(*(uint16*)fHandle);
fHandle += 2;
return true;
}
// Read 32
bool
LittleEndianBuffer::Read(uint32& value)
{
if ((fHandle + 3) >= fBufferEnd)
return false;
value = B_LENDIAN_TO_HOST_INT32(*(uint32*)fHandle);
fHandle += 4;
return true;
}
// Read float
bool
LittleEndianBuffer::Read(float& value)
{
if ((fHandle + sizeof(float) - 1) >= fBufferEnd)
return false;
value = B_LENDIAN_TO_HOST_FLOAT(*(float*)fHandle);
fHandle += sizeof(float);
return true;
}
// Read double
bool
LittleEndianBuffer::Read(double& value)
{
if ((fHandle + sizeof(double) - 1) >= fBufferEnd)
return false;
value = B_LENDIAN_TO_HOST_DOUBLE(*(double*)fHandle);
fHandle += sizeof(double);
return true;
}
// Read LittleEndianBuffer
bool
LittleEndianBuffer::Read(LittleEndianBuffer& other, size_t bytes)
{
if ((fHandle + bytes - 1) >= fBufferEnd)
return false;
if (other.Write(fHandle, bytes)) {
// reset other handle to beginning of pasted data
other.fHandle -= bytes;
fHandle += bytes;
return true;
}
return false;
}
// #pragma mark -
// Skip
void
LittleEndianBuffer::Skip(size_t bytes)
{
// NOTE: is ment to be used while reading!!
// when used while writing, the growing will not work reliably
fHandle += bytes;
}
// Reset
void
LittleEndianBuffer::Reset()
{
fHandle = fBuffer;
}
// #pragma mark -
// _SetSize
void
LittleEndianBuffer::_SetSize(size_t size)
{
if (!fOwnsBuffer) {
// prevent user error
// (we are in read mode)
fBuffer = NULL;
return;
}
int32 pos = fHandle - fBuffer;
fBuffer = (uint8*)realloc((void*)fBuffer, size);
fHandle = fBuffer + pos;
fBufferEnd = fBuffer + size;
fSize = size;
}
@@ -0,0 +1,57 @@
/*
* Copyright 2006, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef LITTLE_ENDIAN_BUFFER_H
#define LITTLE_ENDIAN_BUFFER_H
#include <SupportDefs.h>
class LittleEndianBuffer {
public:
LittleEndianBuffer();
LittleEndianBuffer(size_t size);
LittleEndianBuffer(uint8* buffer,
size_t size);
~LittleEndianBuffer();
bool Write(uint8 value);
bool Write(uint16 value);
bool Write(uint32 value);
bool Write(float value);
bool Write(double value);
bool Write(const LittleEndianBuffer& other);
bool Write(const uint8* buffer, size_t bytes);
bool Read(uint8& value);
bool Read(uint16& value);
bool Read(uint32& value);
bool Read(float& value);
bool Read(double& value);
bool Read(LittleEndianBuffer& other, size_t bytes);
void Skip(size_t bytes);
uint8* Buffer() const
{ return fBuffer; }
size_t SizeUsed() const
{ return fHandle - fBuffer; }
void Reset();
private:
void _SetSize(size_t size);
uint8* fBuffer;
uint8* fHandle;
uint8* fBufferEnd;
size_t fSize;
bool fOwnsBuffer;
};
#endif // LITTLE_ENDIAN_BUFFER_H
@@ -0,0 +1,264 @@
/*
* Copyright 2006, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "PathCommandQueue.h"
#include <stdio.h>
#include <Point.h>
#include "FlatIconFormat.h"
#include "VectorPath.h"
// constructor
PathCommandQueue::PathCommandQueue()
: fCommandBuffer(),
fPointBuffer(),
fCommandByte(0),
fCommandPos(0),
fCommandCount(0)
{
}
// destructor
PathCommandQueue::~PathCommandQueue()
{
}
// Write
bool
PathCommandQueue::Write(LittleEndianBuffer& buffer,
const VectorPath* path, uint8 pointCount)
{
// reset
fCommandCount = 0;
fCommandByte = 0;
fCommandPos = 0;
fCommandBuffer.Reset();
fPointBuffer.Reset();
BPoint last(B_ORIGIN);
for (uint32 p = 0; p < pointCount; p++) {
BPoint point;
BPoint pointIn;
BPoint pointOut;
if (!path->GetPointsAt(p, point, pointIn, pointOut))
return false;
if (point == pointIn && point == pointOut) {
// single point is sufficient
if (point.x == last.x) {
// vertical line
if (!_AppendVLine(point.y))
return false;
} else if (point.y == last.y) {
// horizontal line
if (!_AppendHLine(point.x))
return false;
} else {
// line
if (!_AppendLine(point))
return false;
}
} else {
// needing to write all three points
if (!_AppendCurve(point, pointIn, pointOut))
return false;
}
last = point;
}
if (fCommandPos > 0) {
// the last couple commands have not been written
if (!fCommandBuffer.Write(fCommandByte))
return false;
}
return buffer.Write(fCommandBuffer) && buffer.Write(fPointBuffer);
}
// Read
bool
PathCommandQueue::Read(LittleEndianBuffer& buffer,
VectorPath* path, uint8 pointCount)
{
// reset
fCommandCount = 0;
fCommandByte = 0;
fCommandPos = 0;
fCommandBuffer.Reset();
// NOTE: fPointBuffer is not used for reading
// we read the command buffer and then use the
// buffer directly for the coords
// read command buffer
uint8 commandBufferSize = (pointCount + 3) / 4;
if (!buffer.Read(fCommandBuffer, commandBufferSize))
return false;
BPoint last(B_ORIGIN);
for (uint32 p = 0; p < pointCount; p++) {
uint8 command;
if (!_ReadCommand(command))
return false;
BPoint point;
BPoint pointIn;
BPoint pointOut;
switch (command) {
case PATH_COMMAND_H_LINE:
if (!read_coord(buffer, point.x))
return false;
point.y = last.y;
pointIn = point;
pointOut = point;
break;
case PATH_COMMAND_V_LINE:
if (!read_coord(buffer, point.y))
return false;
point.x = last.x;
pointIn = point;
pointOut = point;
break;
case PATH_COMMAND_LINE:
if (!read_coord(buffer, point.x)
|| !read_coord(buffer, point.y))
return false;
pointIn = point;
pointOut = point;
break;
case PATH_COMMAND_CURVE:
if (!read_coord(buffer, point.x)
|| !read_coord(buffer, point.y)
|| !read_coord(buffer, pointIn.x)
|| !read_coord(buffer, pointIn.y)
|| !read_coord(buffer, pointOut.x)
|| !read_coord(buffer, pointOut.y))
return false;
break;
}
if (!path->AddPoint(point, pointIn, pointOut, false))
return false;
last = point;
}
return true;
}
// #pragma mark -
// _AppendHLine
bool
PathCommandQueue::_AppendHLine(float x)
{
return _AppendCommand(PATH_COMMAND_H_LINE)
&& write_coord(fPointBuffer, x);
}
// _AppendVLine
bool
PathCommandQueue::_AppendVLine(float y)
{
return _AppendCommand(PATH_COMMAND_V_LINE)
&& write_coord(fPointBuffer, y);
}
// _AppendLine
bool
PathCommandQueue::_AppendLine(const BPoint& point)
{
return _AppendCommand(PATH_COMMAND_LINE)
&& write_coord(fPointBuffer, point.x)
&& write_coord(fPointBuffer, point.y);
}
// _AppendCurve
bool
PathCommandQueue::_AppendCurve(const BPoint& point,
const BPoint& pointIn,
const BPoint& pointOut)
{
return _AppendCommand(PATH_COMMAND_CURVE)
&& write_coord(fPointBuffer, point.x)
&& write_coord(fPointBuffer, point.y)
&& write_coord(fPointBuffer, pointIn.x)
&& write_coord(fPointBuffer, pointIn.y)
&& write_coord(fPointBuffer, pointOut.x)
&& write_coord(fPointBuffer, pointOut.y);
}
// #pragma mark -
// _AppendCommand
bool
PathCommandQueue::_AppendCommand(uint8 command)
{
// NOTE: a path command uses 2 bits, so 4 of
// them fit into a single byte
// after we have appended the fourth command,
// the byte is written to fCommandBuffer and
// the cycle repeats
if (fCommandCount == 255) {
printf("PathCommandQueue::_AppendCommand() - "
"maximum path section count reached\n");
return false;
}
fCommandByte |= command << fCommandPos;
fCommandPos += 2;
fCommandCount++;
if (fCommandPos == 8) {
uint8 commandByte = fCommandByte;
fCommandByte = 0;
fCommandPos = 0;
return fCommandBuffer.Write(commandByte);
}
return true;
}
// _ReadCommand
bool
PathCommandQueue::_ReadCommand(uint8& command)
{
if (fCommandCount == 255) {
printf("PathCommandQueue::_NextCommand() - "
"maximum path section count reached\n");
return false;
}
if (fCommandPos == 0) {
// fetch the next four commands from the buffer
if (!fCommandBuffer.Read(fCommandByte))
return false;
}
command = (fCommandByte >> fCommandPos) & 0x03;
fCommandPos += 2;
fCommandCount++;
if (fCommandPos == 8)
fCommandPos = 0;
return true;
}
@@ -0,0 +1,53 @@
/*
* Copyright 2006, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef PATH_COMMAND_QUEUE_H
#define PATH_COMMAND_QUEUE_H
#include "LittleEndianBuffer.h"
class BPoint;
class VectorPath;
class PathCommandQueue {
public:
PathCommandQueue();
virtual ~PathCommandQueue();
bool Write(LittleEndianBuffer& buffer,
const VectorPath* path,
uint8 pointCount);
bool Read(LittleEndianBuffer& buffer,
VectorPath* path,
uint8 pointCount);
private:
// writing
bool _AppendHLine(float x);
bool _AppendVLine(float y);
bool _AppendLine(const BPoint& point);
bool _AppendCurve(const BPoint& point,
const BPoint& pointIn,
const BPoint& pointOut);
bool _AppendCommand(uint8 command);
// reading
bool _ReadCommand(uint8& command);
LittleEndianBuffer fCommandBuffer;
LittleEndianBuffer fPointBuffer;
uint8 fCommandByte;
uint8 fCommandPos;
uint8 fCommandCount;
};
#endif // PATH_COMMAND_QUEUE_H
+213
View File
@@ -0,0 +1,213 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "PathContainer.h"
#include <stdio.h>
#include <string.h>
#include <OS.h>
#include "VectorPath.h"
#ifdef ICON_O_MATIC
PathContainerListener::PathContainerListener() {}
PathContainerListener::~PathContainerListener() {}
#endif
// constructor
PathContainer::PathContainer(bool ownsPaths)
: fPaths(16),
fOwnsPaths(ownsPaths),
#ifdef ICON_O_MATIC
fListeners(2)
#endif
{
}
// destructor
PathContainer::~PathContainer()
{
#ifdef ICON_O_MATIC
int32 count = fListeners.CountItems();
if (count > 0) {
debugger("~PathContainer() - there are still"
"listeners attached\n");
}
#endif // ICON_O_MATIC
_MakeEmpty();
}
// #pragma mark -
// AddPath
bool
PathContainer::AddPath(VectorPath* path)
{
if (!path)
return false;
// prevent adding the same path twice
if (HasPath(path))
return false;
if (fPaths.AddItem((void*)path)) {
#ifdef ICON_O_MATIC
_NotifyPathAdded(path);
#endif
return true;
}
fprintf(stderr, "PathContainer::AddPath() - out of memory!\n");
return false;
}
// RemovePath
bool
PathContainer::RemovePath(VectorPath* path)
{
if (fPaths.RemoveItem((void*)path)) {
#ifdef ICON_O_MATIC
_NotifyPathRemoved(path);
#endif
return true;
}
return false;
}
// RemovePath
VectorPath*
PathContainer::RemovePath(int32 index)
{
VectorPath* path = (VectorPath*)fPaths.RemoveItem(index);
#ifdef ICON_O_MATIC
if (path) {
_NotifyPathRemoved(path);
}
#endif
return path;
}
// MakeEmpty
void
PathContainer::MakeEmpty()
{
_MakeEmpty();
}
// #pragma mark -
// CountPaths
int32
PathContainer::CountPaths() const
{
return fPaths.CountItems();
}
// HasPath
bool
PathContainer::HasPath(VectorPath* path) const
{
return fPaths.HasItem((void*)path);
}
// IndexOf
int32
PathContainer::IndexOf(VectorPath* path) const
{
return fPaths.IndexOf((void*)path);
}
// PathAt
VectorPath*
PathContainer::PathAt(int32 index) const
{
return (VectorPath*)fPaths.ItemAt(index);
}
// PathAtFast
VectorPath*
PathContainer::PathAtFast(int32 index) const
{
return (VectorPath*)fPaths.ItemAtFast(index);
}
// #pragma mark -
#ifdef ICON_O_MATIC
// AddListener
bool
PathContainer::AddListener(PathContainerListener* listener)
{
if (listener && !fListeners.HasItem((void*)listener))
return fListeners.AddItem(listener);
return false;
}
// RemoveListener
bool
PathContainer::RemoveListener(PathContainerListener* listener)
{
return fListeners.RemoveItem(listener);
}
#endif // ICON_O_MATIC
// #pragma mark -
// _MakeEmpty
void
PathContainer::_MakeEmpty()
{
int32 count = CountPaths();
for (int32 i = 0; i < count; i++) {
VectorPath* path = PathAtFast(i);
#ifdef ICON_O_MATIC
_NotifyPathRemoved(path);
if (fOwnsPaths)
path->Release();
#else
if (fOwnsPaths)
delete path;
#endif
}
fPaths.MakeEmpty();
}
// #pragma mark -
#ifdef ICON_O_MATIC
// _NotifyPathAdded
void
PathContainer::_NotifyPathAdded(VectorPath* path) const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
PathContainerListener* listener
= (PathContainerListener*)listeners.ItemAtFast(i);
listener->PathAdded(path);
}
}
// _NotifyPathRemoved
void
PathContainer::_NotifyPathRemoved(VectorPath* path) const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
PathContainerListener* listener
= (PathContainerListener*)listeners.ItemAtFast(i);
listener->PathRemoved(path);
}
}
#endif // ICON_O_MATIC
+64
View File
@@ -0,0 +1,64 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef PATH_CONTAINER_H
#define PATH_CONTAINER_H
#include <List.h>
class VectorPath;
#ifdef ICON_O_MATIC
class PathContainerListener {
public:
PathContainerListener();
virtual ~PathContainerListener();
virtual void PathAdded(VectorPath* path) = 0;
virtual void PathRemoved(VectorPath* path) = 0;
};
#endif // ICON_O_MATIC
class PathContainer {
public:
PathContainer(bool ownsPaths);
virtual ~PathContainer();
bool AddPath(VectorPath* path);
bool RemovePath(VectorPath* path);
VectorPath* RemovePath(int32 index);
void MakeEmpty();
int32 CountPaths() const;
bool HasPath(VectorPath* path) const;
int32 IndexOf(VectorPath* path) const;
VectorPath* PathAt(int32 index) const;
VectorPath* PathAtFast(int32 index) const;
private:
void _MakeEmpty();
BList fPaths;
bool fOwnsPaths;
#ifdef ICON_O_MATIC
public:
bool AddListener(PathContainerListener* listener);
bool RemoveListener(PathContainerListener* listener);
private:
void _NotifyPathAdded(VectorPath* path) const;
void _NotifyPathRemoved(VectorPath* path) const;
BList fListeners;
#endif // ICON_O_MATIC
};
#endif // PATH_CONTAINER_H
+676
View File
@@ -0,0 +1,676 @@
/*
* Copyright 2006, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "Shape.h"
#include <Message.h>
#include <TypeConstants.h>
#include <new>
#include <limits.h>
#include <stdio.h>
#include "agg_bounding_rect.h"
#ifdef ICON_O_MATIC
# include "CommonPropertyIDs.h"
# include "Property.h"
# include "PropertyObject.h"
#endif // ICON_O_MATIC
#include "Style.h"
#include "TransformerFactory.h"
using std::nothrow;
#ifdef ICON_O_MATIC
// constructor
ShapeListener::ShapeListener()
{
}
// destructor
ShapeListener::~ShapeListener()
{
}
#endif // ICON_O_MATIC
// #pragma mark -
// constructor
Shape::Shape(::Style* style)
#ifdef ICON_O_MATIC
: IconObject("<shape>"),
Transformable(),
Observer(),
PathContainerListener(),
#else
: Transformable(),
#endif
fPaths(new (nothrow) PathContainer(false)),
fStyle(NULL),
fPathSource(fPaths),
fTransformers(4),
fNeedsUpdate(true),
fLastBounds(0, 0, -1, -1),
fHinting(false),
fMinVisibilityScale(0.0),
fMaxVisibilityScale(255.0)
#ifdef ICON_O_MATIC
, fListeners(8)
#endif
{
SetStyle(style);
#ifdef ICON_O_MATIC
if (fPaths)
fPaths->AddListener(this);
#endif
}
// constructor
Shape::Shape(const Shape& other)
#ifdef ICON_O_MATIC
: IconObject(other),
Transformable(other),
Observer(),
PathContainerListener(),
#else
: Transformable(other),
#endif
fPaths(new (nothrow) PathContainer(false)),
fStyle(NULL),
fPathSource(fPaths),
fTransformers(4),
fNeedsUpdate(true),
fLastBounds(0, 0, -1, -1),
fHinting(other.fHinting),
fMinVisibilityScale(other.fMinVisibilityScale),
fMaxVisibilityScale(other.fMaxVisibilityScale)
#ifdef ICON_O_MATIC
, fListeners(8)
#endif
{
SetStyle(other.fStyle);
if (fPaths) {
#ifdef ICON_O_MATIC
fPaths->AddListener(this);
#endif
// copy the path references from
// the other shape
if (other.fPaths) {
int32 count = other.fPaths->CountPaths();
for (int32 i = 0; i < count; i++) {
if (!fPaths->AddPath(other.fPaths->PathAtFast(i)))
break;
}
}
}
// clone vertex transformers
int32 count = other.CountTransformers();
for (int32 i = 0; i < count; i++) {
Transformer* original = other.TransformerAtFast(i);
Transformer* cloned = original->Clone(fPathSource);
if (!AddTransformer(cloned)) {
delete cloned;
break;
}
}
}
// destructor
Shape::~Shape()
{
int32 count = fTransformers.CountItems();
for (int32 i = 0; i < count; i++) {
Transformer* t = (Transformer*)fTransformers.ItemAtFast(i);
#ifdef ICON_O_MATIC
t->RemoveObserver(this);
_NotifyTransformerRemoved(t);
#endif
delete t;
}
fPaths->MakeEmpty();
#ifdef ICON_O_MATIC
fPaths->RemoveListener(this);
#endif
delete fPaths;
SetStyle(NULL);
}
// #pragma mark -
#ifdef ICON_O_MATIC
// Unarchive
status_t
Shape::Unarchive(const BMessage* archive)
{
// IconObject properties
status_t ret = IconObject::Unarchive(archive);
if (ret < B_OK)
return ret;
// recreate transformers
BMessage transformerArchive;
for (int32 i = 0;
archive->FindMessage("transformer", i,
&transformerArchive) == B_OK;
i++) {
Transformer* transformer
= TransformerFactory::TransformerFor(
&transformerArchive, VertexSource());
if (!transformer || !AddTransformer(transformer)) {
delete transformer;
}
}
// read transformation
int32 size = Transformable::matrix_size;
const void* matrix;
ssize_t dataSize = size * sizeof(double);
ret = archive->FindData("transformation", B_DOUBLE_TYPE,
&matrix, &dataSize);
if (ret == B_OK && dataSize == (ssize_t)(size * sizeof(double)))
LoadFrom((const double*)matrix);
// hinting
if (archive->FindBool("hinting", &fHinting) < B_OK)
fHinting = false;
// min visibility scale
if (archive->FindFloat("min visibility scale",
&fMinVisibilityScale) < B_OK)
fMinVisibilityScale = 0.0;
// max visibility scale
if (archive->FindFloat("max visibility scale",
&fMaxVisibilityScale) < B_OK)
fMaxVisibilityScale = 255.0;
if (fMinVisibilityScale < 0.0)
fMinVisibilityScale = 0.0;
if (fMinVisibilityScale > 255.0)
fMinVisibilityScale = 255.0;
if (fMaxVisibilityScale < 0.0)
fMaxVisibilityScale = 0.0;
if (fMaxVisibilityScale > 255.0)
fMaxVisibilityScale = 255.0;
return B_OK;
}
// Archive
status_t
Shape::Archive(BMessage* into, bool deep) const
{
status_t ret = IconObject::Archive(into, deep);
// transformers
if (ret == B_OK) {
int32 count = CountTransformers();
for (int32 i = 0; i < count; i++) {
Transformer* transformer = TransformerAtFast(i);
BMessage transformerArchive;
ret = transformer->Archive(&transformerArchive);
if (ret == B_OK)
ret = into->AddMessage("transformer", &transformerArchive);
if (ret < B_OK)
break;
}
}
// transformation
if (ret == B_OK) {
int32 size = Transformable::matrix_size;
double matrix[size];
StoreTo(matrix);
ret = into->AddData("transformation", B_DOUBLE_TYPE,
matrix, size * sizeof(double));
}
// hinting
if (ret ==B_OK)
ret = into->AddBool("hinting", fHinting);
// min visibility scale
if (ret ==B_OK)
ret = into->AddFloat("min visibility scale",
fMinVisibilityScale);
// max visibility scale
if (ret ==B_OK)
ret = into->AddFloat("max visibility scale",
fMaxVisibilityScale);
return ret;
}
// MakePropertyObject
PropertyObject*
Shape::MakePropertyObject() const
{
PropertyObject* object = IconObject::MakePropertyObject();
if (!object)
return NULL;
object->AddProperty(new BoolProperty(PROPERTY_HINTING, fHinting));
object->AddProperty(new FloatProperty(PROPERTY_MIN_VISIBILITY_SCALE,
fMinVisibilityScale, 0, 255));
object->AddProperty(new FloatProperty(PROPERTY_MAX_VISIBILITY_SCALE,
fMaxVisibilityScale, 0, 255));
return object;
}
// SetToPropertyObject
bool
Shape::SetToPropertyObject(const PropertyObject* object)
{
AutoNotificationSuspender _(this);
IconObject::SetToPropertyObject(object);
// hinting
SetHinting(object->Value(PROPERTY_HINTING, fHinting));
// min visibility scale
SetMinVisibilityScale(object->Value(PROPERTY_MIN_VISIBILITY_SCALE,
fMinVisibilityScale));
// max visibility scale
SetMaxVisibilityScale(object->Value(PROPERTY_MAX_VISIBILITY_SCALE,
fMaxVisibilityScale));
return HasPendingNotifications();
}
// #pragma mark -
// TransformationChanged
void
Shape::TransformationChanged()
{
// TODO: notify appearance change
_NotifyRerender();
}
// #pragma mark -
// ObjectChanged
void
Shape::ObjectChanged(const Observable* object)
{
// simply pass on the event for now
// (a path, transformer or the style changed,
// the shape needs to be re-rendered)
_NotifyRerender();
}
// #pragma mark -
// PathAdded
void
Shape::PathAdded(VectorPath* path)
{
path->Acquire();
path->AddListener(this);
_NotifyRerender();
}
// PathRemoved
void
Shape::PathRemoved(VectorPath* path)
{
path->RemoveListener(this);
_NotifyRerender();
path->Release();
}
// #pragma mark -
// PointAdded
void
Shape::PointAdded(int32 index)
{
_NotifyRerender();
}
// PointRemoved
void
Shape::PointRemoved(int32 index)
{
_NotifyRerender();
}
// PointChanged
void
Shape::PointChanged(int32 index)
{
_NotifyRerender();
}
// PathChanged
void
Shape::PathChanged()
{
_NotifyRerender();
}
// PathClosedChanged
void
Shape::PathClosedChanged()
{
_NotifyRerender();
}
// PathReversed
void
Shape::PathReversed()
{
_NotifyRerender();
}
#endif // ICON_O_MATIC
// #pragma mark -
// InitCheck
status_t
Shape::InitCheck() const
{
return fPaths ? B_OK : B_NO_MEMORY;
}
// #pragma mark -
// SetStyle
void
Shape::SetStyle(::Style* style)
{
#ifdef ICON_O_MATIC
if (fStyle == style)
return;
if (fStyle) {
fStyle->RemoveObserver(this);
fStyle->Release();
}
::Style* oldStyle = fStyle;
#else
delete fStyle;
#endif
fStyle = style;
#ifdef ICON_O_MATIC
if (fStyle) {
fStyle->Acquire();
fStyle->AddObserver(this);
}
_NotifyStyleChanged(oldStyle, fStyle);
#endif
}
// #pragma mark -
// Bounds
BRect
Shape::Bounds(bool updateLast) const
{
// TODO: what about sub-paths?!?
// the problem is that the path ids are
// nowhere stored while converting VectorPath
// to agg::path_storage, but it is also unclear
// if those would mean anything later on in
// the Transformer pipeline
uint32 pathID[1];
pathID[0] = 0;
double left, top, right, bottom;
::VertexSource& source = const_cast<Shape*>(this)->VertexSource();
agg::conv_transform< ::VertexSource, Transformable>
transformedSource(source, *this);
agg::bounding_rect(transformedSource, pathID, 0, 1,
&left, &top, &right, &bottom);
BRect bounds(left, top, right, bottom);
if (updateLast)
fLastBounds = bounds;
return bounds;
}
// VertexSource
::VertexSource&
Shape::VertexSource()
{
::VertexSource* source = &fPathSource;
int32 count = fTransformers.CountItems();
for (int32 i = 0; i < count; i++) {
Transformer* t = (Transformer*)fTransformers.ItemAtFast(i);
t->SetSource(*source);
source = t;
}
if (fNeedsUpdate) {
fPathSource.Update(source->WantsOpenPaths(),
source->ApproximationScale());
fNeedsUpdate = false;
}
return *source;
}
// AddTransformer
bool
Shape::AddTransformer(Transformer* transformer)
{
return AddTransformer(transformer, CountTransformers());
}
// AddTransformer
bool
Shape::AddTransformer(Transformer* transformer, int32 index)
{
if (!transformer)
return false;
if (!fTransformers.AddItem((void*)transformer, index))
return false;
#ifdef ICON_O_MATIC
transformer->AddObserver(this);
_NotifyTransformerAdded(transformer, index);
#endif
return true;
}
// RemoveTransformer
bool
Shape::RemoveTransformer(Transformer* transformer)
{
if (fTransformers.RemoveItem((void*)transformer)) {
#ifdef ICON_O_MATIC
transformer->RemoveObserver(this);
_NotifyTransformerRemoved(transformer);
#endif
return true;
}
return false;
}
// #pragma mark -
// CountShapes
int32
Shape::CountTransformers() const
{
return fTransformers.CountItems();
}
// HasTransformer
bool
Shape::HasTransformer(Transformer* transformer) const
{
return fTransformers.HasItem((void*)transformer);
}
// IndexOf
int32
Shape::IndexOf(Transformer* transformer) const
{
return fTransformers.IndexOf((void*)transformer);
}
// TransformerAt
Transformer*
Shape::TransformerAt(int32 index) const
{
return (Transformer*)fTransformers.ItemAt(index);
}
// TransformerAtFast
Transformer*
Shape::TransformerAtFast(int32 index) const
{
return (Transformer*)fTransformers.ItemAtFast(index);
}
// #pragma mark -
// SetHinting
void
Shape::SetHinting(bool hinting)
{
if (fHinting == hinting)
return;
fHinting = hinting;
Notify();
}
// SetMinVisibilityScale
void
Shape::SetMinVisibilityScale(float scale)
{
if (fMinVisibilityScale == scale)
return;
fMinVisibilityScale = scale;
Notify();
}
// SetMaxVisibilityScale
void
Shape::SetMaxVisibilityScale(float scale)
{
if (fMaxVisibilityScale == scale)
return;
fMaxVisibilityScale = scale;
Notify();
}
// #pragma mark -
#ifdef ICON_O_MATIC
// AddListener
bool
Shape::AddListener(ShapeListener* listener)
{
if (listener && !fListeners.HasItem((void*)listener))
return fListeners.AddItem((void*)listener);
return false;
}
// RemoveListener
bool
Shape::RemoveListener(ShapeListener* listener)
{
return fListeners.RemoveItem((void*)listener);
}
// #pragma mark -
// _NotifyTransformerAdded
void
Shape::_NotifyTransformerAdded(Transformer* transformer, int32 index) const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
ShapeListener* listener
= (ShapeListener*)listeners.ItemAtFast(i);
listener->TransformerAdded(transformer, index);
}
// TODO: merge Observable and ShapeListener interface
_NotifyRerender();
}
// _NotifyTransformerRemoved
void
Shape::_NotifyTransformerRemoved(Transformer* transformer) const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
ShapeListener* listener
= (ShapeListener*)listeners.ItemAtFast(i);
listener->TransformerRemoved(transformer);
}
// TODO: merge Observable and ShapeListener interface
_NotifyRerender();
}
// _NotifyStyleChanged
void
Shape::_NotifyStyleChanged(::Style* oldStyle, ::Style* newStyle) const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
ShapeListener* listener
= (ShapeListener*)listeners.ItemAtFast(i);
listener->StyleChanged(oldStyle, newStyle);
}
// TODO: merge Observable and ShapeListener interface
_NotifyRerender();
}
// _NotifyRerender
void
Shape::_NotifyRerender() const
{
fNeedsUpdate = true;
Notify();
}
#endif // ICON_O_MATIC
+162
View File
@@ -0,0 +1,162 @@
/*
* Copyright 2006, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef SHAPE_H
#define SHAPE_H
#include <List.h>
#include <Rect.h>
#ifdef ICON_O_MATIC
# include "IconObject.h"
# include "Observer.h"
#endif
#include "PathContainer.h"
#include "PathSource.h"
#include "Transformable.h"
#include "VectorPath.h"
class Style;
#ifdef ICON_O_MATIC
// TODO: merge Observer and ShapeListener interface
// ie add "AppearanceChanged(Shape* shape)"
class ShapeListener {
public:
ShapeListener();
virtual ~ShapeListener();
virtual void TransformerAdded(Transformer* t,
int32 index) = 0;
virtual void TransformerRemoved(Transformer* t) = 0;
virtual void StyleChanged(::Style* oldStyle,
::Style* newStyle) = 0;
};
#endif // ICON_O_MATIC
#ifdef ICON_O_MATIC
class Shape : public IconObject,
public Transformable,
public Observer, // observing all the paths and the style
public PathContainerListener,
public PathListener {
#else
class Shape : public Transformable {
#endif
public:
Shape(::Style* style);
Shape(const Shape& other);
virtual ~Shape();
#ifdef ICON_O_MATIC
// IconObject interface
virtual status_t Unarchive(const BMessage* archive);
virtual status_t Archive(BMessage* into,
bool deep = true) const;
virtual PropertyObject* MakePropertyObject() const;
virtual bool SetToPropertyObject(
const PropertyObject* object);
// Transformable interface
virtual void TransformationChanged();
// Observer interface
virtual void ObjectChanged(const Observable* object);
// PathContainerListener interface
virtual void PathAdded(VectorPath* path);
virtual void PathRemoved(VectorPath* path);
// PathListener interface
virtual void PointAdded(int32 index);
virtual void PointRemoved(int32 index);
virtual void PointChanged(int32 index);
virtual void PathChanged();
virtual void PathClosedChanged();
virtual void PathReversed();
#else
inline void Notify() {}
#endif // ICON_O_MATIC
// Shape
status_t InitCheck() const;
inline PathContainer* Paths() const
{ return fPaths; }
void SetStyle(::Style* style);
inline ::Style* Style() const
{ return fStyle; }
inline BRect LastBounds() const
{ return fLastBounds; }
BRect Bounds(bool updateLast = false) const;
::VertexSource& VertexSource();
bool AddTransformer(Transformer* transformer);
bool AddTransformer(Transformer* transformer,
int32 index);
bool RemoveTransformer(Transformer* transformer);
int32 CountTransformers() const;
bool HasTransformer(Transformer* transformer) const;
int32 IndexOf(Transformer* transformer) const;
Transformer* TransformerAt(int32 index) const;
Transformer* TransformerAtFast(int32 index) const;
void SetHinting(bool hinting);
bool Hinting() const
{ return fHinting; }
void SetMinVisibilityScale(float scale);
float MinVisibilityScale() const
{ return fMinVisibilityScale; }
void SetMaxVisibilityScale(float scale);
float MaxVisibilityScale() const
{ return fMaxVisibilityScale; }
#ifdef ICON_O_MATIC
bool AddListener(ShapeListener* listener);
bool RemoveListener(ShapeListener* listener);
private:
void _NotifyTransformerAdded(Transformer* t,
int32 index) const;
void _NotifyTransformerRemoved(Transformer* t) const;
void _NotifyStyleChanged(::Style* oldStyle,
::Style* newStyle) const;
void _NotifyRerender() const;
#endif // ICON_O_MATIC
private:
PathContainer* fPaths;
::Style* fStyle;
PathSource fPathSource;
BList fTransformers;
mutable bool fNeedsUpdate;
mutable BRect fLastBounds;
bool fHinting;
float fMinVisibilityScale;
float fMaxVisibilityScale;
#ifdef ICON_O_MATIC
BList fListeners;
#endif
};
#endif // SHAPE_H
+228
View File
@@ -0,0 +1,228 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "ShapeContainer.h"
#include <stdio.h>
#include <string.h>
#include <OS.h>
#include "Shape.h"
#ifdef ICON_O_MATIC
// constructor
ShapeContainerListener::ShapeContainerListener()
{
}
// destructor
ShapeContainerListener::~ShapeContainerListener()
{
}
#endif // ICON_O_MATIC
// constructor
ShapeContainer::ShapeContainer()
: fShapes(16)
#ifdef ICON_O_MATIC
, fListeners(2)
#endif
{
}
// destructor
ShapeContainer::~ShapeContainer()
{
#ifdef ICON_O_MATIC
int32 count = fListeners.CountItems();
if (count > 0) {
debugger("~ShapeContainer() - there are still"
"listeners attached\n");
}
#endif // ICON_O_MATIC
_MakeEmpty();
}
// #pragma mark -
// AddShape
bool
ShapeContainer::AddShape(Shape* shape)
{
return AddShape(shape, CountShapes());
}
// AddShape
bool
ShapeContainer::AddShape(Shape* shape, int32 index)
{
if (!shape)
return false;
// prevent adding the same shape twice
if (HasShape(shape))
return false;
if (fShapes.AddItem((void*)shape, index)) {
#ifdef ICON_O_MATIC
_NotifyShapeAdded(shape, index);
#endif
return true;
}
fprintf(stderr, "ShapeContainer::AddShape() - out of memory!\n");
return false;
}
// RemoveShape
bool
ShapeContainer::RemoveShape(Shape* shape)
{
if (fShapes.RemoveItem((void*)shape)) {
#ifdef ICON_O_MATIC
_NotifyShapeRemoved(shape);
#endif
return true;
}
return false;
}
// RemoveShape
Shape*
ShapeContainer::RemoveShape(int32 index)
{
Shape* shape = (Shape*)fShapes.RemoveItem(index);
#ifdef ICON_O_MATIC
if (shape) {
_NotifyShapeRemoved(shape);
}
#endif
return shape;
}
// MakeEmpty
void
ShapeContainer::MakeEmpty()
{
_MakeEmpty();
}
// #pragma mark -
// CountShapes
int32
ShapeContainer::CountShapes() const
{
return fShapes.CountItems();
}
// HasShape
bool
ShapeContainer::HasShape(Shape* shape) const
{
return fShapes.HasItem((void*)shape);
}
// IndexOf
int32
ShapeContainer::IndexOf(Shape* shape) const
{
return fShapes.IndexOf((void*)shape);
}
// ShapeAt
Shape*
ShapeContainer::ShapeAt(int32 index) const
{
return (Shape*)fShapes.ItemAt(index);
}
// ShapeAtFast
Shape*
ShapeContainer::ShapeAtFast(int32 index) const
{
return (Shape*)fShapes.ItemAtFast(index);
}
// #pragma mark -
#ifdef ICON_O_MATIC
// AddListener
bool
ShapeContainer::AddListener(ShapeContainerListener* listener)
{
if (listener && !fListeners.HasItem((void*)listener))
return fListeners.AddItem((void*)listener);
return false;
}
// RemoveListener
bool
ShapeContainer::RemoveListener(ShapeContainerListener* listener)
{
return fListeners.RemoveItem((void*)listener);
}
#endif // ICON_O_MATIC
// #pragma mark -
// _MakeEmpty
void
ShapeContainer::_MakeEmpty()
{
int32 count = CountShapes();
for (int32 i = 0; i < count; i++) {
Shape* shape = ShapeAtFast(i);
#ifdef ICON_O_MATIC
_NotifyShapeRemoved(shape);
shape->Release();
#else
delete shape;
#endif
}
fShapes.MakeEmpty();
}
// #pragma mark -
#ifdef ICON_O_MATIC
// _NotifyShapeAdded
void
ShapeContainer::_NotifyShapeAdded(Shape* shape, int32 index) const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
ShapeContainerListener* listener
= (ShapeContainerListener*)listeners.ItemAtFast(i);
listener->ShapeAdded(shape, index);
}
}
// _NotifyShapeRemoved
void
ShapeContainer::_NotifyShapeRemoved(Shape* shape) const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
ShapeContainerListener* listener
= (ShapeContainerListener*)listeners.ItemAtFast(i);
listener->ShapeRemoved(shape);
}
}
#endif // ICON_O_MATIC
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef SHAPE_CONTAINER_H
#define SHAPE_CONTAINER_H
#include <List.h>
class Shape;
#ifdef ICON_O_MATIC
class ShapeContainerListener {
public:
ShapeContainerListener();
virtual ~ShapeContainerListener();
virtual void ShapeAdded(Shape* shape, int32 index) = 0;
virtual void ShapeRemoved(Shape* shape) = 0;
};
#endif // ICON_O_MATIC
class ShapeContainer {
public:
ShapeContainer();
virtual ~ShapeContainer();
bool AddShape(Shape* shape);
bool AddShape(Shape* shape, int32 index);
bool RemoveShape(Shape* shape);
Shape* RemoveShape(int32 index);
void MakeEmpty();
int32 CountShapes() const;
bool HasShape(Shape* shape) const;
int32 IndexOf(Shape* shape) const;
Shape* ShapeAt(int32 index) const;
Shape* ShapeAtFast(int32 index) const;
private:
void _MakeEmpty();
BList fShapes;
#ifdef ICON_O_MATIC
public:
bool AddListener(ShapeContainerListener* listener);
bool RemoveListener(
ShapeContainerListener* listener);
private:
void _NotifyShapeAdded(Shape* shape,
int32 index) const;
void _NotifyShapeRemoved(Shape* shape) const;
BList fListeners;
#endif // ICON_O_MATIC
};
#endif // SHAPE_CONTAINER_H
File diff suppressed because it is too large Load Diff
+208
View File
@@ -0,0 +1,208 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef VECTOR_PATH_H
#define VECTOR_PATH_H
#include <Rect.h>
#include <String.h>
#include <agg_path_storage.h>
#ifdef ICON_O_MATIC
# include <Archivable.h>
# include <List.h>
# include "IconObject.h"
#endif // ICON_O_MATIC
class BBitmap;
class BMessage;
class BView;
struct control_point {
BPoint point; // actual point on path
BPoint point_in; // control point for incomming curve
BPoint point_out; // control point for outgoing curve
bool connected; // if all 3 points should be on one line
};
#ifdef ICON_O_MATIC
class PathListener {
public:
PathListener();
virtual ~PathListener();
virtual void PointAdded(int32 index) = 0;
virtual void PointRemoved(int32 index) = 0;
virtual void PointChanged(int32 index) = 0;
virtual void PathChanged() = 0;
virtual void PathClosedChanged() = 0;
virtual void PathReversed() = 0;
};
class VectorPath : public BArchivable,
public IconObject {
#else
class VectorPath {
#endif // ICON_O_MATIC
public:
class Iterator {
public:
Iterator() {}
virtual ~Iterator() {}
virtual void MoveTo(BPoint point) = 0;
virtual void LineTo(BPoint point) = 0;
};
VectorPath();
VectorPath(const VectorPath& from);
#ifdef ICON_O_MATIC
VectorPath(BMessage* archive);
#endif
virtual ~VectorPath();
#ifdef ICON_O_MATIC
// IconObject
virtual status_t Archive(BMessage* into,
bool deep = true) const;
virtual PropertyObject* MakePropertyObject() const;
virtual bool SetToPropertyObject(
const PropertyObject* object);
#else
inline void Notify() {}
#endif // ICON_O_MATIC
// VectorPath
VectorPath& operator=(const VectorPath& from);
// bool operator==(const VectorPath& frrom) const;
void MakeEmpty();
bool AddPoint(BPoint point);
bool AddPoint(const BPoint& point,
const BPoint& pointIn,
const BPoint& pointOut,
bool connected);
bool AddPoint(BPoint point, int32 index);
bool RemovePoint(int32 index);
// modify existing points position
bool SetPoint(int32 index, BPoint point);
bool SetPoint(int32 index, BPoint point,
BPoint pointIn,
BPoint pointOut,
bool connected);
bool SetPointIn(int32 index, BPoint point);
bool SetPointOut(int32 index, BPoint point,
bool mirrorDist = false);
bool SetInOutConnected(int32 index, bool connected);
// query existing points position
bool GetPointAt(int32 index, BPoint& point) const;
bool GetPointInAt(int32 index, BPoint& point) const;
bool GetPointOutAt(int32 index, BPoint& point) const;
bool GetPointsAt(int32 index,
BPoint& point,
BPoint& pointIn,
BPoint& pointOut,
bool* connected = NULL) const;
int32 CountPoints() const;
#ifdef ICON_O_MATIC
// iterates over curve segments and returns
// the distance and index of the point that
// started the segment that is closest
bool GetDistance(BPoint point,
float* distance, int32* index) const;
// at curve segment indicated by "index", this
// function looks for the closest point
// directly on the curve and returns a "scale"
// that indicates the distance on the curve
// between [0..1]
bool FindBezierScale(int32 index, BPoint point,
double* scale) const;
// this function can be used to get a point
// directly on the segment indicated by "index"
// "scale" is on [0..1] indicating the distance
// from the start of the segment to the end
bool GetPoint(int32 index, double scale,
BPoint& point) const;
#endif // ICON_O_MATIC
void SetClosed(bool closed);
bool IsClosed() const
{ return fClosed; }
BRect Bounds() const;
BRect ControlPointBounds() const;
void Iterate(Iterator* iterator,
float smoothScale = 1.0) const;
void CleanUp();
void Reverse();
void PrintToStream() const;
bool GetAGGPathStorage(agg::path_storage& path) const;
#ifdef ICON_O_MATIC
bool AddListener(PathListener* listener);
bool RemoveListener(PathListener* listener);
int32 CountListeners() const;
PathListener* ListenerAtFast(int32 index) const;
#endif // ICON_O_MATIC
private:
BRect _Bounds() const;
void _SetPoint(int32 index, BPoint point);
void _SetPoint(int32 index,
const BPoint& point,
const BPoint& pointIn,
const BPoint& pointOut,
bool connected);
bool _SetPointCount(int32 count);
#ifndef ICON_O_MATIC
inline void _NotifyPointAdded(int32 index) const {}
inline void _NotifyPointChanged(int32 index) const {}
inline void _NotifyPointRemoved(int32 index) const {}
inline void _NotifyPathChanged() const {}
inline void _NotifyClosedChanged() const {}
inline void _NotifyPathReversed() const {}
#else
void _NotifyPointAdded(int32 index) const;
void _NotifyPointChanged(int32 index) const;
void _NotifyPointRemoved(int32 index) const;
void _NotifyPathChanged() const;
void _NotifyClosedChanged() const;
void _NotifyPathReversed() const;
BList fListeners;
#endif // ICON_O_MATIC
control_point* fPath;
bool fClosed;
int32 fPointCount;
int32 fAllocCount;
mutable BRect fCachedBounds;
};
#endif // VECTOR_PATH_H
+638
View File
@@ -0,0 +1,638 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "Gradient.h"
#include <math.h>
#include <stdio.h>
#include <Message.h>
#ifdef ICON_O_MATIC
# include "support.h"
#endif
// constructor
color_step::color_step(const rgb_color c, float o)
{
color.red = c.red;
color.green = c.green;
color.blue = c.blue;
color.alpha = c.alpha;
offset = o;
}
// constructor
color_step::color_step(uint8 r, uint8 g, uint8 b, uint8 a, float o)
{
color.red = r;
color.green = g;
color.blue = b;
color.alpha = a;
offset = o;
}
// constructor
color_step::color_step(const color_step& other)
{
color.red = other.color.red;
color.green = other.color.green;
color.blue = other.color.blue;
color.alpha = other.color.alpha;
offset = other.offset;
}
// constructor
color_step::color_step()
{
color.red = 0;
color.green = 0;
color.blue = 0;
color.alpha = 255;
offset = 0;
}
// operator!=
bool
color_step::operator!=(const color_step& other) const
{
return color.red != other.color.red ||
color.green != other.color.green ||
color.blue != other.color.blue ||
color.alpha != other.color.alpha ||
offset != other.offset;
}
// #pragma mark -
// constructor
Gradient::Gradient(bool empty)
#ifdef ICON_O_MATIC
: BArchivable(),
Observable(),
Transformable(),
#else
: Transformable(),
#endif
fColors(4),
fType(GRADIENT_LINEAR),
fInterpolation(INTERPOLATION_SMOOTH),
fInheritTransformation(true)
{
if (!empty) {
AddColor(color_step(0, 0, 0, 255, 0.0), 0);
AddColor(color_step(255, 255, 255, 255, 1.0), 1);
}
}
#ifdef ICON_O_MATIC
// constructor
Gradient::Gradient(BMessage* archive)
: BArchivable(archive),
Observable(),
Transformable(),
fColors(4),
fType(GRADIENT_LINEAR),
fInterpolation(INTERPOLATION_SMOOTH),
fInheritTransformation(true)
{
if (!archive)
return;
// read transformation
int32 size = Transformable::matrix_size;
const void* matrix;
ssize_t dataSize = size * sizeof(double);
if (archive->FindData("transformation", B_DOUBLE_TYPE,
&matrix, &dataSize) == B_OK
&& dataSize == (ssize_t)(size * sizeof(double)))
LoadFrom((const double*)matrix);
// color steps
color_step step;
for (int32 i = 0; archive->FindFloat("offset", i, &step.offset) >= B_OK; i++) {
if (archive->FindInt32("color", i, (int32*)&step.color) >= B_OK)
AddColor(step, i);
else
break;
}
if (archive->FindInt32("type", (int32*)&fType) < B_OK)
fType = GRADIENT_LINEAR;
if (archive->FindInt32("interpolation", (int32*)&fInterpolation) < B_OK)
fInterpolation = INTERPOLATION_SMOOTH;
if (archive->FindBool("inherit transformation",
&fInheritTransformation) < B_OK)
fInheritTransformation = true;
}
#endif // ICON_O_MATIC
// constructor
Gradient::Gradient(const Gradient& other)
#ifdef ICON_O_MATIC
: BArchivable(other),
Observable(),
Transformable(other),
#else
: Transformable(other),
#endif
fColors(4),
fType(other.fType),
fInterpolation(other.fInterpolation),
fInheritTransformation(other.fInheritTransformation)
{
for (int32 i = 0; color_step* step = other.ColorAt(i); i++) {
AddColor(*step, i);
}
}
// destructor
Gradient::~Gradient()
{
_MakeEmpty();
}
#ifdef ICON_O_MATIC
// Archive
status_t
Gradient::Archive(BMessage* into, bool deep) const
{
status_t ret = BArchivable::Archive(into, deep);
// transformation
if (ret == B_OK) {
int32 size = Transformable::matrix_size;
double matrix[size];
StoreTo(matrix);
ret = into->AddData("transformation", B_DOUBLE_TYPE,
matrix, size * sizeof(double));
}
// color steps
if (ret >= B_OK) {
for (int32 i = 0; color_step* step = ColorAt(i); i++) {
ret = into->AddInt32("color", (const uint32&)step->color);
if (ret < B_OK)
break;
ret = into->AddFloat("offset", step->offset);
if (ret < B_OK)
break;
}
}
// gradient and interpolation type
if (ret >= B_OK)
ret = into->AddInt32("type", (int32)fType);
if (ret >= B_OK)
ret = into->AddInt32("interpolation", (int32)fInterpolation);
if (ret >= B_OK)
ret = into->AddBool("inherit transformation", fInheritTransformation);
// finish off
if (ret >= B_OK)
ret = into->AddString("class", "Gradient");
return ret;
}
#endif // ICON_O_MATIC
// #pragma mark -
// operator=
Gradient&
Gradient::operator=(const Gradient& other)
{
#ifdef ICON_O_MATIC
AutoNotificationSuspender _(this);
#endif
SetTransform(other);
SetColors(other);
SetType(other.fType);
SetInterpolation(other.fInterpolation);
SetInheritTransformation(other.fInheritTransformation);
return *this;
}
// operator==
bool
Gradient::operator==(const Gradient& other) const
{
if (Transformable::operator==(other)) {
int32 count = CountColors();
if (count == other.CountColors() &&
fType == other.fType &&
fInterpolation == other.fInterpolation &&
fInheritTransformation == other.fInheritTransformation) {
bool equal = true;
for (int32 i = 0; i < count; i++) {
color_step* ourStep = ColorAtFast(i);
color_step* otherStep = other.ColorAtFast(i);
if (*ourStep != *otherStep) {
equal = false;
break;
}
}
return equal;
}
}
return false;
}
// operator!=
bool
Gradient::operator!=(const Gradient& other) const
{
return !(*this == other);
}
// SetColors
void
Gradient::SetColors(const Gradient& other)
{
#ifdef ICON_O_MATIC
AutoNotificationSuspender _(this);
#endif
_MakeEmpty();
for (int32 i = 0; color_step* step = other.ColorAt(i); i++)
AddColor(*step, i);
Notify();
}
// #pragma mark -
// AddColor
int32
Gradient::AddColor(const rgb_color& color, float offset)
{
// find the correct index (sorted by offset)
color_step* step = new color_step(color, offset);
int32 index = 0;
int32 count = CountColors();
for (; index < count; index++) {
color_step* s = ColorAtFast(index);
if (s->offset > step->offset)
break;
}
if (!fColors.AddItem((void*)step, index)) {
delete step;
return -1;
}
Notify();
return index;
}
// AddColor
bool
Gradient::AddColor(const color_step& color, int32 index)
{
color_step* step = new color_step(color);
if (!fColors.AddItem((void*)step, index)) {
delete step;
return false;
}
Notify();
return true;
}
// RemoveColor
bool
Gradient::RemoveColor(int32 index)
{
color_step* step = (color_step*)fColors.RemoveItem(index);
if (!step) {
return false;
}
delete step;
Notify();
return true;
}
// #pragma mark -
// SetColor
bool
Gradient::SetColor(int32 index, const color_step& color)
{
if (color_step* step = ColorAt(index)) {
if (*step != color) {
step->color = color.color;
step->offset = color.offset;
Notify();
return true;
}
}
return false;
}
// SetColor
bool
Gradient::SetColor(int32 index, const rgb_color& color)
{
if (color_step* step = ColorAt(index)) {
if ((uint32&)step->color != (uint32&)color) {
step->color = color;
Notify();
return true;
}
}
return false;
}
// SetOffset
bool
Gradient::SetOffset(int32 index, float offset)
{
color_step* step = ColorAt(index);
if (step && step->offset != offset) {
step->offset = offset;
Notify();
return true;
}
return false;
}
// #pragma mark -
// CountColors
int32
Gradient::CountColors() const
{
return fColors.CountItems();
}
// ColorAt
color_step*
Gradient::ColorAt(int32 index) const
{
return (color_step*)fColors.ItemAt(index);
}
// ColorAtFast
color_step*
Gradient::ColorAtFast(int32 index) const
{
return (color_step*)fColors.ItemAtFast(index);
}
// #pragma mark -
// SetType
void
Gradient::SetType(gradient_type type)
{
if (fType != type) {
fType = type;
Notify();
}
}
// SetInterpolation
void
Gradient::SetInterpolation(interpolation_type type)
{
if (fInterpolation != type) {
fInterpolation = type;
Notify();
}
}
// SetInheritTransformation
void
Gradient::SetInheritTransformation(bool inherit)
{
if (fInheritTransformation != inherit) {
fInheritTransformation = inherit;
Notify();
}
}
// #pragma mark -
// gauss
inline double
gauss(double f)
{
// this aint' a real gauss function
if (f > 0.0) {
if (f < 0.5)
return (1.0 - 2.0 * f*f);
f = 1.0 - f;
return (2.0 * f*f);
}
return 1.0;
}
// MakeGradient
void
Gradient::MakeGradient(uint32* colors, int32 count) const
{
color_step* from = ColorAt(0);
if (!from)
return;
// find the step with the lowest offset
for (int32 i = 0; color_step* step = ColorAt(i); i++) {
if (step->offset < from->offset)
from = step;
}
// current index into "colors" array
int32 index = (int32)floorf(count * from->offset + 0.5);
if (index < 0)
index = 0;
if (index > count)
index = count;
// make sure we fill the entire array
if (index > 0) {
uint8* c = (uint8*)&colors[0];
for (int32 i = 0; i < index; i++) {
c[0] = from->color.red;
c[1] = from->color.green;
c[2] = from->color.blue;
c[3] = from->color.alpha;
c += 4;
}
}
// put all steps that we need to interpolate to into a list
BList nextSteps(fColors.CountItems() - 1);
for (int32 i = 0; color_step* step = ColorAt(i); i++) {
if (step != from)
nextSteps.AddItem((void*)step);
}
// interpolate "from" to "to"
while (!nextSteps.IsEmpty()) {
// find the step with the next offset
color_step* to = NULL;
float nextOffsetDist = 2.0;
for (int32 i = 0; color_step* step = (color_step*)nextSteps.ItemAt(i); i++) {
float d = step->offset - from->offset;
if (d < nextOffsetDist && d >= 0) {
to = step;
nextOffsetDist = d;
}
}
if (!to)
break;
nextSteps.RemoveItem((void*)to);
// interpolate
int32 offset = (int32)floorf((count - 1) * to->offset + 0.5);
if (offset >= count)
offset = count - 1;
int32 dist = offset - index;
if (dist >= 0) {
uint8* c = (uint8*)&colors[index];
#if GAMMA_BLEND
uint16 fromRed = kGammaTable[from->color.red];
uint16 fromGreen = kGammaTable[from->color.green];
uint16 fromBlue = kGammaTable[from->color.blue];
uint16 toRed = kGammaTable[to->color.red];
uint16 toGreen = kGammaTable[to->color.green];
uint16 toBlue = kGammaTable[to->color.blue];
for (int32 i = index; i <= offset; i++) {
float f = (float)(offset - i) / (float)(dist + 1);
if (fInterpolation == INTERPOLATION_SMOOTH)
f = gauss(1.0 - f);
float t = 1.0 - f;
c[0] = kInverseGammaTable[(uint16)floor(fromBlue * f + toBlue * t + 0.5)];
c[1] = kInverseGammaTable[(uint16)floor(fromGreen * f + toGreen * t + 0.5)];
c[2] = kInverseGammaTable[(uint16)floor(fromRed * f + toRed * t + 0.5)];
c[3] = (uint8)floor(from->color.alpha * f + to->color.alpha * t + 0.5);
c += 4;
}
#else // GAMMA_BLEND
for (int32 i = index; i <= offset; i++) {
float f = (float)(offset - i) / (float)(dist + 1);
if (fInterpolation == INTERPOLATION_SMOOTH)
f = gauss(1.0 - f);
float t = 1.0 - f;
c[0] = (uint8)floor(from->color.red * f + to->color.red * t + 0.5);
c[1] = (uint8)floor(from->color.green * f + to->color.green * t + 0.5);
c[2] = (uint8)floor(from->color.blue * f + to->color.blue * t + 0.5);
c[3] = (uint8)floor(from->color.alpha * f + to->color.alpha * t + 0.5);
c += 4;
}
#endif // GAMMA_BLEND
}
index = offset + 1;
// the current "to" will be the "from" in the next interpolation
from = to;
}
// make sure we fill the entire array
if (index < count) {
uint8* c = (uint8*)&colors[index];
for (int32 i = index; i < count; i++) {
c[0] = from->color.red;
c[1] = from->color.green;
c[2] = from->color.blue;
c[3] = from->color.alpha;
c += 4;
}
}
}
// string_for_type
static const char*
string_for_type(gradient_type type)
{
switch (type) {
case GRADIENT_LINEAR:
return "GRADIENT_LINEAR";
case GRADIENT_CIRCULAR:
return "GRADIENT_CIRCULAR";
case GRADIENT_DIAMONT:
return "GRADIENT_DIAMONT";
case GRADIENT_CONIC:
return "GRADIENT_CONIC";
case GRADIENT_XY:
return "GRADIENT_XY";
case GRADIENT_SQRT_XY:
return "GRADIENT_SQRT_XY";
}
return "<unkown>";
}
//string_for_interpolation
static const char*
string_for_interpolation(interpolation_type type)
{
switch (type) {
case INTERPOLATION_LINEAR:
return "INTERPOLATION_LINEAR";
case INTERPOLATION_SMOOTH:
return "INTERPOLATION_SMOOTH";
}
return "<unkown>";
}
// GradientArea
BRect
Gradient::GradientArea() const
{
BRect area(0, 0, 63, 63);
switch (fType) {
case GRADIENT_LINEAR:
case GRADIENT_CIRCULAR:
case GRADIENT_DIAMONT:
case GRADIENT_CONIC:
case GRADIENT_XY:
case GRADIENT_SQRT_XY:
break;
}
return area;
}
// TransformationChanged()
void
Gradient::TransformationChanged()
{
Notify();
}
// PrintToStream
void
Gradient::PrintToStream() const
{
printf("Gradient: type: %s, interpolation: %s, inherits transform: %d\n",
string_for_type(fType),
string_for_interpolation(fInterpolation),
fInheritTransformation);
for (int32 i = 0; color_step* step = ColorAt(i); i++) {
printf(" %ld: offset: %.1f -> color(%d, %d, %d, %d)\n",
i, step->offset,
step->color.red,
step->color.green,
step->color.blue,
step->color.alpha);
}
}
// _MakeEmpty
void
Gradient::_MakeEmpty()
{
int32 count = CountColors();
for (int32 i = 0; i < count; i++)
delete ColorAtFast(i);
fColors.MakeEmpty();
}
+124
View File
@@ -0,0 +1,124 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef GRADIENT_H
#define GRADIENT_H
#include <GraphicsDefs.h>
#include <List.h>
#ifdef ICON_O_MATIC
# include <Archivable.h>
# include "Observable.h"
#endif ICON_O_MATIC
#include "Transformable.h"
class BMessage;
enum gradient_type {
GRADIENT_LINEAR = 0,
GRADIENT_CIRCULAR,
GRADIENT_DIAMONT,
GRADIENT_CONIC,
GRADIENT_XY,
GRADIENT_SQRT_XY,
};
enum interpolation_type {
INTERPOLATION_LINEAR = 0,
INTERPOLATION_SMOOTH,
};
struct color_step {
color_step(const rgb_color c, float o);
color_step(uint8 r, uint8 g, uint8 b, uint8 a, float o);
color_step(const color_step& other);
color_step();
bool operator!=(const color_step& other) const;
rgb_color color;
float offset;
};
#ifdef ICON_O_MATIC
class Gradient : public BArchivable,
public Observable,
public Transformable {
#else
class Gradient : public Transformable {
#endif
public:
Gradient(bool empty = false);
#ifdef ICON_O_MATIC
Gradient(BMessage* archive);
#endif
Gradient(const Gradient& other);
virtual ~Gradient();
#ifdef ICON_O_MATIC
status_t Archive(BMessage* into, bool deep = true) const;
#else
inline void Notify() {}
#endif
Gradient& operator=(const Gradient& other);
bool operator==(const Gradient& other) const;
bool operator!=(const Gradient& other) const;
void SetColors(const Gradient& other);
int32 AddColor(const rgb_color& color, float offset);
bool AddColor(const color_step& color, int32 index);
bool RemoveColor(int32 index);
bool SetColor(int32 index, const color_step& step);
bool SetColor(int32 index, const rgb_color& color);
bool SetOffset(int32 index, float offset);
int32 CountColors() const;
color_step* ColorAt(int32 index) const;
color_step* ColorAtFast(int32 index) const;
void SetType(gradient_type type);
gradient_type Type() const
{ return fType; }
void SetInterpolation(interpolation_type type);
interpolation_type Interpolation() const
{ return fInterpolation; }
void SetInheritTransformation(bool inherit);
bool InheritTransformation() const
{ return fInheritTransformation; }
void MakeGradient(uint32* colors,
int32 count) const;
BRect GradientArea() const;
virtual void TransformationChanged();
void PrintToStream() const;
private:
void _MakeEmpty();
BList fColors;
gradient_type fType;
interpolation_type fInterpolation;
bool fInheritTransformation;
};
#endif // GRADIENT_H
+220
View File
@@ -0,0 +1,220 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "Style.h"
#include <new>
#ifdef ICON_O_MATIC
# include <Message.h>
# include "ui_defines.h"
#else
# define kWhite (rgb_color){ 255, 255, 255, 255 }
#endif // ICON_O_MATIC
#include "Gradient.h"
using std::nothrow;
// constructor
Style::Style()
#ifdef ICON_O_MATIC
: IconObject("<style>"),
Observer(),
#else
:
#endif
fColor(kWhite),
fGradient(NULL),
fColors(NULL),
fGammaCorrectedColors(NULL),
fGammaCorrectedColorsValid(false)
{
}
// constructor
Style::Style(const rgb_color& color)
#ifdef ICON_O_MATIC
: IconObject("<style>"),
Observer(),
#else
:
#endif
fColor(color),
fGradient(NULL),
fColors(NULL),
fGammaCorrectedColors(NULL),
fGammaCorrectedColorsValid(false)
{
}
// constructor
Style::Style(const Style& other)
#ifdef ICON_O_MATIC
: IconObject(other),
Observer(),
#else
:
#endif
fColor(other.fColor),
fGradient(NULL),
fColors(NULL),
fGammaCorrectedColors(NULL),
fGammaCorrectedColorsValid(false)
{
SetGradient(other.fGradient);
}
#ifdef ICON_O_MATIC
// constructor
Style::Style(BMessage* archive)
: IconObject(archive),
Observer(),
fColor(kWhite),
fGradient(NULL),
fColors(NULL),
fGammaCorrectedColors(NULL),
fGammaCorrectedColorsValid(false)
{
if (!archive)
return;
if (archive->FindInt32("color", (int32*)&fColor) < B_OK)
fColor = kWhite;
BMessage gradientArchive;
if (archive->FindMessage("gradient", &gradientArchive) == B_OK) {
::Gradient gradient(&gradientArchive);
SetGradient(&gradient);
}
}
#endif // ICON_O_MATIC
// destructor
Style::~Style()
{
SetGradient(NULL);
}
#ifdef ICON_O_MATIC
// ObjectChanged
void
Style::ObjectChanged(const Observable* object)
{
if (object == fGradient && fColors) {
fGradient->MakeGradient((uint32*)fColors, 256);
fGammaCorrectedColorsValid = false;
Notify();
}
}
// #pragma mark -
// Archive
status_t
Style::Archive(BMessage* into, bool deep) const
{
status_t ret = IconObject::Archive(into, deep);
if (ret == B_OK)
ret = into->AddInt32("color", (uint32&)fColor);
if (ret == B_OK && fGradient) {
BMessage gradientArchive;
ret = fGradient->Archive(&gradientArchive, deep);
if (ret == B_OK)
ret = into->AddMessage("gradient", &gradientArchive);
}
return ret;
}
#endif // ICON_O_MATIC
// SetColor
void
Style::SetColor(const rgb_color& color)
{
if ((uint32&)fColor == (uint32&)color)
return;
fColor = color;
Notify();
}
// SetGradient
void
Style::SetGradient(const ::Gradient* gradient)
{
if (!fGradient && !gradient)
return;
if (gradient) {
if (!fGradient) {
fGradient = new (nothrow) ::Gradient(*gradient);
if (fGradient) {
#ifdef ICON_O_MATIC
fGradient->AddObserver(this);
#endif
// generate gradient
fColors = new agg::rgba8[256];
fGradient->MakeGradient((uint32*)fColors, 256);
fGammaCorrectedColorsValid = false;
Notify();
}
} else {
if (*fGradient != *gradient) {
*fGradient = *gradient;
}
}
} else {
#ifdef ICON_O_MATIC
fGradient->RemoveObserver(this);
#endif
delete[] fColors;
delete[] fGammaCorrectedColors;
fColors = NULL;
fGammaCorrectedColors = NULL;
fGradient = NULL;
Notify();
}
}
// GammaCorrectedColors
const agg::rgba8*
Style::GammaCorrectedColors(const GammaTable& table) const
{
if (!fColors)
return NULL;
if (!fGammaCorrectedColors)
fGammaCorrectedColors = new agg::rgba8[256];
if (!fGammaCorrectedColorsValid) {
for (int32 i = 0; i < 256; i++) {
fGammaCorrectedColors[i].r = table.dir(fColors[i].r);
fGammaCorrectedColors[i].g = table.dir(fColors[i].g);
fGammaCorrectedColors[i].b = table.dir(fColors[i].b);
fGammaCorrectedColors[i].a = fColors[i].a;
fGammaCorrectedColors[i].premultiply();
}
fGammaCorrectedColorsValid = true;
}
return fGammaCorrectedColors;
}
+78
View File
@@ -0,0 +1,78 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef STYLE_H
#define STYLE_H
#include <GraphicsDefs.h>
#include <agg_color_rgba.h>
#ifdef ICON_O_MATIC
# include "IconObject.h"
# include "Observer.h"
#endif
#include "IconRenderer.h"
// TODO: put GammaTable into its own file
class Gradient;
#ifdef ICON_O_MATIC
class Style : public IconObject,
public Observer {
#else
class Style {
#endif
public:
Style();
Style(const Style& other);
Style(const rgb_color& color);
#ifdef ICON_O_MATIC
Style(BMessage* archive);
#endif
virtual ~Style();
#ifdef ICON_O_MATIC
// Observer interface
virtual void ObjectChanged(const Observable* object);
// Style
status_t Archive(BMessage* into,
bool deep = true) const;
#else
inline void Notify() {}
#endif // ICON_O_MATIC
void SetColor(const rgb_color& color);
inline rgb_color Color() const
{ return fColor; }
void SetGradient(const ::Gradient* gradient);
::Gradient* Gradient() const
{ return fGradient; }
const agg::rgba8* Colors() const
{ return fColors; }
const agg::rgba8* GammaCorrectedColors(
const GammaTable& table) const;
private:
rgb_color fColor;
::Gradient* fGradient;
// hold gradient color array
agg::rgba8* fColors;
// for caching gamma corrected gradient color array
mutable agg::rgba8* fGammaCorrectedColors;
mutable bool fGammaCorrectedColorsValid;
};
#endif // STYLE_H
+215
View File
@@ -0,0 +1,215 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "StyleContainer.h"
#include <stdio.h>
#include <string.h>
#include <OS.h>
#include "Style.h"
#ifdef ICON_O_MATIC
StyleContainerListener::StyleContainerListener() {}
StyleContainerListener::~StyleContainerListener() {}
#endif
// constructor
StyleContainer::StyleContainer()
#ifdef ICON_O_MATIC
: fStyles(32),
fListeners(2)
#else
: fStyles(32)
#endif
{
}
// destructor
StyleContainer::~StyleContainer()
{
#ifdef ICON_O_MATIC
int32 count = fListeners.CountItems();
if (count > 0) {
debugger("~StyleContainer() - there are still"
"listeners attached\n");
}
#endif // ICON_O_MATIC
_MakeEmpty();
}
// #pragma mark -
// AddStyle
bool
StyleContainer::AddStyle(Style* style)
{
if (!style)
return false;
// prevent adding the same style twice
if (HasStyle(style))
return false;
if (fStyles.AddItem((void*)style)) {
#ifdef ICON_O_MATIC
_NotifyStyleAdded(style);
#endif
return true;
}
fprintf(stderr, "StyleContainer::AddStyle() - out of memory!\n");
return false;
}
// RemoveStyle
bool
StyleContainer::RemoveStyle(Style* style)
{
if (fStyles.RemoveItem((void*)style)) {
#ifdef ICON_O_MATIC
_NotifyStyleRemoved(style);
#endif
return true;
}
return false;
}
// RemoveStyle
Style*
StyleContainer::RemoveStyle(int32 index)
{
Style* style = (Style*)fStyles.RemoveItem(index);
if (style) {
#ifdef ICON_O_MATIC
_NotifyStyleRemoved(style);
#endif
}
return style;
}
// MakeEmpty
void
StyleContainer::MakeEmpty()
{
_MakeEmpty();
}
// #pragma mark -
// CountStyles
int32
StyleContainer::CountStyles() const
{
return fStyles.CountItems();
}
// HasStyle
bool
StyleContainer::HasStyle(Style* style) const
{
return fStyles.HasItem((void*)style);
}
// IndexOf
int32
StyleContainer::IndexOf(Style* style) const
{
return fStyles.IndexOf((void*)style);
}
// StyleAt
Style*
StyleContainer::StyleAt(int32 index) const
{
return (Style*)fStyles.ItemAt(index);
}
// StyleAtFast
Style*
StyleContainer::StyleAtFast(int32 index) const
{
return (Style*)fStyles.ItemAtFast(index);
}
// #pragma mark -
#ifdef ICON_O_MATIC
// AddListener
bool
StyleContainer::AddListener(StyleContainerListener* listener)
{
if (listener && !fListeners.HasItem((void*)listener))
return fListeners.AddItem(listener);
return false;
}
// RemoveListener
bool
StyleContainer::RemoveListener(StyleContainerListener* listener)
{
return fListeners.RemoveItem(listener);
}
#endif // ICON_O_MATIC
// #pragma mark -
// _MakeEmpty
void
StyleContainer::_MakeEmpty()
{
int32 count = CountStyles();
for (int32 i = 0; i < count; i++) {
Style* style = StyleAtFast(i);
#ifdef ICON_O_MATIC
_NotifyStyleRemoved(style);
style->Release();
#else
delete style;
#endif
}
fStyles.MakeEmpty();
}
// #pragma mark -
#ifdef ICON_O_MATIC
// _NotifyStyleAdded
void
StyleContainer::_NotifyStyleAdded(Style* style) const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
StyleContainerListener* listener
= (StyleContainerListener*)listeners.ItemAtFast(i);
listener->StyleAdded(style);
}
}
// _NotifyStyleRemoved
void
StyleContainer::_NotifyStyleRemoved(Style* style) const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
StyleContainerListener* listener
= (StyleContainerListener*)listeners.ItemAtFast(i);
listener->StyleRemoved(style);
}
}
#endif // ICON_O_MATIC
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef STYLE_MANAGER_H
#define STYLE_MANAGER_H
#include <List.h>
class Style;
#ifdef ICON_O_MATIC
class StyleContainerListener {
public:
StyleContainerListener();
virtual ~StyleContainerListener();
virtual void StyleAdded(Style* style) = 0;
virtual void StyleRemoved(Style* style) = 0;
};
#endif // ICON_O_MATIC
class StyleContainer {
public:
StyleContainer();
virtual ~StyleContainer();
bool AddStyle(Style* style);
bool RemoveStyle(Style* style);
Style* RemoveStyle(int32 index);
void MakeEmpty();
int32 CountStyles() const;
bool HasStyle(Style* style) const;
int32 IndexOf(Style* style) const;
Style* StyleAt(int32 index) const;
Style* StyleAtFast(int32 index) const;
private:
BList fStyles;
void _MakeEmpty();
#ifdef ICON_O_MATIC
public:
bool AddListener(StyleContainerListener* listener);
bool RemoveListener(StyleContainerListener* listener);
private:
void _NotifyStyleAdded(Style* style) const;
void _NotifyStyleRemoved(Style* style) const;
BList fListeners;
#endif // ICON_O_MATIC
};
#endif // STYLE_MANAGER_H
@@ -0,0 +1,315 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "Transformable.h"
#include <stdio.h>
#include <string.h>
// constructor
Transformable::Transformable()
: agg::trans_affine()
{
}
// copy constructor
Transformable::Transformable(const Transformable& other)
: agg::trans_affine(other)
{
}
// destructor
Transformable::~Transformable()
{
}
// StoreTo
void
Transformable::StoreTo(double matrix[matrix_size]) const
{
store_to(matrix);
}
// LoadFrom
void
Transformable::LoadFrom(const double matrix[matrix_size])
{
// before calling the potentially heavy TransformationChanged()
// hook function, make sure that the transformation
// really changed
Transformable t;
t.load_from(matrix);
if (*this != t) {
load_from(matrix);
TransformationChanged();
}
}
// SetTransform
void
Transformable::SetTransform(const Transformable& other)
{
if (*this != other) {
*this = other;
TransformationChanged();
}
}
// operator=
Transformable&
Transformable::operator=(const Transformable& other)
{
if (other != *this) {
reset();
multiply(other);
TransformationChanged();
}
return *this;
}
// Multiply
Transformable&
Transformable::Multiply(const Transformable& other)
{
if (!other.IsIdentity()) {
multiply(other);
TransformationChanged();
}
return *this;
}
// Reset
void
Transformable::Reset()
{
reset();
}
// Invert
void
Transformable::Invert()
{
invert();
}
// IsIdentity
bool
Transformable::IsIdentity() const
{
double m[matrix_size];
store_to(m);
if (m[0] == 1.0 &&
m[1] == 0.0 &&
m[2] == 0.0 &&
m[3] == 1.0 &&
m[4] == 0.0 &&
m[5] == 0.0)
return true;
return false;
}
// IsTranslationOnly
bool
Transformable::IsTranslationOnly() const
{
double m[matrix_size];
store_to(m);
if (m[0] == 1.0 &&
m[1] == 0.0 &&
m[2] == 0.0 &&
m[3] == 1.0)
return true;
return false;
}
// IsNotDistorted
bool
Transformable::IsNotDistorted() const
{
double m[matrix_size];
store_to(m);
return (m[0] == m[3]);
}
// IsValid
bool
Transformable::IsValid() const
{
double m[matrix_size];
store_to(m);
return ((m[0] * m[3] - m[1] * m[2]) != 0.0);
}
// operator==
bool
Transformable::operator==(const Transformable& other) const
{
double m1[matrix_size];
other.store_to(m1);
double m2[matrix_size];
store_to(m2);
return memcmp(m1, m2, sizeof(m1)) == 0;
}
// operator!=
bool
Transformable::operator!=(const Transformable& other) const
{
return !(*this == other);
}
// Transform
void
Transformable::Transform(double* x, double* y) const
{
transform(x, y);
}
// Transform
void
Transformable::Transform(BPoint* point) const
{
if (point) {
double x = point->x;
double y = point->y;
transform(&x, &y);
point->x = x;
point->y = y;
}
}
// Transform
BPoint
Transformable::Transform(const BPoint& point) const
{
BPoint p(point);
Transform(&p);
return p;
}
// InverseTransform
void
Transformable::InverseTransform(double* x, double* y) const
{
inverse_transform(x, y);
}
// InverseTransform
void
Transformable::InverseTransform(BPoint* point) const
{
if (point) {
double x = point->x;
double y = point->y;
inverse_transform(&x, &y);
point->x = x;
point->y = y;
}
}
// InverseTransform
BPoint
Transformable::InverseTransform(const BPoint& point) const
{
BPoint p(point);
InverseTransform(&p);
return p;
}
inline float
min4(float a, float b, float c, float d)
{
return min_c(a, min_c(b, min_c(c, d)));
}
inline float
max4(float a, float b, float c, float d)
{
return max_c(a, max_c(b, max_c(c, d)));
}
// TransformBounds
BRect
Transformable::TransformBounds(BRect bounds) const
{
if (bounds.IsValid()) {
BPoint lt(bounds.left, bounds.top);
BPoint rt(bounds.right, bounds.top);
BPoint lb(bounds.left, bounds.bottom);
BPoint rb(bounds.right, bounds.bottom);
Transform(&lt);
Transform(&rt);
Transform(&lb);
Transform(&rb);
return BRect(floorf(min4(lt.x, rt.x, lb.x, rb.x)),
floorf(min4(lt.y, rt.y, lb.y, rb.y)),
ceilf(max4(lt.x, rt.x, lb.x, rb.x)),
ceilf(max4(lt.y, rt.y, lb.y, rb.y)));
}
return bounds;
}
// TranslateBy
void
Transformable::TranslateBy(BPoint offset)
{
if (offset.x != 0.0 || offset.y != 0.0) {
multiply(agg::trans_affine_translation(offset.x, offset.y));
TransformationChanged();
}
}
// RotateBy
void
Transformable::RotateBy(BPoint origin, double degrees)
{
if (degrees != 0.0) {
multiply(agg::trans_affine_translation(-origin.x, -origin.y));
multiply(agg::trans_affine_rotation(degrees * (PI / 180.0)));
multiply(agg::trans_affine_translation(origin.x, origin.y));
TransformationChanged();
}
}
// ScaleBy
void
Transformable::ScaleBy(BPoint origin, double xScale, double yScale)
{
if (xScale != 1.0 || yScale != 1.0) {
multiply(agg::trans_affine_translation(-origin.x, -origin.y));
multiply(agg::trans_affine_scaling(xScale, yScale));
multiply(agg::trans_affine_translation(origin.x, origin.y));
TransformationChanged();
}
}
// ShearBy
void
Transformable::ShearBy(BPoint origin, double xShear, double yShear)
{
if (xShear != 0.0 || yShear != 0.0) {
multiply(agg::trans_affine_translation(-origin.x, -origin.y));
multiply(agg::trans_affine_skewing(xShear, yShear));
multiply(agg::trans_affine_translation(origin.x, origin.y));
TransformationChanged();
}
}
// TransformationChanged
void
Transformable::TransformationChanged()
{
// default implementation doesn't care
}
@@ -0,0 +1,70 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef TRANSFORMABLE_H
#define TRANSFORMABLE_H
#include <Rect.h>
#include <agg_trans_affine.h>
class Transformable : public agg::trans_affine {
public:
enum {
matrix_size = 6,
};
Transformable();
Transformable(const Transformable& other);
virtual ~Transformable();
void StoreTo(double matrix[matrix_size]) const;
void LoadFrom(const double matrix[matrix_size]);
// set to or combine with other matrix
void SetTransform(const Transformable& other);
Transformable& operator=(const Transformable& other);
Transformable& Multiply(const Transformable& other);
virtual void Reset();
void Invert();
bool IsIdentity() const;
bool IsTranslationOnly() const;
bool IsNotDistorted() const;
bool IsValid() const;
bool operator==(const Transformable& other) const;
bool operator!=(const Transformable& other) const;
// transforms coordiantes
void Transform(double* x, double* y) const;
void Transform(BPoint* point) const;
BPoint Transform(const BPoint& point) const;
void InverseTransform(double* x, double* y) const;
void InverseTransform(BPoint* point) const;
BPoint InverseTransform(const BPoint& point) const;
// transforms the rectangle "bounds" and
// returns the *bounding box* of that
BRect TransformBounds(BRect bounds) const;
// some convenience functions
virtual void TranslateBy(BPoint offset);
virtual void RotateBy(BPoint origin, double degrees);
virtual void ScaleBy(BPoint origin, double xScale, double yScale);
virtual void ShearBy(BPoint origin, double xShear, double yShear);
virtual void TransformationChanged();
// hook function that is called when the transformation
// is changed for some reason
};
#endif // TRANSFORMABLE_H
@@ -0,0 +1,194 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "AffineTransformer.h"
#include <new>
#ifdef ICON_O_MATIC
# include <Message.h>
# include "CommonPropertyIDs.h"
# include "Property.h"
# include "PropertyObject.h"
#endif
using std::nothrow;
// constructor
AffineTransformer::AffineTransformer(VertexSource& source)
: Transformer(source, "Transformation"),
Affine(source, *this)
{
}
#ifdef ICON_O_MATIC
// constructor
AffineTransformer::AffineTransformer(VertexSource& source,
BMessage* archive)
: Transformer(source, archive),
Affine(source, *this)
{
if (!archive)
return;
int32 size = 6;
const void* matrix;
ssize_t dataSize = size * sizeof(double);
if (archive->FindData("matrix", B_DOUBLE_TYPE,
&matrix, &dataSize) == B_OK) {
if (dataSize == (ssize_t)(size * sizeof(double)))
load_from((const double*)matrix);
}
}
#endif // ICON_O_MATIC
// destructor
AffineTransformer::~AffineTransformer()
{
}
// Clone
Transformer*
AffineTransformer::Clone(VertexSource& source) const
{
AffineTransformer* clone = new (nothrow) AffineTransformer(source);
if (clone)
clone->multiply(*this);
return clone;
}
// rewind
void
AffineTransformer::rewind(unsigned path_id)
{
Affine::rewind(path_id);
}
// vertex
unsigned
AffineTransformer::vertex(double* x, double* y)
{
return Affine::vertex(x, y);
}
// SetSource
void
AffineTransformer::SetSource(VertexSource& source)
{
Transformer::SetSource(source);
Affine::attach(source);
}
// ApproximationScale
double
AffineTransformer::ApproximationScale() const
{
return fSource.ApproximationScale() * scale();
}
// #pragma mark -
#ifdef ICON_O_MATIC
// Archive
status_t
AffineTransformer::Archive(BMessage* into, bool deep) const
{
status_t ret = Transformer::Archive(into, deep);
if (ret == B_OK)
into->what = archive_code;
if (ret == B_OK) {
double matrix[6];
store_to(matrix);
ret = into->AddData("matrix", B_DOUBLE_TYPE,
matrix, 6 * sizeof(double));
}
return ret;
}
// MakePropertyObject
PropertyObject*
AffineTransformer::MakePropertyObject() const
{
PropertyObject* object = Transformer::MakePropertyObject();
if (!object)
return NULL;
// translation
double tx;
double ty;
translation(&tx, &ty);
object->AddProperty(new FloatProperty(PROPERTY_TRANSLATION_X, tx));
object->AddProperty(new FloatProperty(PROPERTY_TRANSLATION_Y, ty));
// rotation
object->AddProperty(new FloatProperty(PROPERTY_ROTATION,
agg::rad2deg(rotation())));
// scale
double scaleX;
double scaleY;
scaling(&scaleX, &scaleY);
object->AddProperty(new FloatProperty(PROPERTY_SCALE_X, scaleX));
object->AddProperty(new FloatProperty(PROPERTY_SCALE_Y, scaleY));
return object;
}
// SetToPropertyObject
bool
AffineTransformer::SetToPropertyObject(const PropertyObject* object)
{
AutoNotificationSuspender _(this);
Transformer::SetToPropertyObject(object);
// current affine parameters
double tx;
double ty;
translation(&tx, &ty);
double r = rotation();
double scaleX;
double scaleY;
scaling(&scaleX, &scaleY);
// properties
double newTX = object->Value(PROPERTY_TRANSLATION_X, (float)tx);
double newTY = object->Value(PROPERTY_TRANSLATION_Y, (float)ty);
double newR = object->Value(PROPERTY_ROTATION,
(float)agg::rad2deg(r));
newR = agg::deg2rad(newR);
double newScaleX = object->Value(PROPERTY_SCALE_X, (float)scaleX);
double newScaleY = object->Value(PROPERTY_SCALE_Y, (float)scaleY);
if (newTX != tx || newTY != ty
|| newR != r
|| newScaleX != scaleX
|| newScaleY != scaleY) {
reset();
multiply(agg::trans_affine_scaling(newScaleX, newScaleY));
multiply(agg::trans_affine_rotation(newR));
multiply(agg::trans_affine_translation(newTX, newTY));
Notify();
}
return HasPendingNotifications();
}
#endif // ICON_O_MATIC
@@ -0,0 +1,57 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef AFFINE_TRANSFORMER_H
#define AFFINE_TRANSFORMER_H
#include <agg_conv_transform.h>
#include <agg_trans_affine.h>
#include "Transformer.h"
typedef agg::conv_transform<VertexSource,
agg::trans_affine> Affine;
class AffineTransformer : public Transformer,
public Affine,
public agg::trans_affine {
public:
enum {
archive_code = 'affn',
};
AffineTransformer(
VertexSource& source);
#ifdef ICON_O_MATIC
AffineTransformer(
VertexSource& source,
BMessage* archive);
#endif
virtual ~AffineTransformer();
virtual Transformer* Clone(VertexSource& source) const;
virtual void rewind(unsigned path_id);
virtual unsigned vertex(double* x, double* y);
virtual void SetSource(VertexSource& source);
virtual double ApproximationScale() const;
#ifdef ICON_O_MATIC
// IconObject interface
virtual status_t Archive(BMessage* into,
bool deep = true) const;
virtual PropertyObject* MakePropertyObject() const;
virtual bool SetToPropertyObject(
const PropertyObject* object);
#endif
};
#endif // AFFINE_TRANSFORMER_H
@@ -0,0 +1,218 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "ContourTransformer.h"
#include <new>
#ifdef ICON_O_MATIC
# include <Message.h>
# include "CommonPropertyIDs.h"
# include "OptionProperty.h"
# include "Property.h"
# include "PropertyObject.h"
#endif // ICON_O_MATIC
using std::nothrow;
// constructor
ContourTransformer::ContourTransformer(VertexSource& source)
: Transformer(source, "Contour"),
Contour(source)
{
auto_detect_orientation(true);
}
#ifdef ICON_O_MATIC
// constructor
ContourTransformer::ContourTransformer(VertexSource& source,
BMessage* archive)
: Transformer(source, archive),
Contour(source)
{
auto_detect_orientation(true);
if (!archive)
return;
int32 mode;
if (archive->FindInt32("line join", &mode) == B_OK)
line_join((agg::line_join_e)mode);
if (archive->FindInt32("inner join", &mode) == B_OK)
inner_join((agg::inner_join_e)mode);
double value;
if (archive->FindDouble("width", &value) == B_OK)
width(value);
if (archive->FindDouble("miter limit", &value) == B_OK)
miter_limit(value);
if (archive->FindDouble("inner miter limit", &value) == B_OK)
inner_miter_limit(value);
}
#endif // ICON_O_MATIC
// destructor
ContourTransformer::~ContourTransformer()
{
}
// Clone
Transformer*
ContourTransformer::Clone(VertexSource& source) const
{
ContourTransformer* clone = new (nothrow) ContourTransformer(source);
if (clone) {
clone->line_join(line_join());
clone->inner_join(inner_join());
clone->width(width());
clone->miter_limit(miter_limit());
clone->inner_miter_limit(inner_miter_limit());
clone->auto_detect_orientation(auto_detect_orientation());
}
return clone;
}
// rewind
void
ContourTransformer::rewind(unsigned path_id)
{
Contour::rewind(path_id);
}
// vertex
unsigned
ContourTransformer::vertex(double* x, double* y)
{
return Contour::vertex(x, y);
}
// SetSource
void
ContourTransformer::SetSource(VertexSource& source)
{
Transformer::SetSource(source);
Contour::attach(source);
}
// ApproximationScale
double
ContourTransformer::ApproximationScale() const
{
return fSource.ApproximationScale() * width();
}
// #pragma mark -
#ifdef ICON_O_MATIC
// Archive
status_t
ContourTransformer::Archive(BMessage* into, bool deep) const
{
status_t ret = Transformer::Archive(into, deep);
if (ret == B_OK)
into->what = archive_code;
if (ret == B_OK)
ret = into->AddInt32("line join", line_join());
if (ret == B_OK)
ret = into->AddInt32("inner join", inner_join());
if (ret == B_OK)
ret = into->AddDouble("width", width());
if (ret == B_OK)
ret = into->AddDouble("miter limit", miter_limit());
if (ret == B_OK)
ret = into->AddDouble("inner miter limit", inner_miter_limit());
return ret;
}
// MakePropertyObject
PropertyObject*
ContourTransformer::MakePropertyObject() const
{
PropertyObject* object = Transformer::MakePropertyObject();
if (!object)
return NULL;
// width
object->AddProperty(new FloatProperty(PROPERTY_WIDTH, width()));
// auto detect orientation
object->AddProperty(new BoolProperty(PROPERTY_DETECT_ORIENTATION,
auto_detect_orientation()));
// join mode
OptionProperty* property = new OptionProperty(PROPERTY_JOIN_MODE);
property->AddOption(agg::miter_join, "Miter");
property->AddOption(agg::round_join, "Round");
property->AddOption(agg::bevel_join, "Bevel");
property->SetCurrentOptionID(line_join());
object->AddProperty(property);
// miter limit
object->AddProperty(new FloatProperty(PROPERTY_MITER_LIMIT,
miter_limit()));
return object;
}
// SetToPropertyObject
bool
ContourTransformer::SetToPropertyObject(const PropertyObject* object)
{
AutoNotificationSuspender _(this);
Transformer::SetToPropertyObject(object);
// width
float w = object->Value(PROPERTY_WIDTH, (float)width());
if (w != width()) {
width(w);
Notify();
}
// auto detect orientation
bool ado = object->Value(PROPERTY_DETECT_ORIENTATION,
auto_detect_orientation());
if (ado != auto_detect_orientation()) {
auto_detect_orientation(ado);
Notify();
}
// join mode
OptionProperty* property = dynamic_cast<OptionProperty*>(
object->FindProperty(PROPERTY_JOIN_MODE));
if (property && line_join() != property->CurrentOptionID()) {
line_join((agg::line_join_e)property->CurrentOptionID());
Notify();
}
// miter limit
float l = object->Value(PROPERTY_MITER_LIMIT, (float)miter_limit());
if (l != miter_limit()) {
miter_limit(l);
Notify();
}
return HasPendingNotifications();
}
#endif // ICON_O_MATIC
@@ -0,0 +1,54 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef CONTOUR_TRANSFORMER_H
#define CONTOUR_TRANSFORMER_H
#include <agg_conv_contour.h>
#include "Transformer.h"
typedef agg::conv_contour<VertexSource> Contour;
class ContourTransformer : public Transformer,
public Contour {
public:
enum {
archive_code = 'cntr',
};
ContourTransformer(
VertexSource& source);
#ifdef ICON_O_MATIC
ContourTransformer(
VertexSource& source,
BMessage* archive);
#endif
virtual ~ContourTransformer();
virtual Transformer* Clone(VertexSource& source) const;
virtual void rewind(unsigned path_id);
virtual unsigned vertex(double* x, double* y);
virtual void SetSource(VertexSource& source);
virtual double ApproximationScale() const;
#ifdef ICON_O_MATIC
// IconObject interface
virtual status_t Archive(BMessage* into,
bool deep = true) const;
virtual PropertyObject* MakePropertyObject() const;
virtual bool SetToPropertyObject(
const PropertyObject* object);
#endif
};
#endif // CONTOUR_TRANSFORMER_H
+73
View File
@@ -0,0 +1,73 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "PathSource.h"
#include "PathContainer.h"
#include "VectorPath.h"
// constructor
PathSource::PathSource(PathContainer* paths)
: VertexSource(),
fPaths(paths),
fAGGPath(),
fAGGCurvedPath(fAGGPath)
{
}
// destructor
PathSource::~PathSource()
{
}
// rewind
void
PathSource::rewind(unsigned path_id)
{
fAGGCurvedPath.rewind(path_id);
}
// vertex
unsigned
PathSource::vertex(double* x, double* y)
{
return fAGGCurvedPath.vertex(x, y);
}
// WantsOpenPaths
bool
PathSource::WantsOpenPaths() const
{
return false;
}
// ApproximationScale
double
PathSource::ApproximationScale() const
{
return 1.0;
}
// #pragma mark -
// Update
void
PathSource::Update(bool leavePathsOpen, double approximationScale)
{
fAGGPath.remove_all();
int32 count = fPaths->CountPaths();
for (int32 i = 0; i < count; i++) {
fPaths->PathAtFast(i)->GetAGGPathStorage(fAGGPath);
if (!leavePathsOpen)
fAGGPath.close_polygon();
}
fAGGCurvedPath.approximation_scale(approximationScale);
}
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef PATH_SOURCE_H
#define PATH_SOURCE_H
#include "Transformer.h"
#include "agg_path_storage.h"
#include "agg_conv_curve.h"
class PathContainer;
class VectorPath;
typedef agg::path_storage AGGPath;
typedef agg::conv_curve<AGGPath> AGGCurvedPath;
class PathSource : public VertexSource {
public:
PathSource(PathContainer* paths);
virtual ~PathSource();
virtual void rewind(unsigned path_id);
virtual unsigned vertex(double* x, double* y);
virtual bool WantsOpenPaths() const;
virtual double ApproximationScale() const;
// PathSource
void Update(bool leavePathsOpen,
double approximationScale);
private:
PathContainer* fPaths;
AGGPath fAGGPath;
AGGCurvedPath fAGGCurvedPath;
};
#endif // PATH_SOURCE_H
@@ -0,0 +1,106 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "PerspectiveTransformer.h"
#ifdef ICON_O_MATIC
# include <Message.h>
#endif
#include <new>
using std::nothrow;
// constructor
PerspectiveTransformer::PerspectiveTransformer(VertexSource& source)
: Transformer(source, "Perspective"),
Perspective(source, *this)
{
}
#ifdef ICON_O_MATIC
// constructor
PerspectiveTransformer::PerspectiveTransformer(VertexSource& source,
BMessage* archive)
: Transformer(source, archive),
Perspective(source, *this)
{
// TODO: upgrade AGG to be able to use load_from() etc
}
#endif
// destructor
PerspectiveTransformer::~PerspectiveTransformer()
{
}
// Clone
Transformer*
PerspectiveTransformer::Clone(VertexSource& source) const
{
PerspectiveTransformer* clone
= new (nothrow) PerspectiveTransformer(source);
if (clone) {
// TODO: upgrade AGG
// clone->multiply(*this);
}
return clone;
}
// rewind
void
PerspectiveTransformer::rewind(unsigned path_id)
{
Perspective::rewind(path_id);
}
// vertex
unsigned
PerspectiveTransformer::vertex(double* x, double* y)
{
return Perspective::vertex(x, y);
}
// SetSource
void
PerspectiveTransformer::SetSource(VertexSource& source)
{
Transformer::SetSource(source);
Perspective::attach(source);
}
// ApproximationScale
double
PerspectiveTransformer::ApproximationScale() const
{
// TODO: upgrade AGG
return fSource.ApproximationScale();// * scale();
}
// #pragma mark -
#ifdef ICON_O_MATIC
// Archive
status_t
PerspectiveTransformer::Archive(BMessage* into, bool deep) const
{
status_t ret = Transformer::Archive(into, deep);
if (ret == B_OK)
into->what = archive_code;
// TODO: upgrade AGG to be able to use store_to()
return ret;
}
#endif // ICON_O_MATIC
@@ -0,0 +1,55 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef PERSPECTIVE_TRANSFORMER_H
#define PERSPECTIVE_TRANSFORMER_H
#include <agg_conv_transform.h>
#include <agg_trans_perspective.h>
#include "Transformer.h"
typedef agg::conv_transform<VertexSource,
agg::trans_perspective> Perspective;
class PerspectiveTransformer : public Transformer,
public Perspective,
public agg::trans_perspective {
public:
enum {
archive_code = 'prsp',
};
PerspectiveTransformer(
VertexSource& source);
#ifdef ICON_O_MATIC
PerspectiveTransformer(
VertexSource& source,
BMessage* archive);
#endif
virtual ~PerspectiveTransformer();
// Transformer interface
virtual Transformer* Clone(VertexSource& source) const;
virtual void rewind(unsigned path_id);
virtual unsigned vertex(double* x, double* y);
virtual void SetSource(VertexSource& source);
virtual double ApproximationScale() const;
#ifdef ICON_O_MATIC
// IconObject interface
virtual status_t Archive(BMessage* into,
bool deep = true) const;
#endif
};
#endif // PERSPECTIVE_TRANSFORMER_H
@@ -0,0 +1,251 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "StrokeTransformer.h"
#include <new>
#ifdef ICON_O_MATIC
# include <Message.h>
# include "CommonPropertyIDs.h"
# include "OptionProperty.h"
# include "Property.h"
# include "PropertyObject.h"
#endif // ICON_O_MATIC
using std::nothrow;
// constructor
StrokeTransformer::StrokeTransformer(VertexSource& source)
: Transformer(source, "Stroke"),
Stroke(source)
{
}
#ifdef ICON_O_MATIC
// constructor
StrokeTransformer::StrokeTransformer(VertexSource& source,
BMessage* archive)
: Transformer(source, archive),
Stroke(source)
{
if (!archive)
return;
int32 mode;
if (archive->FindInt32("line cap", &mode) == B_OK)
line_cap((agg::line_cap_e)mode);
if (archive->FindInt32("line join", &mode) == B_OK)
line_join((agg::line_join_e)mode);
if (archive->FindInt32("inner join", &mode) == B_OK)
inner_join((agg::inner_join_e)mode);
double value;
if (archive->FindDouble("width", &value) == B_OK)
width(value);
if (archive->FindDouble("miter limit", &value) == B_OK)
miter_limit(value);
if (archive->FindDouble("inner miter limit", &value) == B_OK)
inner_miter_limit(value);
if (archive->FindDouble("shorten", &value) == B_OK)
shorten(value);
}
#endif // ICON_O_MATIC
// destructor
StrokeTransformer::~StrokeTransformer()
{
}
// Clone
Transformer*
StrokeTransformer::Clone(VertexSource& source) const
{
StrokeTransformer* clone = new (nothrow) StrokeTransformer(source);
if (clone) {
clone->line_cap(line_cap());
clone->line_join(line_join());
clone->inner_join(inner_join());
clone->width(width());
clone->miter_limit(miter_limit());
clone->inner_miter_limit(inner_miter_limit());
clone->shorten(shorten());
}
return clone;
}
// rewind
void
StrokeTransformer::rewind(unsigned path_id)
{
Stroke::rewind(path_id);
}
// vertex
unsigned
StrokeTransformer::vertex(double* x, double* y)
{
return Stroke::vertex(x, y);
}
// SetSource
void
StrokeTransformer::SetSource(VertexSource& source)
{
Transformer::SetSource(source);
Stroke::attach(source);
}
// WantsOpenPaths
bool
StrokeTransformer::WantsOpenPaths() const
{
return true;
}
// ApproximationScale
double
StrokeTransformer::ApproximationScale() const
{
return fSource.ApproximationScale() * width();
}
// #pragma mark -
#ifdef ICON_O_MATIC
// Archive
status_t
StrokeTransformer::Archive(BMessage* into, bool deep) const
{
status_t ret = Transformer::Archive(into, deep);
if (ret == B_OK)
into->what = archive_code;
if (ret == B_OK)
ret = into->AddInt32("line cap", line_cap());
if (ret == B_OK)
ret = into->AddInt32("line join", line_join());
if (ret == B_OK)
ret = into->AddInt32("inner join", inner_join());
if (ret == B_OK)
ret = into->AddDouble("width", width());
if (ret == B_OK)
ret = into->AddDouble("miter limit", miter_limit());
if (ret == B_OK)
ret = into->AddDouble("inner miter limit", inner_miter_limit());
if (ret == B_OK)
ret = into->AddDouble("shorten",shorten());
return ret;
}
// MakePropertyObject
PropertyObject*
StrokeTransformer::MakePropertyObject() const
{
PropertyObject* object = Transformer::MakePropertyObject();
if (!object)
return NULL;
// width
object->AddProperty(new FloatProperty(PROPERTY_WIDTH, width()));
// cap mode
OptionProperty* property = new OptionProperty(PROPERTY_CAP_MODE);
property->AddOption(agg::butt_cap, "Butt");
property->AddOption(agg::square_cap, "Square");
property->AddOption(agg::round_cap, "Round");
property->SetCurrentOptionID(line_cap());
object->AddProperty(property);
// join mode
property = new OptionProperty(PROPERTY_JOIN_MODE);
property->AddOption(agg::miter_join, "Miter");
property->AddOption(agg::round_join, "Round");
property->AddOption(agg::bevel_join, "Bevel");
property->SetCurrentOptionID(line_join());
object->AddProperty(property);
// miter limit
if (line_join() == agg::miter_join) {
object->AddProperty(new FloatProperty(PROPERTY_MITER_LIMIT,
miter_limit()));
}
// shorten
object->AddProperty(new FloatProperty(PROPERTY_STROKE_SHORTEN,
shorten()));
return object;
}
// SetToPropertyObject
bool
StrokeTransformer::SetToPropertyObject(const PropertyObject* object)
{
AutoNotificationSuspender _(this);
Transformer::SetToPropertyObject(object);
// width
float w = object->Value(PROPERTY_WIDTH, (float)width());
if (w != width()) {
width(w);
Notify();
}
// cap mode
OptionProperty* property = dynamic_cast<OptionProperty*>(
object->FindProperty(PROPERTY_CAP_MODE));
if (property && line_cap() != property->CurrentOptionID()) {
line_cap((agg::line_cap_e)property->CurrentOptionID());
Notify();
}
// join mode
property = dynamic_cast<OptionProperty*>(
object->FindProperty(PROPERTY_JOIN_MODE));
if (property && line_join() != property->CurrentOptionID()) {
line_join((agg::line_join_e)property->CurrentOptionID());
Notify();
}
// miter limit
float l = object->Value(PROPERTY_MITER_LIMIT, (float)miter_limit());
if (l != miter_limit()) {
miter_limit(l);
Notify();
}
// shorten
float s = object->Value(PROPERTY_STROKE_SHORTEN, (float)shorten());
if (s != shorten()) {
shorten(s);
Notify();
}
return HasPendingNotifications();
}
#endif // ICON_O_MATIC
@@ -0,0 +1,56 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef STROKE_TRANSFORMER_H
#define STROKE_TRANSFORMER_H
#include <agg_conv_stroke.h>
#include "Transformer.h"
typedef agg::conv_stroke<VertexSource> Stroke;
class StrokeTransformer : public Transformer,
public Stroke {
public:
enum {
archive_code = 'strk',
};
StrokeTransformer(
VertexSource& source);
#ifdef ICON_O_MATIC
StrokeTransformer(
VertexSource& source,
BMessage* archive);
#endif
virtual ~StrokeTransformer();
// Transformer interface
virtual Transformer* Clone(VertexSource& source) const;
virtual void rewind(unsigned path_id);
virtual unsigned vertex(double* x, double* y);
virtual void SetSource(VertexSource& source);
virtual bool WantsOpenPaths() const;
virtual double ApproximationScale() const;
#ifdef ICON_O_MATIC
// IconObject interface
virtual status_t Archive(BMessage* into,
bool deep = true) const;
virtual PropertyObject* MakePropertyObject() const;
virtual bool SetToPropertyObject(
const PropertyObject* object);
#endif
};
#endif // STROKE_TRANSFORMER_H
+85
View File
@@ -0,0 +1,85 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "Transformer.h"
// constructor
VertexSource::VertexSource()
{
}
// destructor
VertexSource::~VertexSource()
{
}
// #pragma mark -
// constructor
Transformer::Transformer(VertexSource& source, const char* name)
#ifdef ICON_O_MATIC
: IconObject(name),
#else
:
#endif
fSource(source)
{
}
#ifdef ICON_O_MATIC
// constructor
Transformer::Transformer(VertexSource& source,
BMessage* archive)
: IconObject(archive),
fSource(source)
{
}
#endif // ICON_O_MATIC
// destructor
Transformer::~Transformer()
{
}
// #pragma mark -
// rewind
void
Transformer::rewind(unsigned path_id)
{
fSource.rewind(path_id);
}
// vertex
unsigned
Transformer::vertex(double* x, double* y)
{
return fSource.vertex(x, y);
}
// SetSource
void
Transformer::SetSource(VertexSource& source)
{
fSource = source;
}
// WantsOpenPaths
bool
Transformer::WantsOpenPaths() const
{
return fSource.WantsOpenPaths();
}
// ApproximationScale
double
Transformer::ApproximationScale() const
{
return fSource.ApproximationScale();
}
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef TRANSFORMER_H
#define TRANSFORMER_H
#ifdef ICON_O_MATIC
# include "IconObject.h"
#else
# include <SupportDefs.h>
#endif
class VertexSource {
public:
VertexSource();
virtual ~VertexSource();
virtual void rewind(unsigned path_id) = 0;
virtual unsigned vertex(double* x, double* y) = 0;
virtual bool WantsOpenPaths() const = 0;
virtual double ApproximationScale() const = 0;
};
#ifdef ICON_O_MATIC
class Transformer : public VertexSource,
public IconObject {
#else
class Transformer : public VertexSource {
#endif
public:
Transformer(VertexSource& source,
const char* name);
#ifdef ICON_O_MATIC
Transformer(VertexSource& source,
BMessage* archive);
#endif
virtual ~Transformer();
// Transformer
virtual Transformer* Clone(VertexSource& source) const = 0;
virtual void rewind(unsigned path_id);
virtual unsigned vertex(double* x, double* y);
virtual void SetSource(VertexSource& source);
virtual bool WantsOpenPaths() const;
virtual double ApproximationScale() const;
protected:
VertexSource& fSource;
};
#endif // TRANSFORMER_H
@@ -0,0 +1,82 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "TransformerFactory.h"
#ifdef ICON_O_MATIC
# include <Message.h>
#endif
#include "AffineTransformer.h"
#include "ContourTransformer.h"
#include "PerspectiveTransformer.h"
#include "StrokeTransformer.h"
// TransformerFor
Transformer*
TransformerFactory::TransformerFor(uint32 type, VertexSource& source)
{
switch (type) {
case 0:
return new AffineTransformer(source);
case 1:
return new PerspectiveTransformer(source);
case 2:
return new ContourTransformer(source);
case 3:
return new StrokeTransformer(source);
}
return NULL;
}
#ifdef ICON_O_MATIC
// TransformerFor
Transformer*
TransformerFactory::TransformerFor(BMessage* message,
VertexSource& source)
{
switch (message->what) {
case AffineTransformer::archive_code:
return new AffineTransformer(source, message);
case PerspectiveTransformer::archive_code:
return new PerspectiveTransformer(source, message);
case ContourTransformer::archive_code:
return new ContourTransformer(source, message);
case StrokeTransformer::archive_code:
return new StrokeTransformer(source, message);
}
return NULL;
}
// NextType
bool
TransformerFactory::NextType(int32* cookie, uint32* type, BString* name)
{
*type = *cookie;
*cookie = *cookie + 1;
switch (*type) {
case 0:
*name = "Transformation";
return true;
case 1:
*name = "Perspective";
return true;
case 2:
*name = "Contour";
return true;
case 3:
*name = "Stroke";
return true;
}
return false;
}
#endif // ICON_O_MATIC
@@ -0,0 +1,35 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef TRANSFORMER_FACTORY_H
#define TRANSFORMER_FACTORY_H
#include <String.h>
class BMessage;
class Transformer;
class VertexSource;
class TransformerFactory {
public:
static Transformer* TransformerFor(uint32 type,
VertexSource& source);
#ifdef ICON_O_MATIC
static Transformer* TransformerFor(BMessage* archive,
VertexSource& source);
static bool NextType(int32* cookie,
uint32* type,
BString* name);
#endif // ICON_O_MATIC
};
#endif // TRANSFORMER_FACTORY_H