Adding contour stroke.
diff --git a/include/contour_render_path.hpp b/include/contour_render_path.hpp
index 7392acd..9911f99 100644
--- a/include/contour_render_path.hpp
+++ b/include/contour_render_path.hpp
@@ -82,6 +82,11 @@
 
 	public:
 		std::size_t contourLength() const { return m_ContourVertices.size(); }
+		const std::vector<Vec2D>& contourVertices() const
+		{
+			return m_ContourVertices;
+		}
+
 		bool isContainer() const;
 		void addRenderPath(RenderPath* path, const Mat2D& transform) override;
 
diff --git a/include/contour_stroke.hpp b/include/contour_stroke.hpp
new file mode 100644
index 0000000..118974a
--- /dev/null
+++ b/include/contour_stroke.hpp
@@ -0,0 +1,29 @@
+#ifndef _RIVE_CONTOUR_STROKE_HPP_
+#define _RIVE_CONTOUR_STROKE_HPP_
+
+#include "renderer.hpp"
+#include "math/aabb.hpp"
+#include <vector>
+#include <cstdint>
+
+namespace rive
+{
+	class ContourRenderPath;
+
+	///
+	/// Builds a triangle strip vertex buffer from a ContourRenderPath.
+	///
+	class ContourStroke
+	{
+	protected:
+		std::vector<Vec2D> m_TriangleStrip;
+
+	public:
+		void extrude(const ContourRenderPath* renderPath,
+		             bool isClosed,
+		             StrokeJoin join,
+		             StrokeCap cap,
+		             float strokeWidth);
+	};
+} // namespace rive
+#endif
\ No newline at end of file
diff --git a/src/contour_stroke.cpp b/src/contour_stroke.cpp
new file mode 100644
index 0000000..0657d6e
--- /dev/null
+++ b/src/contour_stroke.cpp
@@ -0,0 +1,35 @@
+#ifdef LOW_LEVEL_RENDERING
+#include "contour_stroke.hpp"
+#include "contour_render_path.hpp"
+#include "math/vec2d.hpp"
+
+using namespace rive;
+
+void ContourStroke::extrude(const ContourRenderPath* renderPath,
+                            bool isClosed,
+                            StrokeJoin join,
+                            StrokeCap cap,
+                            float strokeWidth)
+{
+	m_TriangleStrip.clear();
+
+	const std::vector<Vec2D>& points = renderPath->contourVertices();
+	auto size = points.size();
+	if (size < 2)
+	{
+		return;
+	}
+	const Vec2D& lastPoint = points[0];
+	Vec2D lastDiff;
+	Vec2D::subtract(lastDiff, points[1], lastPoint);
+	float lastLength = Vec2D::length(lastDiff);
+	Vec2D lastDiffNormalized;
+	Vec2D::scale(lastDiffNormalized, lastDiff, 1.0f / lastLength);
+
+	Vec2D lastA, lastB;
+	Vec2D perpendicularStrokeDiff = Vec2D(lastDiffNormalized[1] * -strokeWidth,
+	                                      lastDiffNormalized[0] * strokeWidth);
+	Vec2D::add(lastA, lastPoint, perpendicularStrokeDiff);
+	Vec2D::subtract(lastB, lastPoint, perpendicularStrokeDiff);
+}
+#endif
\ No newline at end of file