Files
haiku-beta6/src/kits/interface/Shape.cpp
T

568 lines
12 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2001-2005, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* Marc Flerackers ([email protected])
* Stephan Aßmus <[email protected]>
*
* Description:
* BShape encapsulates a Postscript-style "path"
*/
2003-06-16 08:05:30 +00:00
#include <stdlib.h>
#include <string.h>
2003-05-14 17:21:46 +00:00
#include <Shape.h>
#include <Point.h>
#include <Rect.h>
#include <Errors.h>
#include <Message.h>
2003-02-06 16:46:10 +00:00
2003-06-16 08:05:30 +00:00
// NOTE: changing these defines will break Painter,
// currently located in src/servers/app/drawing/Painter/Painter.cpp
2003-02-06 16:46:10 +00:00
#define OP_LINETO 0x10000000
#define OP_BEZIERTO 0x20000000
#define OP_CLOSE 0x40000000
#define OP_MOVETO 0x80000000
2003-02-06 16:46:10 +00:00
struct shape_data {
uint32 *opList;
int32 opCount;
int32 opSize;
int32 opBlockSize;
BPoint *ptList;
int32 ptCount;
int32 ptSize;
int32 ptBlockSize;
};
2003-06-16 08:05:30 +00:00
2003-02-06 16:46:10 +00:00
BShapeIterator::BShapeIterator()
{
}
2003-02-06 16:46:10 +00:00
BShapeIterator::~BShapeIterator()
{
}
status_t
BShapeIterator::Iterate(BShape *shape)
2003-02-06 16:46:10 +00:00
{
shape_data *data = (shape_data*)shape->fPrivateData;
BPoint *points = data->ptList;
for (int32 i = 0; i < data->opCount; i++) {
switch (data->opList[i] & 0xFF000000) {
case OP_LINETO: {
2003-02-06 16:46:10 +00:00
int32 count = data->opList[i] & 0x00FFFFFF;
IterateLineTo(count, points);
points += count;
break;
}
case (OP_MOVETO | OP_LINETO): {
2003-02-06 16:46:10 +00:00
int32 count = data->opList[i] & 0x00FFFFFF;
IterateMoveTo(points);
points++;
IterateLineTo(count, points);
points += count;
break;
}
case OP_BEZIERTO: {
2003-02-06 16:46:10 +00:00
int32 count = data->opList[i] & 0x00FFFFFF;
IterateBezierTo(count, points);
points += count;
break;
}
case (OP_MOVETO | OP_BEZIERTO): {
2003-02-06 16:46:10 +00:00
int32 count = data->opList[i] & 0x00FFFFFF;
IterateMoveTo(points);
points++;
IterateBezierTo(count, points);
points += count;
break;
}
case OP_CLOSE:
case OP_CLOSE | OP_LINETO | OP_BEZIERTO: {
2003-02-06 16:46:10 +00:00
IterateClose();
break;
}
}
}
return B_OK;
}
status_t
BShapeIterator::IterateBezierTo(int32 bezierCount,
2003-02-06 16:46:10 +00:00
BPoint *bezierPoints)
{
return B_OK;
}
status_t
BShapeIterator::IterateClose()
2003-02-06 16:46:10 +00:00
{
return B_OK;
}
status_t
BShapeIterator::IterateLineTo(int32 lineCount, BPoint *linePoints)
2003-02-06 16:46:10 +00:00
{
return B_OK;
}
status_t
BShapeIterator::IterateMoveTo ( BPoint *point )
2003-02-06 16:46:10 +00:00
{
return B_OK;
}
2003-02-06 16:46:10 +00:00
void BShapeIterator::_ReservedShapeIterator1() {}
void BShapeIterator::_ReservedShapeIterator2() {}
void BShapeIterator::_ReservedShapeIterator3() {}
void BShapeIterator::_ReservedShapeIterator4() {}
2003-02-06 16:46:10 +00:00
BShape::BShape()
{
InitData();
}
2003-02-06 16:46:10 +00:00
BShape::BShape(const BShape &copyFrom)
{
InitData();
2003-06-16 07:58:45 +00:00
AddShape(&copyFrom);
2003-02-06 16:46:10 +00:00
}
2003-02-06 16:46:10 +00:00
BShape::BShape(BMessage *archive)
2003-06-16 07:58:45 +00:00
: BArchivable(archive)
2003-02-06 16:46:10 +00:00
{
InitData();
2003-06-16 07:58:45 +00:00
shape_data *data = (shape_data*)fPrivateData;
ssize_t size;
int32 i = 0;
const uint32 *opPtr;
while (archive->FindData("ops", B_INT32_TYPE, i++, (const void**)&opPtr, &size) == B_OK) {
if (data->opSize < data->opCount + 1) {
2003-06-20 14:02:46 +00:00
int32 new_size = ((data->opCount + data->opBlockSize) /
data->opBlockSize) * data->opBlockSize;
2003-06-16 07:58:45 +00:00
data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
data->opSize = new_size;
}
data->opList[data->opCount++] = *opPtr;
}
const BPoint *ptPtr;
while (archive->FindData("pts", B_POINT_TYPE, i++, (const void**)&ptPtr, &size) == B_OK) {
if (data->ptSize < data->ptCount + 1) {
2003-06-20 14:02:46 +00:00
int32 new_size = ((data->ptCount + data->ptBlockSize) /
data->ptBlockSize) * data->ptBlockSize;
data->ptList = (BPoint*)realloc(data->ptList,
new_size * sizeof(BPoint));
2003-06-16 07:58:45 +00:00
data->ptSize = new_size;
}
data->ptList[data->ptCount++] = *ptPtr;
}
2003-02-06 16:46:10 +00:00
}
2003-02-06 16:46:10 +00:00
BShape::~BShape()
{
shape_data *data = (shape_data*)fPrivateData;
free(data->opList);
free(data->ptList);
2003-06-16 08:05:30 +00:00
delete (shape_data*)fPrivateData;
2003-02-06 16:46:10 +00:00
}
status_t
BShape::Archive(BMessage *archive, bool deep) const
2003-02-06 16:46:10 +00:00
{
status_t err = BArchivable::Archive(archive, deep);
2003-06-16 08:05:30 +00:00
int32 i;
2003-02-06 16:46:10 +00:00
if (err != B_OK)
return err;
shape_data *data = (shape_data*)fPrivateData;
// If no valid shape data, return
if (data->opCount == 0 || data->ptCount == 0)
return err;
// Avoids allocation for each point
archive->AddData("pts", B_POINT_TYPE, data->ptList, sizeof(BPoint), true,
data->ptCount);
2003-06-16 08:05:30 +00:00
for (i = 1; i < data->ptCount; i++)
2003-02-06 16:46:10 +00:00
archive->AddPoint("pts", data->ptList[i]);
// Avoids allocation for each op
archive->AddData("ops", B_INT32_TYPE, data->opList, sizeof(int32), true,
data->opCount);
for (i = 1; i < data->opCount; i++)
archive->AddInt32("ops", data->opList[i]);
archive->AddInt32("ops", fBuildingOp);
return err;
}
BArchivable*
BShape::Instantiate(BMessage *archive)
2003-02-06 16:46:10 +00:00
{
if (validate_instantiation(archive, "BShape"))
return new BShape(archive);
else
return NULL;
}
void
BShape::Clear()
2003-02-06 16:46:10 +00:00
{
shape_data *data = (shape_data*)fPrivateData;
if (data->opList) {
2003-02-06 16:46:10 +00:00
free(data->opList);
data->opList = NULL;
data->opCount = 0;
data->opSize = 0;
2003-02-06 16:46:10 +00:00
}
if (data->ptList) {
2003-02-06 16:46:10 +00:00
free(data->ptList);
data->ptList = NULL;
data->ptCount = 0;
data->ptSize = 0;
2003-02-06 16:46:10 +00:00
}
fState = 0;
fBuildingOp = 0;
}
BRect
BShape::Bounds() const
2003-02-06 16:46:10 +00:00
{
2003-06-16 07:58:45 +00:00
shape_data *data = (shape_data*)fPrivateData;
BRect bounds;
if (data->ptCount == 0)
return bounds;
bounds.left = data->ptList[0].x;
bounds.top = data->ptList[0].y;
bounds.right = data->ptList[0].x;
bounds.bottom = data->ptList[0].y;
for (int32 i = 1; i < data->ptCount; i++)
{
if (bounds.left > data->ptList[0].x)
bounds.left = data->ptList[0].x;
if (bounds.top > data->ptList[0].y)
bounds.top = data->ptList[0].y;
if (bounds.right < data->ptList[0].x)
bounds.right = data->ptList[0].x;
if (bounds.bottom < data->ptList[0].y)
bounds.bottom = data->ptList[0].y;
}
return bounds;
2003-02-06 16:46:10 +00:00
}
status_t
BShape::AddShape(const BShape *otherShape)
2003-02-06 16:46:10 +00:00
{
2003-06-16 07:58:45 +00:00
shape_data *data = (shape_data*)fPrivateData;
shape_data *otherData = (shape_data*)otherShape->fPrivateData;
2003-06-20 14:02:46 +00:00
if (data->opSize < data->opCount + otherData->opCount)
2003-06-16 07:58:45 +00:00
{
2003-06-20 14:02:46 +00:00
int32 new_size = ((data->opCount + otherData->opBlockSize) /
data->opBlockSize) * data->opBlockSize;
2003-06-16 07:58:45 +00:00
data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
data->opSize = new_size;
}
memcpy(data->opList + data->opCount * sizeof(uint32), otherData->opList,
otherData->opCount * sizeof(uint32));
data->opCount += otherData->opCount;
2003-06-20 14:02:46 +00:00
if (data->ptSize < data->ptCount + otherData->ptCount)
2003-06-16 07:58:45 +00:00
{
2003-06-20 14:02:46 +00:00
int32 new_size = ((data->ptCount + otherData->ptBlockSize) /
data->ptBlockSize) * data->ptBlockSize;
2003-06-16 07:58:45 +00:00
data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(uint32));
data->ptSize = new_size;
}
memcpy(data->ptList + data->ptCount * sizeof(BPoint), otherData->ptList,
otherData->ptCount * sizeof(BPoint));
data->ptCount += otherData->ptCount;
fBuildingOp = otherShape->fBuildingOp;
return B_OK;
2003-02-06 16:46:10 +00:00
}
status_t
BShape::MoveTo(BPoint point)
2003-02-06 16:46:10 +00:00
{
shape_data *data = (shape_data*)fPrivateData;
// If the last op is MoveTo, replace the point
// If there was a previous op, add the op
if (fBuildingOp == OP_MOVETO) {
2003-02-06 16:46:10 +00:00
data->ptList[data->ptCount - 1] = point;
return B_OK;
}
// BuildingOp is MoveTo
fBuildingOp = OP_MOVETO;
// Add point
if (data->ptSize < data->ptCount + 1) {
2003-06-20 14:02:46 +00:00
int32 new_size = ((data->ptCount + data->ptBlockSize) /
data->ptBlockSize) * data->ptBlockSize;
2003-06-16 07:58:45 +00:00
data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(BPoint));
data->ptSize = new_size;
}
2003-02-06 16:46:10 +00:00
data->ptList[data->ptCount++] = point;
return B_OK;
}
status_t
BShape::LineTo(BPoint point)
2003-02-06 16:46:10 +00:00
{
shape_data *data = (shape_data*)fPrivateData;
// If the last op is MoveTo, replace the op and set the count
// If the last op is LineTo increase the count
// If there was a previous op, add the op
bool newOp = true;
if (fBuildingOp == OP_MOVETO) {
fBuildingOp = OP_LINETO | OP_MOVETO;
} else if (fBuildingOp & OP_LINETO) {
newOp = false;
} else {
fBuildingOp = OP_LINETO;
2003-02-06 16:46:10 +00:00
}
fBuildingOp++;
2003-02-06 16:46:10 +00:00
if (newOp) {
if (data->opSize < data->opCount + 1) {
int32 new_size = ((data->opCount + data->opBlockSize) /
data->opBlockSize) * data->opBlockSize;
data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
data->opSize = new_size;
2003-02-06 16:46:10 +00:00
}
data->opCount++;
2003-02-06 16:46:10 +00:00
}
data->opList[data->opCount - 1] = fBuildingOp;
2003-02-06 16:46:10 +00:00
// Add point
if (data->ptSize < data->ptCount + 1) {
2003-06-20 14:02:46 +00:00
int32 new_size = ((data->ptCount + data->ptBlockSize) /
data->ptBlockSize) * data->ptBlockSize;
2003-06-16 07:58:45 +00:00
data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(BPoint));
data->ptSize = new_size;
}
2003-02-06 16:46:10 +00:00
data->ptList[data->ptCount++] = point;
return B_OK;
}
status_t
BShape::BezierTo(BPoint controlPoints[3])
2003-02-06 16:46:10 +00:00
{
shape_data *data = (shape_data*)fPrivateData;
// If the last op is MoveTo, replace the op and set the count
// If the last op is BezierTo increase the count
// If there was a previous op, add the op
bool newOp = true;
if (fBuildingOp == OP_MOVETO) {
fBuildingOp = OP_BEZIERTO | OP_MOVETO;
} else if (fBuildingOp & OP_BEZIERTO) {
newOp = false;
} else {
fBuildingOp = OP_BEZIERTO;
2003-02-06 16:46:10 +00:00
}
fBuildingOp += 3;
2003-02-06 16:46:10 +00:00
if (newOp) {
if (data->opSize < data->opCount + 1) {
int32 new_size = ((data->opCount + data->opBlockSize) /
data->opBlockSize) * data->opBlockSize;
data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
data->opSize = new_size;
2003-02-06 16:46:10 +00:00
}
data->opCount++;
2003-02-06 16:46:10 +00:00
}
data->opList[data->opCount - 1] = fBuildingOp;
2003-02-06 16:46:10 +00:00
// Add points
2003-06-20 14:02:46 +00:00
if (data->ptSize < data->ptCount + 3)
2003-06-16 07:58:45 +00:00
{
2003-06-20 14:02:46 +00:00
int32 new_size = ((data->ptCount + data->ptBlockSize) /
data->ptBlockSize) * data->ptBlockSize;
2003-06-16 07:58:45 +00:00
data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(BPoint));
data->ptSize = new_size;
}
2003-02-06 16:46:10 +00:00
data->ptList[data->ptCount++] = controlPoints[0];
data->ptList[data->ptCount++] = controlPoints[1];
data->ptList[data->ptCount++] = controlPoints[2];
return B_OK;
}
status_t
BShape::Close()
2003-02-06 16:46:10 +00:00
{
shape_data *data = (shape_data*)fPrivateData;
// If there was a previous line/bezier op, add the op
if (fBuildingOp & (OP_LINETO | OP_BEZIERTO)) {
if (data->opSize < data->opCount + 1) {
2003-06-20 14:02:46 +00:00
int32 new_size = ((data->opCount + data->opBlockSize) /
data->opBlockSize) * data->opBlockSize;
2003-06-16 07:58:45 +00:00
data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
data->opSize = new_size;
}
2003-02-06 16:46:10 +00:00
data->opList[data->opCount++] = fBuildingOp;
fBuildingOp = OP_CLOSE;
}
return B_OK;
}
status_t
BShape::Perform(perform_code d, void *arg)
2003-02-06 16:46:10 +00:00
{
2003-06-16 07:58:45 +00:00
return BArchivable::Perform(d, arg);
2003-02-06 16:46:10 +00:00
}
2003-02-06 16:46:10 +00:00
void BShape::_ReservedShape1() {}
void BShape::_ReservedShape2() {}
void BShape::_ReservedShape3() {}
void BShape::_ReservedShape4() {}
void
BShape::GetData(int32 *opCount, int32 *ptCount, uint32 **opList,
2003-02-06 16:46:10 +00:00
BPoint **ptList)
{
shape_data *data = (shape_data*)fPrivateData;
2003-06-16 07:58:45 +00:00
*opCount = data->opCount;
*ptCount = data->ptCount;
*opList = data->opList;
*ptList = data->ptList;
2003-02-06 16:46:10 +00:00
}
void
BShape::SetData(int32 opCount, int32 ptCount, uint32 *opList,
BPoint *ptList)
2003-02-06 16:46:10 +00:00
{
shape_data *data = (shape_data*)fPrivateData;
if (data->opSize < opCount) {
2003-06-20 14:02:46 +00:00
int32 new_size = ((opCount + data->opBlockSize) /
data->opBlockSize) * data->opBlockSize;
2003-02-06 16:46:10 +00:00
2003-06-16 07:58:45 +00:00
data->opList = (uint32*)realloc(data->opList, new_size * sizeof(uint32));
data->opSize = new_size;
2003-02-06 16:46:10 +00:00
}
2003-06-16 07:58:45 +00:00
memcpy(data->opList, opList, opCount * sizeof(uint32));
data->opCount = opCount;
if (data->ptSize < ptCount) {
2003-06-20 14:02:46 +00:00
int32 new_size = ((ptCount + data->ptBlockSize) /
data->ptBlockSize) * data->ptBlockSize;
2003-06-16 07:58:45 +00:00
data->ptList = (BPoint*)realloc(data->ptList, new_size * sizeof(BPoint));
data->ptSize = new_size;
2003-02-06 16:46:10 +00:00
}
2003-06-16 07:58:45 +00:00
memcpy(data->ptList, ptList, ptCount * sizeof(BPoint));
data->ptCount = ptCount;
2003-02-06 16:46:10 +00:00
}
void
BShape::InitData()
2003-02-06 16:46:10 +00:00
{
fPrivateData = new shape_data;
shape_data *data = (shape_data*)fPrivateData;
2003-06-16 07:58:45 +00:00
fState = 0;
fBuildingOp = 0;
2003-02-06 16:46:10 +00:00
data->opList = NULL;
data->opCount = 0;
data->opSize = 0;
data->opBlockSize = 255;
data->ptList = NULL;
data->ptCount = 0;
data->ptSize = 0;
data->ptBlockSize = 255;
}
// #pragma mark -
// R4.5 compatibility
#if __GNUC__ < 3
extern "C" BRect
Bounds__6BShape(BShape *self)
{
return self->Bounds();
}
// ToDo: Add those:
// BShape(BShape &copyFrom);
// status_t AddShape(BShape *other);
#endif // __GNUC__ < 3