Basically, this changeset implements BShape::ArcTo(). In more detail:

* Added BShape::ArcTo() and BShapeIterator::IterateArcTo(), using a previously
   unused virtual slot. (Added the symbols for binary compatibility for GCC2
   and GCC4.)
 * Added operator=(), operator==() and operator!=() to BShape.
 * Added BShape::BezierTo() version taking three points, which is sometimes
   more convenient.
 * Added the four new shape data ops OP_LARGE_ARC_TO_CW, OP_LARGE_ARC_TO_CCW,
   OP_SMALL_ARC_TO_CW and OP_SMALL_ARC_TO_CCW. For a single arc, provided the
   radius is large enough, there are four possibilities to draw the arc, these
   are controlled by the two boolean flags to ArcTo() and mapped to the new
   commands accordingly.
 * Some style cleanup in Shape.cpp (sorry for mixing it up, but it gets
   worse below...)
 * Added ShapeTest to src/tests/servers/app.
 * Changed the way BShapes are transformed from view to screen space in the
   app_server. For arcs, it would be nontrivial to apply a proper transformation,
   it's much easier to let AGG take care of it. This affects ServerPicture as
   well.
 * Wrapped iterating the BShape into try/catch blocks in ShapeIterator. But
   I really don't understand the purpose of the class in the first place.
   Maybe it can now be dropped, since coordinates don't have to be transformed
   in place anymore.
 * Refactored copy&paste shape iteration code in Painter. The transformation
   to screen space happens there.
 * Since RemoteDrawingEngine needed to be adopted anyway, I also updated
   it for the new DrawString() with offsets version. But the client still needs
   to be adapted.
 * Style cleanup in Painter.h


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35905 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2010-03-18 16:58:19 +00:00
parent fe0963a835
commit 76ab3f88df
15 changed files with 684 additions and 190 deletions

View File

@ -30,10 +30,13 @@ public:
BPoint* bezierPts); BPoint* bezierPts);
virtual status_t IterateClose(); 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); status_t Iterate(BShape* shape);
private: private:
virtual void _ReservedShapeIterator1();
virtual void _ReservedShapeIterator2(); virtual void _ReservedShapeIterator2();
virtual void _ReservedShapeIterator3(); virtual void _ReservedShapeIterator3();
virtual void _ReservedShapeIterator4(); virtual void _ReservedShapeIterator4();
@ -53,6 +56,11 @@ public:
virtual status_t Archive(BMessage* archive, virtual status_t Archive(BMessage* archive,
bool deep = true) const; bool deep = true) const;
BShape& operator=(const BShape& other);
bool operator==(const BShape& other) const;
bool operator!=(const BShape& other) const;
void Clear(); void Clear();
BRect Bounds() const; BRect Bounds() const;
@ -61,6 +69,13 @@ public:
status_t MoveTo(BPoint point); status_t MoveTo(BPoint point);
status_t LineTo(BPoint linePoint); status_t LineTo(BPoint linePoint);
status_t BezierTo(BPoint controlPoints[3]); 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(); status_t Close();
private: private:

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2003-2006, Haiku. * Copyright 2003-2010, Haiku.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -13,6 +13,10 @@
#define OP_BEZIERTO 0x20000000 #define OP_BEZIERTO 0x20000000
#define OP_CLOSE 0x40000000 #define OP_CLOSE 0x40000000
#define OP_MOVETO 0x80000000 #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 { struct shape_data {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001-2007, Haiku, Inc. * Copyright (c) 2001-2010, Haiku, Inc.
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Authors: * Authors:
@ -62,6 +62,18 @@ BShapeIterator::Iterate(BShape *shape)
points += count; 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) { if (op & OP_CLOSE) {
IterateClose(); IterateClose();
} }
@ -72,15 +84,7 @@ BShapeIterator::Iterate(BShape *shape)
status_t status_t
BShapeIterator::IterateBezierTo(int32 bezierCount, BShapeIterator::IterateMoveTo(BPoint* point)
BPoint *bezierPoints)
{
return B_OK;
}
status_t
BShapeIterator::IterateClose()
{ {
return B_OK; return B_OK;
} }
@ -94,18 +98,35 @@ BShapeIterator::IterateLineTo(int32 lineCount, BPoint *linePoints)
status_t status_t
BShapeIterator::IterateMoveTo ( BPoint *point ) 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; return B_OK;
} }
void BShapeIterator::_ReservedShapeIterator1() {}
void BShapeIterator::_ReservedShapeIterator2() {} void BShapeIterator::_ReservedShapeIterator2() {}
void BShapeIterator::_ReservedShapeIterator3() {} void BShapeIterator::_ReservedShapeIterator3() {}
void BShapeIterator::_ReservedShapeIterator4() {} void BShapeIterator::_ReservedShapeIterator4() {}
// #pragma mark -
BShape::BShape() BShape::BShape()
{ {
InitData(); InitData();
@ -207,6 +228,46 @@ 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 void
BShape::Clear() BShape::Clear()
{ {
@ -341,6 +402,14 @@ BShape::LineTo(BPoint point)
status_t status_t
BShape::BezierTo(BPoint controlPoints[3]) 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)) if (!AllocatePts(3))
return B_NO_MEMORY; return B_NO_MEMORY;
@ -362,9 +431,54 @@ BShape::BezierTo(BPoint controlPoints[3])
} }
// Add points // Add points
data->ptList[data->ptCount++] = controlPoints[0]; data->ptList[data->ptCount++] = control1;
data->ptList[data->ptCount++] = controlPoints[1]; data->ptList[data->ptCount++] = control2;
data->ptList[data->ptCount++] = controlPoints[2]; 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; return B_OK;
} }
@ -506,11 +620,12 @@ BShape::AllocatePts(int32 count)
} }
// #pragma mark - R4.5 compatibility // #pragma mark - binary compatibility
#if __GNUC__ < 3 #if __GNUC__ < 3
extern "C" BShape* extern "C" BShape*
__6BShapeR6BShape(void* self, BShape& copyFrom) __6BShapeR6BShape(void* self, BShape& copyFrom)
{ {
@ -525,4 +640,20 @@ Bounds__6BShape(BShape *self)
return self->Bounds(); 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

View File

@ -42,7 +42,7 @@ using std::stack;
class ShapePainter : public BShapeIterator { class ShapePainter : public BShapeIterator {
public: public:
ShapePainter(); ShapePainter(View* view);
virtual ~ShapePainter(); virtual ~ShapePainter();
status_t Iterate(const BShape* shape); status_t Iterate(const BShape* shape);
@ -51,16 +51,21 @@ public:
virtual status_t IterateLineTo(int32 lineCount, BPoint* linePts); virtual status_t IterateLineTo(int32 lineCount, BPoint* linePts);
virtual status_t IterateBezierTo(int32 bezierCount, BPoint* bezierPts); virtual status_t IterateBezierTo(int32 bezierCount, BPoint* bezierPts);
virtual status_t IterateClose(); 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: private:
View* fView;
stack<uint32> fOpStack; stack<uint32> fOpStack;
stack<BPoint> fPtStack; stack<BPoint> fPtStack;
}; };
ShapePainter::ShapePainter() ShapePainter::ShapePainter(View* view)
:
fView(view)
{ {
} }
@ -81,8 +86,14 @@ ShapePainter::Iterate(const BShape* shape)
status_t status_t
ShapePainter::IterateMoveTo(BPoint* point) ShapePainter::IterateMoveTo(BPoint* point)
{ {
try {
fOpStack.push(OP_MOVETO); fOpStack.push(OP_MOVETO);
fPtStack.push(*point); BPoint transformed(*point);
fView->ConvertToScreenForDrawing(&transformed);
fPtStack.push(transformed);
} catch (std::bad_alloc) {
return B_NO_MEMORY;
}
return B_OK; return B_OK;
} }
@ -91,9 +102,16 @@ ShapePainter::IterateMoveTo(BPoint* point)
status_t status_t
ShapePainter::IterateLineTo(int32 lineCount, BPoint* linePts) ShapePainter::IterateLineTo(int32 lineCount, BPoint* linePts)
{ {
try {
fOpStack.push(OP_LINETO | lineCount); fOpStack.push(OP_LINETO | lineCount);
for (int32 i = 0; i < lineCount; i++) for (int32 i = 0; i < lineCount; i++) {
fPtStack.push(linePts[i]); BPoint transformed(linePts[i]);
fView->ConvertToScreenForDrawing(&transformed);
fPtStack.push(transformed);
}
} catch (std::bad_alloc) {
return B_NO_MEMORY;
}
return B_OK; return B_OK;
} }
@ -103,27 +121,71 @@ status_t
ShapePainter::IterateBezierTo(int32 bezierCount, BPoint* bezierPts) ShapePainter::IterateBezierTo(int32 bezierCount, BPoint* bezierPts)
{ {
bezierCount *= 3; bezierCount *= 3;
try {
fOpStack.push(OP_BEZIERTO | bezierCount); fOpStack.push(OP_BEZIERTO | bezierCount);
for (int32 i = 0; i < bezierCount; i++) for (int32 i = 0; i < bezierCount; i++) {
fPtStack.push(bezierPts[i]); BPoint transformed(bezierPts[i]);
fView->ConvertToScreenForDrawing(&transformed);
fPtStack.push(transformed);
}
} catch (std::bad_alloc) {
return B_NO_MEMORY;
}
return B_OK; return B_OK;
} }
status_t status_t
ShapePainter::IterateClose(void) ShapePainter::IterateArcTo(float& rx, float& ry,
float& angle, bool largeArc, bool counterClockWise, BPoint& point)
{ {
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); fOpStack.push(OP_CLOSE);
} catch (std::bad_alloc) {
return B_NO_MEMORY;
}
return B_OK; return B_OK;
} }
void void
ShapePainter::Draw(View* view, BRect frame, bool filled) ShapePainter::Draw(BRect frame, bool filled)
{ {
// We're going to draw the currently iterated shape. // We're going to draw the currently iterated shape.
// TODO: This can be more efficient by skipping the conversion.
int32 opCount = fOpStack.size(); int32 opCount = fOpStack.size();
int32 ptCount = fPtStack.size(); int32 ptCount = fPtStack.size();
@ -144,14 +206,15 @@ ShapePainter::Draw(View* view, BRect frame, bool filled)
fOpStack.pop(); fOpStack.pop();
} }
for (i = (ptCount - 1); i >= 0; i--) { for (i = ptCount - 1; i >= 0; i--) {
ptList[i] = fPtStack.top(); ptList[i] = fPtStack.top();
fPtStack.pop(); fPtStack.pop();
view->ConvertToScreenForDrawing(&ptList[i]);
} }
view->Window()->GetDrawingEngine()->DrawShape(frame, opCount, BPoint offset;
opList, ptCount, ptList, filled); fView->ConvertToScreenForDrawing(&offset);
fView->Window()->GetDrawingEngine()->DrawShape(frame, opCount,
opList, ptCount, ptList, filled, offset, fView->Scale());
delete[] opList; delete[] opList;
delete[] ptList; delete[] ptList;
@ -399,20 +462,20 @@ fill_polygon(View* view, int32 numPoints, const BPoint* viewPoints)
static void static void
stroke_shape(View* view, const BShape* shape) stroke_shape(View* view, const BShape* shape)
{ {
ShapePainter drawShape; ShapePainter drawShape(view);
drawShape.Iterate(shape); drawShape.Iterate(shape);
drawShape.Draw(view, shape->Bounds(), false); drawShape.Draw(shape->Bounds(), false);
} }
static void static void
fill_shape(View* view, const BShape* shape) fill_shape(View* view, const BShape* shape)
{ {
ShapePainter drawShape; ShapePainter drawShape(view);
drawShape.Iterate(shape); drawShape.Iterate(shape);
drawShape.Draw(view, shape->Bounds(), true); drawShape.Draw(shape->Bounds(), true);
} }

View File

@ -2541,18 +2541,16 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code,
// this might seem a bit weird, but under R5, the shapes // this might seem a bit weird, but under R5, the shapes
// are always offset by the current pen location // are always offset by the current pen location
BPoint penLocation BPoint screenOffset
= fCurrentView->CurrentState()->PenLocation(); = fCurrentView->CurrentState()->PenLocation();
for (int32 i = 0; i < ptCount; i++) { shapeFrame.OffsetBy(screenOffset);
ptList[i] += penLocation;
fCurrentView->ConvertToScreenForDrawing(&ptList[i]);
}
shapeFrame.OffsetBy(penLocation); fCurrentView->ConvertToScreenForDrawing(&screenOffset);
fCurrentView->ConvertToScreenForDrawing(&shapeFrame); fCurrentView->ConvertToScreenForDrawing(&shapeFrame);
drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount, drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount,
ptList, code == AS_FILL_SHAPE); ptList, code == AS_FILL_SHAPE, screenOffset,
fCurrentView->Scale());
} }
delete[] opList; delete[] opList;
@ -2581,15 +2579,16 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code,
// this might seem a bit weird, but under R5, the shapes // this might seem a bit weird, but under R5, the shapes
// are always offset by the current pen location // are always offset by the current pen location
BPoint penLocation BPoint screenOffset
= fCurrentView->CurrentState()->PenLocation(); = fCurrentView->CurrentState()->PenLocation();
for (int32 i = 0; i < ptCount; i++) { shapeFrame.OffsetBy(screenOffset);
ptList[i] += penLocation;
fCurrentView->ConvertToScreenForDrawing(&ptList[i]); fCurrentView->ConvertToScreenForDrawing(&screenOffset);
} fCurrentView->ConvertToScreenForDrawing(&shapeFrame);
fCurrentView->ConvertToScreenForDrawing(gradient); fCurrentView->ConvertToScreenForDrawing(gradient);
drawingEngine->FillShape(shapeFrame, opCount, opList, drawingEngine->FillShape(shapeFrame, opCount, opList,
ptCount, ptList, *gradient); ptCount, ptList, *gradient, screenOffset,
fCurrentView->Scale());
} }
delete[] opList; delete[] opList;

View File

@ -150,7 +150,7 @@ DrawingEngine::LockExclusiveAccess()
bool bool
DrawingEngine::IsExclusiveAccessLocked() DrawingEngine::IsExclusiveAccessLocked() const
{ {
return fGraphicsCard->IsExclusiveAccessLocked(); return fGraphicsCard->IsExclusiveAccessLocked();
} }
@ -1141,16 +1141,30 @@ DrawingEngine::FillRoundRect(BRect r, float xrad, float yrad,
void void
DrawingEngine::DrawShape(const BRect& bounds, int32 opCount, 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(); ASSERT_PARALLEL_LOCKED();
// NOTE: hides cursor regardless of if and where // TODO: bounds probably does not take curves and arcs into account...
// shape is drawn on screen, TODO: optimize // 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); AutoFloatingOverlaysHider _(fGraphicsCard);
BRect touched = fPainter->DrawShape(opCount, opList, ptCount, ptList, BRect touched = fPainter->DrawShape(opCount, opList, ptCount, ptList,
filled); filled, viewToScreenOffset, viewScale);
_CopyToFront(touched); _CopyToFront(touched);
} }
@ -1159,16 +1173,27 @@ DrawingEngine::DrawShape(const BRect& bounds, int32 opCount,
void void
DrawingEngine::FillShape(const BRect& bounds, int32 opCount, DrawingEngine::FillShape(const BRect& bounds, int32 opCount,
const uint32* opList, int32 ptCount, const BPoint* ptList, const uint32* opList, int32 ptCount, const BPoint* ptList,
const BGradient& gradient) const BGradient& gradient, const BPoint& viewToScreenOffset,
float viewScale)
{ {
ASSERT_PARALLEL_LOCKED(); ASSERT_PARALLEL_LOCKED();
// NOTE: hides cursor regardless of if and where // TODO: bounds probably does not take curves and arcs into account...
// shape is drawn on screen, TODO: optimize // 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); AutoFloatingOverlaysHider _(fGraphicsCard);
BRect touched = fPainter->FillShape(opCount, opList, ptCount, ptList, BRect touched = fPainter->FillShape(opCount, opList, ptCount, ptList,
gradient); gradient, viewToScreenOffset, viewScale);
_CopyToFront(touched); _CopyToFront(touched);
} }

View File

@ -56,7 +56,7 @@ public:
void UnlockParallelAccess(); void UnlockParallelAccess();
bool LockExclusiveAccess(); bool LockExclusiveAccess();
virtual bool IsExclusiveAccessLocked(); virtual bool IsExclusiveAccessLocked() const;
void UnlockExclusiveAccess(); void UnlockExclusiveAccess();
// for screen shots // for screen shots
@ -138,11 +138,14 @@ public:
virtual void DrawShape(const BRect& bounds, virtual void DrawShape(const BRect& bounds,
int32 opcount, const uint32* oplist, int32 opcount, const uint32* oplist,
int32 ptcount, const BPoint* ptlist, int32 ptcount, const BPoint* ptlist,
bool filled); bool filled, const BPoint& viewToScreenOffset,
float viewScale);
virtual void FillShape(const BRect& bounds, virtual void FillShape(const BRect& bounds,
int32 opcount, const uint32* oplist, int32 opcount, const uint32* oplist,
int32 ptcount, const BPoint* ptlist, int32 ptcount, const BPoint* ptlist,
const BGradient& gradient); const BGradient& gradient,
const BPoint& viewToScreenOffset,
float viewScale);
virtual void DrawTriangle(BPoint* points, const BRect& bounds, virtual void DrawTriangle(BPoint* points, const BRect& bounds,
bool filled); bool filled);

View File

@ -668,28 +668,31 @@ Painter::FillBezier(BPoint* p, const BGradient& gradient) const
} }
// DrawShape static void
BRect iterate_shape_data(agg::path_storage& path,
Painter::DrawShape(const int32& opCount, const uint32* opList, const int32& opCount, const uint32* opList,
const int32& ptCount, const BPoint* points, bool filled) const const int32& ptCount, const BPoint* points,
const BPoint& viewToScreenOffset, float viewScale)
{ {
CHECK_CLIPPING
// TODO: if shapes are ever used more heavily in Haiku, // TODO: if shapes are ever used more heavily in Haiku,
// it would be nice to use BShape data directly (write // it would be nice to use BShape data directly (write
// an AGG "VertexSource" adaptor) // an AGG "VertexSource" adaptor)
fPath.remove_all(); path.remove_all();
for (int32 i = 0; i < opCount; i++) { for (int32 i = 0; i < opCount; i++) {
uint32 op = opList[i] & 0xFF000000; uint32 op = opList[i] & 0xFF000000;
if (op & OP_MOVETO) { 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++; points++;
} }
if (op & OP_LINETO) { if (op & OP_LINETO) {
int32 count = opList[i] & 0x00FFFFFF; int32 count = opList[i] & 0x00FFFFFF;
while (count--) { while (count--) {
fPath.line_to(points->x, points->y); path.line_to(
points->x * viewScale + viewToScreenOffset.x,
points->y * viewScale + viewToScreenOffset.y);
points++; points++;
} }
} }
@ -697,16 +700,51 @@ Painter::DrawShape(const int32& opCount, const uint32* opList,
if (op & OP_BEZIERTO) { if (op & OP_BEZIERTO) {
int32 count = opList[i] & 0x00FFFFFF; int32 count = opList[i] & 0x00FFFFFF;
while (count) { while (count) {
fPath.curve4(points[0].x, points[0].y, points[1].x, points[1].y, path.curve4(
points[2].x, points[2].y); 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; points += 3;
count -= 3; count -= 3;
} }
} }
if (op & OP_CLOSE) 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) if (filled)
return _FillPath(fCurve); return _FillPath(fCurve);
@ -718,42 +756,13 @@ Painter::DrawShape(const int32& opCount, const uint32* opList,
// FillShape // FillShape
BRect BRect
Painter::FillShape(const int32& opCount, const uint32* opList, 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 CHECK_CLIPPING
// TODO: if shapes are ever used more heavily in Haiku, iterate_shape_data(fPath, opCount, opList, ptCount, points,
// it would be nice to use BShape data directly (write viewToScreenOffset, viewScale);
// 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();
}
return _FillPath(fCurve, gradient); return _FillPath(fCurve, gradient);
} }

View File

@ -132,12 +132,15 @@ class Painter {
// shapes // shapes
BRect DrawShape(const int32& opCount, BRect DrawShape(const int32& opCount,
const uint32* opList, const int32& ptCount, 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, BRect FillShape(const int32& opCount,
const uint32* opList, const uint32* opList, const int32& ptCount,
const int32& ptCount,
const BPoint* ptList, const BPoint* ptList,
const BGradient& gradient) const; const BGradient& gradient,
const BPoint& viewToScreenOffset,
float viewScale) const;
// rects // rects
BRect StrokeRect(const BRect& r) const; BRect StrokeRect(const BRect& r) const;
@ -383,6 +386,7 @@ Painter::ClipRect(BRect rect) const
return _Clipped(rect); return _Clipped(rect);
} }
inline BRect inline BRect
Painter::AlignAndClipRect(BRect rect) const Painter::AlignAndClipRect(BRect rect) const
{ {

View File

@ -12,6 +12,7 @@
#include "DrawState.h" #include "DrawState.h"
#include <Bitmap.h> #include <Bitmap.h>
#include <utf8_functions.h>
#include <new> #include <new>
@ -682,7 +683,7 @@ RemoteDrawingEngine::FillRoundRect(BRect rect, float xRadius, float yRadius,
void void
RemoteDrawingEngine::DrawShape(const BRect& bounds, int32 opCount, RemoteDrawingEngine::DrawShape(const BRect& bounds, int32 opCount,
const uint32* opList, int32 pointCount, const BPoint* pointList, const uint32* opList, int32 pointCount, const BPoint* pointList,
bool filled) bool filled, const BPoint& viewToScreenOffset, float viewScale)
{ {
BRect clipBounds = bounds; BRect clipBounds = bounds;
if (!filled) if (!filled)
@ -699,13 +700,15 @@ RemoteDrawingEngine::DrawShape(const BRect& bounds, int32 opCount,
message.AddList(opList, opCount); message.AddList(opList, opCount);
message.Add(pointCount); message.Add(pointCount);
message.AddList(pointList, pointCount); message.AddList(pointList, pointCount);
// TODO: viewToScreenOffset and viewScale
} }
void void
RemoteDrawingEngine::FillShape(const BRect& bounds, int32 opCount, RemoteDrawingEngine::FillShape(const BRect& bounds, int32 opCount,
const uint32* opList, int32 pointCount, const BPoint* pointList, const uint32* opList, int32 pointCount, const BPoint* pointList,
const BGradient& gradient) const BGradient& gradient, const BPoint& viewToScreenOffset,
float viewScale)
{ {
if (!fClippingRegion.Intersects(bounds)) if (!fClippingRegion.Intersects(bounds))
return; return;
@ -719,6 +722,7 @@ RemoteDrawingEngine::FillShape(const BRect& bounds, int32 opCount,
message.Add(pointCount); message.Add(pointCount);
message.AddList(pointList, pointCount); message.AddList(pointList, pointCount);
message.AddGradient(gradient); 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 float
RemoteDrawingEngine::StringWidth(const char* string, int32 length, RemoteDrawingEngine::StringWidth(const char* string, int32 length,
escapement_delta* delta) escapement_delta* delta)

View File

@ -107,11 +107,15 @@ virtual void FillRoundRect(BRect rect, float xRadius,
virtual void DrawShape(const BRect& bounds, virtual void DrawShape(const BRect& bounds,
int32 opCount, const uint32* opList, int32 opCount, const uint32* opList,
int32 pointCount, const BPoint* pointList, int32 pointCount, const BPoint* pointList,
bool filled); bool filled,
const BPoint& viewToScreenOffset,
float viewScale);
virtual void FillShape(const BRect& bounds, virtual void FillShape(const BRect& bounds,
int32 opCount, const uint32* opList, int32 opCount, const uint32* opList,
int32 pointCount, const BPoint* pointList, int32 pointCount, const BPoint* pointList,
const BGradient& gradient); const BGradient& gradient,
const BPoint& viewToScreenOffset,
float viewScale);
virtual void DrawTriangle(BPoint* points, virtual void DrawTriangle(BPoint* points,
const BRect& bounds, bool filled); const BRect& bounds, bool filled);
@ -131,6 +135,8 @@ virtual void StrokeLineArray(int32 numlines,
virtual BPoint DrawString(const char* string, int32 length, virtual BPoint DrawString(const char* string, int32 length,
const BPoint& point, const BPoint& point,
escapement_delta* delta = NULL); escapement_delta* delta = NULL);
virtual BPoint DrawString(const char* string, int32 length,
const BPoint* offsets);
virtual float StringWidth(const char* string, int32 length, virtual float StringWidth(const char* string, int32 length,
escapement_delta* delta = NULL); escapement_delta* delta = NULL);

View File

@ -100,6 +100,7 @@ enum {
RP_FILL_REGION_COLOR_NO_CLIPPING, RP_FILL_REGION_COLOR_NO_CLIPPING,
RP_DRAW_STRING = 180, RP_DRAW_STRING = 180,
RP_DRAW_STRING_WITH_OFFSETS,
RP_DRAW_STRING_RESULT, RP_DRAW_STRING_RESULT,
RP_STRING_WIDTH, RP_STRING_WIDTH,
RP_STRING_WIDTH_RESULT, RP_STRING_WIDTH_RESULT,

View File

@ -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 resize_limits ;
SubInclude HAIKU_TOP src tests servers app scrollbar ; SubInclude HAIKU_TOP src tests servers app scrollbar ;
SubInclude HAIKU_TOP src tests servers app scrolling ; 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 statusbar ;
SubInclude HAIKU_TOP src tests servers app stress_test ; SubInclude HAIKU_TOP src tests servers app stress_test ;
SubInclude HAIKU_TOP src tests servers app textview ; SubInclude HAIKU_TOP src tests servers app textview ;

View File

@ -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 ;
}

View File

@ -0,0 +1,181 @@
#include <stdio.h>
#include <string.h>
#include <Application.h>
#include <Message.h>
#include <Shape.h>
#include <View.h>
#include <Window.h>
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;
}