Skip to content

Commit

Permalink
Add the stroke align interface to the ShapeLayer to set the position …
Browse files Browse the repository at this point in the history
…of the stroke.
  • Loading branch information
kevingpqi123 committed Nov 19, 2024
1 parent 738fc92 commit 8650c65
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 28 deletions.
31 changes: 31 additions & 0 deletions include/tgfx/layers/ShapeLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,24 @@
#include "tgfx/layers/ShapeStyle.h"

namespace tgfx {
/**
* The alignment of the stroke concerning the boundaries of the shape.
*/
enum class StrokeAlign {
/**
* Draw a stroke centered along the shape boundary.
*/
Center,
/**
* Draw a stroke inside the shape boundary.
*/
Inside,
/**
* Draw a stroke outside the shape boundary.
*/
Outside
};

/**
* ShapeLayer represents a layer that draws a shape.
*/
Expand Down Expand Up @@ -207,6 +225,18 @@ class ShapeLayer : public Layer {
*/
void setStrokeEnd(float end);

/**
* Returns the stroke alignment applied to the shape’s path when stroked. The default stroke alignment is Center.
*/
StrokeAlign strokeAlign() const {
return _strokeAlign;
}

/**
* Sets the stroke alignment applied to the shape’s path when stroked.
*/
void setStrokeAlign(StrokeAlign align);

~ShapeLayer() override;

protected:
Expand All @@ -223,5 +253,6 @@ class ShapeLayer : public Layer {
float _lineDashPhase = 0.0f;
float _strokeStart = 0.0f;
float _strokeEnd = 1.0f;
StrokeAlign _strokeAlign = StrokeAlign::Center;
};
} // namespace tgfx
21 changes: 20 additions & 1 deletion src/layers/ShapeLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,14 @@ void ShapeLayer::setStrokeEnd(float end) {
invalidateContent();
}

void ShapeLayer::setStrokeAlign(StrokeAlign align) {
if (_strokeAlign == align) {
return;
}
_strokeAlign = align;
invalidateContent();
}

ShapeLayer::~ShapeLayer() {
detachProperty(_strokeStyle.get());
detachProperty(_fillStyle.get());
Expand Down Expand Up @@ -182,7 +190,18 @@ std::unique_ptr<LayerContent> ShapeLayer::onUpdateContent() {
PathEffect::MakeDash(dashes.data(), static_cast<int>(dashes.size()), _lineDashPhase);
strokeShape = Shape::ApplyEffect(std::move(strokeShape), std::move(pathEffect));
}
strokeShape = Shape::ApplyStroke(std::move(strokeShape), &stroke);
if (_strokeAlign != StrokeAlign::Center) {
auto terminalStroke = stroke;
terminalStroke.width *= 2;
strokeShape = Shape::ApplyStroke(std::move(strokeShape), &terminalStroke);
if (_strokeAlign == StrokeAlign::Inside) {
strokeShape = Shape::Merge(std::move(strokeShape), _shape, PathOp::Intersect);
} else {
strokeShape = Shape::Merge(std::move(strokeShape), _shape, PathOp::Difference);
}
} else {
strokeShape = Shape::ApplyStroke(std::move(strokeShape), &stroke);
}
auto content =
std::make_unique<ShapeContent>(std::move(strokeShape), _strokeStyle->getShader());
contents.push_back(std::move(content));
Expand Down
2 changes: 1 addition & 1 deletion test/baseline/version.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
"Layer_hitTestPointNested": "0ee494a",
"ModeColorFilter": "43cd416",
"PassThoughAndNormal": "43cd416",
"draw_shape": "d069eb4",
"draw_shape": "738fc92",
"draw_solid": "b4a1231",
"draw_text": "612c09e",
"dropShadow": "43cd416",
Expand Down
62 changes: 36 additions & 26 deletions test/src/LayerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,35 +441,45 @@ TGFX_TEST(LayerTest, shapeLayer) {
auto device = DevicePool::Make();
ASSERT_TRUE(device != nullptr);
auto context = device->lockContext();
auto surface = Surface::Make(context, 200, 100);
auto surface = Surface::Make(context, 200, 300);
auto displayList = std::make_unique<DisplayList>();
auto layer = Layer::Make();
displayList->root()->addChild(layer);
auto shaperLayer = ShapeLayer::Make();
auto rect = Rect::MakeXYWH(10, 10, 150, 80);
Path path = {};
path.addRect(rect);
shaperLayer->setPath(path);
auto filleStyle = Gradient::MakeLinear({10, 10}, {150, 80});
filleStyle->setColors({{0.f, 0.f, 1.f, 1.f}, {0.f, 1.f, 0.f, 1.f}});
shaperLayer->setFillStyle(filleStyle);
// stroke style
shaperLayer->setLineWidth(10.0f);
shaperLayer->setLineCap(LineCap::Butt);
shaperLayer->setLineJoin(LineJoin::Miter);
shaperLayer->setMiterLimit(2.0f);
auto strokeStyle = SolidColor::Make(Color::Red());
shaperLayer->setStrokeStyle(strokeStyle);
std::vector<float> dashPattern = {10.0f, 10.0f};
shaperLayer->setLineDashPattern(dashPattern);
shaperLayer->setLineDashPhase(0.0f);

layer->addChild(shaperLayer);
auto shapeLayerRect = shaperLayer->getBounds();
auto bounds = Rect::MakeXYWH(5, 5, 160, 90);

EXPECT_EQ(shapeLayerRect, bounds);

for (int i = 0; i < 3; i++) {
auto shaperLayer = ShapeLayer::Make();
auto rect = Rect::MakeXYWH(10, 10 + 100 * i, 140, 80);
Path path = {};
path.addRect(rect);
shaperLayer->setPath(path);
auto filleStyle = Gradient::MakeLinear({rect.left, rect.top}, {rect.right, rect.bottom});
filleStyle->setColors({{0.f, 0.f, 1.f, 1.f}, {0.f, 1.f, 0.f, 1.f}});
shaperLayer->setFillStyle(filleStyle);
// stroke style
shaperLayer->setLineWidth(10.0f);
shaperLayer->setLineCap(LineCap::Butt);
shaperLayer->setLineJoin(LineJoin::Miter);
auto strokeStyle = SolidColor::Make(Color::Red());
shaperLayer->setStrokeStyle(strokeStyle);
std::vector<float> dashPattern = {10.0f, 10.0f};
shaperLayer->setLineDashPattern(dashPattern);
shaperLayer->setLineDashPhase(5.0f);
shaperLayer->setStrokeAlign(static_cast<StrokeAlign>(i));
layer->addChild(shaperLayer);
auto shapeLayerRect = shaperLayer->getBounds();
switch (i) {
case 0:
EXPECT_EQ(shapeLayerRect, Rect::MakeLTRB(5, 5, 155, 95));
break;
case 1:
EXPECT_EQ(shapeLayerRect, Rect::MakeLTRB(0, 100, 160, 200));
break;
case 2:
EXPECT_EQ(shapeLayerRect, Rect::MakeLTRB(0, 200, 160, 300));
break;
default:
break;
}
}
displayList->render(surface.get());
context->submit();
EXPECT_TRUE(Baseline::Compare(surface, "LayerTest/draw_shape"));
Expand Down

0 comments on commit 8650c65

Please sign in to comment.