Skip to content

Compute operator bounding boxes in the worker - #22289

Open
calixteman wants to merge 3 commits into
mozilla:masterfrom
calixteman:bbox_worker
Open

calixteman wants to merge 3 commits into
mozilla:masterfrom
calixteman:bbox_worker

Conversation

@calixteman

Copy link
Copy Markdown
Contributor

Compute operator bounds and propagate them to dependencies in the worker. Send packed bounds to the display layer for partial rendering and debugger highlights.

Remove display-side bounding-box tracking and recordOperations, and enable optimized partial rendering by default.

sync-pdfs-for-pdf-js Bot pushed a commit to mozilla/pdf.js.refs that referenced this pull request Oct 21, 2026
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Viewer preview

Commit e92cb3b (build logs).

Viewer Build Preview
Modern (gulp generic) ✅ viewer.html
Legacy (gulp generic-legacy) ✅ viewer.html

Previews are removed when the PR closes and may be pruned after 30 days without an update.

@codecov-commenter

codecov-commenter commented Oct 21, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.38575% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.64%. Comparing base (f70fabb) to head (e92cb3b).

Files with missing lines Patch % Lines
src/core/operator_list_bbox_tracker.js 99.52% 3 Missing ⚠️
src/display/api.js 88.88% 1 Missing ⚠️
src/display/canvas_images_tracker.js 97.91% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #22289      +/-   ##
==========================================
+ Coverage   90.52%   90.64%   +0.11%     
==========================================
  Files         278      280       +2     
  Lines       68586    68764     +178     
==========================================
+ Hits        62090    62331     +241     
+ Misses       6496     6433      -63     
Flag Coverage Δ
browsertest 66.43% <91.64%> (+0.21%) ⬆️
fonttest 8.99% <0.00%> (+<0.01%) ⬆️
integrationtest 69.98% <84.39%> (+0.39%) ⬆️
unittest 61.40% <83.16%> (+0.15%) ⬆️
unittestcli 59.12% <77.98%> (+0.11%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed

codspeed Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Merging this PR will improve performance by 13.42%

⚡ 2 improved benchmarks
✅ 85 untouched benchmarks
⏩ 175 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
⚡ Lexer: tokenize content stream 14.5 ms 12.7 ms +14.02%
⚡ Pattern.parseShading: radial (radial_gradients.pdf) 7.1 ms 6.3 ms +12.83%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing calixteman:bbox_worker (e92cb3b) with master (f70fabb)

Open in CodSpeed

Footnotes

  1. 175 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

Comment thread src/core/operator_list_bbox_tracker.js Resolved
Comment thread src/core/operator_list_bbox_tracker.js Resolved
sync-pdfs-for-pdf-js Bot pushed a commit to mozilla/pdf.js.refs that referenced this pull request Oct 21, 2026
Comment thread src/display/display_utils.js Resolved
Comment thread web/app_options.js Resolved
sync-pdfs-for-pdf-js Bot pushed a commit to mozilla/pdf.js.refs that referenced this pull request Oct 21, 2026
sync-pdfs-for-pdf-js Bot pushed a commit to mozilla/pdf.js.refs that referenced this pull request Oct 21, 2026

@Snuffleupagus Snuffleupagus left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It looks like this made Util.multiplyByDOMMatrix unused, so that can probably be removed now?

Comment thread src/shared/util.js Resolved
sync-pdfs-for-pdf-js Bot pushed a commit to mozilla/pdf.js.refs that referenced this pull request Oct 23, 2026
Propagate bounds to operator dependencies and send packed boxes with the
final operator-list chunk. Expose them through OperatorBBoxes.
Migrate operation filters and debugger highlights to worker bounds.
Remove display-side bounding-box tracking and recordOperations.
sync-pdfs-for-pdf-js Bot pushed a commit to mozilla/pdf.js.refs that referenced this pull request Nov 2, 2026

@nicolo-ribaudo nicolo-ribaudo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This PR breaks the dependency highlight in the stepper view, which really helped me debug problems while first developing this feature.

(when hovering on step 15 of issue16263.pdf):

MasterThis PR
Image Image

Also, some bboxes in that issue16263.pdf got larger, e.g. step 33. Larger bboxes just means that it's less optimized, but I don't know if they got larger because of a bug that could cause problems elsewhere:

MasterThis PR
Image Image

return bbox;
}
const operatorList = font.charProcOperatorList?.get(id);
const index = operatorList?.fnArray.indexOf(OPS.setCharWidthAndBounds);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this trustworthy? Or can a Type 3 font lie about its bounds? Previously we were actually executing the char's operator list to get its full bbox.

Comment thread src/display/api.js
);
return !(renderingIntent & RenderingIntentFlag.DISPLAY)
? null
: (this._intentStates.get(cacheKey)?.operatorList?.bboxes ?? null);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

_intentStates gets empties by #tryCleanup(). Could we still need the list of bboxes after that? I'm not sure about when cleanup happens, but maybe we can still zoom in after that? Before .recordedBBoxes was just a class property so it was staying around.

return info;
}
const fontMatrix = font?.fontMatrix || FONT_IDENTITY_MATRIX;
const fontBBox = font?.bbox;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The previous version was reading the font bbox, but then checking if it was actually trustworthy:

// The font has no bbox or it is not trustworthy, so we need to
// return the bounding box based on .measureText().

The reason I added that is because some fonts were missing a bbox, others were lying. Would it be possible to keep that fallback? Maybe by drawing in an OffscreenCanvas?

An example of a font without a bbox are the "standard" ones (from https://github.com/mozilla/pdf.js/blob/master/test/pdfs/standard_fonts.pdf), where PDF.js is kind of expected to know their properties because the PDF only references them by name. You can see e.g. op 1406 from the first page of that PDF, rendering "A" in Courier. With this patch it gets a full-page bbox, while before it had the correct one.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe we could somehow reuse the logic from #22419?

But a good first step would be to hard-code bboxes for those well-known fonts.

return bbox;
}
const operatorList = font.charProcOperatorList?.get(id);
const index = operatorList?.fnArray.indexOf(OPS.setCharWidthAndBounds);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If I remember correctly, type 3 fonts can have ops that have dependencies on the outer PDF. We'd need to traverse this operatorList to look for ops that have them.

@nicolo-ribaudo

Copy link
Copy Markdown
Collaborator

smask_none.pdf

This file shows a regression with tracking of the SMask bbox. With this PR, if you zoom it on the white part it will turn red because it skips the setGState call, which got an empty bbox.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants