path.cc 10.0 KB
Newer Older
M
Michael Goderbauer 已提交
1
// Copyright 2013 The Flutter Authors. All rights reserved.
2 3 4 5 6
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/lib/ui/painting/path.h"

7
#define _USE_MATH_DEFINES
8 9 10
#include <math.h>

#include "flutter/lib/ui/painting/matrix.h"
11
#include "flutter/lib/ui/ui_dart_state.h"
12 13 14 15
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/dart_args.h"
#include "third_party/tonic/dart_binding_macros.h"
#include "third_party/tonic/dart_library_natives.h"
16

17 18
using tonic::ToDart;

19
namespace flutter {
20 21 22 23

typedef CanvasPath Path;

static void Path_constructor(Dart_NativeArguments args) {
24
  UIDartState::ThrowIfUIOperationsProhibited();
25
  DartCallConstructor(&CanvasPath::CreateNew, args);
26 27 28 29
}

IMPLEMENT_WRAPPERTYPEINFO(ui, Path);

30 31
#define FOR_EACH_BINDING(V)          \
  V(Path, addArc)                    \
32 33
  V(Path, addOval)                   \
  V(Path, addPath)                   \
34
  V(Path, addPolygon)                \
35
  V(Path, addRect)                   \
36
  V(Path, addRRect)                  \
37 38
  V(Path, arcTo)                     \
  V(Path, arcToPoint)                \
39
  V(Path, close)                     \
40
  V(Path, conicTo)                   \
41
  V(Path, contains)                  \
42 43
  V(Path, cubicTo)                   \
  V(Path, extendWithPath)            \
44
  V(Path, extendWithPathAndMatrix)   \
45 46 47 48 49 50 51 52 53 54 55 56
  V(Path, getFillType)               \
  V(Path, lineTo)                    \
  V(Path, moveTo)                    \
  V(Path, quadraticBezierTo)         \
  V(Path, relativeArcToPoint)        \
  V(Path, relativeConicTo)           \
  V(Path, relativeCubicTo)           \
  V(Path, relativeLineTo)            \
  V(Path, relativeMoveTo)            \
  V(Path, relativeQuadraticBezierTo) \
  V(Path, reset)                     \
  V(Path, setFillType)               \
57
  V(Path, shift)                     \
58 59 60 61 62
  V(Path, transform)                 \
  V(Path, getBounds)                 \
  V(Path, addPathWithMatrix)         \
  V(Path, op)                        \
  V(Path, clone)
63 64 65

FOR_EACH_BINDING(DART_NATIVE_CALLBACK)

66
void CanvasPath::RegisterNatives(tonic::DartLibraryNatives* natives) {
67 68
  natives->Register({{"Path_constructor", Path_constructor, 1, true},
                     FOR_EACH_BINDING(DART_REGISTER_NATIVE)});
69 70
}

71
CanvasPath::CanvasPath() {}
72

73
CanvasPath::~CanvasPath() {}
74 75

int CanvasPath::getFillType() {
76
  return static_cast<int>(path_.getFillType());
77 78 79
}

void CanvasPath::setFillType(int fill_type) {
80
  path_.setFillType(static_cast<SkPathFillType>(fill_type));
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
}

void CanvasPath::moveTo(float x, float y) {
  path_.moveTo(x, y);
}

void CanvasPath::relativeMoveTo(float x, float y) {
  path_.rMoveTo(x, y);
}

void CanvasPath::lineTo(float x, float y) {
  path_.lineTo(x, y);
}

void CanvasPath::relativeLineTo(float x, float y) {
  path_.rLineTo(x, y);
}

void CanvasPath::quadraticBezierTo(float x1, float y1, float x2, float y2) {
  path_.quadTo(x1, y1, x2, y2);
}

103 104 105
void CanvasPath::relativeQuadraticBezierTo(float x1,
                                           float y1,
                                           float x2,
106 107 108 109
                                           float y2) {
  path_.rQuadTo(x1, y1, x2, y2);
}

110 111 112 113 114
void CanvasPath::cubicTo(float x1,
                         float y1,
                         float x2,
                         float y2,
                         float x3,
115 116 117 118
                         float y3) {
  path_.cubicTo(x1, y1, x2, y2, x3, y3);
}

119 120 121 122 123 124
void CanvasPath::relativeCubicTo(float x1,
                                 float y1,
                                 float x2,
                                 float y2,
                                 float x3,
                                 float y3) {
125 126 127 128 129 130 131
  path_.rCubicTo(x1, y1, x2, y2, x3, y3);
}

void CanvasPath::conicTo(float x1, float y1, float x2, float y2, float w) {
  path_.conicTo(x1, y1, x2, y2, w);
}

132 133 134 135
void CanvasPath::relativeConicTo(float x1,
                                 float y1,
                                 float x2,
                                 float y2,
136 137 138 139
                                 float w) {
  path_.rConicTo(x1, y1, x2, y2, w);
}

140 141 142 143 144 145 146
void CanvasPath::arcTo(float left,
                       float top,
                       float right,
                       float bottom,
                       float startAngle,
                       float sweepAngle,
                       bool forceMoveTo) {
147
  path_.arcTo(SkRect::MakeLTRB(left, top, right, bottom),
148
              startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI,
149 150 151
              forceMoveTo);
}

152 153 154 155 156 157 158 159 160
void CanvasPath::arcToPoint(float arcEndX,
                            float arcEndY,
                            float radiusX,
                            float radiusY,
                            float xAxisRotation,
                            bool isLargeArc,
                            bool isClockwiseDirection) {
  const auto arcSize = isLargeArc ? SkPath::ArcSize::kLarge_ArcSize
                                  : SkPath::ArcSize::kSmall_ArcSize;
161 162
  const auto direction =
      isClockwiseDirection ? SkPathDirection::kCW : SkPathDirection::kCCW;
163 164 165 166 167 168 169 170 171 172 173 174 175 176

  path_.arcTo(radiusX, radiusY, xAxisRotation, arcSize, direction, arcEndX,
              arcEndY);
}

void CanvasPath::relativeArcToPoint(float arcEndDeltaX,
                                    float arcEndDeltaY,
                                    float radiusX,
                                    float radiusY,
                                    float xAxisRotation,
                                    bool isLargeArc,
                                    bool isClockwiseDirection) {
  const auto arcSize = isLargeArc ? SkPath::ArcSize::kLarge_ArcSize
                                  : SkPath::ArcSize::kSmall_ArcSize;
177 178
  const auto direction =
      isClockwiseDirection ? SkPathDirection::kCW : SkPathDirection::kCCW;
179 180 181 182
  path_.rArcTo(radiusX, radiusY, xAxisRotation, arcSize, direction,
               arcEndDeltaX, arcEndDeltaY);
}

183 184 185 186 187 188 189 190
void CanvasPath::addRect(float left, float top, float right, float bottom) {
  path_.addRect(SkRect::MakeLTRB(left, top, right, bottom));
}

void CanvasPath::addOval(float left, float top, float right, float bottom) {
  path_.addOval(SkRect::MakeLTRB(left, top, right, bottom));
}

191 192 193 194 195 196
void CanvasPath::addArc(float left,
                        float top,
                        float right,
                        float bottom,
                        float startAngle,
                        float sweepAngle) {
197
  path_.addArc(SkRect::MakeLTRB(left, top, right, bottom),
198
               startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI);
199 200
}

201
void CanvasPath::addPolygon(const tonic::Float32List& points, bool close) {
202
  path_.addPoly(reinterpret_cast<const SkPoint*>(points.data()),
203
                points.num_elements() / 2, close);
204 205 206 207 208 209 210
}

void CanvasPath::addRRect(const RRect& rrect) {
  path_.addRRect(rrect.sk_rrect);
}

void CanvasPath::addPath(CanvasPath* path, double dx, double dy) {
211 212 213
  if (!path)
    Dart_ThrowException(ToDart("Path.addPath called with non-genuine Path."));
  path_.addPath(path->path(), dx, dy, SkPath::kAppend_AddPathMode);
214 215
}

216 217 218 219 220 221 222 223
void CanvasPath::addPathWithMatrix(CanvasPath* path,
                                   double dx,
                                   double dy,
                                   tonic::Float64List& matrix4) {
  if (!path) {
    Dart_ThrowException(
        ToDart("Path.addPathWithMatrix called with non-genuine Path."));
  }
224

225 226 227 228 229 230 231
  SkMatrix matrix = ToSkMatrix(matrix4);
  matrix.setTranslateX(matrix.getTranslateX() + dx);
  matrix.setTranslateY(matrix.getTranslateY() + dy);
  path_.addPath(path->path(), matrix, SkPath::kAppend_AddPathMode);
  matrix4.Release();
}

232
void CanvasPath::extendWithPath(CanvasPath* path, double dx, double dy) {
233
  if (!path)
234 235
    Dart_ThrowException(
        ToDart("Path.extendWithPath called with non-genuine Path."));
236
  path_.addPath(path->path(), dx, dy, SkPath::kExtend_AddPathMode);
237 238
}

239 240 241 242 243 244 245 246
void CanvasPath::extendWithPathAndMatrix(CanvasPath* path,
                                         double dx,
                                         double dy,
                                         tonic::Float64List& matrix4) {
  if (!path) {
    Dart_ThrowException(
        ToDart("Path.addPathWithMatrix called with non-genuine Path."));
  }
247

248 249 250 251 252 253 254
  SkMatrix matrix = ToSkMatrix(matrix4);
  matrix.setTranslateX(matrix.getTranslateX() + dx);
  matrix.setTranslateY(matrix.getTranslateY() + dy);
  path_.addPath(path->path(), matrix, SkPath::kExtend_AddPathMode);
  matrix4.Release();
}

255 256 257 258 259 260 261 262 263 264 265 266
void CanvasPath::close() {
  path_.close();
}

void CanvasPath::reset() {
  path_.reset();
}

bool CanvasPath::contains(double x, double y) {
  return path_.contains(x, y);
}

267 268
void CanvasPath::shift(Dart_Handle path_handle, double dx, double dy) {
  fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle);
269 270 271
  path_.offset(dx, dy, &path->path_);
}

272 273 274
void CanvasPath::transform(Dart_Handle path_handle,
                           tonic::Float64List& matrix4) {
  fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle);
275
  path_.transform(ToSkMatrix(matrix4), &path->path_);
A
Adam Barth 已提交
276
  matrix4.Release();
277 278
}

279 280 281 282 283 284 285 286 287 288 289 290 291 292
tonic::Float32List CanvasPath::getBounds() {
  tonic::Float32List rect(Dart_NewTypedData(Dart_TypedData_kFloat32, 4));
  const SkRect& bounds = path_.getBounds();
  rect[0] = bounds.left();
  rect[1] = bounds.top();
  rect[2] = bounds.right();
  rect[3] = bounds.bottom();
  return rect;
}

bool CanvasPath::op(CanvasPath* path1, CanvasPath* path2, int operation) {
  return Op(path1->path(), path2->path(), (SkPathOp)operation, &path_);
}

293 294
void CanvasPath::clone(Dart_Handle path_handle) {
  fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle);
295 296 297 298 299
  // per Skia docs, this will create a fast copy
  // data is shared until the source path or dest path are mutated
  path->path_ = path_;
}

300 301 302 303 304 305 306
// This is doomed to be called too early, since Paths are mutable.
// However, it can help for some of the clone/shift/transform type methods
// where the resultant path will initially have a meaningful size.
size_t CanvasPath::GetAllocationSize() const {
  return sizeof(CanvasPath) + path_.approximateBytesUsed();
}

307
}  // namespace flutter