-
Notifications
You must be signed in to change notification settings - Fork 10k
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
Add support for optional marked content. #12095
Conversation
/botio test |
From: Bot.io (Windows)ReceivedCommand cmd_test from @brendandahl received. Current queue size: 0 Live output at: http://54.215.176.217:8877/6ff05971f6f1fd5/output.txt |
From: Bot.io (Linux m4)ReceivedCommand cmd_test from @brendandahl received. Current queue size: 0 Live output at: http://54.67.70.0:8877/48e5f33dc64066f/output.txt |
From: Bot.io (Linux m4)FailedFull output at http://54.67.70.0:8877/48e5f33dc64066f/output.txt Total script time: 26.89 mins
Image differences available at: http://54.67.70.0:8877/48e5f33dc64066f/reftest-analyzer.html#web=eq.log |
From: Bot.io (Windows)FailedFull output at http://54.215.176.217:8877/6ff05971f6f1fd5/output.txt Total script time: 31.32 mins
Image differences available at: http://54.215.176.217:8877/6ff05971f6f1fd5/reftest-analyzer.html#web=eq.log |
/botio test |
From: Bot.io (Windows)ReceivedCommand cmd_test from @brendandahl received. Current queue size: 0 Live output at: http://54.215.176.217:8877/ef23cf7e4380623/output.txt |
From: Bot.io (Linux m4)ReceivedCommand cmd_test from @brendandahl received. Current queue size: 0 Live output at: http://54.67.70.0:8877/d7647d4e6988ad1/output.txt |
src/core/evaluator.js
Outdated
} else if (isDict(contentProperties)) { | ||
optionalContent = contentProperties; | ||
} else { | ||
throw new Error("Optional content properties malformed."); |
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.
Should be throw new FormatError(...)
, since that's used for errors with the PDF data itself.
src/core/evaluator.js
Outdated
@@ -1224,6 +1232,61 @@ class PartialEvaluator { | |||
throw new FormatError(`Unknown PatternName: ${patternName}`); | |||
} | |||
|
|||
parseMarkedContentProps(contentProperties, resources) { |
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.
Please make this method async
, since the data fetching below (i.e. the Dict.get(...)
calls) could throw which would thus break the OperatorList parsing, and that way you'll be able to (easier) deal with any errors gracefully (relying on the existing ignoreErrors
functionality).
src/core/evaluator.js
Outdated
warn(`Expected name for beginMarkedContentProps arg0=${args[0]}`); | ||
continue; | ||
} | ||
fn = OPS.beginMarkedContentProps; |
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.
This line looks superfluous, since fn === OPS.beginMarkedContentProps
must hold in order for this block to have been entered!?
src/core/obj.js
Outdated
const properties = this.catDict.get("OCProperties"); | ||
if (!properties) { | ||
return null; | ||
} | ||
const groupsData = properties.get("OCGs"); | ||
if (!Array.isArray(groupsData)) { | ||
return null; | ||
} | ||
const groups = []; | ||
const groupRefs = []; | ||
// Ensure all the optional content groups are valid. | ||
for (const groupRef of groupsData) { | ||
if (!isRef(groupRef)) { | ||
continue; | ||
} | ||
groupRefs.push(groupRef); | ||
const group = properties.xref.fetchIfRef(groupRef); | ||
groups.push({ | ||
id: groupRef.toString(), | ||
name: group.get("Name"), | ||
intent: group.get("Intent"), // TODO validate this. | ||
}); | ||
} | ||
const defaultConfig = properties.get("D"); | ||
if (!defaultConfig) { | ||
return null; | ||
} | ||
const config = this._readOptionalContentConfig(defaultConfig, groupRefs); | ||
config.groups = groups; | ||
return config; |
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.
Similar to all other methods here, see e.g. get permissions()
above, please wrap this in try...catch
to prevent breaking errors if data fetching fails (since Dict.get(...) calls could throw).
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.
Will get optionalContentConfig()
always return the same data for a document with Optional Content groups?
If so, please shadow
the return values to avoid having to repeatedly re-parsing this for every single page. (Or at least, please shadow
the return null;
cases.)
src/core/obj.js
Outdated
} | ||
|
||
_readOptionalContentConfig(config, contentGroupRefs) { | ||
// console.log(contentGroupRefs); |
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.
Left-over debugging statement?
src/core/evaluator.js
Outdated
} | ||
fn = OPS.beginMarkedContentProps; | ||
if (args[0].name === "OC") { | ||
args = ["OC", self.parseMarkedContentProps(args[1], resources)]; |
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.
With parseMarkedContentProps
being asynchronous, as suggested above, this would need to become something like this (which thus handles any errors gracefully):
next(
self.parseMarkedContentProps(args[1], resources)
.then(data => {
operatorList.addOp(OPS.beginMarkedContentProps, ["OC", data]);
})
.catch(reason => {
if (reason instanceof AbortException) {
return;
}
if (self.options.ignoreErrors) {
self.handler.send("UnsupportedFeature", {
featureId: /* Some new UNSUPPORTED_FEATURES id */,
});
warn(`getOperatorList - ignoring beginMarkedContentProps: "${reason}".`);
return;
}
throw reason;
})
);
return;
src/core/evaluator.js
Outdated
}; | ||
|
||
if (dict.has("OC")) { | ||
groupOptions.optionalContent = this.parseMarkedContentProps( |
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.
Nit: With parseMarkedContentProps being asynchronous, as suggested below, this would need to be groupOptions.optionalContent = await this.parseMarkedContentProps(
instead.
src/display/canvas.js
Outdated
if (simpleFillText && !accent && this.contentVisible) { | ||
// common case | ||
ctx.fillText(character, scaledX, scaledY); | ||
} else { | ||
} else if (this.contentVisible) { |
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.
It would in my opinion be, a little bit, clearer if you simply enclosed this entire code-block
Lines 1698 to 1717 in 6c39aff
// Only attempt to draw the glyph if it is actually in the embedded font | |
// file or if there isn't a font file so the fallback font is shown. | |
if (glyph.isInFont || font.missingFile) { | |
if (simpleFillText && !accent) { | |
// common case | |
ctx.fillText(character, scaledX, scaledY); | |
} else { | |
this.paintChar(character, scaledX, scaledY, patternTransform); | |
if (accent) { | |
scaledAccentX = scaledX + accent.offset.x / fontSizeScale; | |
scaledAccentY = scaledY - accent.offset.y / fontSizeScale; | |
this.paintChar( | |
accent.fontChar, | |
scaledAccentX, | |
scaledAccentY, | |
patternTransform | |
); | |
} | |
} | |
} |
in
if (this.contentVisible) { ... }
rather than "inlining" these checks.
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.
Also, unless I'm mistaken there's no similar checks in the showType3Text
below. Don't you need to account for this.contentVisible
there as well?
src/display/api.js
Outdated
if (this._canvas) { | ||
if (canvasInRendering.has(this._canvas)) { | ||
this.capability.reject( | ||
new Error( | ||
"Cannot use the same canvas during multiple render() operations. " + | ||
"Use different canvas or ensure previous operations were " + | ||
"cancelled or completed." | ||
) | ||
); | ||
} else { | ||
canvasInRendering.add(this._canvas); | ||
} | ||
} |
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.
Which test-case required moving this code, and is there another way to deal with that?
(Since the commit message says: - Reject the InternalRenderTask earlier now that InitializeGraphics is waits for another promise.
)
I've not actually tested it, but based on reading the code I'm not entirely convinced that moving this code will actually do the right thing in general.
Currently initializeGraphics
will throw
Lines 2668 to 2672 in 6c39aff
throw new Error( | |
"Cannot use the same canvas during multiple render() operations. " + | |
"Use different canvas or ensure previous operations were " + | |
"cancelled or completed." | |
); |
Lines 1118 to 1121 in 6c39aff
internalRenderTask.initializeGraphics(transparency); | |
internalRenderTask.operatorListChanged(); | |
}) | |
.catch(complete); |
Lines 1054 to 1081 in 6c39aff
const complete = error => { | |
const i = intentState.renderTasks.indexOf(internalRenderTask); | |
if (i >= 0) { | |
intentState.renderTasks.splice(i, 1); | |
} | |
// Attempt to reduce memory usage during *printing*, by always running | |
// cleanup once rendering has finished (regardless of cleanupAfterRender). | |
if (this.cleanupAfterRender || renderingIntent === "print") { | |
this.pendingCleanup = true; | |
} | |
this._tryCleanup(); | |
if (error) { | |
internalRenderTask.capability.reject(error); | |
this._abortOperatorList({ | |
intentState, | |
reason: error, | |
}); | |
} else { | |
internalRenderTask.capability.resolve(); | |
} | |
if (this._stats) { | |
this._stats.timeEnd("Rendering"); | |
this._stats.timeEnd("Overall"); | |
} | |
}; |
With your changes here, it doesn't seem like you're actually guaranteed that complete
is ever called correctly!?
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.
It was the test that calls render twice. It doesn't seem to be failing anymore. This code is quite the mix of callbacks and old style promises.
From: Bot.io (Linux m4)FailedFull output at http://54.67.70.0:8877/d7647d4e6988ad1/output.txt Total script time: 26.87 mins
Image differences available at: http://54.67.70.0:8877/d7647d4e6988ad1/reftest-analyzer.html#web=eq.log |
From: Bot.io (Windows)FailedFull output at http://54.215.176.217:8877/ef23cf7e4380623/output.txt Total script time: 30.57 mins
Image differences available at: http://54.215.176.217:8877/ef23cf7e4380623/reftest-analyzer.html#web=eq.log |
src/core/obj.js
Outdated
continue; | ||
} | ||
groupRefs.push(groupRef); | ||
const group = properties.xref.fetchIfRef(groupRef); |
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 missed this previously: You want this.xref.fetchIfRef(groupRef);
instead here, since this.xref
is guaranteed to be defined whereas a Dict
instance may not always have an xref
property.
src/core/obj.js
Outdated
if (ex instanceof MissingDataException) { | ||
throw ex; | ||
} | ||
warn("Unable to optional content config. " + ex); |
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.
Missing e.g. the word "read" here?
warn(`Unable to read optional content config: ${ex}`);
src/core/obj.js
Outdated
name: group.get("Name"), | ||
intent: group.get("Intent"), // TODO validate this. |
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.
Since this data is being sent between threads, whatever data this contains much be compatible with the "structured clone algorithm". Hence you may want to add at least some basic validation of these two properties since otherwise a corrupt PDF document might refuse to render altogether.
src/core/evaluator.js
Outdated
return { | ||
type: optionalContentType, | ||
ids: groupIds, | ||
policy: optionalContent.get("P"), |
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.
Since this data is being sent between threads, whatever data this contains much be compatible with the "structured clone algorithm". Hence you may want to add at least some basic validation of the P
property since otherwise a corrupt PDF document might refuse to render altogether.
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.
According to the specification, https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G7.3883825, this should be a Name
. In the OptionalContentConfig
class you're accessing them as if they were mere strings, which I don't think will work!?
I believe that you'll need to either validate that it's a name and (essentially) return optionalContent.get("P").name,
here, or possibly return the name as-is a and fix the lookup in OptionalContentConfig
instead.
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 thought there was a test PDF for this, but appears there aren't any with a policy attribute. If I have some time I'll try to make some more tests.
src/core/obj.js
Outdated
name: config.get("Name"), | ||
creator: config.get("Creator"), | ||
baseState: config.get("BaseState"), | ||
on: parseOnOff(config.get("ON")), | ||
off: parseOnOff(config.get("OFF")), |
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.
Since this data is being sent between threads, whatever data this contains much be compatible with the "structured clone algorithm". Hence you may want to add at least some basic validation of the Name
/Creator
/BaseState
properties since otherwise a corrupt PDF document might refuse to render altogether.
src/display/api.js
Outdated
return this.messageHandler | ||
.sendWithPromise("GetOptionalContentConfig", null) | ||
.then(results => { | ||
const config = new OptionalContentConfig(); |
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.
Just wondering: Any particular reason to not simply pass the results
when creating the OptionalContentConfig
instance, and thus essentially inline the initialize
method in the constructor?
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 had plans of doing some unit testing this differently. Not going to do that now, so I'll merge it.
src/core/obj.js
Outdated
const group = properties.xref.fetchIfRef(groupRef); | ||
groups.push({ | ||
id: groupRef.toString(), | ||
name: group.get("Name"), |
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.
Since this is, I believe, a string; don't you need to wrap it in stringToPDFString()
to avoid issues?
Edit: Issue #7283 is one example which requires this.
src/core/obj.js
Outdated
name: config.get("Name"), | ||
creator: config.get("Creator"), |
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.
Since these are, I believe, strings; don't you need to wrap them in stringToPDFString()
to avoid issues?
Edit: Issue #7283 is one example which requires this.
src/core/obj.js
Outdated
return { | ||
name: config.get("Name"), | ||
creator: config.get("Creator"), | ||
baseState: config.get("BaseState"), |
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.
According to the specification, https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G7.3883884, this should be a Name
. In the OptionalContentConfig
class you're accessing them as if they were mere strings, which I don't think will work!?
I believe that you'll need to either validate that it's a name and (essentially) return config.get("BaseState").name,
here, or possibly return the name as-is a and fix the lookup in OptionalContentConfig
instead.
src/core/evaluator.js
Outdated
return { | ||
type: optionalContentType, | ||
ids: groupIds, | ||
policy: optionalContent.get("P"), |
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.
According to the specification, https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G7.3883825, this should be a Name
. In the OptionalContentConfig
class you're accessing them as if they were mere strings, which I don't think will work!?
I believe that you'll need to either validate that it's a name and (essentially) return optionalContent.get("P").name,
here, or possibly return the name as-is a and fix the lookup in OptionalContentConfig
instead.
src/display/canvas.js
Outdated
@@ -790,6 +794,15 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { | |||
ctx.drawImage(mask, 0, 0); | |||
} | |||
|
|||
function isContentVisible(stack) { |
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.
Given that every call-sites seem to pass in this.markedContentStack
manually, any reason not to make this a "normal" method and simply handle the stack internally instead?
E.g. something like this
_computeContentVisible() {
const state = this.markedContentStack;
for (let i = stack.length - 1; i >= 0; i--) {
if (!stack[i].visible) {
return false;
}
}
return true;
},
and the call-sites could then simply read this.contentVisible = this._computeContentVisible();
@@ -1695,6 +1755,45 @@ class PartialEvaluator { | |||
// e.g. as done in https://github.com/mozilla/pdf.js/pull/6266, | |||
// but doing so is meaningless without knowing the semantics. | |||
continue; | |||
case OPS.beginMarkedContentProps: | |||
if (!isName(args[0])) { | |||
warn(`Expected name for beginMarkedContentProps arg0=${args[0]}`); |
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.
Would it actually make sense to simply move this check into the next
handling below and throw a FormatError
instead?
I.e. something similar to the next
code that's used e.g. when parsing OPS.paintXObject
earlier in this file.
Really sorry about the back-and-forth in some of these comments, but it's quite a lot of added code/functionality to "unpack" here and at first glance I unfortunately overlooked some of the finer details.
The overall functionality seem to work very nicely though :-)
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 started to do do this, but sometimes the marked content isn't an "OC" which then causes us to wait async when we really don't need to.
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.
r=me, with the commits squashed and all tests passing.
src/core/obj.js
Outdated
const defaultConfig = properties.get("D"); | ||
if (!defaultConfig) { | ||
return shadow(this, "optionalContentConfig", null); | ||
} |
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.
Nit: Would it make sense to move this to occur earlier in the method, since the groupsData
parsing above seems pointless in the !defaultConfig
case?
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.
Minor comments, also looks good to me after this.
src/core/evaluator.js
Outdated
|
||
let expression = null; | ||
if (optionalContent.get("VE")) { | ||
// TODO support content epxressions. |
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.
Nit: expressions
src/core/worker.js
Outdated
@@ -485,6 +485,13 @@ class WorkerMessageHandler { | |||
return pdfManager.ensureCatalog("documentOutline"); | |||
}); | |||
|
|||
handler.on( | |||
"GetOptionalContentConfig", | |||
function wphSetupGetOptionalContentConfig(data) { |
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.
This handler can be shortened a bit by using an anonymous function like the one below.
src/display/api.js
Outdated
/** | ||
* @returns {Promise} A promise that is resolved with an | ||
* {OptionalContentConfig} that will have all the optional content groups (if | ||
* the document has any). @see {OptionalContentConfig} |
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.
Shouldn't @see
be on a new line for JSDoc?
src/display/api.js
Outdated
* @property {Promise} [optionalContentConfigPromise] - A promise that should | ||
* resolve with an {OptionalContentConfig} created from | ||
* PDFDocumentProxy.getOptionalContentConfig. If null, the | ||
* config will automatically fetched with the default |
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.
Nit: automatically be fetched
@@ -0,0 +1,107 @@ | |||
/* Copyright 2012 Mozilla Foundation |
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.
Nit: 2020
/botio test |
From: Bot.io (Linux m4)ReceivedCommand cmd_test from @brendandahl received. Current queue size: 0 Live output at: http://54.67.70.0:8877/871b55504c08464/output.txt |
From: Bot.io (Windows)ReceivedCommand cmd_test from @brendandahl received. Current queue size: 0 Live output at: http://54.215.176.217:8877/d3650f17b24da81/output.txt |
From: Bot.io (Linux m4)FailedFull output at http://54.67.70.0:8877/871b55504c08464/output.txt Total script time: 26.85 mins
Image differences available at: http://54.67.70.0:8877/871b55504c08464/reftest-analyzer.html#web=eq.log |
From: Bot.io (Windows)FailedFull output at http://54.215.176.217:8877/d3650f17b24da81/output.txt Total script time: 30.81 mins
Image differences available at: http://54.215.176.217:8877/d3650f17b24da81/reftest-analyzer.html#web=eq.log |
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.
According to the test logs, there's two actual errors thrown during rendering:
TEST-UNEXPECTED-FAIL | test failed issue7769 | in firefox | page1 round 1 | render : Error: Optional content group must be found.
TEST-UNEXPECTED-FAIL | test failed issue7769 | in chrome | page1 round 1 | render : Error: Optional content group must be found.
Unfortunately, it appears that this particular error occurs in such a way that the failures aren't displayed in the "Reftest analyzer" (and I thus missed it previously).
src/core/evaluator.js
Outdated
}; | ||
|
||
if (dict.has("OC")) { |
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.
All form XObjects can have an OC
entry, not just transparency groups that have a Group
entry. Then you may need to pass the parsed OC
value also to paintFormXObjectBegin/End
and handle it in canvas.js.
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.
Good catch, I'll just insert a beginMarkedContentProps
before the form object so I don't have to handle this for both.
You should push a Line 2444 in d69fb44
"EMC" is the end of both "BMC" and "BDC" sections. "BMC" is not related to optional content but some PDFs may use it and the marked content stack might go wrong. |
@brendandahl Given that this PR seems really close to being done, since there's just a few more comments to fix (such that all tests pass), do you perhaps have time to fix the remaining things such that this can land? I've been playing around with this patch a fair bit locally[1], and it seems to work really well in practice :-) [1] I've got, more-or-less, finished patches for the viewer integration. |
cbec96b
to
5c370a5
Compare
/botio test |
From: Bot.io (Linux m4)ReceivedCommand cmd_test from @brendandahl received. Current queue size: 0 Live output at: http://54.67.70.0:8877/48c34ec27dcef8c/output.txt |
From: Bot.io (Windows)ReceivedCommand cmd_test from @brendandahl received. Current queue size: 0 Live output at: http://54.215.176.217:8877/0f7ae373a4b37f7/output.txt |
From: Bot.io (Linux m4)FailedFull output at http://54.67.70.0:8877/48c34ec27dcef8c/output.txt Total script time: 26.94 mins
Image differences available at: http://54.67.70.0:8877/48c34ec27dcef8c/reftest-analyzer.html#web=eq.log |
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'm leaving the review for @Snuffleupagus, but I'm just checking the comments/types here. For context, we have been working a lot on that the last few days in #12102 and follow-up pull requests. The main priority was to get TypeScript definitions generated automatically from the source code and to get the comments in a consistent format, so this requires a small number of changes here to make sure that once #12156 lands everything is still consistent and the generated types are correct. Thanks!
src/display/api.js
Outdated
@@ -788,6 +789,16 @@ class PDFDocumentProxy { | |||
return this._transport.getOutline(); | |||
} | |||
|
|||
/** | |||
* @see {OptionalContentConfig} | |||
* @returns {Promise<OptionalContentConfig>} A promise that is resolved with |
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 think this should be @returns {Promise<OptionalContentConfig | null>}
looking at the catalog code. Moreover, @link
should be used to refer to other types/code and it should be formatted in the standard way. In summary, this is my suggestion based on the existing comments:
/**
* @returns {Promise<OptionalContentConfig | null>} A promise that is resolved
* with an {@link OptionalContentConfig} that will have all the optional
* content groups, or `null` if the document does not have any.
*/
src/display/api.js
Outdated
@@ -788,6 +789,16 @@ class PDFDocumentProxy { | |||
return this._transport.getOutline(); | |||
} | |||
|
|||
/** | |||
* @see {OptionalContentConfig} |
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.
This line can be removed since the type is in the @returns
already so JSDoc will pick it up (we don't have this elsewhere too).
@@ -965,6 +976,11 @@ class PDFDocumentProxy { | |||
* image). The default value is 'rgb(255,255,255)'. | |||
* @property {Object} [annotationStorage] - Storage for annotation data in | |||
* forms. | |||
* @property {Promise} [optionalContentConfigPromise] - A promise that should |
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.
Once #12156 lands, this should be changed to mention the promise type and to have each line start with two spaces as per the standard.
From: Bot.io (Windows)FailedFull output at http://54.215.176.217:8877/0f7ae373a4b37f7/output.txt Total script time: 31.48 mins
Image differences available at: http://54.215.176.217:8877/0f7ae373a4b37f7/reftest-analyzer.html#web=eq.log |
By the way, the unit test failures (and most likely the reference test failures as well) are known intermittents and are tracked in #12123 (the Windows one is a new one that I now mentioned there). |
/botio test |
From: Bot.io (Linux m4)ReceivedCommand cmd_test from @Snuffleupagus received. Current queue size: 0 Live output at: http://54.67.70.0:8877/fc2151d724bc8a7/output.txt |
From: Bot.io (Windows)ReceivedCommand cmd_test from @Snuffleupagus received. Current queue size: 0 Live output at: http://54.215.176.217:8877/eacea1f25df0912/output.txt |
From: Bot.io (Linux m4)FailedFull output at http://54.67.70.0:8877/fc2151d724bc8a7/output.txt Total script time: 27.04 mins
Image differences available at: http://54.67.70.0:8877/fc2151d724bc8a7/reftest-analyzer.html#web=eq.log |
From: Bot.io (Windows)FailedFull output at http://54.215.176.217:8877/eacea1f25df0912/output.txt Total script time: 32.10 mins
Image differences available at: http://54.215.176.217:8877/eacea1f25df0912/reftest-analyzer.html#web=eq.log |
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.
Looks good to me, thank you!
src/display/canvas.js
Outdated
@@ -2446,15 +2496,28 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { | |||
}, | |||
beginMarkedContent: function CanvasGraphics_beginMarkedContent(tag) { | |||
// TODO Marked content. |
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.
Nit: Remove this comment?
Add a new method to the API to get the optional content configuration. Add a new render task param that accepts the above configuration. For now, the optional content is not controllable by the user in the viewer, but renders with the default configuration in the PDF. All of the test files added exhibit different uses of optional content. Fixes mozilla#269. Fix test to work with optional content. - Change the stopAtErrors test to ensure the operator list has something, instead of asserting the exact number of operators.
/botio makeref |
From: Bot.io (Linux m4)ReceivedCommand cmd_makeref from @brendandahl received. Current queue size: 0 Live output at: http://54.67.70.0:8877/540ff90a3e49b5e/output.txt |
From: Bot.io (Windows)ReceivedCommand cmd_makeref from @brendandahl received. Current queue size: 0 Live output at: http://54.215.176.217:8877/20d3f22d0d860ed/output.txt |
From: Bot.io (Linux m4)SuccessFull output at http://54.67.70.0:8877/540ff90a3e49b5e/output.txt Total script time: 25.47 mins
|
From: Bot.io (Windows)SuccessFull output at http://54.215.176.217:8877/20d3f22d0d860ed/output.txt Total script time: 27.44 mins
|
Add a new method to the API to get the optional content configuration. Add
a new render task param that accepts the above configuration.
For now, the optional content is not controllable by the user in
the viewer, but renders with the default configuration in the PDF.
All of the test files added exhibit different uses of optional content.
Fixes #269.