| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:math' show max, min; |
| |
| import 'package:flutter/foundation.dart'; |
| |
| /// A class that describes how textual contents should be scaled for better |
| /// readability. |
| /// |
| /// The [scale] function computes the scaled font size given the original |
| /// unscaled font size specified by app developers. |
| /// |
| /// The [==] operator defines the equality of 2 [TextScaler]s, which the |
| /// framework uses to determine whether text widgets should rebuild when their |
| /// [TextScaler] changes. Consider overridding the [==] operator if applicable |
| /// to avoid unnecessary rebuilds. |
| @immutable |
| abstract class TextScaler { |
| /// Creates a TextScaler. |
| const TextScaler(); |
| |
| /// Creates a proportional [TextScaler] that scales the incoming font size by |
| /// multiplying it with the given `textScaleFactor`. |
| const factory TextScaler.linear(double textScaleFactor) = _LinearTextScaler; |
| |
| /// A [TextScaler] that doesn't scale the input font size. |
| /// |
| /// This is equivalent to `TextScaler.linear(1.0)`, the [TextScaler.scale] |
| /// implementation always returns the input font size as-is. |
| static const TextScaler noScaling = _LinearTextScaler(1.0); |
| |
| /// Computes the scaled font size (in logical pixels) with the given unscaled |
| /// `fontSize` (in logical pixels). |
| /// |
| /// The input `fontSize` must be finite and non-negative. |
| /// |
| /// When given the same `fontSize` input, this method returns the same value. |
| /// The output of a larger input `fontSize` is typically larger than that of a |
| /// smaller input, but on unusual occasions they may produce the same output. |
| /// For example, some platforms use single-precision floats to represent font |
| /// sizes, as a result of truncation two different unscaled font sizes can be |
| /// scaled to the same value. |
| double scale(double fontSize); |
| |
| /// The estimated number of font pixels for each logical pixel. This property |
| /// exists only for backward compatibility purposes, and will be removed in |
| /// a future version of Flutter. |
| /// |
| /// The value of this property is only an estimate, so it may not reflect the |
| /// exact text scaling strategy this [TextScaler] represents, especially when |
| /// this [TextScaler] is not linear. Consider using [TextScaler.scale] instead. |
| @Deprecated( |
| 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' |
| 'This feature was deprecated after v3.12.0-2.0.pre.', |
| ) |
| double get textScaleFactor; |
| |
| /// Returns a new [TextScaler] that restricts the scaled font size to within |
| /// the range `[minScaleFactor * fontSize, maxScaleFactor * fontSize]`. |
| TextScaler clamp({ double minScaleFactor = 0, double maxScaleFactor = double.infinity }) { |
| assert(maxScaleFactor >= minScaleFactor); |
| assert(!maxScaleFactor.isNaN); |
| assert(minScaleFactor.isFinite); |
| assert(minScaleFactor >= 0); |
| |
| return minScaleFactor == maxScaleFactor |
| ? TextScaler.linear(minScaleFactor) |
| : _ClampedTextScaler(this, minScaleFactor, maxScaleFactor); |
| } |
| } |
| |
| final class _LinearTextScaler implements TextScaler { |
| const _LinearTextScaler(this.textScaleFactor) : assert(textScaleFactor >= 0); |
| |
| @override |
| final double textScaleFactor; |
| |
| @override |
| double scale(double fontSize) { |
| assert(fontSize >= 0); |
| assert(fontSize.isFinite); |
| return fontSize * textScaleFactor; |
| } |
| |
| @override |
| TextScaler clamp({ double minScaleFactor = 0, double maxScaleFactor = double.infinity }) { |
| assert(maxScaleFactor >= minScaleFactor); |
| assert(!maxScaleFactor.isNaN); |
| assert(minScaleFactor.isFinite); |
| assert(minScaleFactor >= 0); |
| |
| final double newScaleFactor = clampDouble(textScaleFactor, minScaleFactor, maxScaleFactor); |
| return newScaleFactor == textScaleFactor ? this : _LinearTextScaler(newScaleFactor); |
| } |
| |
| @override |
| bool operator ==(Object other) { |
| if (identical(this, other)) { |
| return true; |
| } |
| return other is _LinearTextScaler && other.textScaleFactor == textScaleFactor; |
| } |
| |
| @override |
| int get hashCode => textScaleFactor.hashCode; |
| |
| @override |
| String toString() => textScaleFactor == 1.0 ? 'no scaling' : 'linear (${textScaleFactor}x)'; |
| } |
| |
| final class _ClampedTextScaler implements TextScaler { |
| const _ClampedTextScaler(this.scaler, this.minScale, this.maxScale) : assert(maxScale > minScale); |
| final TextScaler scaler; |
| final double minScale; |
| final double maxScale; |
| |
| @override |
| double get textScaleFactor => clampDouble(scaler.textScaleFactor, minScale, maxScale); |
| |
| @override |
| double scale(double fontSize) { |
| assert(fontSize >= 0); |
| assert(fontSize.isFinite); |
| return minScale == maxScale |
| ? minScale * fontSize |
| : clampDouble(scaler.scale(fontSize), minScale * fontSize, maxScale * fontSize); |
| } |
| |
| @override |
| TextScaler clamp({ double minScaleFactor = 0, double maxScaleFactor = double.infinity }) { |
| return minScaleFactor == maxScaleFactor |
| ? _LinearTextScaler(minScaleFactor) |
| : _ClampedTextScaler(scaler, max(minScaleFactor, minScale), min(maxScaleFactor, maxScale)); |
| } |
| |
| @override |
| bool operator ==(Object other) { |
| if (identical(this, other)) { |
| return true; |
| } |
| return other is _ClampedTextScaler |
| && minScale == other.minScale |
| && maxScale == other.maxScale |
| && (minScale == maxScale || scaler == other.scaler); |
| } |
| |
| @override |
| int get hashCode => minScale == maxScale ? minScale.hashCode : Object.hash(scaler, minScale, maxScale); |
| } |