Skip to content
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

Prevent TypeError: views[index] is undefined being throw in getVisibleElements when the viewer, or all pages, are hidden #10443

Merged
merged 3 commits into from
Jan 13, 2019

Conversation

Snuffleupagus
Copy link
Collaborator

@Snuffleupagus Snuffleupagus commented Jan 12, 2019

Previously a couple of different attempts at fixing this problem has been rejected, given how crucial this code is for the correct function of the viewer, since no one has thus far provided any evidence that the problem actually affects the default viewer[1] nor an example using the viewer components directly (without another library on top).
The fact that none of the prior patches contained even a simple unit-test probably contributed to the unwillingness of a reviewer to sign off on the suggested changes.

However, it turns out that it's possible to create a reduced test-case, using the default viewer, that demonstrates the error[2]. Since this utilizes a hidden <iframe>, please note that this error will thus affect Firefox as well.
Note that while errors are thrown when the hidden <iframe> loads, the default viewer doesn't break completely since rendering does start working once the <iframe> becomes visible (although the errors do break the initial Toolbar state).

Before making any changes here, I carefully read through not just the immediately relevant code but also the rendering code in the viewer (given it's dependence on getVisibleElements). After concluding that the changes should be safe in general, the default viewer was tested without any issues found. (The above being much easier with significant prior experience of working with the viewer code.)
Finally the patch also adds new unit-tests, one of which explicitly triggers the relevant code-path and will thus fail with the current master branch.

This patch also makes PDFViewerApplication slightly more robust against errors during document opening, to ensure that viewer/document initialization always completes as expected.
Please keep in mind that even though this patch prevents an error in getVisibleElements, it's still not possible to set the initial position/zoom level/sidebar view etc. when the viewer is hidden since rendering and scrolling is completely dependent[3] on being able to actually access the DOM elements.

/cc @timvandermeij


[1] And hence the PDF Viewer that's built-in to Firefox.

[2] Copy the HTML code below and save it as iframe.html, and place the file in the web/ folder. Then start the server, with gulp server, and navigate to http://localhost:8888/web/iframe.html

<!DOCTYPE html>
<html>
  <head>
    <title>Iframe test</title>

    <script>
      window.onload = function() {
        const button = document.getElementById('button1');
        const frame = document.getElementById('frame1');

        button.addEventListener('click', function(evt) {
          frame.hidden = !frame.hidden;
        });
      };
    </script>
  </head>

  <body>
    <button id="button1">Toggle iframe</button>
    <br>
    <iframe id="frame1" width="800" height="600" src="http://localhost:8888/web/viewer.html" hidden="true"></iframe>
  </body>
</html>

[3] This is an old, pre-exisiting, issue that's not relevant to this patch as such (and it's already being tracked elsewhere).

@pdfjsbot
Copy link

From: Bot.io (Windows)


Received

Command cmd_unittest from @Snuffleupagus received. Current queue size: 0

Live output at: http://54.215.176.217:8877/c7ce38cf5bbca40/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Received

Command cmd_unittest from @Snuffleupagus received. Current queue size: 0

Live output at: http://54.67.70.0:8877/e8eab42085e7557/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Success

Full output at http://54.67.70.0:8877/e8eab42085e7557/output.txt

Total script time: 2.36 mins

  • Unit Tests: Passed

@pdfjsbot
Copy link

From: Bot.io (Windows)


Success

Full output at http://54.215.176.217:8877/c7ce38cf5bbca40/output.txt

Total script time: 4.84 mins

  • Unit Tests: Passed

With modern JavaScript supporting block-scoped variables, it's no longer necessary to have large numbers of top-level variable definitions (especially when all variables are, implicitly, set to `undefined`).

Besides moving variable definintions, a number of them are also converted to `const` to help ensure that they cannot be *accidentally* modified in the code.
Finally, the `views.length` calculation is now cached *once* rather than being re-computed multiple times.
…ibleElements` when the viewer, or all pages, are hidden

Previously a couple of different attempts at fixing this problem has been rejected, given how *crucial* this code is for the correct function of the viewer, since no one has thus far provided any evidence that the problem actually affects the default viewer[1] nor an example using the viewer components directly (without another library on top).
The fact that none of the prior patches contained even a *simple* unit-test probably contributed to the unwillingness of a reviewer to sign off on the suggested changes.

However, it turns out that it's possible to create a reduced test-case, using the default viewer, that demonstrates the error[2]. Since this utilizes a hidden `<iframe>`, please note that this error will thus affect Firefox as well.
Note that while errors are thrown when the hidden `<iframe>` loads, the default viewer doesn't break completely since rendering does start working once the `<iframe>` becomes visible (although the errors do break the initial Toolbar state).

Before making any changes here, I carefully read through not just the immediately relevant code but also the rendering code in the viewer (given it's dependence on `getVisibleElements`). After concluding that the changes should be safe in general, the default viewer was tested without any issues found. (The above being much easier with significant prior experience of working with the viewer code.)
Finally the patch also adds new unit-tests, one of which explicitly triggers the relevant code-path and will thus fail with the current `master` branch.

This patch also makes `PDFViewerApplication` slightly more robust against errors during document opening, to ensure that viewer/document initialization always completes as expected.
Please keep in mind that even though this patch prevents an error in `getVisibleElements`, it's still not possible to set the initial position/zoom level/sidebar view etc. when the viewer is hidden since rendering and scrolling is completely dependent[3] on being able to actually access the DOM elements.

---
[1] And hence the PDF Viewer that's built-in to Firefox.

[2] Copy the HTML code below and save it as `iframe.html`, and place the file in the `web/` folder. Then start the server, with `gulp server`, and navigate to http://localhost:8888/web/iframe.html

```html
<!DOCTYPE html>
<html>
  <head>
    <title>Iframe test</title>

    <script>
      window.onload = function() {
        const button = document.getElementById('button1');
        const frame = document.getElementById('frame1');

        button.addEventListener('click', function(evt) {
          frame.hidden = !frame.hidden;
        });
      };
    </script>
  </head>

  <body>
    <button id="button1">Toggle iframe</button>
    <br>
    <iframe id="frame1" width="800" height="600" src="http://localhost:8888/web/viewer.html" hidden="true"></iframe>
  </body>
</html>
```

[3] This is an old, pre-exisiting, issue that's not relevant to this patch as such (and it's already being tracked elsewhere).
@Snuffleupagus Snuffleupagus force-pushed the getVisibleElements-fixes branch from 25864e3 to b2235ec Compare January 13, 2019 10:35
@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Received

Command cmd_unittest from @Snuffleupagus received. Current queue size: 0

Live output at: http://54.67.70.0:8877/dbea3343070da41/output.txt

@pdfjsbot
Copy link

From: Bot.io (Windows)


Received

Command cmd_unittest from @Snuffleupagus received. Current queue size: 0

Live output at: http://54.215.176.217:8877/654b06bdb3233ca/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Success

Full output at http://54.67.70.0:8877/dbea3343070da41/output.txt

Total script time: 2.53 mins

  • Unit Tests: Passed

@pdfjsbot
Copy link

From: Bot.io (Windows)


Success

Full output at http://54.215.176.217:8877/654b06bdb3233ca/output.txt

Total script time: 4.80 mins

  • Unit Tests: Passed

@Snuffleupagus
Copy link
Collaborator Author

/botio-linux preview

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Received

Command cmd_preview from @Snuffleupagus received. Current queue size: 0

Live output at: http://54.67.70.0:8877/39c3b7e77c2d5fa/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Success

Full output at http://54.67.70.0:8877/39c3b7e77c2d5fa/output.txt

Total script time: 1.65 mins

Published

@timvandermeij timvandermeij merged commit 5cb00b7 into mozilla:master Jan 13, 2019
@timvandermeij
Copy link
Contributor

Thank you for looking into this and providing unit tests to verify the fix!

@Snuffleupagus Snuffleupagus deleted the getVisibleElements-fixes branch January 13, 2019 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants