/* * Copyright (c) 2001-2010, Haiku, Inc. * Distributed under the terms of the MIT license. * * Authors: * Marc Flerackers (mflerackers@androme.be) * Stephan Aßmus * Michael Lotz * Marcus Overhagen */ /*! BShape encapsulates a Postscript-style "path" */ #include #include #include #include #include #include #include #include BShapeIterator::BShapeIterator() { } BShapeIterator::~BShapeIterator() { } status_t BShapeIterator::Iterate(BShape* shape) { shape_data* data = (shape_data*)shape->fPrivateData; BPoint* points = data->ptList; for (int32 i = 0; i < data->opCount; i++) { int32 op = data->opList[i] & 0xFF000000; if (op & OP_MOVETO) { IterateMoveTo(points); points++; } if (op & OP_LINETO) { int32 count = data->opList[i] & 0x00FFFFFF; IterateLineTo(count, points); points += count; } if (op & OP_BEZIERTO) { int32 count = data->opList[i] & 0x00FFFFFF; IterateBezierTo(count / 3, points); points += count; } if ((op & OP_LARGE_ARC_TO_CW) || (op & OP_LARGE_ARC_TO_CCW) || (op & OP_SMALL_ARC_TO_CW) || (op & OP_SMALL_ARC_TO_CCW)) { int32 count = data->opList[i] & 0x00FFFFFF; for (int32 i = 0; i < count / 3; i++) { IterateArcTo(points[0].x, points[0].y, points[1].x, op & (OP_LARGE_ARC_TO_CW | OP_LARGE_ARC_TO_CCW), op & (OP_SMALL_ARC_TO_CCW | OP_LARGE_ARC_TO_CCW), points[2]); points += 3; } } if (op & OP_CLOSE) { IterateClose(); } } return B_OK; } status_t BShapeIterator::IterateMoveTo(BPoint* point) { return B_OK; } status_t BShapeIterator::IterateLineTo(int32 lineCount, BPoint* linePoints) { return B_OK; } status_t BShapeIterator::IterateBezierTo(int32 bezierCount, BPoint* bezierPoints) { return B_OK; } status_t BShapeIterator::IterateClose() { return B_OK; } status_t BShapeIterator::IterateArcTo(float& rx, float& ry, float& angle, bool largeArc, bool counterClockWise, BPoint& point) { return B_OK; } void BShapeIterator::_ReservedShapeIterator2() {} void BShapeIterator::_ReservedShapeIterator3() {} void BShapeIterator::_ReservedShapeIterator4() {} // #pragma mark - BShape::BShape() { InitData(); } BShape::BShape(const BShape ©From) { InitData(); AddShape(©From); } BShape::BShape(BMessage* archive) : BArchivable(archive) { InitData(); shape_data* data = (shape_data*)fPrivateData; ssize_t size = 0; int32 count = 0; type_code type = 0; archive->GetInfo("ops", &type, &count); if (!AllocateOps(count)) return; int32 i = 0; const uint32* opPtr; while (archive->FindData("ops", B_INT32_TYPE, i++, (const void**)&opPtr, &size) == B_OK) data->opList[data->opCount++] = *opPtr; archive->GetInfo("pts", &type, &count); if (!AllocatePts(count)) { Clear(); return; } i = 0; const BPoint* ptPtr; while (archive->FindData("pts", B_POINT_TYPE, i++, (const void**)&ptPtr, &size) == B_OK) data->ptList[data->ptCount++] = *ptPtr; } BShape::~BShape() { shape_data* data = (shape_data*)fPrivateData; free(data->opList); free(data->ptList); delete (shape_data*)fPrivateData; } status_t BShape::Archive(BMessage* archive, bool deep) const { status_t err = BArchivable::Archive(archive, deep); 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 err = archive->AddData("pts", B_POINT_TYPE, data->ptList, sizeof(BPoint), true, data->ptCount); if (err != B_OK) return err; for (int32 i = 1; i < data->ptCount && err == B_OK; i++) err = archive->AddPoint("pts", data->ptList[i]); // Avoids allocation for each op if (err == B_OK) err = archive->AddData("ops", B_INT32_TYPE, data->opList, sizeof(int32), true, data->opCount); for (int32 i = 1; i < data->opCount && err == B_OK ; i++) err = archive->AddInt32("ops", data->opList[i]); return err; } BArchivable* BShape::Instantiate(BMessage* archive) { if (validate_instantiation(archive, "BShape")) return new BShape(archive); else return NULL; } BShape& BShape::operator=(const BShape& other) { if (this != &other) { Clear(); AddShape(&other); } return *this; } bool BShape::operator==(const BShape& other) const { if (this == &other) return true; shape_data* data = (shape_data*)fPrivateData; shape_data* otherData = (shape_data*)other.fPrivateData; if (data->opCount != otherData->opCount) return false; if (data->ptCount != otherData->ptCount) return false; return memcmp(data->opList, otherData->opList, data->opCount * sizeof(uint32)) == 0 && memcmp(data->ptList, otherData->ptList, data->ptCount * sizeof(BPoint)) == 0; } bool BShape::operator!=(const BShape& other) const { return !(*this == other); } void BShape::Clear() { shape_data* data = (shape_data*)fPrivateData; data->opCount = 0; data->opSize = 0; if (data->opList) { free(data->opList); data->opList = NULL; } data->ptCount = 0; data->ptSize = 0; if (data->ptList) { free(data->ptList); data->ptList = NULL; } fState = 0; fBuildingOp = 0; } BRect BShape::Bounds() const { shape_data* data = (shape_data*)fPrivateData; BRect bounds; if (data->ptCount == 0) return bounds; // TODO: This implementation doesn't take into account curves at all. 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[i].x) bounds.left = data->ptList[i].x; if (bounds.top > data->ptList[i].y) bounds.top = data->ptList[i].y; if (bounds.right < data->ptList[i].x) bounds.right = data->ptList[i].x; if (bounds.bottom < data->ptList[i].y) bounds.bottom = data->ptList[i].y; } return bounds; } BPoint BShape::CurrentPosition() const { shape_data* data = (shape_data*)fPrivateData; if (data->ptCount == 0) return B_ORIGIN; return data->ptList[data->ptCount - 1]; } status_t BShape::AddShape(const BShape* otherShape) { shape_data* data = (shape_data*)fPrivateData; shape_data* otherData = (shape_data*)otherShape->fPrivateData; if (!AllocateOps(otherData->opCount) || !AllocatePts(otherData->ptCount)) return B_NO_MEMORY; memcpy(data->opList + data->opCount, otherData->opList, otherData->opCount * sizeof(uint32)); data->opCount += otherData->opCount; memcpy(data->ptList + data->ptCount, otherData->ptList, otherData->ptCount * sizeof(BPoint)); data->ptCount += otherData->ptCount; fBuildingOp = otherShape->fBuildingOp; return B_OK; } status_t BShape::MoveTo(BPoint point) { shape_data* data = (shape_data*)fPrivateData; // If the last op is MoveTo, replace the point if (fBuildingOp == OP_MOVETO) { data->ptList[data->ptCount - 1] = point; return B_OK; } if (!AllocateOps(1) || !AllocatePts(1)) return B_NO_MEMORY; fBuildingOp = OP_MOVETO; // Add op data->opList[data->opCount++] = fBuildingOp; // Add point data->ptList[data->ptCount++] = point; return B_OK; } status_t BShape::LineTo(BPoint point) { if (!AllocatePts(1)) return B_NO_MEMORY; 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 // Otherwise add the op if (fBuildingOp & OP_LINETO || fBuildingOp == OP_MOVETO) { fBuildingOp |= OP_LINETO; fBuildingOp += 1; data->opList[data->opCount - 1] = fBuildingOp; } else { if (!AllocateOps(1)) return B_NO_MEMORY; fBuildingOp = OP_LINETO + 1; data->opList[data->opCount++] = fBuildingOp; } // Add point data->ptList[data->ptCount++] = point; return B_OK; } status_t BShape::BezierTo(BPoint controlPoints[3]) { return BezierTo(controlPoints[0], controlPoints[1], controlPoints[2]); } status_t BShape::BezierTo(const BPoint& control1, const BPoint& control2, const BPoint& endPoint) { if (!AllocatePts(3)) return B_NO_MEMORY; 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 // Otherwise add the op if (fBuildingOp & OP_BEZIERTO || fBuildingOp == OP_MOVETO) { fBuildingOp |= OP_BEZIERTO; fBuildingOp += 3; data->opList[data->opCount - 1] = fBuildingOp; } else { if (!AllocateOps(1)) return B_NO_MEMORY; fBuildingOp = OP_BEZIERTO + 3; data->opList[data->opCount++] = fBuildingOp; } // Add points data->ptList[data->ptCount++] = control1; data->ptList[data->ptCount++] = control2; data->ptList[data->ptCount++] = endPoint; return B_OK; } status_t BShape::ArcTo(float rx, float ry, float angle, bool largeArc, bool counterClockWise, const BPoint& point) { if (!AllocatePts(3)) return B_NO_MEMORY; shape_data* data = (shape_data*)fPrivateData; uint32 op; if (largeArc) { if (counterClockWise) op = OP_LARGE_ARC_TO_CCW; else op = OP_LARGE_ARC_TO_CW; } else { if (counterClockWise) op = OP_SMALL_ARC_TO_CCW; else op = OP_SMALL_ARC_TO_CW; } // If the last op is MoveTo, replace the op and set the count // If the last op is ArcTo increase the count // Otherwise add the op if (fBuildingOp == op || fBuildingOp == (op | OP_MOVETO)) { fBuildingOp |= op; fBuildingOp += 3; data->opList[data->opCount - 1] = fBuildingOp; } else { if (!AllocateOps(1)) return B_NO_MEMORY; fBuildingOp = op + 3; data->opList[data->opCount++] = fBuildingOp; } // Add points data->ptList[data->ptCount++] = BPoint(rx, ry); data->ptList[data->ptCount++] = BPoint(angle, 0); data->ptList[data->ptCount++] = point; return B_OK; } status_t BShape::Close() { // If the last op is Close or MoveTo, ignore this if (fBuildingOp == OP_CLOSE || fBuildingOp == OP_MOVETO) return B_OK; if (!AllocateOps(1)) return B_NO_MEMORY; shape_data* data = (shape_data*)fPrivateData; // ToDo: Decide about that, it's not BeOS compatible // If there was any op before we can attach the close to it /*if (fBuildingOp) { fBuildingOp |= OP_CLOSE; data->opList[data->opCount - 1] = fBuildingOp; return B_OK; }*/ fBuildingOp = OP_CLOSE; data->opList[data->opCount++] = fBuildingOp; return B_OK; } status_t BShape::Perform(perform_code d, void* arg) { return BArchivable::Perform(d, arg); } void BShape::_ReservedShape1() {} void BShape::_ReservedShape2() {} void BShape::_ReservedShape3() {} void BShape::_ReservedShape4() {} void BShape::GetData(int32* opCount, int32* ptCount, uint32** opList, BPoint** ptList) { shape_data* data = (shape_data*)fPrivateData; *opCount = data->opCount; *ptCount = data->ptCount; *opList = data->opList; *ptList = data->ptList; } void BShape::SetData(int32 opCount, int32 ptCount, const uint32* opList, const BPoint* ptList) { Clear(); if (opCount == 0) return; shape_data* data = (shape_data*)fPrivateData; if (!AllocateOps(opCount) || !AllocatePts(ptCount)) return; memcpy(data->opList, opList, opCount * sizeof(uint32)); data->opCount = opCount; fBuildingOp = data->opList[data->opCount - 1]; if (ptCount > 0) { memcpy(data->ptList, ptList, ptCount * sizeof(BPoint)); data->ptCount = ptCount; } } void BShape::InitData() { fPrivateData = new shape_data; shape_data* data = (shape_data*)fPrivateData; fState = 0; fBuildingOp = 0; data->opList = NULL; data->opCount = 0; data->opSize = 0; data->ptList = NULL; data->ptCount = 0; data->ptSize = 0; } inline bool BShape::AllocateOps(int32 count) { shape_data* data = (shape_data*)fPrivateData; int32 newSize = (data->opCount + count + 255) / 256 * 256; if (data->opSize >= newSize) return true; uint32* resizedArray = (uint32*)realloc(data->opList, newSize * sizeof(uint32)); if (resizedArray) { data->opList = resizedArray; data->opSize = newSize; return true; } return false; } inline bool BShape::AllocatePts(int32 count) { shape_data* data = (shape_data*)fPrivateData; int32 newSize = (data->ptCount + count + 255) / 256 * 256; if (data->ptSize >= newSize) return true; BPoint* resizedArray = (BPoint*)realloc(data->ptList, newSize * sizeof(BPoint)); if (resizedArray) { data->ptList = resizedArray; data->ptSize = newSize; return true; } return false; } // #pragma mark - binary compatibility #if __GNUC__ < 3 extern "C" BShape* __6BShapeR6BShape(void* self, BShape& copyFrom) { return new (self) BShape(copyFrom); // we need to instantiate the object in the provided memory } extern "C" BRect Bounds__6BShape(BShape* self) { return self->Bounds(); } extern "C" void _ReservedShapeIterator1__14BShapeIterator(BShapeIterator* self) { } #else // __GNUC__ < 3 extern "C" void _ZN14BShapeIterator23_ReservedShapeIterator1Ev(BShapeIterator* self) { } #endif // __GNUC__ >= 3