compatibility.js 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840
  1. /* Copyright 2017 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. /* eslint-disable no-extend-native */
  16. /* globals VBArray, PDFJS, global */
  17. // Skip compatibility checks for the extensions and if we already ran
  18. // this module.
  19. if ((typeof PDFJSDev === 'undefined' ||
  20. !PDFJSDev.test('FIREFOX || MOZCENTRAL || CHROME')) &&
  21. (typeof PDFJS === 'undefined' || !PDFJS.compatibilityChecked)) {
  22. var globalScope = (typeof window !== 'undefined') ? window :
  23. (typeof global !== 'undefined') ? global :
  24. (typeof self !== 'undefined') ? self : this;
  25. var userAgent = (typeof navigator !== 'undefined' && navigator.userAgent) || '';
  26. var isAndroid = /Android/.test(userAgent);
  27. var isAndroidPre3 = /Android\s[0-2][^\d]/.test(userAgent);
  28. var isAndroidPre5 = /Android\s[0-4][^\d]/.test(userAgent);
  29. var isChrome = userAgent.indexOf('Chrom') >= 0;
  30. var isChromeWithRangeBug = /Chrome\/(39|40)\./.test(userAgent);
  31. var isIOSChrome = userAgent.indexOf('CriOS') >= 0;
  32. var isIE = userAgent.indexOf('Trident') >= 0;
  33. var isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent);
  34. var isOpera = userAgent.indexOf('Opera') >= 0;
  35. var isSafari = /Safari\//.test(userAgent) &&
  36. !/(Chrome\/|Android\s)/.test(userAgent);
  37. var hasDOM = typeof window === 'object' && typeof document === 'object';
  38. // Initializing PDFJS global object here, it case if we need to change/disable
  39. // some PDF.js features, e.g. range requests
  40. if (typeof PDFJS === 'undefined') {
  41. globalScope.PDFJS = {};
  42. }
  43. PDFJS.compatibilityChecked = true;
  44. // Checking if the typed arrays are supported
  45. // Support: iOS<6.0 (subarray), IE<10, Android<4.0
  46. (function checkTypedArrayCompatibility() {
  47. if (typeof Uint8Array !== 'undefined') {
  48. // Support: iOS<6.0
  49. if (typeof Uint8Array.prototype.subarray === 'undefined') {
  50. Uint8Array.prototype.subarray = function subarray(start, end) {
  51. return new Uint8Array(this.slice(start, end));
  52. };
  53. Float32Array.prototype.subarray = function subarray(start, end) {
  54. return new Float32Array(this.slice(start, end));
  55. };
  56. }
  57. // Support: Android<4.1
  58. if (typeof Float64Array === 'undefined') {
  59. globalScope.Float64Array = Float32Array;
  60. }
  61. return;
  62. }
  63. function subarray(start, end) {
  64. return new TypedArray(this.slice(start, end));
  65. }
  66. function setArrayOffset(array, offset) {
  67. if (arguments.length < 2) {
  68. offset = 0;
  69. }
  70. for (var i = 0, n = array.length; i < n; ++i, ++offset) {
  71. this[offset] = array[i] & 0xFF;
  72. }
  73. }
  74. function Uint32ArrayView(buffer, length) {
  75. this.buffer = buffer;
  76. this.byteLength = buffer.length;
  77. this.length = length;
  78. ensureUint32ArrayViewProps(this.length);
  79. }
  80. Uint32ArrayView.prototype = Object.create(null);
  81. var uint32ArrayViewSetters = 0;
  82. function createUint32ArrayProp(index) {
  83. return {
  84. get() {
  85. var buffer = this.buffer, offset = index << 2;
  86. return (buffer[offset] | (buffer[offset + 1] << 8) |
  87. (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24)) >>> 0;
  88. },
  89. set(value) {
  90. var buffer = this.buffer, offset = index << 2;
  91. buffer[offset] = value & 255;
  92. buffer[offset + 1] = (value >> 8) & 255;
  93. buffer[offset + 2] = (value >> 16) & 255;
  94. buffer[offset + 3] = (value >>> 24) & 255;
  95. },
  96. };
  97. }
  98. function ensureUint32ArrayViewProps(length) {
  99. while (uint32ArrayViewSetters < length) {
  100. Object.defineProperty(Uint32ArrayView.prototype,
  101. uint32ArrayViewSetters,
  102. createUint32ArrayProp(uint32ArrayViewSetters));
  103. uint32ArrayViewSetters++;
  104. }
  105. }
  106. function TypedArray(arg1) {
  107. var result, i, n;
  108. if (typeof arg1 === 'number') {
  109. result = [];
  110. for (i = 0; i < arg1; ++i) {
  111. result[i] = 0;
  112. }
  113. } else if ('slice' in arg1) {
  114. result = arg1.slice(0);
  115. } else {
  116. result = [];
  117. for (i = 0, n = arg1.length; i < n; ++i) {
  118. result[i] = arg1[i];
  119. }
  120. }
  121. result.subarray = subarray;
  122. result.buffer = result;
  123. result.byteLength = result.length;
  124. result.set = setArrayOffset;
  125. if (typeof arg1 === 'object' && arg1.buffer) {
  126. result.buffer = arg1.buffer;
  127. }
  128. return result;
  129. }
  130. globalScope.Uint8Array = TypedArray;
  131. globalScope.Int8Array = TypedArray;
  132. // we don't need support for set, byteLength for 32-bit array
  133. // so we can use the TypedArray as well
  134. globalScope.Int32Array = TypedArray;
  135. globalScope.Uint16Array = TypedArray;
  136. globalScope.Float32Array = TypedArray;
  137. globalScope.Float64Array = TypedArray;
  138. globalScope.Uint32Array = function () {
  139. if (arguments.length === 3) {
  140. // Building view for buffer, offset, and length
  141. if (arguments[1] !== 0) {
  142. throw new Error('offset !== 0 is not supported');
  143. }
  144. return new Uint32ArrayView(arguments[0], arguments[2]);
  145. }
  146. return TypedArray.apply(this, arguments);
  147. };
  148. })();
  149. // window.CanvasPixelArray.buffer/.byteLength
  150. // Support: IE9
  151. (function canvasPixelArrayBuffer() {
  152. if (!hasDOM || !window.CanvasPixelArray) {
  153. return;
  154. }
  155. var cpaProto = window.CanvasPixelArray.prototype;
  156. if ('buffer' in cpaProto) {
  157. return;
  158. }
  159. // Trying to fake CanvasPixelArray as Uint8ClampedArray.
  160. Object.defineProperty(cpaProto, 'buffer', {
  161. get() {
  162. return this;
  163. },
  164. enumerable: false,
  165. configurable: true,
  166. });
  167. Object.defineProperty(cpaProto, 'byteLength', {
  168. get() {
  169. return this.length;
  170. },
  171. enumerable: false,
  172. configurable: true,
  173. });
  174. })();
  175. // URL = URL || webkitURL
  176. // Support: Safari<7, Android 4.2+
  177. (function normalizeURLObject() {
  178. if (!globalScope.URL) {
  179. globalScope.URL = globalScope.webkitURL;
  180. }
  181. })();
  182. // Object.defineProperty()?
  183. // Support: Android<4.0, Safari<5.1
  184. (function checkObjectDefinePropertyCompatibility() {
  185. if (typeof Object.defineProperty !== 'undefined') {
  186. var definePropertyPossible = true;
  187. try {
  188. if (hasDOM) {
  189. // some browsers (e.g. safari) cannot use defineProperty() on DOM
  190. // objects and thus the native version is not sufficient
  191. Object.defineProperty(new Image(), 'id', { value: 'test', });
  192. }
  193. // ... another test for android gb browser for non-DOM objects
  194. var Test = function Test() {};
  195. Test.prototype = { get id() { }, };
  196. Object.defineProperty(new Test(), 'id',
  197. { value: '', configurable: true, enumerable: true, writable: false, });
  198. } catch (e) {
  199. definePropertyPossible = false;
  200. }
  201. if (definePropertyPossible) {
  202. return;
  203. }
  204. }
  205. Object.defineProperty = function objectDefineProperty(obj, name, def) {
  206. delete obj[name];
  207. if ('get' in def) {
  208. obj.__defineGetter__(name, def['get']);
  209. }
  210. if ('set' in def) {
  211. obj.__defineSetter__(name, def['set']);
  212. }
  213. if ('value' in def) {
  214. obj.__defineSetter__(name, function objectDefinePropertySetter(value) {
  215. this.__defineGetter__(name, function objectDefinePropertyGetter() {
  216. return value;
  217. });
  218. return value;
  219. });
  220. obj[name] = def.value;
  221. }
  222. };
  223. })();
  224. // No XMLHttpRequest#response?
  225. // Support: IE<11, Android <4.0
  226. (function checkXMLHttpRequestResponseCompatibility() {
  227. if (typeof XMLHttpRequest === 'undefined') {
  228. return;
  229. }
  230. var xhrPrototype = XMLHttpRequest.prototype;
  231. var xhr = new XMLHttpRequest();
  232. if (!('overrideMimeType' in xhr)) {
  233. // IE10 might have response, but not overrideMimeType
  234. // Support: IE10
  235. Object.defineProperty(xhrPrototype, 'overrideMimeType', {
  236. value: function xmlHttpRequestOverrideMimeType(mimeType) {},
  237. });
  238. }
  239. if ('responseType' in xhr) {
  240. return;
  241. }
  242. Object.defineProperty(xhrPrototype, 'responseType', {
  243. get: function xmlHttpRequestGetResponseType() {
  244. return this._responseType || 'text';
  245. },
  246. set: function xmlHttpRequestSetResponseType(value) {
  247. if (value === 'text' || value === 'arraybuffer') {
  248. this._responseType = value;
  249. if (value === 'arraybuffer' &&
  250. typeof this.overrideMimeType === 'function') {
  251. this.overrideMimeType('text/plain; charset=x-user-defined');
  252. }
  253. }
  254. },
  255. });
  256. // Support: IE9
  257. if (typeof VBArray !== 'undefined') {
  258. Object.defineProperty(xhrPrototype, 'response', {
  259. get: function xmlHttpRequestResponseGet() {
  260. if (this.responseType === 'arraybuffer') {
  261. return new Uint8Array(new VBArray(this.responseBody).toArray());
  262. }
  263. return this.responseText;
  264. },
  265. });
  266. return;
  267. }
  268. Object.defineProperty(xhrPrototype, 'response', {
  269. get: function xmlHttpRequestResponseGet() {
  270. if (this.responseType !== 'arraybuffer') {
  271. return this.responseText;
  272. }
  273. var text = this.responseText;
  274. var i, n = text.length;
  275. var result = new Uint8Array(n);
  276. for (i = 0; i < n; ++i) {
  277. result[i] = text.charCodeAt(i) & 0xFF;
  278. }
  279. return result.buffer;
  280. },
  281. });
  282. })();
  283. // window.btoa (base64 encode function) ?
  284. // Support: IE<10
  285. (function checkWindowBtoaCompatibility() {
  286. if ('btoa' in globalScope) {
  287. return;
  288. }
  289. var digits =
  290. 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
  291. globalScope.btoa = function (chars) {
  292. var buffer = '';
  293. var i, n;
  294. for (i = 0, n = chars.length; i < n; i += 3) {
  295. var b1 = chars.charCodeAt(i) & 0xFF;
  296. var b2 = chars.charCodeAt(i + 1) & 0xFF;
  297. var b3 = chars.charCodeAt(i + 2) & 0xFF;
  298. var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
  299. var d3 = i + 1 < n ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
  300. var d4 = i + 2 < n ? (b3 & 0x3F) : 64;
  301. buffer += (digits.charAt(d1) + digits.charAt(d2) +
  302. digits.charAt(d3) + digits.charAt(d4));
  303. }
  304. return buffer;
  305. };
  306. })();
  307. // window.atob (base64 encode function)?
  308. // Support: IE<10
  309. (function checkWindowAtobCompatibility() {
  310. if ('atob' in globalScope) {
  311. return;
  312. }
  313. // https://github.com/davidchambers/Base64.js
  314. var digits =
  315. 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
  316. globalScope.atob = function (input) {
  317. input = input.replace(/=+$/, '');
  318. if (input.length % 4 === 1) {
  319. throw new Error('bad atob input');
  320. }
  321. for (
  322. // initialize result and counters
  323. var bc = 0, bs, buffer, idx = 0, output = '';
  324. // get next character
  325. (buffer = input.charAt(idx++));
  326. // character found in table?
  327. // initialize bit storage and add its ascii value
  328. ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
  329. // and if not first of each 4 characters,
  330. // convert the first 8 bits to one ascii character
  331. bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
  332. ) {
  333. // try to find character in table (0-63, not found => -1)
  334. buffer = digits.indexOf(buffer);
  335. }
  336. return output;
  337. };
  338. })();
  339. // Function.prototype.bind?
  340. // Support: Android<4.0, iOS<6.0
  341. (function checkFunctionPrototypeBindCompatibility() {
  342. if (typeof Function.prototype.bind !== 'undefined') {
  343. return;
  344. }
  345. Function.prototype.bind = function functionPrototypeBind(obj) {
  346. var fn = this, headArgs = Array.prototype.slice.call(arguments, 1);
  347. var bound = function functionPrototypeBindBound() {
  348. var args = headArgs.concat(Array.prototype.slice.call(arguments));
  349. return fn.apply(obj, args);
  350. };
  351. return bound;
  352. };
  353. })();
  354. // HTMLElement dataset property
  355. // Support: IE<11, Safari<5.1, Android<4.0
  356. (function checkDatasetProperty() {
  357. if (!hasDOM) {
  358. return;
  359. }
  360. var div = document.createElement('div');
  361. if ('dataset' in div) {
  362. return; // dataset property exists
  363. }
  364. Object.defineProperty(HTMLElement.prototype, 'dataset', {
  365. get() {
  366. if (this._dataset) {
  367. return this._dataset;
  368. }
  369. var dataset = {};
  370. for (var j = 0, jj = this.attributes.length; j < jj; j++) {
  371. var attribute = this.attributes[j];
  372. if (attribute.name.substring(0, 5) !== 'data-') {
  373. continue;
  374. }
  375. var key = attribute.name.substring(5).replace(/\-([a-z])/g,
  376. function(all, ch) {
  377. return ch.toUpperCase();
  378. });
  379. dataset[key] = attribute.value;
  380. }
  381. Object.defineProperty(this, '_dataset', {
  382. value: dataset,
  383. writable: false,
  384. enumerable: false,
  385. });
  386. return dataset;
  387. },
  388. enumerable: true,
  389. });
  390. })();
  391. // HTMLElement classList property
  392. // Support: IE<10, Android<4.0, iOS<5.0
  393. (function checkClassListProperty() {
  394. function changeList(element, itemName, add, remove) {
  395. var s = element.className || '';
  396. var list = s.split(/\s+/g);
  397. if (list[0] === '') {
  398. list.shift();
  399. }
  400. var index = list.indexOf(itemName);
  401. if (index < 0 && add) {
  402. list.push(itemName);
  403. }
  404. if (index >= 0 && remove) {
  405. list.splice(index, 1);
  406. }
  407. element.className = list.join(' ');
  408. return (index >= 0);
  409. }
  410. if (!hasDOM) {
  411. return;
  412. }
  413. var div = document.createElement('div');
  414. if ('classList' in div) {
  415. return; // classList property exists
  416. }
  417. var classListPrototype = {
  418. add(name) {
  419. changeList(this.element, name, true, false);
  420. },
  421. contains(name) {
  422. return changeList(this.element, name, false, false);
  423. },
  424. remove(name) {
  425. changeList(this.element, name, false, true);
  426. },
  427. toggle(name) {
  428. changeList(this.element, name, true, true);
  429. },
  430. };
  431. Object.defineProperty(HTMLElement.prototype, 'classList', {
  432. get() {
  433. if (this._classList) {
  434. return this._classList;
  435. }
  436. var classList = Object.create(classListPrototype, {
  437. element: {
  438. value: this,
  439. writable: false,
  440. enumerable: true,
  441. },
  442. });
  443. Object.defineProperty(this, '_classList', {
  444. value: classList,
  445. writable: false,
  446. enumerable: false,
  447. });
  448. return classList;
  449. },
  450. enumerable: true,
  451. });
  452. })();
  453. // Checking if worker has console support. Forwarding all messages to the main
  454. // thread if console object is absent.
  455. (function checkWorkerConsoleCompatibility() {
  456. if (typeof importScripts === 'undefined' || 'console' in globalScope) {
  457. return;
  458. }
  459. var consoleTimer = {};
  460. var workerConsole = {
  461. log: function log() {
  462. var args = Array.prototype.slice.call(arguments);
  463. globalScope.postMessage({
  464. targetName: 'main',
  465. action: 'console_log',
  466. data: args,
  467. });
  468. },
  469. error: function error() {
  470. var args = Array.prototype.slice.call(arguments);
  471. globalScope.postMessage({
  472. targetName: 'main',
  473. action: 'console_error',
  474. data: args,
  475. });
  476. },
  477. time: function time(name) {
  478. consoleTimer[name] = Date.now();
  479. },
  480. timeEnd: function timeEnd(name) {
  481. var time = consoleTimer[name];
  482. if (!time) {
  483. throw new Error('Unknown timer name ' + name);
  484. }
  485. this.log('Timer:', name, Date.now() - time);
  486. },
  487. };
  488. globalScope.console = workerConsole;
  489. })();
  490. // Check console compatibility
  491. // In older IE versions the console object is not available
  492. // unless console is open.
  493. // Support: IE<10
  494. (function checkConsoleCompatibility() {
  495. if (!hasDOM) {
  496. return;
  497. }
  498. if (!('console' in window)) {
  499. window.console = {
  500. log() {},
  501. error() {},
  502. warn() {},
  503. };
  504. return;
  505. }
  506. if (!('bind' in console.log)) {
  507. // native functions in IE9 might not have bind
  508. console.log = (function(fn) {
  509. return function(msg) {
  510. return fn(msg);
  511. };
  512. })(console.log);
  513. console.error = (function(fn) {
  514. return function(msg) {
  515. return fn(msg);
  516. };
  517. })(console.error);
  518. console.warn = (function(fn) {
  519. return function(msg) {
  520. return fn(msg);
  521. };
  522. })(console.warn);
  523. return;
  524. }
  525. })();
  526. // Check onclick compatibility in Opera
  527. // Support: Opera<15
  528. (function checkOnClickCompatibility() {
  529. // workaround for reported Opera bug DSK-354448:
  530. // onclick fires on disabled buttons with opaque content
  531. function ignoreIfTargetDisabled(event) {
  532. if (isDisabled(event.target)) {
  533. event.stopPropagation();
  534. }
  535. }
  536. function isDisabled(node) {
  537. return node.disabled || (node.parentNode && isDisabled(node.parentNode));
  538. }
  539. if (isOpera) {
  540. // use browser detection since we cannot feature-check this bug
  541. document.addEventListener('click', ignoreIfTargetDisabled, true);
  542. }
  543. })();
  544. // Checks if possible to use URL.createObjectURL()
  545. // Support: IE, Chrome on iOS
  546. (function checkOnBlobSupport() {
  547. // sometimes IE and Chrome on iOS loosing the data created with
  548. // createObjectURL(), see #3977 and #8081
  549. if (isIE || isIOSChrome) {
  550. PDFJS.disableCreateObjectURL = true;
  551. }
  552. })();
  553. // Checks if navigator.language is supported
  554. (function checkNavigatorLanguage() {
  555. if (typeof navigator === 'undefined') {
  556. return;
  557. }
  558. if ('language' in navigator) {
  559. return;
  560. }
  561. PDFJS.locale = navigator.userLanguage || 'en-US';
  562. })();
  563. // Support: Safari 6.0+, Android<3.0, Chrome 39/40, iOS
  564. (function checkRangeRequests() {
  565. // Safari has issues with cached range requests see:
  566. // https://github.com/mozilla/pdf.js/issues/3260
  567. // Last tested with version 6.0.4.
  568. // Older versions of Android (pre 3.0) has issues with range requests, see:
  569. // https://github.com/mozilla/pdf.js/issues/3381.
  570. // Make sure that we only match webkit-based Android browsers,
  571. // since Firefox/Fennec works as expected.
  572. // Range requests are broken in Chrome 39 and 40, https://crbug.com/442318
  573. if (isSafari || isAndroidPre3 || isChromeWithRangeBug || isIOS) {
  574. PDFJS.disableRange = true;
  575. PDFJS.disableStream = true;
  576. }
  577. })();
  578. // Check if the browser supports manipulation of the history.
  579. // Support: IE<10, Android<4.2
  580. (function checkHistoryManipulation() {
  581. if (!hasDOM) {
  582. return;
  583. }
  584. // Android 2.x has so buggy pushState support that it was removed in
  585. // Android 3.0 and restored as late as in Android 4.2.
  586. // Support: Android 2.x
  587. if (!history.pushState || isAndroidPre3) {
  588. PDFJS.disableHistory = true;
  589. }
  590. })();
  591. // Support: IE<11, Chrome<21, Android<4.4, Safari<6
  592. (function checkSetPresenceInImageData() {
  593. if (!hasDOM) {
  594. return;
  595. }
  596. // IE < 11 will use window.CanvasPixelArray which lacks set function.
  597. if (window.CanvasPixelArray) {
  598. if (typeof window.CanvasPixelArray.prototype.set !== 'function') {
  599. window.CanvasPixelArray.prototype.set = function(arr) {
  600. for (var i = 0, ii = this.length; i < ii; i++) {
  601. this[i] = arr[i];
  602. }
  603. };
  604. }
  605. } else {
  606. // Old Chrome and Android use an inaccessible CanvasPixelArray prototype.
  607. // Because we cannot feature detect it, we rely on user agent parsing.
  608. var polyfill = false, versionMatch;
  609. if (isChrome) {
  610. versionMatch = userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
  611. // Chrome < 21 lacks the set function.
  612. polyfill = versionMatch && parseInt(versionMatch[2]) < 21;
  613. } else if (isAndroid) {
  614. // Android < 4.4 lacks the set function.
  615. // Android >= 4.4 will contain Chrome in the user agent,
  616. // thus pass the Chrome check above and not reach this block.
  617. polyfill = isAndroidPre5;
  618. } else if (isSafari) {
  619. versionMatch = userAgent.
  620. match(/Version\/([0-9]+)\.([0-9]+)\.([0-9]+) Safari\//);
  621. // Safari < 6 lacks the set function.
  622. polyfill = versionMatch && parseInt(versionMatch[1]) < 6;
  623. }
  624. if (polyfill) {
  625. var contextPrototype = window.CanvasRenderingContext2D.prototype;
  626. var createImageData = contextPrototype.createImageData;
  627. contextPrototype.createImageData = function(w, h) {
  628. var imageData = createImageData.call(this, w, h);
  629. imageData.data.set = function(arr) {
  630. for (var i = 0, ii = this.length; i < ii; i++) {
  631. this[i] = arr[i];
  632. }
  633. };
  634. return imageData;
  635. };
  636. // this closure will be kept referenced, so clear its vars
  637. contextPrototype = null;
  638. }
  639. }
  640. })();
  641. // Support: IE<10, Android<4.0, iOS
  642. (function checkRequestAnimationFrame() {
  643. function installFakeAnimationFrameFunctions() {
  644. window.requestAnimationFrame = function (callback) {
  645. return window.setTimeout(callback, 20);
  646. };
  647. window.cancelAnimationFrame = function (timeoutID) {
  648. window.clearTimeout(timeoutID);
  649. };
  650. }
  651. if (!hasDOM) {
  652. return;
  653. }
  654. if (isIOS) {
  655. // requestAnimationFrame on iOS is broken, replacing with fake one.
  656. installFakeAnimationFrameFunctions();
  657. return;
  658. }
  659. if ('requestAnimationFrame' in window) {
  660. return;
  661. }
  662. window.requestAnimationFrame = window.mozRequestAnimationFrame ||
  663. window.webkitRequestAnimationFrame;
  664. if (window.requestAnimationFrame) {
  665. return;
  666. }
  667. installFakeAnimationFrameFunctions();
  668. })();
  669. // Support: Android, iOS
  670. (function checkCanvasSizeLimitation() {
  671. if (isIOS || isAndroid) {
  672. // 5MP
  673. PDFJS.maxCanvasPixels = 5242880;
  674. }
  675. })();
  676. // Disable fullscreen support for certain problematic configurations.
  677. // Support: IE11+ (when embedded).
  678. (function checkFullscreenSupport() {
  679. if (!hasDOM) {
  680. return;
  681. }
  682. if (isIE && window.parent !== window) {
  683. PDFJS.disableFullscreen = true;
  684. }
  685. })();
  686. // Provides document.currentScript support
  687. // Support: IE, Chrome<29.
  688. (function checkCurrentScript() {
  689. if (!hasDOM) {
  690. return;
  691. }
  692. if ('currentScript' in document) {
  693. return;
  694. }
  695. Object.defineProperty(document, 'currentScript', {
  696. get() {
  697. var scripts = document.getElementsByTagName('script');
  698. return scripts[scripts.length - 1];
  699. },
  700. enumerable: true,
  701. configurable: true,
  702. });
  703. })();
  704. // Provides `input.type = 'type'` runtime failure protection.
  705. // Support: IE9,10.
  706. (function checkInputTypeNumberAssign() {
  707. if (!hasDOM) {
  708. return;
  709. }
  710. var el = document.createElement('input');
  711. try {
  712. el.type = 'number';
  713. } catch (ex) {
  714. var inputProto = el.constructor.prototype;
  715. var typeProperty = Object.getOwnPropertyDescriptor(inputProto, 'type');
  716. Object.defineProperty(inputProto, 'type', {
  717. get() {
  718. return typeProperty.get.call(this);
  719. },
  720. set(value) {
  721. typeProperty.set.call(this, value === 'number' ? 'text' : value);
  722. },
  723. enumerable: true,
  724. configurable: true,
  725. });
  726. }
  727. })();
  728. // Provides correct document.readyState value for legacy browsers.
  729. // Support: IE9,10.
  730. (function checkDocumentReadyState() {
  731. if (!hasDOM) {
  732. return;
  733. }
  734. if (!document.attachEvent) {
  735. return;
  736. }
  737. var documentProto = document.constructor.prototype;
  738. var readyStateProto = Object.getOwnPropertyDescriptor(documentProto,
  739. 'readyState');
  740. Object.defineProperty(documentProto, 'readyState', {
  741. get() {
  742. var value = readyStateProto.get.call(this);
  743. return value === 'interactive' ? 'loading' : value;
  744. },
  745. set(value) {
  746. readyStateProto.set.call(this, value);
  747. },
  748. enumerable: true,
  749. configurable: true,
  750. });
  751. })();
  752. // Provides support for ChildNode.remove in legacy browsers.
  753. // Support: IE.
  754. (function checkChildNodeRemove() {
  755. if (!hasDOM) {
  756. return;
  757. }
  758. if (typeof Element.prototype.remove !== 'undefined') {
  759. return;
  760. }
  761. Element.prototype.remove = function () {
  762. if (this.parentNode) {
  763. this.parentNode.removeChild(this);
  764. }
  765. };
  766. })();
  767. /**
  768. * Polyfill for Promises:
  769. * The following promise implementation tries to generally implement the
  770. * Promise/A+ spec. Some notable differences from other promise libraries are:
  771. * - There currently isn't a separate deferred and promise object.
  772. * - Unhandled rejections eventually show an error if they aren't handled.
  773. *
  774. * Based off of the work in:
  775. * https://bugzilla.mozilla.org/show_bug.cgi?id=810490
  776. */
  777. (function checkPromise() {
  778. if (globalScope.Promise) {
  779. // Promises existing in the DOM/Worker, checking presence of all/resolve
  780. if (typeof globalScope.Promise.all !== 'function') {
  781. globalScope.Promise.all = function (iterable) {
  782. var count = 0, results = [], resolve, reject;
  783. var promise = new globalScope.Promise(function (resolve_, reject_) {
  784. resolve = resolve_;
  785. reject = reject_;
  786. });
  787. iterable.forEach(function (p, i) {
  788. count++;
  789. p.then(function (result) {
  790. results[i] = result;
  791. count--;
  792. if (count === 0) {
  793. resolve(results);
  794. }
  795. }, reject);
  796. });
  797. if (count === 0) {
  798. resolve(results);
  799. }
  800. return promise;
  801. };
  802. }
  803. if (typeof globalScope.Promise.resolve !== 'function') {
  804. globalScope.Promise.resolve = function (value) {
  805. return new globalScope.Promise(function (resolve) {
  806. resolve(value);
  807. });
  808. };
  809. }
  810. if (typeof globalScope.Promise.reject !== 'function') {
  811. globalScope.Promise.reject = function (reason) {
  812. return new globalScope.Promise(function (resolve, reject) {
  813. reject(reason);
  814. });
  815. };
  816. }
  817. if (typeof globalScope.Promise.prototype.catch !== 'function') {
  818. globalScope.Promise.prototype.catch = function (onReject) {
  819. return globalScope.Promise.prototype.then(undefined, onReject);
  820. };
  821. }
  822. return;
  823. }
  824. var STATUS_PENDING = 0;
  825. var STATUS_RESOLVED = 1;
  826. var STATUS_REJECTED = 2;
  827. // In an attempt to avoid silent exceptions, unhandled rejections are
  828. // tracked and if they aren't handled in a certain amount of time an
  829. // error is logged.
  830. var REJECTION_TIMEOUT = 500;
  831. var HandlerManager = {
  832. handlers: [],
  833. running: false,
  834. unhandledRejections: [],
  835. pendingRejectionCheck: false,
  836. scheduleHandlers: function scheduleHandlers(promise) {
  837. if (promise._status === STATUS_PENDING) {
  838. return;
  839. }
  840. this.handlers = this.handlers.concat(promise._handlers);
  841. promise._handlers = [];
  842. if (this.running) {
  843. return;
  844. }
  845. this.running = true;
  846. setTimeout(this.runHandlers.bind(this), 0);
  847. },
  848. runHandlers: function runHandlers() {
  849. var RUN_TIMEOUT = 1; // ms
  850. var timeoutAt = Date.now() + RUN_TIMEOUT;
  851. while (this.handlers.length > 0) {
  852. var handler = this.handlers.shift();
  853. var nextStatus = handler.thisPromise._status;
  854. var nextValue = handler.thisPromise._value;
  855. try {
  856. if (nextStatus === STATUS_RESOLVED) {
  857. if (typeof handler.onResolve === 'function') {
  858. nextValue = handler.onResolve(nextValue);
  859. }
  860. } else if (typeof handler.onReject === 'function') {
  861. nextValue = handler.onReject(nextValue);
  862. nextStatus = STATUS_RESOLVED;
  863. if (handler.thisPromise._unhandledRejection) {
  864. this.removeUnhandeledRejection(handler.thisPromise);
  865. }
  866. }
  867. } catch (ex) {
  868. nextStatus = STATUS_REJECTED;
  869. nextValue = ex;
  870. }
  871. handler.nextPromise._updateStatus(nextStatus, nextValue);
  872. if (Date.now() >= timeoutAt) {
  873. break;
  874. }
  875. }
  876. if (this.handlers.length > 0) {
  877. setTimeout(this.runHandlers.bind(this), 0);
  878. return;
  879. }
  880. this.running = false;
  881. },
  882. addUnhandledRejection: function addUnhandledRejection(promise) {
  883. this.unhandledRejections.push({
  884. promise,
  885. time: Date.now(),
  886. });
  887. this.scheduleRejectionCheck();
  888. },
  889. removeUnhandeledRejection: function removeUnhandeledRejection(promise) {
  890. promise._unhandledRejection = false;
  891. for (var i = 0; i < this.unhandledRejections.length; i++) {
  892. if (this.unhandledRejections[i].promise === promise) {
  893. this.unhandledRejections.splice(i);
  894. i--;
  895. }
  896. }
  897. },
  898. scheduleRejectionCheck: function scheduleRejectionCheck() {
  899. if (this.pendingRejectionCheck) {
  900. return;
  901. }
  902. this.pendingRejectionCheck = true;
  903. setTimeout(() => {
  904. this.pendingRejectionCheck = false;
  905. var now = Date.now();
  906. for (var i = 0; i < this.unhandledRejections.length; i++) {
  907. if (now - this.unhandledRejections[i].time > REJECTION_TIMEOUT) {
  908. var unhandled = this.unhandledRejections[i].promise._value;
  909. var msg = 'Unhandled rejection: ' + unhandled;
  910. if (unhandled.stack) {
  911. msg += '\n' + unhandled.stack;
  912. }
  913. // Raising and catching the error, so debugger can break on it.
  914. try {
  915. throw new Error(msg);
  916. } catch (_) {
  917. console.warn(msg);
  918. }
  919. this.unhandledRejections.splice(i);
  920. i--;
  921. }
  922. }
  923. if (this.unhandledRejections.length) {
  924. this.scheduleRejectionCheck();
  925. }
  926. }, REJECTION_TIMEOUT);
  927. },
  928. };
  929. var Promise = function Promise(resolver) {
  930. this._status = STATUS_PENDING;
  931. this._handlers = [];
  932. try {
  933. resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
  934. } catch (e) {
  935. this._reject(e);
  936. }
  937. };
  938. /**
  939. * Builds a promise that is resolved when all the passed in promises are
  940. * resolved.
  941. * @param {array} promises array of data and/or promises to wait for.
  942. * @return {Promise} New dependent promise.
  943. */
  944. Promise.all = function Promise_all(promises) {
  945. var resolveAll, rejectAll;
  946. var deferred = new Promise(function (resolve, reject) {
  947. resolveAll = resolve;
  948. rejectAll = reject;
  949. });
  950. var unresolved = promises.length;
  951. var results = [];
  952. if (unresolved === 0) {
  953. resolveAll(results);
  954. return deferred;
  955. }
  956. function reject(reason) {
  957. if (deferred._status === STATUS_REJECTED) {
  958. return;
  959. }
  960. results = [];
  961. rejectAll(reason);
  962. }
  963. for (var i = 0, ii = promises.length; i < ii; ++i) {
  964. var promise = promises[i];
  965. var resolve = (function(i) {
  966. return function(value) {
  967. if (deferred._status === STATUS_REJECTED) {
  968. return;
  969. }
  970. results[i] = value;
  971. unresolved--;
  972. if (unresolved === 0) {
  973. resolveAll(results);
  974. }
  975. };
  976. })(i);
  977. if (Promise.isPromise(promise)) {
  978. promise.then(resolve, reject);
  979. } else {
  980. resolve(promise);
  981. }
  982. }
  983. return deferred;
  984. };
  985. /**
  986. * Checks if the value is likely a promise (has a 'then' function).
  987. * @return {boolean} true if value is thenable
  988. */
  989. Promise.isPromise = function Promise_isPromise(value) {
  990. return value && typeof value.then === 'function';
  991. };
  992. /**
  993. * Creates resolved promise
  994. * @param value resolve value
  995. * @returns {Promise}
  996. */
  997. Promise.resolve = function Promise_resolve(value) {
  998. return new Promise(function (resolve) {
  999. resolve(value);
  1000. });
  1001. };
  1002. /**
  1003. * Creates rejected promise
  1004. * @param reason rejection value
  1005. * @returns {Promise}
  1006. */
  1007. Promise.reject = function Promise_reject(reason) {
  1008. return new Promise(function (resolve, reject) {
  1009. reject(reason);
  1010. });
  1011. };
  1012. Promise.prototype = {
  1013. _status: null,
  1014. _value: null,
  1015. _handlers: null,
  1016. _unhandledRejection: null,
  1017. _updateStatus: function Promise__updateStatus(status, value) {
  1018. if (this._status === STATUS_RESOLVED ||
  1019. this._status === STATUS_REJECTED) {
  1020. return;
  1021. }
  1022. if (status === STATUS_RESOLVED &&
  1023. Promise.isPromise(value)) {
  1024. value.then(this._updateStatus.bind(this, STATUS_RESOLVED),
  1025. this._updateStatus.bind(this, STATUS_REJECTED));
  1026. return;
  1027. }
  1028. this._status = status;
  1029. this._value = value;
  1030. if (status === STATUS_REJECTED && this._handlers.length === 0) {
  1031. this._unhandledRejection = true;
  1032. HandlerManager.addUnhandledRejection(this);
  1033. }
  1034. HandlerManager.scheduleHandlers(this);
  1035. },
  1036. _resolve: function Promise_resolve(value) {
  1037. this._updateStatus(STATUS_RESOLVED, value);
  1038. },
  1039. _reject: function Promise_reject(reason) {
  1040. this._updateStatus(STATUS_REJECTED, reason);
  1041. },
  1042. then: function Promise_then(onResolve, onReject) {
  1043. var nextPromise = new Promise(function (resolve, reject) {
  1044. this.resolve = resolve;
  1045. this.reject = reject;
  1046. });
  1047. this._handlers.push({
  1048. thisPromise: this,
  1049. onResolve,
  1050. onReject,
  1051. nextPromise,
  1052. });
  1053. HandlerManager.scheduleHandlers(this);
  1054. return nextPromise;
  1055. },
  1056. catch: function Promise_catch(onReject) {
  1057. return this.then(undefined, onReject);
  1058. },
  1059. };
  1060. globalScope.Promise = Promise;
  1061. })();
  1062. (function checkWeakMap() {
  1063. if (globalScope.WeakMap) {
  1064. return;
  1065. }
  1066. var id = 0;
  1067. function WeakMap() {
  1068. this.id = '$weakmap' + (id++);
  1069. }
  1070. WeakMap.prototype = {
  1071. has(obj) {
  1072. return !!Object.getOwnPropertyDescriptor(obj, this.id);
  1073. },
  1074. get(obj, defaultValue) {
  1075. return this.has(obj) ? obj[this.id] : defaultValue;
  1076. },
  1077. set(obj, value) {
  1078. Object.defineProperty(obj, this.id, {
  1079. value,
  1080. enumerable: false,
  1081. configurable: true,
  1082. });
  1083. },
  1084. delete(obj) {
  1085. delete obj[this.id];
  1086. },
  1087. };
  1088. globalScope.WeakMap = WeakMap;
  1089. })();
  1090. // Polyfill from https://github.com/Polymer/URL
  1091. /* Any copyright is dedicated to the Public Domain.
  1092. * http://creativecommons.org/publicdomain/zero/1.0/ */
  1093. (function checkURLConstructor() {
  1094. // feature detect for URL constructor
  1095. var hasWorkingUrl = false;
  1096. try {
  1097. if (typeof URL === 'function' &&
  1098. typeof URL.prototype === 'object' &&
  1099. ('origin' in URL.prototype)) {
  1100. var u = new URL('b', 'http://a');
  1101. u.pathname = 'c%20d';
  1102. hasWorkingUrl = u.href === 'http://a/c%20d';
  1103. }
  1104. } catch (e) { }
  1105. if (hasWorkingUrl) {
  1106. return;
  1107. }
  1108. var relative = Object.create(null);
  1109. relative['ftp'] = 21;
  1110. relative['file'] = 0;
  1111. relative['gopher'] = 70;
  1112. relative['http'] = 80;
  1113. relative['https'] = 443;
  1114. relative['ws'] = 80;
  1115. relative['wss'] = 443;
  1116. var relativePathDotMapping = Object.create(null);
  1117. relativePathDotMapping['%2e'] = '.';
  1118. relativePathDotMapping['.%2e'] = '..';
  1119. relativePathDotMapping['%2e.'] = '..';
  1120. relativePathDotMapping['%2e%2e'] = '..';
  1121. function isRelativeScheme(scheme) {
  1122. return relative[scheme] !== undefined;
  1123. }
  1124. function invalid() {
  1125. clear.call(this);
  1126. this._isInvalid = true;
  1127. }
  1128. function IDNAToASCII(h) {
  1129. if (h === '') {
  1130. invalid.call(this);
  1131. }
  1132. // XXX
  1133. return h.toLowerCase();
  1134. }
  1135. function percentEscape(c) {
  1136. var unicode = c.charCodeAt(0);
  1137. if (unicode > 0x20 &&
  1138. unicode < 0x7F &&
  1139. // " # < > ? `
  1140. [0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) === -1
  1141. ) {
  1142. return c;
  1143. }
  1144. return encodeURIComponent(c);
  1145. }
  1146. function percentEscapeQuery(c) {
  1147. // XXX This actually needs to encode c using encoding and then
  1148. // convert the bytes one-by-one.
  1149. var unicode = c.charCodeAt(0);
  1150. if (unicode > 0x20 &&
  1151. unicode < 0x7F &&
  1152. // " # < > ` (do not escape '?')
  1153. [0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) === -1
  1154. ) {
  1155. return c;
  1156. }
  1157. return encodeURIComponent(c);
  1158. }
  1159. var EOF, ALPHA = /[a-zA-Z]/,
  1160. ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/;
  1161. function parse(input, stateOverride, base) {
  1162. function err(message) {
  1163. errors.push(message);
  1164. }
  1165. var state = stateOverride || 'scheme start',
  1166. cursor = 0,
  1167. buffer = '',
  1168. seenAt = false,
  1169. seenBracket = false,
  1170. errors = [];
  1171. loop: while ((input[cursor - 1] !== EOF || cursor === 0) &&
  1172. !this._isInvalid) {
  1173. var c = input[cursor];
  1174. switch (state) {
  1175. case 'scheme start':
  1176. if (c && ALPHA.test(c)) {
  1177. buffer += c.toLowerCase(); // ASCII-safe
  1178. state = 'scheme';
  1179. } else if (!stateOverride) {
  1180. buffer = '';
  1181. state = 'no scheme';
  1182. continue;
  1183. } else {
  1184. err('Invalid scheme.');
  1185. break loop;
  1186. }
  1187. break;
  1188. case 'scheme':
  1189. if (c && ALPHANUMERIC.test(c)) {
  1190. buffer += c.toLowerCase(); // ASCII-safe
  1191. } else if (c === ':') {
  1192. this._scheme = buffer;
  1193. buffer = '';
  1194. if (stateOverride) {
  1195. break loop;
  1196. }
  1197. if (isRelativeScheme(this._scheme)) {
  1198. this._isRelative = true;
  1199. }
  1200. if (this._scheme === 'file') {
  1201. state = 'relative';
  1202. } else if (this._isRelative && base &&
  1203. base._scheme === this._scheme) {
  1204. state = 'relative or authority';
  1205. } else if (this._isRelative) {
  1206. state = 'authority first slash';
  1207. } else {
  1208. state = 'scheme data';
  1209. }
  1210. } else if (!stateOverride) {
  1211. buffer = '';
  1212. cursor = 0;
  1213. state = 'no scheme';
  1214. continue;
  1215. } else if (c === EOF) {
  1216. break loop;
  1217. } else {
  1218. err('Code point not allowed in scheme: ' + c);
  1219. break loop;
  1220. }
  1221. break;
  1222. case 'scheme data':
  1223. if (c === '?') {
  1224. this._query = '?';
  1225. state = 'query';
  1226. } else if (c === '#') {
  1227. this._fragment = '#';
  1228. state = 'fragment';
  1229. } else {
  1230. // XXX error handling
  1231. if (c !== EOF && c !== '\t' && c !== '\n' && c !== '\r') {
  1232. this._schemeData += percentEscape(c);
  1233. }
  1234. }
  1235. break;
  1236. case 'no scheme':
  1237. if (!base || !(isRelativeScheme(base._scheme))) {
  1238. err('Missing scheme.');
  1239. invalid.call(this);
  1240. } else {
  1241. state = 'relative';
  1242. continue;
  1243. }
  1244. break;
  1245. case 'relative or authority':
  1246. if (c === '/' && input[cursor + 1] === '/') {
  1247. state = 'authority ignore slashes';
  1248. } else {
  1249. err('Expected /, got: ' + c);
  1250. state = 'relative';
  1251. continue;
  1252. }
  1253. break;
  1254. case 'relative':
  1255. this._isRelative = true;
  1256. if (this._scheme !== 'file') {
  1257. this._scheme = base._scheme;
  1258. }
  1259. if (c === EOF) {
  1260. this._host = base._host;
  1261. this._port = base._port;
  1262. this._path = base._path.slice();
  1263. this._query = base._query;
  1264. this._username = base._username;
  1265. this._password = base._password;
  1266. break loop;
  1267. } else if (c === '/' || c === '\\') {
  1268. if (c === '\\') {
  1269. err('\\ is an invalid code point.');
  1270. }
  1271. state = 'relative slash';
  1272. } else if (c === '?') {
  1273. this._host = base._host;
  1274. this._port = base._port;
  1275. this._path = base._path.slice();
  1276. this._query = '?';
  1277. this._username = base._username;
  1278. this._password = base._password;
  1279. state = 'query';
  1280. } else if (c === '#') {
  1281. this._host = base._host;
  1282. this._port = base._port;
  1283. this._path = base._path.slice();
  1284. this._query = base._query;
  1285. this._fragment = '#';
  1286. this._username = base._username;
  1287. this._password = base._password;
  1288. state = 'fragment';
  1289. } else {
  1290. var nextC = input[cursor + 1];
  1291. var nextNextC = input[cursor + 2];
  1292. if (this._scheme !== 'file' || !ALPHA.test(c) ||
  1293. (nextC !== ':' && nextC !== '|') ||
  1294. (nextNextC !== EOF && nextNextC !== '/' && nextNextC !== '\\' &&
  1295. nextNextC !== '?' && nextNextC !== '#')) {
  1296. this._host = base._host;
  1297. this._port = base._port;
  1298. this._username = base._username;
  1299. this._password = base._password;
  1300. this._path = base._path.slice();
  1301. this._path.pop();
  1302. }
  1303. state = 'relative path';
  1304. continue;
  1305. }
  1306. break;
  1307. case 'relative slash':
  1308. if (c === '/' || c === '\\') {
  1309. if (c === '\\') {
  1310. err('\\ is an invalid code point.');
  1311. }
  1312. if (this._scheme === 'file') {
  1313. state = 'file host';
  1314. } else {
  1315. state = 'authority ignore slashes';
  1316. }
  1317. } else {
  1318. if (this._scheme !== 'file') {
  1319. this._host = base._host;
  1320. this._port = base._port;
  1321. this._username = base._username;
  1322. this._password = base._password;
  1323. }
  1324. state = 'relative path';
  1325. continue;
  1326. }
  1327. break;
  1328. case 'authority first slash':
  1329. if (c === '/') {
  1330. state = 'authority second slash';
  1331. } else {
  1332. err('Expected \'/\', got: ' + c);
  1333. state = 'authority ignore slashes';
  1334. continue;
  1335. }
  1336. break;
  1337. case 'authority second slash':
  1338. state = 'authority ignore slashes';
  1339. if (c !== '/') {
  1340. err('Expected \'/\', got: ' + c);
  1341. continue;
  1342. }
  1343. break;
  1344. case 'authority ignore slashes':
  1345. if (c !== '/' && c !== '\\') {
  1346. state = 'authority';
  1347. continue;
  1348. } else {
  1349. err('Expected authority, got: ' + c);
  1350. }
  1351. break;
  1352. case 'authority':
  1353. if (c === '@') {
  1354. if (seenAt) {
  1355. err('@ already seen.');
  1356. buffer += '%40';
  1357. }
  1358. seenAt = true;
  1359. for (var i = 0; i < buffer.length; i++) {
  1360. var cp = buffer[i];
  1361. if (cp === '\t' || cp === '\n' || cp === '\r') {
  1362. err('Invalid whitespace in authority.');
  1363. continue;
  1364. }
  1365. // XXX check URL code points
  1366. if (cp === ':' && this._password === null) {
  1367. this._password = '';
  1368. continue;
  1369. }
  1370. var tempC = percentEscape(cp);
  1371. if (this._password !== null) {
  1372. this._password += tempC;
  1373. } else {
  1374. this._username += tempC;
  1375. }
  1376. }
  1377. buffer = '';
  1378. } else if (c === EOF || c === '/' || c === '\\' ||
  1379. c === '?' || c === '#') {
  1380. cursor -= buffer.length;
  1381. buffer = '';
  1382. state = 'host';
  1383. continue;
  1384. } else {
  1385. buffer += c;
  1386. }
  1387. break;
  1388. case 'file host':
  1389. if (c === EOF || c === '/' || c === '\\' || c === '?' || c === '#') {
  1390. if (buffer.length === 2 && ALPHA.test(buffer[0]) &&
  1391. (buffer[1] === ':' || buffer[1] === '|')) {
  1392. state = 'relative path';
  1393. } else if (buffer.length === 0) {
  1394. state = 'relative path start';
  1395. } else {
  1396. this._host = IDNAToASCII.call(this, buffer);
  1397. buffer = '';
  1398. state = 'relative path start';
  1399. }
  1400. continue;
  1401. } else if (c === '\t' || c === '\n' || c === '\r') {
  1402. err('Invalid whitespace in file host.');
  1403. } else {
  1404. buffer += c;
  1405. }
  1406. break;
  1407. case 'host':
  1408. case 'hostname':
  1409. if (c === ':' && !seenBracket) {
  1410. // XXX host parsing
  1411. this._host = IDNAToASCII.call(this, buffer);
  1412. buffer = '';
  1413. state = 'port';
  1414. if (stateOverride === 'hostname') {
  1415. break loop;
  1416. }
  1417. } else if (c === EOF || c === '/' ||
  1418. c === '\\' || c === '?' || c === '#') {
  1419. this._host = IDNAToASCII.call(this, buffer);
  1420. buffer = '';
  1421. state = 'relative path start';
  1422. if (stateOverride) {
  1423. break loop;
  1424. }
  1425. continue;
  1426. } else if (c !== '\t' && c !== '\n' && c !== '\r') {
  1427. if (c === '[') {
  1428. seenBracket = true;
  1429. } else if (c === ']') {
  1430. seenBracket = false;
  1431. }
  1432. buffer += c;
  1433. } else {
  1434. err('Invalid code point in host/hostname: ' + c);
  1435. }
  1436. break;
  1437. case 'port':
  1438. if (/[0-9]/.test(c)) {
  1439. buffer += c;
  1440. } else if (c === EOF || c === '/' || c === '\\' ||
  1441. c === '?' || c === '#' || stateOverride) {
  1442. if (buffer !== '') {
  1443. var temp = parseInt(buffer, 10);
  1444. if (temp !== relative[this._scheme]) {
  1445. this._port = temp + '';
  1446. }
  1447. buffer = '';
  1448. }
  1449. if (stateOverride) {
  1450. break loop;
  1451. }
  1452. state = 'relative path start';
  1453. continue;
  1454. } else if (c === '\t' || c === '\n' || c === '\r') {
  1455. err('Invalid code point in port: ' + c);
  1456. } else {
  1457. invalid.call(this);
  1458. }
  1459. break;
  1460. case 'relative path start':
  1461. if (c === '\\') {
  1462. err('\'\\\' not allowed in path.');
  1463. }
  1464. state = 'relative path';
  1465. if (c !== '/' && c !== '\\') {
  1466. continue;
  1467. }
  1468. break;
  1469. case 'relative path':
  1470. if (c === EOF || c === '/' || c === '\\' ||
  1471. (!stateOverride && (c === '?' || c === '#'))) {
  1472. if (c === '\\') {
  1473. err('\\ not allowed in relative path.');
  1474. }
  1475. var tmp;
  1476. if ((tmp = relativePathDotMapping[buffer.toLowerCase()])) {
  1477. buffer = tmp;
  1478. }
  1479. if (buffer === '..') {
  1480. this._path.pop();
  1481. if (c !== '/' && c !== '\\') {
  1482. this._path.push('');
  1483. }
  1484. } else if (buffer === '.' && c !== '/' && c !== '\\') {
  1485. this._path.push('');
  1486. } else if (buffer !== '.') {
  1487. if (this._scheme === 'file' && this._path.length === 0 &&
  1488. buffer.length === 2 && ALPHA.test(buffer[0]) &&
  1489. buffer[1] === '|') {
  1490. buffer = buffer[0] + ':';
  1491. }
  1492. this._path.push(buffer);
  1493. }
  1494. buffer = '';
  1495. if (c === '?') {
  1496. this._query = '?';
  1497. state = 'query';
  1498. } else if (c === '#') {
  1499. this._fragment = '#';
  1500. state = 'fragment';
  1501. }
  1502. } else if (c !== '\t' && c !== '\n' && c !== '\r') {
  1503. buffer += percentEscape(c);
  1504. }
  1505. break;
  1506. case 'query':
  1507. if (!stateOverride && c === '#') {
  1508. this._fragment = '#';
  1509. state = 'fragment';
  1510. } else if (c !== EOF && c !== '\t' && c !== '\n' && c !== '\r') {
  1511. this._query += percentEscapeQuery(c);
  1512. }
  1513. break;
  1514. case 'fragment':
  1515. if (c !== EOF && c !== '\t' && c !== '\n' && c !== '\r') {
  1516. this._fragment += c;
  1517. }
  1518. break;
  1519. }
  1520. cursor++;
  1521. }
  1522. }
  1523. function clear() {
  1524. this._scheme = '';
  1525. this._schemeData = '';
  1526. this._username = '';
  1527. this._password = null;
  1528. this._host = '';
  1529. this._port = '';
  1530. this._path = [];
  1531. this._query = '';
  1532. this._fragment = '';
  1533. this._isInvalid = false;
  1534. this._isRelative = false;
  1535. }
  1536. // Does not process domain names or IP addresses.
  1537. // Does not handle encoding for the query parameter.
  1538. function JURL(url, base /* , encoding */) {
  1539. if (base !== undefined && !(base instanceof JURL)) {
  1540. base = new JURL(String(base));
  1541. }
  1542. this._url = url;
  1543. clear.call(this);
  1544. var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, '');
  1545. // encoding = encoding || 'utf-8'
  1546. parse.call(this, input, null, base);
  1547. }
  1548. JURL.prototype = {
  1549. toString() {
  1550. return this.href;
  1551. },
  1552. get href() {
  1553. if (this._isInvalid) {
  1554. return this._url;
  1555. }
  1556. var authority = '';
  1557. if (this._username !== '' || this._password !== null) {
  1558. authority = this._username +
  1559. (this._password !== null ? ':' + this._password : '') + '@';
  1560. }
  1561. return this.protocol +
  1562. (this._isRelative ? '//' + authority + this.host : '') +
  1563. this.pathname + this._query + this._fragment;
  1564. },
  1565. set href(href) {
  1566. clear.call(this);
  1567. parse.call(this, href);
  1568. },
  1569. get protocol() {
  1570. return this._scheme + ':';
  1571. },
  1572. set protocol(protocol) {
  1573. if (this._isInvalid) {
  1574. return;
  1575. }
  1576. parse.call(this, protocol + ':', 'scheme start');
  1577. },
  1578. get host() {
  1579. return this._isInvalid ? '' : this._port ?
  1580. this._host + ':' + this._port : this._host;
  1581. },
  1582. set host(host) {
  1583. if (this._isInvalid || !this._isRelative) {
  1584. return;
  1585. }
  1586. parse.call(this, host, 'host');
  1587. },
  1588. get hostname() {
  1589. return this._host;
  1590. },
  1591. set hostname(hostname) {
  1592. if (this._isInvalid || !this._isRelative) {
  1593. return;
  1594. }
  1595. parse.call(this, hostname, 'hostname');
  1596. },
  1597. get port() {
  1598. return this._port;
  1599. },
  1600. set port(port) {
  1601. if (this._isInvalid || !this._isRelative) {
  1602. return;
  1603. }
  1604. parse.call(this, port, 'port');
  1605. },
  1606. get pathname() {
  1607. return this._isInvalid ? '' : this._isRelative ?
  1608. '/' + this._path.join('/') : this._schemeData;
  1609. },
  1610. set pathname(pathname) {
  1611. if (this._isInvalid || !this._isRelative) {
  1612. return;
  1613. }
  1614. this._path = [];
  1615. parse.call(this, pathname, 'relative path start');
  1616. },
  1617. get search() {
  1618. return this._isInvalid || !this._query || this._query === '?' ?
  1619. '' : this._query;
  1620. },
  1621. set search(search) {
  1622. if (this._isInvalid || !this._isRelative) {
  1623. return;
  1624. }
  1625. this._query = '?';
  1626. if (search[0] === '?') {
  1627. search = search.slice(1);
  1628. }
  1629. parse.call(this, search, 'query');
  1630. },
  1631. get hash() {
  1632. return this._isInvalid || !this._fragment || this._fragment === '#' ?
  1633. '' : this._fragment;
  1634. },
  1635. set hash(hash) {
  1636. if (this._isInvalid) {
  1637. return;
  1638. }
  1639. this._fragment = '#';
  1640. if (hash[0] === '#') {
  1641. hash = hash.slice(1);
  1642. }
  1643. parse.call(this, hash, 'fragment');
  1644. },
  1645. get origin() {
  1646. var host;
  1647. if (this._isInvalid || !this._scheme) {
  1648. return '';
  1649. }
  1650. // javascript: Gecko returns String(""), WebKit/Blink String("null")
  1651. // Gecko throws error for "data://"
  1652. // data: Gecko returns "", Blink returns "data://", WebKit returns "null"
  1653. // Gecko returns String("") for file: mailto:
  1654. // WebKit/Blink returns String("SCHEME://") for file: mailto:
  1655. switch (this._scheme) {
  1656. case 'data':
  1657. case 'file':
  1658. case 'javascript':
  1659. case 'mailto':
  1660. return 'null';
  1661. }
  1662. host = this.host;
  1663. if (!host) {
  1664. return '';
  1665. }
  1666. return this._scheme + '://' + host;
  1667. },
  1668. };
  1669. // Copy over the static methods
  1670. var OriginalURL = globalScope.URL;
  1671. if (OriginalURL) {
  1672. JURL.createObjectURL = function(blob) {
  1673. // IE extension allows a second optional options argument.
  1674. // http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx
  1675. return OriginalURL.createObjectURL.apply(OriginalURL, arguments);
  1676. };
  1677. JURL.revokeObjectURL = function(url) {
  1678. OriginalURL.revokeObjectURL(url);
  1679. };
  1680. }
  1681. globalScope.URL = JURL;
  1682. })();
  1683. }