Skip to content

Commit

Permalink
[api-minor] Include the document /Lang attribute in the textContent-data
Browse files Browse the repository at this point in the history
  • Loading branch information
Snuffleupagus committed Apr 16, 2024
1 parent 12c4119 commit de07ea9
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 47 deletions.
2 changes: 1 addition & 1 deletion src/core/catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class Catalog {
return shadow(
this,
"lang",
typeof lang === "string" ? stringToPDFString(lang) : null
lang && typeof lang === "string" ? stringToPDFString(lang) : null
);
}

Expand Down
63 changes: 33 additions & 30 deletions src/core/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -381,13 +381,12 @@ class Page {
}

loadResources(keys) {
if (!this.resourcesPromise) {
// TODO: add async `_getInheritableProperty` and remove this.
this.resourcesPromise = this.pdfManager.ensure(this, "resources");
}
return this.resourcesPromise.then(() => {
// TODO: add async `_getInheritableProperty` and remove this.
this.resourcesPromise ||= this.pdfManager.ensure(this, "resources");

return this.resourcesPromise.then(resources => {
const objectLoader = new ObjectLoader(this.resources, keys, this.xref);
return objectLoader.load();
return objectLoader.load().then(() => resources);
});
}

Expand Down Expand Up @@ -611,7 +610,7 @@ class Page {
});
}

extractTextContent({
async extractTextContent({
handler,
task,
includeMarkedContent,
Expand All @@ -625,31 +624,35 @@ class Page {
"Properties",
"XObject",
]);
const langPromise = this.pdfManager.ensureCatalog("lang");

const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
return dataPromises.then(([contentStream]) => {
const partialEvaluator = new PartialEvaluator({
xref: this.xref,
handler,
pageIndex: this.pageIndex,
idFactory: this._localIdFactory,
fontCache: this.fontCache,
builtInCMapCache: this.builtInCMapCache,
standardFontDataCache: this.standardFontDataCache,
globalImageCache: this.globalImageCache,
systemFontCache: this.systemFontCache,
options: this.evaluatorOptions,
});
const [contentStream, resources, lang] = await Promise.all([
contentStreamPromise,
resourcesPromise,
langPromise,
]);
const partialEvaluator = new PartialEvaluator({
xref: this.xref,
handler,
pageIndex: this.pageIndex,
idFactory: this._localIdFactory,
fontCache: this.fontCache,
builtInCMapCache: this.builtInCMapCache,
standardFontDataCache: this.standardFontDataCache,
globalImageCache: this.globalImageCache,
systemFontCache: this.systemFontCache,
options: this.evaluatorOptions,
});

return partialEvaluator.getTextContent({
stream: contentStream,
task,
resources: this.resources,
includeMarkedContent,
disableNormalization,
sink,
viewBox: this.view,
});
return partialEvaluator.getTextContent({
stream: contentStream,
task,
resources,
includeMarkedContent,
disableNormalization,
sink,
viewBox: this.view,
lang,
});
}

Expand Down
3 changes: 3 additions & 0 deletions src/core/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -2307,6 +2307,7 @@ class PartialEvaluator {
sink,
seenStyles = new Set(),
viewBox,
lang = null,
markedContentData = null,
disableNormalization = false,
keepWhiteSpace = false,
Expand All @@ -2323,6 +2324,7 @@ class PartialEvaluator {
const textContent = {
items: [],
styles: Object.create(null),
lang,
};
const textContentItem = {
initialized: false,
Expand Down Expand Up @@ -3296,6 +3298,7 @@ class PartialEvaluator {
sink: sinkWrapper,
seenStyles,
viewBox,
lang,
markedContentData,
disableNormalization,
keepWhiteSpace,
Expand Down
3 changes: 3 additions & 0 deletions src/display/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,7 @@ class PDFDocumentProxy {
* items are included when includeMarkedContent is true.
* @property {Object<string, TextStyle>} styles - {@link TextStyle} objects,
* indexed by font name.
* @property {string | null} lang - The document /Lang attribute.
*/

/**
Expand Down Expand Up @@ -1654,6 +1655,7 @@ class PDFPageProxy {
resolve(textContent);
return;
}
textContent.lang ??= value.lang;
Object.assign(textContent.styles, value.styles);
textContent.items.push(...value.items);
pump();
Expand All @@ -1664,6 +1666,7 @@ class PDFPageProxy {
const textContent = {
items: [],
styles: Object.create(null),
lang: undefined,
};
pump();
});
Expand Down
31 changes: 17 additions & 14 deletions src/display/text_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const DEFAULT_FONT_ASCENT = 0.8;
const ascentCache = new Map();
let _canvasContext = null;

function getCtx() {
function getCtx(lang = null) {
if (!_canvasContext) {
// We don't use an OffscreenCanvas here because we use serif/sans serif
// fonts with it and they depends on the locale.
Expand All @@ -89,13 +89,13 @@ function cleanupTextLayer() {
_canvasContext = null;
}

function getAscent(fontFamily) {
function getAscent(fontFamily, lang) {
const cachedAscent = ascentCache.get(fontFamily);
if (cachedAscent) {
return cachedAscent;
}

const ctx = getCtx();
const ctx = getCtx(lang);

const savedFont = ctx.font;
ctx.canvas.width = ctx.canvas.height = DEFAULT_FONT_SIZE;
Expand Down Expand Up @@ -162,7 +162,7 @@ function getAscent(fontFamily) {
return DEFAULT_FONT_ASCENT;
}

function appendText(task, geom, styles) {
function appendText(task, geom, styles, lang) {
// Initialize all used properties to keep the caches monomorphic.
const textDiv = document.createElement("span");
const textDivProperties = {
Expand All @@ -171,6 +171,7 @@ function appendText(task, geom, styles) {
hasText: geom.str !== "",
hasEOL: geom.hasEOL,
fontSize: 0,
lang,
};
task._textDivs.push(textDiv);

Expand All @@ -184,7 +185,7 @@ function appendText(task, geom, styles) {
const fontFamily =
(task._fontInspectorEnabled && style.fontSubstitution) || style.fontFamily;
const fontHeight = Math.hypot(tx[2], tx[3]);
const fontAscent = fontHeight * getAscent(fontFamily);
const fontAscent = fontHeight * getAscent(fontFamily, lang);

let left, top;
if (angle === 0) {
Expand Down Expand Up @@ -333,7 +334,7 @@ class TextLayerRenderTask {
div: null,
scale: viewport.scale * (globalThis.devicePixelRatio || 1),
properties: null,
ctx: getCtx(),
ctx: null,
};
const { pageWidth, pageHeight, pageX, pageY } = viewport.rawDims;
this._transform = [1, 0, 0, -1, -pageX, pageY + pageHeight];
Expand Down Expand Up @@ -379,7 +380,7 @@ class TextLayerRenderTask {
/**
* @private
*/
_processItems(items, styleCache) {
_processItems(items, styleCache, lang) {
for (const item of items) {
if (item.str === undefined) {
if (
Expand All @@ -398,8 +399,9 @@ class TextLayerRenderTask {
}
continue;
}
this._layoutTextParams.ctx ||= getCtx(lang);
this._textContentItemsStr.push(item.str);
appendText(this, item, styleCache);
appendText(this, item, styleCache, lang);
}
}

Expand Down Expand Up @@ -438,16 +440,16 @@ class TextLayerRenderTask {
}

Object.assign(styleCache, value.styles);
this._processItems(value.items, styleCache);
this._processItems(value.items, styleCache, value.lang);
pump();
}, reject);
};

this._reader = this._textContentSource.getReader();
pump();
} else if (this._textContentSource) {
const { items, styles } = this._textContentSource;
this._processItems(items, styles);
const { items, styles, lang } = this._textContentSource;
this._processItems(items, styles, lang);
resolve();
} else {
throw new Error('No "textContentSource" parameter specified.');
Expand Down Expand Up @@ -487,19 +489,20 @@ function updateTextLayer({
}

if (mustRescale) {
const ctx = getCtx();
const scale = viewport.scale * (globalThis.devicePixelRatio || 1);
const params = {
prevFontSize: null,
prevFontFamily: null,
div: null,
scale,
properties: null,
ctx,
ctx: null,
};
for (const div of textDivs) {
params.properties = textDivProperties.get(div);
const props = textDivProperties.get(div);
params.properties = props;
params.div = div;
params.ctx ||= getCtx(props.lang);
layout(params);
}
}
Expand Down
6 changes: 4 additions & 2 deletions test/unit/api_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2982,10 +2982,11 @@ describe("api", function () {
});

it("gets text content", async function () {
const { items, styles } = await page.getTextContent();
const { items, styles, lang } = await page.getTextContent();

expect(items.length).toEqual(15);
expect(objectSize(styles)).toEqual(5);
expect(lang).toEqual("en");

const text = mergeText(items);
expect(text).toEqual(`Table Of Content
Expand All @@ -3000,13 +3001,14 @@ page 1 / 3`);
);
const pdfDoc = await loadingTask.promise;
const pdfPage = await pdfDoc.getPage(1);
const { items, styles } = await pdfPage.getTextContent({
const { items, styles, lang } = await pdfPage.getTextContent({
disableNormalization: true,
});
expect(items.length).toEqual(1);
// Font name will be a random object id.
const fontName = items[0].fontName;
expect(Object.keys(styles)).toEqual([fontName]);
expect(lang).toEqual(null);

expect(items[0]).toEqual({
dir: "ltr",
Expand Down

0 comments on commit de07ea9

Please sign in to comment.