Skip to content

Fix textscaler clamp assertion error#181716

Merged
auto-submit[bot] merged 4 commits intoflutter:masterfrom
Valansch:fix-textscaler-clamp-assertion
Feb 24, 2026
Merged

Fix textscaler clamp assertion error#181716
auto-submit[bot] merged 4 commits intoflutter:masterfrom
Valansch:fix-textscaler-clamp-assertion

Conversation

@Valansch
Copy link
Copy Markdown
Contributor

@Valansch Valansch commented Jan 30, 2026

Fix TextScaler.clamp assertion failure when clamping already-clamped scalers

Fixes #174828

Description

When calling clamp() on an already-clamped TextScaler, the _ClampedTextScaler.clamp() method was checking if minScaleFactor == maxScaleFactor before calculating the actual new min/max values. This caused assertion failures ('maxScale > minScale': is not true) when the calculated newMinScale and newMaxScale became equal after applying max()/min() operations.

Example scenario that triggers the bug:

final textScaler = MediaQuery.of(context).textScaler;
// First clamp - creates a _ClampedTextScaler
textScaler.clamp(minScaleFactor: 1.0, maxScaleFactor: 1.1);
// Internal framework code calls clamp() again (e.g., in BottomNavigationBar)
// This could result in newMinScale == newMaxScale, triggering the assertion

The fix:

Calculate newMinScale and newMaxScale first, then check for equality. If they are equal, return a _LinearTextScaler instead of creating a _ClampedTextScaler that would fail its constructor assertion.

Important

This breaks before undefined behaviour. We now through an assertion error when new bounds are out of bounds even when min and max are equal. For more detail view my comment on this here

@github-actions github-actions bot added a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels. labels Jan 30, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly fixes an assertion error in TextScaler.clamp when called on an already-clamped scaler. The logic is now more robust by calculating the new clamp boundaries before deciding which type of scaler to return. The added tests effectively cover the bug fix and a related edge case. My only feedback is a suggestion to improve the organization of the new tests for better maintainability, as detailed in the comment.

Comment thread packages/flutter/test/painting/text_scaler_test.dart Outdated
@justinmc justinmc requested a review from victorsanni February 3, 2026 23:31
Comment thread packages/flutter/lib/src/painting/text_scaler.dart Outdated
@Valansch Valansch force-pushed the fix-textscaler-clamp-assertion branch 2 times, most recently from 48b4b5b to 8afaeec Compare February 4, 2026 13:29
Copy link
Copy Markdown
Contributor

@victorsanni victorsanni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you run dart format on all files in this PR to fix failing checks?

Comment thread packages/flutter/test/painting/text_scaler_test.dart Outdated
Comment thread packages/flutter/test/painting/text_scaler_test.dart Outdated
@Valansch
Copy link
Copy Markdown
Contributor Author

Valansch commented Feb 4, 2026

@victorsanni

Can you run dart format on all files in this PR to fix failing checks?

I don't understand why it would be failing. Looks good to me. Is using dart from /bin/ incorrect? Which version should I use. Sorry if I missed some instructions.

./bin/dart format packages/flutter/
Formatted 1685 files (0 changed) in 12.18 seconds

EDIT: Nevermind. Analyze caught it.

@Valansch
Copy link
Copy Markdown
Contributor Author

Valansch commented Feb 4, 2026

@victorsanni nevermind my last comment. Flutter analyze should have caught the issue. I addressed your comments. Will squash the second commit after review.

Copy link
Copy Markdown
Contributor

@victorsanni victorsanni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fix, run dart format packages/flutter/test/painting/text_scaler_test.dart

@Valansch Valansch force-pushed the fix-textscaler-clamp-assertion branch 2 times, most recently from 0d5b1e8 to 0940969 Compare February 5, 2026 09:01
@Valansch
Copy link
Copy Markdown
Contributor Author

Valansch commented Feb 5, 2026

@victorsanni Resolved

@Valansch Valansch requested a review from victorsanni February 5, 2026 09:02
return minScaleFactor == maxScaleFactor
? _LinearTextScaler(minScaleFactor)
: _ClampedTextScaler(scaler, max(minScaleFactor, minScale), min(maxScaleFactor, maxScale));
: _ClampedTextScaler(scaler, minScaleFactor, maxScaleFactor);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is correct. When you compose 2 clampers the first one shouldn't be ignored.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View this comment and make up you mind you two :)
#174828 (comment)

I implemented the fix first respecting the old bounds. Then i was told to ignore them, now not?

Copy link
Copy Markdown
Contributor

@LongCatIsLooong LongCatIsLooong Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I thought by "discard" @victorsanni meant the this.minScale and this.maxScale should be removed from the expression. But with this implementation I think the first clamp is just going to be ignored and that would create some surprising behaviors. I would expect text scalers compose like functions so clamp2 . clamp1 === clamp2 . identityScaler . clamp1 (where identifyScaler is just a text scaler that returns the input text size as-is).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what do you do it the clamps are incompatible? Please view my comment on the issue i explained my thoughts there

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If clamp1 has a range of [1, 2] and clamp2 [3, 4], what should the output size be when the input font size 9 goes through clamp1 and then clamp2? I'm expecting 3 instead of 4 (but I think this implementation would return 4).

The developer doesn't know the runtime type of the TextScaler they're calling clamp on (at least in most cases). And with this implementation I believe when you call clamp the exact behavior will depend on the runtime type of the receiver, if the receiver is a _ClampTextScaler then the receiver's scaling logic will be ignored but if it's not then the clamping will be applied after the receiver's scaling logic is applied.

Copy link
Copy Markdown
Contributor Author

@Valansch Valansch Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about this again: My current approach, as the previous (bugged) version is commutative. But clamping is not. So the current approach is not working. I will add another test and consider your suggestion.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to implement your approach to just nest the clamedScalers like this:

  @override
  TextScaler clamp({double minScaleFactor = 0, double maxScaleFactor = double.infinity}) {
    return minScaleFactor == maxScaleFactor
        ? TextScaler.linear(minScaleFactor)
        : _ClampedTextScaler(this, minScaleFactor, maxScaleFactor);
  }

Unfortunately that breaks equality, because only the last clamps are compared. Now I can fix the equality by implementing a numeric solution to this problem, but then why not just implement the numeric solution directly in the clamp and don't nest? This is in addition to my points raised above.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately that breaks equality, because only the last clamps are compared

Could you elaborate? The "inner" scaler is also compared in the == implementation. Also it's correct to always return false for TextScaler.== implementations because it's just an optimization to prevent unnecessary rebuilds. Function equality is inherently tricky so the documentation only asks that subclasses should identify "equal" text scalers on a best effort basis.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nesting the clamed scalers can result in the same scalers not being equal. Example:

final scaler = TexScaler.linear(2)
scaler.clamp(2,3) != scaler.clamp(1,4).clamp(2,3)

scaler.clamp(1,5).clamp(2,3) != scaler.clamp(1,4).clamp(2,3)

I believe those should be equal.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TextScaler.== is only used by the framework to skip unnecessary widget rebuilds so you can always choose to return false, it's totally optional. But if you really want to prevent rebuilds as much as possible I think you can switch to the original implementation (union of the two clamp intervals) when the intervals overlap.

@Valansch Valansch force-pushed the fix-textscaler-clamp-assertion branch 2 times, most recently from e31a48d to 5517a32 Compare February 5, 2026 23:47
Comment thread packages/flutter/lib/src/painting/text_scaler.dart Outdated
@Valansch Valansch force-pushed the fix-textscaler-clamp-assertion branch from 5517a32 to b7e7914 Compare February 10, 2026 16:27
@Valansch
Copy link
Copy Markdown
Contributor Author

@LongCatIsLooong @victorsanni I implemented a new version now. Please mind my response to your comments under the comment.
I have also extended the test, it now tests all cases and equality.

If you have a change suggestion I can try it against this test. I believe this is the best version. I removed the ternary to add a comment.


if (newMaxScale <= newMinScale) {
// Ranges don't overlap or collapse to a single point.
return TextScaler.linear(clampDouble(minScale, minScaleFactor, maxScaleFactor));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When newMaxScale < newMinScale I don't think this matches the API docs: https://main-api.flutter.dev/flutter/painting/TextScaler/clamp.html

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean for the inputs minScaleFactor maxScaleFactor? You are right this implementation removes the assert when maxScaleFactor > minScaleFactor.

I will expend the test and fix it.

But the goal of this newMaxScale <= newMinScale is to check if the new and old bounds overlap. So this condition is required here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed it in a new commit and added more tests. Now it's consistent with the other two clamp functions

@Valansch Valansch force-pushed the fix-textscaler-clamp-assertion branch 2 times, most recently from 5f1de64 to 690f3bd Compare February 19, 2026 09:59
Copy link
Copy Markdown
Contributor

@LongCatIsLooong LongCatIsLooong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thank you for fixing this!

@Valansch Valansch force-pushed the fix-textscaler-clamp-assertion branch from 690f3bd to 93a455f Compare February 19, 2026 22:04
@Valansch
Copy link
Copy Markdown
Contributor Author

@LongCatIsLooong Thanks for the review. Squashed the commits. Ready to merge from my end.

@victorsanni victorsanni added the autosubmit Merge PR when tree becomes green via auto submit App label Feb 23, 2026
@auto-submit auto-submit bot added this pull request to the merge queue Feb 23, 2026
Merged via the queue into flutter:master with commit cbb7a61 Feb 24, 2026
74 checks passed
@flutter-dashboard flutter-dashboard bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Feb 24, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 24, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 24, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 25, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 25, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 25, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 26, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 26, 2026
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Feb 26, 2026
Roll Flutter from dad6f9d4107a to b31548feb941 (39 revisions)

flutter/flutter@dad6f9d...b31548f

2026-02-25 mdebbar@google.com [web] Fix failure on Firefox 148 (flutter/flutter#182855)
2026-02-25 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from KfPgw04T0OEADLJA5... to XI0Ax7fbtYE4XKYAQ... (flutter/flutter#182887)
2026-02-25 50643541+Mairramer@users.noreply.github.com Use AnimationStyle curve and reverseCurve in ModalBottomSheet animation (flutter/flutter#181403)
2026-02-25 engine-flutter-autoroll@skia.org Roll Dart SDK from fd3dce5b6a4e to 5c57e75f1102 (9 revisions) (flutter/flutter#182801)
2026-02-25 98614782+auto-submit[bot]@users.noreply.github.com Reverts "refactor: remove material in context_menu_controller_test, icon_test, list_wheel_scroll_view_test, media_query_test, platform_menu_bar_test (#182697)" (flutter/flutter#182879)
2026-02-25 ahmedsameha1@gmail.com Make sure that an AnimatedSlide doesn't crash in 0x0 environment (flutter/flutter#181535)
2026-02-24 jmccandless@google.com Reland Standardize on Test* widgets in *_tester.dart files (flutter/flutter#182632)
2026-02-24 nhan13574@gmail.com docs(Path): clarify that zero-length contours are excluded from computeMetrics (flutter/flutter#180165)
2026-02-24 mdebbar@google.com Fix typo in assert message (flutter/flutter#182843)
2026-02-24 matej.knopp@gmail.com [win32] Fix overflow in TaskRunnerWindow. (flutter/flutter#182822)
2026-02-24 abadasamuelosp@gmail.com feat: Add --no-uninstall flag to flutter test for integration tests (flutter/flutter#182714)
2026-02-24 74057391+jhonathanqz@users.noreply.github.com Rename noFrequencyBasedMinification to useFrequencyBasedMinification (flutter/flutter#182684)
2026-02-24 60122246+xiaowei-guan@users.noreply.github.com [Impeller] Fix fail to render pixel buffer texture on Linux (flutter/flutter#181656)
2026-02-24 15619084+vashworth@users.noreply.github.com Remove FlutterFramework app migration (flutter/flutter#182100)
2026-02-24 engine-flutter-autoroll@skia.org Roll Packages from 12b43a1 to 062c8d4 (5 revisions) (flutter/flutter#182839)
2026-02-24 mdebbar@google.com [web] Run webparagraph tests in CI (flutter/flutter#182092)
2026-02-24 jason-simmons@users.noreply.github.com Fix a race in EmbedderTest.CanSpecifyCustomUITaskRunner (flutter/flutter#182649)
2026-02-24 srawlins@google.com flutter_tools: Use a super-parameter in several missed cases (flutter/flutter#182581)
2026-02-24 116356835+AbdeMohlbi@users.noreply.github.com Replace more references to `flutter/engine` with `flutter/flutter` (flutter/flutter#182654)
2026-02-24 50643541+Mairramer@users.noreply.github.com Carousel: Migration from Scrollable+Viewport to CustomScrollView (flutter/flutter#182475)
2026-02-24 97480502+b-luk@users.noreply.github.com Refactor impellerc_main to better organize some of its logic (flutter/flutter#182783)
2026-02-24 116356835+AbdeMohlbi@users.noreply.github.com Remove unused `getPluginList ` (flutter/flutter#182660)
2026-02-24 34465683+rkishan516@users.noreply.github.com Refactor: Remove material from ticker provider test (flutter/flutter#181697)
2026-02-24 engine-flutter-autoroll@skia.org Roll Skia from 26eebffe12bd to f44d7db68805 (3 revisions) (flutter/flutter#182821)
2026-02-24 34465683+rkishan516@users.noreply.github.com refactor: remove material in context_menu_controller_test, icon_test, list_wheel_scroll_view_test, media_query_test, platform_menu_bar_test (flutter/flutter#182697)
2026-02-24 engine-flutter-autoroll@skia.org Roll Skia from 7dad66aae75a to 26eebffe12bd (5 revisions) (flutter/flutter#182810)
2026-02-24 pokepsi@gmail.com Update roadmap for 2026 (flutter/flutter#182798)
2026-02-24 fluttergithubbot@gmail.com Marks Windows tool_tests_commands_1_2 to be unflaky (flutter/flutter#179670)
2026-02-23 zhongliu88889@gmail.com [web] scroll iOS iframe text input into view (flutter/flutter#179759)
2026-02-23 Mail@maikwild.de Fix textscaler clamp assertion error (flutter/flutter#181716)
2026-02-23 engine-flutter-autoroll@skia.org Roll Skia from 9a5a3c92c336 to 7dad66aae75a (4 revisions) (flutter/flutter#182779)
2026-02-23 116356835+AbdeMohlbi@users.noreply.github.com Move more getters from userMessages class to the appropriate places (flutter/flutter#182656)
2026-02-23 engine-flutter-autoroll@skia.org Manual roll Dart SDK from f8fac50475b8 to fd3dce5b6a4e (6 revisions) (flutter/flutter#182768)
2026-02-23 15619084+vashworth@users.noreply.github.com Copy Flutter framework to Add to App FlutterPluginRgistrant (flutter/flutter#182523)
2026-02-23 mr-peipei@web.de Add progress indicator to artifact downloads (flutter/flutter#181808)
2026-02-23 47866232+chunhtai@users.noreply.github.com Clarify batch release mode requirements (flutter/flutter#182228)
2026-02-23 mdebbar@google.com [web] Remove --disable-gpu from flutter chrome tests (flutter/flutter#182618)
2026-02-23 jwren@google.com running-apps: update running-apps to use Duration.ago() (flutter/flutter#182172)
2026-02-23 kevmoo@users.noreply.github.com Refactor bin/ shell scripts for better performance and safety (flutter/flutter#182674)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC louisehsu@google.com,stuartmorgan@google.com on the revert to ensure that a human
is aware of the problem.

...
ahmedsameha1 pushed a commit to ahmedsameha1/flutter that referenced this pull request Feb 27, 2026
Fix `TextScaler.clamp` assertion failure when clamping already-clamped
scalers

Fixes flutter#174828

## Description

When calling `clamp()` on an already-clamped `TextScaler`, the
`_ClampedTextScaler.clamp()` method was checking if `minScaleFactor ==
maxScaleFactor` **before** calculating the actual new min/max values.
This caused assertion failures (`'maxScale > minScale': is not true`)
when the calculated `newMinScale` and `newMaxScale` became equal after
applying `max()`/`min()` operations.

### Example scenario that triggers the bug:
```dart
final textScaler = MediaQuery.of(context).textScaler;
// First clamp - creates a _ClampedTextScaler
textScaler.clamp(minScaleFactor: 1.0, maxScaleFactor: 1.1);
// Internal framework code calls clamp() again (e.g., in BottomNavigationBar)
// This could result in newMinScale == newMaxScale, triggering the assertion
```

### The fix:
Calculate `newMinScale` and `newMaxScale` **first**, then check for
equality. If they are equal, return a `_LinearTextScaler` instead of
creating a `_ClampedTextScaler` that would fail its constructor
assertion.


### Important
This breaks before undefined behaviour. We now through an assertion
error when new bounds are out of bounds even when min and max are equal.
For more detail view my comment on this
[here](flutter#174828 (comment))

---------

Co-authored-by: Victor Sanni <victorsanniay@gmail.com>
okorohelijah pushed a commit to okorohelijah/packages that referenced this pull request Mar 26, 2026
…r#11116)

Roll Flutter from dad6f9d4107a to b31548feb941 (39 revisions)

flutter/flutter@dad6f9d...b31548f

2026-02-25 mdebbar@google.com [web] Fix failure on Firefox 148 (flutter/flutter#182855)
2026-02-25 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from KfPgw04T0OEADLJA5... to XI0Ax7fbtYE4XKYAQ... (flutter/flutter#182887)
2026-02-25 50643541+Mairramer@users.noreply.github.com Use AnimationStyle curve and reverseCurve in ModalBottomSheet animation (flutter/flutter#181403)
2026-02-25 engine-flutter-autoroll@skia.org Roll Dart SDK from fd3dce5b6a4e to 5c57e75f1102 (9 revisions) (flutter/flutter#182801)
2026-02-25 98614782+auto-submit[bot]@users.noreply.github.com Reverts "refactor: remove material in context_menu_controller_test, icon_test, list_wheel_scroll_view_test, media_query_test, platform_menu_bar_test (#182697)" (flutter/flutter#182879)
2026-02-25 ahmedsameha1@gmail.com Make sure that an AnimatedSlide doesn't crash in 0x0 environment (flutter/flutter#181535)
2026-02-24 jmccandless@google.com Reland Standardize on Test* widgets in *_tester.dart files (flutter/flutter#182632)
2026-02-24 nhan13574@gmail.com docs(Path): clarify that zero-length contours are excluded from computeMetrics (flutter/flutter#180165)
2026-02-24 mdebbar@google.com Fix typo in assert message (flutter/flutter#182843)
2026-02-24 matej.knopp@gmail.com [win32] Fix overflow in TaskRunnerWindow. (flutter/flutter#182822)
2026-02-24 abadasamuelosp@gmail.com feat: Add --no-uninstall flag to flutter test for integration tests (flutter/flutter#182714)
2026-02-24 74057391+jhonathanqz@users.noreply.github.com Rename noFrequencyBasedMinification to useFrequencyBasedMinification (flutter/flutter#182684)
2026-02-24 60122246+xiaowei-guan@users.noreply.github.com [Impeller] Fix fail to render pixel buffer texture on Linux (flutter/flutter#181656)
2026-02-24 15619084+vashworth@users.noreply.github.com Remove FlutterFramework app migration (flutter/flutter#182100)
2026-02-24 engine-flutter-autoroll@skia.org Roll Packages from 12b43a1 to 062c8d4 (5 revisions) (flutter/flutter#182839)
2026-02-24 mdebbar@google.com [web] Run webparagraph tests in CI (flutter/flutter#182092)
2026-02-24 jason-simmons@users.noreply.github.com Fix a race in EmbedderTest.CanSpecifyCustomUITaskRunner (flutter/flutter#182649)
2026-02-24 srawlins@google.com flutter_tools: Use a super-parameter in several missed cases (flutter/flutter#182581)
2026-02-24 116356835+AbdeMohlbi@users.noreply.github.com Replace more references to `flutter/engine` with `flutter/flutter` (flutter/flutter#182654)
2026-02-24 50643541+Mairramer@users.noreply.github.com Carousel: Migration from Scrollable+Viewport to CustomScrollView (flutter/flutter#182475)
2026-02-24 97480502+b-luk@users.noreply.github.com Refactor impellerc_main to better organize some of its logic (flutter/flutter#182783)
2026-02-24 116356835+AbdeMohlbi@users.noreply.github.com Remove unused `getPluginList ` (flutter/flutter#182660)
2026-02-24 34465683+rkishan516@users.noreply.github.com Refactor: Remove material from ticker provider test (flutter/flutter#181697)
2026-02-24 engine-flutter-autoroll@skia.org Roll Skia from 26eebffe12bd to f44d7db68805 (3 revisions) (flutter/flutter#182821)
2026-02-24 34465683+rkishan516@users.noreply.github.com refactor: remove material in context_menu_controller_test, icon_test, list_wheel_scroll_view_test, media_query_test, platform_menu_bar_test (flutter/flutter#182697)
2026-02-24 engine-flutter-autoroll@skia.org Roll Skia from 7dad66aae75a to 26eebffe12bd (5 revisions) (flutter/flutter#182810)
2026-02-24 pokepsi@gmail.com Update roadmap for 2026 (flutter/flutter#182798)
2026-02-24 fluttergithubbot@gmail.com Marks Windows tool_tests_commands_1_2 to be unflaky (flutter/flutter#179670)
2026-02-23 zhongliu88889@gmail.com [web] scroll iOS iframe text input into view (flutter/flutter#179759)
2026-02-23 Mail@maikwild.de Fix textscaler clamp assertion error (flutter/flutter#181716)
2026-02-23 engine-flutter-autoroll@skia.org Roll Skia from 9a5a3c92c336 to 7dad66aae75a (4 revisions) (flutter/flutter#182779)
2026-02-23 116356835+AbdeMohlbi@users.noreply.github.com Move more getters from userMessages class to the appropriate places (flutter/flutter#182656)
2026-02-23 engine-flutter-autoroll@skia.org Manual roll Dart SDK from f8fac50475b8 to fd3dce5b6a4e (6 revisions) (flutter/flutter#182768)
2026-02-23 15619084+vashworth@users.noreply.github.com Copy Flutter framework to Add to App FlutterPluginRgistrant (flutter/flutter#182523)
2026-02-23 mr-peipei@web.de Add progress indicator to artifact downloads (flutter/flutter#181808)
2026-02-23 47866232+chunhtai@users.noreply.github.com Clarify batch release mode requirements (flutter/flutter#182228)
2026-02-23 mdebbar@google.com [web] Remove --disable-gpu from flutter chrome tests (flutter/flutter#182618)
2026-02-23 jwren@google.com running-apps: update running-apps to use Duration.ago() (flutter/flutter#182172)
2026-02-23 kevmoo@users.noreply.github.com Refactor bin/ shell scripts for better performance and safety (flutter/flutter#182674)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC louisehsu@google.com,stuartmorgan@google.com on the revert to ensure that a human
is aware of the problem.

...
mboetger pushed a commit to mboetger/flutter that referenced this pull request Mar 26, 2026
Fix `TextScaler.clamp` assertion failure when clamping already-clamped
scalers

Fixes flutter#174828

## Description

When calling `clamp()` on an already-clamped `TextScaler`, the
`_ClampedTextScaler.clamp()` method was checking if `minScaleFactor ==
maxScaleFactor` **before** calculating the actual new min/max values.
This caused assertion failures (`'maxScale > minScale': is not true`)
when the calculated `newMinScale` and `newMaxScale` became equal after
applying `max()`/`min()` operations.

### Example scenario that triggers the bug:
```dart
final textScaler = MediaQuery.of(context).textScaler;
// First clamp - creates a _ClampedTextScaler
textScaler.clamp(minScaleFactor: 1.0, maxScaleFactor: 1.1);
// Internal framework code calls clamp() again (e.g., in BottomNavigationBar)
// This could result in newMinScale == newMaxScale, triggering the assertion
```

### The fix:
Calculate `newMinScale` and `newMaxScale` **first**, then check for
equality. If they are equal, return a `_LinearTextScaler` instead of
creating a `_ClampedTextScaler` that would fail its constructor
assertion.


### Important
This breaks before undefined behaviour. We now through an assertion
error when new bounds are out of bounds even when min and max are equal.
For more detail view my comment on this
[here](flutter#174828 (comment))

---------

Co-authored-by: Victor Sanni <victorsanniay@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

textScalar.clamp throws Failed assertion: line 118 pos 80: 'maxScale > minScale': is not true.

3 participants