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);
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:

View File

@ -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 {

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.
*
* 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 &copyFrom)
}
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

View File

@ -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<uint32> fOpStack;
stack<BPoint> fPtStack;
View* fView;
stack<uint32> fOpStack;
stack<BPoint> 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);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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<agg::path_storage> fCurve;
mutable agg::path_storage fPath;
mutable agg::conv_curve<agg::path_storage> 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
{

View File

@ -12,6 +12,7 @@
#include "DrawState.h"
#include <Bitmap.h>
#include <utf8_functions.h>
#include <new>
@ -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)

View File

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

View File

@ -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,

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

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