Skip to content

Refactors CMapFactory.create to make it async #7039

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

Merged
merged 1 commit into from
Mar 21, 2016
Merged

Refactors CMapFactory.create to make it async #7039

merged 1 commit into from
Mar 21, 2016

Conversation

ManasJayanth
Copy link
Contributor

For #6352. Up for review

Review on Reviewable

@ManasJayanth ManasJayanth changed the title [WIP] Refactors CMapFactory.create to make it async Refactors CMapFactory.create to make it async Mar 2, 2016
return parseBinaryCMap(name, builtInCMapParams);
}
if (builtInCMapParams.packed) {
resolve(parseBinaryCMap(name, builtInCMapParams));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In production we mostly use parseBinaryCMap -- this shall be async too

@yurydelendik
Copy link
Contributor

Review status: 0 of 3 files reviewed at latest revision, 18 unresolved discussions.


src/core/cmap.js, line 445 [r2] (raw file):
You can remove nonBinaryRequest branches and always use request.responseType = 'arraybuffer';


src/core/cmap.js, line 980 [r2] (raw file):
return cMap; here to resolve promise into cMap


src/core/cmap.js, line 1003 [r2] (raw file):
Here (and in XHR above) check if the url is HTTP (e.g. /^https?:/i.test(url);) and if not check status === 0.


src/core/evaluator.js, line 253 [r2] (raw file):
unneeded change


src/core/evaluator.js, line 344 [r2] (raw file):
unneeded change


src/core/evaluator.js, line 430 [r2] (raw file):
unneeded change


src/core/evaluator.js, line 508 [r2] (raw file):
unneeded change


src/core/evaluator.js, line 803 [r2] (raw file):
unneeded change


src/core/evaluator.js, line 827 [r2] (raw file):
unneeded change


src/core/evaluator.js, line 1187 [r2] (raw file):
unneeded change


src/core/evaluator.js, line 1555 [r2] (raw file):
there shall no be return, make it: var toUnicodePromise = toUnicode ? this.readToUnicode(toUnicode) : Promise.resolve(undefined);. Instead of wrapping the code below in then() you can split extractDataStructures into two functions and call rest of extractDataStructures when toUnicodePromise is resolved


src/core/evaluator.js, line 1653 [r2] (raw file):
you already handling then() -- Promise.resolve is not needed


Comments from the review on Reviewable.io

@ManasJayanth
Copy link
Contributor Author

@yurydelendik [TYPO EDIT] I'll squash all the commits at the end when the code review is done. Okay?

I was using reviewable.io, but the tool failed at some point and I think I lost some of the comments :(

@yurydelendik
Copy link
Contributor

@yurydelendik All squash all the commits at the end when the code review is done. Okay?

You can squash commits as you pushing updated version to this PR (reviewable shall be able to track that I hope).

@ManasJayanth
Copy link
Contributor Author

Review status: 0 of 3 files reviewed at latest revision, 18 unresolved discussions.


src/core/cmap.js, line 973 [r1] (raw file):
Done.


src/core/cmap.js, line 985 [r1] (raw file):
Done.


src/core/cmap.js, line 445 [r2] (raw file):
Can you please explain this? Why are the nonBinaryRequest branches no longer necessary?


src/core/cmap.js, line 980 [r2] (raw file):
But processBinaryCMap alreadys returns a cMap


src/core/cmap.js, line 1003 [r2] (raw file):
Done.


src/core/evaluator.js, line 1554 [r1] (raw file):
Done.


src/core/evaluator.js, line 1560 [r1] (raw file):
Done.


src/core/evaluator.js, line 1688 [r1] (raw file):
Done.


src/core/evaluator.js, line 2086 [r1] (raw file):
Done.


src/core/evaluator.js, line 253 [r2] (raw file):
This was after Snuffleupaugus mentioned about the line breaks I made in the patch. He was referring to my patch alone and I guess I overdid.

Reverting the unneeded changes you've pointed out.


src/core/evaluator.js, line 344 [r2] (raw file):
Done.


src/core/evaluator.js, line 430 [r2] (raw file):
Done.


src/core/evaluator.js, line 508 [r2] (raw file):
Done.


src/core/evaluator.js, line 803 [r2] (raw file):
Done.


src/core/evaluator.js, line 827 [r2] (raw file):
Done.


src/core/evaluator.js, line 1187 [r2] (raw file):
Done.


src/core/evaluator.js, line 1555 [r2] (raw file):
Can you explain the reason behind this change?


src/core/evaluator.js, line 1653 [r2] (raw file):
Done.


Comments from the review on Reviewable.io

@yurydelendik
Copy link
Contributor

Looks good so far. One or two thing are left: chaining promises at extractDataStructures and translateFont. Thanks


Reviewed 1 of 3 files at r1, 2 of 2 files at r3.
Review status: all files reviewed at latest revision, 7 unresolved discussions.


src/core/cmap.js, line 445 [r2] (raw file):
nonBinaryRequest was only added because sync XHR cannot handle binary data -- it's not need since we are making everything async and we can use arraybuffer with XHR.


src/core/cmap.js, line 980 [r2] (raw file):
Nevermind, I thought it's a Promise's then callback -- we will refactor this later


src/core/cmap.js, line 1003 [r2] (raw file):
shall be var expectedStatus = /^https?:/i.test(url) ? 200 : 0; ... if (request.status !== expectedStatus) ...


src/core/evaluator.js, line 2086 [r1] (raw file):
The same situation is at extractDataStructures above, we need to chain promise here: wait for CMapFactory.create to be resolve before we proceed with the code below.


src/core/evaluator.js, line 253 [r2] (raw file):
Extra change make it hard to review, it's better if only new/affected code is changed. Thanks


src/core/evaluator.js, line 1555 [r2] (raw file):
The code path below shall continue after this.readToUnicode is done, i.e. the cidToGidMap and differences properties must be assigned too


Comments from the review on Reviewable.io

@ManasJayanth
Copy link
Contributor Author

Review status: all files reviewed at latest revision, 3 unresolved discussions.


src/core/cmap.js, line 445 [r2] (raw file):
So mapping responseText to an character array (ch & 255) is not necessary? resolve(new Uint8Array(request.response)); is enough? (cmap.js#L431)

Can you help me understand this?

      if (!nonBinaryRequest) {
        try {
          request.responseType = 'arraybuffer';
          nonBinaryRequest = request.responseType !== 'arraybuffer';
        } catch (e) {
          nonBinaryRequest = true;
        }
      }

Can this be safely removed too?


src/core/evaluator.js, line 253 [r2] (raw file):
I figured :) My bad


Comments from the review on Reviewable.io

@ManasJayanth
Copy link
Contributor Author

Review status: all files reviewed at latest revision, 3 unresolved discussions.


src/core/cmap.js, line 445 [r2] (raw file):
I mean replace it with request.responseType = 'arraybuffer'


Comments from the review on Reviewable.io

@ManasJayanth
Copy link
Contributor Author

Review status: 1 of 3 files reviewed at latest revision, 3 unresolved discussions.


src/core/evaluator.js, line 253 [r2] (raw file):
Done.


Comments from the review on Reviewable.io

@yurydelendik
Copy link
Contributor

Reviewed 2 of 2 files at r4.
Review status: all files reviewed at latest revision, 3 unresolved discussions.


src/core/cmap.js, line 445 [r2] (raw file):
That's correct, you can use only request.responseType = 'arraybuffer' (We shall have polyfill in compatibility.js for browsers that does not support arraybuffer).


src/core/cmap.js, line 446 [r4] (raw file):
Add the same expectedStatus check as below here


Comments from the review on Reviewable.io

@ManasJayanth
Copy link
Contributor Author

Review status: 2 of 3 files reviewed at latest revision, 2 unresolved discussions.


src/core/cmap.js, line 446 [r4] (raw file):
Done.


Comments from the review on Reviewable.io

@yurydelendik
Copy link
Contributor

Reviewed 1 of 1 files at r5.
Review status: all files reviewed at latest revision, 3 unresolved discussions.


src/core/cmap.js, line 429 [r5] (raw file):
async parameter shall be true here


src/core/evaluator.js, line 345 [r5] (raw file):
unneeded change?


Comments from the review on Reviewable.io

@ManasJayanth
Copy link
Contributor Author

Review status: 1 of 3 files reviewed at latest revision, 3 unresolved discussions.


src/core/evaluator.js, line 345 [r5] (raw file):
Reverting


Comments from the review on Reviewable.io

@yurydelendik
Copy link
Contributor

Review status: 1 of 3 files reviewed at latest revision, 5 unresolved discussions.


src/core/cmap.js, line 718 [r5] (raw file):
processBinaryCMap (aka BinaryCMapReader.read) calls the extend callback which can be async (it returns promise?). Let's not refactor it now, but return extend(useCMap).then(function () { return cMap; }); and fix parseBinaryCMap below


src/core/cmap.js, line 958 [r5] (raw file):
make extendCMap async and return its promise here (the createBuiltInCMap used by this function is async)


Comments from the review on Reviewable.io

@ManasJayanth
Copy link
Contributor Author

Review status: 1 of 3 files reviewed at latest revision, 4 unresolved discussions.


src/core/cmap.js, line 958 [r5] (raw file):
Or simply return cmap from .read()?


Comments from the review on Reviewable.io

@ManasJayanth
Copy link
Contributor Author

Review status: 1 of 3 files reviewed at latest revision, 4 unresolved discussions.


src/core/cmap.js, line 958 [r5] (raw file):
processBinaryCMap (i.e. .read()) returns a promise after all.


Comments from the review on Reviewable.io

@yurydelendik
Copy link
Contributor

Here function async status (-> is a call):

  • processBinaryCMap -> fetchBinaryData, extendCMap
  • parseCMap -> extendCMap
  • extendCMap -> createBuiltInCMap
  • createBuiltInCMap -> parseBinaryCMap, parseCMap
  • CMapFactory.create -> createBuiltInCMap, parseCMap
  • buildToUnicode -> CMapFactory.create
  • readToUnicode -> CMapFactory.create
  • translateFont -> CMapFactory.create, extractDataStructures, new Font
  • extractDataStructures -> readToUnicode
  • new Font -> buildToUnicode -- impossible!!!

Problem we have parseCMap and buildToUnicode is sync. Former is easy to convert, the latter is hard. Let's move buildToUnicode body into evaluator near extractDataStructures and chain its call after toUnicode.


Review status: 1 of 3 files reviewed at latest revision, 6 unresolved discussions.


src/core/evaluator.js, line 1640 [r5] (raw file):
toUnicodePromise.then(function(toUnicode) {


src/core/evaluator.js, line 1655 [r5] (raw file):
nit: indent


Comments from the review on Reviewable.io

@yurydelendik
Copy link
Contributor

Review status: 1 of 3 files reviewed at latest revision, 6 unresolved discussions.


src/core/cmap.js, line 958 [r5] (raw file):
Loading during extendCMap might be incomplete due to its createBuiltInCMap call but we will be signaling that we are done. So we have to make extendCMap async and wait on its promise here. extendCMap may or may not return result cMap, however read() call shall return the cMap we are loading.


Comments from the review on Reviewable.io

@ManasJayanth
Copy link
Contributor Author

Review status: 1 of 3 files reviewed at latest revision, 5 unresolved discussions.


src/core/evaluator.js, line 1640 [r5] (raw file):
Move buildToUnicode here?


Comments from the review on Reviewable.io

@yurydelendik
Copy link
Contributor

Reviewed 1 of 2 files at r7, 1 of 1 files at r8.
Review status: all files reviewed at latest revision, 6 unresolved discussions.


src/core/cmap.js, line 938 [r8] (raw file):
Use right cMap here. Rename the function parameter into e.g. newCMap and assign it to the cMap.useCMap = newCMap. The function shall return cMap


src/core/evaluator.js, line 1640 [r5] (raw file):
That's correct,

return toUnicodePromise.then(function(toUnicode) {
   properties.toUnicode = toUnicode;
   return this.buildToUnicode(properties);
}.this(this)).then(function (toUnicode) {
  properties.toUnicode = toUnicode;
  return properties;
});

We will refactor the logic of buildToUnicode later.


Comments from the review on Reviewable.io

@yurydelendik
Copy link
Contributor

I recommend to rebase it to the newest mozilla/master before moving buildToUnicode (I saw some of PRs landed that will affect it)

@ManasJayanth
Copy link
Contributor Author

Sure. Thanks for the heads up

@ManasJayanth
Copy link
Contributor Author

Review status: all files reviewed at latest revision, 13 unresolved discussions.


src/core/evaluator.js, line 1655 [r5] (raw file):
Tried indenting like Snuffleupagus recommended. How would you like it?


Comments from the review on Reviewable.io

@yurydelendik
Copy link
Contributor

Review status: all files reviewed at latest revision, 12 unresolved discussions.


src/core/evaluator.js, line 1653 [r10] (raw file):
yes


Comments from the review on Reviewable.io


// The viewer's choice, just use an identity map.
return Promise.resolve(new IdentityToUnicodeMap(properties.firstChar,
properties.lastChar));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: please indent this line a bit more, like this

return Promise.resolve(new IdentityToUnicodeMap(properties.firstChar,
                                                properties.lastChar));

@ManasJayanth
Copy link
Contributor Author

Review status: all files reviewed at latest revision, 12 unresolved discussions.


src/core/evaluator.js, line 354 [r11] (raw file):
Not sure what you are referring to.


Comments from the review on Reviewable.io

@yurydelendik
Copy link
Contributor

Review status: 1 of 3 files reviewed at latest revision, 14 unresolved discussions.


src/core/evaluator.js, line 2133 [r13] (raw file):
add }.bind(this)


src/core/evaluator.js, line 2232 [r13] (raw file):
add .bind(this)


Comments from the review on Reviewable.io

@yurydelendik
Copy link
Contributor

Reviewed 1 of 2 files at r12, 1 of 1 files at r14.
Review status: all files reviewed at latest revision, 14 unresolved discussions.


Comments from the review on Reviewable.io

@yurydelendik
Copy link
Contributor

cmap_spec needs to be fixed, e.g.:

@@ -7,16 +7,34 @@ var cMapUrl = '../../external/bcmaps/';
 var cMapPacked = true;

 describe('cmap', function() {
+  var TEST_TIMEOUT = 20000;
+  function waitsForPromiseResolved(promise, successCallback) {
+    var resolved = false;
+    promise.then(function(val) {
+        resolved = true;
+        successCallback(val);
+      },
+      function(error) {
+        // Shouldn't get here.
+        expect(error).toEqual('the promise should not have been rejected');
+      });
+    waitsFor(function() {
+      return resolved;
+    }, TEST_TIMEOUT);
+  }
+
   it('parses beginbfchar', function() {
     var str = '2 beginbfchar\n' +
               '<03> <00>\n' +
               '<04> <01>\n' +
               'endbfchar\n';
     var stream = new StringStream(str);
-    var cmap = CMapFactory.create(stream);
-    expect(cmap.lookup(0x03)).toEqual(String.fromCharCode(0x00));
-    expect(cmap.lookup(0x04)).toEqual(String.fromCharCode(0x01));
-    expect(cmap.lookup(0x05)).toBeUndefined();
+    var cmapPromise = CMapFactory.create(stream);
+    waitsForPromiseResolved(cmapPromise, function (cmap) {
+      expect(cmap.lookup(0x03)).toEqual(String.fromCharCode(0x00));
+      expect(cmap.lookup(0x04)).toEqual(String.fromCharCode(0x01));
+      expect(cmap.lookup(0x05)).toBeUndefined();
+    });
   });
   it('parses beginbfrange with range', function() {
     var str = '1 beginbfrange\n' +

@yurydelendik
Copy link
Contributor

Review status: all files reviewed at latest revision, 14 unresolved discussions.


src/core/evaluator.js, line 354 [r11] (raw file):
Looking at https://github.com/mozilla/pdf.js/pull/7039/files#diff-0b94c2e77a5259f7a728122fdbf9f46aL345, there is some code movement is happening


Comments from the review on Reviewable.io

{ url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null);
properties.vertical = properties.cMap.vertical;
return CMapFactory.create(cidEncoding,
{ url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null).then(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

chain that with this.buildToUnicode call -- we need properties.toUnicode populated before new Font() call.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it would be

        return CMapFactory.create(cidEncoding,
          { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null).then(
            function (cMap) {
          properties.cMap = cMap;
          properties.vertical = properties.cMap.vertical;
          return this.buildToUnicode(cMap.properties)
}.bind(this)).then(function (toUnicode) {
properties.toUnicode = toUnicode;
          return new Font(fontName.name, fontFile, properties);
        });

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make there return this.buildToUnicode(properties); though

@yurydelendik
Copy link
Contributor

r+ when all tests pass, looks good in terms of refactored logic.

@brendandahl
Copy link
Contributor

@prometheansacrifice There are still some test failures. Once those are fixed I'll review.

@yurydelendik
Copy link
Contributor

/botio test

@pdfjsbot
Copy link

From: Bot.io (Windows)


Received

Command cmd_test from @yurydelendik received. Current queue size: 0

Live output at: http://107.22.172.223:8877/9b5649f35803541/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux)


Received

Command cmd_test from @yurydelendik received. Current queue size: 0

Live output at: http://107.21.233.14:8877/256d415292652fd/output.txt

@pdfjsbot
Copy link

From: Bot.io (Windows)


Success

Full output at http://107.22.172.223:8877/9b5649f35803541/output.txt

Total script time: 20.52 mins

  • Font tests: Passed
  • Unit tests: Passed
  • Regression tests: Passed

@pdfjsbot
Copy link

From: Bot.io (Linux)


Success

Full output at http://107.21.233.14:8877/256d415292652fd/output.txt

Total script time: 22.04 mins

  • Font tests: Passed
  • Unit tests: Passed
  • Regression tests: Passed

yurydelendik added a commit that referenced this pull request Mar 21, 2016
Refactors CMapFactory.create to make it async
@yurydelendik yurydelendik merged commit 21ed8ff into mozilla:master Mar 21, 2016
@yurydelendik
Copy link
Contributor

Thank you for the patch. Good work.

@ManasJayanth ManasJayanth deleted the async-cmap-factory branch March 21, 2016 19:15
@ManasJayanth
Copy link
Contributor Author

Thank you too yury. Appreciate your help in this

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.

6 participants