2
0

text_layer_builder.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * JavaScript code in this page
  4. *
  5. * Copyright 2022 Mozilla Foundation
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @licend The above is the entire license notice for the
  20. * JavaScript code in this page
  21. */
  22. "use strict";
  23. Object.defineProperty(exports, "__esModule", {
  24. value: true
  25. });
  26. exports.TextLayerBuilder = void 0;
  27. var _pdf = require("../pdf");
  28. class TextLayerBuilder {
  29. #rotation = 0;
  30. #scale = 0;
  31. #textContentSource = null;
  32. constructor({
  33. highlighter = null,
  34. accessibilityManager = null,
  35. isOffscreenCanvasSupported = true
  36. }) {
  37. this.textContentItemsStr = [];
  38. this.renderingDone = false;
  39. this.textDivs = [];
  40. this.textDivProperties = new WeakMap();
  41. this.textLayerRenderTask = null;
  42. this.highlighter = highlighter;
  43. this.accessibilityManager = accessibilityManager;
  44. this.isOffscreenCanvasSupported = isOffscreenCanvasSupported;
  45. this.div = document.createElement("div");
  46. this.div.className = "textLayer";
  47. this.hide();
  48. }
  49. #finishRendering() {
  50. this.renderingDone = true;
  51. const endOfContent = document.createElement("div");
  52. endOfContent.className = "endOfContent";
  53. this.div.append(endOfContent);
  54. this.#bindMouse();
  55. }
  56. get numTextDivs() {
  57. return this.textDivs.length;
  58. }
  59. async render(viewport) {
  60. if (!this.#textContentSource) {
  61. throw new Error('No "textContentSource" parameter specified.');
  62. }
  63. const scale = viewport.scale * (globalThis.devicePixelRatio || 1);
  64. const {
  65. rotation
  66. } = viewport;
  67. if (this.renderingDone) {
  68. const mustRotate = rotation !== this.#rotation;
  69. const mustRescale = scale !== this.#scale;
  70. if (mustRotate || mustRescale) {
  71. this.hide();
  72. (0, _pdf.updateTextLayer)({
  73. container: this.div,
  74. viewport,
  75. textDivs: this.textDivs,
  76. textDivProperties: this.textDivProperties,
  77. isOffscreenCanvasSupported: this.isOffscreenCanvasSupported,
  78. mustRescale,
  79. mustRotate
  80. });
  81. this.#scale = scale;
  82. this.#rotation = rotation;
  83. }
  84. this.show();
  85. return;
  86. }
  87. this.cancel();
  88. this.highlighter?.setTextMapping(this.textDivs, this.textContentItemsStr);
  89. this.accessibilityManager?.setTextMapping(this.textDivs);
  90. this.textLayerRenderTask = (0, _pdf.renderTextLayer)({
  91. textContentSource: this.#textContentSource,
  92. container: this.div,
  93. viewport,
  94. textDivs: this.textDivs,
  95. textDivProperties: this.textDivProperties,
  96. textContentItemsStr: this.textContentItemsStr,
  97. isOffscreenCanvasSupported: this.isOffscreenCanvasSupported
  98. });
  99. await this.textLayerRenderTask.promise;
  100. this.#finishRendering();
  101. this.#scale = scale;
  102. this.#rotation = rotation;
  103. this.show();
  104. this.accessibilityManager?.enable();
  105. }
  106. hide() {
  107. if (!this.div.hidden) {
  108. this.highlighter?.disable();
  109. this.div.hidden = true;
  110. }
  111. }
  112. show() {
  113. if (this.div.hidden && this.renderingDone) {
  114. this.div.hidden = false;
  115. this.highlighter?.enable();
  116. }
  117. }
  118. cancel() {
  119. if (this.textLayerRenderTask) {
  120. this.textLayerRenderTask.cancel();
  121. this.textLayerRenderTask = null;
  122. }
  123. this.highlighter?.disable();
  124. this.accessibilityManager?.disable();
  125. this.textContentItemsStr.length = 0;
  126. this.textDivs.length = 0;
  127. this.textDivProperties = new WeakMap();
  128. }
  129. setTextContentSource(source) {
  130. this.cancel();
  131. this.#textContentSource = source;
  132. }
  133. #bindMouse() {
  134. const {
  135. div
  136. } = this;
  137. div.addEventListener("mousedown", evt => {
  138. const end = div.querySelector(".endOfContent");
  139. if (!end) {
  140. return;
  141. }
  142. let adjustTop = evt.target !== div;
  143. adjustTop &&= getComputedStyle(end).getPropertyValue("-moz-user-select") !== "none";
  144. if (adjustTop) {
  145. const divBounds = div.getBoundingClientRect();
  146. const r = Math.max(0, (evt.pageY - divBounds.top) / divBounds.height);
  147. end.style.top = (r * 100).toFixed(2) + "%";
  148. }
  149. end.classList.add("active");
  150. });
  151. div.addEventListener("mouseup", () => {
  152. const end = div.querySelector(".endOfContent");
  153. if (!end) {
  154. return;
  155. }
  156. end.style.top = "";
  157. end.classList.remove("active");
  158. });
  159. }
  160. }
  161. exports.TextLayerBuilder = TextLayerBuilder;