Fix O(N²) page list update in pages setter (freezes UI on huge documents) - #694
Merged
espresso3389 merged 1 commit intoAug 19, 2026
Merged
Conversation
The pages setter ran _pages.indexWhere(identical) for every non-identical page. During progressive page loading every batch recreates all unloaded trailing pages, so each batch cost O(N^2) identity comparisons on the main isolate -- about 5.5s per batch for a 47,352-page document (measured on an iPhone with a 1.9GB manual), repeating until all pages are loaded and freezing the UI the whole time. Build an identity map of the previous pages once per call and look up old indexes in O(1), preserving the exact identical() semantics.
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.
Problem
_PdfDocumentPdfium.pagessetter looks up each page's previous index with_pages.indexWhere((p) => identical(p, newPage)). During progressive page loading (loadPagesProgressively→_loadPagesInLimitedTime), every batch recreates all trailing (not-yet-loaded) page instances, so none of them hit theidenticalfast path and each one triggers a full O(N) scan — making every batch O(N²) on the caller's isolate (the UI isolate in Flutter apps).For a 47,352-page document (a 1.9 GB aircraft maintenance manual), that is roughly 2.2 billion identity comparisons per batch: measured ~5.5 s of main-isolate freeze after every ~250 ms load batch, repeating for the entire progressive-load run. The viewer is effectively frozen the whole time (0.3–10 fps while scrolling). Small documents don't show it because the cost is quadratic in page count.
Fix
Build an identity map of the previous pages once per call and look up old indexes in O(1).
HashMap.identity()preserves the exactidentical()semantics of the original lookup, and_pagesnever contains duplicate identities (both internal producers create fresh instances per position), so behavior is unchanged.Results (iPhone, 1.9 GB / 47,352-page PDF)