fix: sanitise non-finite zoom in MapCamera.clampZoom#2228
Closed
Pistacchione wants to merge 1 commit into
Closed
Conversation
During a rapid pinch zoom-out the gesture handler calls `_getZoomForScale`, which computes `startZoom + math.log(scale) / ln2`. When `details.scale + _scaleCorrector` momentarily becomes non-positive (the scale corrector can be negative), `math.log` returns `NaN` or `-Infinity`. `clampZoom` used `num.clamp`, which returns `NaN` unchanged for a `NaN` input and cannot sanitise it, so the invalid zoom was committed to the camera. It then propagated into: - `TileRangeCalculator`, where `halfSize = size / (scale * 2)` becomes non-finite and `DiscreteTileRange.fromPixelBounds` throws `Unsupported operation: Infinity or NaN toInt` from `.floor()`; - `MarkerClusterLayer`, whose visible bounds become `NaN`, tripping the `north <= maxLatitude` assertion. `clampZoom` now treats any non-finite input as an invalid update and returns the current (finite) zoom, keeping the camera in a valid state. This also covers the `minZoom == null` case, where a `-Infinity` zoom previously crashed as well. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Member
|
Please open a bug report with an MRE. Ensure you test to see whether your original issue is resolved on the latest master. As is, this PR does not fix anything and instead just buries the problem, if there is one. |
Author
|
You were right, thanks for the pointer to test against master. Closing the loop here; the PR can stay closed. Thanks again. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
During a rapid pinch zoom-out, the gesture handler calls
_getZoomForScale,which computes
startZoom + math.log(scale) / math.ln2. Whendetails.scale + _scaleCorrectormomentarily becomes non-positive (the scalecorrector can be negative),
math.logreturnsNaNor-Infinity.clampZoomrelied onnum.clamp, which returnsNaNunchanged for aNaNinput and therefore cannot sanitise it. The invalid zoom was committed to the
camera and propagated into:
TileRangeCalculator—halfSize = size / (scale * 2)becomes non-finiteand
DiscreteTileRange.fromPixelBoundsthrowsUnsupported operation: Infinity or NaN toIntfrom.floor().MarkerClusterLayer— the visible bounds becomeNaN, tripping thenorth <= maxLatitudeassertion.The crash is transient/self-healing (the next finite scale update recomputes a
valid zoom), but each bad frame surfaces as an uncaught framework error.
Fix
clampZoomnow treats any non-finite input as an invalid update and returns thecurrent (finite) zoom, keeping the camera in a valid state. Being the single
chokepoint every zoom mutation passes through (gestures and
moveRaw), thiscovers the whole class of NaN-zoom bugs. It also fixes the
minZoom == nullcase, where a
-Infinityzoom crashed as well.Tests
Added
test/map/camera/camera_test.dartcovering the non-finite guard(
NaN/±Infinity), normal min/max clamping, and the no-min/max case. Theexisting
camera/tests still pass.Notes
AI disclosure
This change was written with the assistance of AI (Claude).