"Fossies" - the Fresh Open Source Software Archive

Member "flutter-1.22.4/packages/flutter/lib/src/rendering/image.dart" (13 Nov 2020, 13285 Bytes) of package /linux/misc/flutter-1.22.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Dart source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Copyright 2014 The Flutter Authors. All rights reserved.
    2 // Use of this source code is governed by a BSD-style license that can be
    3 // found in the LICENSE file.
    4 
    5 import 'dart:ui' as ui show Image;
    6 
    7 import 'box.dart';
    8 import 'object.dart';
    9 
   10 export 'package:flutter/painting.dart' show
   11   BoxFit,
   12   ImageRepeat;
   13 
   14 /// An image in the render tree.
   15 ///
   16 /// The render image attempts to find a size for itself that fits in the given
   17 /// constraints and preserves the image's intrinsic aspect ratio.
   18 ///
   19 /// The image is painted using [paintImage], which describes the meanings of the
   20 /// various fields on this class in more detail.
   21 class RenderImage extends RenderBox {
   22   /// Creates a render box that displays an image.
   23   ///
   24   /// The [scale], [alignment], [repeat], [matchTextDirection] and [filterQuality] arguments
   25   /// must not be null. The [textDirection] argument must not be null if
   26   /// [alignment] will need resolving or if [matchTextDirection] is true.
   27   RenderImage({
   28     ui.Image? image,
   29     this.debugImageLabel,
   30     double? width,
   31     double? height,
   32     double scale = 1.0,
   33     Color? color,
   34     BlendMode? colorBlendMode,
   35     BoxFit? fit,
   36     AlignmentGeometry alignment = Alignment.center,
   37     ImageRepeat repeat = ImageRepeat.noRepeat,
   38     Rect? centerSlice,
   39     bool matchTextDirection = false,
   40     TextDirection? textDirection,
   41     bool invertColors = false,
   42     bool isAntiAlias = false,
   43     FilterQuality filterQuality = FilterQuality.low,
   44   }) : assert(scale != null),
   45        assert(repeat != null),
   46        assert(alignment != null),
   47        assert(filterQuality != null),
   48        assert(matchTextDirection != null),
   49        assert(isAntiAlias != null),
   50        _image = image,
   51        _width = width,
   52        _height = height,
   53        _scale = scale,
   54        _color = color,
   55        _colorBlendMode = colorBlendMode,
   56        _fit = fit,
   57        _alignment = alignment,
   58        _repeat = repeat,
   59        _centerSlice = centerSlice,
   60        _matchTextDirection = matchTextDirection,
   61        _invertColors = invertColors,
   62        _textDirection = textDirection,
   63        _isAntiAlias = isAntiAlias,
   64        _filterQuality = filterQuality {
   65     _updateColorFilter();
   66   }
   67 
   68   Alignment? _resolvedAlignment;
   69   bool? _flipHorizontally;
   70 
   71   void _resolve() {
   72     if (_resolvedAlignment != null)
   73       return;
   74     _resolvedAlignment = alignment.resolve(textDirection);
   75     _flipHorizontally = matchTextDirection && textDirection == TextDirection.rtl;
   76   }
   77 
   78   void _markNeedResolution() {
   79     _resolvedAlignment = null;
   80     _flipHorizontally = null;
   81     markNeedsPaint();
   82   }
   83 
   84   /// The image to display.
   85   ui.Image? get image => _image;
   86   ui.Image? _image;
   87   set image(ui.Image? value) {
   88     if (value == _image)
   89       return;
   90     _image = value;
   91     markNeedsPaint();
   92     if (_width == null || _height == null)
   93       markNeedsLayout();
   94   }
   95 
   96   /// A string used to identify the source of the image.
   97   String? debugImageLabel;
   98 
   99   /// If non-null, requires the image to have this width.
  100   ///
  101   /// If null, the image will pick a size that best preserves its intrinsic
  102   /// aspect ratio.
  103   double? get width => _width;
  104   double? _width;
  105   set width(double? value) {
  106     if (value == _width)
  107       return;
  108     _width = value;
  109     markNeedsLayout();
  110   }
  111 
  112   /// If non-null, require the image to have this height.
  113   ///
  114   /// If null, the image will pick a size that best preserves its intrinsic
  115   /// aspect ratio.
  116   double? get height => _height;
  117   double? _height;
  118   set height(double? value) {
  119     if (value == _height)
  120       return;
  121     _height = value;
  122     markNeedsLayout();
  123   }
  124 
  125   /// Specifies the image's scale.
  126   ///
  127   /// Used when determining the best display size for the image.
  128   double get scale => _scale;
  129   double _scale;
  130   set scale(double value) {
  131     assert(value != null);
  132     if (value == _scale)
  133       return;
  134     _scale = value;
  135     markNeedsLayout();
  136   }
  137 
  138   ColorFilter? _colorFilter;
  139 
  140   void _updateColorFilter() {
  141     if (_color == null)
  142       _colorFilter = null;
  143     else
  144       _colorFilter = ColorFilter.mode(_color!, _colorBlendMode ?? BlendMode.srcIn);
  145   }
  146 
  147   /// If non-null, this color is blended with each image pixel using [colorBlendMode].
  148   Color? get color => _color;
  149   Color? _color;
  150   set color(Color? value) {
  151     if (value == _color)
  152       return;
  153     _color = value;
  154     _updateColorFilter();
  155     markNeedsPaint();
  156   }
  157 
  158   /// Used to set the filterQuality of the image
  159   /// Use the [FilterQuality.low] quality setting to scale the image, which corresponds to
  160   /// bilinear interpolation, rather than the default [FilterQuality.none] which corresponds
  161   /// to nearest-neighbor.
  162   FilterQuality get filterQuality => _filterQuality;
  163   FilterQuality _filterQuality;
  164   set filterQuality(FilterQuality value) {
  165     assert(value != null);
  166     if (value == _filterQuality)
  167       return;
  168     _filterQuality = value;
  169     markNeedsPaint();
  170   }
  171 
  172 
  173   /// Used to combine [color] with this image.
  174   ///
  175   /// The default is [BlendMode.srcIn]. In terms of the blend mode, [color] is
  176   /// the source and this image is the destination.
  177   ///
  178   /// See also:
  179   ///
  180   ///  * [BlendMode], which includes an illustration of the effect of each blend mode.
  181   BlendMode? get colorBlendMode => _colorBlendMode;
  182   BlendMode? _colorBlendMode;
  183   set colorBlendMode(BlendMode? value) {
  184     if (value == _colorBlendMode)
  185       return;
  186     _colorBlendMode = value;
  187     _updateColorFilter();
  188     markNeedsPaint();
  189   }
  190 
  191   /// How to inscribe the image into the space allocated during layout.
  192   ///
  193   /// The default varies based on the other fields. See the discussion at
  194   /// [paintImage].
  195   BoxFit? get fit => _fit;
  196   BoxFit? _fit;
  197   set fit(BoxFit? value) {
  198     if (value == _fit)
  199       return;
  200     _fit = value;
  201     markNeedsPaint();
  202   }
  203 
  204   /// How to align the image within its bounds.
  205   ///
  206   /// If this is set to a text-direction-dependent value, [textDirection] must
  207   /// not be null.
  208   AlignmentGeometry get alignment => _alignment;
  209   AlignmentGeometry _alignment;
  210   set alignment(AlignmentGeometry value) {
  211     assert(value != null);
  212     if (value == _alignment)
  213       return;
  214     _alignment = value;
  215     _markNeedResolution();
  216   }
  217 
  218   /// How to repeat this image if it doesn't fill its layout bounds.
  219   ImageRepeat get repeat => _repeat;
  220   ImageRepeat _repeat;
  221   set repeat(ImageRepeat value) {
  222     assert(value != null);
  223     if (value == _repeat)
  224       return;
  225     _repeat = value;
  226     markNeedsPaint();
  227   }
  228 
  229   /// The center slice for a nine-patch image.
  230   ///
  231   /// The region of the image inside the center slice will be stretched both
  232   /// horizontally and vertically to fit the image into its destination. The
  233   /// region of the image above and below the center slice will be stretched
  234   /// only horizontally and the region of the image to the left and right of
  235   /// the center slice will be stretched only vertically.
  236   Rect? get centerSlice => _centerSlice;
  237   Rect? _centerSlice;
  238   set centerSlice(Rect? value) {
  239     if (value == _centerSlice)
  240       return;
  241     _centerSlice = value;
  242     markNeedsPaint();
  243   }
  244 
  245   /// Whether to invert the colors of the image.
  246   ///
  247   /// inverting the colors of an image applies a new color filter to the paint.
  248   /// If there is another specified color filter, the invert will be applied
  249   /// after it. This is primarily used for implementing smart invert on iOS.
  250   bool get invertColors => _invertColors;
  251   bool _invertColors;
  252   set invertColors(bool value) {
  253     if (value == _invertColors)
  254       return;
  255     _invertColors = value;
  256     markNeedsPaint();
  257   }
  258 
  259   /// Whether to paint the image in the direction of the [TextDirection].
  260   ///
  261   /// If this is true, then in [TextDirection.ltr] contexts, the image will be
  262   /// drawn with its origin in the top left (the "normal" painting direction for
  263   /// images); and in [TextDirection.rtl] contexts, the image will be drawn with
  264   /// a scaling factor of -1 in the horizontal direction so that the origin is
  265   /// in the top right.
  266   ///
  267   /// This is occasionally used with images in right-to-left environments, for
  268   /// images that were designed for left-to-right locales. Be careful, when
  269   /// using this, to not flip images with integral shadows, text, or other
  270   /// effects that will look incorrect when flipped.
  271   ///
  272   /// If this is set to true, [textDirection] must not be null.
  273   bool get matchTextDirection => _matchTextDirection;
  274   bool _matchTextDirection;
  275   set matchTextDirection(bool value) {
  276     assert(value != null);
  277     if (value == _matchTextDirection)
  278       return;
  279     _matchTextDirection = value;
  280     _markNeedResolution();
  281   }
  282 
  283   /// The text direction with which to resolve [alignment].
  284   ///
  285   /// This may be changed to null, but only after the [alignment] and
  286   /// [matchTextDirection] properties have been changed to values that do not
  287   /// depend on the direction.
  288   TextDirection? get textDirection => _textDirection;
  289   TextDirection? _textDirection;
  290   set textDirection(TextDirection? value) {
  291     if (_textDirection == value)
  292       return;
  293     _textDirection = value;
  294     _markNeedResolution();
  295   }
  296 
  297   /// Whether to paint the image with anti-aliasing.
  298   ///
  299   /// Anti-aliasing alleviates the sawtooth artifact when the image is rotated.
  300   bool get isAntiAlias => _isAntiAlias;
  301   bool _isAntiAlias;
  302   set isAntiAlias(bool value) {
  303     if (_isAntiAlias == value) {
  304       return;
  305     }
  306     assert(value != null);
  307     _isAntiAlias = value;
  308     markNeedsPaint();
  309   }
  310 
  311   /// Find a size for the render image within the given constraints.
  312   ///
  313   ///  - The dimensions of the RenderImage must fit within the constraints.
  314   ///  - The aspect ratio of the RenderImage matches the intrinsic aspect
  315   ///    ratio of the image.
  316   ///  - The RenderImage's dimension are maximal subject to being smaller than
  317   ///    the intrinsic size of the image.
  318   Size _sizeForConstraints(BoxConstraints constraints) {
  319     // Folds the given |width| and |height| into |constraints| so they can all
  320     // be treated uniformly.
  321     constraints = BoxConstraints.tightFor(
  322       width: _width,
  323       height: _height,
  324     ).enforce(constraints);
  325 
  326     if (_image == null)
  327       return constraints.smallest;
  328 
  329     return constraints.constrainSizeAndAttemptToPreserveAspectRatio(Size(
  330       _image!.width.toDouble() / _scale,
  331       _image!.height.toDouble() / _scale,
  332     ));
  333   }
  334 
  335   @override
  336   double computeMinIntrinsicWidth(double height) {
  337     assert(height >= 0.0);
  338     if (_width == null && _height == null)
  339       return 0.0;
  340     return _sizeForConstraints(BoxConstraints.tightForFinite(height: height)).width;
  341   }
  342 
  343   @override
  344   double computeMaxIntrinsicWidth(double height) {
  345     assert(height >= 0.0);
  346     return _sizeForConstraints(BoxConstraints.tightForFinite(height: height)).width;
  347   }
  348 
  349   @override
  350   double computeMinIntrinsicHeight(double width) {
  351     assert(width >= 0.0);
  352     if (_width == null && _height == null)
  353       return 0.0;
  354     return _sizeForConstraints(BoxConstraints.tightForFinite(width: width)).height;
  355   }
  356 
  357   @override
  358   double computeMaxIntrinsicHeight(double width) {
  359     assert(width >= 0.0);
  360     return _sizeForConstraints(BoxConstraints.tightForFinite(width: width)).height;
  361   }
  362 
  363   @override
  364   bool hitTestSelf(Offset position) => true;
  365 
  366   @override
  367   void performLayout() {
  368     size = _sizeForConstraints(constraints);
  369   }
  370 
  371   @override
  372   void paint(PaintingContext context, Offset offset) {
  373     if (_image == null)
  374       return;
  375     _resolve();
  376     assert(_resolvedAlignment != null);
  377     assert(_flipHorizontally != null);
  378     paintImage(
  379       canvas: context.canvas,
  380       rect: offset & size,
  381       image: _image!,
  382       debugImageLabel: debugImageLabel,
  383       scale: _scale,
  384       colorFilter: _colorFilter,
  385       fit: _fit,
  386       alignment: _resolvedAlignment!,
  387       centerSlice: _centerSlice,
  388       repeat: _repeat,
  389       flipHorizontally: _flipHorizontally!,
  390       invertColors: invertColors,
  391       filterQuality: _filterQuality,
  392       isAntiAlias: _isAntiAlias,
  393     );
  394   }
  395 
  396   @override
  397   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
  398     super.debugFillProperties(properties);
  399     properties.add(DiagnosticsProperty<ui.Image>('image', image));
  400     properties.add(DoubleProperty('width', width, defaultValue: null));
  401     properties.add(DoubleProperty('height', height, defaultValue: null));
  402     properties.add(DoubleProperty('scale', scale, defaultValue: 1.0));
  403     properties.add(ColorProperty('color', color, defaultValue: null));
  404     properties.add(EnumProperty<BlendMode>('colorBlendMode', colorBlendMode, defaultValue: null));
  405     properties.add(EnumProperty<BoxFit>('fit', fit, defaultValue: null));
  406     properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null));
  407     properties.add(EnumProperty<ImageRepeat>('repeat', repeat, defaultValue: ImageRepeat.noRepeat));
  408     properties.add(DiagnosticsProperty<Rect>('centerSlice', centerSlice, defaultValue: null));
  409     properties.add(FlagProperty('matchTextDirection', value: matchTextDirection, ifTrue: 'match text direction'));
  410     properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
  411     properties.add(DiagnosticsProperty<bool>('invertColors', invertColors));
  412     properties.add(EnumProperty<FilterQuality>('filterQuality', filterQuality));
  413   }
  414 }