提交 5f14c774 编写于 作者: A Adam Barth 提交者: GitHub

Implement Canvas.drawPoints (#2748)

* Implement Canvas.drawPoints

This enables drawing polygons faster than using Paths.

Fixes https://github.com/flutter/flutter/issues/92

* Implement more Path functions

Path.fillType
Path.addPolygon
Path.addPath
Path.extendWithPath
Path.transform

Fixes https://github.com/flutter/flutter/issues/252
上级 f7405a37
......@@ -37,6 +37,21 @@ void decodeImageFromDataPipe(int handle, ImageDecoderCallback callback)
void decodeImageFromList(Uint8List list, ImageDecoderCallback callback)
native "decodeImageFromList";
/// Determines how the interior of a [Path] is calculated.
enum PathFillType {
/// The interior is defined by a non-zero sum of signed edge crossings.
winding,
/// The interior is defined by an odd number of edge crossings.
evenOdd,
/// The interior is defined as the exterior region calculated by [winding].
inverseWinding,
/// The interior is defined as the exterior region calculated by [evenOdd].
inverseEvenOdd,
}
/// A complex, one-dimensional subset of a plane.
///
/// A path consists of a number of subpaths, and a _current point_.
......@@ -61,6 +76,13 @@ class Path extends NativeFieldWrapperClass2 {
Path() { _constructor(); }
void _constructor() native "Path_constructor";
/// Determines how the interior of this path is calculated.
PathFillType get fillType => PathFillType.values[_getFillType()];
set fillType (PathFillType value) => _setFillType(value.index);
int _getFillType() native "Path_getFillType";
void _setFillType(int fillType) native "Path_setFillType";
/// Starts a new subpath at the given coordinate.
void moveTo(double x, double y) native "Path_moveTo";
......@@ -162,12 +184,30 @@ class Path extends NativeFieldWrapperClass2 {
void _addArc(double left, double top, double right, double bottom,
double startAngle, double sweepAngle) native "Path_addArc";
/// Adds a new subpath with a sequence of line segments that connect the given
/// points. If `close` is true, a final line segment will be added that
/// connects the last point to the first point.
void addPolygon(List<Point> points, bool close) {
_addPolygon(_encodePointList(points), close);
}
void _addPolygon(Float32List points, bool close) native "Path_addPolygon";
/// Adds a new subpath that consists of the straight lines and
/// curves needed to form the rounded rectangle described by the
/// argument.
void addRRect(RRect rrect) => _addRRect(rrect._value);
void _addRRect(Float32List rrect) native "Path_addRRect";
/// Adds a new subpath that consists of the given path offset by the given
/// offset.
void addPath(Path path, Offset offset) => _addPath(path, offset.dx, offset.dy);
void _addPath(Path path, double dx, double dy) native "Path_addPath";
/// Adds the given path to this path by extending the current segment of this
/// path with the the first segment of the given path.
void extendWithPath(Path path, Offset offset) => _extendWithPath(path, offset.dx, offset.dy);
void _extendWithPath(Path path, double dx, double dy) native "Path_extendWithPath";
/// Closes the last subpath, as if a straight line had been drawn
/// from the current point to the first point of the subpath.
void close() native "Path_close";
......@@ -189,6 +229,15 @@ class Path extends NativeFieldWrapperClass2 {
/// subpath translated by the given offset.
Path shift(Offset offset) => _shift(offset.dx, offset.dy);
Path _shift(double dx, double dy) native "Path_shift";
/// Returns a copy of the path with all the segments of every
/// subpath transformed by the given matrix.
Path transform(Float64List matrix4) {
if (matrix4.length != 16)
throw new ArgumentError("[matrix4] must have 16 entries.");
return _transform(matrix4);
}
Path _transform(Float64List matrix4) native "Path_transform";
}
/// Styles to use for blurs in [MaskFilter] objects.
......@@ -433,13 +482,33 @@ class ImageShader extends Shader {
}
/// Defines how a list of points is interpreted when drawing a set of triangles.
/// See Skia or OpenGL documentation for more details.
///
/// Used by [Canvas.drawVertices].
enum VertexMode {
/// Draw each sequence of three points as the vertices of a triangle.
triangles,
/// Draw each sliding window of three points as the vertices of a triangle.
triangleStrip,
/// Draw the first point and each sliding window of two points as the vertices of a triangle.
triangleFan,
}
/// Defines how a list of points is interpreted when drawing a set of points.
///
/// Used by [Canvas.drawPoints].
enum PointMode {
// Draw each point separately.
points,
// Draw each sequence of two points as a line segment.
lines,
// Draw the entire sequence of point as the vertices of a polygon.
polygon,
}
/// An interface for recording graphical operations.
///
/// [Canvas] objects are used in creating [Picture] objects, which can
......@@ -742,6 +811,12 @@ class Canvas extends NativeFieldWrapperClass2 {
}
void _drawParagraph(Paragraph paragraph, double x, double y) native "Canvas_drawParagraph";
/// Draws a sequence of points according to the given [PointMode].
void drawPoints(PointMode pointMode, List<Point> points, Paint paint) {
_drawPoints(pointMode.index, _encodePointList(points), paint);
}
void _drawPoints(int pointMode, Float32List points, Paint paint) native "Canvas_drawPoints";
void drawVertices(VertexMode vertexMode,
List<Point> vertices,
List<Point> textureCoordinates,
......
......@@ -53,6 +53,7 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Canvas);
V(Canvas, drawImageNine) \
V(Canvas, drawPicture) \
V(Canvas, drawParagraph) \
V(Canvas, drawPoints) \
V(Canvas, drawVertices) \
V(Canvas, drawAtlas)
......@@ -329,6 +330,22 @@ void Canvas::drawParagraph(Paragraph* paragraph, double x, double y) {
paragraph->paint(this, x, y);
}
void Canvas::drawPoints(SkCanvas::PointMode pointMode,
const Float32List& points,
const Paint& paint) {
if (!m_canvas)
return;
static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint doesn't use floats.");
m_canvas->drawPoints(
pointMode,
points.num_elements() / 2, // SkPoints have two floats.
reinterpret_cast<const SkPoint*>(points.data()),
*paint.paint()
);
}
void Canvas::drawVertices(
SkCanvas::VertexMode vertexMode,
const Float32List& vertices,
......@@ -353,7 +370,7 @@ void Canvas::drawVertices(
m_canvas->drawVertices(
vertexMode,
vertices.num_elements(),
vertices.num_elements() / 2, // SkPoints have two floats.
reinterpret_cast<const SkPoint*>(vertices.data()),
reinterpret_cast<const SkPoint*>(textureCoordinates.data()),
reinterpret_cast<const SkColor*>(colors.data()),
......@@ -385,7 +402,7 @@ void Canvas::drawAtlas(
reinterpret_cast<const SkRSXform*>(transforms.data()),
reinterpret_cast<const SkRect*>(rects.data()),
reinterpret_cast<const SkColor*>(colors.data()),
rects.num_elements(),
rects.num_elements() / 4, // SkRect have four floats.
static_cast<SkXfermode::Mode>(transferMode),
reinterpret_cast<const SkRect*>(cullRect.data()),
paint.paint()
......
......@@ -22,6 +22,9 @@ class CanvasImage;
class DartLibraryNatives;
class Paragraph;
template <>
struct DartConverter<SkCanvas::PointMode> : public DartConverterInteger<SkCanvas::PointMode> {};
template <>
struct DartConverter<SkCanvas::VertexMode> : public DartConverterInteger<SkCanvas::VertexMode> {};
......@@ -101,6 +104,10 @@ public:
void drawPicture(Picture* picture);
void drawParagraph(Paragraph* paragraph, double x, double y);
void drawPoints(SkCanvas::PointMode pointMode,
const Float32List& points,
const Paint& paint);
void drawVertices(SkCanvas::VertexMode vertexMode,
const Float32List& vertices,
const Float32List& textureCoordinates,
......
......@@ -40,8 +40,8 @@ void CanvasGradient::initLinear(const Float32List& end_points,
const Int32List& colors,
const Float32List& color_stops,
SkShader::TileMode tile_mode) {
DCHECK(end_points.num_elements() == 2);
DCHECK(colors.num_elements() == color_stops.num_elements() || color_stops.data() == nullptr);
DCHECK(end_points.num_elements() == 4);
DCHECK(colors.num_elements() * 2 == color_stops.num_elements() || color_stops.data() == nullptr);
static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint doesn't use floats.");
static_assert(sizeof(SkColor) == sizeof(int32_t), "SkColor doesn't use int32_t.");
......@@ -60,7 +60,7 @@ void CanvasGradient::initRadial(double centerX,
const Int32List& colors,
const Float32List& color_stops,
SkShader::TileMode tile_mode) {
DCHECK(colors.num_elements() == color_stops.num_elements() || color_stops.data() == nullptr);
DCHECK(colors.num_elements() * 2 == color_stops.num_elements() || color_stops.data() == nullptr);
static_assert(sizeof(SkColor) == sizeof(int32_t), "SkColor doesn't use int32_t.");
......
......@@ -8,6 +8,7 @@
#include "flutter/tonic/dart_binding_macros.h"
#include "flutter/tonic/dart_converter.h"
#include "flutter/tonic/dart_library_natives.h"
#include "sky/engine/core/painting/Matrix.h"
namespace blink {
......@@ -20,6 +21,8 @@ static void Path_constructor(Dart_NativeArguments args) {
IMPLEMENT_WRAPPERTYPEINFO(ui, Path);
#define FOR_EACH_BINDING(V) \
V(Path, getFillType) \
V(Path, setFillType) \
V(Path, moveTo) \
V(Path, relativeMoveTo) \
V(Path, lineTo) \
......@@ -34,11 +37,15 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Path);
V(Path, addRect) \
V(Path, addOval) \
V(Path, addArc) \
V(Path, addPolygon) \
V(Path, addRRect) \
V(Path, addPath) \
V(Path, extendWithPath) \
V(Path, close) \
V(Path, reset) \
V(Path, contains) \
V(Path, shift)
V(Path, shift) \
V(Path, transform)
FOR_EACH_BINDING(DART_NATIVE_CALLBACK)
......@@ -63,4 +70,10 @@ scoped_refptr<CanvasPath> CanvasPath::shift(double dx, double dy) {
return std::move(path);
}
scoped_refptr<CanvasPath> CanvasPath::transform(const Float64List& matrix4) {
scoped_refptr<CanvasPath> path = CanvasPath::create();
m_path.transform(toSkMatrix(matrix4), &path->m_path);
return std::move(path);
}
} // namespace blink
......@@ -9,6 +9,8 @@
#include "base/memory/ref_counted.h"
#include "flutter/tonic/dart_wrappable.h"
#include "flutter/tonic/float32_list.h"
#include "flutter/tonic/float64_list.h"
#include "sky/engine/core/painting/RRect.h"
#include "third_party/skia/include/core/SkPath.h"
......@@ -27,6 +29,9 @@ public:
~CanvasPath() override;
static scoped_refptr<CanvasPath> create() { return new CanvasPath(); }
int getFillType() { return m_path.getFillType(); }
void setFillType(int fill_type) { m_path.setFillType(static_cast<SkPath::FillType>(fill_type)); }
void moveTo(float x, float y) { m_path.moveTo(x, y); }
void relativeMoveTo(float x, float y) { m_path.rMoveTo(x, y); }
void lineTo(float x, float y) { m_path.lineTo(x, y); }
......@@ -45,11 +50,23 @@ public:
void addArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle) {
m_path.addArc(SkRect::MakeLTRB(left, top, right, bottom), startAngle*180.0/M_PI, sweepAngle*180.0/M_PI);
}
void addPolygon(const Float32List& points, bool close) {
m_path.addPoly(reinterpret_cast<const SkPoint*>(points.data()), points.num_elements() / 2, close);
}
void addRRect(const RRect& rrect) { m_path.addRRect(rrect.sk_rrect); }
void addPath(CanvasPath* path, double dx, double dy) {
if (path)
m_path.addPath(path->path(), dx, dy, SkPath::kAppend_AddPathMode);
}
void extendWithPath(CanvasPath* path, double dx, double dy) {
if (path)
m_path.addPath(path->path(), dx, dy, SkPath::kExtend_AddPathMode);
}
void close() { m_path.close(); }
void reset() { m_path.reset(); }
bool contains(double x, double y) { return m_path.contains(x, y); }
scoped_refptr<CanvasPath> shift(double dx, double dy);
scoped_refptr<CanvasPath> transform(const Float64List& matrix4);
const SkPath& path() const { return m_path; }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册