Skip to content

Commit

Permalink
Fix for Issue #67
Browse files Browse the repository at this point in the history
* negative rx or ry should be ignored.

* proper support for rounded rectangle with rx != ry case,
  the backends are also improved.
  • Loading branch information
mpsuzuki committed Dec 18, 2019
1 parent af8bdab commit abfb9aa
Show file tree
Hide file tree
Showing 12 changed files with 70 additions and 4 deletions.
1 change: 1 addition & 0 deletions svgnative/include/SVGRenderer.h
Expand Up @@ -216,6 +216,7 @@ class Path

virtual void Rect(float x, float y, float width, float height) = 0;
virtual void RoundedRect(float x, float y, float width, float height, float cornerRadius) = 0;
virtual void RoundedRect(float x, float y, float width, float height, float cornerRadiusX, float cornerRadiusY) = 0;
virtual void Ellipse(float cx, float cy, float rx, float ry) = 0;

virtual void MoveTo(float x, float y) = 0;
Expand Down
24 changes: 24 additions & 0 deletions svgnative/ports/cairo/CairoSVGRenderer.cpp
Expand Up @@ -62,6 +62,30 @@ void CairoSVGPath::RoundedRect(float x, float y, float width, float height, floa
cairo_close_path(mPathCtx);
}

inline void cairo_arc_rx_ry(cairo_t* cr, float cx, float cy, float rx, float ry, float rad1, float rad2)
{
cairo_save(cr);
cairo_translate(cr, cx, cy);
cairo_scale(cr, rx, ry);
cairo_arc(cr, 0, 0, 1, rad1, rad2);
cairo_restore(cr);
}

void CairoSVGPath::RoundedRect(float x, float y, float width, float height, float cornerRadiusX, float cornerRadiusY)
{
// Cairo does not provide single API to draw "rounded rect". See
// https://www.cairographics.org/samples/rounded_rectangle/

cairo_new_sub_path(mPathCtx);

cairo_arc_rx_ry(mPathCtx, x - cornerRadiusX + width, y + cornerRadiusY, cornerRadiusX, cornerRadiusY, deg2rad(-90), deg2rad( 0));
cairo_arc_rx_ry(mPathCtx, x - cornerRadiusX + width, y - cornerRadiusY + height, cornerRadiusX, cornerRadiusY, deg2rad( 0), deg2rad( 90));
cairo_arc_rx_ry(mPathCtx, x + cornerRadiusX, y - cornerRadiusY + height, cornerRadiusX, cornerRadiusY, deg2rad( 90), deg2rad(180));
cairo_arc_rx_ry(mPathCtx, x + cornerRadiusX, y + cornerRadiusY, cornerRadiusX, cornerRadiusY, deg2rad(180), deg2rad(270));

cairo_close_path(mPathCtx);
}

void CairoSVGPath::Ellipse(float cx, float cy, float rx, float ry)
{
// Cairo does not provide single API to draw "ellipse". See
Expand Down
1 change: 1 addition & 0 deletions svgnative/ports/cairo/CairoSVGRenderer.h
Expand Up @@ -32,6 +32,7 @@ class CairoSVGPath final : public Path

void Rect(float x, float y, float width, float height) override;
void RoundedRect(float x, float y, float width, float height, float cornerRadius) override;
void RoundedRect(float x, float y, float width, float height, float cornerRadiusX, float cornerRadiusY) override;
void Ellipse(float cx, float cy, float rx, float ry) override;

void MoveTo(float x, float y) override;
Expand Down
5 changes: 5 additions & 0 deletions svgnative/ports/cg/CGSVGRenderer.cpp
Expand Up @@ -27,6 +27,11 @@ void CGSVGPath::RoundedRect(float x, float y, float width, float height, float c
CGPathAddRoundedRect(mPath, nullptr, {{x, y}, {width, height}}, cornerRadius, cornerRadius);
}

void CGSVGPath::RoundedRect(float x, float y, float width, float height, float cornerRadiusX, float cornerRadiusY)
{
CGPathAddRoundedRect(mPath, nullptr, {{x, y}, {width, height}}, cornerRadiusX, cornerRadiusY);
}

void CGSVGPath::Ellipse(float cx, float cy, float rx, float ry)
{
CGPathAddEllipseInRect(mPath, nullptr, {{cx - rx, cy - ry}, {2 * rx, 2 * ry}});
Expand Down
1 change: 1 addition & 0 deletions svgnative/ports/cg/CGSVGRenderer.h
Expand Up @@ -26,6 +26,7 @@ class CGSVGPath final : public Path

void Rect(float x, float y, float width, float height) override;
void RoundedRect(float x, float y, float width, float height, float cornerRadius) override;
void RoundedRect(float x, float y, float width, float height, float cornerRadiusX, float cornerRadiusY) override;
void Ellipse(float cx, float cy, float rx, float ry) override;

void MoveTo(float x, float y) override;
Expand Down
16 changes: 16 additions & 0 deletions svgnative/ports/gdiplus/GDIPlusSVGRenderer.cpp
Expand Up @@ -61,6 +61,22 @@ void GDIPlusSVGPath::RoundedRect(float x, float y, float w, float h, float r)
mPath.CloseFigure();
}

void GDIPlusSVGPath::RoundedRect(float x, float y, float w, float h, float rx, float ry)
{
const float dx = rx + rx;
const float dy = ry + ry;

mPath.AddLine(x + rx, y, x + w - dx, y);
mPath.AddArc(x + w - dx, y, dx, dy, 270, 90);
mPath.AddLine(x + w, y + ry, x + w, y + h - dy);
mPath.AddArc(x + w - dx, y + h - dy, dx, dy, 0, 90);
mPath.AddLine(x + w - dx, y + h, x + rx, y + h);
mPath.AddArc(x, y + h - dy, dx, dy, 90, 90);
mPath.AddLine(x, y + h - dy, x, y + ry);
mPath.AddArc(x, y, dx, dy, 180, 90);
mPath.CloseFigure();
}

void GDIPlusSVGPath::Ellipse(float cx, float cy, float rx, float ry)
{
mPath.AddEllipse(cx - rx, cy - ry, rx + rx, ry + ry);
Expand Down
1 change: 1 addition & 0 deletions svgnative/ports/gdiplus/GDIPlusSVGRenderer.h
Expand Up @@ -26,6 +26,7 @@ class GDIPlusSVGPath final : public Path

void Rect(float x, float y, float width, float height) override;
void RoundedRect(float x, float y, float width, float height, float cornerRadius) override;
void RoundedRect(float x, float y, float width, float height, float cornerRadiusX, float cornerRadiusY) override;
void Ellipse(float cx, float cy, float rx, float ry) override;

void MoveTo(float x, float y) override;
Expand Down
7 changes: 7 additions & 0 deletions svgnative/ports/skia/SkiaSVGRenderer.cpp
Expand Up @@ -40,6 +40,13 @@ void SkiaSVGPath::RoundedRect(float x, float y, float width, float height, float
mPath.addRRect(rrect);
}

void SkiaSVGPath::RoundedRect(float x, float y, float width, float height, float cornerRadiusX, float cornerRadiusY)
{
SkRRect rrect;
rrect.setRectXY({x, y, x + width, y + height}, cornerRadiusX, cornerRadiusY);
mPath.addRRect(rrect);
}

void SkiaSVGPath::Ellipse(float cx, float cy, float rx, float ry) { mPath.addOval({cx - rx, cy - ry, cx + rx, cy + ry}); }

void SkiaSVGPath::MoveTo(float x, float y)
Expand Down
1 change: 1 addition & 0 deletions svgnative/ports/skia/SkiaSVGRenderer.h
Expand Up @@ -29,6 +29,7 @@ class SkiaSVGPath final : public Path

void Rect(float x, float y, float width, float height) override;
void RoundedRect(float x, float y, float width, float height, float cornerRadius) override;
void RoundedRect(float x, float y, float width, float height, float cornerRadiusX, float cornerRadiusY) override;
void Ellipse(float cx, float cy, float rx, float ry) override;

void MoveTo(float x, float y) override;
Expand Down
5 changes: 5 additions & 0 deletions svgnative/ports/string/StringSVGRenderer.cpp
Expand Up @@ -32,6 +32,11 @@ void StringSVGPath::RoundedRect(float x, float y, float width, float height, flo
mStringStream << " RoundedRect(" << x << ',' << y << ',' << width << ',' << height << ',' << cornerRadius << ')';
}

void StringSVGPath::RoundedRect(float x, float y, float width, float height, float cornerRadiusX, float cornerRadiusY)
{
mStringStream << " RoundedRect(" << x << ',' << y << ',' << width << ',' << height << ',' << cornerRadiusX << ',' << cornerRadiusY << ')';
}

void StringSVGPath::Ellipse(float cx, float cy, float rx, float ry)
{
mStringStream << " Ellipse(" << cx << ',' << cy << ',' << rx << ',' << ry << ')';
Expand Down
1 change: 1 addition & 0 deletions svgnative/ports/string/StringSVGRenderer.h
Expand Up @@ -28,6 +28,7 @@ class StringSVGPath final : public Path

void Rect(float x, float y, float width, float height) override;
void RoundedRect(float x, float y, float width, float height, float cornerRadius) override;
void RoundedRect(float x, float y, float width, float height, float cornerRadiusX, float cornerRadiusY) override;
void Ellipse(float cx, float cy, float rx, float ry) override;

void MoveTo(float x, float y) override;
Expand Down
11 changes: 7 additions & 4 deletions svgnative/src/SVGDocumentImpl.cpp
Expand Up @@ -498,18 +498,21 @@ std::unique_ptr<Path> SVGDocumentImpl::ParseShape(XMLNode* child)
ry = 0;
}

rx = std::min(rx, width / 2.0f);
ry = std::min(ry, height / 2.0f);
rx = std::max(0.0f, std::min(rx, width / 2.0f));
ry = std::max(0.0f, std::min(ry, height / 2.0f));

auto path = mRenderer->CreatePath();
if (rx == 0 && ry == 0)
{
path->Rect(x, y, width, height);
}
else if (rx == ry)
{
path->RoundedRect(x, y, width, height, rx);
}
else
{
SVG_ASSERT(rx == ry);
path->RoundedRect(x, y, width, height, std::max(rx, ry));
path->RoundedRect(x, y, width, height, rx, ry);
}
return path;
}
Expand Down

0 comments on commit abfb9aa

Please sign in to comment.