Skip to content

Commit 1a8689b

Browse files
authored
Merge pull request #20340 from Aditi-1400/serialize-pattern-ab
Serialize pattern data into ArrayBuffer
2 parents a6934b4 + fa63180 commit 1a8689b

File tree

7 files changed

+741
-172
lines changed

7 files changed

+741
-172
lines changed

src/core/evaluator.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {
4040
lookupMatrix,
4141
lookupNormalRect,
4242
} from "./core_utils.js";
43+
import { FontInfo, PatternInfo } from "../shared/obj-bin-transform.js";
4344
import {
4445
getEncoding,
4546
MacRomanEncoding,
@@ -72,7 +73,6 @@ import { BaseStream } from "./base_stream.js";
7273
import { bidi } from "./bidi.js";
7374
import { ColorSpace } from "./colorspace.js";
7475
import { ColorSpaceUtils } from "./colorspace_utils.js";
75-
import { FontInfo } from "../shared/obj-bin-transform.js";
7676
import { getFontSubstitution } from "./font_substitutions.js";
7777
import { getGlyphsUnicode } from "./glyphlist.js";
7878
import { getMetrics } from "./metrics.js";
@@ -1517,7 +1517,10 @@ class PartialEvaluator {
15171517
localShadingPatternCache.set(shading, id);
15181518

15191519
if (this.parsingType3Font) {
1520-
this.handler.send("commonobj", [id, "Pattern", patternIR]);
1520+
const transfers = [];
1521+
const patternBuffer = PatternInfo.write(patternIR);
1522+
transfers.push(patternBuffer);
1523+
this.handler.send("commonobj", [id, "Pattern", patternBuffer], transfers);
15211524
} else {
15221525
this.handler.send("obj", [id, this.pageIndex, "Pattern", patternIR]);
15231526
}

src/display/api.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import {
4545
StatTimer,
4646
} from "./display_utils.js";
4747
import { FontFaceObject, FontLoader } from "./font_loader.js";
48+
import { FontInfo, PatternInfo } from "../shared/obj-bin-transform.js";
4849
import {
4950
getDataProp,
5051
getFactoryUrlProp,
@@ -67,7 +68,6 @@ import { DOMCMapReaderFactory } from "display-cmap_reader_factory";
6768
import { DOMFilterFactory } from "./filter_factory.js";
6869
import { DOMStandardFontDataFactory } from "display-standard_fontdata_factory";
6970
import { DOMWasmFactory } from "display-wasm_factory";
70-
import { FontInfo } from "../shared/obj-bin-transform.js";
7171
import { GlobalWorkerOptions } from "./worker_options.js";
7272
import { Metadata } from "./metadata.js";
7373
import { OptionalContentConfig } from "./optional_content_config.js";
@@ -2804,9 +2804,12 @@ class WorkerTransport {
28042804
break;
28052805
case "FontPath":
28062806
case "Image":
2807-
case "Pattern":
28082807
this.commonObjs.resolve(id, exportedData);
28092808
break;
2809+
case "Pattern":
2810+
const pattern = new PatternInfo(exportedData);
2811+
this.commonObjs.resolve(id, pattern.getIR());
2812+
break;
28102813
default:
28112814
throw new Error(`Got unknown common object type ${type}`);
28122815
}

src/shared/obj-bin-transform.js

Lines changed: 277 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* limitations under the License.
1414
*/
1515

16-
import { assert } from "./util.js";
16+
import { assert, MeshFigureType } from "./util.js";
1717

1818
class CssFontInfo {
1919
#buffer;
@@ -606,4 +606,279 @@ class FontInfo {
606606
}
607607
}
608608

609-
export { CssFontInfo, FontInfo, SystemFontInfo };
609+
class PatternInfo {
610+
static #KIND = 0; // 1=axial, 2=radial, 3=mesh
611+
612+
static #HAS_BBOX = 1; // 0/1
613+
614+
static #HAS_BACKGROUND = 2; // 0/1 (background for mesh patterns)
615+
616+
static #SHADING_TYPE = 3; // shadingType (only for mesh patterns)
617+
618+
static #N_COORD = 4; // number of coordinate pairs
619+
620+
static #N_COLOR = 8; // number of rgb triplets
621+
622+
static #N_STOP = 12; // number of gradient stops
623+
624+
static #N_FIGURES = 16; // number of figures
625+
626+
constructor(buffer) {
627+
this.buffer = buffer;
628+
this.view = new DataView(buffer);
629+
this.data = new Uint8Array(buffer);
630+
}
631+
632+
static write(ir) {
633+
let kind,
634+
bbox = null,
635+
coords = [],
636+
colors = [],
637+
colorStops = [],
638+
figures = [],
639+
shadingType = null, // only needed for mesh patterns
640+
background = null; // background for mesh patterns
641+
642+
switch (ir[0]) {
643+
case "RadialAxial":
644+
kind = ir[1] === "axial" ? 1 : 2;
645+
bbox = ir[2];
646+
colorStops = ir[3];
647+
if (kind === 1) {
648+
coords.push(...ir[4], ...ir[5]);
649+
} else {
650+
coords.push(ir[4][0], ir[4][1], ir[6], ir[5][0], ir[5][1], ir[7]);
651+
}
652+
break;
653+
case "Mesh":
654+
kind = 3;
655+
shadingType = ir[1];
656+
coords = ir[2];
657+
colors = ir[3];
658+
figures = ir[4] || [];
659+
bbox = ir[6];
660+
background = ir[7];
661+
break;
662+
default:
663+
throw new Error(`Unsupported pattern type: ${ir[0]}`);
664+
}
665+
666+
const nCoord = Math.floor(coords.length / 2);
667+
const nColor = Math.floor(colors.length / 3);
668+
const nStop = colorStops.length;
669+
const nFigures = figures.length;
670+
671+
let figuresSize = 0;
672+
for (const figure of figures) {
673+
figuresSize += 1;
674+
figuresSize = Math.ceil(figuresSize / 4) * 4; // Ensure 4-byte alignment
675+
figuresSize += 4 + figure.coords.length * 4;
676+
figuresSize += 4 + figure.colors.length * 4;
677+
if (figure.verticesPerRow !== undefined) {
678+
figuresSize += 4;
679+
}
680+
}
681+
682+
const byteLen =
683+
20 +
684+
nCoord * 8 +
685+
nColor * 3 +
686+
nStop * 8 +
687+
(bbox ? 16 : 0) +
688+
(background ? 3 : 0) +
689+
figuresSize;
690+
const buffer = new ArrayBuffer(byteLen);
691+
const dataView = new DataView(buffer);
692+
const u8data = new Uint8Array(buffer);
693+
694+
dataView.setUint8(PatternInfo.#KIND, kind);
695+
dataView.setUint8(PatternInfo.#HAS_BBOX, bbox ? 1 : 0);
696+
dataView.setUint8(PatternInfo.#HAS_BACKGROUND, background ? 1 : 0);
697+
dataView.setUint8(PatternInfo.#SHADING_TYPE, shadingType); // Only for mesh pattern, null otherwise
698+
dataView.setUint32(PatternInfo.#N_COORD, nCoord, true);
699+
dataView.setUint32(PatternInfo.#N_COLOR, nColor, true);
700+
dataView.setUint32(PatternInfo.#N_STOP, nStop, true);
701+
dataView.setUint32(PatternInfo.#N_FIGURES, nFigures, true);
702+
703+
let offset = 20;
704+
const coordsView = new Float32Array(buffer, offset, nCoord * 2);
705+
coordsView.set(coords);
706+
offset += nCoord * 8;
707+
708+
u8data.set(colors, offset);
709+
offset += nColor * 3;
710+
711+
for (const [pos, hex] of colorStops) {
712+
dataView.setFloat32(offset, pos, true);
713+
offset += 4;
714+
dataView.setUint32(offset, parseInt(hex.slice(1), 16), true);
715+
offset += 4;
716+
}
717+
if (bbox) {
718+
for (const v of bbox) {
719+
dataView.setFloat32(offset, v, true);
720+
offset += 4;
721+
}
722+
}
723+
724+
if (background) {
725+
u8data.set(background, offset);
726+
offset += 3;
727+
}
728+
729+
for (let i = 0; i < figures.length; i++) {
730+
const figure = figures[i];
731+
dataView.setUint8(offset, figure.type);
732+
offset += 1;
733+
// Ensure 4-byte alignment
734+
offset = Math.ceil(offset / 4) * 4;
735+
dataView.setUint32(offset, figure.coords.length, true);
736+
offset += 4;
737+
const figureCoordsView = new Int32Array(
738+
buffer,
739+
offset,
740+
figure.coords.length
741+
);
742+
figureCoordsView.set(figure.coords);
743+
offset += figure.coords.length * 4;
744+
dataView.setUint32(offset, figure.colors.length, true);
745+
offset += 4;
746+
const colorsView = new Int32Array(buffer, offset, figure.colors.length);
747+
colorsView.set(figure.colors);
748+
offset += figure.colors.length * 4;
749+
750+
if (figure.verticesPerRow !== undefined) {
751+
dataView.setUint32(offset, figure.verticesPerRow, true);
752+
offset += 4;
753+
}
754+
}
755+
return buffer;
756+
}
757+
758+
getIR() {
759+
const dataView = this.view;
760+
const kind = this.data[PatternInfo.#KIND];
761+
const hasBBox = !!this.data[PatternInfo.#HAS_BBOX];
762+
const hasBackground = !!this.data[PatternInfo.#HAS_BACKGROUND];
763+
const nCoord = dataView.getUint32(PatternInfo.#N_COORD, true);
764+
const nColor = dataView.getUint32(PatternInfo.#N_COLOR, true);
765+
const nStop = dataView.getUint32(PatternInfo.#N_STOP, true);
766+
const nFigures = dataView.getUint32(PatternInfo.#N_FIGURES, true);
767+
768+
let offset = 20;
769+
const coords = new Float32Array(this.buffer, offset, nCoord * 2);
770+
offset += nCoord * 8;
771+
const colors = new Uint8Array(this.buffer, offset, nColor * 3);
772+
offset += nColor * 3;
773+
const stops = [];
774+
for (let i = 0; i < nStop; ++i) {
775+
const p = dataView.getFloat32(offset, true);
776+
offset += 4;
777+
const rgb = dataView.getUint32(offset, true);
778+
offset += 4;
779+
stops.push([p, `#${rgb.toString(16).padStart(6, "0")}`]);
780+
}
781+
let bbox = null;
782+
if (hasBBox) {
783+
bbox = [];
784+
for (let i = 0; i < 4; ++i) {
785+
bbox.push(dataView.getFloat32(offset, true));
786+
offset += 4;
787+
}
788+
}
789+
790+
let background = null;
791+
if (hasBackground) {
792+
background = new Uint8Array(this.buffer, offset, 3);
793+
offset += 3;
794+
}
795+
796+
const figures = [];
797+
for (let i = 0; i < nFigures; ++i) {
798+
const type = dataView.getUint8(offset);
799+
offset += 1;
800+
// Ensure 4-byte alignment
801+
offset = Math.ceil(offset / 4) * 4;
802+
803+
const coordsLength = dataView.getUint32(offset, true);
804+
offset += 4;
805+
const figureCoords = new Int32Array(this.buffer, offset, coordsLength);
806+
offset += coordsLength * 4;
807+
808+
const colorsLength = dataView.getUint32(offset, true);
809+
offset += 4;
810+
const figureColors = new Int32Array(this.buffer, offset, colorsLength);
811+
offset += colorsLength * 4;
812+
813+
const figure = {
814+
type,
815+
coords: figureCoords,
816+
colors: figureColors,
817+
};
818+
819+
if (type === MeshFigureType.LATTICE) {
820+
figure.verticesPerRow = dataView.getUint32(offset, true);
821+
offset += 4;
822+
}
823+
824+
figures.push(figure);
825+
}
826+
827+
if (kind === 1) {
828+
// axial
829+
return [
830+
"RadialAxial",
831+
"axial",
832+
bbox,
833+
stops,
834+
Array.from(coords.slice(0, 2)),
835+
Array.from(coords.slice(2, 4)),
836+
null,
837+
null,
838+
];
839+
}
840+
if (kind === 2) {
841+
return [
842+
"RadialAxial",
843+
"radial",
844+
bbox,
845+
stops,
846+
[coords[0], coords[1]],
847+
[coords[3], coords[4]],
848+
coords[2],
849+
coords[5],
850+
];
851+
}
852+
if (kind === 3) {
853+
const shadingType = this.data[PatternInfo.#SHADING_TYPE];
854+
let bounds = null;
855+
if (coords.length > 0) {
856+
let minX = coords[0],
857+
maxX = coords[0];
858+
let minY = coords[1],
859+
maxY = coords[1];
860+
for (let i = 0; i < coords.length; i += 2) {
861+
const x = coords[i],
862+
y = coords[i + 1];
863+
minX = minX > x ? x : minX;
864+
minY = minY > y ? y : minY;
865+
maxX = maxX < x ? x : maxX;
866+
maxY = maxY < y ? y : maxY;
867+
}
868+
bounds = [minX, minY, maxX, maxY];
869+
}
870+
return [
871+
"Mesh",
872+
shadingType,
873+
coords,
874+
colors,
875+
figures,
876+
bounds,
877+
bbox,
878+
background,
879+
];
880+
}
881+
throw new Error(`Unsupported pattern kind: ${kind}`);
882+
}
883+
}
884+
export { CssFontInfo, FontInfo, PatternInfo, SystemFontInfo };

0 commit comments

Comments
 (0)