initialization.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /* Copyright 2020 Mozilla Foundation
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. import {
  16. Border,
  17. Cursor,
  18. Display,
  19. Font,
  20. GlobalConstants,
  21. Highlight,
  22. Position,
  23. ScaleHow,
  24. ScaleWhen,
  25. Style,
  26. Trans,
  27. ZoomType,
  28. } from "./constants.js";
  29. import { CheckboxField, Field, RadioButtonField } from "./field.js";
  30. import { AForm } from "./aform.js";
  31. import { App } from "./app.js";
  32. import { Color } from "./color.js";
  33. import { Console } from "./console.js";
  34. import { Doc } from "./doc.js";
  35. import { ProxyHandler } from "./proxy.js";
  36. import { Util } from "./util.js";
  37. function initSandbox(params) {
  38. delete globalThis.pdfjsScripting;
  39. // externalCall is a function to call a function defined
  40. // outside the sandbox.
  41. // (see src/pdf.sandbox.external.js).
  42. const externalCall = globalThis.callExternalFunction;
  43. delete globalThis.callExternalFunction;
  44. // eslint-disable-next-line no-eval
  45. const globalEval = code => globalThis.eval(code);
  46. const send = data => externalCall("send", [data]);
  47. const proxyHandler = new ProxyHandler();
  48. const { data } = params;
  49. const doc = new Doc({
  50. send,
  51. globalEval,
  52. ...data.docInfo,
  53. });
  54. const _document = { obj: doc, wrapped: new Proxy(doc, proxyHandler) };
  55. const app = new App({
  56. send,
  57. globalEval,
  58. externalCall,
  59. _document,
  60. calculationOrder: data.calculationOrder,
  61. proxyHandler,
  62. ...data.appInfo,
  63. });
  64. const util = new Util({ externalCall });
  65. const appObjects = app._objects;
  66. if (data.objects) {
  67. const annotations = [];
  68. for (const [name, objs] of Object.entries(data.objects)) {
  69. annotations.length = 0;
  70. let container = null;
  71. for (const obj of objs) {
  72. if (obj.type !== "") {
  73. annotations.push(obj);
  74. } else {
  75. container = obj;
  76. }
  77. }
  78. let obj = container;
  79. if (annotations.length > 0) {
  80. obj = annotations[0];
  81. obj.send = send;
  82. }
  83. obj.globalEval = globalEval;
  84. obj.doc = _document;
  85. obj.fieldPath = name;
  86. obj.appObjects = appObjects;
  87. let field;
  88. switch (obj.type) {
  89. case "radiobutton": {
  90. const otherButtons = annotations.slice(1);
  91. field = new RadioButtonField(otherButtons, obj);
  92. break;
  93. }
  94. case "checkbox": {
  95. const otherButtons = annotations.slice(1);
  96. field = new CheckboxField(otherButtons, obj);
  97. break;
  98. }
  99. case "text":
  100. if (annotations.length <= 1) {
  101. field = new Field(obj);
  102. break;
  103. }
  104. obj.siblings = annotations.map(x => x.id).slice(1);
  105. field = new Field(obj);
  106. break;
  107. default:
  108. field = new Field(obj);
  109. }
  110. const wrapped = new Proxy(field, proxyHandler);
  111. const _object = { obj: field, wrapped };
  112. doc._addField(name, _object);
  113. for (const object of objs) {
  114. appObjects[object.id] = _object;
  115. }
  116. if (container) {
  117. appObjects[container.id] = _object;
  118. }
  119. }
  120. }
  121. const color = new Color();
  122. globalThis.event = null;
  123. globalThis.global = Object.create(null);
  124. globalThis.app = new Proxy(app, proxyHandler);
  125. globalThis.color = new Proxy(color, proxyHandler);
  126. globalThis.console = new Proxy(new Console({ send }), proxyHandler);
  127. globalThis.util = new Proxy(util, proxyHandler);
  128. globalThis.border = Border;
  129. globalThis.cursor = Cursor;
  130. globalThis.display = Display;
  131. globalThis.font = Font;
  132. globalThis.highlight = Highlight;
  133. globalThis.position = Position;
  134. globalThis.scaleHow = ScaleHow;
  135. globalThis.scaleWhen = ScaleWhen;
  136. globalThis.style = Style;
  137. globalThis.trans = Trans;
  138. globalThis.zoomtype = ZoomType;
  139. // Avoid to have a popup asking to update Acrobat.
  140. globalThis.ADBE = {
  141. Reader_Value_Asked: true,
  142. Viewer_Value_Asked: true,
  143. };
  144. // AF... functions
  145. const aform = new AForm(doc, app, util, color);
  146. for (const name of Object.getOwnPropertyNames(AForm.prototype)) {
  147. if (name !== "constructor" && !name.startsWith("_")) {
  148. globalThis[name] = aform[name].bind(aform);
  149. }
  150. }
  151. // Add global constants such as IDS_GREATER_THAN or RE_NUMBER_ENTRY_DOT_SEP
  152. for (const [name, value] of Object.entries(GlobalConstants)) {
  153. Object.defineProperty(globalThis, name, {
  154. value,
  155. writable: false,
  156. });
  157. }
  158. // Color functions
  159. Object.defineProperties(globalThis, {
  160. ColorConvert: {
  161. value: color.convert.bind(color),
  162. writable: true,
  163. },
  164. ColorEqual: {
  165. value: color.equal.bind(color),
  166. writable: true,
  167. },
  168. });
  169. // The doc properties must live in the global scope too
  170. const properties = Object.create(null);
  171. for (const name of Object.getOwnPropertyNames(Doc.prototype)) {
  172. if (name === "constructor" || name.startsWith("_")) {
  173. continue;
  174. }
  175. const descriptor = Object.getOwnPropertyDescriptor(Doc.prototype, name);
  176. if (descriptor.get) {
  177. properties[name] = {
  178. get: descriptor.get.bind(doc),
  179. set: descriptor.set.bind(doc),
  180. };
  181. } else {
  182. properties[name] = {
  183. value: Doc.prototype[name].bind(doc),
  184. };
  185. }
  186. }
  187. Object.defineProperties(globalThis, properties);
  188. const functions = {
  189. dispatchEvent: app._dispatchEvent.bind(app),
  190. timeoutCb: app._evalCallback.bind(app),
  191. };
  192. return (name, args) => {
  193. try {
  194. functions[name](args);
  195. } catch (error) {
  196. const value = `${error.toString()}\n${error.stack}`;
  197. send({ command: "error", value });
  198. }
  199. };
  200. }
  201. export { initSandbox };