diff --git a/headers/os/interface/Shape.h b/headers/os/interface/Shape.h index da394e7561..7b6181be9c 100644 --- a/headers/os/interface/Shape.h +++ b/headers/os/interface/Shape.h @@ -30,10 +30,13 @@ public: BPoint* bezierPts); virtual status_t IterateClose(); + virtual status_t IterateArcTo(float& rx, float& ry, + float& angle, bool largeArc, + bool counterClockWise, BPoint& point); + status_t Iterate(BShape* shape); private: - virtual void _ReservedShapeIterator1(); virtual void _ReservedShapeIterator2(); virtual void _ReservedShapeIterator3(); virtual void _ReservedShapeIterator4(); @@ -53,6 +56,11 @@ public: virtual status_t Archive(BMessage* archive, bool deep = true) const; + BShape& operator=(const BShape& other); + + bool operator==(const BShape& other) const; + bool operator!=(const BShape& other) const; + void Clear(); BRect Bounds() const; @@ -61,6 +69,13 @@ public: status_t MoveTo(BPoint point); status_t LineTo(BPoint linePoint); status_t BezierTo(BPoint controlPoints[3]); + status_t BezierTo(const BPoint& control1, + const BPoint& control2, + const BPoint& endPoint); + status_t ArcTo(float rx, float ry, + float angle, bool largeArc, + bool counterClockWise, + const BPoint& point); status_t Close(); private: diff --git a/headers/private/interface/ShapePrivate.h b/headers/private/interface/ShapePrivate.h index 517c889fac..6262e0d32a 100644 --- a/headers/private/interface/ShapePrivate.h +++ b/headers/private/interface/ShapePrivate.h @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006, Haiku. + * Copyright 2003-2010, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -9,10 +9,14 @@ #ifndef SHAPE_PRIVATE_H #define SHAPE_PRIVATE_H -#define OP_LINETO 0x10000000 -#define OP_BEZIERTO 0x20000000 -#define OP_CLOSE 0x40000000 -#define OP_MOVETO 0x80000000 +#define OP_LINETO 0x10000000 +#define OP_BEZIERTO 0x20000000 +#define OP_CLOSE 0x40000000 +#define OP_MOVETO 0x80000000 +#define OP_LARGE_ARC_TO_CW 0x01000000 +#define OP_LARGE_ARC_TO_CCW 0x02000000 +#define OP_SMALL_ARC_TO_CW 0x04000000 +#define OP_SMALL_ARC_TO_CCW 0x08000000 struct shape_data { diff --git a/src/kits/interface/Shape.cpp b/src/kits/interface/Shape.cpp index e2cfcca64d..7dbbca64fa 100644 --- a/src/kits/interface/Shape.cpp +++ b/src/kits/interface/Shape.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2007, Haiku, Inc. + * Copyright (c) 2001-2010, Haiku, Inc. * Distributed under the terms of the MIT license. * * Authors: @@ -37,10 +37,10 @@ BShapeIterator::~BShapeIterator() status_t -BShapeIterator::Iterate(BShape *shape) +BShapeIterator::Iterate(BShape* shape) { - shape_data *data = (shape_data*)shape->fPrivateData; - BPoint *points = data->ptList; + 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; @@ -62,6 +62,18 @@ BShapeIterator::Iterate(BShape *shape) 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(); } @@ -72,8 +84,21 @@ BShapeIterator::Iterate(BShape *shape) status_t -BShapeIterator::IterateBezierTo(int32 bezierCount, - BPoint *bezierPoints) +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; } @@ -87,25 +112,21 @@ BShapeIterator::IterateClose() status_t -BShapeIterator::IterateLineTo(int32 lineCount, BPoint *linePoints) +BShapeIterator::IterateArcTo(float& rx, float& ry, float& angle, bool largeArc, + bool counterClockWise, BPoint& point) { return B_OK; } -status_t -BShapeIterator::IterateMoveTo ( BPoint *point ) -{ - return B_OK; -} - - -void BShapeIterator::_ReservedShapeIterator1() {} void BShapeIterator::_ReservedShapeIterator2() {} void BShapeIterator::_ReservedShapeIterator3() {} void BShapeIterator::_ReservedShapeIterator4() {} +// #pragma mark - + + BShape::BShape() { InitData(); @@ -119,12 +140,12 @@ BShape::BShape(const BShape ©From) } -BShape::BShape(BMessage *archive) +BShape::BShape(BMessage* archive) : BArchivable(archive) { InitData(); - shape_data *data = (shape_data*)fPrivateData; + shape_data* data = (shape_data*)fPrivateData; ssize_t size = 0; int32 count = 0; @@ -134,8 +155,8 @@ BShape::BShape(BMessage *archive) return; int32 i = 0; - const uint32 *opPtr; - while (archive->FindData("ops", B_INT32_TYPE, i++, (const void **)&opPtr, &size) == B_OK) + 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); @@ -145,15 +166,15 @@ BShape::BShape(BMessage *archive) } i = 0; - const BPoint *ptPtr; - while (archive->FindData("pts", B_POINT_TYPE, i++, (const void **)&ptPtr, &size) == B_OK) + 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; + shape_data* data = (shape_data*)fPrivateData; free(data->opList); free(data->ptList); @@ -163,14 +184,14 @@ BShape::~BShape() status_t -BShape::Archive(BMessage *archive, bool deep) const +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; + shape_data* data = (shape_data*)fPrivateData; // If no valid shape data, return if (data->opCount == 0 || data->ptCount == 0) @@ -198,7 +219,7 @@ BShape::Archive(BMessage *archive, bool deep) const BArchivable* -BShape::Instantiate(BMessage *archive) +BShape::Instantiate(BMessage* archive) { if (validate_instantiation(archive, "BShape")) return new BShape(archive); @@ -207,10 +228,50 @@ BShape::Instantiate(BMessage *archive) } +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; + shape_data* data = (shape_data*)fPrivateData; data->opCount = 0; data->opSize = 0; @@ -234,7 +295,7 @@ BShape::Clear() BRect BShape::Bounds() const { - shape_data *data = (shape_data*)fPrivateData; + shape_data* data = (shape_data*)fPrivateData; BRect bounds; if (data->ptCount == 0) @@ -262,10 +323,10 @@ BShape::Bounds() const status_t -BShape::AddShape(const BShape *otherShape) +BShape::AddShape(const BShape* otherShape) { - shape_data *data = (shape_data*)fPrivateData; - shape_data *otherData = (shape_data*)otherShape->fPrivateData; + shape_data* data = (shape_data*)fPrivateData; + shape_data* otherData = (shape_data*)otherShape->fPrivateData; if (!AllocateOps(otherData->opCount) || !AllocatePts(otherData->ptCount)) return B_NO_MEMORY; @@ -287,7 +348,7 @@ BShape::AddShape(const BShape *otherShape) status_t BShape::MoveTo(BPoint point) { - shape_data *data = (shape_data*)fPrivateData; + shape_data* data = (shape_data*)fPrivateData; // If the last op is MoveTo, replace the point if (fBuildingOp == OP_MOVETO) { @@ -316,7 +377,7 @@ BShape::LineTo(BPoint point) if (!AllocatePts(1)) return B_NO_MEMORY; - shape_data *data = (shape_data*)fPrivateData; + 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 @@ -341,11 +402,19 @@ BShape::LineTo(BPoint point) 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; + 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 @@ -362,9 +431,54 @@ BShape::BezierTo(BPoint controlPoints[3]) } // Add points - data->ptList[data->ptCount++] = controlPoints[0]; - data->ptList[data->ptCount++] = controlPoints[1]; - data->ptList[data->ptCount++] = controlPoints[2]; + 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; } @@ -380,7 +494,7 @@ BShape::Close() if (!AllocateOps(1)) return B_NO_MEMORY; - shape_data *data = (shape_data*)fPrivateData; + 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 @@ -398,7 +512,7 @@ BShape::Close() status_t -BShape::Perform(perform_code d, void *arg) +BShape::Perform(perform_code d, void* arg) { return BArchivable::Perform(d, arg); } @@ -411,10 +525,10 @@ void BShape::_ReservedShape4() {} void -BShape::GetData(int32 *opCount, int32 *ptCount, uint32 **opList, - BPoint **ptList) +BShape::GetData(int32* opCount, int32* ptCount, uint32** opList, + BPoint** ptList) { - shape_data *data = (shape_data*)fPrivateData; + shape_data* data = (shape_data*)fPrivateData; *opCount = data->opCount; *ptCount = data->ptCount; @@ -424,15 +538,15 @@ BShape::GetData(int32 *opCount, int32 *ptCount, uint32 **opList, void -BShape::SetData(int32 opCount, int32 ptCount, const uint32 *opList, - const BPoint *ptList) +BShape::SetData(int32 opCount, int32 ptCount, const uint32* opList, + const BPoint* ptList) { Clear(); if (opCount == 0) return; - shape_data *data = (shape_data*)fPrivateData; + shape_data* data = (shape_data*)fPrivateData; if (!AllocateOps(opCount) || !AllocatePts(ptCount)) return; @@ -454,7 +568,7 @@ void BShape::InitData() { fPrivateData = new shape_data; - shape_data *data = (shape_data*)fPrivateData; + shape_data* data = (shape_data*)fPrivateData; fState = 0; fBuildingOp = 0; @@ -471,7 +585,7 @@ BShape::InitData() inline bool BShape::AllocateOps(int32 count) { - shape_data *data = (shape_data*)fPrivateData; + shape_data* data = (shape_data*)fPrivateData; int32 newSize = (data->opCount + count + 255) / 256 * 256; if (data->opSize >= newSize) @@ -490,7 +604,7 @@ BShape::AllocateOps(int32 count) inline bool BShape::AllocatePts(int32 count) { - shape_data *data = (shape_data*)fPrivateData; + shape_data* data = (shape_data*)fPrivateData; int32 newSize = (data->ptCount + count + 255) / 256 * 256; if (data->ptSize >= newSize) @@ -506,11 +620,12 @@ BShape::AllocatePts(int32 count) } -// #pragma mark - R4.5 compatibility +// #pragma mark - binary compatibility #if __GNUC__ < 3 + extern "C" BShape* __6BShapeR6BShape(void* self, BShape& copyFrom) { @@ -520,9 +635,25 @@ __6BShapeR6BShape(void* self, BShape& copyFrom) extern "C" BRect -Bounds__6BShape(BShape *self) +Bounds__6BShape(BShape* self) { return self->Bounds(); } -#endif // __GNUC__ < 3 + +extern "C" void +_ReservedShapeIterator1__14BShapeIterator(BShapeIterator* self) +{ +} + + +#else // __GNUC__ < 3 + + +extern "C" void +_ZN14BShapeIterator23_ReservedShapeIterator1Ev(BShapeIterator* self) +{ +} + + +#endif // __GNUC__ >= 3 diff --git a/src/servers/app/ServerPicture.cpp b/src/servers/app/ServerPicture.cpp index 68fd4d341d..d1b19a0789 100644 --- a/src/servers/app/ServerPicture.cpp +++ b/src/servers/app/ServerPicture.cpp @@ -42,7 +42,7 @@ using std::stack; class ShapePainter : public BShapeIterator { public: - ShapePainter(); + ShapePainter(View* view); virtual ~ShapePainter(); status_t Iterate(const BShape* shape); @@ -51,16 +51,21 @@ public: virtual status_t IterateLineTo(int32 lineCount, BPoint* linePts); virtual status_t IterateBezierTo(int32 bezierCount, BPoint* bezierPts); virtual status_t IterateClose(); + virtual status_t IterateArcTo(float& rx, float& ry, + float& angle, bool largeArc, bool counterClockWise, BPoint& point); - void Draw(View* view, BRect frame, bool filled); + void Draw(BRect frame, bool filled); private: - stack fOpStack; - stack fPtStack; + View* fView; + stack fOpStack; + stack fPtStack; }; -ShapePainter::ShapePainter() +ShapePainter::ShapePainter(View* view) + : + fView(view) { } @@ -81,8 +86,14 @@ ShapePainter::Iterate(const BShape* shape) status_t ShapePainter::IterateMoveTo(BPoint* point) { - fOpStack.push(OP_MOVETO); - fPtStack.push(*point); + try { + fOpStack.push(OP_MOVETO); + BPoint transformed(*point); + fView->ConvertToScreenForDrawing(&transformed); + fPtStack.push(transformed); + } catch (std::bad_alloc) { + return B_NO_MEMORY; + } return B_OK; } @@ -91,9 +102,16 @@ ShapePainter::IterateMoveTo(BPoint* point) status_t ShapePainter::IterateLineTo(int32 lineCount, BPoint* linePts) { - fOpStack.push(OP_LINETO | lineCount); - for (int32 i = 0; i < lineCount; i++) - fPtStack.push(linePts[i]); + try { + fOpStack.push(OP_LINETO | lineCount); + for (int32 i = 0; i < lineCount; i++) { + BPoint transformed(linePts[i]); + fView->ConvertToScreenForDrawing(&transformed); + fPtStack.push(transformed); + } + } catch (std::bad_alloc) { + return B_NO_MEMORY; + } return B_OK; } @@ -103,27 +121,71 @@ status_t ShapePainter::IterateBezierTo(int32 bezierCount, BPoint* bezierPts) { bezierCount *= 3; - fOpStack.push(OP_BEZIERTO | bezierCount); - for (int32 i = 0; i < bezierCount; i++) - fPtStack.push(bezierPts[i]); + try { + fOpStack.push(OP_BEZIERTO | bezierCount); + for (int32 i = 0; i < bezierCount; i++) { + BPoint transformed(bezierPts[i]); + fView->ConvertToScreenForDrawing(&transformed); + fPtStack.push(transformed); + } + } catch (std::bad_alloc) { + return B_NO_MEMORY; + } return B_OK; } status_t -ShapePainter::IterateClose(void) +ShapePainter::IterateArcTo(float& rx, float& ry, + float& angle, bool largeArc, bool counterClockWise, BPoint& point) { - fOpStack.push(OP_CLOSE); + 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; + } + + try { + fOpStack.push(op | 3); + fPtStack.push(BPoint(rx * fView->Scale(), ry * fView->Scale())); + fPtStack.push(BPoint(angle, 0)); + BPoint transformed(point); + fView->ConvertToScreenForDrawing(&transformed); + fPtStack.push(transformed); + } catch (std::bad_alloc) { + return B_NO_MEMORY; + } + + return B_OK; +} + + +status_t +ShapePainter::IterateClose() +{ + try { + fOpStack.push(OP_CLOSE); + } catch (std::bad_alloc) { + return B_NO_MEMORY; + } return B_OK; } void -ShapePainter::Draw(View* view, BRect frame, bool filled) +ShapePainter::Draw(BRect frame, bool filled) { // We're going to draw the currently iterated shape. + // TODO: This can be more efficient by skipping the conversion. int32 opCount = fOpStack.size(); int32 ptCount = fPtStack.size(); @@ -144,14 +206,15 @@ ShapePainter::Draw(View* view, BRect frame, bool filled) fOpStack.pop(); } - for (i = (ptCount - 1); i >= 0; i--) { + for (i = ptCount - 1; i >= 0; i--) { ptList[i] = fPtStack.top(); fPtStack.pop(); - view->ConvertToScreenForDrawing(&ptList[i]); } - view->Window()->GetDrawingEngine()->DrawShape(frame, opCount, - opList, ptCount, ptList, filled); + BPoint offset; + fView->ConvertToScreenForDrawing(&offset); + fView->Window()->GetDrawingEngine()->DrawShape(frame, opCount, + opList, ptCount, ptList, filled, offset, fView->Scale()); delete[] opList; delete[] ptList; @@ -399,20 +462,20 @@ fill_polygon(View* view, int32 numPoints, const BPoint* viewPoints) static void stroke_shape(View* view, const BShape* shape) { - ShapePainter drawShape; + ShapePainter drawShape(view); drawShape.Iterate(shape); - drawShape.Draw(view, shape->Bounds(), false); + drawShape.Draw(shape->Bounds(), false); } static void fill_shape(View* view, const BShape* shape) { - ShapePainter drawShape; + ShapePainter drawShape(view); drawShape.Iterate(shape); - drawShape.Draw(view, shape->Bounds(), true); + drawShape.Draw(shape->Bounds(), true); } diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 4085b66823..18b9f62c12 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -2541,18 +2541,16 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, // this might seem a bit weird, but under R5, the shapes // are always offset by the current pen location - BPoint penLocation + BPoint screenOffset = fCurrentView->CurrentState()->PenLocation(); - for (int32 i = 0; i < ptCount; i++) { - ptList[i] += penLocation; - fCurrentView->ConvertToScreenForDrawing(&ptList[i]); - } + shapeFrame.OffsetBy(screenOffset); - shapeFrame.OffsetBy(penLocation); + fCurrentView->ConvertToScreenForDrawing(&screenOffset); fCurrentView->ConvertToScreenForDrawing(&shapeFrame); drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount, - ptList, code == AS_FILL_SHAPE); + ptList, code == AS_FILL_SHAPE, screenOffset, + fCurrentView->Scale()); } delete[] opList; @@ -2581,15 +2579,16 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, // this might seem a bit weird, but under R5, the shapes // are always offset by the current pen location - BPoint penLocation + BPoint screenOffset = fCurrentView->CurrentState()->PenLocation(); - for (int32 i = 0; i < ptCount; i++) { - ptList[i] += penLocation; - fCurrentView->ConvertToScreenForDrawing(&ptList[i]); - } + shapeFrame.OffsetBy(screenOffset); + + fCurrentView->ConvertToScreenForDrawing(&screenOffset); + fCurrentView->ConvertToScreenForDrawing(&shapeFrame); fCurrentView->ConvertToScreenForDrawing(gradient); drawingEngine->FillShape(shapeFrame, opCount, opList, - ptCount, ptList, *gradient); + ptCount, ptList, *gradient, screenOffset, + fCurrentView->Scale()); } delete[] opList; diff --git a/src/servers/app/drawing/DrawingEngine.cpp b/src/servers/app/drawing/DrawingEngine.cpp index 7f4dd6fc40..4e3a8367a6 100644 --- a/src/servers/app/drawing/DrawingEngine.cpp +++ b/src/servers/app/drawing/DrawingEngine.cpp @@ -150,7 +150,7 @@ DrawingEngine::LockExclusiveAccess() bool -DrawingEngine::IsExclusiveAccessLocked() +DrawingEngine::IsExclusiveAccessLocked() const { return fGraphicsCard->IsExclusiveAccessLocked(); } @@ -1141,16 +1141,30 @@ DrawingEngine::FillRoundRect(BRect r, float xrad, float yrad, void DrawingEngine::DrawShape(const BRect& bounds, int32 opCount, - const uint32* opList, int32 ptCount, const BPoint* ptList, bool filled) + const uint32* opList, int32 ptCount, const BPoint* ptList, bool filled, + const BPoint& viewToScreenOffset, float viewScale) { ASSERT_PARALLEL_LOCKED(); - // NOTE: hides cursor regardless of if and where - // shape is drawn on screen, TODO: optimize +// TODO: bounds probably does not take curves and arcs into account... +// BRect clipped(bounds); +// if (!filled) +// extend_by_stroke_width(clipped, fPainter->PenSize()); +// clipped = fPainter->ClipRect(bounds); +// +// clipped.left = floorf(clipped.left); +// clipped.top = floorf(clipped.top); +// clipped.right = ceilf(clipped.right); +// clipped.bottom = ceilf(clipped.bottom); +// +// if (!clipped.IsValid()) +// return; +// +// AutoFloatingOverlaysHider _(fGraphicsCard, clipped); AutoFloatingOverlaysHider _(fGraphicsCard); BRect touched = fPainter->DrawShape(opCount, opList, ptCount, ptList, - filled); + filled, viewToScreenOffset, viewScale); _CopyToFront(touched); } @@ -1159,16 +1173,27 @@ DrawingEngine::DrawShape(const BRect& bounds, int32 opCount, void DrawingEngine::FillShape(const BRect& bounds, int32 opCount, const uint32* opList, int32 ptCount, const BPoint* ptList, - const BGradient& gradient) + const BGradient& gradient, const BPoint& viewToScreenOffset, + float viewScale) { ASSERT_PARALLEL_LOCKED(); - // NOTE: hides cursor regardless of if and where - // shape is drawn on screen, TODO: optimize +// TODO: bounds probably does not take curves and arcs into account... +// BRect clipped = fPainter->ClipRect(bounds); +// +// clipped.left = floorf(clipped.left); +// clipped.top = floorf(clipped.top); +// clipped.right = ceilf(clipped.right); +// clipped.bottom = ceilf(clipped.bottom); +// +// if (!clipped.IsValid()) +// return; +// +// AutoFloatingOverlaysHider _(fGraphicsCard, clipped); AutoFloatingOverlaysHider _(fGraphicsCard); BRect touched = fPainter->FillShape(opCount, opList, ptCount, ptList, - gradient); + gradient, viewToScreenOffset, viewScale); _CopyToFront(touched); } diff --git a/src/servers/app/drawing/DrawingEngine.h b/src/servers/app/drawing/DrawingEngine.h index d9aee5e7cb..ce89487ea3 100644 --- a/src/servers/app/drawing/DrawingEngine.h +++ b/src/servers/app/drawing/DrawingEngine.h @@ -56,7 +56,7 @@ public: void UnlockParallelAccess(); bool LockExclusiveAccess(); - virtual bool IsExclusiveAccessLocked(); + virtual bool IsExclusiveAccessLocked() const; void UnlockExclusiveAccess(); // for screen shots @@ -138,11 +138,14 @@ public: virtual void DrawShape(const BRect& bounds, int32 opcount, const uint32* oplist, int32 ptcount, const BPoint* ptlist, - bool filled); + bool filled, const BPoint& viewToScreenOffset, + float viewScale); virtual void FillShape(const BRect& bounds, - int32 opcount, const uint32* oplist, - int32 ptcount, const BPoint* ptlist, - const BGradient& gradient); + int32 opcount, const uint32* oplist, + int32 ptcount, const BPoint* ptlist, + const BGradient& gradient, + const BPoint& viewToScreenOffset, + float viewScale); virtual void DrawTriangle(BPoint* points, const BRect& bounds, bool filled); diff --git a/src/servers/app/drawing/Painter/Painter.cpp b/src/servers/app/drawing/Painter/Painter.cpp index 0231e5498c..18729ab56c 100644 --- a/src/servers/app/drawing/Painter/Painter.cpp +++ b/src/servers/app/drawing/Painter/Painter.cpp @@ -668,28 +668,31 @@ Painter::FillBezier(BPoint* p, const BGradient& gradient) const } -// DrawShape -BRect -Painter::DrawShape(const int32& opCount, const uint32* opList, - const int32& ptCount, const BPoint* points, bool filled) const +static void +iterate_shape_data(agg::path_storage& path, + const int32& opCount, const uint32* opList, + const int32& ptCount, const BPoint* points, + const BPoint& viewToScreenOffset, float viewScale) { - CHECK_CLIPPING - // TODO: if shapes are ever used more heavily in Haiku, // it would be nice to use BShape data directly (write // an AGG "VertexSource" adaptor) - fPath.remove_all(); + path.remove_all(); for (int32 i = 0; i < opCount; i++) { uint32 op = opList[i] & 0xFF000000; if (op & OP_MOVETO) { - fPath.move_to(points->x, points->y); + path.move_to( + points->x * viewScale + viewToScreenOffset.x, + points->y * viewScale + viewToScreenOffset.y); points++; } if (op & OP_LINETO) { int32 count = opList[i] & 0x00FFFFFF; while (count--) { - fPath.line_to(points->x, points->y); + path.line_to( + points->x * viewScale + viewToScreenOffset.x, + points->y * viewScale + viewToScreenOffset.y); points++; } } @@ -697,16 +700,51 @@ Painter::DrawShape(const int32& opCount, const uint32* opList, if (op & OP_BEZIERTO) { int32 count = opList[i] & 0x00FFFFFF; while (count) { - fPath.curve4(points[0].x, points[0].y, points[1].x, points[1].y, - points[2].x, points[2].y); + path.curve4( + points[0].x * viewScale + viewToScreenOffset.x, + points[0].y * viewScale + viewToScreenOffset.y, + points[1].x * viewScale + viewToScreenOffset.x, + points[1].y * viewScale + viewToScreenOffset.y, + points[2].x * viewScale + viewToScreenOffset.x, + points[2].y * viewScale + viewToScreenOffset.y); + points += 3; + count -= 3; + } + } + + 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 = opList[i] & 0x00FFFFFF; + while (count) { + path.arc_to( + points[0].x * viewScale, + points[0].y * viewScale, + points[1].x, + op & (OP_LARGE_ARC_TO_CW | OP_LARGE_ARC_TO_CCW), + op & (OP_SMALL_ARC_TO_CW | OP_LARGE_ARC_TO_CW), + points[2].x * viewScale + viewToScreenOffset.x, + points[2].y * viewScale + viewToScreenOffset.y); points += 3; count -= 3; } } if (op & OP_CLOSE) - fPath.close_polygon(); + path.close_polygon(); } +} + + +// DrawShape +BRect +Painter::DrawShape(const int32& opCount, const uint32* opList, + const int32& ptCount, const BPoint* points, bool filled, + const BPoint& viewToScreenOffset, float viewScale) const +{ + CHECK_CLIPPING + + iterate_shape_data(fPath, opCount, opList, ptCount, points, + viewToScreenOffset, viewScale); if (filled) return _FillPath(fCurve); @@ -718,42 +756,13 @@ Painter::DrawShape(const int32& opCount, const uint32* opList, // FillShape BRect Painter::FillShape(const int32& opCount, const uint32* opList, - const int32& ptCount, const BPoint* points, const BGradient& gradient) const + const int32& ptCount, const BPoint* points, const BGradient& gradient, + const BPoint& viewToScreenOffset, float viewScale) const { CHECK_CLIPPING - // TODO: if shapes are ever used more heavily in Haiku, - // it would be nice to use BShape data directly (write - // an AGG "VertexSource" adaptor) - fPath.remove_all(); - for (int32 i = 0; i < opCount; i++) { - uint32 op = opList[i] & 0xFF000000; - if (op & OP_MOVETO) { - fPath.move_to(points->x, points->y); - points++; - } - - if (op & OP_LINETO) { - int32 count = opList[i] & 0x00FFFFFF; - while (count--) { - fPath.line_to(points->x, points->y); - points++; - } - } - - if (op & OP_BEZIERTO) { - int32 count = opList[i] & 0x00FFFFFF; - while (count) { - fPath.curve4(points[0].x, points[0].y, points[1].x, points[1].y, - points[2].x, points[2].y); - points += 3; - count -= 3; - } - } - - if (op & OP_CLOSE) - fPath.close_polygon(); - } + iterate_shape_data(fPath, opCount, opList, ptCount, points, + viewToScreenOffset, viewScale); return _FillPath(fCurve, gradient); } diff --git a/src/servers/app/drawing/Painter/Painter.h b/src/servers/app/drawing/Painter/Painter.h index 29638e4ffa..5192ceae65 100644 --- a/src/servers/app/drawing/Painter/Painter.h +++ b/src/servers/app/drawing/Painter/Painter.h @@ -50,7 +50,7 @@ class Transformable; class Painter { - public: +public: Painter(); virtual ~Painter(); @@ -132,12 +132,15 @@ class Painter { // shapes BRect DrawShape(const int32& opCount, const uint32* opList, const int32& ptCount, - const BPoint* ptList, bool filled) const; + const BPoint* ptList, bool filled, + const BPoint& viewToScreenOffset, + float viewScale) const; BRect FillShape(const int32& opCount, - const uint32* opList, - const int32& ptCount, + const uint32* opList, const int32& ptCount, const BPoint* ptList, - const BGradient& gradient) const; + const BGradient& gradient, + const BPoint& viewToScreenOffset, + float viewScale) const; // rects BRect StrokeRect(const BRect& r) const; @@ -237,7 +240,7 @@ class Painter { inline BRect AlignAndClipRect(BRect rect) const; - private: +private: void _Transform(BPoint* point, bool centerOffset = true) const; BPoint _Transform(const BPoint& point, @@ -330,46 +333,46 @@ class Painter { void _FillPathGradientConic(VertexSource& path, const BGradientConic& conic) const; -mutable agg::rendering_buffer fBuffer; + mutable agg::rendering_buffer fBuffer; // AGG rendering and rasterization classes - pixfmt fPixelFormat; -mutable renderer_base fBaseRenderer; + pixfmt fPixelFormat; + mutable renderer_base fBaseRenderer; -mutable scanline_unpacked_type fUnpackedScanline; -mutable scanline_packed_type fPackedScanline; -mutable scanline_packed_subpix_type fSubpixPackedScanline; -mutable scanline_unpacked_subpix_type fSubpixUnpackedScanline; -mutable rasterizer_subpix_type fSubpixRasterizer; -mutable rasterizer_type fRasterizer; -mutable renderer_subpix_type fSubpixRenderer; -mutable renderer_type fRenderer; -mutable renderer_bin_type fRendererBin; + mutable scanline_unpacked_type fUnpackedScanline; + mutable scanline_packed_type fPackedScanline; + mutable scanline_packed_subpix_type fSubpixPackedScanline; + mutable scanline_unpacked_subpix_type fSubpixUnpackedScanline; + mutable rasterizer_subpix_type fSubpixRasterizer; + mutable rasterizer_type fRasterizer; + mutable renderer_subpix_type fSubpixRenderer; + mutable renderer_type fRenderer; + mutable renderer_bin_type fRendererBin; -mutable agg::path_storage fPath; -mutable agg::conv_curve fCurve; + mutable agg::path_storage fPath; + mutable agg::conv_curve fCurve; // for internal coordinate rounding/transformation - bool fSubpixelPrecise : 1; - bool fValidClipping : 1; - bool fDrawingText : 1; - bool fAttached : 1; + bool fSubpixelPrecise : 1; + bool fValidClipping : 1; + bool fDrawingText : 1; + bool fAttached : 1; - float fPenSize; - const BRegion* fClippingRegion; - drawing_mode fDrawingMode; - source_alpha fAlphaSrcMode; - alpha_function fAlphaFncMode; - cap_mode fLineCapMode; - join_mode fLineJoinMode; - float fMiterLimit; + float fPenSize; + const BRegion* fClippingRegion; + drawing_mode fDrawingMode; + source_alpha fAlphaSrcMode; + alpha_function fAlphaFncMode; + cap_mode fLineCapMode; + join_mode fLineJoinMode; + float fMiterLimit; - PatternHandler fPatternHandler; + PatternHandler fPatternHandler; // a class handling rendering and caching of glyphs // it is setup to load from a specific Freetype supported // font file which it gets from ServerFont -mutable AGGTextRenderer fTextRenderer; + mutable AGGTextRenderer fTextRenderer; }; @@ -383,6 +386,7 @@ Painter::ClipRect(BRect rect) const return _Clipped(rect); } + inline BRect Painter::AlignAndClipRect(BRect rect) const { diff --git a/src/servers/app/drawing/remote/RemoteDrawingEngine.cpp b/src/servers/app/drawing/remote/RemoteDrawingEngine.cpp index 75028029b0..4feabff161 100644 --- a/src/servers/app/drawing/remote/RemoteDrawingEngine.cpp +++ b/src/servers/app/drawing/remote/RemoteDrawingEngine.cpp @@ -12,6 +12,7 @@ #include "DrawState.h" #include +#include #include @@ -682,7 +683,7 @@ RemoteDrawingEngine::FillRoundRect(BRect rect, float xRadius, float yRadius, void RemoteDrawingEngine::DrawShape(const BRect& bounds, int32 opCount, const uint32* opList, int32 pointCount, const BPoint* pointList, - bool filled) + bool filled, const BPoint& viewToScreenOffset, float viewScale) { BRect clipBounds = bounds; if (!filled) @@ -699,13 +700,15 @@ RemoteDrawingEngine::DrawShape(const BRect& bounds, int32 opCount, message.AddList(opList, opCount); message.Add(pointCount); message.AddList(pointList, pointCount); + // TODO: viewToScreenOffset and viewScale } void RemoteDrawingEngine::FillShape(const BRect& bounds, int32 opCount, const uint32* opList, int32 pointCount, const BPoint* pointList, - const BGradient& gradient) + const BGradient& gradient, const BPoint& viewToScreenOffset, + float viewScale) { if (!fClippingRegion.Intersects(bounds)) return; @@ -719,6 +722,7 @@ RemoteDrawingEngine::FillShape(const BRect& bounds, int32 opCount, message.Add(pointCount); message.AddList(pointList, pointCount); message.AddGradient(gradient); + // TODO: viewToScreenOffset and viewScale } @@ -824,6 +828,37 @@ RemoteDrawingEngine::DrawString(const char* string, int32 length, } +BPoint +RemoteDrawingEngine::DrawString(const char* string, int32 length, + const BPoint* offsets) +{ + // Guaranteed to have at least one point. + RemoteMessage message(NULL, fHWInterface->SendBuffer()); + + message.Start(RP_DRAW_STRING_WITH_OFFSETS); + message.Add(fToken); + message.AddString(string, length); + message.AddList(offsets, UTF8CountChars(string, length)); + + status_t result = _AddCallback(); + if (message.Flush() != B_OK) + return offsets[0]; + + if (result != B_OK) + return offsets[0]; + + do { + result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT, + 1 * 1000 * 1000); + } while (result == B_INTERRUPTED); + + if (result != B_OK) + return offsets[0]; + + return fDrawStringResult; +} + + float RemoteDrawingEngine::StringWidth(const char* string, int32 length, escapement_delta* delta) diff --git a/src/servers/app/drawing/remote/RemoteDrawingEngine.h b/src/servers/app/drawing/remote/RemoteDrawingEngine.h index 1d25bf9d5e..8767a10c17 100644 --- a/src/servers/app/drawing/remote/RemoteDrawingEngine.h +++ b/src/servers/app/drawing/remote/RemoteDrawingEngine.h @@ -107,11 +107,15 @@ virtual void FillRoundRect(BRect rect, float xRadius, virtual void DrawShape(const BRect& bounds, int32 opCount, const uint32* opList, int32 pointCount, const BPoint* pointList, - bool filled); + bool filled, + const BPoint& viewToScreenOffset, + float viewScale); virtual void FillShape(const BRect& bounds, int32 opCount, const uint32* opList, int32 pointCount, const BPoint* pointList, - const BGradient& gradient); + const BGradient& gradient, + const BPoint& viewToScreenOffset, + float viewScale); virtual void DrawTriangle(BPoint* points, const BRect& bounds, bool filled); @@ -131,6 +135,8 @@ virtual void StrokeLineArray(int32 numlines, virtual BPoint DrawString(const char* string, int32 length, const BPoint& point, escapement_delta* delta = NULL); +virtual BPoint DrawString(const char* string, int32 length, + const BPoint* offsets); virtual float StringWidth(const char* string, int32 length, escapement_delta* delta = NULL); diff --git a/src/servers/app/drawing/remote/RemoteMessage.h b/src/servers/app/drawing/remote/RemoteMessage.h index 8cd97fbe35..f32e19d85e 100644 --- a/src/servers/app/drawing/remote/RemoteMessage.h +++ b/src/servers/app/drawing/remote/RemoteMessage.h @@ -100,6 +100,7 @@ enum { RP_FILL_REGION_COLOR_NO_CLIPPING, RP_DRAW_STRING = 180, + RP_DRAW_STRING_WITH_OFFSETS, RP_DRAW_STRING_RESULT, RP_STRING_WIDTH, RP_STRING_WIDTH_RESULT, diff --git a/src/tests/servers/app/Jamfile b/src/tests/servers/app/Jamfile index 0f24d68519..cadb857ca5 100644 --- a/src/tests/servers/app/Jamfile +++ b/src/tests/servers/app/Jamfile @@ -192,6 +192,7 @@ SubInclude HAIKU_TOP src tests servers app regularapps ; SubInclude HAIKU_TOP src tests servers app resize_limits ; SubInclude HAIKU_TOP src tests servers app scrollbar ; SubInclude HAIKU_TOP src tests servers app scrolling ; +SubInclude HAIKU_TOP src tests servers app shape_test ; SubInclude HAIKU_TOP src tests servers app statusbar ; SubInclude HAIKU_TOP src tests servers app stress_test ; SubInclude HAIKU_TOP src tests servers app textview ; diff --git a/src/tests/servers/app/shape_test/Jamfile b/src/tests/servers/app/shape_test/Jamfile new file mode 100644 index 0000000000..458b78afa4 --- /dev/null +++ b/src/tests/servers/app/shape_test/Jamfile @@ -0,0 +1,17 @@ +SubDir HAIKU_TOP src tests servers app shape_test ; + +SetSubDirSupportedPlatformsBeOSCompatible ; +AddSubDirSupportedPlatforms libbe_test ; + +UseHeaders [ FDirName os app ] ; +UseHeaders [ FDirName os interface ] ; + +SimpleTest ShapeTest : + main.cpp + : be $(TARGET_LIBSUPC++) + ; + +if ( $(TARGET_PLATFORM) = libbe_test ) { + HaikuInstall install-test-apps : $(HAIKU_APP_TEST_DIR) : ShapeTest + : tests!apps ; +} diff --git a/src/tests/servers/app/shape_test/main.cpp b/src/tests/servers/app/shape_test/main.cpp new file mode 100644 index 0000000000..c5f2548ae7 --- /dev/null +++ b/src/tests/servers/app/shape_test/main.cpp @@ -0,0 +1,181 @@ +#include +#include + +#include +#include +#include +#include +#include + + +static const char* kAppSignature = "application/x.vnd-Haiku.ShapeTest"; + + +class TestView : public BView { +public: + TestView(BRect frame, const char* name, + uint32 resizeFlags, uint32 flags); + + virtual void Draw(BRect updateRect); +}; + + +TestView::TestView(BRect frame, const char* name, uint32 resizeFlags, + uint32 flags) + : + BView(frame, name, resizeFlags, flags) +{ +} + + +void +TestView::Draw(BRect updateRect) +{ + BRect r(Bounds()); + + SetDrawingMode(B_OP_ALPHA); + SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); + SetHighColor(0, 0, 0, 240); + + class TranslateIterator : public BShapeIterator { + public: + TranslateIterator() + : + fOffsetX(0), + fOffsetY(0) + { + } + + TranslateIterator(float offsetX, float offsetY) + : + fOffsetX(offsetX), + fOffsetY(offsetY) + { + } + + void SetOffset(float offsetX, float offsetY) + { + fOffsetX = offsetX; + fOffsetY = offsetY; + } + + virtual status_t IterateMoveTo(BPoint* point) + { + point->x += fOffsetX; + point->y += fOffsetY; + return B_OK; + } + + virtual status_t IterateLineTo(int32 lineCount, BPoint* linePts) + { + while (lineCount--) { + linePts->x += fOffsetX; + linePts->y += fOffsetY; + linePts++; + } + return B_OK; + } + + virtual status_t IterateBezierTo(int32 bezierCount, BPoint* bezierPts) + { + while (bezierCount--) { + bezierPts[0].x += fOffsetX; + bezierPts[0].y += fOffsetY; + bezierPts[1].x += fOffsetX; + bezierPts[1].y += fOffsetY; + bezierPts[2].x += fOffsetX; + bezierPts[2].y += fOffsetY; + bezierPts += 3; + } + return B_OK; + } + + virtual status_t IterateArcTo(float& rx, float& ry, float& angle, + bool largeArc, bool counterClockWise, BPoint& point) + { + point.x += fOffsetX; + point.y += fOffsetY; + return B_OK; + } + + private: + float fOffsetX; + float fOffsetY; + } translator; + + MovePenTo(B_ORIGIN); + + const float arcRX = 50; + const float arcRY = 80; + + BShape shape; + shape.MoveTo(BPoint(20, 10)); + shape.LineTo(BPoint(10, 90)); + shape.LineTo(BPoint(90, 100)); + shape.ArcTo(arcRX, arcRY, 45, true, true, BPoint(100, 20)); + shape.Close(); + + StrokeShape(&shape); + + shape.Clear(); + shape.MoveTo(BPoint(20, 10)); + shape.LineTo(BPoint(10, 90)); + shape.LineTo(BPoint(90, 100)); + shape.ArcTo(arcRX, arcRY, 45, false, true, BPoint(100, 20)); + shape.Close(); + + translator.SetOffset(10, 10); + translator.Iterate(&shape); + + SetHighColor(140, 30, 50, 255); + StrokeShape(&shape); + + shape.Clear(); + shape.MoveTo(BPoint(20, 10)); + shape.LineTo(BPoint(10, 90)); + shape.LineTo(BPoint(90, 100)); + shape.ArcTo(arcRX, arcRY, 45, true, false, BPoint(100, 20)); + shape.Close(); + + translator.SetOffset(20, 20); + translator.Iterate(&shape); + + SetHighColor(140, 130, 50, 255); + StrokeShape(&shape); + + shape.Clear(); + shape.MoveTo(BPoint(20, 10)); + shape.LineTo(BPoint(10, 90)); + shape.LineTo(BPoint(90, 100)); + shape.ArcTo(arcRX, arcRY, 45, false, false, BPoint(100, 20)); + shape.Close(); + + translator.SetOffset(30, 30); + translator.Iterate(&shape); + + SetHighColor(40, 130, 150, 255); + StrokeShape(&shape); +} + + +// #pragma mark - + + +int +main(int argc, char** argv) +{ + BApplication app(kAppSignature); + + BWindow* window = new BWindow(BRect(50.0, 50.0, 300.0, 250.0), + "BShape Test", B_TITLED_WINDOW, + B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE); + + BView* view = new TestView(window->Bounds(), "test", B_FOLLOW_ALL, + B_WILL_DRAW); + window->AddChild(view); + + window->Show(); + + app.Run(); + return 0; +}