painting.dart 132.5 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 _matrix4IsValid(Float64List matrix4) {
  assert(matrix4 != null, 'Matrix4 argument was null.');
  assert(matrix4.length == 16, 'Matrix4 must have 16 entries.');
  return true;
}

48 49 50 51 52 53
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;
}

54
Color _scaleAlpha(Color a, double factor) {
55
  return a.withAlpha((a.alpha * factor).round().clamp(0, 255));
56 57
}

I
Ian Hickson 已提交
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
/// 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 已提交
83 84 85 86 87
///
/// See also:
///
///  * [Colors](https://docs.flutter.io/flutter/material/Colors-class.html), which
///    defines the colors found in the Material Design specification.
88
class Color {
I
Ian Hickson 已提交
89
  /// Construct a color from the lower 32 bits of an [int].
90
  ///
I
Ian Hickson 已提交
91 92 93 94 95 96 97 98 99 100 101 102 103 104
  /// 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).
105
  const Color(int value) : value = value & 0xFFFFFFFF;
106 107

  /// Construct a color from the lower 8 bits of four integers.
A
Adam Barth 已提交
108 109 110 111 112 113 114 115 116 117 118
  ///
  /// * `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.
119
  const Color.fromARGB(int a, int r, int g, int b) :
120 121 122 123
    value = (((a & 0xff) << 24) |
             ((r & 0xff) << 16) |
             ((g & 0xff) << 8)  |
             ((b & 0xff) << 0)) & 0xFFFFFFFF;
124

A
Adam Barth 已提交
125 126 127 128 129 130 131 132 133 134 135 136
  /// 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) :
137 138 139 140
    value = ((((opacity * 0xff ~/ 1) & 0xff) << 24) |
              ((r                    & 0xff) << 16) |
              ((g                    & 0xff) << 8)  |
              ((b                    & 0xff) << 0)) & 0xFFFFFFFF;
A
Adam Barth 已提交
141

142 143
  /// A 32 bit value representing this color.
  ///
I
Ian Hickson 已提交
144 145 146 147 148 149
  /// 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.
150
  final int value;
151 152

  /// The alpha channel of this color in an 8 bit value.
A
Adam Barth 已提交
153 154 155
  ///
  /// A value of 0 means this color is fully transparent. A value of 255 means
  /// this color is fully opaque.
156
  int get alpha => (0xff000000 & value) >> 24;
157 158

  /// The alpha channel of this color as a double.
A
Adam Barth 已提交
159 160 161
  ///
  /// A value of 0.0 means this color is fully transparent. A value of 1.0 means
  /// this color is fully opaque.
162 163 164
  double get opacity => alpha / 0xFF;

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

  /// The green channel of this color in an 8 bit value.
168
  int get green => (0x0000ff00 & value) >> 8;
169 170

  /// The blue channel of this color in an 8 bit value.
171
  int get blue => (0x000000ff & value) >> 0;
172 173

  /// Returns a new color that matches this color with the alpha channel
I
Ian Hickson 已提交
174
  /// replaced with `a` (which ranges from 0 to 255).
175 176
  ///
  /// Out of range values will have unexpected effects.
177 178 179 180 181
  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 已提交
182
  /// replaced with the given `opacity` (which ranges from 0.0 to 1.0).
183 184
  ///
  /// Out of range values will have unexpected effects.
185 186 187 188 189 190
  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
191 192 193
  /// with `r` (which ranges from 0 to 255).
  ///
  /// Out of range values will have unexpected effects.
194 195 196 197 198
  Color withRed(int r) {
    return new Color.fromARGB(alpha, r, green, blue);
  }

  /// Returns a new color that matches this color with the green channel
199 200 201
  /// replaced with `g` (which ranges from 0 to 255).
  ///
  /// Out of range values will have unexpected effects.
202 203 204 205 206
  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
207 208 209
  /// with `b` (which ranges from 0 to 255).
  ///
  /// Out of range values will have unexpected effects.
210 211 212 213
  Color withBlue(int b) {
    return new Color.fromARGB(alpha, red, green, b);
  }

X
xster 已提交
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
  // 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 已提交
235
  /// Linearly interpolate between two colors.
236
  ///
237 238 239
  /// This is intended to be fast but as a result may be ugly. Consider
  /// [HSVColor] or writing custom logic for interpolating colors.
  ///
240
  /// If either color is null, this function linearly interpolates from a
241
  /// transparent instance of the other color. This is usually preferable to
242 243
  /// interpolating from [material.Colors.transparent] (`const
  /// Color(0x00000000)`), which is specifically transparent _black_.
244
  ///
245 246 247 248 249 250 251 252 253
  /// 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.
254
  ///
255 256
  /// Values for `t` are usually obtained from an [Animation<double>], such as
  /// an [AnimationController].
257
  static Color lerp(Color a, Color b, double t) {
258
    assert(t != null);
259 260 261 262 263 264 265
    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(
266 267 268 269
      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),
270 271 272
    );
  }

G
Greg Spencer 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
  /// Combine the foreground color as a transparent color over top
  /// of a background color, and return the resulting combined color.
  ///
  /// This uses standard alpha blending ("SRC over DST") rules to produce a
  /// blended color from two colors. This can be used as a performance
  /// enhancement when trying to avoid needless alpha blending compositing
  /// operations for two things that are solid colors with the same shape, but
  /// overlay each other: instead, just paint one with the combined color.
  static Color alphaBlend(Color foreground, Color background) {
    final int alpha = foreground.alpha;
    if (alpha == 0x00) { // Foreground completely transparent.
      return background;
    }
    final int invAlpha = 0xff - alpha;
    int backAlpha = background.alpha;
    if (backAlpha == 0xff) { // Opaque background case
      return new Color.fromARGB(
        0xff,
        (alpha * foreground.red + invAlpha * background.red) ~/ 0xff,
        (alpha * foreground.green + invAlpha * background.green) ~/ 0xff,
        (alpha * foreground.blue + invAlpha * background.blue) ~/ 0xff,
      );
    } else { // General case
      backAlpha = (backAlpha * invAlpha) ~/ 0xff;
      final int outAlpha = alpha + backAlpha;
      assert(outAlpha != 0x00);
      return new Color.fromARGB(
        outAlpha,
        (foreground.red * alpha + background.red * backAlpha) ~/ outAlpha,
        (foreground.green * alpha + background.green * backAlpha) ~/ outAlpha,
        (foreground.blue * alpha + background.blue * backAlpha) ~/ outAlpha,
      );
    }
  }

308 309
  @override
  bool operator ==(dynamic other) {
310 311 312
    if (identical(this, other))
      return true;
    if (other.runtimeType != runtimeType)
313 314 315 316 317 318
      return false;
    final Color typedOther = other;
    return value == typedOther.value;
  }

  @override
319
  int get hashCode => value.hashCode;
320 321

  @override
322
  String toString() => 'Color(0x${value.toRadixString(16).padLeft(8, '0')})';
323 324 325 326
}

/// Algorithms to use when painting on the canvas.
///
327 328 329
/// When drawing a shape or image onto a canvas, different algorithms can be
/// used to blend the pixels. The different values of [BlendMode] specify
/// different such algorithms.
330
///
331 332 333 334 335 336 337
/// Each algorithm has two inputs, the _source_, which is the image being drawn,
/// and the _destination_, which is the image into which the source image is
/// being composited. The destination is often thought of as the _background_.
/// The source and destination both have four color channels, the red, green,
/// blue, and alpha channels. These are typically represented as numbers in the
/// range 0.0 to 1.0. The output of the algorithm also has these same four
/// channels, with values computed from the source and destination.
338
///
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
/// The documentation of each value below describes how the algorithm works. In
/// each case, an image shows the output of blending a source image with a
/// destination image. In the images below, the destination is represented by an
/// image with horizontal lines and an opaque landscape photograph, and the
/// source is represented by an image with vertical lines (the same lines but
/// rotated) and a bird clip-art image. The [src] mode shows only the source
/// image, and the [dst] mode shows only the destination image. In the
/// documentation below, the transparency is illustrated by a checkerboard
/// pattern. The [clear] mode drops both the source and destination, resulting
/// in an output that is entirely transparent (illustrated by a solid
/// checkerboard pattern).
///
/// The horizontal and vertical bars in these images show the red, green, and
/// blue channels with varying opacity levels, then all three color channels
/// together with those same varying opacity levels, then all three color
G
Greg Spencer 已提交
354
/// channels set to zero with those varying opacity levels, then two bars showing
355 356 357 358 359
/// a red/green/blue repeating gradient, the first with full opacity and the
/// second with partial opacity, and finally a bar with the three color channels
/// set to zero but the opacity varying in a repeating gradient.
///
/// ## Application to the [Canvas] API
360
///
361 362 363 364
/// 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
365 366
/// called, that layer is then composited onto the parent layer, with the source
/// being the most-recently-drawn shapes and images, and the destination being
367 368
/// the parent layer. (For the first [Canvas.saveLayer] call, the parent layer
/// is the canvas itself.)
369 370 371 372 373
///
/// See also:
///
///  * [Paint.blendMode], which uses [BlendMode] to define the compositing
///    strategy.
374
enum BlendMode {
375 376 377 378
  // 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

379 380 381
  /// Drop both the source and destination images, leaving nothing.
  ///
  /// This corresponds to the "clear" Porter-Duff operator.
382 383
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_clear.png)
384
  clear,
385 386 387 388 389 390 391

  /// 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.
392 393
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_src.png)
394
  src,
395 396 397 398 399 400 401

  /// 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.
402 403
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_dst.png)
404
  dst,
405 406 407 408 409 410 411 412 413

  /// 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.
414 415
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_srcOver.png)
416
  srcOver,
417 418 419 420 421 422

  /// Composite the source image under the destination image.
  ///
  /// This is the opposite of [srcOver].
  ///
  /// This corresponds to the "Destination over Source" Porter-Duff operator.
423 424 425 426 427
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_dstOver.png)
  ///
  /// This is useful when the source image should have been painted before the
  /// destination image, but could not be.
428
  dstOver,
429 430

  /// Show the source image, but only where the two images overlap. The
431 432 433
  /// destination image is not rendered, it is treated merely as a mask. The
  /// color channels of the destination are ignored, only the opacity has an
  /// effect.
434 435 436 437 438 439 440 441
  ///
  /// 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.
442 443
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_srcIn.png)
444
  srcIn,
445 446

  /// Show the destination image, but only where the two images overlap. The
447 448
  /// source image is not rendered, it is treated merely as a mask. The color
  /// channels of the source are ignored, only the opacity has an effect.
449 450 451 452
  ///
  /// To show the source image instead, consider [srcIn].
  ///
  /// To reverse the semantic of the mask (only showing the source where the
453
  /// destination is present, rather than where it is absent), consider [dstOut].
454 455
  ///
  /// This corresponds to the "Destination in Source" Porter-Duff operator.
456 457
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_dstIn.png)
458
  dstIn,
459 460

  /// Show the source image, but only where the two images do not overlap. The
461 462
  /// destination image is not rendered, it is treated merely as a mask. The color
  /// channels of the destination are ignored, only the opacity has an effect.
463 464 465 466 467 468 469
  ///
  /// 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.
470 471
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_srcOut.png)
472
  srcOut,
473 474

  /// Show the destination image, but only where the two images do not overlap. The
475 476
  /// source image is not rendered, it is treated merely as a mask. The color
  /// channels of the source are ignored, only the opacity has an effect.
477 478 479 480 481 482 483
  ///
  /// 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.
484 485
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_dstOut.png)
486
  dstOut,
487 488 489 490 491

  /// 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.
492 493 494 495 496 497 498 499 500
  ///
  /// This is essentially the [srcOver] operator, but with the output's opacity
  /// channel being set to that of the destination image instead of being a
  /// combination of both image's opacity channels.
  ///
  /// For a variant with the destination on top instead of the source, see
  /// [dstATop].
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_srcATop.png)
501
  srcATop,
502 503 504 505 506

  /// 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.
507 508 509 510 511 512 513 514 515
  ///
  /// This is essentially the [dstOver] operator, but with the output's opacity
  /// channel being set to that of the source image instead of being a
  /// combination of both image's opacity channels.
  ///
  /// For a variant with the source on top instead of the destination, see
  /// [srcATop].
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_dstATop.png)
516
  dstATop,
517

518 519
  /// Apply a bitwise `xor` operator to the source and destination images. This
  /// leaves transparency where they would overlap.
520 521
  ///
  /// This corresponds to the "Source xor Destination" Porter-Duff operator.
522 523
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_xor.png)
524
  xor,
525

526 527 528 529 530
  /// Sum the components of the source and destination images.
  ///
  /// Transparency in a pixel of one of the images reduces the contribution of
  /// that image to the corresponding output pixel, as if the color of that
  /// pixel in that image was darker.
531 532
  ///
  /// This corresponds to the "Source plus Destination" Porter-Duff operator.
533 534
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_plus.png)
535
  plus,
536

537 538 539 540 541 542 543 544 545 546 547 548 549 550
  /// Multiply the color components of the source and destination images.
  ///
  /// This can only result in the same or darker colors (multiplying by white,
  /// 1.0, results in no change; multiplying by black, 0.0, results in black).
  ///
  /// When compositing two opaque images, this has similar effect to overlapping
  /// two transparencies on a projector.
  ///
  /// For a variant that also multiplies the alpha channel, consider [multiply].
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_modulate.png)
  ///
  /// See also:
  ///
G
Greg Spencer 已提交
551
  ///  * [screen], which does a similar computation but inverted.
552 553 554 555
  ///  * [overlay], which combines [modulate] and [screen] to favor the
  ///    destination image.
  ///  * [hardLight], which combines [modulate] and [screen] to favor the
  ///    source image.
556 557 558 559
  modulate,

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

560 561 562
  /// Multiply the inverse of the components of the source and destination
  /// images, and inverse the result.
  ///
G
Greg Spencer 已提交
563
  /// Inverting the components means that a fully saturated channel (opaque
564 565 566 567
  /// white) is treated as the value 0.0, and values normally treated as 0.0
  /// (black, transparent) are treated as 1.0.
  ///
  /// This is essentially the same as [modulate] blend mode, but with the values
G
Greg Spencer 已提交
568 569
  /// of the colors inverted before the multiplication and the result being
  /// inverted back before rendering.
570 571 572 573 574 575 576 577 578 579 580 581
  ///
  /// This can only result in the same or lighter colors (multiplying by black,
  /// 1.0, results in no change; multiplying by white, 0.0, results in white).
  /// Similarly, in the alpha channel, it can only result in more opaque colors.
  ///
  /// This has similar effect to two projectors displaying their images on the
  /// same screen simultaneously.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_screen.png)
  ///
  /// See also:
  ///
G
Greg Spencer 已提交
582
  ///  * [modulate], which does a similar computation but without inverting the
583 584 585 586 587
  ///    values.
  ///  * [overlay], which combines [modulate] and [screen] to favor the
  ///    destination image.
  ///  * [hardLight], which combines [modulate] and [screen] to favor the
  ///    source image.
588 589
  screen,  // The last coeff mode.

590 591 592 593 594 595
  /// Multiply the components of the source and destination images after
  /// adjusting them to favor the destination.
  ///
  /// Specifically, if the destination value is smaller, this multiplies it with
  /// the source value, whereas is the source value is smaller, it multiplies
  /// the inverse of the source value with the inverse of the destination value,
G
Greg Spencer 已提交
596
  /// then inverts the result.
597
  ///
G
Greg Spencer 已提交
598
  /// Inverting the components means that a fully saturated channel (opaque
599 600 601 602 603 604 605 606 607 608 609
  /// white) is treated as the value 0.0, and values normally treated as 0.0
  /// (black, transparent) are treated as 1.0.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_overlay.png)
  ///
  /// See also:
  ///
  ///  * [modulate], which always multiplies the values.
  ///  * [screen], which always multiplies the inverses of the values.
  ///  * [hardLight], which is similar to [overlay] but favors the source image
  ///    instead of the destination image.
610
  overlay,
611 612 613 614 615 616 617 618

  /// Composite the source and destination image by choosing the lowest value
  /// from each color channel.
  ///
  /// The opacity of the output image is computed in the same way as for
  /// [srcOver].
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_darken.png)
619
  darken,
620 621 622 623 624 625 626 627

  /// Composite the source and destination image by choosing the highest value
  /// from each color channel.
  ///
  /// The opacity of the output image is computed in the same way as for
  /// [srcOver].
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_lighten.png)
628
  lighten,
629 630 631

  /// Divide the destination by the inverse of the source.
  ///
G
Greg Spencer 已提交
632
  /// Inverting the components means that a fully saturated channel (opaque
633 634 635 636
  /// white) is treated as the value 0.0, and values normally treated as 0.0
  /// (black, transparent) are treated as 1.0.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_colorDodge.png)
637
  colorDodge,
638 639 640

  /// Divide the inverse of the destination by the the source, and inverse the result.
  ///
G
Greg Spencer 已提交
641
  /// Inverting the components means that a fully saturated channel (opaque
642 643 644 645
  /// white) is treated as the value 0.0, and values normally treated as 0.0
  /// (black, transparent) are treated as 1.0.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_colorBurn.png)
646
  colorBurn,
647 648 649 650 651 652 653

  /// Multiply the components of the source and destination images after
  /// adjusting them to favor the source.
  ///
  /// Specifically, if the source value is smaller, this multiplies it with the
  /// destination value, whereas is the destination value is smaller, it
  /// multiplies the inverse of the destination value with the inverse of the
G
Greg Spencer 已提交
654
  /// source value, then inverts the result.
655
  ///
G
Greg Spencer 已提交
656
  /// Inverting the components means that a fully saturated channel (opaque
657 658 659 660 661 662 663 664 665 666 667
  /// white) is treated as the value 0.0, and values normally treated as 0.0
  /// (black, transparent) are treated as 1.0.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_hardLight.png)
  ///
  /// See also:
  ///
  ///  * [modulate], which always multiplies the values.
  ///  * [screen], which always multiplies the inverses of the values.
  ///  * [overlay], which is similar to [hardLight] but favors the destination
  ///    image instead of the source image.
668
  hardLight,
669 670 671 672

  /// Use [colorDodge] for source values below 0.5 and [colorBurn] for source
  /// values above 0.5.
  ///
G
Greg Spencer 已提交
673
  /// This results in a similar but softer effect than [overlay].
674 675 676 677 678 679
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_softLight.png)
  ///
  /// See also:
  ///
  ///  * [color], which is a more subtle tinting effect.
680
  softLight,
681 682 683

  /// Subtract the smaller value from the bigger value for each channel.
  ///
G
Greg Spencer 已提交
684
  /// Compositing black has no effect; compositing white inverts the colors of
685 686 687 688 689 690 691 692
  /// the other image.
  ///
  /// The opacity of the output image is computed in the same way as for
  /// [srcOver].
  ///
  /// The effect is similar to [exclusion] but harsher.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_difference.png)
693
  difference,
694 695 696 697

  /// Subtract double the product of the two images from the sum of the two
  /// images.
  ///
G
Greg Spencer 已提交
698
  /// Compositing black has no effect; compositing white inverts the colors of
699 700 701 702 703 704 705 706
  /// the other image.
  ///
  /// The opacity of the output image is computed in the same way as for
  /// [srcOver].
  ///
  /// The effect is similar to [difference] but softer.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_exclusion.png)
707
  exclusion,
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722

  /// Multiply the components of the source and destination images, including
  /// the alpha channel.
  ///
  /// This can only result in the same or darker colors (multiplying by white,
  /// 1.0, results in no change; multiplying by black, 0.0, results in black).
  ///
  /// Since the alpha channel is also multiplied, a fully-transparent pixel
  /// (opacity 0.0) in one image results in a fully transparent pixel in the
  /// output. This is similar to [dstIn], but with the colors combined.
  ///
  /// For a variant that multiplies the colors but does not multiply the alpha
  /// channel, consider [modulate].
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_multiply.png)
723 724
  multiply,  // The last separable mode.

725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
  /// Take the hue of the source image, and the saturation and luminosity of the
  /// destination image.
  ///
  /// The effect is to tint the destination image with the source image.
  ///
  /// The opacity of the output image is computed in the same way as for
  /// [srcOver]. Regions that are entirely transparent in the source image take
  /// their hue from the destination.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_hue.png)
  ///
  /// See also:
  ///
  ///  * [color], which is a similar but stronger effect as it also applies the
  ///    saturation of the source image.
  ///  * [HSVColor], which allows colors to be expressed using Hue rather than
  ///    the red/green/blue channels of [Color].
742
  hue,
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757

  /// Take the saturation of the source image, and the hue and luminosity of the
  /// destination image.
  ///
  /// The opacity of the output image is computed in the same way as for
  /// [srcOver]. Regions that are entirely transparent in the source image take
  /// their saturation from the destination.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_hue.png)
  ///
  /// See also:
  ///
  ///  * [color], which also applies the hue of the source image.
  ///  * [luminosity], which applies the luminosity of the source image to the
  ///    destination.
758
  saturation,
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775

  /// Take the hue and saturation of the source image, and the luminosity of the
  /// destination image.
  ///
  /// The effect is to tint the destination image with the source image.
  ///
  /// The opacity of the output image is computed in the same way as for
  /// [srcOver]. Regions that are entirely transparent in the source image take
  /// their hue and saturation from the destination.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_color.png)
  ///
  /// See also:
  ///
  ///  * [hue], which is a similar but weaker effect.
  ///  * [softLight], which is a similar tinting effect but also tints white.
  ///  * [saturation], which only applies the saturation of the source image.
776
  color,
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792

  /// Take the luminosity of the source image, and the hue and saturation of the
  /// destination image.
  ///
  /// The opacity of the output image is computed in the same way as for
  /// [srcOver]. Regions that are entirely transparent in the source image take
  /// their luminosity from the destination.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/blend_mode_luminosity.png)
  ///
  /// See also:
  ///
  ///  * [saturation], which applies the saturation of the source image to the
  ///    destination.
  ///  * [ImageFilter.blur], which can be used with [BackdropFilter] for a
  ///    related effect.
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
  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].
828
// These enum values must be kept in sync with SkPaint::Cap.
829 830 831 832 833 834 835 836 837 838 839 840 841
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,
}

842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
/// 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,
}

861 862 863
/// Strategies for painting shapes and paths on a canvas.
///
/// See [Paint.style].
864
// These enum values must be kept in sync with SkPaint::Style.
865 866 867 868 869
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 已提交
870
  /// applied to the [Canvas.drawCircle] call, this results in a disc
871 872 873 874
  /// of the given size being painted.
  fill,

  /// Apply the [Paint] to the edge of the shape. For example, when
I
Ian Hickson 已提交
875
  /// applied to the [Canvas.drawCircle] call, this results is a hoop
876 877 878 879 880
  /// of the given size being painted. The line drawn on the edge will
  /// be the width given by the [Paint.strokeWidth] property.
  stroke,
}

881
// If we actually run on big endian machines, we'll need to do something smarter
882
// here. We don't use [Endian.Host] because it's not a compile-time
883
// constant and can't propagate into the set/get calls.
884
const Endian _kFakeHostEndian = Endian.little;
885

886 887 888 889 890
/// 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 {
891 892 893 894 895
  // 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
896
  //   value of zero, but some, such as color, have a non-zero default value.
897 898 899 900 901 902 903 904 905 906 907
  //   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;
908
  static const int _kBlendModeIndex = 2;
909 910 911
  static const int _kStyleIndex = 3;
  static const int _kStrokeWidthIndex = 4;
  static const int _kStrokeCapIndex = 5;
912 913 914 915 916 917
  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;
918 919 920
  static const int _kMaskFilterIndex = 12;
  static const int _kMaskFilterBlurStyleIndex = 13;
  static const int _kMaskFilterSigmaIndex = 14;
921 922 923

  static const int _kIsAntiAliasOffset = _kIsAntiAliasIndex << 2;
  static const int _kColorOffset = _kColorIndex << 2;
924
  static const int _kBlendModeOffset = _kBlendModeIndex << 2;
925 926 927
  static const int _kStyleOffset = _kStyleIndex << 2;
  static const int _kStrokeWidthOffset = _kStrokeWidthIndex << 2;
  static const int _kStrokeCapOffset = _kStrokeCapIndex << 2;
928 929
  static const int _kStrokeJoinOffset = _kStrokeJoinIndex << 2;
  static const int _kStrokeMiterLimitOffset = _kStrokeMiterLimitIndex << 2;
930 931 932
  static const int _kFilterQualityOffset = _kFilterQualityIndex << 2;
  static const int _kColorFilterOffset = _kColorFilterIndex << 2;
  static const int _kColorFilterColorOffset = _kColorFilterColorIndex << 2;
933
  static const int _kColorFilterBlendModeOffset = _kColorFilterBlendModeIndex << 2;
934 935 936
  static const int _kMaskFilterOffset = _kMaskFilterIndex << 2;
  static const int _kMaskFilterBlurStyleOffset = _kMaskFilterBlurStyleIndex << 2;
  static const int _kMaskFilterSigmaOffset = _kMaskFilterSigmaIndex << 2;
937
  // If you add more fields, remember to update _kDataByteCount.
938
  static const int _kDataByteCount = 75;
939 940 941

  // Binary format must match the deserialization code in paint.cc.
  List<dynamic> _objects;
942 943
  static const int _kShaderIndex = 0;
  static const int _kObjectCount = 1; // Must be one larger than the largest index.
944 945 946 947

  /// Whether to apply anti-aliasing to lines and images drawn on the
  /// canvas.
  ///
948 949 950 951 952 953 954 955 956 957 958
  /// 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);
  }

959
  // Must be kept in sync with the default in paint.cc.
960
  static const int _kColorDefault = 0xFF000000;
961 962 963

  /// The color to use when stroking or filling a shape.
  ///
964
  /// Defaults to opaque black.
965 966 967 968 969 970 971 972 973
  ///
  /// 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].
974 975 976 977 978 979 980 981 982 983
  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);
  }

984
  // Must be kept in sync with the default in paint.cc.
985
  static final int _kBlendModeDefault = BlendMode.srcOver.index;
986

987
  /// A blend mode to apply when a shape is drawn or a layer is composited.
988 989 990 991 992 993 994 995 996
  ///
  /// 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.
  ///
997
  /// Defaults to [BlendMode.srcOver].
998 999 1000 1001 1002 1003
  ///
  /// 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].
1004 1005 1006
  BlendMode get blendMode {
    final int encoded = _data.getInt32(_kBlendModeOffset, _kFakeHostEndian);
    return BlendMode.values[encoded ^ _kBlendModeDefault];
1007
  }
1008
  set blendMode(BlendMode value) {
1009
    assert(value != null);
1010 1011
    final int encoded = value.index ^ _kBlendModeDefault;
    _data.setInt32(_kBlendModeOffset, encoded, _kFakeHostEndian);
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
  }

  /// 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
1027 1028
  /// [PaintingStyle.stroke]. The width is given in logical pixels measured in
  /// the direction orthogonal to the direction of the path.
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
  ///
  /// 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
1041
  /// [style] is set to [PaintingStyle.stroke].
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
  ///
  /// 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);
  }
1052

1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
  /// 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);
  }

1091 1092 1093 1094
  /// 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.
1095
  MaskFilter get maskFilter {
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
    switch (_data.getInt32(_kMaskFilterOffset, _kFakeHostEndian)) {
      case MaskFilter._TypeNone:
        return null;
      case MaskFilter._TypeBlur:
        return new MaskFilter.blur(
          BlurStyle.values[_data.getInt32(_kMaskFilterBlurStyleOffset, _kFakeHostEndian)],
          _data.getFloat32(_kMaskFilterSigmaOffset, _kFakeHostEndian),
        );
    }
    return null;
1106 1107
  }
  set maskFilter(MaskFilter value) {
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
    if (value == null) {
      _data.setInt32(_kMaskFilterOffset, MaskFilter._TypeNone, _kFakeHostEndian);
      _data.setInt32(_kMaskFilterBlurStyleOffset, 0, _kFakeHostEndian);
      _data.setFloat32(_kMaskFilterSigmaOffset, 0.0, _kFakeHostEndian);
    } else {
      // For now we only support one kind of MaskFilter, so we don't need to
      // check what the type is if it's not null.
      _data.setInt32(_kMaskFilterOffset, MaskFilter._TypeBlur, _kFakeHostEndian);
      _data.setInt32(_kMaskFilterBlurStyleOffset, value._style.index, _kFakeHostEndian);
      _data.setFloat32(_kMaskFilterSigmaOffset, value._sigma, _kFakeHostEndian);
    }
1119
  }
1120 1121 1122 1123

  /// 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].
1124 1125
  ///
  /// Defaults to [FilterQuality.none].
1126
  // TODO(ianh): verify that the image drawing methods actually respect this
1127 1128 1129 1130 1131 1132 1133 1134
  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);
  }
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145

  /// 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.
1146 1147 1148 1149 1150 1151 1152 1153 1154
  Shader get shader {
    if (_objects == null)
      return null;
    return _objects[_kShaderIndex];
  }
  set shader(Shader value) {
    _objects ??= new List<dynamic>(_kObjectCount);
    _objects[_kShaderIndex] = value;
  }
1155 1156 1157 1158 1159 1160 1161

  /// 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].
1162 1163 1164 1165 1166 1167
  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)),
1168
      BlendMode.values[_data.getInt32(_kColorFilterBlendModeOffset, _kFakeHostEndian)]
1169 1170 1171 1172 1173 1174
    );
  }
  set colorFilter(ColorFilter value) {
    if (value == null) {
      _data.setInt32(_kColorFilterOffset, 0, _kFakeHostEndian);
      _data.setInt32(_kColorFilterColorOffset, 0, _kFakeHostEndian);
1175
      _data.setInt32(_kColorFilterBlendModeOffset, 0, _kFakeHostEndian);
1176 1177
    } else {
      assert(value._color != null);
1178
      assert(value._blendMode != null);
1179 1180
      _data.setInt32(_kColorFilterOffset, 1, _kFakeHostEndian);
      _data.setInt32(_kColorFilterColorOffset, value._color.value, _kFakeHostEndian);
1181
      _data.setInt32(_kColorFilterBlendModeOffset, value._blendMode.index, _kFakeHostEndian);
1182 1183 1184 1185 1186
    }
  }

  @override
  String toString() {
1187
    final StringBuffer result = new StringBuffer();
1188 1189
    String semicolon = '';
    result.write('Paint(');
1190
    if (style == PaintingStyle.stroke) {
1191
      result.write('$style');
1192
      if (strokeWidth != 0.0)
1193
        result.write(' ${strokeWidth.toStringAsFixed(1)}');
1194 1195
      else
        result.write(' hairline');
1196
      if (strokeCap != StrokeCap.butt)
1197
        result.write(' $strokeCap');
1198 1199 1200 1201 1202 1203
      if (strokeJoin == StrokeJoin.miter) {
        if (strokeMiterLimit != _kStrokeMiterLimitDefault)
          result.write(' $strokeJoin up to ${strokeMiterLimit.toStringAsFixed(1)}');
      } else {
        result.write(' $strokeJoin');
      }
1204 1205 1206 1207 1208 1209
      semicolon = '; ';
    }
    if (isAntiAlias != true) {
      result.write('${semicolon}antialias off');
      semicolon = '; ';
    }
1210
    if (color != const Color(_kColorDefault)) {
1211 1212 1213 1214 1215 1216
      if (color != null)
        result.write('$semicolon$color');
      else
        result.write('${semicolon}no color');
      semicolon = '; ';
    }
1217
    if (blendMode.index != _kBlendModeDefault) {
1218
      result.write('$semicolon$blendMode');
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228
      semicolon = '; ';
    }
    if (colorFilter != null) {
      result.write('${semicolon}colorFilter: $colorFilter');
      semicolon = '; ';
    }
    if (maskFilter != null) {
      result.write('${semicolon}maskFilter: $maskFilter');
      semicolon = '; ';
    }
1229
    if (filterQuality != FilterQuality.none) {
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
      result.write('${semicolon}filterQuality: $filterQuality');
      semicolon = '; ';
    }
    if (shader != null)
      result.write('${semicolon}shader: $shader');
    result.write(')');
    return result.toString();
  }
}

1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
/// The format in which image bytes should be returned when using
/// [Image.toByteData].
enum ImageByteFormat {
  /// Raw RGBA format.
  ///
  /// Unencoded bytes, in RGBA row-primary form, 8 bits per channel.
  rawRgba,

  /// Raw unmodified format.
  ///
  /// Unencoded bytes, in the image's existing format. For example, a grayscale
  /// image may use a single 8-bit channel for each pixel.
  rawUnmodified,

  /// PNG format.
  ///
  /// A loss-less compression format for images. This format is well suited for
  /// images with hard edges, such as screenshots or sprites, and images with
  /// text. Transparency is supported. The PNG format supports images up to
  /// 2,147,483,647 pixels in either dimension, though in practice available
  /// memory provides a more immediate limitation on maximum image size.
  ///
  /// PNG images normally use the `.png` file extension and the `image/png` MIME
  /// type.
  ///
  /// See also:
  ///
  ///  * <https://en.wikipedia.org/wiki/Portable_Network_Graphics>, the Wikipedia page on PNG.
  ///  * <https://tools.ietf.org/rfc/rfc2083.txt>, the PNG standard.
  png,
}

I
Ian Hickson 已提交
1272 1273
/// Opaque handle to raw decoded image data (pixels).
///
1274
/// To obtain an [Image] object, use [instantiateImageCodec].
I
Ian Hickson 已提交
1275
///
1276
/// To draw an [Image], use one of the methods on the [Canvas] class, such as
I
Ian Hickson 已提交
1277
/// [Canvas.drawImage].
1278 1279 1280 1281 1282 1283 1284
class Image extends NativeFieldWrapperClass2 {
  /// This class is created by the engine, and should not be instantiated
  /// or extended directly.
  ///
  /// To obtain an [Image] object, use [instantiateImageCodec].
  Image._();

I
Ian Hickson 已提交
1285
  /// The number of image pixels along the image's horizontal axis.
1286
  int get width native 'Image_width';
I
Ian Hickson 已提交
1287 1288

  /// The number of image pixels along the image's vertical axis.
1289
  int get height native 'Image_height';
1290

1291 1292
  /// Converts the [Image] object into a byte array.
  ///
1293 1294
  /// The [format] argument specifies the format in which the bytes will be
  /// returned.
1295
  ///
1296 1297
  /// Returns a future that completes with the binary image data or an error
  /// if encoding fails.
1298
  Future<ByteData> toByteData({ImageByteFormat format: ImageByteFormat.rawRgba}) {
1299
    return _futurize((_Callback<ByteData> callback) {
1300
      return _toByteData(format.index, (Uint8List encoded) {
1301
        callback(encoded?.buffer?.asByteData());
1302 1303 1304 1305 1306
      });
    });
  }

  /// Returns an error message on failure, null on success.
1307
  String _toByteData(int format, _Callback<Uint8List> callback) native 'Image_toByteData';
1308

I
Ian Hickson 已提交
1309 1310
  /// Release the resources used by this object. The object is no longer usable
  /// after this method is called.
1311
  void dispose() native 'Image_dispose';
A
Adam Barth 已提交
1312

1313
  @override
A
Adam Barth 已提交
1314
  String toString() => '[$width\u00D7$height]';
1315 1316
}

1317
/// Callback signature for [decodeImageFromList].
I
Ian Hickson 已提交
1318
typedef void ImageDecoderCallback(Image result);
1319

1320
/// Information for a single frame of an animation.
1321
///
1322 1323
/// To obtain an instance of the [FrameInfo] interface, see
/// [Codec.getNextFrame].
1324 1325 1326 1327 1328 1329 1330 1331
class FrameInfo extends NativeFieldWrapperClass2 {
  /// This class is created by the engine, and should not be instantiated
  /// or extended directly.
  ///
  /// To obtain an instance of the [FrameInfo] interface, see
  /// [Codec.getNextFrame].
  FrameInfo._();

1332
  /// The duration this frame should be shown.
1333
  Duration get duration => new Duration(milliseconds: _durationMillis);
1334
  int get _durationMillis native 'FrameInfo_durationMillis';
1335

1336 1337
  /// The [Image] object for this frame.
  Image get image native 'FrameInfo_image';
1338 1339 1340
}

/// A handle to an image codec.
1341 1342 1343 1344 1345 1346 1347 1348
class Codec extends NativeFieldWrapperClass2 {
  /// This class is created by the engine, and should not be instantiated
  /// or extended directly.
  ///
  /// To obtain an instance of the [Codec] interface, see
  /// [instantiateImageCodec].
  Codec._();

1349
  /// Number of frames in this image.
1350
  int get frameCount native 'Codec_frameCount';
1351 1352 1353 1354 1355

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

1358
  /// Fetches the next animation frame.
1359 1360
  ///
  /// Wraps back to the first frame after returning the last frame.
1361
  ///
1362 1363 1364 1365 1366
  /// The returned future can complete with an error if the decoding has failed.
  Future<FrameInfo> getNextFrame() {
    return _futurize(_getNextFrame);
  }

1367
  /// Returns an error message on failure, null on success.
1368
  String _getNextFrame(_Callback<FrameInfo> callback) native 'Codec_getNextFrame';
1369 1370 1371

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

1375
/// Instantiates an image codec [Codec] object.
1376
///
1377 1378 1379
/// [list] is the binary image data (e.g a PNG or GIF binary data).
/// The data can be for either static or animated images.
///
1380 1381
/// The following image formats are supported: {@macro flutter.dart:ui.imageFormats}
///
1382 1383 1384 1385 1386 1387 1388
/// 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)
  );
}
1389

1390
/// Instantiates a [Codec] object for an image binary data.
1391 1392
///
/// Returns an error message if the instantiation has failed, null otherwise.
1393
String _instantiateImageCodec(Uint8List list, _Callback<Codec> callback)
1394
  native 'instantiateImageCodec';
1395

1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
/// 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);
}
1409

1410 1411 1412 1413
/// 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 已提交
1414 1415
enum PathFillType {
  /// The interior is defined by a non-zero sum of signed edge crossings.
1416 1417 1418 1419 1420 1421 1422 1423
  ///
  /// 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 已提交
1424 1425

  /// The interior is defined by an odd number of edge crossings.
1426 1427 1428 1429 1430
  ///
  /// 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 已提交
1431 1432 1433
  evenOdd,
}

1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465
/// Strategies for combining paths.
/// 
/// See also:
/// 
/// * [Path.combine], which uses this enum to decide how to combine two paths.
// Must be kept in sync with SkPathOp
enum PathOperation {
  /// Subtract the second path from the first path.
  ///
  /// For example, if the two paths are overlapping circles of equal diameter
  /// but differing centers, the result would be a crescent portion of the 
  /// first circle that was not overlapped by the second circle.
  ///
  /// See also:
  ///
  ///  * [reverseDifference], which is the same but subtracting the first path
  ///    from the second.
  difference,
  /// Create a new path that is the intersection of the two paths, leaving the
  /// overlapping pieces of the path.
  /// 
  /// For example, if the two paths are overlapping circles of equal diameter
  /// but differing centers, the result would be only the overlapping portion
  /// of the two circles.
  /// 
  /// See also:
  ///  * [xor], which is the inverse of this operation
  intersect,
  /// Create a new path that is the union (inclusive-or) of the two paths.
  /// 
  /// For example, if the two paths are overlapping circles of equal diameter
  /// but differing centers, the result would be a figure-eight like shape 
G
Greg Spencer 已提交
1466
  /// matching the outer boundaries of both circles.
1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
  union,
  /// Create a new path that is the exclusive-or of the two paths, leaving 
  /// everything but the overlapping pieces of the path.
  /// 
  /// For example, if the two paths are overlapping circles of equal diameter
  /// but differing centers, the figure-eight like shape less the overlapping parts
  /// 
  /// See also:
  ///  * [intersect], which is the inverse of this operation
  xor,
  /// Subtract the first path from the second path.
  ///
  /// For example, if the two paths are overlapping circles of equal diameter
  /// but differing centers, the result would be a crescent portion of the 
  /// second circle that was not overlapped by the first circle.
  ///
  /// See also:
  ///
  ///  * [difference], which is the same but subtracting the second path
G
Greg Spencer 已提交
1486
  ///    from the first.
1487 1488 1489
  reverseDifference,
}

A
Adam Barth 已提交
1490 1491
/// A complex, one-dimensional subset of a plane.
///
H
Hixie 已提交
1492
/// A path consists of a number of subpaths, and a _current point_.
H
Hixie 已提交
1493
///
H
Hixie 已提交
1494 1495 1496 1497 1498
/// 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
1499
/// plane based on the current [fillType].
H
Hixie 已提交
1500 1501 1502 1503 1504 1505
///
/// 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 已提交
1506
/// used to create clip regions using [Canvas.clipPath].
A
Adam Barth 已提交
1507
class Path extends NativeFieldWrapperClass2 {
H
Hixie 已提交
1508
  /// Create a new empty [Path] object.
A
Adam Barth 已提交
1509
  Path() { _constructor(); }
1510
  void _constructor() native 'Path_constructor';
A
Adam Barth 已提交
1511

1512 1513 1514 1515 1516 1517 1518 1519 1520
  /// Creates a copy of another [Path].
  /// 
  /// This copy is fast and does not require additional memory unless either 
  /// the `source` path or the path returned by this constructor are modified.
  factory Path.from(Path source) {
    return source._clone();
  }
  Path _clone() native 'Path_clone';

A
Adam Barth 已提交
1521
  /// Determines how the interior of this path is calculated.
1522 1523
  ///
  /// Defaults to the non-zero winding rule, [PathFillType.nonZero].
A
Adam Barth 已提交
1524
  PathFillType get fillType => PathFillType.values[_getFillType()];
1525
  set fillType(PathFillType value) => _setFillType(value.index);
A
Adam Barth 已提交
1526

1527 1528
  int _getFillType() native 'Path_getFillType';
  void _setFillType(int fillType) native 'Path_setFillType';
A
Adam Barth 已提交
1529

H
Hixie 已提交
1530
  /// Starts a new subpath at the given coordinate.
1531
  void moveTo(double x, double y) native 'Path_moveTo';
H
Hixie 已提交
1532 1533

  /// Starts a new subpath at the given offset from the current point.
1534
  void relativeMoveTo(double dx, double dy) native 'Path_relativeMoveTo';
H
Hixie 已提交
1535 1536 1537

  /// Adds a straight line segment from the current point to the given
  /// point.
1538
  void lineTo(double x, double y) native 'Path_lineTo';
H
Hixie 已提交
1539 1540 1541

  /// Adds a straight line segment from the current point to the point
  /// at the given offset from the current point.
1542
  void relativeLineTo(double dx, double dy) native 'Path_relativeLineTo';
H
Hixie 已提交
1543 1544 1545 1546

  /// Adds a quadratic bezier segment that curves from the current
  /// point to the given point (x2,y2), using the control point
  /// (x1,y1).
1547
  void quadraticBezierTo(double x1, double y1, double x2, double y2) native 'Path_quadraticBezierTo';
H
Hixie 已提交
1548 1549 1550 1551 1552

  /// 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.
1553
  void relativeQuadraticBezierTo(double x1, double y1, double x2, double y2) native 'Path_relativeQuadraticBezierTo';
H
Hixie 已提交
1554 1555 1556 1557

  /// 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).
1558
  void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) native 'Path_cubicTo';
H
Hixie 已提交
1559

G
Greg Spencer 已提交
1560
  /// Adds a cubic bezier segment that curves from the current point
H
Hixie 已提交
1561 1562 1563
  /// 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.
1564
  void relativeCubicTo(double x1, double y1, double x2, double y2, double x3, double y3) native 'Path_relativeCubicTo';
H
Hixie 已提交
1565 1566 1567 1568 1569 1570

  /// 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.
1571
  void conicTo(double x1, double y1, double x2, double y2, double w) native 'Path_conicTo';
H
Hixie 已提交
1572 1573 1574 1575 1576 1577 1578

  /// 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.
1579
  void relativeConicTo(double x1, double y1, double x2, double y2, double w) native 'Path_relativeConicTo';
H
Hixie 已提交
1580

1581
  /// If the `forceMoveTo` argument is false, adds a straight line
H
Hixie 已提交
1582 1583
  /// segment and an arc segment.
  ///
1584
  /// If the `forceMoveTo` argument is true, starts a new subpath
H
Hixie 已提交
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594
  /// 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.
  ///
1595
  /// The line segment added if `forceMoveTo` is false starts at the
H
Hixie 已提交
1596
  /// current point and ends at the start of the arc.
1597
  void arcTo(Rect rect, double startAngle, double sweepAngle, bool forceMoveTo) {
1598
    assert(_rectIsValid(rect));
1599 1600 1601
    _arcTo(rect.left, rect.top, rect.right, rect.bottom, startAngle, sweepAngle, forceMoveTo);
  }
  void _arcTo(double left, double top, double right, double bottom,
1602
              double startAngle, double sweepAngle, bool forceMoveTo) native 'Path_arcTo';
H
Hixie 已提交
1603

1604 1605
  /// Appends up to four conic curves weighted to describe an oval of `radius`
  /// and rotated by `rotation`.
1606 1607
  ///
  /// The first curve begins from the last point in the path and the last ends
1608 1609
  /// at `arcEnd`. The curves follow a path in a direction determined by
  /// `clockwise` and `largeArc` in such a way that the sweep angle
1610 1611 1612
  /// is always less than 360 degrees.
  ///
  /// A simple line is appended if either either radii are zero or the last
1613
  /// point in the path is `arcEnd`. The radii are scaled to fit the last path
1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628
  /// 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,
1629
                   bool clockwise) native 'Path_arcToPoint';
1630 1631


1632 1633
  /// Appends up to four conic curves weighted to describe an oval of `radius`
  /// and rotated by `rotation`.
1634 1635 1636 1637
  ///
  /// The last path point is described by (px, py).
  ///
  /// The first curve begins from the last point in the path and the last ends
1638 1639
  /// at `arcEndDelta.dx + px` and `arcEndDelta.dy + py`. The curves follow a
  /// path in a direction determined by `clockwise` and `largeArc`
1640 1641 1642
  /// 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
1643
  /// `arcEndDelta.dx` and `arcEndDelta.dy` are zero. The radii are scaled to
1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
  /// 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)
1660
                           native 'Path_relativeArcToPoint';
1661

H
Hixie 已提交
1662 1663
  /// Adds a new subpath that consists of four lines that outline the
  /// given rectangle.
1664
  void addRect(Rect rect) {
1665
    assert(_rectIsValid(rect));
1666 1667
    _addRect(rect.left, rect.top, rect.right, rect.bottom);
  }
1668
  void _addRect(double left, double top, double right, double bottom) native 'Path_addRect';
H
Hixie 已提交
1669 1670 1671

  /// Adds a new subpath that consists of a curve that forms the
  /// ellipse that fills the given rectangle.
1672 1673
  ///
  /// To add a circle, pass an appropriate rectangle as `oval`. [Rect.fromCircle]
D
Dan Field 已提交
1674
  /// can be used to easily describe the circle's center [Offset] and radius.
1675
  void addOval(Rect oval) {
1676
    assert(_rectIsValid(oval));
1677 1678
    _addOval(oval.left, oval.top, oval.right, oval.bottom);
  }
1679
  void _addOval(double left, double top, double right, double bottom) native 'Path_addOval';
H
Hixie 已提交
1680 1681 1682 1683 1684 1685 1686 1687 1688

  /// 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.
1689
  void addArc(Rect oval, double startAngle, double sweepAngle) {
1690
    assert(_rectIsValid(oval));
1691 1692 1693
    _addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);
  }
  void _addArc(double left, double top, double right, double bottom,
1694
               double startAngle, double sweepAngle) native 'Path_addArc';
H
Hixie 已提交
1695

A
Adam Barth 已提交
1696
  /// Adds a new subpath with a sequence of line segments that connect the given
I
Ian Hickson 已提交
1697 1698 1699 1700 1701 1702 1703
  /// 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) {
1704
    assert(points != null);
A
Adam Barth 已提交
1705 1706
    _addPolygon(_encodePointList(points), close);
  }
1707
  void _addPolygon(Float32List points, bool close) native 'Path_addPolygon';
A
Adam Barth 已提交
1708

H
Hixie 已提交
1709 1710 1711
  /// Adds a new subpath that consists of the straight lines and
  /// curves needed to form the rounded rectangle described by the
  /// argument.
1712
  void addRRect(RRect rrect) {
1713
    assert(_rrectIsValid(rrect));
1714 1715
    _addRRect(rrect._value);
  }
1716
  void _addRRect(Float32List rrect) native 'Path_addRRect';
H
Hixie 已提交
1717

1718 1719 1720 1721 1722 1723 1724
  /// Adds a new subpath that consists of the given `path` offset by the given
  /// `offset`.
  /// 
  /// If `matrix4` is specified, the path will be transformed by this matrix
  /// after the matrix is translated by the given offset. The matrix is a 4x4
  /// matrix stored in column major order.
  void addPath(Path path, Offset offset, {Float64List matrix4}) {
1725
    assert(path != null); // path is checked on the engine side
1726
    assert(_offsetIsValid(offset));
1727 1728 1729 1730 1731 1732
    if (matrix4 != null) {
      assert(_matrix4IsValid(matrix4));
      _addPathWithMatrix(path, offset.dx, offset.dy, matrix4);
    } else {
      _addPath(path, offset.dx, offset.dy);
    }
1733
  }
1734
  void _addPath(Path path, double dx, double dy) native 'Path_addPath';
1735 1736
  void _addPathWithMatrix(Path path, double dx, double dy, Float64List matrix) native 'Path_addPathWithMatrix';
  
A
Adam Barth 已提交
1737 1738
  /// Adds the given path to this path by extending the current segment of this
  /// path with the the first segment of the given path.
1739 1740 1741 1742 1743
  /// 
  /// If `matrix4` is specified, the path will be transformed by this matrix
  /// after the matrix is translated by the given `offset`.  The matrix is a 4x4
  /// matrix stored in column major order.
  void extendWithPath(Path path, Offset offset, {Float64List matrix4}) {
1744
    assert(path != null); // path is checked on the engine side
1745
    assert(_offsetIsValid(offset));
1746 1747 1748 1749 1750 1751
    if (matrix4 != null) {
      assert(_matrix4IsValid(matrix4));
      _extendWithPathAndMatrix(path, offset.dx, offset.dy, matrix4);
    } else {
      _extendWithPath(path, offset.dx, offset.dy);
    }
1752
  }
1753
  void _extendWithPath(Path path, double dx, double dy) native 'Path_extendWithPath';
1754
  void _extendWithPathAndMatrix(Path path, double dx, double dy, Float64List matrix) native 'Path_extendWithPathAndMatrix';
A
Adam Barth 已提交
1755

H
Hixie 已提交
1756 1757
  /// Closes the last subpath, as if a straight line had been drawn
  /// from the current point to the first point of the subpath.
1758
  void close() native 'Path_close';
H
Hixie 已提交
1759 1760 1761 1762

  /// 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.
1763
  void reset() native 'Path_reset';
H
Hixie 已提交
1764

I
Ian Hickson 已提交
1765 1766 1767 1768 1769
  /// 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.
1770 1771
  ///
  /// Returns true if the point is in the path, and false otherwise.
1772
  bool contains(Offset point) {
1773
    assert(_offsetIsValid(point));
1774 1775
    return _contains(point.dx, point.dy);
  }
1776
  bool _contains(double x, double y) native 'Path_contains';
1777

H
Hixie 已提交
1778 1779
  /// Returns a copy of the path with all the segments of every
  /// subpath translated by the given offset.
1780
  Path shift(Offset offset) {
1781
    assert(_offsetIsValid(offset));
1782 1783
    return _shift(offset.dx, offset.dy);
  }
1784
  Path _shift(double dx, double dy) native 'Path_shift';
A
Adam Barth 已提交
1785 1786 1787 1788

  /// Returns a copy of the path with all the segments of every
  /// subpath transformed by the given matrix.
  Path transform(Float64List matrix4) {
1789
    assert(_matrix4IsValid(matrix4));
A
Adam Barth 已提交
1790 1791
    return _transform(matrix4);
  }
1792
  Path _transform(Float64List matrix4) native 'Path_transform';
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 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989

  /// Computes the bounding rectangle for this path.
  Rect getBounds() {
    final Float32List rect = _getBounds();
    return new Rect.fromLTRB(rect[0], rect[1], rect[2], rect[3]);
  }
  Float32List _getBounds() native 'Path_getBounds';

  /// Combines the two paths according to the manner specified by the given 
  /// `operation`.
  /// 
  /// The resulting path will be constructed from non-overlapping contours. The
  /// curve order is reduced where possible so that cubics may be turned into
  /// quadratics, and quadratics maybe turned into lines.
  static Path combine(PathOperation operation, Path path1, Path path2) {
    assert(path1 != null);
    assert(path2 != null);
    final Path path = new Path();
    if (path._op(path1, path2, operation.index)) {
      return path;
    } 
    throw new StateError('Path.combine() failed.  This may be due an invalid path; in particular, check for NaN values.');
  }
  bool _op(Path path1, Path path2, int operation) native 'Path_op';

  /// Creates a [PathMetrics] object for this path.
  /// 
  /// If `forceClosed` is set to true, the contours of the path will be measured
  /// as if they had been closed, even if they were not explicitly closed.
  PathMetrics computeMetrics({bool forceClosed: false}) {
    return new PathMetrics._(this, forceClosed);
  }
}

/// The geometric description of a tangent: the angle at a point.
/// 
/// See also:
///  * [PathMetric.getTangentForOffset], which returns the tangent of an offset along a path.
class Tangent {
  /// Creates a [Tangent] with the given values.
  /// 
  /// The arguments must not be null.
  const Tangent(this.position, this.vector) 
    : assert(position != null), 
      assert(vector != null);

  /// Creates a [Tangent] based on the angle rather than the vector.
  /// 
  /// The [vector] is computed to be the unit vector at the given angle, interpreted
  /// as clockwise radians from the x axis.
  factory Tangent.fromAngle(Offset position, double angle) {
    return new Tangent(position, new Offset(math.cos(angle), math.sin(angle)));
  }

  /// Position of the tangent.
  /// 
  /// When used with [PathMetric.getTangentForOffset], this represents the precise
  /// position that the given offset along the path corresponds to.
  final Offset position;

  /// The vector of the curve at [position].
  /// 
  /// When used with [PathMetric.getTangentForOffset], this is the vector of the
  /// curve that is at the given offset along the path (i.e. the direction of the
  /// curve at [position]).
  final Offset vector;

  /// The direction of the curve at [position].
  /// 
  /// When used with [PathMetric.getTangentForOffset], this is the angle of the
  /// curve that is the given offset along the path (i.e. the direction of the
  /// curve at [position]).
  /// 
  /// This value is in radians, with 0.0 meaning pointing along the x axis in 
  /// the positive x-axis direction, positive numbers pointing downward toward
  /// the negative y-axis, i.e. in a clockwise direction, and negative numbers
  /// pointing upward toward the positive y-axis, i.e. in a counter-clockwise 
  /// direction.
  // flip the sign to be consistent with [Path.arcTo]'s `sweepAngle`
  double get angle => -math.atan2(vector.dy, vector.dx);
}

/// An iterable collection of [PathMetric] objects describing a [Path].
/// 
/// A [PathMetrics] object is created by using the [Path.computeMetrics] method,
/// and represents the path as it stood at the time of the call. Subsequent 
/// modifications of the path do not affect the [PathMetrics] object.
/// 
/// Each path metric corresponds to a segment, or contour, of a path.
/// 
/// For example, a path consisting of a [Path.lineTo], a [Path.moveTo], and 
/// another [Path.lineTo] will contain two contours and thus be represented by 
/// two [PathMetric] objects.
///
/// When iterating across a [PathMetrics]' contours, the [PathMetric] objects are only
/// valid until the next one is obtained.
class PathMetrics extends collection.IterableBase<PathMetric> {
  PathMetrics._(Path path, bool forceClosed) :
    _iterator = new PathMetricIterator._(new PathMetric._(path, forceClosed));
    
  final Iterator<PathMetric> _iterator;

  @override
  Iterator<PathMetric> get iterator => _iterator;
}

/// Tracks iteration from one segment of a path to the next for measurement.
class PathMetricIterator implements Iterator<PathMetric> {
  PathMetricIterator._(this._pathMetric);

  PathMetric _pathMetric;
  bool _firstTime = true;

  @override
  PathMetric get current => _firstTime ? null : _pathMetric;

  @override
  bool moveNext() {
    // PathMetric isn't a normal iterable - it's already initialized to its
    // first Path.  Should only call _moveNext when done with the first one. 
    if (_firstTime == true) {
      _firstTime = false;
      return true;
    } else if (_pathMetric?._moveNext() == true) {
      return true;
    } 
    _pathMetric = null;
    return false;
  }
}

/// Utilities for measuring a [Path] and extracting subpaths.
/// 
/// Iterate over the object returned by [Path.computeMetrics] to obtain 
/// [PathMetric] objects.
///
/// Once created, metrics will only be valid while the iterator is at the given
/// contour. When the next contour's [PathMetric] is obtained, this object 
/// becomes invalid.
class PathMetric extends NativeFieldWrapperClass2 {
  /// Create a new empty [Path] object.
  PathMetric._(Path path, bool forceClosed) { _constructor(path, forceClosed); }
  void _constructor(Path path, bool forceClosed) native 'PathMeasure_constructor';

  /// Return the total length of the current contour.
  double get length native 'PathMeasure_getLength';

  /// Computes the position of hte current contour at the given offset, and the
  /// angle of the path at that point.
  /// 
  /// For example, calling this method with a distance of 1.41 for a line from 
  /// 0.0,0.0 to 2.0,2.0 would give a point 1.0,1.0 and the angle 45 degrees
  /// (but in radians).
  /// 
  /// Returns null if the contour has zero [length].
  /// 
  /// The distance is clamped to the [length] of the current contour.
  Tangent getTangentForOffset(double distance) {
    final Float32List posTan = _getPosTan(distance);
    // first entry == 0 indicates that Skia returned false
    if (posTan[0] == 0.0) {
      return null;
    } else {
      return new Tangent(
        new Offset(posTan[1], posTan[2]), 
        new Offset(posTan[3], posTan[4]) 
      );
    }
  }
  Float32List _getPosTan(double distance) native 'PathMeasure_getPosTan';

  /// Given a start and stop distance, return the intervening segment(s).
  /// 
  /// `start` and `end` are pinned to legal values (0..[length])
  /// Returns null if the segment is 0 length or `start` > `stop`.
  /// Begin the segment with a moveTo if `startWithMoveTo` is true.
  Path extractPath(double start, double end, {bool startWithMoveTo: true}) native 'PathMeasure_getSegment';

  /// Whether the contour is closed.
  /// 
  /// Returns true if the contour ends with a call to [Path.close] (which may
  /// have been implied when using [Path.addRect]) or if `forceClosed` was 
  /// specified as true in the call to [Path.computeMetrics].  Returns false
  /// otherwise.
  bool get isClosed native 'PathMeasure_isClosed';

  // Move to the next contour in the path.
  //
  // A path can have a next contour if [Path.moveTo] was called after drawing began.
  // Return true if one exists, or false.
  // 
  // This is not exactly congruent with a regular [Iterator.moveNext].
  // Typically, [Iterator.moveNext] should be called before accessing the
  // [Iterator.current]. In this case, the [PathMetric] is valid before 
  // calling `_moveNext` - `_moveNext` should be called after the first
  // iteration is done instead of before.
  bool _moveNext() native 'PathMeasure_nextContour';
A
Adam Barth 已提交
1990 1991
}

H
Hixie 已提交
1992
/// Styles to use for blurs in [MaskFilter] objects.
1993
// These enum values must be kept in sync with SkBlurStyle.
1994
enum BlurStyle {
H
Hixie 已提交
1995 1996
  // These mirror SkBlurStyle and must be kept in sync.

1997
  /// Fuzzy inside and outside. This is useful for painting shadows that are
1998
  /// offset from the shape that ostensibly is casting the shadow.
A
Adam Barth 已提交
1999 2000
  normal,

2001 2002 2003
  /// 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 已提交
2004 2005
  solid,

2006 2007 2008
  /// 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 已提交
2009 2010
  outer,

2011 2012
  /// Fuzzy inside, nothing outside. This can make shapes appear to be lit from
  /// within.
A
Adam Barth 已提交
2013
  inner,
2014 2015
}

2016 2017 2018 2019 2020
/// 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.
2021
class MaskFilter {
2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032
  /// 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.
  ///
2033
  /// A blur is an expensive operation and should therefore be used sparingly.
2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060
  ///
  /// The arguments must not be null.
  ///
  /// See also:
  ///
  ///  * [Canvas.drawShadow], which is a more efficient way to draw shadows.
  const MaskFilter.blur(
    this._style,
    this._sigma,
  ) : assert(_style != null),
      assert(_sigma != null);

  final BlurStyle _style;
  final double _sigma;

  // The type of MaskFilter class to create for Skia.
  // These constants must be kept in sync with MaskFilterType in paint.cc.
  static const int _TypeNone = 0; // null
  static const int _TypeBlur = 1; // SkBlurMaskFilter

  @override
  bool operator ==(dynamic other) {
    if (other is! MaskFilter)
      return false;
    final MaskFilter typedOther = other;
    return _style == typedOther._style &&
           _sigma == typedOther._sigma;
2061
  }
2062 2063 2064 2065 2066

  @override
  int get hashCode => hashValues(_style, _sigma);

  @override
2067
  String toString() => 'MaskFilter.blur($_style, ${_sigma.toStringAsFixed(1)})';
2068 2069
}

2070 2071 2072 2073 2074
/// 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 已提交
2075
///
2076 2077
/// Instances of this class are used with [Paint.colorFilter] on [Paint]
/// objects.
2078
class ColorFilter {
2079
  /// Creates a color filter that applies the blend mode given as the second
2080 2081 2082 2083
  /// 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
2084
  /// to the [Paint.blendMode], using the output of this filter as the source
2085
  /// and the background as the destination.
I
Ian Hickson 已提交
2086
  const ColorFilter.mode(Color color, BlendMode blendMode)
2087
    : _color = color, _blendMode = blendMode;
2088 2089

  final Color _color;
2090
  final BlendMode _blendMode;
2091 2092 2093 2094 2095 2096 2097

  @override
  bool operator ==(dynamic other) {
    if (other is! ColorFilter)
      return false;
    final ColorFilter typedOther = other;
    return _color == typedOther._color &&
2098
           _blendMode == typedOther._blendMode;
2099 2100 2101
  }

  @override
2102
  int get hashCode => hashValues(_color, _blendMode);
2103 2104

  @override
2105
  String toString() => 'ColorFilter($_color, $_blendMode)';
2106
}
A
Adam Barth 已提交
2107

2108 2109
/// A filter operation to apply to a raster image.
///
2110 2111 2112 2113 2114
/// See also:
///
///  * [BackdropFilter], a widget that applies [ImageFilter] to its rendering.
///  * [SceneBuilder.pushBackdropFilter], which is the low-level API for using
///    this class.
2115
class ImageFilter extends NativeFieldWrapperClass2 {
2116
  void _constructor() native 'ImageFilter_constructor';
2117

2118
  /// Creates an image filter that applies a Gaussian blur.
2119 2120 2121 2122
  ImageFilter.blur({ double sigmaX: 0.0, double sigmaY: 0.0 }) {
    _constructor();
    _initBlur(sigmaX, sigmaY);
  }
2123
  void _initBlur(double sigmaX, double sigmaY) native 'ImageFilter_initBlur';
2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136

  /// Creates an image filter that applies a matrix transformation.
  ///
  /// For example, applying a positive scale matrix (see [new Matrix4.diagonal3])
  /// when used with [BackdropFilter] would magnify the background image.
  ImageFilter.matrix(Float64List matrix4,
                     { FilterQuality filterQuality: FilterQuality.low }) {
    if (matrix4.length != 16)
      throw new ArgumentError('"matrix4" must have 16 entries.');
    _constructor();
    _initMatrix(matrix4, filterQuality.index);
  }
  void _initMatrix(Float64List matrix4, int filterQuality) native 'ImageFilter_initMatrix';
2137 2138
}

H
Hixie 已提交
2139
/// Base class for objects such as [Gradient] and [ImageShader] which
2140
/// correspond to shaders as used by [Paint.shader].
2141 2142 2143 2144 2145
class Shader extends NativeFieldWrapperClass2 {
  /// This class is created by the engine, and should not be instantiated
  /// or extended directly.
  Shader._();
}
A
Adam Barth 已提交
2146 2147

/// Defines what happens at the edge of the gradient.
2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165
///
/// 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.
2166
// These enum values must be kept in sync with SkShader::TileMode.
A
Adam Barth 已提交
2167 2168
enum TileMode {
  /// Edge is clamped to the final color.
2169 2170 2171 2172 2173
  ///
  /// 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_radial.png)
A
Adam Barth 已提交
2174
  clamp,
2175

2176 2177 2178 2179 2180 2181 2182 2183 2184 2185
  /// 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 已提交
2186
  /// Edge is mirrored from last color to first.
2187 2188 2189 2190 2191 2192 2193 2194
  ///
  /// 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)
2195
  mirror,
A
Adam Barth 已提交
2196 2197
}

2198 2199 2200 2201 2202 2203 2204 2205
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 已提交
2206
Float32List _encodePointList(List<Offset> points) {
2207
  assert(points != null);
2208 2209 2210 2211 2212
  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 已提交
2213
    final Offset point = points[i];
2214
    assert(_offsetIsValid(point));
I
Ian Hickson 已提交
2215 2216
    result[xIndex] = point.dx;
    result[yIndex] = point.dy;
2217 2218 2219 2220
  }
  return result;
}

I
Ian Hickson 已提交
2221
Float32List _encodeTwoPoints(Offset pointA, Offset pointB) {
2222 2223
  assert(_offsetIsValid(pointA));
  assert(_offsetIsValid(pointB));
I
Ian Hickson 已提交
2224 2225 2226 2227 2228 2229 2230 2231
  final Float32List result = new Float32List(4);
  result[0] = pointA.dx;
  result[1] = pointA.dy;
  result[2] = pointB.dx;
  result[3] = pointB.dy;
  return result;
}

2232 2233
/// A shader (as used by [Paint.shader]) that renders a color gradient.
///
V
Victor Choueiri 已提交
2234 2235
/// There are several types of gradients, represented by the various constructors
/// on this class.
A
Adam Barth 已提交
2236
class Gradient extends Shader {
2237

2238
  void _constructor() native 'Gradient_constructor';
A
Adam Barth 已提交
2239

I
Ian Hickson 已提交
2240 2241 2242 2243 2244 2245 2246 2247
  /// 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`
2248 2249 2250 2251 2252
  /// 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 已提交
2253 2254 2255 2256 2257 2258 2259 2260
  ///
  /// 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, [
2261
    List<double> colorStops,
2262
    TileMode tileMode = TileMode.clamp,
2263 2264 2265
  ]) : assert(_offsetIsValid(from)),
       assert(_offsetIsValid(to)),
       assert(colors != null),
2266 2267
       assert(tileMode != null),
       super._() {
A
Adam Barth 已提交
2268
    _validateColorStops(colors, colorStops);
I
Ian Hickson 已提交
2269
    final Float32List endPointsBuffer = _encodeTwoPoints(from, to);
2270 2271 2272 2273
    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 已提交
2274
  }
2275
  void _initLinear(Float32List endPoints, Int32List colors, Float32List colorStops, int tileMode) native 'Gradient_initLinear';
A
Adam Barth 已提交
2276

2277
  /// Creates a radial gradient centered at `center` that ends at `radius`
I
Ian Hickson 已提交
2278 2279 2280 2281 2282 2283 2284 2285
  /// 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`
2286 2287 2288 2289 2290
  /// 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 已提交
2291 2292 2293 2294
  ///
  /// If `center`, `radius`, `colors`, or `tileMode` are null, or if `colors` or
  /// `colorStops` contain null values, this constructor will throw a
  /// [NoSuchMethodError].
2295 2296
  ///
  /// If `matrix4` is provided, the gradient fill will be transformed by the
2297 2298
  /// specified 4x4 matrix relative to the local coordinate system. `matrix4` must
  /// be a column-major matrix packed into a list of 16 values.
2299 2300 2301 2302 2303 2304
  Gradient.radial(
    Offset center,
    double radius,
    List<Color> colors, [
    List<double> colorStops,
    TileMode tileMode = TileMode.clamp,
2305
    Float64List matrix4
2306 2307
  ]) : assert(_offsetIsValid(center)),
       assert(colors != null),
2308
       assert(tileMode != null),
V
Victor Choueiri 已提交
2309
       assert(matrix4 == null || _matrix4IsValid(matrix4)),
2310
       super._() {
A
Adam Barth 已提交
2311
    _validateColorStops(colors, colorStops);
2312 2313 2314
    final Int32List colorsBuffer = _encodeColorList(colors);
    final Float32List colorStopsBuffer = colorStops == null ? null : new Float32List.fromList(colorStops);
    _constructor();
2315
    _initRadial(center.dx, center.dy, radius, colorsBuffer, colorStopsBuffer, tileMode.index, matrix4);
A
Adam Barth 已提交
2316
  }
2317
  void _initRadial(double centerX, double centerY, double radius, Int32List colors, Float32List colorStops, int tileMode, Float64List matrix4) native 'Gradient_initRadial';
H
Hixie 已提交
2318

V
Victor Choueiri 已提交
2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368
  /// Creates a sweep gradient centered at `center` that starts at `startAngle`
  /// and ends at `endAngle`.
  ///
  /// `startAngle` and `endAngle` should be provided in radians, with zero
  /// radians being the horizontal line to the right of the `center` and with
  /// positive angles going clockwise around 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 `startAngle` and after `endAngle` is described by the
  /// `tileMode` argument. For details, see the [TileMode] enum.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_clamp_sweep.png)
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_mirror_sweep.png)
  /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_repeated_sweep.png)
  ///
  /// If `center`, `colors`, `tileMode`, `startAngle`, or `endAngle` are null,
  /// or if `colors` or `colorStops` contain null values, this constructor will
  /// throw a [NoSuchMethodError].
  ///
  /// If `matrix4` is provided, the gradient fill will be transformed by the 
  /// specified 4x4 matrix relative to the local coordinate system. `matrix4` must
  /// be a column-major matrix packed into a list of 16 values.
  Gradient.sweep(
    Offset center,
    List<Color> colors, [
    List<double> colorStops,
    TileMode tileMode = TileMode.clamp,
    double startAngle = 0.0,
    double endAngle = math.pi * 2,
    Float64List matrix4,
  ]) : assert(_offsetIsValid(center)),
       assert(colors != null),
       assert(tileMode != null),
       assert(startAngle != null),
       assert(endAngle != null),
       assert(startAngle < endAngle),
       assert(matrix4 == null || _matrix4IsValid(matrix4)),
       super._() {
    _validateColorStops(colors, colorStops);
    final Int32List colorsBuffer = _encodeColorList(colors);
    final Float32List colorStopsBuffer = colorStops == null ? null : new Float32List.fromList(colorStops);
    _constructor();
    _initSweep(center.dx, center.dy, colorsBuffer, colorStopsBuffer, tileMode.index, startAngle, endAngle, matrix4);
  }
  void _initSweep(double centerX, double centerY, Int32List colors, Float32List colorStops, int tileMode, double startAngle, double endAngle, Float64List matrix) native 'Gradient_initSweep';

H
Hixie 已提交
2369
  static void _validateColorStops(List<Color> colors, List<double> colorStops) {
I
Ian Hickson 已提交
2370 2371
    if (colorStops == null) {
      if (colors.length != 2)
2372
        throw new ArgumentError('"colors" must have length 2 if "colorStops" is omitted.');
I
Ian Hickson 已提交
2373 2374
    } else {
      if (colors.length != colorStops.length)
2375
        throw new ArgumentError('"colors" and "colorStops" arguments must have equal length.');
I
Ian Hickson 已提交
2376
    }
H
Hixie 已提交
2377
  }
A
Adam Barth 已提交
2378 2379
}

2380
/// A shader (as used by [Paint.shader]) that tiles an image.
A
Adam Barth 已提交
2381
class ImageShader extends Shader {
2382 2383 2384 2385 2386
  /// 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.
2387 2388 2389 2390
  ImageShader(Image image, TileMode tmx, TileMode tmy, Float64List matrix4) :
    assert(image != null), // image is checked on the engine side
    assert(tmx != null),
    assert(tmy != null),
2391 2392
    assert(matrix4 != null),
    super._() {
2393
    if (matrix4.length != 16)
2394
      throw new ArgumentError('"matrix4" must have 16 entries.');
H
Hixie 已提交
2395
    _constructor();
A
Adam Barth 已提交
2396 2397
    _initWithImage(image, tmx.index, tmy.index, matrix4);
  }
2398 2399
  void _constructor() native 'ImageShader_constructor';
  void _initWithImage(Image image, int tmx, int tmy, Float64List matrix4) native 'ImageShader_initWithImage';
A
Adam Barth 已提交
2400 2401
}

2402
/// Defines how a list of points is interpreted when drawing a set of triangles.
A
Adam Barth 已提交
2403 2404
///
/// Used by [Canvas.drawVertices].
2405
// These enum values must be kept in sync with SkVertices::VertexMode.
2406
enum VertexMode {
A
Adam Barth 已提交
2407
  /// Draw each sequence of three points as the vertices of a triangle.
2408
  triangles,
A
Adam Barth 已提交
2409 2410

  /// Draw each sliding window of three points as the vertices of a triangle.
2411
  triangleStrip,
A
Adam Barth 已提交
2412 2413

  /// Draw the first point and each sliding window of two points as the vertices of a triangle.
2414 2415 2416
  triangleFan,
}

2417 2418 2419 2420
/// A set of vertex data used by [Canvas.drawVertices].
class Vertices extends NativeFieldWrapperClass2 {
  Vertices(
    VertexMode mode,
I
Ian Hickson 已提交
2421 2422 2423 2424
    List<Offset> positions, {
    List<Offset> textureCoordinates,
    List<Color> colors,
    List<int> indices,
2425 2426
  }) : assert(mode != null),
       assert(positions != null) {
2427
    if (textureCoordinates != null && textureCoordinates.length != positions.length)
2428
      throw new ArgumentError('"positions" and "textureCoordinates" lengths must match.');
2429
    if (colors != null && colors.length != positions.length)
2430
      throw new ArgumentError('"positions" and "colors" lengths must match.');
2431
    if (indices != null && indices.any((int i) => i < 0 || i >= positions.length))
2432
      throw new ArgumentError('"indices" values must be valid indices in the positions list.');
2433

2434 2435 2436 2437 2438 2439 2440 2441 2442 2443
    final Float32List encodedPositions = _encodePointList(positions);
    final Float32List encodedTextureCoordinates = (textureCoordinates != null)
      ? _encodePointList(textureCoordinates)
      : null;
    final Int32List encodedColors = colors != null
      ? _encodeColorList(colors)
      : null;
    final Int32List encodedIndices = indices != null
      ? new Int32List.fromList(indices)
      : null;
2444 2445

    _constructor();
2446 2447 2448 2449 2450 2451 2452 2453 2454
    _init(mode.index, encodedPositions, encodedTextureCoordinates, encodedColors, encodedIndices);
  }

  Vertices.raw(
    VertexMode mode,
    Float32List positions, {
    Float32List textureCoordinates,
    Int32List colors,
    Int32List indices,
2455 2456
  }) : assert(mode != null),
       assert(positions != null) {
2457 2458 2459 2460 2461 2462 2463 2464 2465
    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);
2466 2467
  }

2468
  void _constructor() native 'Vertices_constructor';
2469 2470 2471 2472 2473

  void _init(int mode,
             Float32List positions,
             Float32List textureCoordinates,
             Int32List colors,
2474
             Int32List indices) native 'Vertices_init';
2475 2476
}

A
Adam Barth 已提交
2477 2478
/// Defines how a list of points is interpreted when drawing a set of points.
///
2479
// ignore: deprecated_member_use
A
Adam Barth 已提交
2480
/// Used by [Canvas.drawPoints].
2481
// These enum values must be kept in sync with SkCanvas::PointMode.
A
Adam Barth 已提交
2482
enum PointMode {
2483 2484
  /// Draw each point separately.
  ///
I
Ian Hickson 已提交
2485
  /// If the [Paint.strokeCap] is [StrokeCap.round], then each point is drawn
2486 2487 2488 2489 2490 2491
  /// 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 已提交
2492 2493
  points,

2494 2495 2496 2497 2498 2499
  /// 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 已提交
2500 2501
  lines,

2502 2503 2504 2505
  /// Draw the entire sequence of point as one line.
  ///
  /// The lines are stroked as described by the [Paint] (ignoring
  /// [Paint.style]).
A
Adam Barth 已提交
2506 2507 2508
  polygon,
}

2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520
/// 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 已提交
2521 2522
/// An interface for recording graphical operations.
///
H
Hixie 已提交
2523 2524 2525
/// [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.
2526 2527 2528 2529
///
/// 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],
2530
/// and [transform] methods.
2531 2532 2533 2534 2535 2536 2537
///
/// 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.
2538
class Canvas extends NativeFieldWrapperClass2 {
H
Hixie 已提交
2539 2540
  /// Creates a canvas for recording graphical operations into the
  /// given picture recorder.
A
Adam Barth 已提交
2541 2542
  ///
  /// Graphical operations that affect pixels entirely outside the given
2543
  /// `cullRect` might be discarded by the implementation. However, the
A
Adam Barth 已提交
2544
  /// implementation might draw outside these bounds if, for example, a command
2545
  /// draws partially inside and outside the `cullRect`. To ensure that pixels
2546 2547
  /// outside a given region are discarded, consider using a [clipRect]. The
  /// `cullRect` is optional; by default, all operations are kept.
H
Hixie 已提交
2548 2549 2550
  ///
  /// To end the recording, call [PictureRecorder.endRecording] on the
  /// given recorder.
2551
  Canvas(PictureRecorder recorder, [ Rect cullRect ]) : assert(recorder != null) {
2552
    if (recorder.isRecording)
2553
      throw new ArgumentError('"recorder" must not already be associated with another Canvas.');
2554
    cullRect ??= Rect.largest;
2555
    _constructor(recorder, cullRect.left, cullRect.top, cullRect.right, cullRect.bottom);
2556
  }
2557 2558 2559 2560
  void _constructor(PictureRecorder recorder,
                    double left,
                    double top,
                    double right,
2561
                    double bottom) native 'Canvas_constructor';
2562

H
Hixie 已提交
2563 2564 2565
  /// Saves a copy of the current transform and clip on the save stack.
  ///
  /// Call [restore] to pop the save stack.
2566 2567 2568 2569 2570
  ///
  /// See also:
  ///
  ///  * [saveLayer], which does the same thing but additionally also groups the
  ///    commands done until the matching [restore].
2571
  void save() native 'Canvas_save';
2572

2573 2574 2575
  /// 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
2576
  /// have the given `paint`'s [Paint.colorFilter] and [Paint.blendMode]
2577
  /// applied.
H
Hixie 已提交
2578
  ///
2579 2580 2581 2582 2583 2584
  /// 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 已提交
2585
  ///
2586
  /// Call [restore] to pop the save stack and apply the paint to the group.
2587 2588 2589
  ///
  /// ## Using saveLayer with clips
  ///
G
Greg Spencer 已提交
2590
  /// When a rectangular clip operation (from [clipRect]) is not axis-aligned
2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679
  /// 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.
2680 2681
  ///  * [BlendMode], which discusses the use of [Paint.blendMode] with
  ///    [saveLayer].
2682
  void saveLayer(Rect bounds, Paint paint) {
2683
    assert(_rectIsValid(bounds));
2684
    assert(paint != null);
2685 2686 2687 2688 2689 2690
    if (bounds == null) {
      _saveLayerWithoutBounds(paint._objects, paint._data);
    } else {
      _saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom,
                 paint._objects, paint._data);
    }
2691
  }
2692
  void _saveLayerWithoutBounds(List<dynamic> paintObjects, ByteData paintData)
2693
      native 'Canvas_saveLayerWithoutBounds';
2694 2695 2696 2697
  void _saveLayer(double left,
                  double top,
                  double right,
                  double bottom,
2698
                  List<dynamic> paintObjects,
2699
                  ByteData paintData) native 'Canvas_saveLayer';
H
Hixie 已提交
2700 2701 2702 2703 2704

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

H
Hixie 已提交
2710 2711 2712 2713 2714 2715
  /// 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.
2716
  int getSaveCount() native 'Canvas_getSaveCount';
2717

2718 2719
  /// Add a translation to the current transform, shifting the coordinate space
  /// horizontally by the first argument and vertically by the second argument.
2720
  void translate(double dx, double dy) native 'Canvas_translate';
2721 2722 2723 2724

  /// 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.
2725
  void scale(double sx, double sy) native 'Canvas_scale';
2726 2727

  /// Add a rotation to the current transform. The argument is in radians clockwise.
2728
  void rotate(double radians) native 'Canvas_rotate';
2729 2730 2731 2732 2733

  /// 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.
2734
  void skew(double sx, double sy) native 'Canvas_skew';
A
Adam Barth 已提交
2735

2736 2737
  /// Multiply the current transform by the specified 4⨉4 transformation matrix
  /// specified as a list of values in column-major order.
A
Adam Barth 已提交
2738
  void transform(Float64List matrix4) {
2739
    assert(matrix4 != null);
A
Adam Barth 已提交
2740
    if (matrix4.length != 16)
2741
      throw new ArgumentError('"matrix4" must have 16 entries.');
A
Adam Barth 已提交
2742 2743
    _transform(matrix4);
  }
2744
  void _transform(Float64List matrix4) native 'Canvas_transform';
A
Adam Barth 已提交
2745

2746 2747
  /// Reduces the clip region to the intersection of the current clip and the
  /// given rectangle.
2748
  ///
2749 2750 2751 2752 2753
  /// 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.
2754 2755 2756 2757
  ///
  /// Use [ClipOp.difference] to subtract the provided rectangle from the
  /// current clip.
  void clipRect(Rect rect, { ClipOp clipOp: ClipOp.intersect }) {
2758
    assert(_rectIsValid(rect));
2759 2760
    assert(clipOp != null);
    _clipRect(rect.left, rect.top, rect.right, rect.bottom, clipOp.index);
2761 2762 2763 2764
  }
  void _clipRect(double left,
                 double top,
                 double right,
2765
                 double bottom,
2766
                 int clipOp) native 'Canvas_clipRect';
2767

2768 2769
  /// Reduces the clip region to the intersection of the current clip and the
  /// given rounded rectangle.
2770
  ///
2771 2772 2773 2774
  /// 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].
2775
  void clipRRect(RRect rrect) {
2776
    assert(_rrectIsValid(rrect));
2777 2778
    _clipRRect(rrect._value);
  }
2779
  void _clipRRect(Float32List rrect) native 'Canvas_clipRRect';
2780

2781 2782
  /// Reduces the clip region to the intersection of the current clip and the
  /// given [Path].
2783
  ///
2784 2785 2786 2787
  /// 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.
2788 2789 2790 2791
  void clipPath(Path path) {
    assert(path != null); // path is checked on the engine side
    _clipPath(path);
  }
2792
  void _clipPath(Path path) native 'Canvas_clipPath';
2793

2794
  /// Paints the given [Color] onto the canvas, applying the given
2795
  /// [BlendMode], with the given color being the source and the background
2796
  /// being the destination.
2797
  void drawColor(Color color, BlendMode blendMode) {
2798 2799
    assert(color != null);
    assert(blendMode != null);
2800
    _drawColor(color.value, blendMode.index);
2801
  }
2802
  void _drawColor(int color, int blendMode) native 'Canvas_drawColor';
2803

I
Ian Hickson 已提交
2804
  /// Draws a line between the given points using the given paint. The line is
2805
  /// stroked, the value of the [Paint.style] is ignored for this call.
I
Ian Hickson 已提交
2806 2807 2808
  ///
  /// The `p1` and `p2` arguments are interpreted as offsets from the origin.
  void drawLine(Offset p1, Offset p2, Paint paint) {
2809 2810
    assert(_offsetIsValid(p1));
    assert(_offsetIsValid(p2));
2811
    assert(paint != null);
I
Ian Hickson 已提交
2812
    _drawLine(p1.dx, p1.dy, p2.dx, p2.dy, paint._objects, paint._data);
2813
  }
2814 2815 2816 2817 2818
  void _drawLine(double x1,
                 double y1,
                 double x2,
                 double y2,
                 List<dynamic> paintObjects,
2819
                 ByteData paintData) native 'Canvas_drawLine';
2820

2821 2822
  /// Fills the canvas with the given [Paint].
  ///
2823
  /// To fill the canvas with a solid color and blend mode, consider
2824
  /// [drawColor] instead.
2825 2826 2827 2828
  void drawPaint(Paint paint) {
    assert(paint != null);
    _drawPaint(paint._objects, paint._data);
  }
2829
  void _drawPaint(List<dynamic> paintObjects, ByteData paintData) native 'Canvas_drawPaint';
2830

2831 2832
  /// Draws a rectangle with the given [Paint]. Whether the rectangle is filled
  /// or stroked (or both) is controlled by [Paint.style].
2833
  void drawRect(Rect rect, Paint paint) {
2834
    assert(_rectIsValid(rect));
2835
    assert(paint != null);
2836 2837
    _drawRect(rect.left, rect.top, rect.right, rect.bottom,
              paint._objects, paint._data);
2838 2839 2840 2841 2842
  }
  void _drawRect(double left,
                 double top,
                 double right,
                 double bottom,
2843
                 List<dynamic> paintObjects,
2844
                 ByteData paintData) native 'Canvas_drawRect';
2845

2846 2847
  /// Draws a rounded rectangle with the given [Paint]. Whether the rectangle is
  /// filled or stroked (or both) is controlled by [Paint.style].
2848
  void drawRRect(RRect rrect, Paint paint) {
2849
    assert(_rrectIsValid(rrect));
2850
    assert(paint != null);
2851 2852 2853 2854
    _drawRRect(rrect._value, paint._objects, paint._data);
  }
  void _drawRRect(Float32List rrect,
                  List<dynamic> paintObjects,
2855
                  ByteData paintData) native 'Canvas_drawRRect';
2856

2857 2858 2859 2860 2861
  /// 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.
2862
  void drawDRRect(RRect outer, RRect inner, Paint paint) {
2863 2864
    assert(_rrectIsValid(outer));
    assert(_rrectIsValid(inner));
2865
    assert(paint != null);
2866 2867 2868 2869 2870
    _drawDRRect(outer._value, inner._value, paint._objects, paint._data);
  }
  void _drawDRRect(Float32List outer,
                   Float32List inner,
                   List<dynamic> paintObjects,
2871
                   ByteData paintData) native 'Canvas_drawDRRect';
2872

2873 2874 2875
  /// 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].
2876
  void drawOval(Rect rect, Paint paint) {
2877
    assert(_rectIsValid(rect));
2878
    assert(paint != null);
2879 2880
    _drawOval(rect.left, rect.top, rect.right, rect.bottom,
              paint._objects, paint._data);
2881 2882 2883 2884 2885
  }
  void _drawOval(double left,
                 double top,
                 double right,
                 double bottom,
2886
                 List<dynamic> paintObjects,
2887
                 ByteData paintData) native 'Canvas_drawOval';
2888

I
Ian Hickson 已提交
2889 2890 2891
  /// 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
2892
  /// controlled by [Paint.style].
I
Ian Hickson 已提交
2893
  void drawCircle(Offset c, double radius, Paint paint) {
2894
    assert(_offsetIsValid(c));
2895
    assert(paint != null);
I
Ian Hickson 已提交
2896
    _drawCircle(c.dx, c.dy, radius, paint._objects, paint._data);
2897
  }
2898 2899 2900 2901
  void _drawCircle(double x,
                   double y,
                   double radius,
                   List<dynamic> paintObjects,
2902
                   ByteData paintData) native 'Canvas_drawCircle';
2903

2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914
  /// 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) {
2915
    assert(_rectIsValid(rect));
2916
    assert(paint != null);
2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927
    _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,
2928
                ByteData paintData) native 'Canvas_drawArc';
2929

2930 2931 2932
  /// 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]).
2933
  void drawPath(Path path, Paint paint) {
2934 2935
    assert(path != null); // path is checked on the engine side
    assert(paint != null);
2936 2937 2938 2939
    _drawPath(path, paint._objects, paint._data);
  }
  void _drawPath(Path path,
                 List<dynamic> paintObjects,
2940
                 ByteData paintData) native 'Canvas_drawPath';
2941

2942
  /// Draws the given [Image] into the canvas with its top-left corner at the
I
Ian Hickson 已提交
2943 2944
  /// given [Offset]. The image is composited into the canvas using the given [Paint].
  void drawImage(Image image, Offset p, Paint paint) {
2945
    assert(image != null); // image is checked on the engine side
2946
    assert(_offsetIsValid(p));
2947
    assert(paint != null);
I
Ian Hickson 已提交
2948
    _drawImage(image, p.dx, p.dy, paint._objects, paint._data);
2949
  }
2950 2951 2952 2953
  void _drawImage(Image image,
                  double x,
                  double y,
                  List<dynamic> paintObjects,
2954
                  ByteData paintData) native 'Canvas_drawImage';
2955

2956 2957
  /// 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.
2958
  ///
2959 2960
  /// This might sample from outside the `src` rect by up to half the width of
  /// an applied filter.
2961 2962 2963 2964
  ///
  /// Multiple calls to this method with different arguments (from the same
  /// image) can be batched into a single call to [drawAtlas] to improve
  /// performance.
2965
  void drawImageRect(Image image, Rect src, Rect dst, Paint paint) {
2966
    assert(image != null); // image is checked on the engine side
2967 2968
    assert(_rectIsValid(src));
    assert(_rectIsValid(dst));
2969
    assert(paint != null);
2970 2971 2972 2973 2974 2975 2976 2977 2978
    _drawImageRect(image,
                   src.left,
                   src.top,
                   src.right,
                   src.bottom,
                   dst.left,
                   dst.top,
                   dst.right,
                   dst.bottom,
2979 2980
                   paint._objects,
                   paint._data);
2981 2982 2983 2984 2985 2986 2987 2988 2989 2990
  }
  void _drawImageRect(Image image,
                      double srcLeft,
                      double srcTop,
                      double srcRight,
                      double srcBottom,
                      double dstLeft,
                      double dstTop,
                      double dstRight,
                      double dstBottom,
2991
                      List<dynamic> paintObjects,
2992
                      ByteData paintData) native 'Canvas_drawImageRect';
2993

2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006
  /// 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.
3007
  void drawImageNine(Image image, Rect center, Rect dst, Paint paint) {
3008
    assert(image != null); // image is checked on the engine side
3009 3010
    assert(_rectIsValid(center));
    assert(_rectIsValid(dst));
3011
    assert(paint != null);
3012 3013 3014 3015 3016 3017 3018 3019 3020
    _drawImageNine(image,
                   center.left,
                   center.top,
                   center.right,
                   center.bottom,
                   dst.left,
                   dst.top,
                   dst.right,
                   dst.bottom,
3021 3022
                   paint._objects,
                   paint._data);
3023 3024 3025 3026 3027 3028 3029 3030 3031 3032
  }
  void _drawImageNine(Image image,
                      double centerLeft,
                      double centerTop,
                      double centerRight,
                      double centerBottom,
                      double dstLeft,
                      double dstTop,
                      double dstRight,
                      double dstBottom,
3033
                      List<dynamic> paintObjects,
3034
                      ByteData paintData) native 'Canvas_drawImageNine';
3035

H
Hixie 已提交
3036 3037
  /// Draw the given picture onto the canvas. To create a picture, see
  /// [PictureRecorder].
3038 3039 3040 3041
  void drawPicture(Picture picture) {
    assert(picture != null); // picture is checked on the engine side
    _drawPicture(picture);
  }
3042
  void _drawPicture(Picture picture) native 'Canvas_drawPicture';
3043

I
Ian Hickson 已提交
3044 3045
  /// Draws the text in the given [Paragraph] into this canvas at the given
  /// [Offset].
A
Adam Barth 已提交
3046
  ///
I
Ian Hickson 已提交
3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063
  /// 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.
3064
  void drawParagraph(Paragraph paragraph, Offset offset) {
3065
    assert(paragraph != null);
3066
    assert(_offsetIsValid(offset));
3067
    paragraph._paint(this, offset.dx, offset.dy);
3068
  }
A
Adam Barth 已提交
3069

A
Adam Barth 已提交
3070
  /// Draws a sequence of points according to the given [PointMode].
I
Ian Hickson 已提交
3071 3072
  ///
  /// The `points` argument is interpreted as offsets from the origin.
3073 3074 3075 3076 3077
  ///
  /// See also:
  ///
  ///  * [drawRawPoints], which takes `points` as a [Float32List] rather than a
  ///    [List<Offset>].
I
Ian Hickson 已提交
3078
  void drawPoints(PointMode pointMode, List<Offset> points, Paint paint) {
3079 3080 3081
    assert(pointMode != null);
    assert(points != null);
    assert(paint != null);
3082
    _drawPoints(paint._objects, paint._data, pointMode.index, _encodePointList(points));
A
Adam Barth 已提交
3083
  }
3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094

  /// 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) {
3095 3096 3097
    assert(pointMode != null);
    assert(points != null);
    assert(paint != null);
3098 3099 3100 3101 3102
    if (points.length % 2 != 0)
      throw new ArgumentError('"points" must have an even number of values.');
    _drawPoints(paint._objects, paint._data, pointMode.index, points);
  }

3103 3104 3105
  void _drawPoints(List<dynamic> paintObjects,
                   ByteData paintData,
                   int pointMode,
3106
                   Float32List points) native 'Canvas_drawPoints';
A
Adam Barth 已提交
3107

3108
  void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint) {
3109 3110 3111 3112
    assert(vertices != null); // vertices is checked on the engine side
    assert(paint != null);
    assert(blendMode != null);
    _drawVertices(vertices, blendMode.index, paint._objects, paint._data);
3113
  }
3114
  void _drawVertices(Vertices vertices,
3115
                     int blendMode,
3116
                     List<dynamic> paintObjects,
3117
                     ByteData paintData) native 'Canvas_drawVertices';
3118

3119 3120 3121 3122 3123
  //
  // See also:
  //
  //  * [drawRawAtlas], which takes its arguments as typed data lists rather
  //    than objects.
3124
  void drawAtlas(Image atlas,
3125 3126 3127
                 List<RSTransform> transforms,
                 List<Rect> rects,
                 List<Color> colors,
3128
                 BlendMode blendMode,
3129 3130
                 Rect cullRect,
                 Paint paint) {
3131 3132 3133 3134 3135 3136
    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);
3137

3138
    final int rectCount = rects.length;
3139
    if (transforms.length != rectCount)
3140
      throw new ArgumentError('"transforms" and "rects" lengths must match.');
3141
    if (colors.isNotEmpty && colors.length != rectCount)
3142
      throw new ArgumentError('If non-null, "colors" length must match that of "transforms" and "rects".');
3143

A
Adam Barth 已提交
3144 3145
    final Float32List rstTransformBuffer = new Float32List(rectCount * 4);
    final Float32List rectBuffer = new Float32List(rectCount * 4);
3146 3147 3148 3149 3150 3151 3152 3153

    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];
3154
      assert(_rectIsValid(rect));
3155 3156 3157 3158 3159 3160 3161 3162
      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;
3163
    }
3164

3165
    final Int32List colorBuffer = colors.isEmpty ? null : _encodeColorList(colors);
3166 3167
    final Float32List cullRectBuffer = cullRect?._value;

3168 3169
    _drawAtlas(
      paint._objects, paint._data, atlas, rstTransformBuffer, rectBuffer,
3170
      colorBuffer, blendMode.index, cullRectBuffer
3171
    );
3172
  }
3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195

  //
  // 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) {
3196 3197 3198 3199 3200 3201
    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);
3202

3203
    final int rectCount = rects.length;
3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216
    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
    );
  }

3217 3218
  void _drawAtlas(List<dynamic> paintObjects,
                  ByteData paintData,
A
Adam Barth 已提交
3219
                  Image atlas,
3220 3221 3222
                  Float32List rstTransforms,
                  Float32List rects,
                  Int32List colors,
3223
                  int blendMode,
3224
                  Float32List cullRect) native 'Canvas_drawAtlas';
3225 3226 3227

  /// Draws a shadow for a [Path] representing the given material elevation.
  ///
3228 3229 3230 3231
  /// The `transparentOccluder` argument should be true if the occluding object
  /// is not opaque.
  ///
  /// The arguments must not be null.
3232
  void drawShadow(Path path, Color color, double elevation, bool transparentOccluder) {
3233 3234
    assert(path != null); // path is checked on the engine side
    assert(color != null);
3235
    assert(transparentOccluder != null);
3236 3237 3238 3239
    _drawShadow(path, color.value, elevation, transparentOccluder);
  }
  void _drawShadow(Path path,
                   int color,
3240
                   double elevation,
3241
                   bool transparentOccluder) native 'Canvas_drawShadow';
3242 3243
}

A
Adam Barth 已提交
3244
/// An object representing a sequence of recorded graphical operations.
3245 3246
///
/// To create a [Picture], use a [PictureRecorder].
H
Hixie 已提交
3247 3248 3249 3250
///
/// 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.
3251 3252 3253
class Picture extends NativeFieldWrapperClass2 {
  /// This class is created by the engine, and should not be instantiated
  /// or extended directly.
3254
  ///
3255 3256
  /// To create a [Picture], use a [PictureRecorder].
  Picture._();
3257

A
Adam Barth 已提交
3258
  /// Creates an image from this picture.
3259
  ///
A
Adam Barth 已提交
3260 3261
  /// The picture is rasterized using the number of pixels specified by the
  /// given width and height.
3262
  ///
A
Adam Barth 已提交
3263 3264
  /// Although the image is returned synchronously, the picture is actually
  /// rasterized the first time the image is drawn and then cached.
3265
  Image toImage(int width, int height) native 'Picture_toImage';
A
Adam Barth 已提交
3266

I
Ian Hickson 已提交
3267 3268
  /// Release the resources used by this object. The object is no longer usable
  /// after this method is called.
3269
  void dispose() native 'Picture_dispose';
3270 3271
}

A
Adam Barth 已提交
3272 3273 3274
/// Records a [Picture] containing a sequence of graphical operations.
///
/// To begin recording, construct a [Canvas] to record the commands.
3275
/// To end recording, use the [PictureRecorder.endRecording] method.
3276
class PictureRecorder extends NativeFieldWrapperClass2 {
3277 3278 3279
  /// Creates a new idle PictureRecorder. To associate it with a
  /// [Canvas] and begin recording, pass this [PictureRecorder] to the
  /// [Canvas] constructor.
3280
  PictureRecorder() { _constructor(); }
3281
  void _constructor() native 'PictureRecorder_constructor';
3282

A
Adam Barth 已提交
3283 3284
  /// Whether this object is currently recording commands.
  ///
3285 3286 3287 3288 3289
  /// 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.
3290
  bool get isRecording native 'PictureRecorder_isRecording';
A
Adam Barth 已提交
3291 3292 3293 3294 3295 3296

  /// 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.
3297 3298
  ///
  /// Returns null if the PictureRecorder is not associated with a canvas.
3299
  Picture endRecording() native 'PictureRecorder_endRecording';
3300
}
3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313

/// 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.
///
G
Greg Spencer 已提交
3314 3315
/// Return a [String] to cause an [Exception] to be synchronously thrown with
/// that string as a message.
3316 3317 3318
///
/// If the callback is called with null, the future completes with an error.
///
3319
/// Example usage:
3320
///
3321 3322
/// ```dart
/// typedef void IntCallback(int result);
3323
///
3324
/// String _doSomethingAndCallback(IntCallback callback) {
3325 3326
///   new Timer(new Duration(seconds: 1), () { callback(1); });
/// }
3327
///
3328
/// Future<int> doSomething() {
3329
///   return _futurize(_doSomethingAndCallback);
3330 3331
/// }
/// ```
3332 3333
Future<T> _futurize<T>(_Callbacker<T> callbacker) {
  final Completer<T> completer = new Completer<T>.sync();
3334
  final String error = callbacker((T t) {
3335 3336 3337 3338 3339 3340
    if (t == null) {
      completer.completeError(new Exception('operation failed'));
    } else {
      completer.complete(t);
    }
  });
3341 3342
  if (error != null)
    throw new Exception(error);
3343
  return completer.future;
3344 3345
}