painting.dart 98.3 KB
Newer Older
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

A
Adam Barth 已提交
5
part of dart.ui;
6

7 8 9 10 11 12 13 14
// Some methods in this file assert that their arguments are not null. These
// asserts are just to improve the error messages; they should only cover
// arguments that are either dereferenced _in Dart_, before being passed to the
// engine, or that the engine explicitly null-checks itself (after attempting to
// convert the argument to a native type). It should not be possible for a null
// or invalid value to be used by the engine even in release mode, since that
// would cause a crash. It is, however, acceptable for error messages to be much
// less useful or correct in release mode than in debug mode.
15
//
16 17
// Painting APIs will also warn about arguments representing NaN coordinates,
// which can not be rendered by Skia.
18

19 20 21 22 23
// Update this list when changing the list of supported codecs.
/// {@template flutter.dart:ui.imageFormats}
/// JPEG, PNG, GIF, Animated GIF, WebP, Animated WebP, BMP, and WBMP
/// {@endtemplate}

24
bool _rectIsValid(Rect rect) {
25 26 27
  assert(rect != null, 'Rect argument was null.');
  assert(!rect._value.any((double value) => value.isNaN), 'Rect argument contained a NaN value.');
  return true;
28 29 30
}

bool _rrectIsValid(RRect rrect) {
31 32 33
  assert(rrect != null, 'RRect argument was null.');
  assert(!rrect._value.any((double value) => value.isNaN), 'RRect argument contained a NaN value.');
  return true;
34 35 36
}

bool _offsetIsValid(Offset offset) {
37 38 39
  assert(offset != null, 'Offset argument was null.');
  assert(!offset.dx.isNaN && !offset.dy.isNaN, 'Offset argument contained a NaN value.');
  return true;
40
}
41

42 43 44 45 46 47
bool _radiusIsValid(Radius radius) {
  assert(radius != null, 'Radius argument was null.');
  assert(!radius.x.isNaN && !radius.y.isNaN, 'Radius argument contained a NaN value.');
  return true;
}

48
Color _scaleAlpha(Color a, double factor) {
49
  return a.withAlpha((a.alpha * factor).round().clamp(0, 255));
50 51
}

I
Ian Hickson 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
/// An immutable 32 bit color value in ARGB format.
///
/// Consider the light teal of the Flutter logo. It is fully opaque, with a red
/// channel value of 0x42 (66), a green channel value of 0xA5 (165), and a blue
/// channel value of 0xF5 (245). In the common "hash syntax" for colour values,
/// it would be described as `#42A5F5`.
///
/// Here are some ways it could be constructed:
///
/// ```dart
/// Color c = const Color(0xFF42A5F5);
/// Color c = const Color.fromARGB(0xFF, 0x42, 0xA5, 0xF5);
/// Color c = const Color.fromARGB(255, 66, 165, 245);
/// Color c = const Color.fromRGBO(66, 165, 245, 1.0);
/// ```
///
/// If you are having a problem with `Color` wherein it seems your color is just
/// not painting, check to make sure you are specifying the full 8 hexadecimal
/// digits. If you only specify six, then the leading two digits are assumed to
/// be zero, which means fully-transparent:
///
/// ```dart
/// Color c1 = const Color(0xFFFFFF); // fully transparent white (invisible)
/// Color c2 = const Color(0xFFFFFFFF); // fully opaque white (visible)
/// ```
S
Seth Ladd 已提交
77 78 79 80 81
///
/// See also:
///
///  * [Colors](https://docs.flutter.io/flutter/material/Colors-class.html), which
///    defines the colors found in the Material Design specification.
82
class Color {
I
Ian Hickson 已提交
83
  /// Construct a color from the lower 32 bits of an [int].
84
  ///
I
Ian Hickson 已提交
85 86 87 88 89 90 91 92 93 94 95 96 97 98
  /// The bits are interpreted as follows:
  ///
  /// * Bits 24-31 are the alpha value.
  /// * Bits 16-23 are the red value.
  /// * Bits 8-15 are the green value.
  /// * Bits 0-7 are the blue value.
  ///
  /// In other words, if AA is the alpha value in hex, RR the red value in hex,
  /// GG the green value in hex, and BB the blue value in hex, a color can be
  /// expressed as `const Color(0xAARRGGBB)`.
  ///
  /// For example, to get a fully opaque orange, you would use `const
  /// Color(0xFFFF9000)` (`FF` for the alpha, `FF` for the red, `90` for the
  /// green, and `00` for the blue).
99
  const Color(int value) : value = value & 0xFFFFFFFF;
100 101

  /// Construct a color from the lower 8 bits of four integers.
A
Adam Barth 已提交
102 103 104 105 106 107 108 109 110 111 112
  ///
  /// * `a` is the alpha value, with 0 being transparent and 255 being fully
  ///   opaque.
  /// * `r` is [red], from 0 to 255.
  /// * `g` is [red], from 0 to 255.
  /// * `b` is [red], from 0 to 255.
  ///
  /// Out of range values are brought into range using modulo 255.
  ///
  /// See also [fromARGB], which takes the alpha value as a floating point
  /// value.
113
  const Color.fromARGB(int a, int r, int g, int b) :
114 115 116 117
    value = (((a & 0xff) << 24) |
             ((r & 0xff) << 16) |
             ((g & 0xff) << 8)  |
             ((b & 0xff) << 0)) & 0xFFFFFFFF;
118

A
Adam Barth 已提交
119 120 121 122 123 124 125 126 127 128 129 130
  /// Create a color from red, green, blue, and opacity, similar to `rgba()` in CSS.
  ///
  /// * `r` is [red], from 0 to 255.
  /// * `g` is [red], from 0 to 255.
  /// * `b` is [red], from 0 to 255.
  /// * `opacity` is alpha channel of this color as a double, with 0.0 being
  ///   transparent and 1.0 being fully opaque.
  ///
  /// Out of range values are brought into range using modulo 255.
  ///
  /// See also [fromARGB], which takes the opacity as an integer value.
  const Color.fromRGBO(int r, int g, int b, double opacity) :
131 132 133 134
    value = ((((opacity * 0xff ~/ 1) & 0xff) << 24) |
              ((r                    & 0xff) << 16) |
              ((g                    & 0xff) << 8)  |
              ((b                    & 0xff) << 0)) & 0xFFFFFFFF;
A
Adam Barth 已提交
135

136 137
  /// A 32 bit value representing this color.
  ///
I
Ian Hickson 已提交
138 139 140 141 142 143
  /// The bits are assigned as follows:
  ///
  /// * Bits 24-31 are the alpha value.
  /// * Bits 16-23 are the red value.
  /// * Bits 8-15 are the green value.
  /// * Bits 0-7 are the blue value.
144
  final int value;
145 146

  /// The alpha channel of this color in an 8 bit value.
A
Adam Barth 已提交
147 148 149
  ///
  /// A value of 0 means this color is fully transparent. A value of 255 means
  /// this color is fully opaque.
150
  int get alpha => (0xff000000 & value) >> 24;
151 152

  /// The alpha channel of this color as a double.
A
Adam Barth 已提交
153 154 155
  ///
  /// A value of 0.0 means this color is fully transparent. A value of 1.0 means
  /// this color is fully opaque.
156 157 158
  double get opacity => alpha / 0xFF;

  /// The red channel of this color in an 8 bit value.
159
  int get red => (0x00ff0000 & value) >> 16;
160 161

  /// The green channel of this color in an 8 bit value.
162
  int get green => (0x0000ff00 & value) >> 8;
163 164

  /// The blue channel of this color in an 8 bit value.
165
  int get blue => (0x000000ff & value) >> 0;
166 167

  /// Returns a new color that matches this color with the alpha channel
I
Ian Hickson 已提交
168
  /// replaced with `a` (which ranges from 0 to 255).
169 170
  ///
  /// Out of range values will have unexpected effects.
171 172 173 174 175
  Color withAlpha(int a) {
    return new Color.fromARGB(a, red, green, blue);
  }

  /// Returns a new color that matches this color with the alpha channel
I
Ian Hickson 已提交
176
  /// replaced with the given `opacity` (which ranges from 0.0 to 1.0).
177 178
  ///
  /// Out of range values will have unexpected effects.
179 180 181 182 183 184
  Color withOpacity(double opacity) {
    assert(opacity >= 0.0 && opacity <= 1.0);
    return withAlpha((255.0 * opacity).round());
  }

  /// Returns a new color that matches this color with the red channel replaced
185 186 187
  /// with `r` (which ranges from 0 to 255).
  ///
  /// Out of range values will have unexpected effects.
188 189 190 191 192
  Color withRed(int r) {
    return new Color.fromARGB(alpha, r, green, blue);
  }

  /// Returns a new color that matches this color with the green channel
193 194 195
  /// replaced with `g` (which ranges from 0 to 255).
  ///
  /// Out of range values will have unexpected effects.
196 197 198 199 200
  Color withGreen(int g) {
    return new Color.fromARGB(alpha, red, g, blue);
  }

  /// Returns a new color that matches this color with the blue channel replaced
201 202 203
  /// with `b` (which ranges from 0 to 255).
  ///
  /// Out of range values will have unexpected effects.
204 205 206 207
  Color withBlue(int b) {
    return new Color.fromARGB(alpha, red, green, b);
  }

X
xster 已提交
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
  // See <https://www.w3.org/TR/WCAG20/#relativeluminancedef>
  static double _linearizeColorComponent(double component) {
    if (component <= 0.03928)
      return component / 12.92;
    return math.pow((component + 0.055) / 1.055, 2.4);
  }

  /// Returns a brightness value between 0 for darkest and 1 for lightest.
  ///
  /// Represents the relative luminance of the color. This value is computationally
  /// expensive to calculate.
  ///
  /// See <https://en.wikipedia.org/wiki/Relative_luminance>.
  double computeLuminance() {
    // See <https://www.w3.org/TR/WCAG20/#relativeluminancedef>
    final double R = _linearizeColorComponent(red / 0xFF);
    final double G = _linearizeColorComponent(green / 0xFF);
    final double B = _linearizeColorComponent(blue / 0xFF);
    return 0.2126 * R + 0.7152 * G + 0.0722 * B;
  }

I
Ian Hickson 已提交
229
  /// Linearly interpolate between two colors.
230
  ///
231 232 233
  /// This is intended to be fast but as a result may be ugly. Consider
  /// [HSVColor] or writing custom logic for interpolating colors.
  ///
234
  /// If either color is null, this function linearly interpolates from a
235
  /// transparent instance of the other color. This is usually preferable to
236 237
  /// interpolating from [material.Colors.transparent] (`const
  /// Color(0x00000000)`), which is specifically transparent _black_.
238
  ///
239 240 241 242 243 244 245 246 247
  /// The `t` argument represents position on the timeline, with 0.0 meaning
  /// that the interpolation has not started, returning `a` (or something
  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
  /// returning `b` (or something equivalent to `b`), and values in between
  /// meaning that the interpolation is at the relevant point on the timeline
  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
  /// 1.0, so negative values and values greater than 1.0 are valid (and can
  /// easily be generated by curves such as [Curves.elasticInOut]). Each channel
  /// will be clamped to the range 0 to 255.
248
  ///
249 250
  /// Values for `t` are usually obtained from an [Animation<double>], such as
  /// an [AnimationController].
251
  static Color lerp(Color a, Color b, double t) {
252
    assert(t != null);
253 254 255 256 257 258 259
    if (a == null && b == null)
      return null;
    if (a == null)
      return _scaleAlpha(b, t);
    if (b == null)
      return _scaleAlpha(a, 1.0 - t);
    return new Color.fromARGB(
260 261 262 263
      lerpDouble(a.alpha, b.alpha, t).toInt().clamp(0, 255),
      lerpDouble(a.red, b.red, t).toInt().clamp(0, 255),
      lerpDouble(a.green, b.green, t).toInt().clamp(0, 255),
      lerpDouble(a.blue, b.blue, t).toInt().clamp(0, 255),
264 265 266 267 268
    );
  }

  @override
  bool operator ==(dynamic other) {
269 270 271
    if (identical(this, other))
      return true;
    if (other.runtimeType != runtimeType)
272 273 274 275 276 277
      return false;
    final Color typedOther = other;
    return value == typedOther.value;
  }

  @override
278
  int get hashCode => value.hashCode;
279 280

  @override
281
  String toString() => "Color(0x${value.toRadixString(16).padLeft(8, '0')})";
282 283 284 285 286 287 288 289
}

/// Algorithms to use when painting on the canvas.
///
/// When drawing a shape or image onto a canvas, different algorithms
/// can be used to blend the pixels. The image below shows the effects
/// of these modes.
///
290
/// [![Open Skia fiddle to view image.](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode.png)](https://fiddle.skia.org/c/864acd0659c7a866ea7296a3184b8bdd)
291
///
292 293 294 295
/// The "src" (source) image is the shape or image being drawn, the "dst"
/// (destination) image is the current contents of the canvas onto which the
/// source is being drawn.
///
296 297 298 299 300 301 302 303
/// When using [Canvas.saveLayer] and [Canvas.restore], the blend mode of the
/// [Paint] given to the [Canvas.saveLayer] will be applied when
/// [Canvas.restore] is called. Each call to [Canvas.saveLayer] introduces a new
/// layer onto which shapes and images are painted; when [Canvas.restore] is
/// called, that layer is then _composited_ onto the parent layer, with the
/// "src" being the most-recently-drawn shapes and images, and the "dst" being
/// the parent layer. (For the first [Canvas.saveLayer] call, the parent layer
/// is the canvas itself.)
304 305 306 307 308
///
/// See also:
///
///  * [Paint.blendMode], which uses [BlendMode] to define the compositing
///    strategy.
309
enum BlendMode {
310 311 312 313
  // This list comes from Skia's SkXfermode.h and the values (order) should be
  // kept in sync.
  // See: https://skia.org/user/api/skpaint#SkXfermode

314 315 316
  /// Drop both the source and destination images, leaving nothing.
  ///
  /// This corresponds to the "clear" Porter-Duff operator.
317
  clear,
318 319 320 321 322 323 324

  /// Drop the destination image, only paint the source image.
  ///
  /// Conceptually, the destination is first cleared, then the source image is
  /// painted.
  ///
  /// This corresponds to the "Copy" Porter-Duff operator.
325
  src,
326 327 328 329 330 331 332

  /// Drop the source image, only paint the destination image.
  ///
  /// Conceptually, the source image is discarded, leaving the destination
  /// untouched.
  ///
  /// This corresponds to the "Destination" Porter-Duff operator.
333
  dst,
334 335 336 337 338 339 340 341 342

  /// Composite the source image over the destination image.
  ///
  /// This is the default value. It represents the most intuitive case, where
  /// shapes are painted on top of what is below, with transparent areas showing
  /// the destination layer.
  ///
  /// This corresponds to the "Source over Destination" Porter-Duff operator,
  /// also known as the Painter's Algorithm.
343
  srcOver,
344 345 346 347 348 349

  /// Composite the source image under the destination image.
  ///
  /// This is the opposite of [srcOver].
  ///
  /// This corresponds to the "Destination over Source" Porter-Duff operator.
350
  dstOver,
351 352 353 354 355 356 357 358 359 360 361

  /// Show the source image, but only where the two images overlap. The
  /// destination image is not rendered, it is treated merely as a mask.
  ///
  /// To show the destination image instead, consider [dstIn].
  ///
  /// To reverse the semantic of the mask (only showing the source where the
  /// destination is absent, rather than where it is present), consider
  /// [srcOut].
  ///
  /// This corresponds to the "Source in Destination" Porter-Duff operator.
362
  srcIn,
363 364 365 366 367 368 369 370 371 372

  /// Show the destination image, but only where the two images overlap. The
  /// source image is not rendered, it is treated merely as a mask.
  ///
  /// To show the source image instead, consider [srcIn].
  ///
  /// To reverse the semantic of the mask (only showing the source where the
  /// destination is present, rather than where it is absent), consider [srcIn].
  ///
  /// This corresponds to the "Destination in Source" Porter-Duff operator.
373
  dstIn,
374 375 376 377 378 379 380 381 382 383

  /// Show the source image, but only where the two images do not overlap. The
  /// destination image is not rendered, it is treated merely as a mask.
  ///
  /// To show the destination image instead, consider [dstOut].
  ///
  /// To reverse the semantic of the mask (only showing the source where the
  /// destination is present, rather than where it is absent), consider [srcIn].
  ///
  /// This corresponds to the "Source out Destination" Porter-Duff operator.
384
  srcOut,
385 386 387 388 389 390 391 392 393 394

  /// Show the destination image, but only where the two images do not overlap. The
  /// source image is not rendered, it is treated merely as a mask.
  ///
  /// To show the source image instead, consider [srcOut].
  ///
  /// To reverse the semantic of the mask (only showing the destination where the
  /// source is present, rather than where it is absent), consider [dstIn].
  ///
  /// This corresponds to the "Destination out Source" Porter-Duff operator.
395
  dstOut,
396 397 398 399 400

  /// Composite the source image over the destination image, but only where it
  /// overlaps the destination.
  ///
  /// This corresponds to the "Source atop Destination" Porter-Duff operator.
401
  srcATop,
402 403 404 405 406

  /// Composite the destination image over the source image, but only where it
  /// overlaps the source.
  ///
  /// This corresponds to the "Destination atop Source" Porter-Duff operator.
407
  dstATop,
408 409 410 411 412

  /// Composite the source and destination images, leaving transparency where
  /// they would overlap.
  ///
  /// This corresponds to the "Source xor Destination" Porter-Duff operator.
413
  xor,
414 415 416 417

  /// Composite the source and destination images by summing their components.
  ///
  /// This corresponds to the "Source plus Destination" Porter-Duff operator.
418
  plus,
419

420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
  modulate,

  // Following blend modes are defined in the CSS Compositing standard.

  screen,  // The last coeff mode.

  overlay,
  darken,
  lighten,
  colorDodge,
  colorBurn,
  hardLight,
  softLight,
  difference,
  exclusion,
  multiply,  // The last separable mode.

  hue,
  saturation,
  color,
  luminosity,
}

/// Quality levels for image filters.
///
/// See [Paint.filterQuality].
enum FilterQuality {
  // This list comes from Skia's SkFilterQuality.h and the values (order) should
  // be kept in sync.

  /// Fastest possible filtering, albeit also the lowest quality.
  ///
  /// Typically this implies nearest-neighbour filtering.
  none,

  /// Better quality than [none], faster than [medium].
  ///
  /// Typically this implies bilinear interpolation.
  low,

  /// Better quality than [low], faster than [high].
  ///
  /// Typically this implies a combination of bilinear interpolation and
  /// pyramidal parametric prefiltering (mipmaps).
  medium,

  /// Best possible quality filtering, albeit also the slowest.
  ///
  /// Typically this implies bicubic interpolation or better.
  high,
}

/// Styles to use for line endings.
///
/// See [Paint.strokeCap].
475
// These enum values must be kept in sync with SkPaint::Cap.
476 477 478 479 480 481 482 483 484 485 486 487 488
enum StrokeCap {
  /// Begin and end contours with a flat edge and no extension.
  butt,

  /// Begin and end contours with a semi-circle extension.
  round,

  /// Begin and end contours with a half square extension. This is
  /// similar to extending each contour by half the stroke width (as
  /// given by [Paint.strokeWidth]).
  square,
}

489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
/// Styles to use for line joins.
///
/// This only affects line joins for polygons drawn by [Canvas.drawPath] and
/// rectangles, not points drawn as lines with [Canvas.drawPoints].
///
/// See [Paint.strokeJoin].
// These enum values must be kept in sync with SkPaint::Join.
enum StrokeJoin {
  /// Joins between line segments form sharp corners.
  miter,

  /// Joins between line segments are semi-circular.
  round,

  /// Joins between line segments connect the corners of the butt ends of the
  /// line segments to give a beveled appearance.
  bevel,
}

508 509 510
/// Strategies for painting shapes and paths on a canvas.
///
/// See [Paint.style].
511
// These enum values must be kept in sync with SkPaint::Style.
512 513 514 515 516
enum PaintingStyle {
  // This list comes from Skia's SkPaint.h and the values (order) should be kept
  // in sync.

  /// Apply the [Paint] to the inside of the shape. For example, when
I
Ian Hickson 已提交
517
  /// applied to the [Canvas.drawCircle] call, this results in a disc
518 519 520 521
  /// of the given size being painted.
  fill,

  /// Apply the [Paint] to the edge of the shape. For example, when
I
Ian Hickson 已提交
522
  /// applied to the [Canvas.drawCircle] call, this results is a hoop
523 524 525 526 527
  /// of the given size being painted. The line drawn on the edge will
  /// be the width given by the [Paint.strokeWidth] property.
  stroke,
}

528 529 530 531 532
// If we actually run on big endian machines, we'll need to do something smarter
// here. We don't use [Endianness.HOST_ENDIAN] because it's not a compile-time
// constant and can't propagate into the set/get calls.
const Endianness _kFakeHostEndian = Endianness.LITTLE_ENDIAN;

533 534 535 536 537
/// A description of the style to use when drawing on a [Canvas].
///
/// Most APIs on [Canvas] take a [Paint] object to describe the style
/// to use for that operation.
class Paint {
538 539 540 541 542
  // Paint objects are encoded in two buffers:
  //
  // * _data is binary data in four-byte fields, each of which is either a
  //   uint32_t or a float. The default value for each field is encoded as
  //   zero to make initialization trivial. Most values already have a default
543
  //   value of zero, but some, such as color, have a non-zero default value.
544 545 546 547 548 549 550 551 552 553 554
  //   To encode or decode these values, XOR the value with the default value.
  //
  // * _objects is a list of unencodable objects, typically wrappers for native
  //   objects. The objects are simply stored in the list without any additional
  //   encoding.
  //
  // The binary format must match the deserialization code in paint.cc.

  final ByteData _data = new ByteData(_kDataByteCount);
  static const int _kIsAntiAliasIndex = 0;
  static const int _kColorIndex = 1;
555
  static const int _kBlendModeIndex = 2;
556 557 558
  static const int _kStyleIndex = 3;
  static const int _kStrokeWidthIndex = 4;
  static const int _kStrokeCapIndex = 5;
559 560 561 562 563 564
  static const int _kStrokeJoinIndex = 6;
  static const int _kStrokeMiterLimitIndex = 7;
  static const int _kFilterQualityIndex = 8;
  static const int _kColorFilterIndex = 9;
  static const int _kColorFilterColorIndex = 10;
  static const int _kColorFilterBlendModeIndex = 11;
565 566 567

  static const int _kIsAntiAliasOffset = _kIsAntiAliasIndex << 2;
  static const int _kColorOffset = _kColorIndex << 2;
568
  static const int _kBlendModeOffset = _kBlendModeIndex << 2;
569 570 571
  static const int _kStyleOffset = _kStyleIndex << 2;
  static const int _kStrokeWidthOffset = _kStrokeWidthIndex << 2;
  static const int _kStrokeCapOffset = _kStrokeCapIndex << 2;
572 573
  static const int _kStrokeJoinOffset = _kStrokeJoinIndex << 2;
  static const int _kStrokeMiterLimitOffset = _kStrokeMiterLimitIndex << 2;
574 575 576
  static const int _kFilterQualityOffset = _kFilterQualityIndex << 2;
  static const int _kColorFilterOffset = _kColorFilterIndex << 2;
  static const int _kColorFilterColorOffset = _kColorFilterColorIndex << 2;
577
  static const int _kColorFilterBlendModeOffset = _kColorFilterBlendModeIndex << 2;
578
  // If you add more fields, remember to update _kDataByteCount.
579
  static const int _kDataByteCount = 48;
580 581 582 583 584 585

  // Binary format must match the deserialization code in paint.cc.
  List<dynamic> _objects;
  static const int _kMaskFilterIndex = 0;
  static const int _kShaderIndex = 1;
  static const int _kObjectCount = 2;  // Must be one larger than the largest index
586 587 588 589

  /// Whether to apply anti-aliasing to lines and images drawn on the
  /// canvas.
  ///
590 591 592 593 594 595 596 597 598 599 600
  /// Defaults to true.
  bool get isAntiAlias {
    return _data.getInt32(_kIsAntiAliasOffset, _kFakeHostEndian) == 0;
  }
  set isAntiAlias(bool value) {
    // We encode true as zero and false as one because the default value, which
    // we always encode as zero, is true.
    final int encoded = value ? 0 : 1;
    _data.setInt32(_kIsAntiAliasOffset, encoded, _kFakeHostEndian);
  }

601
  // Must be kept in sync with the default in paint.cc.
602
  static const int _kColorDefault = 0xFF000000;
603 604 605

  /// The color to use when stroking or filling a shape.
  ///
606
  /// Defaults to opaque black.
607 608 609 610 611 612 613 614 615
  ///
  /// See also:
  ///
  ///  * [style], which controls whether to stroke or fill (or both).
  ///  * [colorFilter], which overrides [color].
  ///  * [shader], which overrides [color] with more elaborate effects.
  ///
  /// This color is not used when compositing. To colorize a layer, use
  /// [colorFilter].
616 617 618 619 620 621 622 623 624 625
  Color get color {
    final int encoded = _data.getInt32(_kColorOffset, _kFakeHostEndian);
    return new Color(encoded ^ _kColorDefault);
  }
  set color(Color value) {
    assert(value != null);
    final int encoded = value.value ^ _kColorDefault;
    _data.setInt32(_kColorOffset, encoded, _kFakeHostEndian);
  }

626
  // Must be kept in sync with the default in paint.cc.
627
  static final int _kBlendModeDefault = BlendMode.srcOver.index;
628

629
  /// A blend mode to apply when a shape is drawn or a layer is composited.
630 631 632 633 634 635 636 637 638
  ///
  /// The source colors are from the shape being drawn (e.g. from
  /// [Canvas.drawPath]) or layer being composited (the graphics that were drawn
  /// between the [Canvas.saveLayer] and [Canvas.restore] calls), after applying
  /// the [colorFilter], if any.
  ///
  /// The destination colors are from the background onto which the shape or
  /// layer is being composited.
  ///
639
  /// Defaults to [BlendMode.srcOver].
640 641 642 643 644 645
  ///
  /// See also:
  ///
  ///  * [Canvas.saveLayer], which uses its [Paint]'s [blendMode] to composite
  ///    the layer when [restore] is called.
  ///  * [BlendMode], which discusses the user of [saveLayer] with [blendMode].
646 647 648
  BlendMode get blendMode {
    final int encoded = _data.getInt32(_kBlendModeOffset, _kFakeHostEndian);
    return BlendMode.values[encoded ^ _kBlendModeDefault];
649
  }
650
  set blendMode(BlendMode value) {
651
    assert(value != null);
652 653
    final int encoded = value.index ^ _kBlendModeDefault;
    _data.setInt32(_kBlendModeOffset, encoded, _kFakeHostEndian);
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
  }

  /// Whether to paint inside shapes, the edges of shapes, or both.
  ///
  /// Defaults to [PaintingStyle.fill].
  PaintingStyle get style {
    return PaintingStyle.values[_data.getInt32(_kStyleOffset, _kFakeHostEndian)];
  }
  set style(PaintingStyle value) {
    assert(value != null);
    final int encoded = value.index;
    _data.setInt32(_kStyleOffset, encoded, _kFakeHostEndian);
  }

  /// How wide to make edges drawn when [style] is set to
669 670
  /// [PaintingStyle.stroke]. The width is given in logical pixels measured in
  /// the direction orthogonal to the direction of the path.
671 672 673 674 675 676 677 678 679 680 681 682
  ///
  /// Defaults to 0.0, which correspond to a hairline width.
  double get strokeWidth {
    return _data.getFloat32(_kStrokeWidthOffset, _kFakeHostEndian);
  }
  set strokeWidth(double value) {
    assert(value != null);
    final double encoded = value;
    _data.setFloat32(_kStrokeWidthOffset, encoded, _kFakeHostEndian);
  }

  /// The kind of finish to place on the end of lines drawn when
683
  /// [style] is set to [PaintingStyle.stroke].
684 685 686 687 688 689 690 691 692 693
  ///
  /// Defaults to [StrokeCap.butt], i.e. no caps.
  StrokeCap get strokeCap {
    return StrokeCap.values[_data.getInt32(_kStrokeCapOffset, _kFakeHostEndian)];
  }
  set strokeCap(StrokeCap value) {
    assert(value != null);
    final int encoded = value.index;
    _data.setInt32(_kStrokeCapOffset, encoded, _kFakeHostEndian);
  }
694

695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
  /// The kind of finish to place on the joins between segments.
  ///
  /// This applies to paths drawn when [style] is set to [PaintingStyle.stroke],
  /// It does not apply to points drawn as lines with [Canvas.drawPoints].
  ///
  /// Defaults to [StrokeJoin.miter], i.e. sharp corners. See also
  /// [strokeMiterLimit] to control when miters are replaced by bevels.
  StrokeJoin get strokeJoin {
    return StrokeJoin.values[_data.getInt32(_kStrokeJoinOffset, _kFakeHostEndian)];
  }
  set strokeJoin(StrokeJoin value) {
    assert(value != null);
    final int encoded = value.index;
    _data.setInt32(_kStrokeJoinOffset, encoded, _kFakeHostEndian);
  }

  // Must be kept in sync with the default in paint.cc.
  static final double _kStrokeMiterLimitDefault = 4.0;

  /// The limit for miters to be drawn on segments when the join is set to
  /// [StrokeJoin.miter] and the [style] is set to [PaintingStyle.stroke]. If
  /// this limit is exceeded, then a [StrokeJoin.bevel] join will be drawn
  /// instead. This may cause some 'popping' of the corners of a path if the
  /// angle between line segments is animated.
  ///
  /// This limit is expressed as a limit on the length of the miter.
  ///
  /// Defaults to 4.0.  Using zero as a limit will cause a [StrokeJoin.bevel]
  /// join to be used all the time.
  double get strokeMiterLimit {
    return _data.getFloat32(_kStrokeMiterLimitOffset, _kFakeHostEndian);
  }
  set strokeMiterLimit(double value) {
    assert(value != null);
    final double encoded = value - _kStrokeMiterLimitDefault;
    _data.setFloat32(_kStrokeMiterLimitOffset, encoded, _kFakeHostEndian);
  }

733 734 735 736
  /// A mask filter (for example, a blur) to apply to a shape after it has been
  /// drawn but before it has been composited into the image.
  ///
  /// See [MaskFilter] for details.
737 738 739 740 741 742 743 744 745
  MaskFilter get maskFilter {
    if (_objects == null)
      return null;
    return _objects[_kMaskFilterIndex];
  }
  set maskFilter(MaskFilter value) {
    _objects ??= new List<dynamic>(_kObjectCount);
    _objects[_kMaskFilterIndex] = value;
  }
746 747 748 749

  /// Controls the performance vs quality trade-off to use when applying
  /// filters, such as [maskFilter], or when drawing images, as with
  /// [Canvas.drawImageRect] or [Canvas.drawImageNine].
750 751
  ///
  /// Defaults to [FilterQuality.none].
752
  // TODO(ianh): verify that the image drawing methods actually respect this
753 754 755 756 757 758 759 760
  FilterQuality get filterQuality {
    return FilterQuality.values[_data.getInt32(_kFilterQualityOffset, _kFakeHostEndian)];
  }
  set filterQuality(FilterQuality value) {
    assert(value != null);
    final int encoded = value.index;
    _data.setInt32(_kFilterQualityOffset, encoded, _kFakeHostEndian);
  }
761 762 763 764 765 766 767 768 769 770 771

  /// The shader to use when stroking or filling a shape.
  ///
  /// When this is null, the [color] is used instead.
  ///
  /// See also:
  ///
  ///  * [Gradient], a shader that paints a color gradient.
  ///  * [ImageShader], a shader that tiles an [Image].
  ///  * [colorFilter], which overrides [shader].
  ///  * [color], which is used if [shader] and [colorFilter] are null.
772 773 774 775 776 777 778 779 780
  Shader get shader {
    if (_objects == null)
      return null;
    return _objects[_kShaderIndex];
  }
  set shader(Shader value) {
    _objects ??= new List<dynamic>(_kObjectCount);
    _objects[_kShaderIndex] = value;
  }
781 782 783 784 785 786 787

  /// A color filter to apply when a shape is drawn or when a layer is
  /// composited.
  ///
  /// See [ColorFilter] for details.
  ///
  /// When a shape is being drawn, [colorFilter] overrides [color] and [shader].
788 789 790 791 792 793
  ColorFilter get colorFilter {
    final bool isNull = _data.getInt32(_kColorFilterOffset, _kFakeHostEndian) == 0;
    if (isNull)
      return null;
    return new ColorFilter.mode(
      new Color(_data.getInt32(_kColorFilterColorOffset, _kFakeHostEndian)),
794
      BlendMode.values[_data.getInt32(_kColorFilterBlendModeOffset, _kFakeHostEndian)]
795 796 797 798 799 800
    );
  }
  set colorFilter(ColorFilter value) {
    if (value == null) {
      _data.setInt32(_kColorFilterOffset, 0, _kFakeHostEndian);
      _data.setInt32(_kColorFilterColorOffset, 0, _kFakeHostEndian);
801
      _data.setInt32(_kColorFilterBlendModeOffset, 0, _kFakeHostEndian);
802 803
    } else {
      assert(value._color != null);
804
      assert(value._blendMode != null);
805 806
      _data.setInt32(_kColorFilterOffset, 1, _kFakeHostEndian);
      _data.setInt32(_kColorFilterColorOffset, value._color.value, _kFakeHostEndian);
807
      _data.setInt32(_kColorFilterBlendModeOffset, value._blendMode.index, _kFakeHostEndian);
808 809 810 811 812 813 814 815
    }
  }

  @override
  String toString() {
    StringBuffer result = new StringBuffer();
    String semicolon = '';
    result.write('Paint(');
816
    if (style == PaintingStyle.stroke) {
817
      result.write('$style');
818
      if (strokeWidth != 0.0)
819
        result.write(' ${strokeWidth.toStringAsFixed(1)}');
820 821
      else
        result.write(' hairline');
822
      if (strokeCap != StrokeCap.butt)
823
        result.write(' $strokeCap');
824 825 826 827 828 829
      if (strokeJoin == StrokeJoin.miter) {
        if (strokeMiterLimit != _kStrokeMiterLimitDefault)
          result.write(' $strokeJoin up to ${strokeMiterLimit.toStringAsFixed(1)}');
      } else {
        result.write(' $strokeJoin');
      }
830 831 832 833 834 835
      semicolon = '; ';
    }
    if (isAntiAlias != true) {
      result.write('${semicolon}antialias off');
      semicolon = '; ';
    }
836
    if (color != const Color(_kColorDefault)) {
837 838 839 840 841 842
      if (color != null)
        result.write('$semicolon$color');
      else
        result.write('${semicolon}no color');
      semicolon = '; ';
    }
843
    if (blendMode.index != _kBlendModeDefault) {
844
      result.write('$semicolon$blendMode');
845 846 847 848 849 850 851 852 853 854
      semicolon = '; ';
    }
    if (colorFilter != null) {
      result.write('${semicolon}colorFilter: $colorFilter');
      semicolon = '; ';
    }
    if (maskFilter != null) {
      result.write('${semicolon}maskFilter: $maskFilter');
      semicolon = '; ';
    }
855
    if (filterQuality != FilterQuality.none) {
856 857 858 859 860 861 862 863 864 865
      result.write('${semicolon}filterQuality: $filterQuality');
      semicolon = '; ';
    }
    if (shader != null)
      result.write('${semicolon}shader: $shader');
    result.write(')');
    return result.toString();
  }
}

I
Ian Hickson 已提交
866 867
/// Opaque handle to raw decoded image data (pixels).
///
868
/// To obtain an [Image] object, use [instantiateImageCodec].
I
Ian Hickson 已提交
869
///
870
/// To draw an [Image], use one of the methods on the [Canvas] class, such as
I
Ian Hickson 已提交
871
/// [Canvas.drawImage].
872
abstract class Image extends NativeFieldWrapperClass2 {
I
Ian Hickson 已提交
873
  /// The number of image pixels along the image's horizontal axis.
874
  int get width native "Image_width";
I
Ian Hickson 已提交
875 876

  /// The number of image pixels along the image's vertical axis.
877 878
  int get height native "Image_height";

I
Ian Hickson 已提交
879 880
  /// Release the resources used by this object. The object is no longer usable
  /// after this method is called.
881
  void dispose() native "Image_dispose";
A
Adam Barth 已提交
882

883
  @override
A
Adam Barth 已提交
884
  String toString() => '[$width\u00D7$height]';
885 886
}

887
/// Callback signature for [decodeImageFromList].
I
Ian Hickson 已提交
888
typedef void ImageDecoderCallback(Image result);
889

890 891 892 893 894
/// Information for a single animation frame.
///
/// Obtain a FrameInfo with [Codec.getNextFrame].
abstract class FrameInfo extends NativeFieldWrapperClass2 {
  // The duration this frame should be shown.
895 896 897
  Duration get duration => new Duration(milliseconds: _durationMillis);

  int get _durationMillis native "FrameInfo_durationMillis";
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913

  // The Image object for this frame.
  Image get image native "FrameInfo_image";
}

/// A handle to an image codec.
abstract class Codec extends NativeFieldWrapperClass2 {
  /// Number of frames in this image.
  int get frameCount native "Codec_frameCount";

  /// Number of times to repeat the animation.
  ///
  /// * 0 when the animation should be played once.
  /// * -1 for infinity repetitions.
  int get repetitionCount native "Codec_repetitionCount";

914
  /// Fetches the next animation frame.
915 916
  ///
  /// Wraps back to the first frame after returning the last frame.
917
  ///
918 919 920 921 922
  /// The returned future can complete with an error if the decoding has failed.
  Future<FrameInfo> getNextFrame() {
    return _futurize(_getNextFrame);
  }

923
  /// Returns an error message on failure, null on success.
924
  String _getNextFrame(_Callback<FrameInfo> callback) native "Codec_getNextFrame";
925 926 927 928 929 930

  /// Release the resources used by this object. The object is no longer usable
  /// after this method is called.
  void dispose() native "Codec_dispose";
}

931
/// Instantiates an image codec [Codec] object.
932
///
933 934 935
/// [list] is the binary image data (e.g a PNG or GIF binary data).
/// The data can be for either static or animated images.
///
936 937
/// The following image formats are supported: {@macro flutter.dart:ui.imageFormats}
///
938 939 940 941 942 943 944
/// The returned future can complete with an error if the image decoding has
/// failed.
Future<Codec> instantiateImageCodec(Uint8List list) {
  return _futurize(
    (_Callback<Codec> callback) => _instantiateImageCodec(list, callback)
  );
}
945

946
/// Instantiates a [Codec] object for an image binary data.
947 948
///
/// Returns an error message if the instantiation has failed, null otherwise.
949
String _instantiateImageCodec(Uint8List list, _Callback<Codec> callback)
950 951
  native "instantiateImageCodec";

952 953 954 955 956 957 958 959 960 961 962 963 964
/// Loads a single image frame from a byte array into an [Image] object.
///
/// This is a convenience wrapper around [instantiateImageCodec].
/// Prefer using [instantiateImageCodec] which also supports multi frame images.
void decodeImageFromList(Uint8List list, ImageDecoderCallback callback) {
  _decodeImageFromListAsync(list, callback);
}

Future<Null> _decodeImageFromListAsync(Uint8List list, ImageDecoderCallback callback) async {
  final Codec codec = await instantiateImageCodec(list);
  final FrameInfo frameInfo = await codec.getNextFrame();
  callback(frameInfo.image);
}
965

966 967 968 969
/// Determines the winding rule that decides how the interior of a [Path] is
/// calculated.
///
/// This enum is used by the [Path.fillType] property.
A
Adam Barth 已提交
970 971
enum PathFillType {
  /// The interior is defined by a non-zero sum of signed edge crossings.
972 973 974 975 976 977 978 979
  ///
  /// For a given point, the point is considered to be on the inside of the path
  /// if a line drawn from the point to infinity crosses lines going clockwise
  /// around the point a different number of times than it crosses lines going
  /// counter-clockwise around that point.
  ///
  /// See: <https://en.wikipedia.org/wiki/Nonzero-rule>
  nonZero,
A
Adam Barth 已提交
980 981

  /// The interior is defined by an odd number of edge crossings.
982 983 984 985 986
  ///
  /// For a given point, the point is considered to be on the inside of the path
  /// if a line drawn from the point to infinity crosses an odd number of lines.
  ///
  /// See: <https://en.wikipedia.org/wiki/Even-odd_rule>
A
Adam Barth 已提交
987 988 989
  evenOdd,
}

A
Adam Barth 已提交
990 991
/// A complex, one-dimensional subset of a plane.
///
H
Hixie 已提交
992
/// A path consists of a number of subpaths, and a _current point_.
H
Hixie 已提交
993
///
H
Hixie 已提交
994 995 996 997 998
/// Subpaths consist of segments of various types, such as lines,
/// arcs, or beziers. Subpaths can be open or closed, and can
/// self-intersect.
///
/// Closed subpaths enclose a (possibly discontiguous) region of the
999
/// plane based on the current [fillType].
H
Hixie 已提交
1000 1001 1002 1003 1004 1005
///
/// The _current point_ is initially at the origin. After each
/// operation adding a segment to a subpath, the current point is
/// updated to the end of that segment.
///
/// Paths can be drawn on canvases using [Canvas.drawPath], and can
H
Hixie 已提交
1006
/// used to create clip regions using [Canvas.clipPath].
A
Adam Barth 已提交
1007
class Path extends NativeFieldWrapperClass2 {
H
Hixie 已提交
1008
  /// Create a new empty [Path] object.
A
Adam Barth 已提交
1009
  Path() { _constructor(); }
H
Hixie 已提交
1010
  void _constructor() native "Path_constructor";
A
Adam Barth 已提交
1011

A
Adam Barth 已提交
1012
  /// Determines how the interior of this path is calculated.
1013 1014
  ///
  /// Defaults to the non-zero winding rule, [PathFillType.nonZero].
A
Adam Barth 已提交
1015
  PathFillType get fillType => PathFillType.values[_getFillType()];
1016
  set fillType(PathFillType value) => _setFillType(value.index);
A
Adam Barth 已提交
1017 1018 1019 1020

  int _getFillType() native "Path_getFillType";
  void _setFillType(int fillType) native "Path_setFillType";

H
Hixie 已提交
1021
  /// Starts a new subpath at the given coordinate.
A
Adam Barth 已提交
1022
  void moveTo(double x, double y) native "Path_moveTo";
H
Hixie 已提交
1023 1024

  /// Starts a new subpath at the given offset from the current point.
A
Adam Barth 已提交
1025
  void relativeMoveTo(double dx, double dy) native "Path_relativeMoveTo";
H
Hixie 已提交
1026 1027 1028

  /// Adds a straight line segment from the current point to the given
  /// point.
A
Adam Barth 已提交
1029
  void lineTo(double x, double y) native "Path_lineTo";
H
Hixie 已提交
1030 1031 1032

  /// Adds a straight line segment from the current point to the point
  /// at the given offset from the current point.
A
Adam Barth 已提交
1033
  void relativeLineTo(double dx, double dy) native "Path_relativeLineTo";
H
Hixie 已提交
1034 1035 1036 1037

  /// Adds a quadratic bezier segment that curves from the current
  /// point to the given point (x2,y2), using the control point
  /// (x1,y1).
A
Adam Barth 已提交
1038
  void quadraticBezierTo(double x1, double y1, double x2, double y2) native "Path_quadraticBezierTo";
H
Hixie 已提交
1039 1040 1041 1042 1043

  /// Adds a quadratic bezier segment that curves from the current
  /// point to the point at the offset (x2,y2) from the current point,
  /// using the control point at the offset (x1,y1) from the current
  /// point.
A
Adam Barth 已提交
1044
  void relativeQuadraticBezierTo(double x1, double y1, double x2, double y2) native "Path_relativeQuadraticBezierTo";
H
Hixie 已提交
1045 1046 1047 1048

  /// Adds a cubic bezier segment that curves from the current point
  /// to the given point (x3,y3), using the control points (x1,y1) and
  /// (x2,y2).
A
Adam Barth 已提交
1049
  void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) native "Path_cubicTo";
H
Hixie 已提交
1050 1051 1052 1053 1054

  /// Adds a cubcic bezier segment that curves from the current point
  /// to the point at the offset (x3,y3) from the current point, using
  /// the control points at the offsets (x1,y1) and (x2,y2) from the
  /// current point.
A
Adam Barth 已提交
1055
  void relativeCubicTo(double x1, double y1, double x2, double y2, double x3, double y3) native "Path_relativeCubicTo";
H
Hixie 已提交
1056 1057 1058 1059 1060 1061

  /// Adds a bezier segment that curves from the current point to the
  /// given point (x2,y2), using the control points (x1,y1) and the
  /// weight w. If the weight is greater than 1, then the curve is a
  /// hyperbola; if the weight equals 1, it's a parabola; and if it is
  /// less than 1, it is an ellipse.
A
Adam Barth 已提交
1062
  void conicTo(double x1, double y1, double x2, double y2, double w) native "Path_conicTo";
H
Hixie 已提交
1063 1064 1065 1066 1067 1068 1069

  /// Adds a bezier segment that curves from the current point to the
  /// point at the offset (x2,y2) from the current point, using the
  /// control point at the offset (x1,y1) from the current point and
  /// the weight w. If the weight is greater than 1, then the curve is
  /// a hyperbola; if the weight equals 1, it's a parabola; and if it
  /// is less than 1, it is an ellipse.
A
Adam Barth 已提交
1070
  void relativeConicTo(double x1, double y1, double x2, double y2, double w) native "Path_relativeConicTo";
H
Hixie 已提交
1071

1072
  /// If the `forceMoveTo` argument is false, adds a straight line
H
Hixie 已提交
1073 1074
  /// segment and an arc segment.
  ///
1075
  /// If the `forceMoveTo` argument is true, starts a new subpath
H
Hixie 已提交
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
  /// consisting of an arc segment.
  ///
  /// In either case, the arc segment consists of the arc that follows
  /// the edge of the oval bounded by the given rectangle, from
  /// startAngle radians around the oval up to startAngle + sweepAngle
  /// radians around the oval, with zero radians being the point on
  /// the right hand side of the oval that crosses the horizontal line
  /// that intersects the center of the rectangle and with positive
  /// angles going clockwise around the oval.
  ///
1086
  /// The line segment added if `forceMoveTo` is false starts at the
H
Hixie 已提交
1087
  /// current point and ends at the start of the arc.
1088
  void arcTo(Rect rect, double startAngle, double sweepAngle, bool forceMoveTo) {
1089
    assert(_rectIsValid(rect));
1090 1091 1092 1093
    _arcTo(rect.left, rect.top, rect.right, rect.bottom, startAngle, sweepAngle, forceMoveTo);
  }
  void _arcTo(double left, double top, double right, double bottom,
              double startAngle, double sweepAngle, bool forceMoveTo) native "Path_arcTo";
H
Hixie 已提交
1094

1095 1096
  /// Appends up to four conic curves weighted to describe an oval of `radius`
  /// and rotated by `rotation`.
1097 1098
  ///
  /// The first curve begins from the last point in the path and the last ends
1099 1100
  /// at `arcEnd`. The curves follow a path in a direction determined by
  /// `clockwise` and `largeArc` in such a way that the sweep angle
1101 1102 1103
  /// is always less than 360 degrees.
  ///
  /// A simple line is appended if either either radii are zero or the last
1104
  /// point in the path is `arcEnd`. The radii are scaled to fit the last path
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
  /// point if both are greater than zero but too small to describe an arc.
  ///
  void arcToPoint(Offset arcEnd, {
    Radius radius: Radius.zero,
    double rotation: 0.0,
    bool largeArc: false,
    bool clockwise: true,
    }) {
    assert(_offsetIsValid(arcEnd));
    assert(_radiusIsValid(radius));
    _arcToPoint(arcEnd.dx, arcEnd.dy, radius.x, radius.y, rotation,
                largeArc, clockwise);
  }
  void _arcToPoint(double arcEndX, double arcEndY, double radiusX,
                   double radiusY, double rotation, bool largeArc,
                   bool clockwise) native "Path_arcToPoint";


1123 1124
  /// Appends up to four conic curves weighted to describe an oval of `radius`
  /// and rotated by `rotation`.
1125 1126 1127 1128
  ///
  /// The last path point is described by (px, py).
  ///
  /// The first curve begins from the last point in the path and the last ends
1129 1130
  /// at `arcEndDelta.dx + px` and `arcEndDelta.dy + py`. The curves follow a
  /// path in a direction determined by `clockwise` and `largeArc`
1131 1132 1133
  /// in such a way that the sweep angle is always less than 360 degrees.
  ///
  /// A simple line is appended if either either radii are zero, or, both
1134
  /// `arcEndDelta.dx` and `arcEndDelta.dy` are zero. The radii are scaled to
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
  /// fit the last path point if both are greater than zero but too small to
  /// describe an arc.
  void relativeArcToPoint(Offset arcEndDelta, {
    Radius radius: Radius.zero,
    double rotation: 0.0,
    bool largeArc: false,
    bool clockwise: true,
    }) {
    assert(_offsetIsValid(arcEndDelta));
    assert(_radiusIsValid(radius));
    _relativeArcToPoint(arcEndDelta.dx, arcEndDelta.dy, radius.x, radius.y,
                        rotation, largeArc, clockwise);
  }
  void _relativeArcToPoint(double arcEndX, double arcEndY, double radiusX,
                           double radiusY, double rotation,
                           bool largeArc, bool clockwise)
                           native "Path_relativeArcToPoint";

H
Hixie 已提交
1153 1154
  /// Adds a new subpath that consists of four lines that outline the
  /// given rectangle.
1155
  void addRect(Rect rect) {
1156
    assert(_rectIsValid(rect));
1157 1158 1159
    _addRect(rect.left, rect.top, rect.right, rect.bottom);
  }
  void _addRect(double left, double top, double right, double bottom) native "Path_addRect";
H
Hixie 已提交
1160 1161 1162

  /// Adds a new subpath that consists of a curve that forms the
  /// ellipse that fills the given rectangle.
1163
  void addOval(Rect oval) {
1164
    assert(_rectIsValid(oval));
1165 1166 1167
    _addOval(oval.left, oval.top, oval.right, oval.bottom);
  }
  void _addOval(double left, double top, double right, double bottom) native "Path_addOval";
H
Hixie 已提交
1168 1169 1170 1171 1172 1173 1174 1175 1176

  /// Adds a new subpath with one arc segment that consists of the arc
  /// that follows the edge of the oval bounded by the given
  /// rectangle, from startAngle radians around the oval up to
  /// startAngle + sweepAngle radians around the oval, with zero
  /// radians being the point on the right hand side of the oval that
  /// crosses the horizontal line that intersects the center of the
  /// rectangle and with positive angles going clockwise around the
  /// oval.
1177
  void addArc(Rect oval, double startAngle, double sweepAngle) {
1178
    assert(_rectIsValid(oval));
1179 1180 1181 1182
    _addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);
  }
  void _addArc(double left, double top, double right, double bottom,
               double startAngle, double sweepAngle) native "Path_addArc";
H
Hixie 已提交
1183

A
Adam Barth 已提交
1184
  /// Adds a new subpath with a sequence of line segments that connect the given
I
Ian Hickson 已提交
1185 1186 1187 1188 1189 1190 1191
  /// points.
  ///
  /// If `close` is true, a final line segment will be added that connects the
  /// last point to the first point.
  ///
  /// The `points` argument is interpreted as offsets from the origin.
  void addPolygon(List<Offset> points, bool close) {
1192
    assert(points != null);
A
Adam Barth 已提交
1193 1194 1195 1196
    _addPolygon(_encodePointList(points), close);
  }
  void _addPolygon(Float32List points, bool close) native "Path_addPolygon";

H
Hixie 已提交
1197 1198 1199
  /// Adds a new subpath that consists of the straight lines and
  /// curves needed to form the rounded rectangle described by the
  /// argument.
1200
  void addRRect(RRect rrect) {
1201
    assert(_rrectIsValid(rrect));
1202 1203
    _addRRect(rrect._value);
  }
1204
  void _addRRect(Float32List rrect) native "Path_addRRect";
H
Hixie 已提交
1205

A
Adam Barth 已提交
1206 1207
  /// Adds a new subpath that consists of the given path offset by the given
  /// offset.
1208 1209
  void addPath(Path path, Offset offset) {
    assert(path != null); // path is checked on the engine side
1210
    assert(_offsetIsValid(offset));
1211 1212
    _addPath(path, offset.dx, offset.dy);
  }
A
Adam Barth 已提交
1213 1214 1215 1216
  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.
1217 1218
  void extendWithPath(Path path, Offset offset) {
    assert(path != null); // path is checked on the engine side
1219
    assert(_offsetIsValid(offset));
1220 1221
    _extendWithPath(path, offset.dx, offset.dy);
  }
A
Adam Barth 已提交
1222 1223
  void _extendWithPath(Path path, double dx, double dy) native "Path_extendWithPath";

H
Hixie 已提交
1224 1225
  /// Closes the last subpath, as if a straight line had been drawn
  /// from the current point to the first point of the subpath.
A
Adam Barth 已提交
1226
  void close() native "Path_close";
H
Hixie 已提交
1227 1228 1229 1230

  /// Clears the [Path] object of all subpaths, returning it to the
  /// same state it had when it was created. The _current point_ is
  /// reset to the origin.
A
Adam Barth 已提交
1231
  void reset() native "Path_reset";
H
Hixie 已提交
1232

I
Ian Hickson 已提交
1233 1234 1235 1236 1237
  /// Tests to see if the given point is within the path. (That is, whether the
  /// point would be in the visible portion of the path if the path was used
  /// with [Canvas.clipPath].)
  ///
  /// The `point` argument is interpreted as an offset from the origin.
1238 1239
  ///
  /// Returns true if the point is in the path, and false otherwise.
1240
  bool contains(Offset point) {
1241
    assert(_offsetIsValid(point));
1242 1243
    return _contains(point.dx, point.dy);
  }
1244
  bool _contains(double x, double y) native "Path_contains";
1245

H
Hixie 已提交
1246 1247
  /// Returns a copy of the path with all the segments of every
  /// subpath translated by the given offset.
1248
  Path shift(Offset offset) {
1249
    assert(_offsetIsValid(offset));
1250 1251
    return _shift(offset.dx, offset.dy);
  }
1252
  Path _shift(double dx, double dy) native "Path_shift";
A
Adam Barth 已提交
1253 1254 1255 1256

  /// Returns a copy of the path with all the segments of every
  /// subpath transformed by the given matrix.
  Path transform(Float64List matrix4) {
1257
    assert(matrix4 != null);
A
Adam Barth 已提交
1258
    if (matrix4.length != 16)
1259
      throw new ArgumentError('"matrix4" must have 16 entries.');
A
Adam Barth 已提交
1260 1261 1262
    return _transform(matrix4);
  }
  Path _transform(Float64List matrix4) native "Path_transform";
A
Adam Barth 已提交
1263 1264
}

H
Hixie 已提交
1265
/// Styles to use for blurs in [MaskFilter] objects.
1266
// These enum values must be kept in sync with SkBlurStyle.
1267
enum BlurStyle {
H
Hixie 已提交
1268 1269
  // These mirror SkBlurStyle and must be kept in sync.

1270
  /// Fuzzy inside and outside. This is useful for painting shadows that are
1271
  /// offset from the shape that ostensibly is casting the shadow.
A
Adam Barth 已提交
1272 1273
  normal,

1274 1275 1276
  /// Solid inside, fuzzy outside. This corresponds to drawing the shape, and
  /// additionally drawing the blur. This can make objects appear brighter,
  /// maybe even as if they were fluorescent.
A
Adam Barth 已提交
1277 1278
  solid,

1279 1280 1281
  /// Nothing inside, fuzzy outside. This is useful for painting shadows for
  /// partially transparent shapes, when they are painted separately but without
  /// an offset, so that the shadow doesn't paint below the shape.
A
Adam Barth 已提交
1282 1283
  outer,

1284 1285
  /// Fuzzy inside, nothing outside. This can make shapes appear to be lit from
  /// within.
A
Adam Barth 已提交
1286
  inner,
1287 1288
}

1289 1290 1291 1292 1293
/// A mask filter to apply to shapes as they are painted. A mask filter is a
/// function that takes a bitmap of color pixels, and returns another bitmap of
/// color pixels.
///
/// Instances of this class are used with [Paint.maskFilter] on [Paint] objects.
1294
class MaskFilter extends NativeFieldWrapperClass2 {
1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305
  /// Creates a mask filter that takes the shape being drawn and blurs it.
  ///
  /// This is commonly used to approximate shadows.
  ///
  /// The `style` argument controls the kind of effect to draw; see [BlurStyle].
  ///
  /// The `sigma` argument controls the size of the effect. It is the standard
  /// deviation of the Gaussian blur to apply. The value must be greater than
  /// zero. The sigma corresponds to very roughly half the radius of the effect
  /// in pixels.
  ///
1306 1307
  /// A blur is an expensive operation and should therefore be used sparingly.
  MaskFilter.blur(BlurStyle style, double sigma) {
1308
    assert(style != null);
1309 1310 1311
    _constructor(style.index, sigma);
  }
  void _constructor(int style, double sigma) native "MaskFilter_constructor";
1312 1313
}

1314 1315 1316 1317 1318
/// A description of a color filter to apply when drawing a shape or compositing
/// a layer with a particular [Paint]. A color filter is a function that takes
/// two colors, and outputs one color. When applied during compositing, it is
/// independently applied to each pixel of the layer being drawn before the
/// entire layer is merged with the destination.
H
Hixie 已提交
1319
///
1320 1321
/// Instances of this class are used with [Paint.colorFilter] on [Paint]
/// objects.
1322
class ColorFilter {
1323
  /// Creates a color filter that applies the blend mode given as the second
1324 1325 1326 1327
  /// argument. The source color is the one given as the first argument, and the
  /// destination color is the one from the layer being composited.
  ///
  /// The output of this filter is then composited into the background according
1328
  /// to the [Paint.blendMode], using the output of this filter as the source
1329
  /// and the background as the destination.
I
Ian Hickson 已提交
1330
  const ColorFilter.mode(Color color, BlendMode blendMode)
1331
    : _color = color, _blendMode = blendMode;
1332 1333

  final Color _color;
1334
  final BlendMode _blendMode;
1335 1336 1337 1338 1339 1340 1341

  @override
  bool operator ==(dynamic other) {
    if (other is! ColorFilter)
      return false;
    final ColorFilter typedOther = other;
    return _color == typedOther._color &&
1342
           _blendMode == typedOther._blendMode;
1343 1344 1345
  }

  @override
1346
  int get hashCode => hashValues(_color, _blendMode);
1347 1348

  @override
1349
  String toString() => "ColorFilter($_color, $_blendMode)";
1350
}
A
Adam Barth 已提交
1351

1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371
/// A filter operation to apply to a raster image.
///
/// See [SceneBuilder.pushBackdropFilter].
class ImageFilter extends NativeFieldWrapperClass2 {
  void _constructor() native "ImageFilter_constructor";

  /// A source filter containing an image.
  // ImageFilter.image({ Image image }) {
  //   _constructor();
  //   _initImage(image);
  // }
  // void _initImage(Image image) native "ImageFilter_initImage";

  /// A source filter containing a picture.
  // ImageFilter.picture({ Picture picture }) {
  //   _constructor();
  //   _initPicture(picture);
  // }
  // void _initPicture(Picture picture) native "ImageFilter_initPicture";

1372
  /// Creates an image filter that applies a Gaussian blur.
1373 1374 1375 1376 1377 1378 1379
  ImageFilter.blur({ double sigmaX: 0.0, double sigmaY: 0.0 }) {
    _constructor();
    _initBlur(sigmaX, sigmaY);
  }
  void _initBlur(double sigmaX, double sigmaY) native "ImageFilter_initBlur";
}

H
Hixie 已提交
1380
/// Base class for objects such as [Gradient] and [ImageShader] which
1381
/// correspond to shaders as used by [Paint.shader].
H
Hixie 已提交
1382
abstract class Shader extends NativeFieldWrapperClass2 { }
A
Adam Barth 已提交
1383 1384

/// Defines what happens at the edge of the gradient.
1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402
///
/// A gradient is defined along a finite inner area. In the case of a linear
/// gradient, it's between the parallel lines that are orthogonal to the line
/// drawn between two points. In the case of radial gradients, it's the disc
/// that covers the circle centered on a particular point up to a given radius.
///
/// This enum is used to define how the gradient should paint the regions
/// outside that defined inner area.
///
/// See also:
///
///  * [painting.Gradient], the superclass for [LinearGradient] and
///    [RadialGradient], as used by [BoxDecoration] et al, which works in
///    relative coordinates and can create a [Shader] representing the gradient
///    for a particular [Rect] on demand.
///  * [dart:ui.Gradient], the low-level class used when dealing with the
///    [Paint.shader] property directly, with its [new Gradient.linear] and [new
///    Gradient.radial] constructors.
1403
// These enum values must be kept in sync with SkShader::TileMode.
A
Adam Barth 已提交
1404 1405
enum TileMode {
  /// Edge is clamped to the final color.
1406 1407 1408 1409 1410 1411
  ///
  /// The gradient will paint the all the regions outside the inner area with
  /// the color of the point closest to that region.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_clamp_linear.png)
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_clamp_radial.png)
A
Adam Barth 已提交
1412
  clamp,
1413

1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
  /// Edge is repeated from first color to last.
  ///
  /// This is as if the stop points from 0.0 to 1.0 were then repeated from 1.0
  /// to 2.0, 2.0 to 3.0, and so forth (and for linear gradients, similarly from
  /// -1.0 to 0.0, -2.0 to -1.0, etc).
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_repeated_linear.png)
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_repeated_radial.png)
  repeated,

A
Adam Barth 已提交
1424
  /// Edge is mirrored from last color to first.
1425 1426 1427 1428 1429 1430 1431 1432
  ///
  /// This is as if the stop points from 0.0 to 1.0 were then repeated backwards
  /// from 2.0 to 1.0, then forwards from 2.0 to 3.0, then backwards again from
  /// 4.0 to 3.0, and so forth (and for linear gradients, similarly from in the
  /// negative direction).
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_mirror_linear.png)
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_mirror_radial.png)
1433
  mirror,
A
Adam Barth 已提交
1434 1435
}

1436 1437 1438 1439 1440 1441 1442 1443
Int32List _encodeColorList(List<Color> colors) {
  final int colorCount = colors.length;
  final Int32List result = new Int32List(colorCount);
  for (int i = 0; i < colorCount; ++i)
    result[i] = colors[i].value;
  return result;
}

I
Ian Hickson 已提交
1444
Float32List _encodePointList(List<Offset> points) {
1445
  assert(points != null);
1446 1447 1448 1449 1450
  final int pointCount = points.length;
  final Float32List result = new Float32List(pointCount * 2);
  for (int i = 0; i < pointCount; ++i) {
    final int xIndex = i * 2;
    final int yIndex = xIndex + 1;
I
Ian Hickson 已提交
1451
    final Offset point = points[i];
1452
    assert(_offsetIsValid(point));
I
Ian Hickson 已提交
1453 1454
    result[xIndex] = point.dx;
    result[yIndex] = point.dy;
1455 1456 1457 1458
  }
  return result;
}

I
Ian Hickson 已提交
1459
Float32List _encodeTwoPoints(Offset pointA, Offset pointB) {
1460 1461
  assert(_offsetIsValid(pointA));
  assert(_offsetIsValid(pointB));
I
Ian Hickson 已提交
1462 1463 1464 1465 1466 1467 1468 1469
  final Float32List result = new Float32List(4);
  result[0] = pointA.dx;
  result[1] = pointA.dy;
  result[2] = pointB.dx;
  result[3] = pointB.dy;
  return result;
}

1470 1471 1472
/// A shader (as used by [Paint.shader]) that renders a color gradient.
///
/// There are two useful types of gradients, created by [new Gradient.linear]
I
Ian Hickson 已提交
1473
/// and [new Gradient.radial].
A
Adam Barth 已提交
1474
class Gradient extends Shader {
H
Hixie 已提交
1475 1476
  /// Creates a Gradient object that is not initialized.
  ///
I
Ian Hickson 已提交
1477
  /// Use the [new Gradient.linear] or [new Gradient.radial] constructors to
H
Hixie 已提交
1478 1479
  /// obtain a usable [Gradient] object.
  Gradient();
A
Adam Barth 已提交
1480 1481
  void _constructor() native "Gradient_constructor";

I
Ian Hickson 已提交
1482 1483 1484 1485 1486 1487 1488 1489
  /// Creates a linear gradient from `from` to `to`.
  ///
  /// If `colorStops` is provided, `colorStops[i]` is a number from 0.0 to 1.0
  /// that specifies where `color[i]` begins in the gradient. If `colorStops` is
  /// not provided, then only two stops, at 0.0 and 1.0, are implied (and
  /// `color` must therefore only have two entries).
  ///
  /// The behavior before `from` and after `to` is described by the `tileMode`
1490 1491 1492 1493 1494
  /// argument. For details, see the [TileMode] enum.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_clamp_linear.png)
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_mirror_linear.png)
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_repeated_linear.png)
I
Ian Hickson 已提交
1495 1496 1497 1498 1499 1500 1501 1502 1503
  ///
  /// If `from`, `to`, `colors`, or `tileMode` are null, or if `colors` or
  /// `colorStops` contain null values, this constructor will throw a
  /// [NoSuchMethodError].
  Gradient.linear(
    Offset from,
    Offset to,
    List<Color> colors, [
    List<double> colorStops = null,
1504
    TileMode tileMode = TileMode.clamp,
I
Ian Hickson 已提交
1505
  ]) {
1506 1507
    assert(_offsetIsValid(from));
    assert(_offsetIsValid(to));
1508 1509
    assert(colors != null);
    assert(tileMode != null);
A
Adam Barth 已提交
1510
    _validateColorStops(colors, colorStops);
I
Ian Hickson 已提交
1511
    final Float32List endPointsBuffer = _encodeTwoPoints(from, to);
1512 1513 1514 1515
    final Int32List colorsBuffer = _encodeColorList(colors);
    final Float32List colorStopsBuffer = colorStops == null ? null : new Float32List.fromList(colorStops);
    _constructor();
    _initLinear(endPointsBuffer, colorsBuffer, colorStopsBuffer, tileMode.index);
A
Adam Barth 已提交
1516
  }
1517
  void _initLinear(Float32List endPoints, Int32List colors, Float32List colorStops, int tileMode) native "Gradient_initLinear";
A
Adam Barth 已提交
1518

1519
  /// Creates a radial gradient centered at `center` that ends at `radius`
I
Ian Hickson 已提交
1520 1521 1522 1523 1524 1525 1526 1527
  /// distance from the center.
  ///
  /// If `colorStops` is provided, `colorStops[i]` is a number from 0.0 to 1.0
  /// that specifies where `color[i]` begins in the gradient. If `colorStops` is
  /// not provided, then only two stops, at 0.0 and 1.0, are implied (and
  /// `color` must therefore only have two entries).
  ///
  /// The behavior before and after the radius is described by the `tileMode`
1528 1529 1530 1531 1532
  /// argument. For details, see the [TileMode] enum.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_clamp_radial.png)
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_mirror_radial.png)
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_repeated_radial.png)
I
Ian Hickson 已提交
1533 1534 1535 1536 1537
  ///
  /// If `center`, `radius`, `colors`, or `tileMode` are null, or if `colors` or
  /// `colorStops` contain null values, this constructor will throw a
  /// [NoSuchMethodError].
  Gradient.radial(Offset center,
A
Adam Barth 已提交
1538
                  double radius,
1539 1540 1541 1542
                  List<Color> colors, [
                  List<double> colorStops = null,
                  TileMode tileMode = TileMode.clamp,
  ]) {
1543
    assert(_offsetIsValid(center));
1544 1545
    assert(colors != null);
    assert(tileMode != null);
A
Adam Barth 已提交
1546
    _validateColorStops(colors, colorStops);
1547 1548 1549
    final Int32List colorsBuffer = _encodeColorList(colors);
    final Float32List colorStopsBuffer = colorStops == null ? null : new Float32List.fromList(colorStops);
    _constructor();
I
Ian Hickson 已提交
1550
    _initRadial(center.dx, center.dy, radius, colorsBuffer, colorStopsBuffer, tileMode.index);
A
Adam Barth 已提交
1551
  }
1552
  void _initRadial(double centerX, double centerY, double radius, Int32List colors, Float32List colorStops, int tileMode) native "Gradient_initRadial";
H
Hixie 已提交
1553 1554

  static void _validateColorStops(List<Color> colors, List<double> colorStops) {
I
Ian Hickson 已提交
1555 1556
    if (colorStops == null) {
      if (colors.length != 2)
1557
        throw new ArgumentError('"colors" must have length 2 if "colorStops" is omitted.');
I
Ian Hickson 已提交
1558 1559
    } else {
      if (colors.length != colorStops.length)
1560
        throw new ArgumentError('"colors" and "colorStops" arguments must have equal length.');
I
Ian Hickson 已提交
1561
    }
H
Hixie 已提交
1562
  }
A
Adam Barth 已提交
1563 1564
}

1565
/// A shader (as used by [Paint.shader]) that tiles an image.
A
Adam Barth 已提交
1566
class ImageShader extends Shader {
1567 1568 1569 1570 1571
  /// Creates an image-tiling shader. The first argument specifies the image to
  /// tile. The second and third arguments specify the [TileMode] for the x
  /// direction and y direction respectively. The fourth argument gives the
  /// matrix to apply to the effect. All the arguments are required and must not
  /// be null.
A
Adam Barth 已提交
1572
  ImageShader(Image image, TileMode tmx, TileMode tmy, Float64List matrix4) {
1573 1574 1575 1576
    assert(image != null); // image is checked on the engine side
    assert(tmx != null);
    assert(tmy != null);
    assert(matrix4 != null);
1577
    if (matrix4.length != 16)
1578
      throw new ArgumentError('"matrix4" must have 16 entries.');
H
Hixie 已提交
1579
    _constructor();
A
Adam Barth 已提交
1580 1581
    _initWithImage(image, tmx.index, tmy.index, matrix4);
  }
H
Hixie 已提交
1582 1583
  void _constructor() native "ImageShader_constructor";
  void _initWithImage(Image image, int tmx, int tmy, Float64List matrix4) native "ImageShader_initWithImage";
A
Adam Barth 已提交
1584 1585
}

1586
/// Defines how a list of points is interpreted when drawing a set of triangles.
A
Adam Barth 已提交
1587 1588
///
/// Used by [Canvas.drawVertices].
1589
// These enum values must be kept in sync with SkVertices::VertexMode.
1590
enum VertexMode {
A
Adam Barth 已提交
1591
  /// Draw each sequence of three points as the vertices of a triangle.
1592
  triangles,
A
Adam Barth 已提交
1593 1594

  /// Draw each sliding window of three points as the vertices of a triangle.
1595
  triangleStrip,
A
Adam Barth 已提交
1596 1597

  /// Draw the first point and each sliding window of two points as the vertices of a triangle.
1598 1599 1600
  triangleFan,
}

1601 1602 1603 1604
/// A set of vertex data used by [Canvas.drawVertices].
class Vertices extends NativeFieldWrapperClass2 {
  Vertices(
    VertexMode mode,
I
Ian Hickson 已提交
1605 1606 1607 1608 1609
    List<Offset> positions, {
    List<Offset> textureCoordinates,
    List<Color> colors,
    List<int> indices,
  }) {
1610 1611
    assert(mode != null);
    assert(positions != null);
1612
    if (textureCoordinates != null && textureCoordinates.length != positions.length)
1613
      throw new ArgumentError('"positions" and "textureCoordinates" lengths must match.');
1614
    if (colors != null && colors.length != positions.length)
1615
      throw new ArgumentError('"positions" and "colors" lengths must match.');
1616
    if (indices != null && indices.any((int i) => i < 0 || i >= positions.length))
1617
      throw new ArgumentError('"indices" values must be valid indices in the positions list.');
1618 1619

    Float32List encodedPositions = _encodePointList(positions);
1620
    Float32List encodedTextureCoordinates = (textureCoordinates != null) ?
1621
      _encodePointList(textureCoordinates) : null;
1622 1623
    Int32List encodedColors = colors != null ? _encodeColorList(colors) : null;
    Int32List encodedIndices = indices != null ? new Int32List.fromList(indices) : null;
1624 1625

    _constructor();
1626 1627 1628 1629 1630 1631 1632 1633 1634 1635
    _init(mode.index, encodedPositions, encodedTextureCoordinates, encodedColors, encodedIndices);
  }

  Vertices.raw(
    VertexMode mode,
    Float32List positions, {
    Float32List textureCoordinates,
    Int32List colors,
    Int32List indices,
  }) {
1636 1637
    assert(mode != null);
    assert(positions != null);
1638 1639 1640 1641 1642 1643 1644 1645 1646
    if (textureCoordinates != null && textureCoordinates.length != positions.length)
      throw new ArgumentError('"positions" and "textureCoordinates" lengths must match.');
    if (colors != null && colors.length * 2 != positions.length)
      throw new ArgumentError('"positions" and "colors" lengths must match.');
    if (indices != null && indices.any((int i) => i < 0 || i >= positions.length))
      throw new ArgumentError('"indices" values must be valid indices in the positions list.');

    _constructor();
    _init(mode.index, positions, textureCoordinates, colors, indices);
1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657
  }

  void _constructor() native "Vertices_constructor";

  void _init(int mode,
             Float32List positions,
             Float32List textureCoordinates,
             Int32List colors,
             Int32List indices) native "Vertices_init";
}

A
Adam Barth 已提交
1658 1659
/// Defines how a list of points is interpreted when drawing a set of points.
///
1660
// ignore: deprecated_member_use
A
Adam Barth 已提交
1661
/// Used by [Canvas.drawPoints].
1662
// These enum values must be kept in sync with SkCanvas::PointMode.
A
Adam Barth 已提交
1663
enum PointMode {
1664 1665
  /// Draw each point separately.
  ///
I
Ian Hickson 已提交
1666
  /// If the [Paint.strokeCap] is [StrokeCap.round], then each point is drawn
1667 1668 1669 1670 1671 1672
  /// as a circle with the diameter of the [Paint.strokeWidth], filled as
  /// described by the [Paint] (ignoring [Paint.style]).
  ///
  /// Otherwise, each point is drawn as an axis-aligned square with sides of
  /// length [Paint.strokeWidth], filled as described by the [Paint] (ignoring
  /// [Paint.style]).
A
Adam Barth 已提交
1673 1674
  points,

1675 1676 1677 1678 1679 1680
  /// Draw each sequence of two points as a line segment.
  ///
  /// If the number of points is odd, then the last point is ignored.
  ///
  /// The lines are stroked as described by the [Paint] (ignoring
  /// [Paint.style]).
A
Adam Barth 已提交
1681 1682
  lines,

1683 1684 1685 1686
  /// Draw the entire sequence of point as one line.
  ///
  /// The lines are stroked as described by the [Paint] (ignoring
  /// [Paint.style]).
A
Adam Barth 已提交
1687 1688 1689
  polygon,
}

1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701
/// Defines how a new clip region should be merged with the existing clip
/// region.
///
/// Used by [Canvas.clipRect].
enum ClipOp {
  /// Subtract the new region from the existing region.
  difference,

  /// Intersect the new region from the existing region.
  intersect,
}

A
Adam Barth 已提交
1702 1703
/// An interface for recording graphical operations.
///
H
Hixie 已提交
1704 1705 1706
/// [Canvas] objects are used in creating [Picture] objects, which can
/// themselves be used with a [SceneBuilder] to build a [Scene]. In
/// normal usage, however, this is all handled by the framework.
1707 1708 1709 1710
///
/// A canvas has a current transformation matrix which is applied to all
/// operations. Initially, the transformation matrix is the identity transform.
/// It can be modified using the [translate], [scale], [rotate], [skew],
1711
/// and [transform] methods.
1712 1713 1714 1715 1716 1717 1718
///
/// A canvas also has a current clip region which is applied to all operations.
/// Initially, the clip region is infinite. It can be modified using the
/// [clipRect], [clipRRect], and [clipPath] methods.
///
/// The current transform and clip can be saved and restored using the stack
/// managed by the [save], [saveLayer], and [restore] methods.
1719
class Canvas extends NativeFieldWrapperClass2 {
H
Hixie 已提交
1720 1721
  /// Creates a canvas for recording graphical operations into the
  /// given picture recorder.
A
Adam Barth 已提交
1722 1723 1724 1725
  ///
  /// Graphical operations that affect pixels entirely outside the given
  /// cullRect might be discarded by the implementation. However, the
  /// implementation might draw outside these bounds if, for example, a command
1726
  /// draws partially inside and outside the `cullRect`. To ensure that pixels
A
Adam Barth 已提交
1727
  /// outside a given region are discarded, consider using a [clipRect].
H
Hixie 已提交
1728 1729 1730
  ///
  /// To end the recording, call [PictureRecorder.endRecording] on the
  /// given recorder.
A
Adam Barth 已提交
1731
  Canvas(PictureRecorder recorder, Rect cullRect) {
1732
    assert(recorder != null);
1733
    if (recorder.isRecording)
1734
      throw new ArgumentError('"recorder" must not already be associated with another Canvas.');
1735
    assert(cullRect != null);
1736
    _constructor(recorder, cullRect.left, cullRect.top, cullRect.right, cullRect.bottom);
1737
  }
1738 1739 1740 1741 1742
  void _constructor(PictureRecorder recorder,
                    double left,
                    double top,
                    double right,
                    double bottom) native "Canvas_constructor";
1743

H
Hixie 已提交
1744 1745 1746
  /// Saves a copy of the current transform and clip on the save stack.
  ///
  /// Call [restore] to pop the save stack.
1747 1748 1749 1750 1751
  ///
  /// See also:
  ///
  ///  * [saveLayer], which does the same thing but additionally also groups the
  ///    commands done until the matching [restore].
1752
  void save() native "Canvas_save";
1753

1754 1755 1756
  /// Saves a copy of the current transform and clip on the save stack, and then
  /// creates a new group which subsequent calls will become a part of. When the
  /// save stack is later popped, the group will be flattened into a layer and
1757
  /// have the given `paint`'s [Paint.colorFilter] and [Paint.blendMode]
1758
  /// applied.
H
Hixie 已提交
1759
  ///
1760 1761 1762 1763 1764 1765
  /// This lets you create composite effects, for example making a group of
  /// drawing commands semi-transparent. Without using [saveLayer], each part of
  /// the group would be painted individually, so where they overlap would be
  /// darker than where they do not. By using [saveLayer] to group them
  /// together, they can be drawn with an opaque color at first, and then the
  /// entire group can be made transparent using the [saveLayer]'s paint.
H
Hixie 已提交
1766
  ///
1767
  /// Call [restore] to pop the save stack and apply the paint to the group.
1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860
  ///
  /// ## Using saveLayer with clips
  ///
  /// When a rectanglular clip operation (from [clipRect]) is not axis-aligned
  /// with the raster buffer, or when the clip operation is not rectalinear (e.g.
  /// because it is a rounded rectangle clip created by [clipRRect] or an
  /// arbitrarily complicated path clip created by [clipPath]), the edge of the
  /// clip needs to be anti-aliased.
  ///
  /// If two draw calls overlap at the edge of such a clipped region, without
  /// using [saveLayer], the first drawing will be anti-aliased with the
  /// background first, and then the second will be anti-aliased with the result
  /// of blending the first drawing and the background. On the other hand, if
  /// [saveLayer] is used immediately after establishing the clip, the second
  /// drawing will cover the first in the layer, and thus the second alone will
  /// be anti-aliased with the background when the layer is clipped and
  /// composited (when [restore] is called).
  ///
  /// For example, this [CustomPainter.paint] method paints a clean white
  /// rounded rectangle:
  ///
  /// ```dart
  /// void paint(Canvas canvas, Size size) {
  ///   Rect rect = Offset.zero & size;
  ///   canvas.save();
  ///   canvas.clipRRect(new RRect.fromRectXY(rect, 100.0, 100.0));
  ///   canvas.saveLayer(rect, new Paint());
  ///   canvas.drawPaint(new Paint()..color = Colors.red);
  ///   canvas.drawPaint(new Paint()..color = Colors.white);
  ///   canvas.restore();
  ///   canvas.restore();
  /// }
  /// ```
  ///
  /// On the other hand, this one renders a red outline, the result of the red
  /// paint being anti-aliased with the background at the clip edge, then the
  /// white paint being similarly anti-aliased with the background _including
  /// the clipped red paint_:
  ///
  /// ```dart
  /// void paint(Canvas canvas, Size size) {
  ///   // (this example renders poorly, prefer the example above)
  ///   Rect rect = Offset.zero & size;
  ///   canvas.save();
  ///   canvas.clipRRect(new RRect.fromRectXY(rect, 100.0, 100.0));
  ///   canvas.drawPaint(new Paint()..color = Colors.red);
  ///   canvas.drawPaint(new Paint()..color = Colors.white);
  ///   canvas.restore();
  /// }
  /// ```
  ///
  /// This point is moot if the clip only clips one draw operation. For example,
  /// the following paint method paints a pair of clean white rounded
  /// rectangles, even though the clips are not done on a separate layer:
  ///
  /// ```dart
  /// void paint(Canvas canvas, Size size) {
  ///   canvas.save();
  ///   canvas.clipRRect(new RRect.fromRectXY(Offset.zero & (size / 2.0), 50.0, 50.0));
  ///   canvas.drawPaint(new Paint()..color = Colors.white);
  ///   canvas.restore();
  ///   canvas.save();
  ///   canvas.clipRRect(new RRect.fromRectXY(size.center(Offset.zero) & (size / 2.0), 50.0, 50.0));
  ///   canvas.drawPaint(new Paint()..color = Colors.white);
  ///   canvas.restore();
  /// }
  /// ```
  ///
  /// (Incidentally, rather than using [clipRRect] and [drawPaint] to draw
  /// rounded rectangles like this, prefer the [drawRRect] method. These
  /// examples are using [drawPaint] as a proxy for "complicated draw operations
  /// that will get clipped", to illustrate the point.)
  ///
  /// ## Performance considerations
  ///
  /// Generally speaking, [saveLayer] is relatively expensive.
  ///
  /// There are a several different hardware architectures for GPUs (graphics
  /// processing units, the hardware that handles graphics), but most of them
  /// involve batching commands and reordering them for performance. When layers
  /// are used, they cause the rendering pipeline to have to switch render
  /// target (from one layer to another). Render target switches can flush the
  /// GPU's command buffer, which typically means that optimizations that one
  /// could get with larger batching are lost. Render target switches also
  /// generate a lot of memory churn because the GPU needs to copy out the
  /// current frame buffer contents from the part of memory that's optimized for
  /// writing, and then needs to copy it back in once the previous render target
  /// (layer) is restored.
  ///
  /// See also:
  ///
  ///  * [save], which saves the current state, but does not create a new layer
  ///    for subsequent commands.
1861 1862
  ///  * [BlendMode], which discusses the use of [Paint.blendMode] with
  ///    [saveLayer].
1863
  void saveLayer(Rect bounds, Paint paint) {
1864
    assert(_rectIsValid(bounds));
1865
    assert(paint != null);
1866 1867 1868 1869 1870 1871
    if (bounds == null) {
      _saveLayerWithoutBounds(paint._objects, paint._data);
    } else {
      _saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom,
                 paint._objects, paint._data);
    }
1872
  }
1873 1874
  void _saveLayerWithoutBounds(List<dynamic> paintObjects, ByteData paintData)
      native "Canvas_saveLayerWithoutBounds";
1875 1876 1877 1878
  void _saveLayer(double left,
                  double top,
                  double right,
                  double bottom,
1879 1880
                  List<dynamic> paintObjects,
                  ByteData paintData) native "Canvas_saveLayer";
H
Hixie 已提交
1881 1882 1883 1884 1885

  /// Pops the current save stack, if there is anything to pop.
  /// Otherwise, does nothing.
  ///
  /// Use [save] and [saveLayer] to push state onto the stack.
1886 1887 1888
  ///
  /// If the state was pushed with with [saveLayer], then this call will also
  /// cause the new layer to be composited into the previous layer.
1889
  void restore() native "Canvas_restore";
1890

H
Hixie 已提交
1891 1892 1893 1894 1895 1896
  /// Returns the number of items on the save stack, including the
  /// initial state. This means it returns 1 for a clean canvas, and
  /// that each call to [save] and [saveLayer] increments it, and that
  /// each matching call to [restore] decrements it.
  ///
  /// This number cannot go below 1.
1897
  int getSaveCount() native "Canvas_getSaveCount";
1898

1899 1900
  /// Add a translation to the current transform, shifting the coordinate space
  /// horizontally by the first argument and vertically by the second argument.
1901
  void translate(double dx, double dy) native "Canvas_translate";
1902 1903 1904 1905

  /// Add an axis-aligned scale to the current transform, scaling by the first
  /// argument in the horizontal direction and the second in the vertical
  /// direction.
1906
  void scale(double sx, double sy) native "Canvas_scale";
1907 1908

  /// Add a rotation to the current transform. The argument is in radians clockwise.
1909
  void rotate(double radians) native "Canvas_rotate";
1910 1911 1912 1913 1914

  /// Add an axis-aligned skew to the current transform, with the first argument
  /// being the horizontal skew in radians clockwise around the origin, and the
  /// second argument being the vertical skew in radians clockwise around the
  /// origin.
1915
  void skew(double sx, double sy) native "Canvas_skew";
A
Adam Barth 已提交
1916

1917 1918
  /// Multiply the current transform by the specified 4⨉4 transformation matrix
  /// specified as a list of values in column-major order.
A
Adam Barth 已提交
1919
  void transform(Float64List matrix4) {
1920
    assert(matrix4 != null);
A
Adam Barth 已提交
1921
    if (matrix4.length != 16)
1922
      throw new ArgumentError('"matrix4" must have 16 entries.');
A
Adam Barth 已提交
1923 1924
    _transform(matrix4);
  }
H
Hixie 已提交
1925
  void _transform(Float64List matrix4) native "Canvas_transform";
A
Adam Barth 已提交
1926

1927 1928
  /// Reduces the clip region to the intersection of the current clip and the
  /// given rectangle.
1929
  ///
1930 1931 1932 1933 1934
  /// If the clip is not axis-aligned with the display device, and
  /// [Paint.isAntiAlias] is true, then the clip will be anti-aliased. If
  /// multiple draw commands intersect with the clip boundary, this can result
  /// in incorrect blending at the clip boundary. See [saveLayer] for a
  /// discussion of how to address that.
1935 1936 1937 1938
  ///
  /// Use [ClipOp.difference] to subtract the provided rectangle from the
  /// current clip.
  void clipRect(Rect rect, { ClipOp clipOp: ClipOp.intersect }) {
1939
    assert(_rectIsValid(rect));
1940 1941
    assert(clipOp != null);
    _clipRect(rect.left, rect.top, rect.right, rect.bottom, clipOp.index);
1942 1943 1944 1945
  }
  void _clipRect(double left,
                 double top,
                 double right,
1946 1947
                 double bottom,
                 int clipOp) native "Canvas_clipRect";
1948

1949 1950
  /// Reduces the clip region to the intersection of the current clip and the
  /// given rounded rectangle.
1951
  ///
1952 1953 1954 1955
  /// If [Paint.isAntiAlias] is true, then the clip will be anti-aliased. If
  /// multiple draw commands intersect with the clip boundary, this can result
  /// in incorrect blending at the clip boundary. See [saveLayer] for a
  /// discussion of how to address that and some examples of using [clipRRect].
1956
  void clipRRect(RRect rrect) {
1957
    assert(_rrectIsValid(rrect));
1958 1959
    _clipRRect(rrect._value);
  }
1960
  void _clipRRect(Float32List rrect) native "Canvas_clipRRect";
1961

1962 1963
  /// Reduces the clip region to the intersection of the current clip and the
  /// given [Path].
1964
  ///
1965 1966 1967 1968
  /// If [Paint.isAntiAlias] is true, then the clip will be anti-aliased. If
  /// multiple draw commands intersect with the clip boundary, this can result
  /// in incorrect blending at the clip boundary. See [saveLayer] for a
  /// discussion of how to address that.
1969 1970 1971 1972 1973
  void clipPath(Path path) {
    assert(path != null); // path is checked on the engine side
    _clipPath(path);
  }
  void _clipPath(Path path) native "Canvas_clipPath";
1974

1975
  /// Paints the given [Color] onto the canvas, applying the given
1976
  /// [BlendMode], with the given color being the source and the background
1977
  /// being the destination.
1978
  void drawColor(Color color, BlendMode blendMode) {
1979 1980
    assert(color != null);
    assert(blendMode != null);
1981
    _drawColor(color.value, blendMode.index);
1982
  }
1983
  void _drawColor(int color, int blendMode) native "Canvas_drawColor";
1984

I
Ian Hickson 已提交
1985
  /// Draws a line between the given points using the given paint. The line is
1986
  /// stroked, the value of the [Paint.style] is ignored for this call.
I
Ian Hickson 已提交
1987 1988 1989
  ///
  /// The `p1` and `p2` arguments are interpreted as offsets from the origin.
  void drawLine(Offset p1, Offset p2, Paint paint) {
1990 1991
    assert(_offsetIsValid(p1));
    assert(_offsetIsValid(p2));
1992
    assert(paint != null);
I
Ian Hickson 已提交
1993
    _drawLine(p1.dx, p1.dy, p2.dx, p2.dy, paint._objects, paint._data);
1994
  }
1995 1996 1997 1998 1999 2000
  void _drawLine(double x1,
                 double y1,
                 double x2,
                 double y2,
                 List<dynamic> paintObjects,
                 ByteData paintData) native "Canvas_drawLine";
2001

2002 2003
  /// Fills the canvas with the given [Paint].
  ///
2004
  /// To fill the canvas with a solid color and blend mode, consider
2005
  /// [drawColor] instead.
2006 2007 2008 2009
  void drawPaint(Paint paint) {
    assert(paint != null);
    _drawPaint(paint._objects, paint._data);
  }
2010
  void _drawPaint(List<dynamic> paintObjects, ByteData paintData) native "Canvas_drawPaint";
2011

2012 2013
  /// Draws a rectangle with the given [Paint]. Whether the rectangle is filled
  /// or stroked (or both) is controlled by [Paint.style].
2014
  void drawRect(Rect rect, Paint paint) {
2015
    assert(_rectIsValid(rect));
2016
    assert(paint != null);
2017 2018
    _drawRect(rect.left, rect.top, rect.right, rect.bottom,
              paint._objects, paint._data);
2019 2020 2021 2022 2023
  }
  void _drawRect(double left,
                 double top,
                 double right,
                 double bottom,
2024 2025
                 List<dynamic> paintObjects,
                 ByteData paintData) native "Canvas_drawRect";
2026

2027 2028
  /// Draws a rounded rectangle with the given [Paint]. Whether the rectangle is
  /// filled or stroked (or both) is controlled by [Paint.style].
2029
  void drawRRect(RRect rrect, Paint paint) {
2030
    assert(_rrectIsValid(rrect));
2031
    assert(paint != null);
2032 2033 2034 2035 2036
    _drawRRect(rrect._value, paint._objects, paint._data);
  }
  void _drawRRect(Float32List rrect,
                  List<dynamic> paintObjects,
                  ByteData paintData) native "Canvas_drawRRect";
2037

2038 2039 2040 2041 2042
  /// Draws a shape consisting of the difference between two rounded rectangles
  /// with the given [Paint]. Whether this shape is filled or stroked (or both)
  /// is controlled by [Paint.style].
  ///
  /// This shape is almost but not quite entirely unlike an annulus.
2043
  void drawDRRect(RRect outer, RRect inner, Paint paint) {
2044 2045
    assert(_rrectIsValid(outer));
    assert(_rrectIsValid(inner));
2046
    assert(paint != null);
2047 2048 2049 2050 2051 2052
    _drawDRRect(outer._value, inner._value, paint._objects, paint._data);
  }
  void _drawDRRect(Float32List outer,
                   Float32List inner,
                   List<dynamic> paintObjects,
                   ByteData paintData) native "Canvas_drawDRRect";
2053

2054 2055 2056
  /// Draws an axis-aligned oval that fills the given axis-aligned rectangle
  /// with the given [Paint]. Whether the oval is filled or stroked (or both) is
  /// controlled by [Paint.style].
2057
  void drawOval(Rect rect, Paint paint) {
2058
    assert(_rectIsValid(rect));
2059
    assert(paint != null);
2060 2061
    _drawOval(rect.left, rect.top, rect.right, rect.bottom,
              paint._objects, paint._data);
2062 2063 2064 2065 2066
  }
  void _drawOval(double left,
                 double top,
                 double right,
                 double bottom,
2067 2068
                 List<dynamic> paintObjects,
                 ByteData paintData) native "Canvas_drawOval";
2069

I
Ian Hickson 已提交
2070 2071 2072
  /// Draws a circle centered at the point given by the first argument and
  /// that has the radius given by the second argument, with the [Paint] given in
  /// the third argument. Whether the circle is filled or stroked (or both) is
2073
  /// controlled by [Paint.style].
I
Ian Hickson 已提交
2074
  void drawCircle(Offset c, double radius, Paint paint) {
2075
    assert(_offsetIsValid(c));
2076
    assert(paint != null);
I
Ian Hickson 已提交
2077
    _drawCircle(c.dx, c.dy, radius, paint._objects, paint._data);
2078
  }
2079 2080 2081 2082 2083
  void _drawCircle(double x,
                   double y,
                   double radius,
                   List<dynamic> paintObjects,
                   ByteData paintData) native "Canvas_drawCircle";
2084

2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095
  /// Draw an arc scaled to fit inside the given rectangle. It starts from
  /// startAngle radians around the oval up to startAngle + sweepAngle
  /// radians around the oval, with zero radians being the point on
  /// the right hand side of the oval that crosses the horizontal line
  /// that intersects the center of the rectangle and with positive
  /// angles going clockwise around the oval. If useCenter is true, the arc is
  /// closed back to the center, forming a circle sector. Otherwise, the arc is
  /// not closed, forming a circle segment.
  ///
  /// This method is optimized for drawing arcs and should be faster than [Path.arcTo].
  void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint) {
2096
    assert(_rectIsValid(rect));
2097
    assert(paint != null);
2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110
    _drawArc(rect.left, rect.top, rect.right, rect.bottom, startAngle,
             sweepAngle, useCenter, paint._objects, paint._data);
  }
  void _drawArc(double left,
                double top,
                double right,
                double bottom,
                double startAngle,
                double sweepAngle,
                bool useCenter,
                List<dynamic> paintObjects,
                ByteData paintData) native "Canvas_drawArc";

2111 2112 2113
  /// Draws the given [Path] with the given [Paint]. Whether this shape is
  /// filled or stroked (or both) is controlled by [Paint.style]. If the path is
  /// filled, then subpaths within it are implicitly closed (see [Path.close]).
2114
  void drawPath(Path path, Paint paint) {
2115 2116
    assert(path != null); // path is checked on the engine side
    assert(paint != null);
2117 2118 2119 2120 2121
    _drawPath(path, paint._objects, paint._data);
  }
  void _drawPath(Path path,
                 List<dynamic> paintObjects,
                 ByteData paintData) native "Canvas_drawPath";
2122

2123
  /// Draws the given [Image] into the canvas with its top-left corner at the
I
Ian Hickson 已提交
2124 2125
  /// given [Offset]. The image is composited into the canvas using the given [Paint].
  void drawImage(Image image, Offset p, Paint paint) {
2126
    assert(image != null); // image is checked on the engine side
2127
    assert(_offsetIsValid(p));
2128
    assert(paint != null);
I
Ian Hickson 已提交
2129
    _drawImage(image, p.dx, p.dy, paint._objects, paint._data);
2130
  }
2131 2132 2133 2134 2135
  void _drawImage(Image image,
                  double x,
                  double y,
                  List<dynamic> paintObjects,
                  ByteData paintData) native "Canvas_drawImage";
2136

2137 2138
  /// Draws the subset of the given image described by the `src` argument into
  /// the canvas in the axis-aligned rectangle given by the `dst` argument.
2139
  ///
2140 2141
  /// This might sample from outside the `src` rect by up to half the width of
  /// an applied filter.
2142 2143 2144 2145
  ///
  /// Multiple calls to this method with different arguments (from the same
  /// image) can be batched into a single call to [drawAtlas] to improve
  /// performance.
2146
  void drawImageRect(Image image, Rect src, Rect dst, Paint paint) {
2147
    assert(image != null); // image is checked on the engine side
2148 2149
    assert(_rectIsValid(src));
    assert(_rectIsValid(dst));
2150
    assert(paint != null);
2151 2152 2153 2154 2155 2156 2157 2158 2159
    _drawImageRect(image,
                   src.left,
                   src.top,
                   src.right,
                   src.bottom,
                   dst.left,
                   dst.top,
                   dst.right,
                   dst.bottom,
2160 2161
                   paint._objects,
                   paint._data);
2162 2163 2164 2165 2166 2167 2168 2169 2170 2171
  }
  void _drawImageRect(Image image,
                      double srcLeft,
                      double srcTop,
                      double srcRight,
                      double srcBottom,
                      double dstLeft,
                      double dstTop,
                      double dstRight,
                      double dstBottom,
2172 2173
                      List<dynamic> paintObjects,
                      ByteData paintData) native "Canvas_drawImageRect";
2174

2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187
  /// Draws the given [Image] into the canvas using the given [Paint].
  ///
  /// The image is drawn in nine portions described by splitting the image by
  /// drawing two horizontal lines and two vertical lines, where the `center`
  /// argument describes the rectangle formed by the four points where these
  /// four lines intersect each other. (This forms a 3-by-3 grid of regions,
  /// the center region being described by the `center` argument.)
  ///
  /// The four regions in the corners are drawn, without scaling, in the four
  /// corners of the destination rectangle described by `dst`. The remaining
  /// five regions are drawn by stretching them to fit such that they exactly
  /// cover the destination rectangle while maintaining their relative
  /// positions.
2188
  void drawImageNine(Image image, Rect center, Rect dst, Paint paint) {
2189
    assert(image != null); // image is checked on the engine side
2190 2191
    assert(_rectIsValid(center));
    assert(_rectIsValid(dst));
2192
    assert(paint != null);
2193 2194 2195 2196 2197 2198 2199 2200 2201
    _drawImageNine(image,
                   center.left,
                   center.top,
                   center.right,
                   center.bottom,
                   dst.left,
                   dst.top,
                   dst.right,
                   dst.bottom,
2202 2203
                   paint._objects,
                   paint._data);
2204 2205 2206 2207 2208 2209 2210 2211 2212 2213
  }
  void _drawImageNine(Image image,
                      double centerLeft,
                      double centerTop,
                      double centerRight,
                      double centerBottom,
                      double dstLeft,
                      double dstTop,
                      double dstRight,
                      double dstBottom,
2214 2215
                      List<dynamic> paintObjects,
                      ByteData paintData) native "Canvas_drawImageNine";
2216

H
Hixie 已提交
2217 2218
  /// Draw the given picture onto the canvas. To create a picture, see
  /// [PictureRecorder].
2219 2220 2221 2222 2223
  void drawPicture(Picture picture) {
    assert(picture != null); // picture is checked on the engine side
    _drawPicture(picture);
  }
  void _drawPicture(Picture picture) native "Canvas_drawPicture";
2224

I
Ian Hickson 已提交
2225 2226
  /// Draws the text in the given [Paragraph] into this canvas at the given
  /// [Offset].
A
Adam Barth 已提交
2227
  ///
I
Ian Hickson 已提交
2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244
  /// The [Paragraph] object must have had [Paragraph.layout] called on it
  /// first.
  ///
  /// To align the text, set the `textAlign` on the [ParagraphStyle] object
  /// passed to the [new ParagraphBuilder] constructor. For more details see
  /// [TextAlign] and the discussion at [new ParagraphStyle].
  ///
  /// If the text is left aligned or justified, the left margin will be at the
  /// position specified by the `offset` argument's [Offset.dx] coordinate.
  ///
  /// If the text is right aligned or justified, the right margin will be at the
  /// position described by adding the [ParagraphConstraints.width] given to
  /// [Paragraph.layout], to the `offset` argument's [Offset.dx] coordinate.
  ///
  /// If the text is centered, the centering axis will be at the position
  /// described by adding half of the [ParagraphConstraints.width] given to
  /// [Paragraph.layout], to the `offset` argument's [Offset.dx] coordinate.
2245
  void drawParagraph(Paragraph paragraph, Offset offset) {
2246
    assert(paragraph != null);
2247
    assert(_offsetIsValid(offset));
2248
    paragraph._paint(this, offset.dx, offset.dy);
2249
  }
A
Adam Barth 已提交
2250

A
Adam Barth 已提交
2251
  /// Draws a sequence of points according to the given [PointMode].
I
Ian Hickson 已提交
2252 2253
  ///
  /// The `points` argument is interpreted as offsets from the origin.
2254 2255 2256 2257 2258
  ///
  /// See also:
  ///
  ///  * [drawRawPoints], which takes `points` as a [Float32List] rather than a
  ///    [List<Offset>].
I
Ian Hickson 已提交
2259
  void drawPoints(PointMode pointMode, List<Offset> points, Paint paint) {
2260 2261 2262
    assert(pointMode != null);
    assert(points != null);
    assert(paint != null);
2263
    _drawPoints(paint._objects, paint._data, pointMode.index, _encodePointList(points));
A
Adam Barth 已提交
2264
  }
2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275

  /// Draws a sequence of points according to the given [PointMode].
  ///
  /// The `points` argument is interpreted as a list of pairs of floating point
  /// numbers, where each pair represents an x and y offset from the origin.
  ///
  /// See also:
  ///
  ///  * [drawPoints], which takes `points` as a [List<Offset>] rather than a
  ///    [List<Float32List>].
  void drawRawPoints(PointMode pointMode, Float32List points, Paint paint) {
2276 2277 2278
    assert(pointMode != null);
    assert(points != null);
    assert(paint != null);
2279 2280 2281 2282 2283
    if (points.length % 2 != 0)
      throw new ArgumentError('"points" must have an even number of values.');
    _drawPoints(paint._objects, paint._data, pointMode.index, points);
  }

2284 2285 2286 2287
  void _drawPoints(List<dynamic> paintObjects,
                   ByteData paintData,
                   int pointMode,
                   Float32List points) native "Canvas_drawPoints";
A
Adam Barth 已提交
2288

2289
  void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint) {
2290 2291 2292 2293
    assert(vertices != null); // vertices is checked on the engine side
    assert(paint != null);
    assert(blendMode != null);
    _drawVertices(vertices, blendMode.index, paint._objects, paint._data);
2294
  }
2295
  void _drawVertices(Vertices vertices,
2296
                     int blendMode,
2297 2298
                     List<dynamic> paintObjects,
                     ByteData paintData) native "Canvas_drawVertices";
2299

2300 2301 2302 2303 2304
  //
  // See also:
  //
  //  * [drawRawAtlas], which takes its arguments as typed data lists rather
  //    than objects.
2305
  void drawAtlas(Image atlas,
2306 2307 2308
                 List<RSTransform> transforms,
                 List<Rect> rects,
                 List<Color> colors,
2309
                 BlendMode blendMode,
2310 2311
                 Rect cullRect,
                 Paint paint) {
2312 2313 2314 2315 2316 2317
    assert(atlas != null); // atlas is checked on the engine side
    assert(transforms != null);
    assert(rects != null);
    assert(colors != null);
    assert(blendMode != null);
    assert(paint != null);
2318

2319
    final int rectCount = rects.length;
2320
    if (transforms.length != rectCount)
2321
      throw new ArgumentError('"transforms" and "rects" lengths must match.');
2322
    if (colors.isNotEmpty && colors.length != rectCount)
2323
      throw new ArgumentError('If non-null, "colors" length must match that of "transforms" and "rects".');
2324

A
Adam Barth 已提交
2325 2326
    final Float32List rstTransformBuffer = new Float32List(rectCount * 4);
    final Float32List rectBuffer = new Float32List(rectCount * 4);
2327 2328 2329 2330 2331 2332 2333 2334

    for (int i = 0; i < rectCount; ++i) {
      final int index0 = i * 4;
      final int index1 = index0 + 1;
      final int index2 = index0 + 2;
      final int index3 = index0 + 3;
      final RSTransform rstTransform = transforms[i];
      final Rect rect = rects[i];
2335
      assert(_rectIsValid(rect));
2336 2337 2338 2339 2340 2341 2342 2343
      rstTransformBuffer[index0] = rstTransform.scos;
      rstTransformBuffer[index1] = rstTransform.ssin;
      rstTransformBuffer[index2] = rstTransform.tx;
      rstTransformBuffer[index3] = rstTransform.ty;
      rectBuffer[index0] = rect.left;
      rectBuffer[index1] = rect.top;
      rectBuffer[index2] = rect.right;
      rectBuffer[index3] = rect.bottom;
2344
    }
2345

2346
    final Int32List colorBuffer = colors.isEmpty ? null : _encodeColorList(colors);
2347 2348
    final Float32List cullRectBuffer = cullRect?._value;

2349 2350
    _drawAtlas(
      paint._objects, paint._data, atlas, rstTransformBuffer, rectBuffer,
2351
      colorBuffer, blendMode.index, cullRectBuffer
2352
    );
2353
  }
2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376

  //
  // The `rstTransforms` argument is interpreted as a list of four-tuples, with
  // each tuple being ([RSTransform.scos], [RSTransform.ssin],
  // [RSTransform.tx], [RSTransform.ty]).
  //
  // The `rects` argument is interpreted as a list of four-tuples, with each
  // tuple being ([Rect.left], [Rect.top], [Rect.right], [Rect.bottom]).
  //
  // The `colors` argument, which can be null, is interpreted as a list of
  // 32-bit colors, with the same packing as [Color.value].
  //
  // See also:
  //
  //  * [drawAtlas], which takes its arguments as objects rather than typed
  //    data lists.
  void drawRawAtlas(Image atlas,
                    Float32List rstTransforms,
                    Float32List rects,
                    Int32List colors,
                    BlendMode blendMode,
                    Rect cullRect,
                    Paint paint) {
2377 2378 2379 2380 2381 2382
    assert(atlas != null); // atlas is checked on the engine side
    assert(rstTransforms != null);
    assert(rects != null);
    assert(colors != null);
    assert(blendMode != null);
    assert(paint != null);
2383

2384
    final int rectCount = rects.length;
2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397
    if (rstTransforms.length != rectCount)
      throw new ArgumentError('"rstTransforms" and "rects" lengths must match.');
    if (rectCount % 4 != 0)
      throw new ArgumentError('"rstTransforms" and "rects" lengths must be a multiple of four.');
    if (colors != null && colors.length * 4 != rectCount)
      throw new ArgumentError('If non-null, "colors" length must be one fourth the length of "rstTransforms" and "rects".');

    _drawAtlas(
      paint._objects, paint._data, atlas, rstTransforms, rects,
      colors, blendMode.index, cullRect?._value
    );
  }

2398 2399
  void _drawAtlas(List<dynamic> paintObjects,
                  ByteData paintData,
A
Adam Barth 已提交
2400
                  Image atlas,
2401 2402 2403
                  Float32List rstTransforms,
                  Float32List rects,
                  Int32List colors,
2404
                  int blendMode,
A
Adam Barth 已提交
2405
                  Float32List cullRect) native "Canvas_drawAtlas";
2406 2407 2408 2409

  /// Draws a shadow for a [Path] representing the given material elevation.
  ///
  /// transparentOccluder should be true if the occluding object is not opaque.
2410
  void drawShadow(Path path, Color color, double elevation, bool transparentOccluder) {
2411 2412
    assert(path != null); // path is checked on the engine side
    assert(color != null);
2413 2414 2415 2416
    _drawShadow(path, color.value, elevation, transparentOccluder);
  }
  void _drawShadow(Path path,
                   int color,
2417
                   double elevation,
2418
                   bool transparentOccluder) native "Canvas_drawShadow";
2419 2420
}

A
Adam Barth 已提交
2421
/// An object representing a sequence of recorded graphical operations.
2422 2423
///
/// To create a [Picture], use a [PictureRecorder].
H
Hixie 已提交
2424 2425 2426 2427
///
/// A [Picture] can be placed in a [Scene] using a [SceneBuilder], via
/// the [SceneBuilder.addPicture] method. A [Picture] can also be
/// drawn into a [Canvas], using the [Canvas.drawPicture] method.
2428
abstract class Picture extends NativeFieldWrapperClass2 {
2429 2430 2431 2432 2433
  /// Creates an uninitialized Picture object.
  ///
  /// Calling the Picture constructor directly will not create a useable
  /// object. To create a Picture object, use a [PictureRecorder].
  Picture(); // (this constructor is here just so we can document it)
2434

A
Adam Barth 已提交
2435
  /// Creates an image from this picture.
2436
  ///
A
Adam Barth 已提交
2437 2438
  /// The picture is rasterized using the number of pixels specified by the
  /// given width and height.
2439
  ///
A
Adam Barth 已提交
2440 2441 2442 2443
  /// Although the image is returned synchronously, the picture is actually
  /// rasterized the first time the image is drawn and then cached.
  Image toImage(int width, int height) native "Picture_toImage";

I
Ian Hickson 已提交
2444 2445
  /// Release the resources used by this object. The object is no longer usable
  /// after this method is called.
2446 2447 2448
  void dispose() native "Picture_dispose";
}

A
Adam Barth 已提交
2449 2450 2451
/// Records a [Picture] containing a sequence of graphical operations.
///
/// To begin recording, construct a [Canvas] to record the commands.
2452
/// To end recording, use the [PictureRecorder.endRecording] method.
2453
class PictureRecorder extends NativeFieldWrapperClass2 {
2454 2455 2456
  /// Creates a new idle PictureRecorder. To associate it with a
  /// [Canvas] and begin recording, pass this [PictureRecorder] to the
  /// [Canvas] constructor.
2457
  PictureRecorder() { _constructor(); }
2458
  void _constructor() native "PictureRecorder_constructor";
2459

A
Adam Barth 已提交
2460 2461
  /// Whether this object is currently recording commands.
  ///
2462 2463 2464 2465 2466
  /// Specifically, this returns true if a [Canvas] object has been
  /// created to record commands and recording has not yet ended via a
  /// call to [endRecording], and false if either this
  /// [PictureRecorder] has not yet been associated with a [Canvas],
  /// or the [endRecording] method has already been called.
2467
  bool get isRecording native "PictureRecorder_isRecording";
A
Adam Barth 已提交
2468 2469 2470 2471 2472 2473

  /// Finishes recording graphical operations.
  ///
  /// Returns a picture containing the graphical operations that have been
  /// recorded thus far. After calling this function, both the picture recorder
  /// and the canvas objects are invalid and cannot be used further.
2474 2475
  ///
  /// Returns null if the PictureRecorder is not associated with a canvas.
2476 2477
  Picture endRecording() native "PictureRecorder_endRecording";
}
2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503

/// Generic callback signature, used by [_futurize].
typedef void _Callback<T>(T result);

/// Signature for a method that receives a [_Callback].
///
/// Return value should be null on success, and a string error message on
/// failure.
typedef String _Callbacker<T>(_Callback<T> callback);

/// Converts a method that receives a value-returning callback to a method that
/// returns a Future.
///
/// Example usage:
/// ```dart
/// typedef void IntCallback(int result);
/// 
/// void doSomethingAndCallback(IntCallback callback) {
///   new Timer(new Duration(seconds: 1), () { callback(1); });
/// }
/// 
/// Future<int> doSomething() {
///   return _futurize(domeSomethingAndCallback);
/// }
/// ```
///
2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514
Future<T> _futurize<T>(_Callbacker<T> callbacker) {
  final Completer<T> completer = new Completer<T>.sync();
  final String err = callbacker((t) {
    if (t == null) {
      completer.completeError(new Exception('operation failed'));
    } else {
      completer.complete(t);
    }
  });

  if (err != null)
2515
    throw new Exception(err);
2516 2517

  return completer.future;
2518 2519
}