-
Notifications
You must be signed in to change notification settings - Fork 10.6k
Offload canvas drawing operations to a worker #20729
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
61eb6f6
7cd8e24
3ae950b
089354d
2db7631
9b65c48
bfa56ac
2b4aecd
767b5f1
73eefc2
fc86d76
a2a486b
4df8779
01f8333
a3d2879
14b136b
d44b269
5531f28
c6a0631
d8776a2
cf48e41
eb2f3c0
fc247fc
7cbb9fe
4557e3e
afdfee3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -398,6 +398,121 @@ class PartialEvaluator { | |
| return false; | ||
| } | ||
|
|
||
| _hasTransferMaps(transferObj) { | ||
| let transferArray; | ||
| if (Array.isArray(transferObj)) { | ||
| transferArray = transferObj; | ||
| } else if (isPDFFunction(transferObj)) { | ||
| transferArray = [transferObj]; | ||
| } else { | ||
| return false; | ||
| } | ||
|
|
||
| const numFns = transferArray.length; | ||
| if (!(numFns === 1 || numFns === 4)) { | ||
| return false; | ||
| } | ||
|
|
||
| let numEffectfulFns = 0; | ||
| for (const entry of transferArray) { | ||
| const transfer = this.xref.fetchIfRef(entry); | ||
| if (isName(transfer, "Identity")) { | ||
| continue; | ||
| } | ||
| if (!isPDFFunction(transfer)) { | ||
| return false; | ||
| } | ||
| numEffectfulFns++; | ||
| } | ||
| return numEffectfulFns > 0; | ||
| } | ||
|
|
||
| hasCanvasFilters(resources) { | ||
| if (!(resources instanceof Dict)) { | ||
| return false; | ||
| } | ||
|
|
||
| const processed = new RefSet(); | ||
| if (resources.objId) { | ||
| processed.put(resources.objId); | ||
| } | ||
| const xref = this.xref; | ||
| const nodes = [resources]; | ||
| while (nodes.length) { | ||
| const node = nodes.shift(); | ||
|
|
||
| const graphicStates = node.get("ExtGState"); | ||
| if (graphicStates instanceof Dict) { | ||
| for (let graphicState of graphicStates.getRawValues()) { | ||
| if (graphicState instanceof Ref) { | ||
| if (processed.has(graphicState)) { | ||
| continue; | ||
| } | ||
| try { | ||
| graphicState = xref.fetch(graphicState); | ||
| } catch (ex) { | ||
| info(`hasCanvasFilters - failed to fetch ExtGState: "${ex}".`); | ||
| // A fetch failure means we can't inspect the resource, so fall | ||
| // back to main-thread rendering rather than misclassify a corrupt | ||
| // PDF as filter-free. | ||
| return true; | ||
| } | ||
| } | ||
| if (!(graphicState instanceof Dict)) { | ||
| continue; | ||
| } | ||
| if (graphicState.objId) { | ||
| processed.put(graphicState.objId); | ||
| } | ||
| try { | ||
| if (this._hasTransferMaps(graphicState.get("TR"))) { | ||
| return true; | ||
| } | ||
| } catch (ex) { | ||
| info(`hasCanvasFilters - failed to inspect filter data: "${ex}".`); | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| const xObjects = node.get("XObject"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You only visit XObject but a TR/TR2 can be in a tiling pattern too. |
||
| if (xObjects instanceof Dict) { | ||
| for (let xObject of xObjects.getRawValues()) { | ||
| if (xObject instanceof Ref) { | ||
| if (processed.has(xObject)) { | ||
| continue; | ||
| } | ||
| try { | ||
| xObject = xref.fetch(xObject); | ||
| } catch (ex) { | ||
| info(`hasCanvasFilters - failed to fetch XObject: "${ex}".`); | ||
| return true; | ||
| } | ||
| } | ||
| if (!(xObject instanceof BaseStream)) { | ||
| continue; | ||
| } | ||
| if (xObject.dict.objId) { | ||
| processed.put(xObject.dict.objId); | ||
| } | ||
| const xResources = xObject.dict.get("Resources"); | ||
| if (!(xResources instanceof Dict)) { | ||
| continue; | ||
| } | ||
| if (xResources.objId && processed.has(xResources.objId)) { | ||
| continue; | ||
| } | ||
|
|
||
| nodes.push(xResources); | ||
| if (xResources.objId) { | ||
| processed.put(xResources.objId); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+445
to
+512
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The two loops look very similar, maybe we could have an helper function to avoid redundancy.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did try doing that, in one of the earlier versions of the patch, I think this is probably the commit which captures the idea, later though I felt it added too much complexity and reduced readability of the code without significant returns, so I isolated them, let me know if you prefer extracting the common bits though, it should be a minimal effort to go back to that approach |
||
| return false; | ||
| } | ||
|
|
||
| async fetchBuiltInCMap(name) { | ||
| const cachedData = this.builtInCMapCache.get(name); | ||
| if (cachedData) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recently added support for TR2 too