-
Notifications
You must be signed in to change notification settings - Fork 10.2k
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
Rotate annotations based on the MK::R value (bug 1675139) #15060
Conversation
calixteman
commented
Jun 19, 2022
- it aims to fix: https://bugzilla.mozilla.org/show_bug.cgi?id=1675139;
- An annotation can be rotated (counterclockwise);
- the rotation can be set in using JS.
14c609a
to
73a05e5
Compare
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.
Does this perhaps also fix issue #9596?
src/core/annotation.js
Outdated
this.rotation = 0; | ||
if (mk instanceof Dict) { | ||
let angle = mk.get("R") || 0; | ||
if (angle !== 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.
Let's ensure that the angle is also an integer, since otherwise none of the code below makes sense.
if (angle !== 0) { | |
if (Number.isInteger(angle) && angle !== 0) { |
src/core/annotation.js
Outdated
// If the angle is negative then angle % 360 is still negative. | ||
angle = (360 + (angle % 360)) % 360; |
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 finding this a bit less clear than what we have in other parts of the code-base, see e.g.
pdf.js/src/display/display_utils.js
Lines 179 to 183 in 45de73b
// Normalize the rotation, by clamping it to the [0, 360) range. | |
rotation %= 360; | |
if (rotation < 0) { | |
rotation += 360; | |
} |
Lines 509 to 513 in 45de73b
// Normalize the rotation, by clamping it to the [0, 360) range. | |
rotation %= 360; | |
if (rotation < 0) { | |
rotation += 360; | |
} |
src/core/annotation.js
Outdated
case 270: | ||
return [0, -1, 1, 0, 0, height]; | ||
default: | ||
return [1, 0, 0, 1, 0, 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.
This should be unreachable, given the if (rotation === 0) { ... }
block above, right?
Hence I'd suggest replacing this with:
return [1, 0, 0, 1, 0, 0]; | |
throw new Error("Invalid rotation"); |
src/display/annotation_layer.js
Outdated
setRotation(angle, container) { | ||
container ||= this.container; |
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.
Can't we just do the following?
setRotation(angle, container) { | |
container ||= this.container; | |
setRotation(angle, container = this.container) { |
src/scripting_api/field.js
Outdated
if (angle % 90 !== 0) { | ||
throw new Error("Invalid rotation: must be a multiple of 90"); | ||
} | ||
this._rotation = (360 + (angle % 360)) % 360; |
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.
As above, regarding the normalization of the rotation angle.
73a05e5
to
b4e3f79
Compare
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.
src/core/annotation.js
Outdated
// If the angle is negative then angle % 360 is still negative. | ||
angle %= 360; | ||
angle = angle >= 0 ? angle : 360 + angle; |
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.
Can't we just do exactly what's done elsewhere in the code-base, since re-assigning the value when it's non-negative just feels unnecessary?
// If the angle is negative then angle % 360 is still negative. | |
angle %= 360; | |
angle = angle >= 0 ? angle : 360 + angle; | |
// Normalize the rotation, by clamping it to the [0, 360) range. | |
angle %= 360; | |
if (angle < 0) { | |
angle += 360; | |
} |
b4e3f79
to
3bebf31
Compare
/botio test |
From: Bot.io (Linux m4)ReceivedCommand cmd_test from @calixteman received. Current queue size: 0 Live output at: http://54.241.84.105:8877/1ceb5d3b61383b5/output.txt |
From: Bot.io (Windows)ReceivedCommand cmd_test from @calixteman received. Current queue size: 0 Live output at: http://54.193.163.58:8877/13263b2150144ac/output.txt |
From: Bot.io (Linux m4)FailedFull output at http://54.241.84.105:8877/1ceb5d3b61383b5/output.txt Total script time: 23.40 mins
Image differences available at: http://54.241.84.105:8877/1ceb5d3b61383b5/reftest-analyzer.html#web=eq.log |
From: Bot.io (Windows)FailedFull output at http://54.193.163.58:8877/13263b2150144ac/output.txt Total script time: 24.89 mins
Image differences available at: http://54.193.163.58:8877/13263b2150144ac/reftest-analyzer.html#web=eq.log |
3bebf31
to
715d61d
Compare
/botio test |
From: Bot.io (Linux m4)ReceivedCommand cmd_test from @calixteman received. Current queue size: 0 Live output at: http://54.241.84.105:8877/24f1c535738c29a/output.txt |
From: Bot.io (Windows)ReceivedCommand cmd_test from @calixteman received. Current queue size: 0 Live output at: http://54.193.163.58:8877/3de612af212205b/output.txt |
From: Bot.io (Linux m4)FailedFull output at http://54.241.84.105:8877/24f1c535738c29a/output.txt Total script time: 24.16 mins
Image differences available at: http://54.241.84.105:8877/24f1c535738c29a/reftest-analyzer.html#web=eq.log |
From: Bot.io (Windows)FailedFull output at http://54.193.163.58:8877/3de612af212205b/output.txt Total script time: 25.24 mins
Image differences available at: http://54.193.163.58:8877/3de612af212205b/reftest-analyzer.html#web=eq.log |
715d61d
to
4d5ab84
Compare
/botio test |
From: Bot.io (Linux m4)ReceivedCommand cmd_test from @calixteman received. Current queue size: 0 Live output at: http://54.241.84.105:8877/e737b527aafe572/output.txt |
From: Bot.io (Windows)ReceivedCommand cmd_test from @calixteman received. Current queue size: 0 Live output at: http://54.193.163.58:8877/d55981fc023da10/output.txt |
From: Bot.io (Linux m4)FailedFull output at http://54.241.84.105:8877/e737b527aafe572/output.txt Total script time: 14.58 mins
Image differences available at: http://54.241.84.105:8877/e737b527aafe572/reftest-analyzer.html#web=eq.log |
From: Bot.io (Windows)FailedFull output at http://54.193.163.58:8877/d55981fc023da10/output.txt Total script time: 28.40 mins
Image differences available at: http://54.193.163.58:8877/d55981fc023da10/reftest-analyzer.html#web=eq.log |
4d5ab84
to
863b4d0
Compare
/botio browsertest |
From: Bot.io (Linux m4)ReceivedCommand cmd_browsertest from @calixteman received. Current queue size: 1 Live output at: http://54.241.84.105:8877/e6f7dd620a48d4b/output.txt |
From: Bot.io (Windows)ReceivedCommand cmd_browsertest from @calixteman received. Current queue size: 0 Live output at: http://54.193.163.58:8877/f1d9074371d6af0/output.txt |
From: Bot.io (Windows)FailedFull output at http://54.193.163.58:8877/f1d9074371d6af0/output.txt Total script time: 21.26 mins
Image differences available at: http://54.193.163.58:8877/f1d9074371d6af0/reftest-analyzer.html#web=eq.log |
From: Bot.io (Linux m4)FailedFull output at http://54.241.84.105:8877/e6f7dd620a48d4b/output.txt Total script time: 21.89 mins
Image differences available at: http://54.241.84.105:8877/e6f7dd620a48d4b/reftest-analyzer.html#web=eq.log |
@Snuffleupagus, would you mind to review this patch again ? |
test/integration/scripting_spec.js
Outdated
await closePages(pages); | ||
}); | ||
|
||
it("must data-annotation-attribute has the correct value", async () => { |
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.
Did you mean something like the following here?
it("must data-annotation-attribute has the correct value", async () => { | |
it("must check that data-annotation-rotation is correct", async () => { |
src/core/annotation.js
Outdated
if (mk instanceof Dict) { | ||
let angle = mk.get("R") || 0; | ||
if (Number.isInteger(angle) && angle !== 0) { | ||
// If the angle is negative then angle % 360 is still negative. |
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 comment can probably be removed.
src/core/annotation.js
Outdated
} | ||
} | ||
|
||
getRotationMatrix(annotationStorage) { |
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.
Is this necessary for all Annotation-types, or can we perhaps move it into the WidgetAnnotation
-class instead?
src/core/annotation.js
Outdated
if (rotation || this.borderColor || this.backgroundColor) { | ||
const MK = new Dict(xref); | ||
MK.set("R", rotation); | ||
MK.set("BC", getPDFRgbArray(this.borderColor)); | ||
MK.set("BG", getPDFRgbArray(this.backgroundColor)); | ||
dict.set("MK", MK); | ||
} |
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 code is repeated multiple times, how about adding a helper-method on the WidgetAnnotation
-class that returns a MK
-dict when that's necessary?
Also, do we need to populate some of the dictionary entries with empty Arrays (and is that even generally correct)?
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.
Maybe if you add a method like this, on the WidgetAnnotation
-class:
_getMKDict(rotation) {
const mk = new Dict(null); // `null` can probably be used here, since none of the data below will be a /Ref
if (rotation) {
mk.set("R", rotation);
}
if (this.borderColor) {
mk.set("BC", Array.from(this.borderColor).map(c => c / 255));
}
if (this.backgroundColor) {
mk.set("BG", Array.from(this.backgroundColor).map(c => c / 255));
}
return mk.size > 0 ? mk : null;
}
and then you can simply do (here and elsewhere):
if (rotation || this.borderColor || this.backgroundColor) { | |
const MK = new Dict(xref); | |
MK.set("R", rotation); | |
MK.set("BC", getPDFRgbArray(this.borderColor)); | |
MK.set("BG", getPDFRgbArray(this.backgroundColor)); | |
dict.set("MK", MK); | |
} | |
const maybeMK = this._getMKDict(rotation); | |
if (maybeMK) { | |
dict.set("MK", maybeMK); | |
} |
src/core/annotation.js
Outdated
@@ -721,13 +778,24 @@ class Annotation { | |||
} | |||
} | |||
|
|||
getBorderAndBackgroundAppearances() { | |||
getBorderAndBackgroundAppearances(annotationStorage) { |
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 is existing code, but the question above (regarding WidgetAnnotation
) applies here as well.
src/core/annotation.js
Outdated
} | ||
|
||
if (rotation === 0) { | ||
return [1, 0, 0, 1, 0, 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.
I don't know how much it matters, but you may want to return IDENTITY_MATRIX
here (can be imported from src/shared/util.js
)?
src/core/annotation.js
Outdated
if (rotationMatrix[0] !== 1) { | ||
// The matrix isn't the identity one. |
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 not sure how much it matters here, but with a previous comment implemented you could just do the following here:
if (rotationMatrix[0] !== 1) { | |
// The matrix isn't the identity one. | |
if (rotationMatrix === IDENTITY_MATRIX) { |
src/core/annotation.js
Outdated
@@ -2220,6 +2343,17 @@ class ButtonWidgetAnnotation extends WidgetAnnotation { | |||
: this.uncheckedAppearance; | |||
if (appearance) { | |||
const savedAppearance = this.appearance; | |||
const savedMatrix = appearance.dict.getArray("Matrix") || [ | |||
1, 0, 0, 1, 0, 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.
Again, you could maybe just fallback on IDENTITY_MATRIX
here?
src/core/annotation.js
Outdated
if (rotation || this.borderColor || this.backgroundColor) { | ||
const MK = new Dict(evaluator.xref); | ||
MK.set("R", rotation); | ||
MK.set("BC", getPDFRgbArray(this.borderColor)); | ||
MK.set("BG", getPDFRgbArray(this.backgroundColor)); | ||
dict.set("MK", MK); | ||
} | ||
|
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 see previous comments.
src/core/annotation.js
Outdated
if (rotation || this.borderColor || this.backgroundColor) { | ||
const MK = new Dict(evaluator.xref); | ||
MK.set("R", rotation); | ||
MK.set("BC", getPDFRgbArray(this.borderColor)); | ||
MK.set("BG", getPDFRgbArray(this.backgroundColor)); | ||
dict.set("MK", MK); | ||
} | ||
|
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 see previous comments.
863b4d0
to
34ba918
Compare
/botio test |
From: Bot.io (Linux m4)ReceivedCommand cmd_test from @calixteman received. Current queue size: 0 Live output at: http://54.241.84.105:8877/3273fbcaed07a30/output.txt |
From: Bot.io (Windows)ReceivedCommand cmd_test from @calixteman received. Current queue size: 0 Live output at: http://54.193.163.58:8877/d8a3b1614b4457a/output.txt |
From: Bot.io (Linux m4)FailedFull output at http://54.241.84.105:8877/3273fbcaed07a30/output.txt Total script time: 26.20 mins
Image differences available at: http://54.241.84.105:8877/3273fbcaed07a30/reftest-analyzer.html#web=eq.log |
From: Bot.io (Windows)FailedFull output at http://54.193.163.58:8877/d8a3b1614b4457a/output.txt Total script time: 28.40 mins
Image differences available at: http://54.193.163.58:8877/d8a3b1614b4457a/reftest-analyzer.html#web=eq.log |
The "regression" is due to a rotation of 270deg on a checkbox and this one is not exactly a square, hence the change, so it's an improvement. |
src/core/annotation.js
Outdated
@@ -1535,20 +1596,42 @@ class WidgetAnnotation extends Annotation { | |||
); | |||
} | |||
|
|||
_getMKDict(rotation) { | |||
const mk = new Dict(null); // `null` can probably be used here, since none of the data below will be a /Ref |
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 remove the comment, since I only included it to explain my reasoning as part of the review comment.
- it aims to fix: https://bugzilla.mozilla.org/show_bug.cgi?id=1675139; - An annotation can be rotated (counterclockwise); - the rotation can be set in using JS.
34ba918
to
cdc58b7
Compare
/botio makeref |
From: Bot.io (Windows)ReceivedCommand cmd_makeref from @calixteman received. Current queue size: 2 Live output at: http://54.193.163.58:8877/88023865608c3bd/output.txt |
From: Bot.io (Linux m4)ReceivedCommand cmd_makeref from @calixteman received. Current queue size: 1 Live output at: http://54.241.84.105:8877/b8be093142b6744/output.txt |
From: Bot.io (Linux m4)SuccessFull output at http://54.241.84.105:8877/b8be093142b6744/output.txt Total script time: 22.92 mins
|
From: Bot.io (Windows)SuccessFull output at http://54.193.163.58:8877/88023865608c3bd/output.txt Total script time: 22.33 mins
|