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
5import 'dart:math' show max, min;
6
7import 'package:flutter/foundation.dart';
8
9/// A class that describes how textual contents should be scaled for better
10/// readability.
11///
12/// The [scale] function computes the scaled font size given the original
13/// unscaled font size specified by app developers.
14///
15/// The [==] operator defines the equality of 2 [TextScaler]s, which the
16/// framework uses to determine whether text widgets should rebuild when their
17/// [TextScaler] changes. Consider overriding the [==] operator if applicable
18/// to avoid unnecessary rebuilds.
19@immutable
20abstract class TextScaler {
21 /// Creates a TextScaler.
22 const TextScaler();
23
24 /// Creates a proportional [TextScaler] that scales the incoming font size by
25 /// multiplying it with the given `textScaleFactor`.
26 const factory TextScaler.linear(double textScaleFactor) = _LinearTextScaler;
27
28 /// A [TextScaler] that doesn't scale the input font size.
29 ///
30 /// This is equivalent to `TextScaler.linear(1.0)`, the [TextScaler.scale]
31 /// implementation always returns the input font size as-is.
32 static const TextScaler noScaling = _LinearTextScaler(1.0);
33
34 /// Computes the scaled font size (in logical pixels) with the given unscaled
35 /// `fontSize` (in logical pixels).
36 ///
37 /// The input `fontSize` must be finite and non-negative.
38 ///
39 /// When given the same `fontSize` input, this method returns the same value.
40 /// The output of a larger input `fontSize` is typically larger than that of a
41 /// smaller input, but on unusual occasions they may produce the same output.
42 /// For example, some platforms use single-precision floats to represent font
43 /// sizes, as a result of truncation two different unscaled font sizes can be
44 /// scaled to the same value.
45 double scale(double fontSize);
46
47 /// The estimated number of font pixels for each logical pixel. This property
48 /// exists only for backward compatibility purposes, and will be removed in
49 /// a future version of Flutter.
50 ///
51 /// The value of this property is only an estimate, so it may not reflect the
52 /// exact text scaling strategy this [TextScaler] represents, especially when
53 /// this [TextScaler] is not linear. Consider using [TextScaler.scale] instead.
54 @Deprecated(
55 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. '
56 'This feature was deprecated after v3.12.0-2.0.pre.',
57 )
58 double get textScaleFactor;
59
60 /// Returns a new [TextScaler] that restricts the scaled font size to within
61 /// the range `[minScaleFactor * fontSize, maxScaleFactor * fontSize]`.
62 TextScaler clamp({double minScaleFactor = 0, double maxScaleFactor = double.infinity}) {
63 assert(maxScaleFactor >= minScaleFactor);
64 assert(!maxScaleFactor.isNaN);
65 assert(minScaleFactor.isFinite);
66 assert(minScaleFactor >= 0);
67
68 return minScaleFactor == maxScaleFactor
69 ? TextScaler.linear(minScaleFactor)
70 : _ClampedTextScaler(this, minScaleFactor, maxScaleFactor);
71 }
72}
73
74final class _LinearTextScaler implements TextScaler {
75 const _LinearTextScaler(this.textScaleFactor) : assert(textScaleFactor >= 0);
76
77 @override
78 final double textScaleFactor;
79
80 @override
81 double scale(double fontSize) {
82 assert(fontSize >= 0);
83 assert(fontSize.isFinite);
84 return fontSize * textScaleFactor;
85 }
86
87 @override
88 TextScaler clamp({double minScaleFactor = 0, double maxScaleFactor = double.infinity}) {
89 assert(maxScaleFactor >= minScaleFactor);
90 assert(!maxScaleFactor.isNaN);
91 assert(minScaleFactor.isFinite);
92 assert(minScaleFactor >= 0);
93
94 final double newScaleFactor = clampDouble(textScaleFactor, minScaleFactor, maxScaleFactor);
95 return newScaleFactor == textScaleFactor ? this : _LinearTextScaler(newScaleFactor);
96 }
97
98 @override
99 bool operator ==(Object other) {
100 if (identical(this, other)) {
101 return true;
102 }
103 return other is _LinearTextScaler && other.textScaleFactor == textScaleFactor;
104 }
105
106 @override
107 int get hashCode => textScaleFactor.hashCode;
108
109 @override
110 String toString() => textScaleFactor == 1.0 ? 'no scaling' : 'linear (${textScaleFactor}x)';
111}
112
113final class _ClampedTextScaler implements TextScaler {
114 const _ClampedTextScaler(this.scaler, this.minScale, this.maxScale) : assert(maxScale > minScale);
115 final TextScaler scaler;
116 final double minScale;
117 final double maxScale;
118
119 @override
120 double get textScaleFactor => clampDouble(scaler.textScaleFactor, minScale, maxScale);
121
122 @override
123 double scale(double fontSize) {
124 assert(fontSize >= 0);
125 assert(fontSize.isFinite);
126 return minScale == maxScale
127 ? minScale * fontSize
128 : clampDouble(scaler.scale(fontSize), minScale * fontSize, maxScale * fontSize);
129 }
130
131 @override
132 TextScaler clamp({double minScaleFactor = 0, double maxScaleFactor = double.infinity}) {
133 return minScaleFactor == maxScaleFactor
134 ? _LinearTextScaler(minScaleFactor)
135 : _ClampedTextScaler(scaler, max(minScaleFactor, minScale), min(maxScaleFactor, maxScale));
136 }
137
138 @override
139 bool operator ==(Object other) {
140 if (identical(this, other)) {
141 return true;
142 }
143 return other is _ClampedTextScaler &&
144 minScale == other.minScale &&
145 maxScale == other.maxScale &&
146 (minScale == maxScale || scaler == other.scaler);
147 }
148
149 @override
150 int get hashCode =>
151 minScale == maxScale ? minScale.hashCode : Object.hash(scaler, minScale, maxScale);
152}
153

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com