Basic mathematics would suggest that a double negative should always become positive, but it appears that Adobe Reader simply ignores that case. Hence I think that it makes sense for us to do the same.
Fixes 6218.
After the creation of `PDFViewer`, its `_resetView` method takes care of resetting, among other things, the page number property. Hence we don't need to set `pdfViewer.currentPageNumber = 1;` here any more, and the comment is no longer accurate either.
When the parser finds a stream, it retrieves the Length from the stream
dictionary and advances the lexer to the offset as specified in Length.
If this Length is incorrect, the lexer could end up anywhere.
When the lexer gets in an invalid state, it could throw errors. For
example, in issue 6108, the lexer ends up inside the stream data. This
stream has the ASCIIHexDecode filter, so all characters are made up from
ASCII characters, and the lexer interprets it as a command token. Tokens
cannot be longer than 127 bytes, so eventually 128 bytes are consumed
and the lexer throws "Command token too long" error.
Another possible error is "Illegal character: 41" when the lexer happens
to end up at a ')' due to the length mismatch.
These problems are solved by catching lexer errors and recovering the
parser via the existing stream length detection branch.
*With this patch we're getting very close to fixing 6158.*
The only use-case for `PDFViewerApplication.updateScaleControls` is to try and avoid calling `selectScaleOption` from the `scalechange` event handler in viewer.js.
This will *only* happen when the user has manually changed the scale by using the `<select>` dropdown, which means that in reality this is just a micro optimization. Furthermore, `selectScaleOption` is only skipped for the "named" scale values (e.g. `auto`, `page-actual`, `page-fit`, `page-width`), thus further reducing the value of this code.
Also, since we're updating the scale `<select>` dropdown from an event handler, we're currently depending on the event being dispatched (and handled) completely before the next `scalechange` event. Relying on the execution order of the code in this way, even though it currently works, seems unfortunate since it *could* potentially cause the internal scale value and the UI from getting out of sync.
Xref offsets are relative to the start of the PDF data, not to the start
of the PDF file. This is clear if you look at the other code:
- In the XRef's readXRefTable and processXRefTable methods of XRef, the
offset of a xref entry is set to the bytes as given by a PDF file.
These values are always relative to the start of the PDF file (%PDF-).
- The XRef's readXRef method adds the start offset of the stream to
Xref entry's offset: "stream.pos = startXRef + stream.start".
Clearly, this line assumes that the entry offset excludes the start
offset.
However, when the PDF is parsed in recovery mode, the xref table is
filled with entries whose offset is relative to the start of the stream
rather than the PDF file. This is incorrect, and the fix is to subtract
the start offset of the stream from the entry's byte offset.
The manually created PDF file serves as a regression test. It is a valid
PDF, except:
- The integer to point to the start of the xref table and the %%EOF
trailer are missing. This will activate recovery mode in PDF.js
- Some junk was added before the start of the PDF file. This exposes the
bad offset bug.
The PDF specification (cited below) specifies a maximum length of a name
in bytes as a minimal architectural limit. This means that PDF *writers*
should not create names that exceed 127 bytes.
It does not forbid PDF *readers* to accept such names though. These
names are only used internally to link PDF objects to other objects. For
these use cases, the lengths of the names do not really matter. Hence I
have changed the implementation to not treat long names as errors, but
warnings.
> (7.3.5) The length of a name shall be subject to an implementation
> limit; see Annex C.
>
> (Annex C.2) Table C.1 describes the minimum architectural limits that
> should be accommodated by conforming readers running on 32-bit
> machines. Because conforming readers may be subject to these limits,
> conforming writers producing PDF files should remain within them.
>
> (Table C.1) name 127 "Maximum length of a name, in bytes."
http://adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf
*This is the next step towards fixing 6158.*
This patch removes the dependency on the state of the scale `<select>` dropdown from the `resize` event handler, and instead uses the (in `PDFViewer`) stored `currentScaleValue`.
I believe that the way this code is currently written is purely for historical reasons, since originally *only* the numerical scale was stored internally (hence there was no other way to access the scale value).
However, since we now store the scale value, we should use it instead of quering the DOM. This helps ensure that the internally stored scale value is always accurately displayed in the UI (which should be good since, after the creation of `PDFViewer`, the `<select>` DOM element is now updated by an event handler).
For named destinations that are contained in a `Dict`, as opposed to a `NameTree`, we currently iterate through the *entire* dictionary just to fetch *one* destination.
This code appears to simply have been copy-pasted from the `get destinations` method, but in its current form it's quite unnecessary/inefficient since can just get the required destination directly instead.
Doing this helped uncover an issue with the `getDestination` implementation.
Currently if a named destination doesn't exist, the method (in `obj.js`) may return `undefined` which leads to the promise being stuck in a pending state.
*Note:* returning `null` for this case is consistent with other methods, e.g. `getOutline` and `getAttachments`.
*The next step towards fixing issue 6158.*
We can just as well access `pdfViewer.currentScaleValue` directly in `PDFViewerApplication`, instead of having a helper function which just acts as a wrapper for it.
Currently if the zoom level is reset multiple times in a row, i.e. by pressing <kbd>Ctrl</kbd>+<kbd>0</kbd>, the pages can be re-rendered each time even though their size shouldn't change. Whether this happens can depend on the size of the viewer, but documents with pages in landscape mode seem to be very susceptible to this. (An example is: https://wiki.mozilla.org/images/5/55/MobileOpportunity.pdf.)
This can also effect documents with pages in portrait mode, when they are displayed in Presentation Mode.
The reason for this unnecessary re-rendering is that due to limited numerical precision, the new scale value may change in *only* the last decimal place.