Implement missing methods in PictureBoundingBoxPlayer

* Remove const from gradient in StrokeLineGradient.
  BoundingBoxPlayer needs to apply transform to it.
* Extend LayersTest.
* Use BStackOrHeapArray for polygons.
* Fixes #12937.

Change-Id: If0a4abec0168dbe9afe7ea92bb29017ea8c89c79
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10211
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Kacper Kasper
2026-01-06 21:22:30 +00:00
committed by waddlesplash
parent a65ba286ee
commit d620b23279
5 changed files with 236 additions and 52 deletions
+2 -3
View File
@@ -101,8 +101,7 @@ public:
BGradient& gradient, bool fill);
virtual void DrawShapeGradient(const BShape& shape, BGradient& gradient, bool fill);
virtual void SetFillRule(int32 fillRule);
virtual void StrokeLineGradient(const BPoint& start, const BPoint& end,
const BGradient& gradient);
virtual void StrokeLineGradient(const BPoint& start, const BPoint& end, BGradient& gradient);
private:
void* fUserData;
@@ -626,7 +625,7 @@ CallbackAdapterPlayer::SetFillRule(int32 fillRule)
void
CallbackAdapterPlayer::StrokeLineGradient(const BPoint& start, const BPoint& end, const BGradient& gradient)
CallbackAdapterPlayer::StrokeLineGradient(const BPoint& start, const BPoint& end, BGradient& gradient)
{
fCallbacks->stroke_line_gradient(fUserData, start, end, gradient);
}
+175 -27
View File
@@ -33,6 +33,7 @@
#include <PicturePlayer.h>
#include <PictureProtocol.h>
#include <Shape.h>
#include <StackOrHeapArray.h>
//#define DEBUG_TRACE_BB
@@ -194,6 +195,23 @@ public:
virtual void ScaleBy(double x, double y);
virtual void RotateBy(double angleRadians);
virtual void BlendLayer(Layer* layer);
virtual void ClipToRect(const BRect& rect, bool inverse);
virtual void ClipToShape(int32 opCount, const uint32 opList[], int32 ptCount,
const BPoint ptList[], bool inverse);
virtual void DrawStringLocations(const char* string, size_t length, const BPoint locations[],
size_t locationCount);
virtual void DrawRectGradient(const BRect& rect, BGradient& gradient, bool fill);
virtual void DrawRoundRectGradient(const BRect& rect, const BPoint& radii, BGradient& gradient,
bool fill);
virtual void DrawBezierGradient(const BPoint controlPoints[4], BGradient& gradient, bool fill);
virtual void DrawArcGradient(const BPoint& center, const BPoint& radii, float startTheta,
float arcTheta, BGradient& gradient, bool fill);
virtual void DrawEllipseGradient(const BRect& rect, BGradient& gradient, bool fill);
virtual void DrawPolygonGradient(size_t numPoints, const BPoint points[], bool isClosed,
BGradient& gradient, bool fill);
virtual void DrawShapeGradient(const BShape& shape, BGradient& gradient, bool fill);
virtual void SetFillRule(int32 fillRule);
virtual void StrokeLineGradient(const BPoint& start, const BPoint& end, BGradient& gradient);
private:
BoundingBoxState* const fState;
@@ -248,7 +266,7 @@ expand_rect_for_pen_size(BoundingBoxState* state, RectType& rect)
void
BoundingBoxCallbacks::MovePenBy(const BPoint& delta)
{
TRACE_BB("%p move pen by %.2f %.2f\n", _state, delta.x, delta.y);
TRACE_BB("%p move pen by %.2f %.2f\n", fState, delta.x, delta.y);
fState->GetDrawState()->SetPenLocation(
fState->GetDrawState()->PenLocation() + delta);
@@ -259,7 +277,7 @@ void
BoundingBoxCallbacks::StrokeLine(const BPoint& _start,
const BPoint& _end)
{
TRACE_BB("%p stroke line %.2f %.2f -> %.2f %.2f\n", _state,
TRACE_BB("%p stroke line %.2f %.2f -> %.2f %.2f\n", fState,
_start.x, _start.y, _end.x, _end.y);
BPoint start = _start;
@@ -295,7 +313,7 @@ BoundingBoxCallbacks::StrokeLine(const BPoint& _start,
void
BoundingBoxCallbacks::DrawRect(const BRect& _rect, bool fill)
{
TRACE_BB("%p draw rect fill=%d %.2f %.2f %.2f %.2f\n", _state, fill,
TRACE_BB("%p draw rect fill=%d %.2f %.2f %.2f %.2f\n", fState, fill,
_rect.left, _rect.top, _rect.right, _rect.bottom);
BRect rect = _rect;
@@ -344,7 +362,7 @@ BoundingBoxCallbacks::DrawBezier(const BPoint viewPoints[4], bool fill)
{
TRACE_BB("%p draw bezier fill=%d (%.2f %.2f) (%.2f %.2f) "
"(%.2f %.2f) (%.2f %.2f)\n",
_state,
fState,
fill,
viewPoints[0].x, viewPoints[0].y,
viewPoints[1].x, viewPoints[1].y,
@@ -362,7 +380,7 @@ BoundingBoxCallbacks::DrawBezier(const BPoint viewPoints[4], bool fill)
void
BoundingBoxCallbacks::DrawEllipse(const BRect& _rect, bool fill)
{
TRACE_BB("%p draw ellipse fill=%d (%.2f %.2f) (%.2f %.2f)\n", _state, fill,
TRACE_BB("%p draw ellipse fill=%d (%.2f %.2f) (%.2f %.2f)\n", fState, fill,
_rect.left, _rect.top, _rect.right, _rect.bottom);
BRect rect = _rect;
@@ -390,27 +408,9 @@ determine_bounds_polygon(BoundingBoxState* state, int32 numPoints,
if (numPoints <= 0)
return;
if (numPoints <= 200) {
// fast path: no malloc/free, also avoid
// constructor/destructor calls
char data[200 * sizeof(BPoint)];
BPoint* points = (BPoint*)data;
state->PenToLocalTransform().Apply(points, viewPoints, numPoints);
get_polygon_frame(points, numPoints, &outRect);
} else {
// avoid constructor/destructor calls by
// using malloc instead of new []
BPoint* points = (BPoint*)malloc(numPoints * sizeof(BPoint));
if (points == NULL)
return;
state->PenToLocalTransform().Apply(points, viewPoints, numPoints);
get_polygon_frame(points, numPoints, &outRect);
free(points);
}
BStackOrHeapArray<BPoint, 200> points(numPoints);
state->PenToLocalTransform().Apply(points, viewPoints, numPoints);
get_polygon_frame(points, numPoints, &outRect);
}
@@ -769,7 +769,155 @@ BoundingBoxCallbacks::BlendLayer(Layer* layer)
}
// #pragma mark - PictureBoundingBoxPlayer
void
BoundingBoxCallbacks::DrawRectGradient(const BRect& _rect, BGradient& gradient, bool fill)
{
TRACE_BB("%p draw rect gradient fill=%d %.2f %.2f %.2f %.2f\n", fState, fill,
_rect.left, _rect.top, _rect.right, _rect.bottom);
BRect rect = _rect;
const SimpleTransform transform = fState->PenToLocalTransform();
transform.Apply(&rect);
transform.Apply(&gradient);
if (!fill)
expand_rect_for_pen_size(fState, rect);
fState->IncludeRect(rect);
}
void
BoundingBoxCallbacks::DrawRoundRectGradient(const BRect& rect, const BPoint& radii,
BGradient& gradient, bool fill)
{
TRACE_BB("%p draw round rect gradient fill=%d %.2f %.2f %.2f %.2f\n", fState, fill,
rect.left, rect.top, rect.right, rect.bottom);
DrawRectGradient(rect, gradient, fill);
}
void
BoundingBoxCallbacks::DrawBezierGradient(const BPoint controlPoints[4], BGradient& gradient,
bool fill)
{
TRACE_BB("%p draw bezier gradient fill=%d (%.2f %.2f) (%.2f %.2f) "
"(%.2f %.2f) (%.2f %.2f)\n",
fState,
fill,
viewPoints[0].x, viewPoints[0].y,
viewPoints[1].x, viewPoints[1].y,
viewPoints[2].x, viewPoints[2].y,
viewPoints[3].x, viewPoints[3].y);
BRect rect;
determine_bounds_bezier(fState, controlPoints, rect);
fState->PenToLocalTransform().Apply(&gradient);
if (!fill)
expand_rect_for_pen_size(fState, rect);
fState->IncludeRect(rect);
}
void
BoundingBoxCallbacks::DrawEllipseGradient(const BRect& _rect, BGradient& gradient, bool fill)
{
TRACE_BB("%p draw ellipse gradient fill=%d (%.2f %.2f) (%.2f %.2f)\n", fState, fill,
_rect.left, _rect.top, _rect.right, _rect.bottom);
BRect rect = _rect;
const SimpleTransform transform = fState->PenToLocalTransform();
transform.Apply(&rect);
transform.Apply(&gradient);
if (!fill)
expand_rect_for_pen_size(fState, rect);
fState->IncludeRect(rect);
}
void
BoundingBoxCallbacks::DrawArcGradient(const BPoint& center, const BPoint& radii, float startTheta,
float arcTheta, BGradient& gradient, bool fill)
{
BRect rect(center.x - radii.x, center.y - radii.y,
center.x + radii.x - 1, center.y + radii.y - 1);
DrawEllipseGradient(rect, gradient, fill);
}
void
BoundingBoxCallbacks::DrawPolygonGradient(size_t numPoints, const BPoint points[], bool isClosed,
BGradient& gradient, bool fill)
{
TRACE_BB("%p draw polygon fill=%d (%ld points)\n", fState, fill, numPoints);
if (numPoints <= 0)
return;
BRect rect;
determine_bounds_polygon(fState, numPoints, points, rect);
fState->PenToLocalTransform().Apply(&gradient);
if (!fill)
expand_rect_for_pen_size(fState, rect);
fState->IncludeRect(rect);
}
void
BoundingBoxCallbacks::DrawShapeGradient(const BShape& shape, BGradient& gradient, bool fill)
{
BRect rect = shape.Bounds();
// FIXME: this doesn't work - ShapePainter uses ScreenTransform unconditionally
TRACE_BB("%p stroke shape gradient (bounds %.2f %.2f %.2f %.2f)\n", fState,
rect.left, rect.top, rect.right, rect.bottom);
const SimpleTransform transform = fState->PenToLocalTransform();
transform.Apply(&rect);
transform.Apply(&gradient);
if (!fill)
expand_rect_for_pen_size(fState, rect);
fState->IncludeRect(rect);
}
void
BoundingBoxCallbacks::ClipToRect(const BRect& rect, bool inverse)
{
// TODO
}
void
BoundingBoxCallbacks::ClipToShape(int32 opCount, const uint32 opList[], int32 ptCount,
const BPoint ptList[], bool inverse)
{
// TODO
}
void
BoundingBoxCallbacks::DrawStringLocations(const char* string, size_t length,
const BPoint locations[], size_t locationCount)
{
// TODO
}
void
BoundingBoxCallbacks::SetFillRule(int32 fillRule)
{
// TODO
}
void
BoundingBoxCallbacks::StrokeLineGradient(const BPoint& start, const BPoint& end,
BGradient& gradient)
{
TRACE_BB("%p stroke line gradient %.2f %.2f -> %.2f %.2f\n", fState,
start.x, start.y, end.x, end.y);
const SimpleTransform transform = fState->PenToLocalTransform();
transform.Apply(&gradient);
StrokeLine(start, end);
}
/* static */ void
+2 -3
View File
@@ -305,8 +305,7 @@ public:
BGradient& gradient, bool fill);
virtual void DrawShapeGradient(const BShape& shape, BGradient& gradient, bool fill);
virtual void SetFillRule(int32 fillRule);
virtual void StrokeLineGradient(const BPoint& start, const BPoint& end,
const BGradient& gradient);
virtual void StrokeLineGradient(const BPoint& start, const BPoint& end, BGradient& gradient);
private:
Canvas* const fCanvas;
@@ -570,7 +569,7 @@ CanvasCallbacks::DrawShapeGradient(const BShape& shape, BGradient& gradient, boo
void
CanvasCallbacks::StrokeLineGradient(const BPoint& _start, const BPoint& _end,
const BGradient& gradient)
BGradient& gradient)
{
BPoint start = _start;
BPoint end = _end;
@@ -1,5 +1,5 @@
/*
* Copyright 2016, Haiku Inc.
* Copyright 2016, 2026, Haiku Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
@@ -9,6 +9,9 @@
#include <Application.h>
#include <GradientRadial.h>
#include <GradientLinear.h>
#include <Shape.h>
#include <Polygon.h>
#include <String.h>
#include <View.h>
#include <Window.h>
@@ -24,11 +27,33 @@ class View : public BView {
virtual ~View();
virtual void Draw(BRect);
BGradientLinear g[3];
BPoint bezierPoints[3][4];
BShape shapes[3];
BPolygon polygon;
};
View::View(BRect rect)
: BView(rect, "gradients", B_FOLLOW_ALL, B_WILL_DRAW)
{
SetViewColor(0, 255, 0);
for(int i = 0; i < 3; i++) {
g[i].SetStart(BPoint(0, i * 100));
g[i].SetEnd(BPoint(0, (i + 1) * 100));
g[i].AddColor((rgb_color) { 255, 0, 0, 255 }, 255.0);
g[i].AddColor((rgb_color) { 255, 255, 255, 0 }, 0.0);
bezierPoints[i][0] = BPoint(540, i * 100 + 10);
bezierPoints[i][1] = BPoint(610, i * 100 + 10);
bezierPoints[i][2] = BPoint(580, (i + 1) * 100);
bezierPoints[i][3] = BPoint(630, (i + 1) * 100);
shapes[i].MoveTo(BPoint(640, i * 100 + 10));
shapes[i].LineTo(BPoint(670, i * 100 + 40));
shapes[i].LineTo(BPoint(700, i * 100 + 40));
shapes[i].LineTo(BPoint(640, i * 100 + 100));
shapes[i].Close();
}
BPoint p[4] = { BPoint(0, 0), BPoint(0, 50), BPoint(90, 90), BPoint(50, 50) };
polygon.AddPoints(p, 4);
}
@@ -40,22 +65,36 @@ View::~View()
void
View::Draw(BRect)
{
BGradientRadial g(BPoint(50, 50), 50.0);
g.AddColor((rgb_color) { 0, 0, 0, 255 }, 255.0);
g.AddColor((rgb_color) { 255, 255, 255, 0 }, 0.0);
SetHighColor(0, 0, 0);
BeginLayer(255);
// 1, 1
FillRect(BRect(10, 10, 90, 90));
// 2, 1
FillRect(BRect(100, 10, 190, 90), g);
EndLayer();
BeginLayer(100);
// 1, 2
FillRect(BRect(10, 100, 90, 190));
// 2, 2
FillRect(BRect(100, 100, 190, 190), g);
EndLayer();
BPoint text(5, 60);
BRect rect(10, 10, 100, 100);
BRect gradient(110, 10, 200, 100);
rect.OffsetBy(30, 0);
gradient.OffsetBy(30, 0);
int opacity[3] = {255, 254, 100};
for(int i = 0; i < 3; i++) {
BString s;
s << opacity[i];
DrawString(s, 3, text);
BeginLayer(opacity[i]);
FillRect(rect);
FillRect(gradient, g[i]);
FillRoundRect(gradient.OffsetByCopy(100, 0), 10, 10, g[i]);
FillEllipse(gradient.OffsetByCopy(200, 0), g[i]);
FillArc(gradient.OffsetByCopy(300, 0), 30, 120, g[i]);
FillBezier(bezierPoints[i], g[i]);
BShape sh = shapes[i];
MovePenTo(B_ORIGIN);
FillShape(&sh, g[i]);
BPolygon p = polygon;
p.MapTo(BRect(0, 0, 90, 90), gradient.OffsetByCopy(600, 0));
FillPolygon(&p, g[i]);
StrokeLine(BPoint(840, i * 100 + 10), BPoint(930, i * 100 + 100), g[i]);
EndLayer();
rect.OffsetBy(0, 100);
gradient.OffsetBy(0, 100);
text.y += 100;
}
}
@@ -72,7 +111,7 @@ class Window : public BWindow {
Window::Window()
: BWindow(BRect(100, 100, 300, 300), "Layers-Test",
: BWindow(BRect(100, 100, 1040, 410), "Layers-Test",
B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS)
{
BView *view = new View(Bounds());